Permalink for CPT with taxonomy

(Updated/new answer)

So here I’m going straight to the code you need: (but do read the updated version of the original answer)

Register the CPT’s and Set the proper rewrite slug

  1. This is for the “English Speaking” CPT, which is assigned to the
    custom taxonomy “Speaking Task”:

    register_post_type( 'english-speaking', array(
        'label' => 'English Speaking',
        'public' => true,
        'rewrite' => array(
            'slug' => 'english/speaking/%speaking_task%/%question_id%',
        ),
        // Other args here.
    ) );
    
  2. This is for the “English Writing” CPT, which is not assigned to
    any taxonomy:

    register_post_type( 'english-writing', array(
        'label' => 'English Writing',
        'public' => true,
        'rewrite' => array(
            'slug' => 'english/writing/%question_id%',
        ),
        // Other args here.
    ) );
    

Register the custom taxonomy “Speaking Task”

register_taxonomy( 'speaking-task', array( 'english-speaking' ), array(
    'label' => 'Speaking Tasks',
    'public' => true,
    'rewrite' => array(
        'slug' => 'english/speaking',
    ),
    // Other args here.
) );

Make sure the rewrite slug is set to english/speaking.

The “English Speaking” archive would be accessible at:

  • http://example.com/english/speaking

  • http://example.com/english/speaking/{SPEAKING TASK SLUG}

Register the custom rewrite tags

add_rewrite_tag( '%question_id%', '(\d+)' );
add_rewrite_tag( '%speaking_task%', '([^/]+)' );

Add the code for replacing the custom rewrite tags

add_filter( 'post_type_link', 'my_filter_questions_post_type_link', 10, 2 );
function my_filter_questions_post_type_link( $post_link, $post ) {
    // Replaces/rewrites %question_id% in the permalink.
    if ( false !== strpos( $post_link, '%question_id%' ) ) {
        $id = get_post_meta( $post->ID, 'wpcf-question-id', true );

        // A default value is necessary, and the value has to be a 0.
        $id = $id ? $id : '0';

        $post_link = str_replace( '%question_id%', $id, $post_link );
    }

    // Replaces/rewrites %speaking_task% in the permalink.
    if ( false !== strpos( $post_link, '%speaking_task%' ) ) {
        // A default value is necessary, but the term/category doesn't need to
        // actually exists. So you could, for example, use 'all' as the value.
        $slug = 'uncategorized';

        $cats = get_the_terms( $post, 'speaking-task' );
        if ( $cats && ! is_wp_error( $cats ) ) {
            $slug = $cats[0]->slug;
        }

        $post_link = str_replace( '%speaking_task%', $slug, $post_link );
    }

    return $post_link;
}

Flush the rewrite rules

Refer to my other answer if you don’t know how to flush the rules..

Use get_query_var() to retrieve the rewrite tag values

  • get_query_var( 'question_id' ) for %question_id%

  • get_query_var( 'task_slug' ) for %task_slug%


The full sample code is available here. 🙂


UPDATE

If you use a plugin to register the post type, you can filter (set/change) the rewrite slug via the register_post_type_args filter, like so:

add_filter( 'register_post_type_args', 'my_filter_post_type_args', 10, 2 );
function my_filter_post_type_args( $args, $post_type ) {
    if ( ! isset( $args['rewrite'] ) ) {
        $args['rewrite'] = array();
    }

    if ( 'english-speaking' === $post_type ) {
        $args['rewrite']['slug'] = 'english/speaking/%speaking_task%/%question_id%';
    } elseif ( 'english-speaking' === $post_type ) {
        $args['rewrite']['slug'] = 'english/writing/%question_id%';
    }

    return $args;
}

And likewise if you use a plugin to register the custom taxonomy, you can filter (set/change) the rewrite slug via the register_taxonomy_args filter, like so:

add_filter( 'register_taxonomy_args', 'my_filter_taxonomy_args', 10, 2 );
function my_filter_taxonomy_args( $args, $taxonomy ) {
    if ( ! isset( $args['rewrite'] ) ) {
        $args['rewrite'] = array();
    }

    if ( 'speaking-task' === $taxonomy ) {
        $args['rewrite']['slug'] = 'english/speaking';
    }

    return $args;
}

You might need to set a lower priority — i.e. change the 10 to 11 or a higher value (number) — greater number = lower priority, whereas lower number = higher priority.

Alternatively, without custom coding, and if the plugin allows you to manually set the rewrite slug of the custom post type or taxonomy, then just use the appropriate box/field to enter the appropriate rewrite slug. =)

Leave a Comment