Search code examples
phpwordpressseo

Limit the size of the existing and new permalink slugs in Wordpress for SEO


I read an article on Google that says for good SEO it is best that the size of the slug in the URL is limited to 5 words.

As I use WordPress the link is assigned automatically to the article title. To redo all the links with just 5 words I would have to spend months editing all the links on my blog.

Would it be possible to do this automatically? There is some function or code for that. I found this code and added it to the function page of my theme and had no results.

See the code:

function pm_limit_slugs_length($uri) {
    $max_words = 5; // If any part of URI contains more than 5 words, the slug will be limited to first 5 words
    $new_title = '';
    $slugs = explode('/', $uri);
    
    for($i=0, $count = count($slugs); $i < $count; $i++) {
        $slug = $slugs[$i];
        $words = explode('-', $slug);
        
        $new_title .= "/";
        if(count($words) > $max_words) {
            $new_title .= implode("-", array_slice($words, 0, $max_words));
        } else {
            $new_title .= $slug;
        }
    }
    
    // Remove trailing slashes
    $new_title = trim($new_title, "/");
    
    return $new_title;
}
add_filter('permalink_manager_filter_default_post_uri', 'pm_limit_slugs_length', 99);
add_filter('permalink_manager_filter_default_term_uri', 'pm_limit_slugs_length', 99);

I found the code here: https://permalinkmanager.pro/docs/filters-hooks/how-to-limit-the-number-of-words-in-wordpress-permalinks/

How can I use it to limit the Wordpress slug size to 5 words?


Solution

  • First, a note on whether it is worthwhile to do this:

    There are literally 100s of factors that affect SEO. You are not expected to implement all of them, and many will not have a big influence overall. In my opinion, doing this is most likely not going to have any significant effect, and it only makes things more difficult for you.

    More importantly, to have any influence on SEO the slug should include your keywords, and if you change them programmatically, there is no way to ensure the slug will include keywords, so you could even do more harm than good.

    FYI, a few versions ago, WP was changed to implement this limit on slugs and then very quickly changed back. That would suggest to me that it might not be very useful or practical.

    However if you still want to do this:

    Limiting the words in new slugs

    The code in your question is from this article, right?: How to limit the number of words in WordPress permalinks or slugs?

    The first example - that you used - is for use with their plugin. The next example (included below) will work in Wordpress without the plugin. This can be added into your functions.php.

    UPDATE: I have incorporated the code to Automatically Remove Short Words From URL into this function to remove short words less than 3 characters, see updated function below.

    <?php  
    /**
     * Trim native slugs
     */
    function pm_trim_native_slug($slug, $post_ID, $post_status, $post_type, $post_parent) {
        global $wpdb;
    
        $max_words = 5; // Limit the number of words to 5; This value can be changed.
        $words = explode('-', $slug);
    
        /* UPDATED CODE TO REMOVE SHORT WORDS */
        $min_word_length = 2;
    
        foreach ($words as $k => $word) {
            if (strlen($word) <= $min_word_length)
                unset($words[$k]);
        }
        /* END OF UPDATED CODE FOR SHORT WORDS */
    
        if(count($words) > $max_words) {
            $slug = implode("-", array_slice($words, 0, $max_words));
    
            // Make the slugs unique
            $check_sql       = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
            $post_name_check = $wpdb->get_var($wpdb->prepare($check_sql, $slug, $post_ID));
    
            if($post_name_check) {
                $suffix = 2;
                do {
                    $alt_post_name = _truncate_post_slug($slug, 200 - (strlen($suffix) + 1)) . "-$suffix";
                    $post_name_check = $wpdb->get_var($wpdb->prepare($check_sql, $alt_post_name, $post_type, $post_ID, $post_parent));
                    $suffix++;
                } while ($post_name_check);
                $slug = $alt_post_name;
            }
        }
    
        return $slug;
    }
    add_filter('wp_unique_post_slug', 'pm_trim_native_slug', 99, 5);
    

    Note that this only works on new slugs, you still need to regenerate the old slugs, or write code to go through the existing slugs to update them.

    Updating existing slugs

    You can add this function to your functions.php to get all your slugs, call the function above to generate a new slug, and then update it in the DB:

    function limit_all_existing_slugs(){
        // get all posts
        $posts = get_posts( array (  'numberposts' => -1 ) );
        
        foreach ( $posts as $post ){
    
            // create the new slug using the pm_trim_native_slug function 
            $new_slug = pm_trim_native_slug($post->post_name, 
                                            $post->ID, 
                                            $post->post_status, 
                                            $post->post_type, 
                                            $post->post_parent);
    
            // only do the update if the new slug is different 
            if ( $post->post_name != $new_slug ){
                wp_update_post(
                    array (
                        'ID'        => $post->ID,
                        'post_name' => $new_slug
                    )
                );
            }
        }
    }
    

    Note that the code above is my own and is untested, so make sure you try it out in a test environment first.

    How to use this function

    To update all the existing slugs, you only want to call this function once on demand, instead of automatically (otherwise it will update the slugs everytime your functions.php loads). You can do that in an external script outside of WP by creating a separate standalone page as follows:

    <?php
        include('wp-load.php');           //Include the wp-load.php file
        define('WP_USE_THEMES', false);   //We don't need the theme files 
    
        echo "<p>About to update all slugs...</p>";
        limit_all_existing_slugs();
        echo "<p>...DONE</p>";
    ?>