Custom post type URL with post ID that allows archiving and paging

I’m having a difficult time trying to get my custom post types URLs to work correctly. Every solution I find has crippled another part that needs to work. What I am trying to accomplish is domain.com/post_type/post_id/post_name.

What I have that works for everything except archives is:

Read More
register_post_type('post-type',
    array(
    'rewrite' => array(
    'slug' => 'post-type/%post_id%',
    'with_front' => false,
    'pages' => true,
    'ep_mask' => 1 
    )
))

Then I have:

add_filter('post_type_link', 'custom_post_type_link', 1, 3);
function custom_post_type_link($post_link, $post = 0, $leavename = false) {

    if ($post->post_type == 'post-type')) {
        return str_replace('%post_id%', $post->ID, $post_link);
    } else {
        return $post_link;
    }
}

So I’m trying to find a way to get domain.com/post_type to work. It currently throws a 404.

I know that if I remove the filter and /%post_id% from my rewrite that the archive will work. From there I’ve tried adding a rewrite rule:

add_action( 'init', 'custom_rewrites_init' );
function custom_rewrites_init(){
    add_rewrite_rule(
        'post-type/([0-9]+)?$',
        'index.php?post_type=post-type&p=$matches[1]',
        'top' );
}

Doing it this way the URL wont redirect if someone types in domain.com/post_type/post_id and domain.com/post_type/post_id/post_name/2 doesn’t work.

Anyone know of the best way to do this?

Related posts

3 comments

  1. Your code/solutions is pretty good. You use slug param in a very smart way, so WordPress automatically creates correct permastruct for this CPT.

    The only thing you’re missing, I guess, is has_archive param. It’s default value is false and you don’t set it to true. So WordPress doesn’t create archive links/pages for your CPT.

    has_archive (boolean or string)

    (optional) Enables post type archives.

    Will use $post_type as archive slug by default. Default: false Note:
    Will generate the proper rewrite rules if rewrite is enabled. Also use
    rewrite to change the slug used.

    If you do this, WordPress will create rewrite rules for archive pages. There will be a tiny problem. They will contain %post_id% in them. But it’s pretty easy to correct. You just have to add this code after your register_post_type call:

    global $wp_rewrite;
    
    $new_rules = array();
    foreach ( $wp_rewrite->extra_rules_top as $key => $rule ) {
        echo $key;
        if (strpos($key, 'post-type/%post_id%/') === 0 ) {
            $new_rules[ str_replace('%post_id%/', '', $key) ] = $rule;
            unset( $wp_rewrite->extra_rules_top[$key] );
        }
    }
    $wp_rewrite->extra_rules_top = $wp_rewrite->extra_rules_top + $new_rules;
    

    It will repair rules for archive pages created by WordPress. It’s clean solution – it doesn’t leave any mess behind, and it takes care of all rules for archive page (feeds, etc.)

  2. You could try to add this code snippet:

    add_filter( 'rewrite_rules_array', 'custom_rewrite_rules_array' );
    function custom_rewrite_rules_array( $rules ) {
            $newrules = array();
            $newrules['^post-type/page/?([0-9]{1,})/?$'] = 'index.php?post_type=post-type&paged=$matches[1]';
            $newrules['^post-type$'] = 'index.php?post_type=post-type';
           return $newrules + $rules;
    }
    

    to add support for domain.com/post-type/ and domain.com/post-type/page/2.

    You just have to remember to save the permalinks.

  3. Have you reset your permalink settings after saving the template file? Before you can use a new permalink like that you must resave your permalink settings in Settings->Permalinks.

Comments are closed.