I would like to dynamically insert post IDs into their URL slugs.

What I have

  • Code that strips out the prepended post name (WC's '/product')
  • Code that generates the URL that I want

What I want

  • URLs that look like: ~/category-name/hey-slug-12903/
  • The reason for this is I have loads of products that are only different because of the category within which they reside...as such I want to automatically insert the ID within the subdirectory to prevent any duplicate weirdness.
  • I do not want IDs to be appended as superfluous subdirectories like: ~/category-name/hey-slug/12903/ or ~/category-name/12903/hey-slug/

My Issue

  • I'm getting 404s (I've flushed rewrite rules)
  • I don't know if I also need to use add_rewrite_rule();

My Code:

add_filter( 'post_type_link', 'wpp_remove_slug', 10, 3 );
function wpp_remove_slug( $post_link, $post, $name ) {

    if ( 'product' != $post->post_type || 'publish' != $post->post_status ) {
      return $post_link;
    $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
    $post_link = substr($post_link, 0, -1);
    $post_link = $post_link . "-" . $post->ID . '/';
    return $post_link;

  • Have you tried using the %post_id% and %product_cat% tags in the custom base for the permalink product settings? – birgire Dec 28 '18 at 16:48
  • Yes, I have tried /%product_cat%/%post_id%- in permalink settings, but WP always appends a / ..when I try to remove the slash and make the ID separated by a dash, I get a 404 again. – Ryan Dorn Dec 28 '18 at 17:37

The rewrite argument in register_post_type is limited, but you can define a more complex structure with add_permastruct. The added benefits are that this will generate all the rewrite rules for you, and the new rules will overwrite the originals. You just have to be sure to hook after the post type is registered.

function wpd_woo_product_permastruct(){
            'walk_dirs' => false,
            'with_front' => false
add_action( 'init', 'wpd_woo_product_permastruct', 99 );

And that is, magically, all you need. The rewrite tag replacements will be done for you, so the post_type_link filter won't be needed.

Normally, the absence of a static slug would cause clashes with other rules, but in this case it works because the embedded post ID triggers a more strict match.

What you can't have is the %product_cat% rules without a static slug, which is why we have to set walk_dirs to false. Otherwise, any request for a root page will be overridden by the taxonomy rule, and WordPress will go looking for a term that matches your page slug.

If you do want rules that introduce this ambiguity, you can do something like this answer, where you manually resolve conflicts.

| improve this answer | |
  • Much simpler +1 :) – birgire Dec 29 '18 at 8:11
  • I have a question, i tried this with products using the same slug and WP still appended the -2 (i.e. ~?/cat-1/my-post-12345, ~?/cat-2/my-post-2-12345) is there any way to disable appending the -2? – Ryan Dorn Jan 5 '19 at 21:43
  • hmm, might need to rethink the approach. wp_unique_post_slug will still enforce unique slugs, this is separate from permalink structure. there's a filter of the same name that you can use to manually override it. but then why not just skip adding post ID onto the end and use the unique slugs wp generates? – Milo Jan 5 '19 at 22:01
  • hello @Milo can you check please, this question wordpress.stackexchange.com/questions/376279/… I've done something similar, but the post types stop working.That is to say, all the rules I have set work, but the others do not. – jcarlosweb Oct 11 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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