Certain single CPT items result in 404 since 3.7
|Reported by:||boonebgorges||Owned by:|
|Component:||Posts, Post Types||Keywords:||needs-patch needs-unit-tests|
The changes in  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:
- 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, // ... ) );
- Set permalink settings to "Post name" (and flush)
- 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.
- 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 , 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.