Back to Blog
Lesson 10 of the WordPress Plugin Development: Foundations (PHP & MVC) course
WordPressJune 25, 20263 min read

Registering Custom Post Types: A WordPress Developer’s Guide

Master the art of registering a custom post type (CPT) in WordPress. Learn to use register_post_type to structure your plugin data effectively today.

WordPressPHPPlugin DevelopmentCPTCustom Post TypeRegistrationplugin-development

Previously in this course, we explored The Controller Layer for Admin Pages, where we learned how to route menu requests and keep our admin logic organized. In this lesson, we shift our focus from UI management to data structure by defining a Custom Post Type (CPT).

A CPT allows you to store specific types of content—like our "Knowledge Articles"—separately from regular blog posts, giving you full control over how that data is managed, queried, and displayed within WordPress.

Understanding Custom Post Type Registration

In WordPress, everything is a post. Whether it's a page, an attachment, or a blog post, they all reside in the wp_posts table. A CPT is simply a way to flag a row in that table with a unique identifier (the post_type).

When you register a CPT, you aren't creating a new database table; you are telling WordPress how to treat a specific category of posts. This unlocks the full power of the WordPress ecosystem, including the editor, taxonomies, and the native query engine.

The register_post_type Function

The primary tool for this is register_post_type(). It accepts two arguments: the post type name (a string, max 20 characters) and an array of arguments that define its behavior.

To keep our plugin architecture clean, we will implement this within a dedicated method in our model layer or a specific registration class, ensuring we hook into the init action.

Worked Example: Registering the Knowledge Article CPT

Let’s define our "Knowledge Article" CPT. We want this to be public, searchable, and manageable in the admin dashboard.

PHP
#6A9955">/**
 * Register the Knowledge Article CPT.
 */
public function register_knowledge_articles() {
    $labels = [
        'name'          => 'Knowledge Articles',
        'singular_name' => 'Knowledge Article',
        'add_new'       => 'Add New Article',
        'edit_item'     => 'Edit Article',
    ];

    $args = [
        'label'             => 'Knowledge Articles',
        'labels'            => $labels,
        'public'            => true,
        'has_archive'       => true,
        'rewrite'           => ['slug' => 'knowledge-base'],
        'supports'          => ['title', 'editor', 'thumbnail'],
        'capabilities'      => ['edit_posts' => 'edit_posts'],
        'show_in_rest'      => true, #6A9955">// Required for Gutenberg support
    ];

    register_post_type('kb_article', $args);
}

#6A9955">// Hook into the 'init' action
add_action('init', [$this, 'register_knowledge_articles']);

Key Components of the Registration Array

  • Labels: These define the strings users see in the dashboard. Providing these improves the user experience significantly.
  • Public: Setting this to true makes the post type available in the admin and potentially the front end.
  • Show in REST: Always set this to true if you want your CPT to work with the block editor (Gutenberg).
  • Capabilities: By default, WordPress maps CPT capabilities to post capabilities. You can create custom ones, but for most plugins, sticking to the standard edit_posts mapping is sufficient.

Hands-on Exercise

  1. Open your plugin's primary model class (or create a PostTypeManager class).
  2. Add the register_knowledge_articles method as shown above.
  3. Ensure the init action is triggered correctly within your plugin's lifecycle.
  4. Activate your plugin, then navigate to your WordPress dashboard. You should see "Knowledge Articles" in the sidebar.
  5. Crucial Step: After registering a CPT, visit Settings > Permalinks and click "Save Changes." This flushes the rewrite rules, ensuring your new CPT URLs work immediately.

Common Pitfalls

  • Forgetting to Flush Permalinks: If you get a 404 error when visiting a new CPT URL, it’s almost always because the rewrite rules haven't been flushed.
  • Reserved Names: Avoid using post type names that WordPress reserves, such as post, page, attachment, revision, or nav_menu_item.
  • Missing 'show_in_rest': If you don't set show_in_rest to true, your CPT will fall back to the classic editor instead of the modern block editor.
  • Namespace Collisions: Always prefix your CPT name (e.g., kb_article instead of just article) to prevent conflicts with other plugins or themes.

Recap

We have successfully extended the WordPress data structure by registering a custom post type. By using register_post_type, we’ve enabled a dedicated space for our Knowledge Base content, configured its admin labels, and ensured compatibility with the block editor. This provides a robust foundation for the CRUD operations we will implement later in the course.

Up next: Configuring CPT Arguments, where we will dive deeper into fine-tuning the behavior of our Knowledge Article CPT, including custom rewrite slugs and hierarchical support.

Similar Posts