I'm currently working on a website which is a collective name of 2 schools. That's why I've renamed the taxonomy categories to schools. So in every post of a custom post type I can select the right school/category.

Now I have 3 custom post types in this theme.

  1. Agenda
  2. Schoolgids (schoolguide)
  3. Vacatures (vacancies)

Everything looks like it's working good, but only the URL-structure is not the way I want it to be. The way I want it, is for example: domainname.com/schoolname/post-type/post-name. My custom post type(s) is/are looking like this:

Post type (agenda for example):

function custom_post_agenda() {
    register_post_type( 'agenda',
        array('labels' => array(
            'name' => __('Agenda', 'raadhuiswp'),
            'singular_name' => __('Agenda', 'raadhuiswp'),
            'all_items' => __('Alle agendapunten', 'raadhuiswp'),
            'add_new' => __('Nieuw agendapunt', 'raadhuiswp'),
            'add_new_item' => __('Voeg nieuw agendapunt toe', 'raadhuiswp'),
            'edit' => __( 'Wijzig', 'raadhuiswp' ),
            'edit_item' => __('Wijzig agendapunt', 'raadhuiswp'),
            'new_item' => __('Voeg nieuw agendapunt toe', 'raadhuiswp'),
            'view_item' => __('Toon agendapunt', 'raadhuiswp'),
            'search_items' => __('Zoeken naar agendapunten', 'raadhuiswp'),
            'not_found' =>  __('Niks gevonden in de database.', 'raadhuiswp'),
            'not_found_in_trash' => __('Niks gevonden en de prullenbak.', 'raadhuiswp'),
            'parent_item_colon' => ''
            'description' => __( 'Een post type voor agendapunten', 'raadhuiswp' ),
            'public' => true,
            'publicly_queryable' => true,
            'exclude_from_search' => false,
            'show_ui' => true,
            'query_var' => true,
            'menu_position' => 8,
            'menu_icon' => 'dashicons-calendar-alt',
            'rewrite'   => array( 'slug' => '%school%/agenda',
            'with_front' => true ),
            'has_archive' => true,
            'capability_type' => 'post',
            'hierarchical' => false,
            'show_in_rest' => true,

            'supports' => array( 'title', 'author', 'thumbnail', 'excerpt', 'revisions', 'page-attributes')

    register_taxonomy_for_object_type('category', 'agenda');
    register_taxonomy_for_object_type('post_tag', 'agenda');

add_action( 'init', 'custom_post_agenda');

Now I've already managed to rewrite the slug for the post types with the following function:


function school_post_type_link($link, $post) {

      if ($post->post_type == 'agenda') {

            if ($school = get_the_terms($post->ID, 'category')) {

                $link = str_replace('%school%', array_pop($school)->slug, $link);

                return $link;

    } elseif ($post->post_type == 'vacatures') {

        if ($school = get_the_terms($post->ID, 'category')) {

            $link = str_replace('%school%', array_pop($school)->slug, $link);

            return $link;

        } elseif ($post->post_type == 'schoolgids') {

            if ($school = get_the_terms($post->ID, 'category')) {

                $link = str_replace('%school%', array_pop($school)->slug, $link);

                return $link;

    } else {
        return $link;

add_filter('post_type_link', 'school_post_type_link', 1, 3);

This way, I replace the '%school%' for the for the category name. And it seem to work:


So what I'm basicly doing is, checking if the post type is one of my custom post types, and if so, I replace the slug of it.

Now when I click view page, I keep getting the page not found (404) page. I have no idea why this is, because I can edit the post in WordPress itself without any problems.

Any idea what could cause this? Thanks in advance!

  • Have you flushed the rewrite rules? Just visit the Permalink Settings page.
    – Sally CJ
    Jul 26, 2019 at 10:15
  • @SallyCJ Yes, everytime I change something
    – Loosie94
    Jul 26, 2019 at 12:48
  • Sorry, I didn't really notice the rewrite structure. But see my answer and let me know.
    – Sally CJ
    Jul 26, 2019 at 14:42

1 Answer 1


The error 404 happens because you haven't registered the %school% rewrite tag — you need to register it so that WordPress will know what to replace it with when generating the rewrite rules — i.e. it doesn't remain as %school% in the generated rewrite rules. And you can register the tag using add_rewrite_tag():

// Add this to custom_post_agenda(), before you call register_post_type().
add_rewrite_tag( '%school%', '([^/]+)' );

Secondly, when you register the post type, the has_archive should be set to a unique slug such as agendas and not just true because if you use 'has_archive' => true, the archive slug would be %school%:

register_post_type( 'agenda', array(
    'has_archive' => 'agendas',
    // ...
) );

And third, because the post type's rewrite slug starts with the ([^/]+) (i.e. a category slug), you need the following filter to remove unnecessary rewrite rules (for that post type) which will conflict with Page's (and possibly other post types' and/or taxonomies') rewrite rules:

// Add this after custom_post_agenda() or somewhere else where appropriate.
add_filter( 'agenda_rewrite_rules', function( $rules ){
    // Remove all rules which don't have "/agenda/".
    unset( $rules['([^/]+)/page/?([0-9]{1,})/?$'] );
    unset( $rules['([^/]+)/comment-page-([0-9]{1,})/?$'] );
    unset( $rules['([^/]+)/?$'] );

    return $rules;
} );


I forgot to mention that you need to apply the above filter (i.e. <post type>_rewrite_rules) to other post types with the same rewrite slug format (%school%/<post type> like %school%/agenda). So remove the above code from your functions file and use this instead:

function fix_school_rewrite_rules( $rules ) {
    // Remove all rules which don't have "/<post type>/".
    unset( $rules['([^/]+)/page/?([0-9]{1,})/?$'] );
    unset( $rules['([^/]+)/comment-page-([0-9]{1,})/?$'] );
    unset( $rules['([^/]+)/?$'] );

    return $rules;
add_filter( 'agenda_rewrite_rules', 'fix_school_rewrite_rules' );     // for "agenda" CPT
add_filter( 'vacatures_rewrite_rules', 'fix_school_rewrite_rules' );  // for "vacatures" CPT
add_filter( 'schoolgids_rewrite_rules', 'fix_school_rewrite_rules' ); // for "schoolgids" CPT

And don't forget to flush the rewrite rules. And once again, for each CPT, the has_archive should be set to a unique slug.

  • 1
    Hi Sally, this works great, thanks! Didn't know I had to add the rewrite rule for this. But your explanation makes sense :) Thanks again!
    – Loosie94
    Jul 30, 2019 at 7:15
  • It seems that the school name (set by %school%) now redirects to the index.php. It ignores my template (template-school.php) and also the page.php. Any idea why this happens?
    – Loosie94
    Jul 30, 2019 at 14:20
  • Do you actually have a custom taxonomy with the slug school? Can you show the code that you use to register the taxonomy?
    – Sally CJ
    Jul 30, 2019 at 21:57
  • This is the default category taxonomy, renamed (labels only) to school(s). I register this in the custom post types with: register_taxonomy_for_object_type('category', 'agenda');
    – Loosie94
    Jul 31, 2019 at 20:12
  • 1
    Hi Sally, this did the trick! I also didn't see it... Again, thanks a 1000 times!
    – Loosie94
    Aug 1, 2019 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.