0

I've created 2 custom post types like so:

register_post_type(
    'resources',
    theme_build_post_args(
        // $slug, $singular, $plural
        'resources', 'Resource', 'Resources',
        array(
            'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
            'menu_position' => 20,
            'has_archive'   => true,
            'public'        => true,
            'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
      'taxonomies'      => array('tags'),
            // 'rewrite' => array( 'slug' => 'resources' ),
        )
    )
);

register_post_type(
  'video-demos-tours',
  theme_build_post_args(
    // $slug, $singular, $plural
    'video-demos-tours', 'Video Demos & Tours', 'Video Demos & Tours',
    array(
      'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
      'menu_position' => 23,
      'has_archive'     => true,
      'public'          => true,
      'supports'            => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
      'taxonomies'      => array('tags'),
      // 'rewrite' => array('slug' => 'resources'),
    )
  )
);

video-demo-tours shares the same single- template as the resources post type, via this function:

function custom_single_template($single_template) {
  global $post;
  if (in_array($post->post_type, array('video-demos-tours'))) {
    return get_stylesheet_directory() . '/single-resources.php';
  }
  return $single_template;
}

add_filter('single_template', 'custom_single_template');

All posts from resources and video-demos-tours are being shown on /resources

But, when I click into a video-demos-tours post, the URL is /video-demos-tours/post-name. I want it to be /resources/post-name.

To do this, I've tried rewrite:

function custom_post_type_permalink($url, $post) {
    if (in_array($post->post_type, array('resources', 'video-demos-tours'))) {
        return home_url("resources/{$post->post_type}/{$post->post_name}/");
    }
    return $url;
}

add_filter('post_type_link', 'custom_post_type_permalink', 10, 2);

But, it didn't change anything (have flushed permalinks after too).

Any ideas?

Edit

Latest CTP and function:

register_post_type(
  'resources',
  theme_build_post_args(
    // $slug, $singular, $plural
    'resources', 'Resource', 'Resources',
    array(
      'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
      'menu_position' => 20,
      'has_archive'     => true,
      'public'          => true,
      'supports'            => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
      'taxonomies'      => array('tags'),
    )
  )
);

register_post_type(
  'video-demos-tours',
  theme_build_post_args(
    // $slug, $singular, $plural
    'video-demos-tours', 'Video Demos & Tours', 'Video Demos & Tours',
    array(
      'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
      'menu_position' => 23,
      'has_archive'     => true,
      'public'          => true,
      'supports'            => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
      'taxonomies'      => array('tags'),
      'rewrite' => array( 'slug' => 'resources' )
    )
  )
);

add_action( 'parse_request', 'wpse418900_parse_request' );

function wpse418900_parse_request( $wp ) {
  $post_types = array( 'resources', 'video-demos-tours' );
  if ( preg_match( '#^resources/#', $wp->request ) &&
    isset( $wp->query_vars['post_type'], $wp->query_vars['name'] ) &&
    in_array( $wp->query_vars['post_type'], $post_types )
  ) {
    $wp->query_vars['post_type'] = $post_types;
  }
}

I have flushed permalinks via settings but my posts still sit under /video-demos-tours/video-post/

To clarify (incase misunderstood), I want my video posts to sit under the resources CPT slug, as in /resources/video-post/.

Edit 2 ##:

Full list of CPTs and taxonomies:

