Is it possible to redeclare/change the slug of a plugin’s existing custom post type (without simply editing the plugin)?
That is, if Plugin X creates a custom post type with the slug /uncookedtoast/, is it possible to add a filter to functions.php (or something similar) that changes the slug to /bread/?
Yes, this is possible, but if the plugin is creating a custom post type using the rewrite => array('slug' => 'post_type')
parameter, then it’s not likely that you’re going to be able to replace the slug.
Whenever custom post types are created, URL rewrite rules are written to the database. Depending on which action triggers the creation of the custom post type (such as the init action), WordPress will flush the rewrite rules and restore the custom post type’s slugs regardless of what changes you attempt to make.
That said, you can provide custom slugs for the custom post types. The following example assumes that you have a custom post type of movies
and that you’re attempting to change the /movies/
slug to /films/
.
To be complete, here’s the basic function used to define the movies
custom post type. The plugin that you’re referencing should be doing something like this:
function movies_register_post_type() {
register_post_type(
'movies',
array(
'labels' => array(
'name' => __('Movies'),
'singular_name' => __('Movie')
),
'public' => true,
'has_archive' => true,
'rewrite' => array(
'slug' => 'movies'
)
)
);
} // end example_register_post_type
add_action('init', 'movies_register_post_type');
You can modify the options table by providing your own custom rules based on the existing post type.
Basically, we’ll do this:
- Take the existing set of rules and then write our own with our own custom slugs
- Give the new rule a higher priority than the custom post type’s slug
Here’s how you can do this:
function add_custom_rewrite_rule() {
// First, try to load up the rewrite rules. We do this just in case
// the default permalink structure is being used.
if( ($current_rules = get_option('rewrite_rules')) ) {
// Next, iterate through each custom rule adding a new rule
// that replaces 'movies' with 'films' and give it a higher
// priority than the existing rule.
foreach($current_rules as $key => $val) {
if(strpos($key, 'movies') !== false) {
add_rewrite_rule(str_ireplace('movies', 'films', $key), $val, 'top');
} // end if
} // end foreach
} // end if/else
// ...and we flush the rules
flush_rewrite_rules();
} // end add_custom_rewrite_rule
add_action('init', 'add_custom_rewrite_rule');
Now, you’ll have two ways to access your movies:
/movies/Back-To-The-Future
/films/Back-To-The-Future
Note that I don’t recommend hooking the add_custom_rewrite_rule
into the init
action as it will fire too frequently. This is just an example. A better place to apply the function would be on theme activation, plugin activate, perhaps the save_post action, etc. Depending on what you need to do, you may only need to fire it once or just a few times.
At this point, you may want to consider updating the permalinks for the custom post type to use the ‘/movies/
slug. For example, if you navigate to /films/
, you will see a listing of all your movies but hovering over the title will reveal that the /movies/
slug is still being used.
To go one step further, you could technically instate a 301 redirect to catch all links to /movies/
to redirect to their /films/
counterpart, but this all depends on what you’re attempting to do.