Skip to content
GPLWP Guides

How to create custom post types in WordPress

Developer Tools Time About 30–60 minutes manually, or 15–20 minutes with a plugin 6 steps Updated 10 Sep 2026

DEVELOPER TOOLS
The short answer

You can create a custom post type manually with register_post_type() in a site-specific plugin, then add taxonomies, fields and templates as needed. For a visual site, a plugin such as JetEngine For Elementor is the faster route because it handles the structure without custom coding.

The route
  1. 01Plan the content structure
  2. 02Register it in a plugin
  3. 03Add taxonomies and fields
  4. 04Create the display templates
  5. 05Refresh permalinks and test
  6. 06Use a visual builder instead

What you need

  • WordPress administrator or code access
  • A staging site or recent backup
  • A clear name, URL slug and content fields for the new post type
  • A child theme or site-specific plugin if you need custom templates

Plan the content structure

Decide what the content represents, such as books, case studies or team members. Choose a singular label, plural label, internal post type key and public URL slug. Keep the internal key lowercase, use no spaces, and avoid generic slugs that may conflict with pages, plugins or themes. WordPress limits post type keys to 20 characters.

List the editor features you need, such as title, editor, excerpt, featured image, author, revisions and custom fields. Decide whether the type needs a public single URL, an archive page, search results and the block editor.

Register it in a plugin

For the manual route, add the registration to a site-specific plugin rather than a theme. WordPress recommends a plugin so the content type remains available when you change themes. Register it on the init action with register_post_type().

A minimal example is function site_register_books(){register_post_type('site_book',array('labels'=>array('name'=>'Books','singular_name'=>'Book'),'public'=>true,'has_archive'=>true,'show_in_rest'=>true,'supports'=>array('title','editor','thumbnail'),'rewrite'=>array('slug'=>'books')));} add_action('init','site_register_books');. Replace the labels, key and slug with your own values, and prefix function names and identifiers to reduce collisions.

Add taxonomies and fields

Use a taxonomy when visitors need to group or filter entries, such as genres, locations or departments. Register a custom taxonomy with register_taxonomy() and associate it with your post type. Register the post type and taxonomy on init; custom taxonomies still need their own registration even when listed in the post type's taxonomies argument.

For a few simple values, enable custom fields or add a meta box. For repeaters, relationships, validation and user-friendly field screens, use a dedicated custom-fields or content-modelling plugin rather than storing unstructured text in the editor.

Create the display templates

Publish one test entry and decide how it should appear. A public post type normally needs a single-entry view and, if has_archive is enabled, an archive view. Your theme can provide these templates, or a block theme, page builder or dynamic-content plugin can render the title, content, featured image, taxonomy terms and custom fields.

Set show_in_rest to true if you want the post type in the block editor or REST API. Without it, the editor experience may be limited even though the post type appears in the admin area.

Refresh permalinks and test

Go to Settings → Permalinks and select Save Changes once after registering or changing the post type. This rebuilds WordPress rewrite rules. If you skip it, single entries and archives commonly return 404 errors even when the registration code is correct. WordPress documents flush_rewrite_rules() for controlled programmatic flushing, but it is an expensive operation and should not run on every request.

Test the admin menu, editor, single URL, archive URL, search, taxonomy URLs and navigation links. If unrelated pages also return 404 errors, check for a duplicate page or archive slug and for overly broad custom rewrite rules. Support threads repeatedly identify slug conflicts and stale rewrite rules as common causes.

Use a visual builder instead

The fast route is to use JetEngine For Elementor. It provides screens for custom post types, taxonomies, dynamic fields, listings, filters and Elementor layouts, so you do not need to maintain the registration code or build every listing template by hand.

Install and activate the plugin, create the post type and its fields, choose the public slug, then build a listing and single-item layout in Elementor. Still check the generated URLs, avoid slug conflicts, and save the WordPress permalink settings after changing rewrite-related options. This route is a good fit when the site needs several content types, relationships or visual templates; the manual route is fine for one simple type that will be maintained by a developer.

The fast route

Let JetEngine For Elementor do it

Combines custom post types, fields, listings, and Elementor layouts for dynamic sites without custom coding.

Get JetEngine For Elementor

Sources

  1. developer.wordpress.org /reference/functions/register_post_type/?utm_source=openai
  2. developer.wordpress.org /plugins/post-types/registering-custom-post-types/?utm_sourc…
  3. developer.wordpress.org /reference/functions/register_taxonomy/?utm_source=openai
  4. wordpress.org /support/topic/setting-custom-rewrite-slug-gives-404/?utm_so…

Questions

Can I create a custom post type without a plugin?
Yes. Add a small registration function to a site-specific plugin and call <code>register_post_type()</code> on <code>init</code>. You can then register taxonomies, add meta boxes and create theme templates yourself. The drawback is that you must maintain the code, permissions, fields, templates and rewrite behaviour when the site changes.
Should a custom post type go in a theme or plugin?
Put a custom post type in a plugin when the content should survive a theme change. If it lives in the theme, switching themes can remove the admin menu and make existing entries difficult to manage, even though the database records may remain. A site-specific plugin keeps the content model separate from presentation.
Why does my custom post type URL show a 404 error?
The usual first fix is to visit Settings → Permalinks and save the current structure to rebuild rewrite rules. If that does not work, check that the post type is registered on <code>init</code>, that the rewrite slug does not duplicate a page or another content type, and that no broad rewrite rule is intercepting the request.
What does show_in_rest do for a custom post type?
The <code>show_in_rest</code> argument exposes the post type through the WordPress REST API and is required for the block editor. Set it to <code>true</code> when you want to edit entries with Gutenberg or use REST-based integrations. It does not, by itself, create custom fields or front-end templates.
Is a plugin better than code for custom post types?
A plugin is usually better when you need several post types, custom fields, listings, filters or visual layouts. Code is perfectly suitable for one simple content type and gives you tighter control with fewer dependencies. JetEngine For Elementor is the faster option when the site owner needs to manage the structure and layouts without editing PHP.