When you call the register_post_type()
function to register a custom post type, the first parameter is a unique string to identify the post_type you’re creating. Since this string needs to be unique, it is a bad idea to use a string that others might use (e.g. book
).
If another plugin does try to register the same “unique” custom post type, things break. It is bad when things break so please use a prefix on your post type. Below I’ll walk you through the URL problems that occur when you use a prefixed post type and how to fix them.
Register a WordPress Custom Post Type
Here we are registering a custom post type, without prefixing the post type string. This is a bad idea.
While the URLs look good, we are using a post type of book
which has a high probability of collision (i.e. another plugin using the same post type).
Do NOT use this code
function fe_register_cpt_fe_book() {
$args = array(
'public' => true,
'label' => 'Books',
'has_archive' => true,
);
register_post_type( 'book', $args );
}
add_action( 'init', 'fe_register_cpt_fe_book' );
Now when I create an example post called “Anathem”, I have the following:
- http://example.com/book/anathem/ (Single Post Page)
- http://example.com/book/ (Archive Page of CPT book)
- http://example.com/wp-admin/edit.php?post_type=book (wp-admin page listing book posts)
Register a Prefixed WordPress CPT
Here we are going to use a prefixed post type name, which is good. Unfortunately, this has a negative impact on our URLs.
Do NOT use this code either
function fe_register_cpt_fe_book() {
$args = array(
'public' => true,
'label' => 'Books',
'has_archive' => true,
);
register_post_type( 'fe_book', $args );
}
add_action( 'init', 'fe_register_cpt_fe_book' );
You’ll notice the only thing I’ve changed is the first parameter for register_post_type()
, I’ve changed book
to fe_book
.
This results in the following URLs.
Note: If you’re trying this at home, you’ll have to recreate the Anathem post because WordPress will no longer find it (since the previous post was type book
rather than fe_book
).
- http://example.com/fe_book/anathem/ (Single Post Page) Problem
- http://example.com/fe_book/ (Archive Page of CPT fe_book) Problem
- http://example.com/wp-admin/edit.php?post_type=fe_book (wp-admin page listing fe_book posts)
You’ll notice I’ve marked two URLs as problems. We don’t want our public facing URLs to have fe_book
. We would rather have books
in the URL.
Register a Prefixed WordPress CPT with Rewrite
Here we use a prefixed post type and use the rewrite
parameter to get the URLs we want.
This is the solution we want
function fe_register_cpt_fe_book() {
$args = array(
'public' => true,
'label' => 'Books',
'has_archive' => true,
'rewrite' => array(
'slug' => 'books',
),
);
register_post_type( 'fe_book', $args );
}
add_action( 'init', 'fe_register_cpt_fe_book' );
You’ll notice this time we added rewrite
with a slug of books
to the $args array.
This results in the following URLs.
- http://example.com/books/anathem/ (Single Post Page)
- http://example.com/books/ (Archive Page of CPT fe_book)
- http://example.com/wp-admin/edit.php?post_type=fe_book (wp-admin page listing fe_book posts)
Bonus Points for Plugin Authors Filtering the Slug
If you are going to be distributing your code, I strongly recommend you add a filter to the slug. This allows a developer to programmatically override your URLs, without modifying your code.
'slug' => 'books',
becomes
'slug' => apply_filters( 'fe_rad_book_plugin_slug', 'books' ),
where fe_rad_book_plugin_slug is a name that uniquely identifies your plugin (and ends in slug). If two custom post types both try to use the same slug, they won’t work properly. However, with this filter, we can easily change the slug and correct the collision.
This is a great article! I’ve been building custom post types for the last year or so, and this article along with another article (https://salferrarello.com/cpt-best-practices/) were very helpful!
Quick question:
At the end of this post, you mention adding a filter to your CPT slug so it can be customized without modifying the plugin code. Do you have any other articles or resources that explain how to leverage that entirely? I’d love to add a field to the permalinks settings area where my client could change the slug of their CPT.
Thanks!
Fantastic article, thank you!