How to control which category will be picked for the slug of a post?

I’m using the permalink structure “/%category%/%postname%/”.

What bothers me is that I have posts that belong to two categories. And of course, unfortunately, WordPress always picks the wrong one for the slug generation.

Read More

Is there a nice and clean way of having control on which category will be chosen for the post slugs?

Thanks a lot!

Related posts

Leave a Reply

3 comments

  1. WordPress picks the lowest ID as its main permalink. However, ALL categories will contain your post automatically. Meaning both these:

    …will return your post (given that post-A is in both category-A and category-B) via a redirect. It can’t list them all to you on the Edit page, sorry. But it will make sure they’re available in all categories.

    Of course, get_permalink will return the wrong one for you.

    http://codex.wordpress.org/Using_Permalinks#Using_.25category.25_with_multiple_categories_on_a_post

    Now as for overriding the behavior, look at:

    http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/link-template.php#L71, specifically a little lower on line 121. It’s going to use $cats[0]->slug after sorting by ID. Which does not appear to be hookable in any way inside there, so either higher or lower.

    This is a ticket that was going to change the way it worked http://core.trac.wordpress.org/ticket/18752 it’s marked for Future Release, though. Subscribe to the ticket to show your interest, maybe it makes it into WordPress 3.5 later this year.

    The pre_post_link filter will allow you to override the permalink. post_link, too.

    Alternatively, get_the_category, should allow you to hack the IDs for a post (or remove the others to leave only one), but this should only occur when the permalink is requested.

    add_filter( 'pre_post_link', function( $permalink, $post ) {
    
         if ( strpos($permalink, '%category%') === false )
             return; /* not interested */
         add_filter( 'get_the_categories', 'wpse46860_prune_categories' );
         return $permalink;
    
    }, null, 2 );
    
    function wpse46860_prune_categories( $categories ) {
    
        /* run once */
        remove_filter( 'get_the_categories', 'wpse46860_prune_categories' );
    
        /* .. prune the categories to leave the one you need .. */
        global $_hijack_post_id;
    
        return $categories;
    
    }
    

    This is a hack.

    An additional difficulty is to get the post_ID to prune the categories against, the get_the_categories filter does not pass the post_ID to us; use a global (dirty) or a class property (clean).

    You can try out different permalink plugins like: