Permalinks when filtering multiple custom post types by single taxonomy

admin2025-01-07  6

I've been working with Custom Post Types and Custom Taxonomies for ages but one thing I can never get right are the rewrites when applying a shared taxonomy to multiple CPTs.

For instance, I have CPTs for 'Events' and 'Courses'. Each has individual taxonomies and also one shared taxonomy.

The individual taxonomies work fine:

  • Events with a specific topic: /events/topic/{term}/
  • Courses of a specific type: /courses/type/{term}/

However, I have a shared taxonomy called 'Accessibility Criteria'. With the custom taxonomy defined as it is below, I want (and would expect) to be able to filter each CPT by the shared taxonomy at different URLs:

  • Events with specific accessibility criteria: /events/accessibility/{term}/
  • Courses with specific accessibility criteria: /courses/accessibility/{term}/

But whenever I try and use /events/accessibility/{term}/ it gets rewritten as /accessibility/{term}/. Surprisingly (to me), the context is actually retained correctly e.g. if I trigger the taxonomy from the Events archive then only Event CPTs are shown, so the end-user experience still works fine. However, it doesn't sit comfortably with me as I feel it should work differently (as well as potentially better SEO etc).

I have defined the custom taxonomies before defining the CPTs as I have read that affects the ability of a CPT to use the taxonomy rewrite.

Any help much appreciated.

$labels = array(
  "name" => __('Accessibility Criteria', ''),
  "singular_name" => __('Accessibility Criteria', ''),
  "add_new_item" => __('Add Accessibility Criteria', ''),
  "new_item_name" => __('Add Accessibility Criteria', ''),
  "edit_item" => __('Edit Accessibility Criteria', ''),
  "view_item" => __('View Accessibility Criteria', ''),
  "update_item" => __('Update Accessibility Criteria', ''),
  "parent_item" => __('Parent Criteria', '')
);
$args = array(
  "label" => __('Accessibility Criteria', ''),
  "labels" => $labels,
  "public" => true,
  "hierarchical" => true,
  "label" => "Accessibility Criteria",
  "show_ui" => true,
  "show_in_menu" => true,
  "show_in_nav_menus" => false,
  "capabilities" => array(
    'manage_terms' => 'manage_accessibility_criteria',
    'edit_terms'   => 'edit_accessibility_criteria',
    'delete_terms' => 'delete_accessibility_criteria',
    'assign_terms' => 'assign_accessibility_criteria'
  ),
  "query_var" => 'accessibility_criteria',
  "rewrite" => array('slug' => 'accessibility', 'with_front' => true),
  "show_admin_column" => true,
  "show_in_rest" => false,
  "rest_base" => "",
  "show_in_quick_edit" => true,
);
register_taxonomy("accessibility_criteria", array("event", "course"), $args);

I've been working with Custom Post Types and Custom Taxonomies for ages but one thing I can never get right are the rewrites when applying a shared taxonomy to multiple CPTs.

For instance, I have CPTs for 'Events' and 'Courses'. Each has individual taxonomies and also one shared taxonomy.

The individual taxonomies work fine:

  • Events with a specific topic: /events/topic/{term}/
  • Courses of a specific type: /courses/type/{term}/

However, I have a shared taxonomy called 'Accessibility Criteria'. With the custom taxonomy defined as it is below, I want (and would expect) to be able to filter each CPT by the shared taxonomy at different URLs:

  • Events with specific accessibility criteria: /events/accessibility/{term}/
  • Courses with specific accessibility criteria: /courses/accessibility/{term}/

But whenever I try and use /events/accessibility/{term}/ it gets rewritten as /accessibility/{term}/. Surprisingly (to me), the context is actually retained correctly e.g. if I trigger the taxonomy from the Events archive then only Event CPTs are shown, so the end-user experience still works fine. However, it doesn't sit comfortably with me as I feel it should work differently (as well as potentially better SEO etc).

I have defined the custom taxonomies before defining the CPTs as I have read that affects the ability of a CPT to use the taxonomy rewrite.

Any help much appreciated.

$labels = array(
  "name" => __('Accessibility Criteria', ''),
  "singular_name" => __('Accessibility Criteria', ''),
  "add_new_item" => __('Add Accessibility Criteria', ''),
  "new_item_name" => __('Add Accessibility Criteria', ''),
  "edit_item" => __('Edit Accessibility Criteria', ''),
  "view_item" => __('View Accessibility Criteria', ''),
  "update_item" => __('Update Accessibility Criteria', ''),
  "parent_item" => __('Parent Criteria', '')
);
$args = array(
  "label" => __('Accessibility Criteria', ''),
  "labels" => $labels,
  "public" => true,
  "hierarchical" => true,
  "label" => "Accessibility Criteria",
  "show_ui" => true,
  "show_in_menu" => true,
  "show_in_nav_menus" => false,
  "capabilities" => array(
    'manage_terms' => 'manage_accessibility_criteria',
    'edit_terms'   => 'edit_accessibility_criteria',
    'delete_terms' => 'delete_accessibility_criteria',
    'assign_terms' => 'assign_accessibility_criteria'
  ),
  "query_var" => 'accessibility_criteria',
  "rewrite" => array('slug' => 'accessibility', 'with_front' => true),
  "show_admin_column" => true,
  "show_in_rest" => false,
  "rest_base" => "",
  "show_in_quick_edit" => true,
);
register_taxonomy("accessibility_criteria", array("event", "course"), $args);
Share Improve this question asked Jan 25, 2018 at 13:09 onebconebc 1844 bronze badges 2
  • 2 Really? No-one? Come on... everyone loves CPT questions. Someone knows how to do this and can put me straight surely. :-) – onebc Commented Jan 29, 2018 at 17:31
  • I have the same problem and have not found a solution... not much of a comment help but will upvote your question. Maybe you can put a bounty on it or I will. – Enkode Commented May 15, 2018 at 5:13
Add a comment  | 

3 Answers 3

Reset to default 0

I think you need to add a rewrite rule as the "normal" rewrite rules don't support your wanted permalink structure. For your use case, you can try it like this:

First: remove the "rewrite" argument from your register_taxonomy arguments (not sure if you definitely need to do this, but it works on my site)

Second: Add the rewrite rule like this in your functions.php

add_action( 'init', 'wpse13483_init' );
function wpse292188_init(){   
    add_rewrite_rule('(events|courses)/accessibility/([^/]+)(/page/?([0-9]{1,}))?/?$','index.php?post_type=$matches[1]&taxonomy=accessibility&term=$matches[2]&paged=$matches[3]','top');
}

Don't forget to save permalinks after uploading!

Happy Coding!

You have to add these permalinks by your own. I do not see any code in WordPress which is creating $post_type/$taxonomy/$term permalinks. I do not see such a rules also in my rewrite rule array after creating custom taxonomy assigned only to one custom post type. Behavior of your application might be caused by some plugin. Below you will find code which will add custom permalinks for $post_type/$taxonomy/$term structure and load custom template when such a permalink is visited.

<?php
/**
 * Register event post type
 *
 * Method is used by init hook
 */
function wpse_292188_register_event_post_type() {

    $labels = array(
        'name' => __( 'Events' ),
        'singular_name' => __( 'Event' ),
        'add_new' => __( 'Add new' ),
        'add_new_item' => __( 'Add new' ),
        'edit_item' => __( 'Edit' ),
        'new_item' => __( 'New' ),
        'view_item' => __( 'View' ),
        'search_items' => __( 'Search' ),
        'not_found' => __( 'Not found' ),
        'not_found_in_trash' => __( 'Not found Events in trash' ),
        'parent_item_colon' => __( 'Parent' ),
        'menu_name' => __( 'Events' ),

    );

    $args = array(
        'labels' => $labels,
        'hierarchical' => false,
        'supports' => array( 'title', 'page-attributes' ),
        'taxonomies' => array(),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => false,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' => array('slug' => 'event'),
        'capability_type' => 'post',
    );

    register_post_type( 'event', $args );
}

add_action( 'init', 'wpse_292188_register_event_post_type' );

/**
 * Register course post type
 *
 * Method is used by init hook
 */
function wpse_292188_register_course_post_type() {

    $labels = array(
        'name' => __( 'Courses' ),
        'singular_name' => __( 'Course' ),
        'add_new' => __( 'Add new' ),
        'add_new_item' => __( 'Add new' ),
        'edit_item' => __( 'Edit' ),
        'new_item' => __( 'New' ),
        'view_item' => __( 'View' ),
        'search_items' => __( 'Search' ),
        'not_found' => __( 'Not found' ),
        'not_found_in_trash' => __( 'Not found Courses in trash' ),
        'parent_item_colon' => __( 'Parent' ),
        'menu_name' => __( 'Courses' ),

    );

    $args = array(
        'labels' => $labels,
        'hierarchical' => false,
        'supports' => array( 'title', 'page-attributes' ),
        'taxonomies' => array(),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => false,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' => array('slug' => 'course'),
        'capability_type' => 'post',
    );

    register_post_type( 'course', $args );
}

add_action( 'init', 'wpse_292188_register_course_post_type' );


/**
 * Register accessibility_criteria taxonomy
 *
 * Method is used by init hook
 */
function wpse_292188_register_accessibility_criteria_taxonomy() {

    $labels = array(
        'name'              => __( 'Accessibility Criteria', 'textdomain' ),
        'singular_name'     => __( 'Accessibility Criteria', 'textdomain' ),
        'search_items'      => __( 'Search Accessibility Criteria', 'textdomain' ),
        'all_items'         => __( 'All Accessibility Criteria', 'textdomain' ),
        'parent_item'       => __( 'Parent Accessibility Criteria', 'textdomain' ),
        'parent_item_colon' => __( 'Parent Accessibility Criteria:', 'textdomain' ),
        'edit_item'         => __( 'Edit Accessibility Criteria', 'textdomain' ),
        'update_item'       => __( 'Update Accessibility Criteria', 'textdomain' ),
        'add_new_item'      => __( 'Add New Accessibility Criteria', 'textdomain' ),
        'new_item_name'     => __( 'New Accessibility Criteria Name', 'textdomain' ),
        'menu_name'         => __( 'Accessibility Criteria', 'textdomain' ),
    );

    $args = array(
        'hierarchical'      => true,
        'labels'            => $labels,
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'rewrite'           => array( 'slug' => 'accessibility' ),
    );

    register_taxonomy( 'accessibility_criteria', array( 'event', 'course' ), $args );
}

