[wp-hackers] Hierarchical Custom Post Type Issue

Mike Burns mike at grady-etc.com
Thu Dec 19 23:23:49 UTC 2013


‘lo fellow hackers!

We are in the process of creating a new theme for one of our larger sites.  As part of this project a few thousand “Pages” will be split into two hierarchical custom post types — “Services” and “Support Items”.

All services get a rewrite slug of /service/, i.e.:
http://example.org/service/one
http://example.org/service/one/child

And all support items get a rewrite slug of /support/, i.e.:
http://example.org/support/one
http://example.org/support/one/child

We’ve run in to an issue during implementation — requests for top-level “Services” or “Support Items” (post_parent = 0) are returning ALL posts of that post type that share the same slug (post_name).

As an example — if the following “Service” posts exist:
http://example.org/service/accounts/google
http://example.org/service/e-mail/google

And a request comes in for:
http://example.org/service/google

Instead of a 404, our single-service.php template is happily looping over those two posts.  If a “/service/google” post exists, we get all three.

I’ve tracked this down to the following logic in wp-includes/query.php — `WP_Query::get_posts()`:

```
if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], ‘/‘) === false ) {
// Non-hierarchical post_types & parent-level-hierarchical post_types can directly use ‘name’
$q[‘name’] = $q[ $ptype_obj->query_var ];
} else {
// Hierarchical post_types will operate through the
$q[‘pagename’] = $q[ $ptype_obj->query_var ];
$q[‘name’] = ‘’;
}
```

That branch in logic results in this query for top-level hierarchical posts:

SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_name = ‘google’ AND wp_posts.post_type = ‘support’ ORDER BY wp_posts.post_date DESC

As opposed to this one for non-top-level hierarchical posts:

SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND (wp_posts.ID = ‘123’) AND wp_posts.post_type = ‘support’ ORDER BY wp_posts.post_date DESC

The latter results in exactly one “Support Item” post, or a 404 if none are found (makes sense).  The former results in all “Support Items” with a slug of “google” (kind of crazy).

Why do requests for top-level custom hierarchical post type objects get special treatment?  I can work around it by adding filters to `parse_query` but I feel dirty doing it.

I was going to file a Trac ticket, but I figured I’d run it by the list first to make sure I’m not missing something obvious.

Thanks,
Mike


More information about the wp-hackers mailing list