Skip to main content

Command Palette

Search for a command to run...

How To: Remove Custom Post Type URL slugs

Published
•4 min read•View as Markdown
S
Hello there! I am a seasoned senior software engineer, currently working at Ropardo, a prominent company based in Sibiu. My expertise lies in frontend development, which is where I mainly focus my work efforts. In the past, I have contributed to various projects for SmartBill, spearheaded a community of over 1.5 million members, and developed exceptional products for Koding, a San Francisco-based company. Furthermore, I have built and helped with the development of presentation websites and online stores for small businesses at Sensmedia. As a passionate advocate of the open-source movement, I am always on the lookout for fresh and innovative projects to work on. Currently, I am dedicated to constructing a local web community called @SibiuWebMeetup in Sibiu. If you need to contact me, please don't hesitate to drop me an email at hello@stefancosma.xyz or look me up on most social media platforms using the handle @stefanbc. On a personal note, I am an avid comics enthusiast and amateur photographer, and you can often find me indulging in these hobbies in my free time. Please note that I usually respond to messages within 1-2 business days.

Disclaimer: This is a version I found useful and it worked for my particular case. It may not work for you, but you can post a comment bellow and maybe we can figure it out.

Interesting issue. If you're a WordPress developer than you might have come across this issue in your endeavors to become an ultimate WordPress ninja.

I came across this while working on a recent project for an in-house project at the agency I work.

Having a custom post type and wanting the slug removed from the URL is tricky and is case depended. I tried a lot of plugins and solutions until I came across one (Sadly I can't find the original link, but if you do find it, please let me know in the comments below.) that I later tweaked for my own personal use (The version you are about to read is my version!), because, as I said this issue is case depended.

So, let us get down to the nitty-gritty. All you need are the following lines of code, that should be placed in your theme's functions.php file, and your permalink structure should be /%postname%/.

_Advice: Before placing these functions in your file you need to replace each occurrence of CUSTOM_POST_TYPE_NAME and, depending on your case, replace this line _

$post_name = $query->get('name');

with this one

$post_name = $query->get('pagename');

and you should be good to go.

If you want a more detailed explanation on how this works, keep reading the rest of the article after the following code section.

    add_filter('post_type_link','custom_post_type_link', 10, 3);
    function custom_post_type_link($permalink, $post, $leavename) {

        $url_components = parse_url($permalink);
        $post_path = $url_components['path'];
        $post_name = end(explode('/', trim($post_path, '/')));

        if(!empty($post_name)) {
            switch($post->post_type) {
                case 'CUSTOM_POST_TYPE_NAME':
                    $permalink = str_replace($post_path, '/' . $post_name . '/', $permalink);
                break;
            }
        }
        return $permalink;
    }

    function custom_pre_get_posts($query) {
        global $wpdb;

        if(!$query->is_main_query()) {
            return;
        }

        $post_name = $query->get('name');
        $post_type = $wpdb->get_var( $wpdb->prepare( 'SELECT post_type FROM ' . $wpdb->posts . ' WHERE post_name = %s LIMIT 1', $post_name ) );

        switch($post_type) {
            case 'CUSTOM_POST_TYPE_NAME':
                $query->set('CUSTOM_POST_TYPE_NAME', $post_name);
                $query->set('post_type', $post_type);
                $query->is_single = true;
                $query->is_page = false;
            break;
        }

        return $query;
     }
     add_action('pre_get_posts','custom_pre_get_posts');

Ok, you got to code, you placed it in your functions.php file but you want to understand the ways of the force.

Ok, let's dissect this sucker. The first thing that we have to do is to remove the actual slug from the actual URL. We can do this by getting the permalink for the current post and dissecting it using parse_url function (Very useful function!).

In the end (See what I did there?) we get the post name from the URL. Now we check the post type and if the current post has the desired type we proceed in removing the slug using str_replace on the permalink.

In order for this function to work we need it to be attach to a hook. Luckly, good guy WordPress has a filter called post_type_link that is used

prior to printing by the function get_post_permalink.

Ok, you managed to get until this step but you get a 404, right? Right. Well that's because WordPress doesn't recognize that post as a custom post type anymore. But we can fix that and trick WordPress into thinking that the requested post is in fact a custom post type.

The last function does this very thing. We need the global $wpdb variable, because we're going to play with the DB a bit (Don't worry we won't break anything important!). After checking if we're on the main query we proceed in getting the name for the current post.

The next logical step is to get the post type for the requested post. We do this with a simple SQL select. And now for the fun part. If the post type is our desired post type than we do the following actions. We set the value for the custom post type, the requested post. The basic syntax for query set is this:

$query->set('key', 'value')

WordPress needs to know what type the requested post is. After that we need to specify that the post is indeed a custom post type. And now for some little developer fairy dust and magic. We remind dear old WordPress that our post is in fact a post and it should be treated like one, that's where is_single comes in and is_page walks away. In order for this little trick to work, WordPress has a nifty little action called pre_get_posts that is

called after the query variable object is created, but before the actual query is run.

You can change all the stuff you want using this hook, before "all the gates open".

Useful resources:

  • Debug Bar with WP_DEBUG and SAVEQUERIES set to true in wp_config.php

And that was our lesson in WordPress slug removing (Nasty little buggers!).

Until next time, code long and prosper!

Stefan

More from this blog

S

Stefan Cosma

50 posts

Lead Software Developer | Community builder @ Sibiu Web Meetup | Co-organiser @ Friendly.rb | Hackathon Coordinator