How to create a custom post type in WordPress (remove slug, enable block editor)

If you use WordPress on a daily basis, then you are probably familiar with commonly used post types such as posts and pages. However, there are times when you might want to break things down into separate categories or templates, and that is where custom post types come into play.

Custom post types help to extend and organize your site, and allow you to more easily scale your WordPress site. From press releases to case studies, or even a database of artists. Custom post types can be used for all sorts of different things.

One of the problems though is they aren’t always the easiest thing to set up. Typically developers are the ones that configure custom post types for a site. But that doesn’t have to be the case.

Below I’ll walk you through a couple of easy ways to set up a basic custom post type (CPT), as well as fixing the slug and enabling it to work in the WordPress block editor.

Examples of custom post types and usage

I thought it might help if you could see some examples of custom post types being used on live sites. So here are a couple.

Food and menus example

On our No Gluten site, we have different gluten-free foods lists as well as gluten-free restaurants and fast food places. Each of these has its own custom post type. You can click into “Menus” and add a new post, just like you would with a standard blog post.

Custom post type with food and menus
Custom post type with food and menus

The difference is that these don’t appear on the blog. We already a blog section on our site. This allows us to completely customize a separate template for these types of posts. As you can see below, we have built a directory using the custom post types.

Custom post type with custom template
Custom post type with custom template

You can then build out different types within a custom post type. These are similar to how categories work with normal posts. So we have a menu type for fast food and one for restaurants.

A type within a custom post type
A type within a custom post type

Coupon example

Another example is with our WP Coupons plugin that you seeing powering our deals page on this site. Each coupon is simply a post underneath the “Coupons” custom post type. In this case, the custom post type is created automatically when you install and activate the plugin.

Coupon custom post type
Coupon custom post type

Artist example

One last example is from a new project that I’m working on about synthwave music. In the project, I’m creating a database of synthwave artists. So for this, it made logical sense to create a new “artist” custom post type in WordPress.

Artist custom post type
Artist custom post type

I then display the artists (CPT) automatically in alphabetical order on a page.

Artist custom post type in alphabetical order
Artist custom post type in alphabetical order

How to create a custom post type

The first way you could go about creating a custom post type would be to simply use a plugin on the repository. However, I’m not a fan of installing additional plugins if I don’t have to. Especially if all that is needed is a separate custom post type without much customization.

If you want to go down the plugin route, here are a few plugins that can help:

Note: If you use one of the plugins above, some of the following steps below, like removing the slug, might not work.

I’m actually going to walk you through to create a custom post type manually with code. But don’t worry, you don’t need to be a developer to do this.

Step 1

The first step is to generate the code needed for your custom post type. I always use the handy online Custom Post Type Generator from Meta Box.

WordPress custom post type generator
WordPress custom post type generator

This allows you to easily change all the attributes and simply output the code in a few clicks. Here are a few attributes you will want to update:

  • Plural name
  • Singular name
  • Name in admin bar (make sure to capitalize this)
  • Show in menu? (choose show as top-level menu)
  • Menu position after (choose Posts)
  • Menu icon (Use one that is appropriate for your custom post type)

Here is the final code result. I’m using my “artist” custom post type as an example. So you will want to update this accordingly. I’ve also created a gist you can bookmark.