public function post_types_taxonomies() {

  register_post_type(
    'resources',
    theme_build_post_args(
      // $slug, $singular, $plural
      'resources', 'Resource', 'Resources',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 20,
        'has_archive'   => true,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
      )
    )
  );

  register_post_type(
    'blogs-and-news',
    theme_build_post_args(
      // $slug, $singular, $plural
      'blogs-and-news', 'Blogs and News', 'Blogs and News',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 21,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/blogs-and-news'),
      )
    )
  );

  register_post_type(
    'case-studies',
    theme_build_post_args(
      // $slug, $singular, $plural
      'case-studies', 'Case study', 'Case studies',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 22,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'case-studies', 'with_front' => false),
      )
    )
  );

  register_post_type(
    'video-demos-tours',
    theme_build_post_args(
      // $slug, $singular, $plural
      'video-demos-tours', 'Video Demos & Tours', 'Video Demos & Tours',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 23,
        'has_archive'   => true,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array( 'slug' => 'resources/video-demos-tours' )
      )
    )
  );

  register_post_type(
    'whitepapers',
    theme_build_post_args(
      // $slug, $singular, $plural
      'whitepapers-and-reports', 'Whitepaper & Reports', 'Whitepapers & Reports',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => null,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/whitepapers-and-reports'),
      )
    )
  );

  register_post_type(
    'solution-briefs',
    theme_build_post_args(
      // $slug, $singular, $plural
      'solution-briefs', 'Solution brief', 'Solution briefs',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 25,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/solution-briefs'),
      )
    )
  );

  register_post_type(
    'user-guides',
    theme_build_post_args(
      // $slug, $singular, $plural
      'user-guides', 'User guide', 'User guides',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 26,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/user-guides'),
      )
    )
  );

  register_post_type(
    'product-briefs',
    theme_build_post_args(
      // $slug, $singular, $plural
      'product-briefs', 'Product brief', 'Product briefs',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 27,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/product-briefs'),
      )
    )
  );

  register_post_type(
    'webinars-whiteboards',
    theme_build_post_args(
      // $slug, $singular, $plural
      'webinars-whiteboards', 'Webinars & Whiteboards', 'Webinars & Whiteboards',
      array(
        'menu_icon' => get_template_directory_uri().'/assets/build/vectors/backend-icon.svg',
        'menu_position' => 28,
        'has_archive'   => false,
        'public'        => true,
        'supports'          => array('title', 'revisions', 'thumbnail', 'editor', 'author'),
        'taxonomies'        => array('tags'),
        'rewrite' => array('slug' => 'resources/webinars-whiteboards'),
      )
    )
  );

}


function themes_taxonomy() {

  $post_types = array('resources', 'blogs-and-news', 'case-studies', 'video-demos-tours', 'whitepapers', 'solution-briefs', 'user-guides', 'product-briefs', 'webinars-whiteboards');

  $taxonomy_args = array(
      'hierarchical'       => true,
      'public'             => true,
      'rewrite'            => array('slug' => 'resources/tag'),
      'label'              => 'Tags',
      'query_var'          => true,
      'show_admin_column'  => true,
      'publicly_queryable' => true,
  );

  foreach ($post_types as $post_type) {
    register_taxonomy(
      'tags', // taxonomy name/slug
      $post_type, // attach to this post type
      $taxonomy_args
    );
  }

}

theme_build_post_args():

public function buildPostLabels( $singular = 'Post', $plural = 'Posts' )
{
    if($singular != 'Post' && $plural == 'Posts' ) {
        $plural = $singular . 's';
    }


    $labels = array(
        'name'               => _x($plural, 'post type general name', 'lightbox'),
        'singular_name'      => _x($singular, 'post type singular name', 'lightbox'),
        'menu_name'          => _x($plural, 'admin menu', 'lightbox'),
        'name_admin_bar'     => _x($singular, 'add new on admin bar', 'lightbox'),
        'add_new'            => _x('Add New', $singular, 'lightbox'),
        'add_new_item'       => __('Add New ' . $singular, 'lightbox'),
        'new_item'           => __('New ' . $singular, 'lightbox'),
        'edit_item'          => __('Edit ' . $singular, 'lightbox'),
        'view_item'          => __('View ' . $singular, 'lightbox'),
        'all_items'          => __('All ' . $plural, 'lightbox'),
        'search_items'       => __('Search ' . $plural, 'lightbox'),
        'parent_item_colon'  => __('Parent ' . $plural . ':', 'lightbox'),
        'not_found'          => __('No ' . strtolower($plural) . ' found.', 'lightbox'),
        'not_found_in_trash' => __('No ' . strtolower($plural) . ' found in Trash.', 'lightbox'),
    );


    return $labels;
}

