Make WordPress Core

Ticket #38928: 38928.4.diff

File 38928.4.diff, 12.0 KB (added by westonruter, 7 years ago)

Adding unit tests for wp_unique_post_slug() changes: https://github.com/xwp/wordpress-develop/pull/210

  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index 1f5da60..e4e7d9f 100644
    final class WP_Customize_Manager { 
    971971                        $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, $changeset_data['nav_menus_created_posts']['value'] );
    972972                }
    973973
     974                // Make an index of all the posts needed and what their slugs are.
     975                $needed_posts = array();
     976                $attachments = $this->prepare_starter_content_attachments( $attachments );
     977                foreach ( $attachments as $attachment ) {
     978                        $key = 'attachment:' . $attachment['post_name'];
     979                        $needed_posts[ $key ] = true;
     980                }
     981                foreach ( array_keys( $posts ) as $post_symbol ) {
     982                        if ( empty( $posts[ $post_symbol ]['post_name'] ) && empty( $posts[ $post_symbol ]['post_title'] ) ) {
     983                                unset( $posts[ $post_symbol ] );
     984                                continue;
     985                        }
     986                        if ( empty( $posts[ $post_symbol ]['post_name'] ) ) {
     987                                $posts[ $post_symbol ]['post_name'] = sanitize_title( $posts[ $post_symbol ]['post_title'] );
     988                        }
     989                        if ( empty( $posts[ $post_symbol ]['post_type'] ) ) {
     990                                $posts[ $post_symbol ]['post_type'] = 'post';
     991                        }
     992                        $needed_posts[ $posts[ $post_symbol ]['post_type'] . ':' . $posts[ $post_symbol ]['post_name'] ] = true;
     993                }
     994                $all_post_slugs = array_merge(
     995                        wp_list_pluck( $attachments, 'post_name' ),
     996                        wp_list_pluck( $posts, 'post_name' )
     997                );
     998
     999                // Re-use auto-draft starter content posts referenced in the current customized state.
    9741000                $existing_starter_content_posts = array();
    9751001                if ( ! empty( $starter_content_auto_draft_post_ids ) ) {
    9761002                        $existing_posts_query = new WP_Query( array(
    final class WP_Customize_Manager { 
    9841010                        }
    9851011                }
    9861012
     1013                // Re-use non-auto-draft posts.
     1014                if ( ! empty( $all_post_slugs ) ) {
     1015                        $existing_posts_query = new WP_Query( array(
     1016                                'post_name__in' => $all_post_slugs,
     1017                                'post_status' => array_diff( get_post_stati(), array( 'auto-draft' ) ),
     1018                                'post_type' => 'any',
     1019                                'number' => -1,
     1020                        ) );
     1021                        foreach ( $existing_posts_query->posts as $existing_post ) {
     1022                                $key = $existing_post->post_type . ':' . $existing_post->post_name;
     1023                                if ( isset( $needed_posts[ $key ] ) && ! isset( $existing_starter_content_posts[ $key ] ) ) {
     1024                                        $existing_starter_content_posts[ $key ] = $existing_post;
     1025                                }
     1026                        }
     1027                }
     1028
    9871029                // Attachments are technically posts but handled differently.
    9881030                if ( ! empty( $attachments ) ) {
    989                         // Such is The WordPress Way.
    990                         require_once( ABSPATH . 'wp-admin/includes/file.php' );
    991                         require_once( ABSPATH . 'wp-admin/includes/media.php' );
    992                         require_once( ABSPATH . 'wp-admin/includes/image.php' );
    9931031
    9941032                        $attachment_ids = array();
    9951033
    9961034                        foreach ( $attachments as $symbol => $attachment ) {
    997 
    998                                 // A file is required and URLs to files are not currently allowed.
    999                                 if ( empty( $attachment['file'] ) || preg_match( '#^https?://$#', $attachment['file'] ) ) {
    1000                                         continue;
    1001                                 }
    1002 
    1003                                 $file_array = array();
    1004                                 $file_path = null;
    1005                                 if ( file_exists( $attachment['file'] ) ) {
    1006                                         $file_path = $attachment['file']; // Could be absolute path to file in plugin.
    1007                                 } elseif ( is_child_theme() && file_exists( get_stylesheet_directory() . '/' . $attachment['file'] ) ) {
    1008                                         $file_path = get_stylesheet_directory() . '/' . $attachment['file'];
    1009                                 } elseif ( file_exists( get_template_directory() . '/' . $attachment['file'] ) ) {
    1010                                         $file_path = get_template_directory() . '/' . $attachment['file'];
    1011                                 } else {
    1012                                         continue;
    1013                                 }
    1014                                 $file_array['name'] = basename( $attachment['file'] );
    1015 
    1016                                 // Skip file types that are not recognized.
    1017                                 $checked_filetype = wp_check_filetype( $file_array['name'] );
    1018                                 if ( empty( $checked_filetype['type'] ) ) {
    1019                                         continue;
    1020                                 }
    1021 
    1022                                 // Ensure post_name is set since not automatically derived from post_title for new auto-draft posts.
    1023                                 if ( empty( $attachment['post_name'] ) ) {
    1024                                         if ( ! empty( $attachment['post_title'] ) ) {
    1025                                                 $attachment['post_name'] = sanitize_title( $attachment['post_title'] );
    1026                                         } else {
    1027                                                 $attachment['post_name'] = sanitize_title( preg_replace( '/\.\w+$/', '', $file_array['name'] ) );
    1028                                         }
    1029                                 }
    1030 
     1035                                $file_array = array(
     1036                                        'name' => $attachment['file_name'],
     1037                                );
     1038                                $file_path = $attachment['file_path'];
    10311039                                $attachment_id = null;
    10321040                                $attached_file = null;
    10331041                                if ( isset( $existing_starter_content_posts[ 'attachment:' . $attachment['post_name'] ] ) ) {
    final class WP_Customize_Manager { 
    10801088                                }
    10811089
    10821090                                $attachment_ids[ $symbol ] = $attachment_id;
    1083                                 $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, array_values( $attachment_ids ) );
    10841091                        }
     1092                        $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, array_values( $attachment_ids ) );
    10851093                }
    10861094
    10871095                // Posts & pages.
    10881096                if ( ! empty( $posts ) ) {
    10891097                        foreach ( array_keys( $posts ) as $post_symbol ) {
    1090                                 if ( empty( $posts[ $post_symbol ]['post_type'] ) ) {
     1098                                if ( empty( $posts[ $post_symbol ]['post_type'] ) || empty( $posts[ $post_symbol ]['post_name'] ) ) {
    10911099                                        continue;
    10921100                                }
    10931101                                $post_type = $posts[ $post_symbol ]['post_type'];
    final class WP_Customize_Manager { 
    12411249        }
    12421250
    12431251        /**
     1252         * Prepare starter content attachments.
     1253         *
     1254         * Ensure that the attachments are valid and that they have slugs and file name/path.
     1255         *
     1256         * @since 4.7.0
     1257         * @access private
     1258         *
     1259         * @param array $attachments Attachments.
     1260         * @return array Prepared attachments.
     1261         */
     1262        protected function prepare_starter_content_attachments( $attachments ) {
     1263                $prepared_attachments = array();
     1264                if ( empty( $attachments ) ) {
     1265                        return $prepared_attachments;
     1266                }
     1267
     1268                // Such is The WordPress Way.
     1269                require_once( ABSPATH . 'wp-admin/includes/file.php' );
     1270                require_once( ABSPATH . 'wp-admin/includes/media.php' );
     1271                require_once( ABSPATH . 'wp-admin/includes/image.php' );
     1272
     1273                foreach ( $attachments as $symbol => $attachment ) {
     1274
     1275                        // A file is required and URLs to files are not currently allowed.
     1276                        if ( empty( $attachment['file'] ) || preg_match( '#^https?://$#', $attachment['file'] ) ) {
     1277                                continue;
     1278                        }
     1279
     1280                        $file_path = null;
     1281                        if ( file_exists( $attachment['file'] ) ) {
     1282                                $file_path = $attachment['file']; // Could be absolute path to file in plugin.
     1283                        } elseif ( is_child_theme() && file_exists( get_stylesheet_directory() . '/' . $attachment['file'] ) ) {
     1284                                $file_path = get_stylesheet_directory() . '/' . $attachment['file'];
     1285                        } elseif ( file_exists( get_template_directory() . '/' . $attachment['file'] ) ) {
     1286                                $file_path = get_template_directory() . '/' . $attachment['file'];
     1287                        } else {
     1288                                continue;
     1289                        }
     1290                        $file_name = basename( $attachment['file'] );
     1291
     1292                        // Skip file types that are not recognized.
     1293                        $checked_filetype = wp_check_filetype( $file_name );
     1294                        if ( empty( $checked_filetype['type'] ) ) {
     1295                                continue;
     1296                        }
     1297
     1298                        // Ensure post_name is set since not automatically derived from post_title for new auto-draft posts.
     1299                        if ( empty( $attachment['post_name'] ) ) {
     1300                                if ( ! empty( $attachment['post_title'] ) ) {
     1301                                        $attachment['post_name'] = sanitize_title( $attachment['post_title'] );
     1302                                } else {
     1303                                        $attachment['post_name'] = sanitize_title( preg_replace( '/\.\w+$/', '', $file_name ) );
     1304                                }
     1305                        }
     1306
     1307                        $attachment['file_name'] = $file_name;
     1308                        $attachment['file_path'] = $file_path;
     1309                        $prepared_attachments[ $symbol ] = $attachment;
     1310                }
     1311                return $prepared_attachments;
     1312        }
     1313
     1314        /**
    12441315         * Save starter content changeset.
    12451316         *
    12461317         * @since 4.7.0
  • src/wp-includes/post.php

    diff --git src/wp-includes/post.php src/wp-includes/post.php
    index 620d1e4..2c70fdd 100644
    function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_p 
    36733673
    36743674        if ( 'attachment' == $post_type ) {
    36753675                // Attachment slugs must be unique across all types.
    3676                 $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
     3676                $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_status != 'auto-draft' AND post_name = %s AND ID != %d LIMIT 1";
    36773677                $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
    36783678
    36793679                /**
    function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_p 
    37013701                 * Page slugs must be unique within their own trees. Pages are in a separate
    37023702                 * namespace than posts so page slugs are allowed to overlap post slugs.
    37033703                 */
    3704                 $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1";
     3704                $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_status != 'auto-draft' AND post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1";
    37053705                $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );
    37063706
    37073707                /**
    function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_p 
    37253725                }
    37263726        } else {
    37273727                // Post slugs must be unique across all posts.
    3728                 $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
     3728                $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_status != 'auto-draft' AND post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
    37293729                $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );
    37303730
    37313731                // Prevent new post slugs that could result in URLs that conflict with date archives.
  • tests/phpunit/tests/post/wpUniquePostSlug.php

    diff --git tests/phpunit/tests/post/wpUniquePostSlug.php tests/phpunit/tests/post/wpUniquePostSlug.php
    index 536017d..a728454 100644
    class Tests_Post_WpUniquePostSlug extends WP_UnitTestCase { 
    347347                $found = wp_unique_post_slug( 'embed', $p, 'publish', 'attachment', 0 );
    348348                $this->assertSame( 'embed-2', $found );
    349349        }
     350
     351        /**
     352         * @ticket 38928
     353         */
     354        public function test_non_unique_slugs_for_existing_auto_draft_posts() {
     355                $auto_draft_post_id = self::factory()->post->create( array(
     356                        'post_type' => 'post',
     357                        'post_name' => 'existing-post',
     358                        'post_status' => 'auto-draft',
     359                ) );
     360                $auto_draft_page_id = self::factory()->post->create( array(
     361                        'post_type' => 'page',
     362                        'post_name' => 'existing-page',
     363                        'post_status' => 'auto-draft',
     364                ) );
     365                $auto_draft_attachment_id = self::factory()->attachment->create_object( 'image.jpg', $auto_draft_page_id, array(
     366                        'post_mime_type' => 'image/jpeg',
     367                        'post_type' => 'attachment',
     368                        'post_name' => 'existing-attachment',
     369                        'post_status' => 'auto-draft',
     370                ) );
     371
     372                $post_id = self::factory()->post->create( array( 'post_type' => 'post' ) );
     373                $page_id = self::factory()->post->create( array( 'post_type' => 'page' ) );
     374                $attachment_id = self::factory()->attachment->create_object( 'image2.jpg', $page_id, array(
     375                        'post_mime_type' => 'image/jpeg',
     376                        'post_type' => 'attachment',
     377                        'post_name' => 'existing-image',
     378                ) );
     379
     380                $this->assertEquals( 'existing-post', wp_unique_post_slug( 'existing-post', $post_id, 'publish', get_post_type( $post_id ), 0 ) );
     381                wp_publish_post( $auto_draft_post_id );
     382                $this->assertEquals( 'existing-post-2', wp_unique_post_slug( 'existing-post', $post_id, 'publish', get_post_type( $post_id ), 0 ) );
     383
     384                $this->assertEquals( 'existing-page', wp_unique_post_slug( 'existing-page', $page_id, 'publish', get_post_type( $page_id ), 0 ) );
     385                wp_publish_post( $auto_draft_page_id );
     386                $this->assertEquals( 'existing-page-2', wp_unique_post_slug( 'existing-page', $page_id, 'publish', get_post_type( $page_id ), 0 ) );
     387
     388                $this->assertEquals( 'existing-attachment', wp_unique_post_slug( 'existing-attachment', $attachment_id, 'publish', get_post_type( $attachment_id ), 0 ) );
     389                wp_publish_post( $auto_draft_attachment_id );
     390                $this->assertEquals( 'existing-attachment-2', wp_unique_post_slug( 'existing-attachment', $attachment_id, 'publish', get_post_type( $attachment_id ), 0 ) );
     391        }
    350392}