Issues when using taxonomies and custom post types in the URL
-
I am trying to use taxonomies and custom post types in the URL. For example, my post type is “books” and my taxonomies could be hierarchical or single-level like “/arts/modern/”.
I have managed to do permalink rewrites that gives me the the URL like this:
https://www.example.com/books/arts/modern/sample-book/The issue is that the above URL is giving me a 404 page.
Is there a better or easier way to do this in WordPress?
One way to tackle this would be to create /books/arts/modern/sample-book/ as parent-child page structure but I really want to have the books and taxonomies separated so that it’s easier to manage.
-
See if this information will help:
To create custom permalinks with taxonomies and custom post types in WordPress, you’ll need to make sure you have the proper rewrite rules set up. Here’s a guide on how you can achieve this:
Register your custom post type: In your theme’s
functions.phpfile (or in a custom plugin), use theregister_post_type()function to register your custom post type. For example:function create_book_post_type() { $args = array( 'public' => true, 'label' => 'Books', // Add more arguments as needed ); register_post_type( 'books', $args ); } add_action( 'init', 'create_book_post_type' );Register your custom taxonomy: Similarly, register your custom taxonomy using the
register_taxonomy()function. You can set the hierarchical parameter to true if your taxonomy is hierarchical. For example:function create_book_taxonomy() { $args = array( 'hierarchical' => true, 'label' => 'Arts', // Add more arguments as needed ); register_taxonomy( 'arts', 'books', $args ); } add_action( 'init', 'create_book_taxonomy' );Flush rewrite rules: After registering the post type and taxonomy, you’ll need to flush the rewrite rules so that WordPress recognizes the new URLs. You can do this by simply visiting the “Settings” > “Permalinks” page in your WordPress admin area and clicking the “Save Changes” button. This will regenerate the rewrite rules.
With the above steps completed, your custom post type “books” and hierarchical taxonomy “arts” should now work with the desired URLs. For example, the URL
https://www.example.com/books/arts/modern/sample-book/should load the appropriate content.It’s important to note that if you change the code for registering the custom post type or taxonomy, you’ll need to flush the rewrite rules again for the changes to take effect.
By following this approach, you can keep the books and taxonomies separated, making it easier to manage.
You’ll want a custom rewrite rule so WP would know how to correctly parse the request. Rewrite rules should have a unique static element to ensure only the desired requests are matched. Avoid using post type slugs since your rewrite rule would conflict with the post type rewrite rules. If your post type is “books”, perhaps the static element for your rule would be “book” (singular).
In the case of single post requests like “sample-book”, you don’t really need to rewrite the category term since the post slug alone is enough to retrieve the correct post. If you do rewrite the term, if someone were to supply the wrong category in the request, they’ll get a nothing found response. If that’s desirable, then pass the term. If you’d rather they got the right post despite the wrong term, don’t pass the term.
https://developer.wordpress.org/reference/functions/add_rewrite_rule/@abretado1985 Simply registering the post type and taxonomy; and then re-saving the Permalinks did not automatically load the content on this URL:
https://www.example.com/books/arts/modern/sample-book/. This needed additional rewrite rules (see below) and permalink rewrites.@bcworkz Yes, I’ve managed to fix the issue by using the
add_rewrite_rule()function inside theinithook. I have a couple of questions in regards to the efficiency of the code.In my code, the rewrite rule includes nested
foreach()statements that generates several of these rewrite rules to captureparent/child hierarchical taxonomy termslike the following (there might be hundreds):https://www.example.com/books/arts/modern/sample-book/ https://www.example.com/books/arts/african/book-2/ https://www.example.com/books/arts/tattoo/needle-works/ https://www.example.com/books/comedy/classics/comedy-book-1/ https://www.example.com/books/crime/europe/crime-book-mafia/ https://www.example.com/books/crime/asia/crime-book-japan/ https://www.example.com/books/drama/classics/romeo-and-juliet/ https://www.example.com/books/drama/comedy/hello-world/ https://www.example.com/books/cars/classics/history-of-cars/This is the code:
function book_category_rewrite_rule() { $parent_terms = get_terms(...); // Get parent terms foreach( $parent_terms as $parent_term ) { $child_terms = get_terms(....); // Get child terms foreach( $child_terms as $child_term ) { add_rewrite_rule( '^books/' . $parent_term->slug.'/'.$child_term->slug . '/([a-z0-9-]+)[/]?$', 'index.php?books=$matches[1]', 'top' ); } } } add_action( 'init', 'book_category_rewrite_rule' );Does this always need to be fired from the
inithook or can this be fired from other hooks? I was wondering if this could potentially slow down the site if this gets fired on every page load.The code just assigns some values to an array, it’s not very resource intensive. It does need to be in place for when WP flushes and regenerates its rules. I’m not sure how one could conditionally call the code only for rewrite flushes, it’s not normally done.
The real inefficiency is in having so many rewrite rules. WP needs to apply each in turn for every request until it finds a match. Sometimes the match is near the top and happens quickly. If the match is near the bottom it’ll take a while.
You shouldn’t need a rule for every term though. A single rule can manage all variations provided the initial static element is matched. A regex can capture the remaining elements and pass them as an URL query string. Look at this example from the docs page:
add_rewrite_rule('^nutrition/([^/]*)/([^/]*)/?','index.php?page_id=12&food=$matches[1]&variety=$matches[2]','top');
The static element “nutrition” is all that needs to be matched. The remaining two elements are captured with([^/]*)and assigned to the $matches array, which is reused in the index.php query string.If the request is “example.com/nutrition/apple/fuji/, the rewritten request will be “example.com/index.php?page_id=12&food=apple&variety=fuji”. Food and variety are custom query vars that are used by the page template for page ID 12 to query for the related nutrition information. There could be thousands of different foods and varieties all covered by a single rewrite rule.
@bcworkz All good now. I had been over-complicating the logic. Thanks for your tips.
The topic ‘Issues when using taxonomies and custom post types in the URL’ is closed to new replies.