How to Register a Custom Post Type in WordPress

The function register_post_type registers a post type in WordPress.

Preparation

Suppose a website to manage the collection of books in a bookstore. For each book, the website should manage information like title, author, year, summary, ISBN, editorial, and price. The website should also allow searching for books using any field.

Custom post types

Post types are a way to refer to each type of content on a WordPress website. By default, WordPress comes with post types like Post, Page, and Attachment; but you can create other post types. These user-defined post types are called “custom post types”.

Custom post types have extended WordPress beyond a blog tool. By using custom post types and post metadata, you can adapt WordPress to practically any situation. From a blog to an online store containing millions of items.

Registration

Custom post types are registered in WordPress. They are never saved to the database. From a basic perspective, registering a post type means adding a new item to the global variable $wp_post_types. This variable is an associative array that stores all post types registered in WordPress.

The function register_post_type registers a post type. It should be called during the 'init' action. This function takes as input the identifier of the post type and an associative array containing the attributes of the post type.

The identifier of a post type:

  • Must not exceed 20 characters
  • Should be prefixed to avoid conflicts
  • Should only contain lowercase alphanumeric characters, underscores, and dashes

The list of supported attributes is large. The best way to stay up to date with the latest changes is by consulting the PHPDoc in the source code of the function.

Example

A website to manage the collection of books in a bookstore was introduced above. The first step to resolve this problem is to register the custom post type Book.

/*
 * Registers the custom post type Book.
 */
function ns_register_book_cpt(){
    
    // See all possible labels in the PHPDoc of the function get_post_type_labels
    $labels = array(
       'name'                  => __('Books', 'ns'),
       'singular_name'         => __('Book', 'ns'),
       'menu_name'             => __('Books', 'ns'),
       'all_items'             => __('All Books', 'ns'),
       'add_new'               => __('Add New', 'ns'),
       'add_new_item'          => __('Add New Book', 'ns'),
       'edit_item'             => __('Edit Book', 'ns'),
       'new_item'              => __('New Book', 'ns'),
       'view_item'             => __('View Book', 'ns'),
       'view_items'            => __('View Books', 'ns'),
       'search_items'          => __('Search Books', 'ns'),
       'not_found'             => __('No books found.', 'ns'),
       'not_found_in_trash'    => __('No books found in Trash.', 'ns'),
       'archives'              => __('Book Archives', 'ns'),
       'filter_items_list'     => __('Filter books list', 'ns'),
       'items_list_navigation' => __('Books list navigation', 'ns'),
       'items_list'            => __('Books list', 'ns')
    );
    
    // See all possible attributes in the PHPDoc of the function register_post_type
    $args = array(
        'label'                 => __('Books', 'ns'),
        'labels'                => $labels, 
        'public'                => true,
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'show_ui'               => true,
        'show_in_nav_menus'     => true,
        'show_in_menu'          => true,
        'show_in_admin_bar'     => true,
        'hierarchical'          => false,
        'supports'              => array('title', 'editor', 'author'), 
        'taxonomies'            => array('post_tag'),
        'has_archive'           => true, 
        'rewrite'               => array('slug' => 'books'),
        'query_var'             => 'book'
    );
    
    register_post_type('ns_book_cpt', $args);
}
add_action('init', 'ns_register_book_cpt', 10, 0);

This post type supports the features 'title', 'editor', and 'author'. We will use the features 'title' and 'editor' to enter the title and the summary of each book. To enter the other fields, we need to use post metadata.

Administration

If the attributes show_ui and show_in_menu are TRUE, WordPress creates automatically sections in the administration area to manage entries of the post type.

Translate source code strings for proper display in languages other than English.

WordPress administration area - Post type "Book".

Issues

If you get a “Page not found” error when you try to visit a book or a post of any other custom post type, apply this procedure:

  1. Open the administration area
  2. Go to the Settings menu
  3. Go to the Permalinks submenu
  4. Click the Save Changes button

Further reading

I recommend the other tutorials in this series to learn more about post types in WordPress.

Exercise

Register the custom post type Movie. Note that this post type:

  • Is public
  • Supports the features 'title', 'editor', 'excerpt', 'author', and 'revisions'
  • Supports the taxonomies Tag and Category
  • Has archive and it is available at /movies/

Source code

The source code developed in this tutorial, including an answer to the exercise, is available here.

Open chat
Need help?
Hi! 🤝 Open the chat if you have any question, feedback, or business proposal. I would love to hear from you.