Make WordPress Core

Changeset 53813


Ignore:
Timestamp:
08/03/2022 09:01:05 AM (21 months ago)
Author:
audrasjb
Message:

Posts, Post Types: Force unique slugs for draft posts.

This fixes a behavior where a draft created with the same slug as an existing post would set the existing post to a 404.

wp_unique_post_slug() returns the same slug for 'draft' or 'pending' posts, so to ensure that a unique slug is generated, this changeset adds the post data with the 'publish' status to wp_unique_post_slug().

Props Toro_Unit, h2ham, peterwilsoncc, costdev, antonvlasenko, azaozz, ironprogrammer, audrasjb, hellofromTonya.
Fixes #52422.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r53778 r53813  
    654654        $prepared_post->post_type = $this->post_type;
    655655
     656        if ( ! empty( $prepared_post->post_name )
     657            && ! empty( $prepared_post->post_status )
     658            && in_array( $prepared_post->post_status, array( 'draft', 'pending' ), true )
     659        ) {
     660            /*
     661             * `wp_unique_post_slug()` returns the same
     662             * slug for 'draft' or 'pending' posts.
     663             *
     664             * To ensure that a unique slug is generated,
     665             * pass the post data with the 'publish' status.
     666             */
     667            $prepared_post->post_name = wp_unique_post_slug(
     668                $prepared_post->post_name,
     669                $prepared_post->id,
     670                'publish',
     671                $prepared_post->post_type,
     672                $prepared_post->post_parent
     673            );
     674        }
     675
    656676        $post_id = wp_insert_post( wp_slash( (array) $prepared_post ), true, false );
    657677
     
    833853        if ( is_wp_error( $post ) ) {
    834854            return $post;
     855        }
     856
     857        if ( ! empty( $post->post_status ) ) {
     858            $post_status = $post->post_status;
     859        } else {
     860            $post_status = $post_before->post_status;
     861        }
     862
     863        /*
     864         * `wp_unique_post_slug()` returns the same
     865         * slug for 'draft' or 'pending' posts.
     866         *
     867         * To ensure that a unique slug is generated,
     868         * pass the post data with the 'publish' status.
     869         */
     870        if ( ! empty( $post->post_name ) && in_array( $post_status, array( 'draft', 'pending' ), true ) ) {
     871            $post_parent     = ! empty( $post->post_parent ) ? $post->post_parent : 0;
     872            $post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, 'publish', $post->post_type, $post_parent );
    835873        }
    836874
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r53759 r53813  
    52375237    }
    52385238
     5239    /**
     5240     * @ticket 52422
     5241     *
     5242     * @covers WP_REST_Request::create_item
     5243     */
     5244    public function test_draft_post_do_not_have_the_same_slug_as_existing_post() {
     5245        wp_set_current_user( self::$editor_id );
     5246        $this->factory()->post->create( array( 'post_name' => 'sample-slug' ) );
     5247
     5248        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     5249        $params  = $this->set_post_data(
     5250            array(
     5251                'status' => 'draft',
     5252                'slug'   => 'sample-slug',
     5253            )
     5254        );
     5255        $request->set_body_params( $params );
     5256        $response = rest_get_server()->dispatch( $request );
     5257
     5258        $new_data = $response->get_data();
     5259        $this->assertSame(
     5260            'sample-slug-2',
     5261            $new_data['slug'],
     5262            'The slug from the REST response did not match'
     5263        );
     5264
     5265        $post = get_post( $new_data['id'] );
     5266
     5267        $this->assertSame(
     5268            'draft',
     5269            $post->post_status,
     5270            'The post status is not draft'
     5271        );
     5272
     5273        $this->assertSame(
     5274            'sample-slug-2',
     5275            $post->post_name,
     5276            'The post slug was not set to "sample-slug-2"'
     5277        );
     5278    }
     5279
    52395280    public function tear_down() {
    52405281        if ( isset( $this->attachment_id ) ) {
Note: See TracChangeset for help on using the changeset viewer.