Skip to content

WordPress – Replace post name slug with post ID in Custom Post Types

Here is a way to replace the post slug with the post ID in a custom post type permalink structure.




Assuming the post type already exists with

'rewrite' => array('slug' => 'some-type')
 * Add new rewrite for post type
 * Add permalink structure
function _post_type_rewrite() {
    global $wp_rewrite;
    // Set the query arguments used by WordPress
    $queryarg = 'post_type=some-type&p=';
    // Concatenate %cpt_id% to $queryarg (eg.. &p=123)
    $wp_rewrite->add_rewrite_tag( '%cpt_id%', '([^/]+)', $queryarg );
    // Add the permalink structure
    $wp_rewrite->add_permastruct( 'some-type', '/some-type/%cpt_id%/', false );
add_action( 'init', '_post_type_rewrite' );
 * Replace permalink segment with post ID
function _post_type_permalink( $post_link, $id = 0, $leavename ) {
    global $wp_rewrite;
    $post = get_post( $id );
    if ( is_wp_error( $post ) )
        return $post;
        // Get post permalink (should be something like /some-type/%cpt_id%/
        $newlink = $wp_rewrite->get_extra_permastruct( 'some-type' );
        // Replace %cpt_id% in permalink structure with actual post ID
        $newlink = str_replace( '%cpt_id%', $post->ID, $newlink );
        $newlink = home_url( user_trailingslashit( $newlink ) );
    return $newlink;
add_filter('post_type_link', '_post_type_permalink', 1, 3);

Refresh permalinks

With thanks


10 years + experience in web development working with lots of different technology.

Published inPHPWordPress


  1. Ash Ash

    I have a custom post type called ‘paper’. I copied your snippet and replaced all instances of ‘some-type’ with ‘paper’, refreshed permalinks and it isn’t working.

    Am I missing something?

    • Just tested this on a site I’m working on. Seems to work fine for me although there was the ampersand before `get_post( $id )` causing a warning which I have now removed.

      Permalinks need to be set to something other than `Plain`

Leave a Reply

Your email address will not be published. Required fields are marked *