public function buildPostArgs( $slug, $singular = 'Post', $plural = 'Posts', $args = array() )
{
    $args = wp_parse_args($args, $this->postDefaults);

    $args['rewrite']['slug'] = $slug;

    $args['labels'] = $this->buildPostLabels($singular, $plural);

    return $args;
}

function theme_build_post_args( $slug, $singular = 'Post', $plural = 'Posts', $args = array() )
{
    $builder = new theme_PTTaxArgBuilder;
    return $builder->buildPostArgs($slug, $singular, $plural, $args);
}

1 Answer 1

1

You were getting /video-demos-tours/post-name instead of /resources/post-name because the following line in your theme_build_post_args function is setting the rewrite slug to the post type slug (video-demos-tours):

$args['rewrite']['slug'] = $slug;

So you should fix that, but as for how, that is up to you.


But then, although fixing that would give you the permalink structure you preferred (e.g. https://example.com/resources/video-post/), visiting the URL of a post in the other CPT (resources) would display a 404 error because the rewrite rules for video-demos-tours now have a higher priority than the ones for the resources CPT.

Therefore, you should actually use a different/unique rewrite slug which is not already in use by another post type.

  • resources/video-demos-tours can be used, but the post type must be registered before the resources CPT.

If, however, you must share the same rewrite slug between two or more of your CPTs, then one easy way without having to add custom rewrite rules, is by using the parse_request hook like so:

add_action( 'parse_request', 'wpse418900_parse_request' );
function wpse418900_parse_request( $wp ) {
    // Define the post types which share the same rewrite slug.
    $post_types = array( 'resources', 'video-demos-tours' );

    // If the URL path (i.e. $_SERVER['REQUEST_URI']) begins with /resources/
    // as in https://example.com/resources/video-post/, then we'd modify the
    // post_type value so that WordPress will "choose" from one of the above
    // post types.
    if ( preg_match( '#^resources/#', $wp->request ) &&
        isset( $wp->query_vars['post_type'], $wp->query_vars['name'] ) &&
        in_array( $wp->query_vars['post_type'], $post_types )
    ) {
        $wp->query_vars['post_type'] = $post_types;
    }
}

It worked well for me on my WordPress v6.3.1 site, but:

  1. Remember that the solution will result in a slight overhead when loading the single post page.

  2. The same slug (post_name) can be shared among posts in different post types, however, you would want to always use a unique slug with your posts if the post type is sharing the same rewrite slug.

6
  • PS: Don't forget to flush the rewrite rules, i.e. re-save your permalinks, and before doing so, you should remove the add_filter('post_type_link', 'custom_post_type_permalink', 10, 2); from your code.
    – Sally CJ
    Commented Sep 23, 2023 at 16:15
  • Hi Sally, thanks for the insight. I've tried adjusting my code to follow your above approach, but it still yields the same approach. I've edited my question to showcase the CPT declaration and the rewrite. I've also tried 'with_front' => false. Just want to make sure I'm not misunderstanding your answer.
    – Freddy
    Commented Sep 23, 2023 at 21:57
  • Do you have any taxonomies, and/or other CPTs other than the two in question, where the rewrite base/slug is exactly resources or that it begins with a resources/? Have you already tried deactivating all plugins (for a while) and did the same issue persist? You should also now add to your question the code for the theme_build_post_args function.
    – Sally CJ
    Commented Sep 24, 2023 at 0:15
  • I have 9 CPTs in total and 1 custom taxonomy. None which are exactly resources, but they do being with resources/. I've updated my question to showcase all the CPTs, taxonomies and also theme_build_post_args. Have also tried it with plugins disabled and flushing permalinks after.
    – Freddy
    Commented Sep 24, 2023 at 12:07
  • Hi Sally, following up on the above, the issue is definitely in theme_build_post_args or a related function as when I created the CPT without theme_build_post_args and added the rewrite and parse request as you've mentioned in your answer, it started to work. Apologies for not seeing so sooner and thanks me helping me identify it!
    – Freddy
    Commented Sep 24, 2023 at 17:10

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.