Site icon WP Smith

How to Reserve Slugs for WordPress Custom Post Types

If you are using a plugin (or two or three) that do not prefix (improperly I might add!) their custom post types (e.g., downloads from WordPress Download Monitor, listings from AgentPress Listings, etc.) with a namespace like (wps_portfolio, etc.). Or maybe you didn't know and you were using a GUI Custom Post Type plugin. So now you possibly have an archive page of http://domain.com/downloads or http://domain.com/portfolio or http://domain.com/listings.

However, if you have pages, you possibly could have a conflict where a page was created titled Portfolio. So its slug or URI becomes http://domain.com/portfolio (or a page called Listings and have http://domain.com/listings). This can lead to all sorts of issues!!! Issues with content going missing or page displaying improperly. Etc. If you didn't know this was the case, then you may not know to look here, and if you do eventually find out, hours have gone by in frustration, angst, and hatred towards WordPress grows even though it was clearly a user error.

So how do you prevent this? Simple. Two filters: wp_unique_post_slug_is_bad_hierarchical_slug & wp_unique_post_slug_is_bad_flat_slug. These filters are applied when wp_unique_post_slug() runs to check a post's slug. So hooking into that filter enables you to block whatever slugs you'd like preventing pages or any other custom post type from using that name.

Recently, for a plugin I developed, I registered a taxonomy so that the url would be similar to pages. So if a person entered "Fun Times" as a term, the URL would be http://domain.com/fun-times/ which could potentially conflict with a page called "Fun Times" (URL would also be http://domain.com/fun-times/). So to help WordPress recognize this, I wrote a simple function:
[php]<?php
add_filter( 'wp_unique_post_slug_is_bad_hierarchical_slug', 'k12_is_bad_slug', 10, 2 );
add_filter( 'wp_unique_post_slug_is_bad_flat_slug', 'k12_is_bad_slug', 10, 2 );
/**
* Checks "post" slugs for potential conflicts with my new custom post type
* Return true to block slug, false to "approve" the slug
*
* @param boolean $is_bad_slug Default false.
* @param string $slug Slug in question
* @return boolean $is_bad_slug True if slug matches a taxonomy term
*/
function k12_is_bad_slug( $is_bad_slug, $slug ) {
if ( get_terms( 'k12_worksheet_type', array( 'hide_empty' => false, 'slug' => $slug ) ) || 'worksheet' == $slug || 'worksheets' == $slug )
return true;
return $is_bad_slug;
}
[/php]

wp_unique_post_slug_is_bad_hierarchical_slug can also pass 2 more arguments: $post_type (string, post type registered name), $post_parent (int, post parent post ID) & wp_unique_post_slug_is_bad_flat_slug can also pass 1 more argument: $post_type (string, post type registered name).

So let me explain this briefly. The conditional statement is checking 3 things: terms, and two hardcoded slugs ("worksheet" and "worksheets"). To check the terms, I use get_terms() to search all terms (hide_empty = false) in k12_worksheet_type taxonomy for the slug ($slug) in question.

This was first brought to my attention when I came across Rachel Carden's Post How to Define Reserve Slugs for WordPress Posts and Pages.