WordPress.org

Make WordPress Core

Opened 21 months ago

Last modified 17 months ago

#25798 new defect (bug)

Certain single CPT items result in 404 since 3.7

Reported by: boonebgorges Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 3.7
Component: Posts, Post Types Keywords:
Focuses: Cc:

Description

Related: #25749

The changes in [25182] to the query_var mapping of hierarchical post types have broken single permalinks in some cases, when Permalink setting is set to "Post name". To reproduce:

  1. Register a post type as follows:
    register_post_type( 'bbg_test', array(
        // ...
        'hierarchical' => true,
        'public' => true,
        'rewrite' => true, // any value other than false
        'query_var' => false,
        // ...
    ) );
    
  1. Set permalink settings to "Post name" (and flush)
  1. Create a new post of the type above, and attempt to visit at the url http://example.com/bbg_test/foo (or whatever). Result: 404.
  1. Change to any other permalink setting. Result: page loads as expected.

Cause: When the CPT is registered with 'rewrite' other than false, it passes the test at http://core.trac.wordpress.org/browser/tags/3.7/src/wp-includes/post.php#L1275. When it's hierarchical, it passes the test at line 1293. When, because 'query_var' is set to false, the rewrite tag set on line 1294 is of the form 'post_type=bbg_test&pagename=foo' (instead of 'bbg_test=foo'). Then, when an item is loaded, during WP::parse_request(), it passes the preg_match() test here http://core.trac.wordpress.org/browser/tags/3.7/src/wp-includes/class-wp.php#L198, but a page (ie, an item with post_type 'page') is not found by get_page_by_path(), and as a result the correct rewrite rule is not matched.

As noted, this is a regression in 3.7 [25182], before which preg_match( '/pagename=\$matches... wouldn't have matched.

Obviously it's an edge case that (a) a post type is hierarchical AND has query_var set to false, and also (b) permalinks are set to "Post name", but it is a change in behavior that broke one of my plugins, and has been a bit of a bear to track down :) I'm going to set query_var to true for my purposes (no harm done on my end) but that may not be possible for others.

Change History (3)

comment:1 @mordauk17 months ago

I've replicated the issue.

comment:2 @mordauk17 months ago

After a quick test, it looks like passing the post type to get_page_by_path() here fixes the issue.

I just hard coded the post type to test it quickly and it resolved the 404 error.

if ( ! get_page_by_path( $matches[ $varmatch[1] ], OBJECT, 'bbg_test' ) )

Last edited 17 months ago by mordauk (previous) (diff)

comment:3 @duck_17 months ago

Good catch.

Untested, but this could probably be fixed by tightening up the matching in class-wp.php, e.g. also check there's no "post_type=page" in $query or it's not "post_type=page".

Note: See TracTickets for help on using tickets.