Ultimate Web Tips
your Wordpress, jQuery, PHP, MySQL, Linux and CSS guide to a successful website
Read more:

November 8th, 2011

Remove slug from custom post type

Wordpress, by Joakim Ling.

Remove slug from custom post typeIn WordPress 2.9 custom post type was introduced, that opened a new world for many WordPress developers. I’ve come across a painful issue when it comes to removing the slug and not destroying the rewrite rules for other post types. This only concerns those who are using %postname% as permalink structure and want to add a custom post type so that the urls for them are in the same way as normal posts and pages: http://siteurl/%custom_post_type_title%/.

Add custom post type

In this example I’ll add “books” as a custom post type. What we want to achieve is that the urls are http://siteurl/%bookname%/

First we need to have a closer look at what rewrite options we have when we register a new post type with register_post_type.

For my hack to work you need to add a slug and set with_front to false:

array("slug" => "/book", "with_front" => false);

Don’t set the “slug” to “/”, because it overrides other rules and gives post/pages a 404 when you try to access them.

Step 1: Register post type

First we will start with registering our new post type

function register_book_type() {
	register_post_type('books', array(
		'labels' => array(
			'name' => __( 'Books' ),
			'singular_name' => __( 'Book' ),
			'add_new' => __( 'Add New' ),
			'add_new_item' => __( 'Add New Book' ),
			'edit' => __( 'Edit' ),
			'edit_item' => __( 'Edit Book' ),
			'new_item' => __( 'New Book' ),
			'view' => __( 'View Book' ),
			'view_item' => __( 'View Book' ),
			'search_items' => __( 'Search Books' ),
			'not_found' => __( 'No Books found' ),
			'not_found_in_trash' => __( 'No Books found in Trash' ),
			'parent' => __( 'Parent Book' ),
		),
		'public' => true,
		'menu_position' => 5,
		'show_ui' => true,
		'_builtin' => false,
		'_edit_link' => 'post.php?post=%d',
		'capability_type' => 'post',
		'hierarchical' => false,
		'rewrite' => array("slug" => "/book", "with_front" => false),
		'query_var' => "book",
		'supports' => array('title', 'editor', 'thumbnail')
	));
}
add_action('init', 'register_book_type');

If you now add a book it will get the url http://siteurl/book/%post_title%/, so far so good.

Step 2: Add rewrite rule

We need to add a new rewrite rule to make the system recognise books without the slug /book/.
It’s important that you hook the rewrite rule after the theme setup is finished, otherwise it will be overwritten.

in this case, the regular expression to look for anything in the root will be “(.*?)$”, basically look for anything.
Our redirection is the query ‘index.php?book=$id’.

function book_rewrite_rule() {
	add_rewrite_rule('(.*?)$', 'index.php?book=$matches[1]', 'top');
}
add_action('after_theme_setup', 'book_rewrite_rule');

Remember to flush your rules, 2 easy ways to do this. Access the Permalink page from WordPress Admin or call “flush_rewrite_rules” anywhere once from your theme or plugin.

flush_rewrite_rules();

This has to be done each time you change something in your permalink structure or rewrite rules.

Your book posts will now be accessible from http://siteurl/%post_title%/ as well as http://siteurl/book/%post_title%/ and we don’t want to have two links to the same post.

Step 3: .htaccess

Add a rule to redirect /book/%post_title%/ to /%post_title%/ in .htaccess

RewriteRule ^book/(.+)$ /$1 [R=301,L]

Step 4: Fix the permalink that is shown when editing

When adding a new book in this case or editing an old one, the permalink will still show “Permalink: http://siteurl/book/%post_title%/” and View will also go to the url with the slug. Here is the final piece to hack the slug away

function remove_slug($permalink, $post, $leavename) {
	$permalink = str_replace(get_bloginfo('url') . '/book' , get_bloginfo('url'), $permalink);
	return $permalink;
}
add_filter('post_type_link', 'remove_slug', 10, 3);

