I have a CPT: 'Guide' and Custom Taxonomy 'Guide Category'.
What I want to achieve is:
The CPT permalink structure is: example.com/guides/custom-taxonomy/post-name/
So that the following should display the single-guide.php
:
example.com/guides/database/best-dbms-for-web-apps/
example.com/guides/database/mysql/how-to-optimize-mysql-databases/
At the same time, I want these to show the taxonomy-guide-category.php
:
example.com/guides/database/
example.com/guides/database/mysql/
Here's the code to register the CPT:
$args = [
'label' => esc_html__('How-to Guides', 'text-domain'),
'labels' => $labels,
'description' => 'How-to Guides',
'public' => true,
'hierarchical' => false,
'exclude_from_search' => false,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => true,
'show_in_rest' => true,
'query_var' => true,
'can_export' => true,
'delete_with_user' => false,
'has_archive' => 'guides',
'rest_base' => '',
'show_in_menu' => true,
'menu_position' => '',
'menu_icon' => 'dashicons-welcome-learn-more',
'capability_type' => 'post',
'supports' => ['title', 'editor', 'thumbnail', 'author', 'comments'],
'taxonomies' => ['guide-category'],
'rewrite' => [
// 'slug' => 'guides',
'slug' => 'guides/%guide_category%',
'with_front' => false,
],
];
register_post_type('guide', $args);
And here is the custom taxonomy code:
$args = [
'label' => esc_html__('Guide Categories', 'text-domain'),
'labels' => $labels,
'description' => 'How-to Guides Category',
'public' => true,
'publicly_queryable' => true,
'hierarchical' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'show_tagcloud' => true,
'show_in_quick_edit' => true,
'show_admin_column' => true,
'query_var' => true,
'sort' => false,
'meta_box_cb' => 'post_categories_meta_box',
'rest_base' => '',
'rewrite' => [
'slug' => 'guides',
'with_front' => false,
'hierarchical' => true,
],
];
register_taxonomy('guide-category', 'guide', $args);
This is the current code to achieve what I want:
/// STEP 1: Create Rewrite Rules
function xx_cpt_permalink_rewrite_rules() {
// Guides CPT
add_rewrite_rule(
'^guides/([^/]+)/([^/]+)/?$',
'index.php?post_type=guide&taxonomy=$matches[1]&name=$matches[2]',
'top'
);
add_rewrite_rule(
'^guides/([^/]+)/([^/]+)/([^/]+)/?$',
'index.php?post_type=guide&taxonomy=$matches[1]&name=$matches[3]',
'top'
);
add_rewrite_rule(
'^guides/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$',
'index.php?post_type=guide&taxonomy=$matches[1]&name=$matches[4]',
'top'
);
}
add_action('init', 'xx_cpt_permalink_rewrite_rules');
/// STEP 2: Create desired PERMALINKS
function xx_guide_permalink_structure($post_link, $post) {
// Guides CPT
if ('guide' === $post->post_type && $terms = get_the_terms($post->ID, 'guide-category')) {
// Get categories in reverse order (parent first)
$terms = array_reverse($terms);
$category_links = array();
foreach ($terms as $term) {
$category_links[] = $term->slug;
}
$permalink = home_url('/guides/' . $post->post_type_link . implode('/', $category_links) . '/' . $post->post_name . '/');
} else {
$permalink = $post_link;
}
return $permalink;
}
add_filter('post_type_link', 'xx_guide_permalink_structure', 10, 2);
/// STEP 3: (by default, while accessing: "EXAMPLE.COM/category/postname"
// WP thinks, that a standard post is requested. So, we are adding CUSTOM POST TYPE into that query.
function xx_add_cpts_to_pre_get_posts_query($query) {
if ($query->is_main_query() && !is_admin() && $query->is_single && 'guide' === $query->post_type) {
$query->set('post_type', array_merge(array('post'), array('guide')));
}
return $query;
}
add_action('pre_get_posts', 'xx_add_cpts_to_pre_get_posts_query', 12);
Now, the following URLs work as expected:
example.com/guides/database/best-dbms-for-web-apps/
=>single-guide.php
example.com/guides/database/mysql/how-to-optimize-mysql-databases/
=>single-guide.php
example.com/guides/database/
=>taxonomy-guide-category.php
However, the following URLs do NOT work as expected:
example.com/guides/database/mysql/
=>taxonomy-guide-category.php
How do I achieve the required results? What is wrong with my code and what could be improved/optimized?
Thanks in advance.