I built a plugin for wordpress with custom post types and somewhere along the line I realized that I had to rebuild the way slugs are generated. Originally, I had the cpt making default slugs like new-post-1, new-post-2, etc. I realized this was silly and rewrote the naming convention to create a slug from the post title like it should be. The only issue I have now is that I want to have all the old posts I entered into wordpress use the new naming convention. Is there a function or a way to tell wordpress to rebuild/regenerate the slugs for a particular custom post type.

I found this plugin: http://wordpress.org/plugins/re-slug/

But.. it does not work for cpts

Thanks for the help.


2 Answers 2


I also created a similar approach as was mentioned by @sri, however using $wpdb vs wp_update_post should be more performant and configurable.

 * Reset the slugs on a particular post type to use the default sanatized slugs
 * @param  string  $post_type         filter by post type
 * @param  int $offset                set the paginated post to start
 * @param  boolean $force_guid_update * WARNING * never enable this
 * @example add the following code into your theme's functions.php file, ensure
 * that the desired post type is set when calling wp20140226_reset_slugs('post');
 * Then navigate to wp-admin/options-permalink.php to activate query to reset slugs.
 * Depending on how many posts need to be updated this method may take quite 
 * some time, on a shared host there may be a need to set the $offset argument
 * to limit the amount of time the script runs and use multiple calls by adjusting
 * the offset to progress through the entire record set.
function wp20140226_reset_slugs( $post_type = null, $offset = 0, $force_guid_update = false ){
    global $pagenow, $wpdb;

    if ( $pagenow != 'options-permalink.php' || empty($post_type) )

    $get_post_args = array(
        'post_type' => $post_type, 
        'post_status' => 'any'

    if( $offset == 0 ){
        $get_post_args['posts_per_page'] = -1;
    } else {
        $get_post_args['offset'] = $offset;

    $posts_to_fix = new WP_Query( $get_post_args );

    foreach( $posts_to_fix->posts as $post_to_fix ){
            array( 'post_name' => sanitize_title( $post_to_fix->post_title ) ), 
            array( 'ID' => $post_to_fix->ID ), 
            array( '%s' ), 
            array( '%d' ) 

    // you should really leave this alone (do not set to true unless you need to)
    if( $force_guid_update ){
        $siteurl = trailingslashit( get_option('siteurl') );
        $wpdb->query( "UPDATE {$wpdb->posts} SET guid = CONCAT( '{$siteurl}?p=', ID ) WHERE post_type = {$post_type} OR post_type = 'revision';" );

    add_action('admin_notices', 'wp20140226_reset_slugs_admin_notice');


 * notify the user when the reset slug queries are run
function wp20140226_reset_slugs_admin_notice(){
    <div class="updated">
        <p><?php _e('You have successfully run the reset slugs function, please disable or suffer impact when in the admin.'); ?></p>

wp20140226_reset_slugs('post'); // change this to be your custom post type

source: https://gist.github.com/codearachnid/9243595


The re-slug plugin can be fixed to work with Wordpress 4 and up. Edit line 13 of re-slug.php to read:

$return = str_replace('Edit</button>', 'Edit</button> <button type="button" id="re-slug" class="edit-slug button button-small hide-if-no-js" style="display:inherit;"><a href="#re-slug">Re-slug</a></button>', $return);

My fix isn't very clean but for a first pass it works well enough, including for custom post types. The button is added which allows for the current post to be reslugged with whatever is in the Title field.

This is the only solution I've been able to find for a re-slug for a single post.

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.