Skip to content

Everything for WordPress, web development — and beyond

💡 How to create a custom post type in WordPress: code and plugin

💡 How to create a custom post type in WordPress: code and plugin

Standard Posts and Pages cover most tasks for a typical website. But when a product catalog, real estate database, or project portfolio comes into play, these two content types are no longer enough. Mixing products with blog drafts is inconvenient, and overloading pages with custom fields is a path to admin panel chaos.

WordPress solves this problem through Custom Post Types, Custom Post Types (CPT). You create a separate section in the sidebar menu with its own fields, categories, and display templates. Products live separately from articles. Events don't get mixed up with pages. Data stays where it belongs.

Below are two tested methods: through code using register_post_type() (flexible, zero extra plugins) and through the free plugin CPT UI (no PHP required). Both work on WordPress 6.7+ and have been tested on production sites.

💡 Quick overview:

  • Register a new post type through the core function register_post_type(), without plugins, with full control over parameters.
  • Code-free alternative: the Custom Post Type UI plugin provides a visual interface, lowers the barrier to entry, and eliminates syntax errors.
  • After registration, the type appears in the sidebar menu. Final touches: taxonomies, fields, and permalink flush.

What is a custom post type

Any content in WordPress is a record with a post_type field in the wp_posts table. For blog posts, it's post. For pages, it's page. For attachments, it's attachment. A custom type adds another value: product for products, event for events, portfolio for projects. Whatever fits your site's needs.

Each CPT gets its own menu item in the admin panel, a URL structure (/events/webinar-2026/), its own taxonomies, and support for the editor blocks you need: thumbnails, excerpts, editor, comments. All of this is enabled through checkboxes in the supports array, no magic involved.

The main benefit is organization. Products don't float around in the blog feed. Events don't need to be filtered out from a general pile. Administration speeds up, and site search works more precisely.

Method 1: registration through code, register_post_type()

The basic method that has worked since WordPress 3.0. No third-party plugins needed. The code goes in your child theme's functions.php or, more safely, through the Code Snippets plugin: a code error won't crash the site but will simply disable that specific snippet.

Step 1: function on the init hook

The function hooks into init. Earlier won't work because the core isn't ready to accept registrations yet. Later means the type won't be picked up until the next request. Here's a minimal working template:

1/**
2 * Registers a custom post type 'Books'.
3 * Place in functions.php of the child theme or via Code Snippets.
4 */
5function myprefix_register_book_post_type() {
6 register_post_type( 'book', array(
7 'labels' => array(
8 'name' => 'Books',
9 'singular_name' => 'Book',
10 'add_new_item' => 'Add New Book',
11 'edit_item' => 'Edit Book',
12 'view_item' => 'View Book',
13 'search_items' => 'Search Books',
14 'not_found' => 'No books found',
15 ),
16 'public' => true,
17 'has_archive' => true,
18 'rewrite' => array( 'slug' => 'books' ),
19 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
20 'show_in_rest' => true,
21 'menu_icon' => 'dashicons-book-alt',
22 ) );
23}
24add_action( 'init', 'myprefix_register_book_post_type' );

After inserting the code, a "Books" section appears in the admin panel. Record URLs become site.ru/books/book-name/. It works immediately.

Step 2: key parameters

The function takes two arguments: a type key string (up to 20 characters, Latin letters and hyphens) and a settings array. Here are the parameters worth configuring deliberately:

Parameter

What it does

Recommendation

public

Visibility in admin and frontend

true for most cases

has_archive

Archive page for all records of this type

true for catalogs and collections

rewrite

URL structure (slug)

Set explicitly, without special characters

supports

Editor blocks

Minimum: title editor thumbnail

show_in_rest

Availability in the block editor

true is mandatory, otherwise Gutenberg won't open

menu_icon

Icon in the sidebar menu

Choose from Dashicons

Step 3: taxonomies

Post categories and tags are not attached to your CPT by default. Create your own:

1function myprefix_register_book_taxonomies() {
2 register_taxonomy( 'genre', 'book', array(
3 'label' => 'Genres',
4 'rewrite' => array( 'slug' => 'genre' ),
5 'hierarchical' => true,
6 'show_in_rest' => true,
7 ) );
8
9 register_taxonomy( 'book_tag', 'book', array(
10 'label' => 'Book Tags',
11 'rewrite' => array( 'slug' => 'book-tag' ),
12 'hierarchical' => false,
13 'show_in_rest' => true,
14 ) );
15}
16add_action( 'init', 'myprefix_register_book_taxonomies' );

