Custom taxonomy listing page when no term set (all terms)
-
16-10-2019 - |
Question
I've created a custom taxonomy "foo" with rewrite slug "foo" and query_var "foo".
Say for example, I also have terms "bar" and "baz" in the "foo" taxonomy.
At the moment, permalinks like /foo/bar
and /foo/baz
work fine, using my taxonomy-foo.php
template.
What I'd like to do is be able to hit /foo
and retrieve all posts with a link to any "foo" taxonomy. Currently, this URL shows a 404.
How can I achieve this? If I can somehow hook into the rewrite code and set a default term value ('all'
for example) if missing, that might be a way to move forward but I'm not sure if this is possible.
I'd preferably like to use the taxonomy-foo.php
template file for the "catch all", dealing with the logic of showing posts from one or all terms in there.
Cheers
Edit: I've figured how to catch a request for /foo
and set some defaults using add_filter('request', ...)
though I had to use an existing term as using anything else generates a 404. Is there any way to avoid this limitation?
Solution
What you want is an index page for custom taxonomies. There is a ticket for that, but it's not clear what is the most obvious thing to show on this page: 1) a list of all posts attached to any term of that taxonomy, or 2) a list of all terms of this taxonomy? Remember that category
is also a taxonomy, but it is assumed that all posts fall under at least one category (with Uncategorized
as the default). In that case, option 1 would be the same as the regular post query, and option 2 might make more sense.
The related issue of an index page for custom post types will be fixed in the upcoming 3.1 release.
I tried something myself, and instead of interfering with the request
hook, I think the better way to do this is adding a new rewrite rule and modifying the query:
add_action( 'init', 'wpse4663_init' );
function wpse4663_init()
{
// The custom taxonomy rewrite rules end up at the top of the rewrite array
register_taxonomy(
'wpse4663',
array( 'post' ),
array(
'label' => 'WPSE 4663',
)
);
// So there probably is no danger in adding this specific rewrite rule there too
// We re-use the existing `taxonomy` query var, but with no `term`
// We clean this up in `parse_query`, otherwise get_posts() complains
// You could make this work for all taxonomies (categories, tags, ...) by doing this repeatedly
// But then it's probably better to do this in the `rewrite_rules_array` filter
add_rewrite_rule( 'wpse4663(/page/([0-9]+))?/?$', 'index.php?taxonomy=wpse4663&paged=$matches[2]', 'top' );
}
add_filter( 'parse_query', 'wpse4663_parse_query' );
function wpse4663_parse_query( &$wp_query )
{
// is_tax is only true if both a taxonomy and a term are set, otherwise is_home is true
// But we don't want that: is_tax and is_archive should be true, is_home should be false
if ( !$wp_query->is_tax && $taxonomy_query = $wp_query->get( 'taxonomy' ) ) {
foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
if ( $t->query_var && $taxonomy_query == $t->query_var ) {
// Make sure the conditional tags work, so the right template is loaded
$wp_query->is_tax = true;
$wp_query->is_archive = true;
$wp_query->is_home = false;
// Make is_tax($taxonomy) work
$wp_query->queried_object = $t;
$wp_query->queried_object->taxonomy = $taxonomy;
// If term is null, get_terms (query.php line 2043) will get all terms of this taxonomy
$wp_query->set( 'term', null );
break;
}
}
}
}
OTHER TIPS
Though the above answer will work for the default setups in wordpress. If you are rewriting the slug names for your taxonomies then Jan Fabry's answer won't work. It just requires a modification.
Also I would suggest to no do this as this will not fit with other plugins that you are might be using which does not know that you are using an index page for your taxonomy. It will start spitting undefined notices and other errors.
add_action( 'init', 'wpse4663_init' );
function wpse4663_init()
{
// The custom taxonomy rewrite rules end up at the top of the rewrite array
register_taxonomy(
'wpse4663',
array( 'post' ),
array(
'label' => 'WPSE 4663',
)
);
// So there probably is no danger in adding this specific rewrite rule there too
// We re-use the existing `taxonomy` query var, but with no `term`
// We clean this up in `parse_query`, otherwise get_posts() complains
// You could make this work for all taxonomies (categories, tags, ...) by doing this repeatedly
// But then it's probably better to do this in the `rewrite_rules_array` filter
add_rewrite_rule( 'wpse4663(/page/([0-9]+))?/?$', 'index.php?taxonomy=wpse4663&paged=$matches[2]', 'top' );
}
add_filter( 'parse_query', 'wpse4663_parse_query' );
function wpse4663_parse_query( &$wp_query )
{
// is_tax is only true if both a taxonomy and a term are set, otherwise is_home is true
// But we don't want that: is_tax and is_archive should be true, is_home should be false
if ( !$wp_query->is_tax && $taxonomy_query = $wp_query->get( 'taxonomy' ) ) {
foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
if($t->rewrite && isset($t->rewrite['slug']){
$slug = $t->rewrite['slug'];
}
else{
$slug = $t->query_var;
}
if ( $t->query_var && $taxonomy_query == $slug ) {
// Make sure the conditional tags work, so the right template is loaded
$wp_query->is_tax = true;
$wp_query->is_archive = true;
$wp_query->is_home = false;
// Make is_tax($taxonomy) work
$wp_query->queried_object = $t;
$wp_query->queried_object->taxonomy = $taxonomy;
// If term is null, get_terms (query.php line 2043) will get all terms of this taxonomy
$wp_query->set( 'term', null );
break;
}
}
}
}