That’s all! I’m sure this could be done in a million ways but this is the only way I got it to work. Please comment if you find any difficulties or improvements.

Download the full plugin from from wordpress.org

Rank Tracker Wordpress Plugin

See which keywords are really bringing you traffic. Use the information to improve your sites income, download plugin


Themedy Thesis & Genesis Skin Club

Themedy is a premium skin marketplace offering quality child themes for the some of the most popular Wordpress frameworks like Thesis & Genesis. Read more

Back Top

Club World Casinos
  • http://www.kurageart.eu Kurageart

    very nice… but i’m wondering if is possible to append somehow the .html suffix , in order to match the old permalinks structure i have on my site …
    right now , i’m using your plugin remove-slug-from-custom-post-type very nice job :)

    • Anonymous

      Thanks mate, about the .html, do I understand correctly that you want /%postname%.html instead of /%postname%/ ? If so I can make a setting for it with next update

      • Anonymous

        Yes, exactly.. I think think is an important feature…
        If you can give me some directions to fix it manually, waiting for your upgrade, that will be really great! :)

        • Anonymous

          Update the plugin and you will find under Settings tab an option to add any suffix to get the structure you looking for. Please let me know if it works for you

  • dog$tar44

    I am trying to use your plugin, everything works fine in terms of the links generated by the Custom Post Type in the dashboard.  But when I click on View post or View page I get a 404.  Do you have any ideas?  I assume it is to do with the htaccess file.

  • Anonymous

    yes, exactly, I would like /%postname%.html , to match the old structure…but if you can give me any tips on how to do that manually in the meanwhile that you are making the upgrade, that will be great… for now i kind of fixed the thing with another plugin, called Permalink Editor .. but that’s not really working as i want..

  • Anonymous

    I found the issue, will release an update shortly.

  • Jason

    So i needed to deactivate the plugin because I get 404 or redirects to regular blog posts title the same. Huge problem – the redirects set won’t go away and none of my custom posts will load. PLEASE HELP!

  • Stefan Leitner

    HEY HEY -> YOU ARE MY HERO!!
    I wasted hours of searching. 
    Your solution works!!

    See on: http://www.stefanleitner.com

  • Sam

    One feature request for the plugin would be the ability to select specific cpts to apply the ‘remove slug’ functionality via a settings page. In my case I only needed one cpt effected, however the plugin works great.

    • http://eliteeternity.com/ eliteeternity

       What the heck? I’m trying to get it to remove both of the slugs from two different post types, and it only removes one. Looks like we have opposite problems.

      +1 for this feature request though.

      Great plugin & thank you for developing it.

  • Jared

    this is very interesting. I’m working on some bbpress 2.x customization and this is exactly the type of information i need. this plugin breaks bbpress 2.x outright but it’s on the right track of what i’m trying to do, hope to get in touch with you soon, ty

  • Johan

    Didn´t get it to work. Followed the instructions except that I use: ’hierarchical’ => true, Got Error 404 even if I tried over and over again.

    • http://www.ultimatewebtips.com Joakim Ling

      Did you try the plugin, it has some additional code that could work for you

  • http://daltonrooney.com Dalton

    This is a brilliant bit of code, but I wonder if it can be adapted to work in a WordPress multisite environment? It seems to work on my root blog but not on any of the subsites. Would love to get this working…

    Cheers,Dalton

    • http://www.ultimatewebtips.com Joakim Ling

      haven’t thought about it, but dont think it would be that hard to implement. will have a closer look on that

  • Zelol

    Thanks for the plugin, but i’m thinking, do you can implement a remove slug from custom categories?

    • http://www.ultimatewebtips.com Joakim Ling

      you could say that. but what it really does is to creates new rules so only the post title is in the url.

  • Tsun

    Thanks for this great idea and bunch of code…the slug is remove but unfortunately a 404error page displayed ? i wonder if it comes from the php template used ? before, we can handle the custom post with single-book.php, but after this it does not handle the post. Any idea someone please ?

    • http://www.ultimatewebtips.com Joakim Ling

      Are you calling the function “flush_rewrite_rules” in your theme or plugins? It could be it

  • http://nakedink.us Edbury Enegren

    Is it possible to alter the slug of an existing custom post type (e.g. one already registered by a plugin)?

    Not necessarily remove it, just change the slug – the process seems similar.

    • http://www.ultimatewebtips.com Joakim Ling

      Can’t you just alter the slug or make a rewrite rule in .htaccess? I guess would be pretty easy to add custom slug for all custom posts.

      • http://nakedink.us Edbury Enegren

        Found an answer for doing it via WP here: http://wordpress.stackexchange.com/questions/41988/redeclare-change-slug-of-a-plugins-custom-post-type

  • Ediboy Ilagan

     Hi,

    I’m having this error when i try to add a portfolio (custom post type) and it’s not working 404 error.

    Remove Slug Custom post type error!
    .htaccess is not writable, please add following lines to complete your installation:

    RewriteRule ^/(.+)$ /$1 [R=301,L]
    RewriteRule ^portfolio/(.+)$ /$1 [R=301,L]

    When I check my htaccess here’s what I found. It’s already written in my htaccess except it has “acf” in the first rewrite.

    # BEGIN REMOVE SLUG CUSTOM POST TYPE RULES
    RewriteRule ^acf/(.+)/$ /$1 [R=301,L]
    RewriteRule ^portfolio/(.+)/$ /$1 [R=301,L]
    # END REMOVE SLUG CUSTOM POST TYPE RULES

    I try to change It and put the code that the error suggested and still having error after I refresh the page.

    Thanks in advance

    • http://www.ultimatewebtips.com Joakim Ling

      Strange, never happen before. I guess you dont have a custom post type named “acf” either. Would need a closer look on your WordPress setup. Can you send me your contact details to info@ultimatewebtips.com please?

      • http://eliteeternity.com/ eliteeternity

         I just barely started having this problem as well. Any chance you have any solutions?

        My htaccess is saying:

        # BEGIN REMOVE SLUG CUSTOM POST TYPE RULES
        RewriteRule ^products/(.+)/$ /$1 [R=301,L]
        RewriteRule ^/(.+)/$ /$1 [R=301,L]
        # END REMOVE SLUG CUSTOM POST TYPE RULES

        and i’m getting this error message:

        Remove Slug Custom post type error!
        .htaccess is not writable, please add following lines to complete your installation:
        RewriteRule ^products/(.+)$ /$1 [R=301,L]
        RewriteRule ^slide/(.+)$ /$1 [R=301,L]

        • http://eliteeternity.com/ eliteeternity

           Oddly enough, I see the error, but a second glance shows everything working just fine as far as URL’s are concerned.

          The error disappears after publishing the post. Just comes back every time.

          Minor annoyance, but functionality still exists.

          Thanks again for the plugin. Lifesaver!

          • http://receptizakolace.net/ Kolači

            Same red error is shown at my page too :( did you find a solution for this?

          • http://eliteeternity.com/ eliteeternity

            I still get the red error, but I locked my .htaccess file once I got the config that worked for me. That might help.

          • http://receptizakolace.net/ Kolači

            thanks for answering me. :)
            I tried everything..nothing helps…My client wants me to remove it and I don’t know what is the cause. Any thoughts from developer?

      • Christinarule

        Hi, 
         I’m having the same exact problem. any suggestions?

  • Dustypants

    Your plugin seems to work for cpt’s that are non-hierarchical.  I have a hierarchical cpt structure, and all works fine for the root cpt pages/posts in the hierarchy, but for child pages, I get 404.  I will dig in to see if I can identify the issue, but if you have any immediate insights, it would be greatly appreciated!  Thanks for the plugin!

    • Dustypants

      Update:
      So the cpt child pages show up fine if I remove its parent from the url. 
      example:  www.foo.com/{cpt-parent}/{cpt-child}/ = 404
                      www.foo.com/{cpt-parent}/ = OK
                      http://www.foo.com{cpt-child}/ = OK
      I’m thinking its an issue with the rewrite rule.

      • Dustypants

        Okay, I’ve resolve the issue with a small modification to your plugin.  The rewrite rules were not being created properly for hierarchial cpt’s.  I added “, {$wpdb->posts}.post_parent” to the query in the rewrite_rules() function, along with a condition to your foreach loop (which can be eliminated, but I kept it in for ease of readablility).  To top it off, I added a recursive function to build the regex pattern for the hierarchy.  Here is the code with my changes…  I hope this helps!

        public function rewrite_rules($flash = false) {  global $wp_post_types, $wpdb;  $suffix = get_option(‘uwt_permalink_customtype_suffix’);  foreach ($wp_post_types as $type=>$custom_post) {   if ($custom_post->_builtin == false) {    $querystr = “SELECT {$wpdb->posts}.post_name, {$wpdb->posts}.post_parent        FROM {$wpdb->posts}         WHERE {$wpdb->posts}.post_status = ‘publish’              AND {$wpdb->posts}.post_type = ‘{$type}’             AND {$wpdb->posts}.post_date get_results($querystr, OBJECT);    foreach ($posts as $post) {      if($post->post_parent > 0) {      $regexStr = $this->build_regex($post);      $regex = (!empty($suffix)) ? $regexStr . “/{$post->post_name}\.{$suffix}$” : $regexStr . “/{$post->post_name}$”;      add_rewrite_rule($regex, “index.php?{$custom_post->query_var}={$post->post_name}”, ‘top’);     } else {      $regex = (!empty($suffix)) ? “{$post->post_name}\.{$suffix}$” : “{$post->post_name}$”;      add_rewrite_rule($regex, “index.php?{$custom_post->query_var}={$post->post_name}”, ‘top’);      }    }   }  }  if ($flash == true)   flush_rewrite_rules(false); } // a recursive function to build the path of the cpt’s hierarchy used in the regex pattern  private function build_regex($post) {  $parent = get_post($post->post_parent);  if($parent->post_parent > 0)   $str .= $this->build_regex($parent) . ‘/’ . $parent->post_name;  else   $str .= $parent->post_name;  return $str; }

        • http://www.ultimatewebtips.com Joakim Ling

          Thanks Dustypants, will have a look at it and try it before I update the plugin

  • wikicms

    Hi. I’ll try to use this example, but not working. If I used plugin, working fine. But by default plugin remove slug from all custom post type. How I can remove slug from one CPT, eg. ‘topic’? 

    • http://twitter.com/Espo_74 Espo

      wikicms–did you figure out how to get this to work properly? I am looking for what sounds like the same solution as you and running into the same problems

  • Max

    I’m having a weird issue with your plugin (which I think might be related to the fact that the urls are using japanese characters, but I’m not 100% sure).

    When you are on the homepage (http://xn--ddke8bye7a6c5851dq3icj3e.jp/)
    and click on one of the links in the top navigation (all links listed there, are permalinks to custom post type entries) it redirects just fine to the desired post, but when entering the url directly into the url bar, he will redirect directly to the homepage.

    Not exactly sure what causes the issue and was wondering if you or someone else stumbled upon a similar problem so far.

    Regards,
    Max

  • http://receptizakolace.net/ Kolači

    One of most usefule plugins ever! Thanks!

  • http://receptizakolace.net/ Kolači

    thanks for answering me :)
    i knew that, but my client is annoyed with that message, and I don’t know what is the cause.

    I tried re-install but it doesn’t help. 
    And..while plugin is deleted old URL (without slug) still works… any words from developer?

  • Pingback: some cool links which helps you to make you full programmer | myjunk.in

  • Mohamedrias

    Hi,
    Its giving me 404 page errors :(
    Please help me. I am using Woothemes content builder to create the custom post type. So how to remove slug manually..

  • http://twitter.com/akemola Sergio Simarro

    Two things in order to make the code work without the plugin:
    1. The action name for Step 2 is called: after_setup_theme http://codex.wordpress.org/Plugin_API/Action_Reference/after_setup_theme

    2. I was able to make it working not calling the action for Step 2, so code keeps as follows:

    add_rewrite_rule(‘(.*?)$’, ‘index.php?book=$matches[1]‘, ‘top’);
    flush_rewrite_rules();

    function remove_slug($permalink, $post, $leavename) {
        $permalink = str_replace(get_bloginfo(‘url’) . ‘/book’ , get_bloginfo(‘url’), $permalink);
        return $permalink;
    }
    add_filter(‘post_type_link’, ‘remove_slug’, 10, 3);

    Thanks Joakim for helping me.

    • http://twitter.com/Espo_74 Espo

      Sergio–do you mind posting your full code here or on something similar to pastebin ?

  • Tedy

    I’m also getting 404 error:( Help please

    • Ted

      Hi. Thanks For The plugin ! The plugin works perfect for old “product-review” specific posts. But when creating a new post I’m getting a 404 error  :( 

      • http://twitter.com/Espo_74 Espo

        Ted–did you find a patch/work-around for this? I am having the same problem.

  • happylife

    An useful plugin. But function “Permalink custom type suffix” doesn’t work as expected.

    Permalink settings: “/%postname%/
    post url: mysite/postname/
    custom post type: mysite/postname/

    ———————-

    Use “Permalink custom type suffix” function

    Permalink settings: “/%postname%.html

    post url: mysite/postname.html

    custom post type: mysite/postnam.html

    Now, the last letter of post name is lost. Some custom posts are accessed, some aren’t. I don’t know how to fix this. Any ideas ?

    • happylife

       I find that the lost letter is the reason why I can’t view custom post type. I can view them after adding the lack letter in url. Anyone know how to fix this when Permalink settings is “/%postname%.html”

      • happylife

        I just made it by using “Custom Post Type Permalinks” plugin with “Remove slug from custom post type” at the same time to get /%postname%.html work.

  • http://twitter.com/Espo_74 Espo

    I am having a similar issue with the plugin not working with new posts added, only already existing ones. Any ideas on this?

    Thank you so much…I have been getting beat around the head with this for a long time….glad to see someone got it working!

    • brokenflipside

      I am having the same problem right now.

    • Aahz

      Has anyone found a solution to this?  I’m having the same issue – old posts work, new posts get 404

  • http://twitter.com/Espo_74 Espo

    now ALL of my permalinks are broken and only the default WP structure works.

    • Social Blogsite

      Same to me, My CPTs work fine but the rest are broken. 

      Have you figured out what the issue was?

      I can tell you where the error is not:

      I used a different technique to prevent the /book/%post_title%/ and /%post_title%/ duplicated issue by filtering post_type_link and term_link, rather than a .httaccess, and the error still happens (so the .htaccess redirects are not to blame)

      Also, I used something like %book% as the slug of my CPT, and later got it replaced by the above filters.

      As soon as I remove the %% from the slug, everything works.

      I tried custom permastructs, modifying the order of the rewrites (top or bottom), different ways to accomplish the same (replacin the CPT slug by the term in the permalink) but as soon as any technique works, all the pages/posts permalinks break.

      It must be something with telling WP to TRY the default permalink structures when our didn’t work, or the other way around.

      One thing I haven’t tried yet, is to re-register the normal pages and posts AFTER my rewrite rules.

      I’d almos swear it worked at some point before I made my wp installation a MU one.

  • http://www.dmcworks.com/ Devin Columbus

    Great plugin! Is there a way to include an “ignore” rule so that the “/blog/” slug is NOT removed? This way, all blog posts remain under the permalink structure of “/blog/my-blog-post/”