Taxonomies are registered through register_taxonomy() with an explicit binding to the post_type as the second parameter. hierarchical => true provides a tree structure like categories. false gives a flat list like tags.

After registration, go to Settings → Permalinks and click "Save Changes," even if you haven't changed anything. WordPress will rebuild the routing rules. Without this step, URLs like /books/ will return 404.

When code is enough

This method works well for one or two custom types when the structure doesn't change often. Plus: zero extra plugins and full control over every parameter. Minus: for complex relationships between multiple CPTs and frontend submission forms, the code quickly grows.

Method 2: without code, Custom Post Type UI plugin

If you don't want to touch functions.php, install Custom Post Type UI. A free plugin from WebDevStudios: one million active installations, 4.6 rating on WordPress.org. Updated in May 2026, tested up to WP 7.0.

Interface for adding a custom post type in the CPT UI plugin

How to create a CPT through the interface

  • Install the plugin: Plugins → Add New → "Custom Post Type UI" → Install → Activate.
  • Go to CPT UI → Add/Edit Post Types.
  • Fill in the fields: Post Type Slug (Latin letters, for example event), Plural Label ("Events"), Singular Label ("Event").
  • In the Settings block, check: Public (True), Has Archive (True), Show in REST API (True).
  • In the Supports block, check at minimum: Title, Editor, Thumbnail, Excerpt.
  • Click Add Post Type.

Taxonomies are created in the same place, on the Add/Edit Taxonomies tab. Specify the binding to your post type, and categories will appear in the sidebar menu.

Strengths

Quick registration without risk of syntax errors: the plugin assembles a correct $args array on its own. The Tools tab enables type migration between sites through code export and import. CPT UI Pro adds blocks for frontend output and drag-and-drop columns in the admin panel, but the free version fully covers the registration task.

Note that the plugin only registers types and taxonomies. For frontend display, you'll need either theme templates, CPT UI Pro, or a combination with Advanced Custom Fields or Elementor.

Comparison: code versus plugin

Criterion

Code (register_post_type)

Plugin (CPT UI)

Barrier to entry

Requires understanding of PHP arrays

Interface similar to standard WP settings

Number of CPTs

Unlimited

Unlimited

Transfer between sites

Copy the code

Export/import through Tools

Extra code on site

None

Plus one plugin

Plugin dependency

None

Yes, CPT UI must be active

Documentation

developer.wordpress.org

docs.pluginize.com

In practice, a combination is often used: register types through CPT UI for speed, and add fields through Advanced Custom Fields. This gives you a visual configuration interface without a single line of PHP.

⁉️🤔 Frequently asked questions

Do I need to flush permalinks after creating a CPT?

Yes, always. Go to Settings → Permalinks and click "Save." WordPress will rebuild the routing rules. Without this, new URLs like /books/ will return 404.

How does CPT UI differ from ACF in type registration?

CPT UI only registers post types and taxonomies. ACF, starting from version 6.1, can also register CPTs, but its main strength is custom fields. The CPT UI + ACF combination gives you an interface for types and flexible fields. You're not locked into a single vendor.

Can I rename an existing post type?

There's no direct mechanism. When you change the post_type in the database, old records disappear from the admin panel. The proper approach: create a new type with the desired name, migrate records with an SQL query UPDATE wp_posts SET post_type = 'new_type' WHERE post_type = 'old_type', and only then remove the old registration. A full database backup before migration is mandatory.

Will custom types disappear when changing themes?

If types are registered in the theme's functions.php, yes, when you change themes they will disappear from the admin panel. The records will remain in the database but won't be visible. Register CPTs in a separate plugin or through Code Snippets, and the types will survive any theme change.

How do I display CPT on the homepage in the general feed?

Add a filter in Code Snippets: add_filter( 'pre_get_posts', function( $query ) { if ( $query->is_home() && $query->is_main_query() ) { $query->set( 'post_type', array( 'post', 'book' ) ); } } );. Substitute your post_type in the array, and the records will appear in the feed alongside regular posts.

Which method to choose: final summary

Both methods lead to the same result: a new section appears in the sidebar menu, ready to be filled with content. The difference is only in the tool.

If you work with the site hands-on and aren't afraid of functions.php, use code. One register_post_type() function, zero extra plugins. Suitable for landing pages, small catalogs, and projects with developer support.

If you're handing the site over to a client or building a content project with a dozen types, install CPT UI. The visual interface lowers the barrier to entry, and configuration export saves hours when migrating between platforms.

In any case, after registration, set up the display: single and archive templates in the theme or visual layout through CPT UI Pro / Elementor Pro. Without this step, the content will remain only in the admin panel.