How to create WordPress custom post type programmatically

Kate

Kate Bairstow

August 15, 2024

Creating a custom post type (CPT) in WordPress programmatically is a powerful way to extend the functionality of your website. Custom post types allow you to create content types that go beyond the default posts and pages, such as portfolios, testimonials, or products. In this guide, we’ll walk through the steps to create a custom post type programmatically.

Step 1: Understand Custom Post Types

Before diving into the code, it’s important to understand what a custom post type is. In WordPress, a post type is a way of grouping content. The default post types include:

  • Posts
  • Pages
  • Attachments
  • Revisions
  • Navigation menus

Custom post types allow you to create your own group of content, which can have different custom fields, taxonomies, and display options.

Step 2: Set Up Your Child Theme or Custom Plugin

To keep your changes organized and update-safe, it’s best to add custom post types in a child theme’s functions.php file or in a custom plugin. Here’s how you can do it:

In a Child Theme:

  1. Go to your WordPress installation directory.
  2. Navigate to wp-content/themes/your-child-theme/.
  3. Open functions.php file.

In a Custom Plugin:

  1. Go to wp-content/plugins/.
  2. Create a new folder for your plugin, e.g., custom-post-types.
  3. Inside this folder, create a file named custom-post-types.php.

Step 3: Write the Code to Register the Custom Post Type

Here’s the code snippet you need to add to your functions.php or custom-post-types.php file:

function create_custom_post_type() {
    $labels = array(
        'name'                  => _x( 'Books', 'Post type general name', 'textdomain' ),
        'singular_name'         => _x( 'Book', 'Post type singular name', 'textdomain' ),
        'menu_name'             => _x( 'Books', 'Admin Menu text', 'textdomain' ),
        'name_admin_bar'        => _x( 'Book', 'Add New on Toolbar', 'textdomain' ),
        'add_new'               => __( 'Add New', 'textdomain' ),
        'add_new_item'          => __( 'Add New Book', 'textdomain' ),
        'new_item'              => __( 'New Book', 'textdomain' ),
        'edit_item'             => __( 'Edit Book', 'textdomain' ),
        'view_item'             => __( 'View Book', 'textdomain' ),
        'all_items'             => __( 'All Books', 'textdomain' ),
        'search_items'          => __( 'Search Books', 'textdomain' ),
        'parent_item_colon'     => __( 'Parent Books:', 'textdomain' ),
        'not_found'             => __( 'No books found.', 'textdomain' ),
        'not_found_in_trash'    => __( 'No books found in Trash.', 'textdomain' ),
        'featured_image'        => _x( 'Book Cover Image', 'Overrides the “Featured Image” phrase for this post type.', 'textdomain' ),
        'set_featured_image'    => _x( 'Set cover image', 'Overrides the “Set featured image” phrase for this post type.', 'textdomain' ),
        'remove_featured_image' => _x( 'Remove cover image', 'Overrides the “Remove featured image” phrase for this post type.', 'textdomain' ),
        'use_featured_image'    => _x( 'Use as cover image', 'Overrides the “Use as featured image” phrase for this post type.', 'textdomain' ),
        'archives'              => _x( 'Book archives', 'The post type archive label used in nav menus.', 'textdomain' ),
        'insert_into_item'      => _x( 'Insert into book', 'Overrides the “Insert into post”/”Insert into page” phrase.', 'textdomain' ),
        'uploaded_to_this_item' => _x( 'Uploaded to this book', 'Overrides the “Uploaded to this post”/”Uploaded to this page” phrase.', 'textdomain' ),
        'filter_items_list'     => _x( 'Filter books list', 'Screen reader text for the filter links heading.', 'textdomain' ),
        'items_list_navigation' => _x( 'Books list navigation', 'Screen reader text for the pagination heading.', 'textdomain' ),
        'items_list'            => _x( 'Books list', 'Screen reader text for the items list heading.', 'textdomain' ),
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'book' ),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => null,
        'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
        'show_in_rest'       => true, // Enable Gutenberg editor
    );

    register_post_type( 'book', $args );
}

add_action( 'init', 'create_custom_post_type' );

Step 4: Customize the Post Type

In the code above, the custom post type is named “Book.” Here’s how you can customize it:

  • labels: Change these to suit the name and purpose of your custom post type.
  • public: Set to true to make the post type public.
  • supports: This array controls what features the post type supports, like title, editor, thumbnails, etc. Add or remove features based on your needs.
  • rewrite: Customize the URL slug for your custom post type.
  • show_in_rest: Set to true if you want to use the Gutenberg editor with your custom post type.

After registering your custom post type, it’s essential to flush the permalinks to avoid 404 errors on your new post type. To do this:

  1. Go to Settings > Permalinks in the WordPress dashboard.
  2. Click Save Changes (no need to change anything, just saving will refresh the permalinks).

Step 6: Test Your Custom Post Type

Go to your WordPress dashboard, and you should see a new menu item for your custom post type (e.g., “Books”). You can start adding content, and it will behave like any other post type.

Conclusion

Creating a custom post type programmatically in WordPress is a straightforward process that significantly enhances the flexibility of your site. By following these steps, you can tailor your WordPress site to better fit your content needs, whether it’s for a portfolio, testimonials, or any other custom content type.

Call to Action

Ready to take your WordPress site to the next level? Start creating custom post types today and unlock new possibilities for managing and displaying your content!