add_action( 'init', 'your_prefix_register_post_type' );
function your_prefix_register_post_type() {
	$args = [
		'label'  => esc_html__( 'artists', 'text-domain' ),
		'labels' => [
			'menu_name'          => esc_html__( 'artists', 'your-textdomain' ),
			'name_admin_bar'     => esc_html__( 'Artist', 'your-textdomain' ),
			'add_new'            => esc_html__( 'Add artist', 'your-textdomain' ),
			'add_new_item'       => esc_html__( 'Add new artist', 'your-textdomain' ),
			'new_item'           => esc_html__( 'New artist', 'your-textdomain' ),
			'edit_item'          => esc_html__( 'Edit artist', 'your-textdomain' ),
			'view_item'          => esc_html__( 'View artist', 'your-textdomain' ),
			'update_item'        => esc_html__( 'View artist', 'your-textdomain' ),
			'all_items'          => esc_html__( 'All artists', 'your-textdomain' ),
			'search_items'       => esc_html__( 'Search artists', 'your-textdomain' ),
			'parent_item_colon'  => esc_html__( 'Parent artist', 'your-textdomain' ),
			'not_found'          => esc_html__( 'No artists found', 'your-textdomain' ),
			'not_found_in_trash' => esc_html__( 'No artists found in Trash', 'your-textdomain' ),
			'name'               => esc_html__( 'artists', 'your-textdomain' ),
			'singular_name'      => esc_html__( 'artist', 'your-textdomain' ),
		],
		'public'              => true,
		'exclude_from_search' => false,
		'publicly_queryable'  => true,
		'show_ui'             => true,
		'show_in_nav_menus'   => true,
		'show_in_admin_bar'   => true,
		'show_in_rest'        => true,
		'capability_type'     => 'post',
		'hierarchical'        => false,
		'has_archive'         => true,
		'query_var'           => true,
		'can_export'          => true,
		'rewrite_no_front'    => false,
		'show_in_menu'        => true,
		'menu_position'       => 5,
		'menu_icon'           => 'dashicons-format-audio',
		'supports' => [
			'title',
			'editor',
			'thumbnail',
		],
		
		'rewrite' => true
	];

	register_post_type( 'artist', $args );

Step 2

Next, you need to add the code to your WordPress site. As in a lot of my other posts, I always recommend using the free Code Snippets plugin for this. Then you don’t have to worry about losing any custom code when you update WordPress or your theme.

After adding the above code in a new snippet, you will then see your custom post type in the WordPress dashboard menu.

Custom post type in WordPress dashboard
Custom post type in WordPress dashboard

Enable block editor support

Most of you are now using the WordPress block editor. So you will want to make sure you enable support for it to work with your custom post type. This is already included in the snippet above, but I wanted to point this out. It is this line (gist):

'show_in_rest' => true,

Remove base slug from custom post type URL

Out of the box, custom post types look like this:

domain.com/url/url

If you are like me, you probably prefer to remove the base slug from the URL for SEO purposes. Google generally prefers simple and short URLs.

domain.com/url

To remove the base slug, you can add another code snippet with the following (gist). You will need to update accordingly with your CPT name.

function na_remove_slug( $post_link, $post, $leavename ) {

    if ( 'artist' != $post->post_type || 'publish' != $post->post_status ) {
        return $post_link;
    }

    $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );

    return $post_link;
}
add_filter( 'post_type_link', 'na_remove_slug', 10, 3 );

function na_parse_request( $query ) {

    if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
        return;
    }

    if ( ! empty( $query->query['name'] ) ) {
        $query->set( 'post_type', array( 'post', 'artist', 'page' ) );
    }
}
add_action( 'pre_get_posts', 'na_parse_request' );

Note: While the above works fine, and I’m using it on some of my sites, know that it might cause functionality issues with other plugins that rely on the full URL being there. This is rare, but there are a few instances I’ve seen it cause problems.

Here is an alternative way to remove the rewrite base from custom post types. Props to Maciej for sharing this with me. Add a code snippet with the following (gist). You will need to update accordingly with your CPT name.

function bis_remove_cpt_slug($args, $post_type) {
if(in_array($post_type, array('artist'))) {
    $args['rewrite'] = array('slug' => '/');
}

return $args;
}
add_filter('register_post_type_args', 'bis_remove_cpt_slug', 10, 2);

Enable custom post type preview

Next, you will want to add support for the preview window in the editor to work with the custom post type. Add another code snippet with the following (gist).

//adds custom post type query var to preview links
function mycptname_cpt_previow_query_vars($link, $post) {
	$custom_post_types = array('artist');
	if(in_array($post->post_type, $custom_post_types)) {
		return add_query_arg(['post_type' => $post->post_type], $link);
	}
	return $link;
}
add_filter('preview_post_link', 'mycptname_cpt_previow_query_vars', 10, 2);

Note: You can combine the above functions, I’m just showing them separately as it’s easier to see how everything is pieced together.

How to display custom post type on a page

Last but not least, I’ll show you an easy way to display your custom post types. In some cases, you might want to create a separate template for the custom post type, but if you want something simple, the following works great.

