WordPress.org

Make WordPress Core

Ticket #5305: 5305.10.diff

File 5305.10.diff, 13.2 KB (added by boonebgorges, 5 years ago)
  • src/wp-includes/query.php

    diff --git src/wp-includes/query.php src/wp-includes/query.php
    index f076533..69493ea 100644
    class WP_Query { 
    17431743                        $qv['withcomments'] = 1;
    17441744                }
    17451745
     1746                // Resolve conflicts between posts with numeric slugs and date archive queries.
     1747                $this->resolve_numeric_slug_conflicts();
     1748
    17461749                $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
    17471750
    17481751                if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
    class WP_Query { 
    23212324        }
    23222325
    23232326        /**
     2327         * Resolve numeric slugs that collide with date permalinks.
     2328         *
     2329         * Permalinks of posts with numeric slugs can sometimes look to `WP_Query::parse_query()` like a date archive,
     2330         * as when your permalink structure is `/%year%/%postname%/` and a post with post_name '05' has the URL
     2331         * `/2015/05/`. This method detects these conflicts and resolves conflicts in favor of the post permalink.
     2332         *
     2333         * @since 4.2.0
     2334         * @access protected
     2335         */
     2336        protected function resolve_numeric_slug_conflicts() {
     2337                if ( ! $this->is_date ) {
     2338                        return;
     2339                }
     2340
     2341                // Identify the 'postname' position in the permastruct array.
     2342                $permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
     2343                $postname_index = array_search( '%postname%', $permastructs );
     2344
     2345                if ( false === $postname_index ) {
     2346                        return;
     2347                }
     2348
     2349                /*
     2350                 * A numeric slug could be confused with a year, month, or day, depending on position. To account for
     2351                 * the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our
     2352                 * `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check
     2353                 * for month-slug clashes when `is_month` *or* `is_day`.
     2354                 */
     2355                $compare = '';
     2356                if ( 0 === $postname_index && ( $this->is_year || $this->is_month ) ) {
     2357                        $compare = 'year';
     2358                } else if ( '%year%' === $permastructs[ $postname_index - 1 ] && ( $this->is_month || $this->is_day ) ) {
     2359                        $compare = 'monthnum';
     2360                } else if ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && $this->is_day ) {
     2361                        $compare = 'day';
     2362                }
     2363
     2364                if ( ! $compare ) {
     2365                        return;
     2366                }
     2367
     2368                // This is the potentially clashing slug.
     2369                $value = $this->get( $compare );
     2370
     2371                /*
     2372                 * `WP_Query::parse_query()` casts 'day' and 'monthnum' values to integers, stripping leading zeroes.
     2373                 * If we detect that the value originally passed to the query had a leading zero, re-add it to avoid
     2374                 * the potential of false slug matches.
     2375                 */
     2376                if ( 'year' !== $compare && isset( $this->query[ $compare ] ) && '0' === substr( $this->query[ $compare ], 0, 1 ) ) {
     2377                        $value = zeroise( $value, 2 );
     2378                }
     2379
     2380                $post = get_page_by_path( $value, OBJECT, 'post' );
     2381                if ( ! ( $post instanceof WP_Post ) ) {
     2382                        return;
     2383                }
     2384
     2385                /*
     2386                 * If the located post contains nextpage pagination, then the URL chunk following postname may be
     2387                 * intended as the page number. Verify that it's a valid page before resolving to it.
     2388                 */
     2389                $maybe_page = '';
     2390                if ( 'year' === $compare && $this->is_month ) {
     2391                        $maybe_page = $this->get( 'monthnum' );
     2392                } else if ( 'monthnum' === $compare && $this->is_day ) {
     2393                        $maybe_page = $this->get( 'day' );
     2394                }
     2395
     2396                $post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1;
     2397
     2398                // If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive.
     2399                if ( 1 === $post_page_count && $maybe_page ) {
     2400                        return;
     2401                }
     2402
     2403                // If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive.
     2404                if ( $post_page_count > 1 && $maybe_page > $post_page_count ) {
     2405                        return;
     2406                }
     2407
     2408                // If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage.
     2409                if ( '' !== $maybe_page ) {
     2410                        $this->set( 'page', intval( $maybe_page ) );
     2411                }
     2412
     2413                // Next, unset autodetected date-related query vars.
     2414                $this->is_archive = false;
     2415                $this->is_date    = false;
     2416                $this->is_year    = false;
     2417                $this->is_month   = false;
     2418                $this->is_day     = false;
     2419                $this->set( 'year', '' );
     2420                $this->set( 'monthnum', '' );
     2421                $this->set( 'day', '' );
     2422
     2423                // Finally, tell the query that it's a singular query for the identified post.
     2424                $this->is_single   = true;
     2425                $this->is_singular = true;
     2426                $this->set( 'name', $post->post_name );
     2427        }
     2428
     2429        /**
    23242430         * Sets the 404 property and saves whether query is feed.
    23252431         *
    23262432         * @since 2.0.0
  • tests/phpunit/tests/post.php

    diff --git tests/phpunit/tests/post.php tests/phpunit/tests/post.php
    index ae549e0..b61591b 100644
    class Tests_Post extends WP_UnitTestCase { 
    470470        }
    471471
    472472        /**
     473         * @ticket 5305
     474         */
     475        function test_permalink_year_segment_collision_without_title() {
     476                global $wp_rewrite, $wpdb;
     477                $wp_rewrite->init();
     478                $wp_rewrite->set_permalink_structure( '/%postname%/' );
     479                $wp_rewrite->flush_rules();
     480
     481                $id = $this->factory->post->create( array(
     482                        'post_author'  => $this->author_id,
     483                        'post_status'  => 'publish',
     484                        'post_content' => rand_str(),
     485                        'post_title'   => '',
     486                        'post_name'    => '2015',
     487                        'post_date'    => '2015-02-01 01:00:00'
     488                ) );
     489
     490                // Force an ID that resembles a year format
     491                $wpdb->update(
     492                        $wpdb->posts,
     493                        array(
     494                                'ID'   => '2015',
     495                                'guid' => 'http://example.org/?p=2015'
     496                        ),
     497                        array( 'ID' => $id )
     498                );
     499
     500                $this->go_to( get_permalink( '2015' ) );
     501
     502                $this->assertQueryTrue( 'is_single', 'is_singular' );
     503
     504                $wp_rewrite->set_permalink_structure('');
     505        }
     506
     507        /**
     508         * @ticket 5305
     509         */
     510        function test_permalink_year_segment_collision_with_title() {
     511                global $wp_rewrite;
     512                $wp_rewrite->init();
     513                $wp_rewrite->set_permalink_structure( '/%postname%/' );
     514                $wp_rewrite->flush_rules();
     515
     516                $id = $this->factory->post->create( array(
     517                        'post_author'  => $this->author_id,
     518                        'post_status'  => 'publish',
     519                        'post_content' => rand_str(),
     520                        'post_title'   => '2015',
     521                        'post_date'    => '2015-02-01 01:00:00',
     522                ) );
     523
     524                $this->assertEquals( $id, url_to_postid( get_permalink( $id ) ) );
     525
     526                $wp_rewrite->set_permalink_structure('');
     527        }
     528
     529        /**
     530         * @ticket 5305
     531         */
     532        function test_permalink_month_segment_collision_without_title() {
     533                global $wp_rewrite;
     534                $wp_rewrite->init();
     535                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     536                $wp_rewrite->flush_rules();
     537
     538                $id = $this->factory->post->create( array(
     539                        'post_author'  => $this->author_id,
     540                        'post_status'  => 'publish',
     541                        'post_content' => rand_str(),
     542                        'post_title'   => '',
     543                        'post_name'    => '02',
     544                        'post_date'    => '2015-02-01 01:00:00',
     545                ) );
     546
     547                $this->go_to( get_permalink( $id ) );
     548
     549                $this->assertQueryTrue( 'is_single', 'is_singular' );
     550
     551                $wp_rewrite->set_permalink_structure('');
     552        }
     553
     554        /**
     555         * @ticket 5305
     556         */
     557        function test_permalink_month_segment_collision_without_title_no_leading_zero() {
     558                global $wp_rewrite;
     559                $wp_rewrite->init();
     560                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     561                $wp_rewrite->flush_rules();
     562
     563                $id = $this->factory->post->create( array(
     564                        'post_author'  => $this->author_id,
     565                        'post_status'  => 'publish',
     566                        'post_content' => rand_str(),
     567                        'post_title'   => '',
     568                        'post_name'    => '2',
     569                        'post_date'    => '2015-02-01 01:00:00',
     570                ) );
     571
     572                $this->go_to( get_permalink( $id ) );
     573
     574                $this->assertQueryTrue( 'is_single', 'is_singular' );
     575
     576                $wp_rewrite->set_permalink_structure('');
     577        }
     578
     579        /**
     580         * @ticket 5305
     581         */
     582        function test_permalink_month_segment_collision_with_title() {
     583                global $wp_rewrite;
     584                $wp_rewrite->init();
     585                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     586                $wp_rewrite->flush_rules();
     587
     588                $id = $this->factory->post->create( array(
     589                        'post_author'  => $this->author_id,
     590                        'post_status'  => 'publish',
     591                        'post_content' => rand_str(),
     592                        'post_title'   => '02',
     593                        'post_date'    => '2015-02-01 01:00:00',
     594                ) );
     595
     596                $this->assertEquals( $id, url_to_postid( get_permalink( $id ) ) );
     597
     598                $wp_rewrite->set_permalink_structure('');
     599        }
     600
     601        /**
     602         * @ticket 5305
     603         */
     604        function test_permalink_month_segment_collision_with_title_no_leading_zero() {
     605                global $wp_rewrite;
     606                $wp_rewrite->init();
     607                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     608                $wp_rewrite->flush_rules();
     609
     610                $id = $this->factory->post->create( array(
     611                        'post_author'  => $this->author_id,
     612                        'post_status'  => 'publish',
     613                        'post_content' => rand_str(),
     614                        'post_title'   => '2',
     615                        'post_date'    => '2015-02-01 01:00:00',
     616                ) );
     617
     618                $this->assertEquals( $id, url_to_postid( get_permalink( $id ) ) );
     619
     620                $wp_rewrite->set_permalink_structure('');
     621        }
     622
     623        /**
     624         * @ticket 5305
     625         */
     626        function test_permalink_day_segment_collision_without_title() {
     627                global $wp_rewrite;
     628                $wp_rewrite->init();
     629                $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%postname%/' );
     630                $wp_rewrite->flush_rules();
     631
     632                $id = $this->factory->post->create( array(
     633                        'post_author'  => $this->author_id,
     634                        'post_status'  => 'publish',
     635                        'post_content' => rand_str(),
     636                        'post_title'   => '',
     637                        'post_name'    => '01',
     638                        'post_date'    => '2015-02-01 01:00:00',
     639                ) );
     640
     641                $this->go_to( get_permalink( $id ) );
     642
     643                $this->assertQueryTrue( 'is_single', 'is_singular' );
     644
     645                $wp_rewrite->set_permalink_structure('');
     646        }
     647
     648        /**
     649         * @ticket 5305
     650         */
     651        function test_permalink_day_segment_collision_with_title() {
     652                global $wp_rewrite;
     653                $wp_rewrite->init();
     654                $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%postname%/' );
     655                $wp_rewrite->flush_rules();
     656
     657                $id = $this->factory->post->create( array(
     658                        'post_author'  => $this->author_id,
     659                        'post_status'  => 'publish',
     660                        'post_content' => rand_str(),
     661                        'post_title'   => '01',
     662                        'post_date'    => '2015-02-01 01:00:00',
     663                ) );
     664
     665                $this->assertEquals( $id, url_to_postid( get_permalink( $id ) ) );
     666
     667                $wp_rewrite->set_permalink_structure('');
     668        }
     669
     670        /**
     671         * @ticket 5305
     672         */
     673        public function test_numeric_slug_permalink_conflicts_should_only_be_resolved_for_the_main_query() {
     674                global $wp_rewrite;
     675                $wp_rewrite->init();
     676                $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%postname%/' );
     677                $wp_rewrite->flush_rules();
     678
     679                $id = $this->factory->post->create( array(
     680                        'post_author'  => $this->author_id,
     681                        'post_status'  => 'publish',
     682                        'post_content' => rand_str(),
     683                        'post_title'   => '01',
     684                        'post_date'    => '2015-02-01 01:00:00',
     685                ) );
     686
     687                $q = new WP_Query( array(
     688                        'year' => '2015',
     689                        'monthnum' => '02',
     690                        'day' => '01',
     691                ) );
     692
     693                $this->assertTrue( $q->is_day );
     694                $this->assertFalse( $q->is_single );
     695
     696                $wp_rewrite->set_permalink_structure('');
     697        }
     698
     699        /**
     700         * @ticket 5305
     701         */
     702        public function test_date_slug_collision_should_distinguish_valid_pagination_from_date() {
     703                global $wp_rewrite;
     704                $wp_rewrite->init();
     705                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     706                $wp_rewrite->flush_rules();
     707
     708                $id = $this->factory->post->create( array(
     709                        'post_author'  => $this->author_id,
     710                        'post_status'  => 'publish',
     711                        'post_content' => 'Page 0<!--nextpage-->Page 1<!--nextpage-->Page 2<!--nextpage-->Page 3',
     712                        'post_title'   => '02',
     713                        'post_date'    => '2015-02-01 01:00:00',
     714                ) );
     715
     716                $this->go_to( get_permalink( $id ) . '1' );
     717
     718                $this->assertFalse( is_day() );
     719        }
     720
     721        /**
     722         * @ticket 5305
     723         */
     724        public function test_date_slug_collision_should_distinguish_too_high_pagination_from_date() {
     725                global $wp_rewrite;
     726                $wp_rewrite->init();
     727                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     728                $wp_rewrite->flush_rules();
     729
     730                $id = $this->factory->post->create( array(
     731                        'post_author'  => $this->author_id,
     732                        'post_status'  => 'publish',
     733                        'post_content' => 'Page 0<!--nextpage-->Page 1<!--nextpage-->Page 2<!--nextpage-->Page 3',
     734                        'post_title'   => '02',
     735                        'post_date'    => '2015-02-05 01:00:00',
     736                ) );
     737
     738                $this->go_to( get_permalink( $id ) . '5' );
     739
     740                $this->assertTrue( is_day() );
     741        }
     742
     743        /**
     744         * @ticket 5305
     745         */
     746        public function test_date_slug_collision_should_not_require_pagination_query_var() {
     747                global $wp_rewrite;
     748                $wp_rewrite->init();
     749                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     750                $wp_rewrite->flush_rules();
     751
     752                $id = $this->factory->post->create( array(
     753                        'post_author'  => $this->author_id,
     754                        'post_status'  => 'publish',
     755                        'post_content' => 'Page 0<!--nextpage-->Page 1<!--nextpage-->Page 2<!--nextpage-->Page 3',
     756                        'post_title'   => '02',
     757                        'post_date'    => '2015-02-05 01:00:00',
     758                ) );
     759
     760                $this->go_to( get_permalink( $id ) );
     761
     762                $this->assertQueryTrue( 'is_single', 'is_singular' );
     763                $this->assertFalse( is_date() );
     764        }
     765
     766        /**
     767         * @ticket 5305
     768         */
     769        public function test_date_slug_collision_should_be_ignored_when_pagination_var_is_present_but_post_does_not_have_multiple_pages() {
     770                global $wp_rewrite;
     771                $wp_rewrite->init();
     772                $wp_rewrite->set_permalink_structure( '/%year%/%postname%/' );
     773                $wp_rewrite->flush_rules();
     774
     775                $id = $this->factory->post->create( array(
     776                        'post_author'  => $this->author_id,
     777                        'post_status'  => 'publish',
     778                        'post_content' => 'This post does not have pagination.',
     779                        'post_title'   => '02',
     780                        'post_date'    => '2015-02-05 01:00:00',
     781                ) );
     782
     783                $this->go_to( get_permalink( $id ) . '5' );
     784
     785                $this->assertTrue( is_day() );
     786        }
     787
     788        /**
    473789         * @ticket 21013
    474790         */
    475791        function test_wp_unique_post_slug_with_non_latin_slugs() {