Modifying a WordPress custom post type archive URL

I have two custom post types:

  • Programs, which have the URL structure: /program/[program-name]/
  • Episodes, which have the URL structure: /program/[program-name]/episode/[episode-name]

Episodes use a custom field to tell WordPress which program it belongs to. I’ve got this part working just fine.

However, the program page shows only basic information about the program and three featured episodes. I need to create an archive page for each program that lists all the episodes.

Based on how I’ve set things up, I believe I need an archive page for episodes that use the following URL structure: /program/[program-name]/episodes. I know I can create a file called archive-episodes.php to get started. However, I’m having trouble with determining how to modify the URL to suit my needs, especially in light of what I’ve already done.

Here are the functions I’ve used to accomplish what I have so far:

// Create the custom post types

function create_cpts() {
  // Programs
  register_post_type('programs',
    array(
      'labels' => array(
        'name' => __( 'Programs' ),
        'singular_name' => __( 'Program' ),
        'edit_item' => __( 'Edit Program' ),
        'add_new' => __( 'Add New Program' ),
        'add_new_item' => __( 'Add New Program' )
      ),
      'public' => true,
      'has_archive' => true,
      'rewrite' => array(
        'with_front' => false,
        'slug' => 'program'
      ),
      'taxonomies' => array('program-category'),
      'supports' => array('thumbnail', 'title', 'editor', 'excerpt'),
      'menu_position' => 6,
      'menu_icon' => 'dashicons-video-alt2'
    )
  );

  // Episodes
  register_post_type('episodes',
    array(
      'labels' => array(
        'name' => __( 'Episodes' ),
        'singular_name' => __( 'Episode' ),
        'edit_item' => __( 'Edit Episode' ),
        'add_new' => __( 'Add New Episode' ),
        'add_new_item' => __( 'Add New Episode' )
      ),
      'public' => true,
      'has_archive' => false,
      'rewrite' => array(
        'with_front' => false,
        'slug' => 'program/%program%/episode'
      ),
      'supports' => array('thumbnail', 'title', 'editor', 'excerpt'),
      'menu_position' => 7,
      'menu_icon' => 'dashicons-media-video'
    )
  );
}
add_action( 'init', __NAMESPACE__ . '\\create_cpts' );

// Custom program permalink for episodes
function add_directory_rewrite() {
  global $wp_rewrite;
  add_rewrite_tag('%program%', '(.+)');
  add_rewrite_rule('^program/(.+)/episode/(.+)/', 'index.php?p=$matches[2]&program=$matches[1]', 'top');
}
add_action('init', __NAMESPACE__ . '\\add_directory_rewrite');

function episode_rewrite($permalink, $post, $leavename) {
  if ($post->post_type == 'episodes') {
    if ($program = get_field('program', $post->ID)) {
      $program = $program->post_name;
    } else {
      $program = 'default';    
    }

    return str_replace('%program%', $program, $permalink);
  } else {
    return $permalink;
  }
}
add_filter('post_type_link', __NAMESPACE__ . '\\episode_rewrite', 11, 3);

Any help or direction would be greatly appreciated. Thanks.

So, first thing, this is very much a standard WP question and probably belongs more on https://wordpress.stackexchange.com/

With that being said, is there any reason Programs needs to be a CPT? I would assume that you’re just using that for sorting of episodes. I would consider making Programs a taxonomy which Episodes could tag, I think that would be much more straight forward. Perhaps you need a dedicated page for the programs, in which case ACF could probably fill that out for you. Unfortunately WP is not great at posts to posts, and generally requires a plugin or extra code.

Rewrites would probably get more help from a more dedicated WP forum though.

1 Like

I actually have this question on StackOverflow as well, but decided to put it here because this community seems a little more helpful, responsive and I’m using Sage 8. But you’re probably right.

I decided to set up Programs as a custom post type for several reasons:

  1. Programs have their own custom taxonomy, somewhat similar to categories.
  2. Programs need their own dedicated pages that are easily admin editable, particularly when swapping out featured episodes.
  3. I’m using a flexible content system powered by ACF Pro, which basically powers the majority of the site. Applying this system to a programs taxonomy wouldn’t have worked as well.

I’ve started using CPT UI for expediencies sake. It should have the options to do what you want.

Instead of using archive-episodes.php you can create the new WordPress custom post type where you should call your /program/ and /episode/ post type using the fetch post type function and merge all the content together.

For creating a custom taxonomy you have to add this code in functions.php

add_action( 'init', 'create_cw_hierarchical_taxonomy', 0 );
//create a custom taxonomy name
function create_cw_hierarchical_taxonomy() {
$labels = array(
'name' => _x( 'Topics', 'taxonomy general name' ),
'singular_name' => _x( 'Topic', 'taxonomy singular name' ),
'search_items' => __( 'Search Topics' ),
'all_items' => __( 'All Topics' ),
'parent_item' => __( 'Parent Topic' ),
'parent_item_colon' => __( 'Parent Topic:' ),
'edit_item' => __( 'Edit Topic' ),
'update_item' => __( 'Update Topic' ),
'add_new_item' => __( 'Add New Topic' ),
'new_item_name' => __( 'New Topic Name' ),
'menu_name' => __( 'Topics' ),
);
// taxonomy register
register_taxonomy('topics',array('post'), array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'topic' ),
));
}

For further reference I would like to suggest a WordPress custom taxonomy tutorial that will help you to implement the whole task.