Step 1

Download and install the free WP Show Posts plugin. This is developed by Tom Usborne, the developer of GeneratePress. So you can rest easy knowing it’s super lightweight. It’s actually quite powerful once you dive in and start using it.

Step 2

Next, create a new list and configure the settings. I’m using a simple list on my synthwave site in this example.

Posts

Under posts, make sure to change the post type to your new custom post type that you’ve created.

WP Show Posts with custom post type
WP Show Posts with custom post type

Below are the screens and settings for the rest.

Columns

I’m using one column for now due to only having a few items. But if you have a lot of posts already, you could easily do a two, three, or four column layout which would fill out a page more.

WP Show Posts columns
WP Show Posts columns

Images

I remove the images as I want a simple list.

WP Show Posts images
WP Show Posts images

Content

I tweak the content to include the title.

WP Show Posts content
WP Show Posts content

Meta

I remove all the meta data attributes.

WP Show Posts meta
WP Show Posts meta

More settings

You can sort the posts a lot of different ways. For mine, I wanted it to be alphabetical. So I changed the “Order” to ascending and the “Order by” to title.

WP Show Posts settings
WP Show Posts settings

Step 3

Then grab the shortcode from the sidebar of your list and enter it into the page where you want to list your custom post type.

WP Show Posts shortcode
WP Show Posts shortcode

You will then have a sorted list your new custom post type. As you publish new posts they will automatically appear.

Display custom post type with shortcode
Display custom post type with shortcode

Summary

The tutorial above is just a simple example of how to create a custom post type and a way you could use it dynamically on your WordPress site. As you dive deeper you can start making custom post type templates and really utilize them to build out your site in an efficient and organized way.

If this tutorial was helpful please let me know below in the comments.

author bio
Brian Jackson

I craft actionable content and develop performance-driven WordPress plugins. Connect on X, subscribe to my newsletter (once a month), or buy me coffee.

12 thoughts on “How to create a custom post type in WordPress (remove slug, enable block editor)”

  1. Thank You,Mr Brian!
    I started with WordPress via Australians( WP MUDEV,) then followed Syed Balkhi ( I have my own opinion about him which I’ll keep to myself ) and I’ve been receiving a notification of every single tweet by You as a CMO at Kinsta on my Android and it’s still like that 😀.

    You are definitely one of my best tutors about the depths of Wordpress.
    That’s not a flattery but a gratitude!

    Kind regards from Bulgaria!

    Reply
    • Wow, thanks Dimiter. I appreciate the kind words. I’ll definitely keep publishing more content like this. So stay tuned!

      Reply
  2. Hi Brian,

    Thanks for publishing this tutorial. I just paid someone $100 for doing this for me and they messed up everything.

    I want to add category slug in the final URL. Is it possible? I would appreciate if you can include a vcode for that in this guide.

    Thank you,
    -Swadhin

    Reply
  3. Awesome post , you made it really easy to understand this pretty hard topic for beginners. You helped me a lot so I just wanna say thank you.

    Reply
  4. I was looking for something simple and clean looking like Wp Show Post, the best part is it was made by Tom. I’ll buy the pro version immediately for sure. I even purchased Essential Grid Plugin from Codecanyon in the past but still I am not satisfied enough with it.

    I really thank you Brian for publishing a clear and easy tutorial like this one, straight and to the point. I’m heading to your Newsletter page directly and push that subscribe button. Seriously, this Blog is GOLD Nugget! Will be waiting your new post :D

    Reply
    • Glad you liked it. Yes, WP Show Posts is an awesome plugin. I use it on a couple of my sites. Also agree that with Tom from GeneratePress being the developer, it makes it even better. :)

      Reply
  5. Hey Brian,

    nice blogpost! Exactly what I was looking for.
    the URL for my Post is correct now. The problem I have: I cant access to the archive, to see all posts of the CPT. The archive should be found under the normal /cpt-slug/. Is their a solution for that?

    Thanks and best regards

    Reply
    • I just updated the permalink settings page and now it works perfectly :) ! Amazing! Thank you.

      Just your second short gist does not work for me. Both pages showing 404.

      Reply

Leave a Comment

5