add_action( 'init', 'wpse_292188_register_accessibility_criteria_taxonomy' );

/**
 * Add rewrite rules for common taxonomy
 *
 * @return void
 */
function wpse_292188_add_taxonomy_and_post_type_rewrite_rule() {

    /**
     * This rewrite rule will match sample following link
     *
     * /event/accessibility/criteria-1
     * /event/accessibility/criteria-1/page/2
     *
     * /course/accessibility/criteria-1
     * /course/accessibility/criteria-1/page/2
     *
     * and "redirect" it to index.php with such a arguments
     *
     * index.php?post_type=event&accessibility_criteria=criteria-1
     * index.php?post_type=event&accessibility_criteria=criteria-1&paged=2
     *
     * index.php?post_type=course&accessibility_criteria=criteria-1
     * index.php?post_type=course&accessibility_criteria=criteria-1&paged=2
     */
    add_rewrite_rule( 'event/accessibility/([^/]+)/?', 'index.php?post_type=event&accessibility_criteria=$matches[1]', 'top' );
    add_rewrite_rule( 'event/accessibility/([^/]+)/page/?([0-9]{1,})/?', 'index.php?pots_type=eventaccessibility_criteria=$matches[1]&paged=$matches[2]', 'top' );

    add_rewrite_rule( 'course/accessibility/([^/]+)/?', 'index.php?post_type=course&accessibility_criteria=$matches[1]', 'top' );
    add_rewrite_rule( 'course/accessibility/([^/]+)/page/?([0-9]{1,})/?', 'index.php?pots_type=courseaccessibility_criteria=$matches[1]&paged=$matches[2]', 'top' );

}

add_action( 'init', 'wpse_292188_add_taxonomy_and_post_type_rewrite_rule' );


/**
 * Register activation hooks. Only works in plugin file.
 */
register_activation_hook( __FILE__ , 'wpse_292188_activate' );
register_deactivation_hook( __FILE__ , 'wpse_292188_deactivate' );

/**
 * Activation function
 */
function wpse_292188_activate() {

    wpse_292188_add_taxonomy_and_post_type_rewrite_rule();
    flush_rewrite_rules();
}
/**
 * Deactivation function
 */
function wpse_292188_deactivate() {

    flush_rewrite_rules();
}

/**
 * Load proper template for taxonomy and post type rewrite rule
 *
 * @return string
 *
 * @throws \Exception When template do not exist.
 */
function wpse_292188_load_proper_template_for_taxonomy_and_post_type_rewrite_rule( $template ) {

    $post_type              = get_query_var('post_type');
    $accessibility_criteria = get_query_var('accessibility_criteria');

    /**
     * Check if current page has post type and accessibility_criteria custom
     * query var. If yest load our template.
     */
    if( $post_type && !empty( $post_type ) && $accessibility_criteria && !empty( $accessibility_criteria ) ) {

        /**
         * Locate our custom template. You can use $post_type and/or
         * $accessibility_criteria variables to create custom template.
         */
        $template = locate_template( array( 'taxonomy.php' ) );
    }

    if( $template == '' ) {
        throw new \Exception('No template found');
    }

    return $template;
}

add_filter( 'template_include', 'wpse_292188_load_proper_template_for_taxonomy_and_post_type_rewrite_rule' );

I'm using register_activation_hook and register_deactivation_hookso please put this code in your custom plugin.

I'm clearly late to the party but just in case someone else is looking for a solution I managed to do something similar by using some ideas from kierzniak's answer above.

I have 3 CPT's (news, events, downloads) that share the same taxonomy group (strategy) but I could not figure out the rewrite rules to make it all work.

Finally here's what I set up in my init function which works just fine:

add_rewrite_rule( '(news|events|downloads)/strategy/([^/]+)/?', 'index.php?post_type=$matches[1]&strategy=$matches[2]', 'top' );
add_rewrite_rule( '(news|events|downloads)/strategy/([^/]+)/page/?([0-9]{1,})/?', 'index.php?post_type=$matches[1]&strategy=$matches[2]&paged=$matches[3]', 'top' );
add_rewrite_rule( '(news|events|downloads)/strategy/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?', 'index.php?post_type=$matches[1]&strategy=$matches[2]&feed=$matches[3]', 'top' );
add_rewrite_rule( '(news|events|downloads)/strategy/([^/]+)/(feed|rdf|rss|rss2|atom)/?', 'index.php?post_type=$matches[1]&strategy=$matches[2]&feed=$matches[3]', 'top' );
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1736263286a878.html

最新回复(0)