PHPwordpressintermediate

Register Custom Post Type

Complete example of registering a custom post type with all common options

#custom-post-type#wordpress#development#cpt
Share this snippet:

Code

php
1function register_portfolio_post_type() {
2 $labels = array(
3 'name' => _x('Portfolio Items', 'Post type general name', 'textdomain'),
4 'singular_name' => _x('Portfolio Item', 'Post type singular name', 'textdomain'),
5 'menu_name' => _x('Portfolio', 'Admin Menu text', 'textdomain'),
6 'name_admin_bar' => _x('Portfolio Item', 'Add New on Toolbar', 'textdomain'),
7 'add_new' => __('Add New', 'textdomain'),
8 'add_new_item' => __('Add New Portfolio Item', 'textdomain'),
9 'new_item' => __('New Portfolio Item', 'textdomain'),
10 'edit_item' => __('Edit Portfolio Item', 'textdomain'),
11 'view_item' => __('View Portfolio Item', 'textdomain'),
12 'all_items' => __('All Portfolio Items', 'textdomain'),
13 'search_items' => __('Search Portfolio Items', 'textdomain'),
14 'parent_item_colon' => __('Parent Portfolio Items:', 'textdomain'),
15 'not_found' => __('No portfolio items found.', 'textdomain'),
16 'not_found_in_trash' => __('No portfolio items found in Trash.', 'textdomain'),
17 'featured_image' => _x('Portfolio Cover Image', 'Overrides the "Featured Image" phrase', 'textdomain'),
18 'set_featured_image' => _x('Set cover image', 'Overrides the "Set featured image" phrase', 'textdomain'),
19 'remove_featured_image' => _x('Remove cover image', 'Overrides the "Remove featured image" phrase', 'textdomain'),
20 'use_featured_image' => _x('Use as cover image', 'Overrides the "Use as featured image" phrase', 'textdomain'),
21 'archives' => _x('Portfolio archives', 'The post type archive label', 'textdomain'),
22 'insert_into_item' => _x('Insert into portfolio item', 'Overrides the "Insert into post" phrase', 'textdomain'),
23 'uploaded_to_this_item' => _x('Uploaded to this portfolio item', 'Overrides the "Uploaded to this post" phrase', 'textdomain'),
24 'filter_items_list' => _x('Filter portfolio items list', 'Screen reader text for the filter links', 'textdomain'),
25 'items_list_navigation' => _x('Portfolio items list navigation', 'Screen reader text for the pagination', 'textdomain'),
26 'items_list' => _x('Portfolio items list', 'Screen reader text for the items list', 'textdomain'),
27 );
28
29 $args = array(
30 'labels' => $labels,
31 'public' => true,
32 'publicly_queryable' => true,
33 'show_ui' => true,
34 'show_in_menu' => true,
35 'query_var' => true,
36 'rewrite' => array('slug' => 'portfolio'),
37 'capability_type' => 'post',
38 'has_archive' => true,
39 'hierarchical' => false,
40 'menu_position' => 5,
41 'menu_icon' => 'dashicons-portfolio',
42 'show_in_rest' => true, // Enable Gutenberg editor
43 'supports' => array('title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions'),
44 );
45
46 register_post_type('portfolio', $args);
47}
48add_action('init', 'register_portfolio_post_type');

Register Custom Post Type

A comprehensive example of registering a custom post type in WordPress with all the common options configured. This creates a "Portfolio" post type with full support for the block editor, featured images, and custom taxonomies.

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

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array('slug' => 'portfolio'),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => 5,
        'menu_icon'          => 'dashicons-portfolio',
        'show_in_rest'       => true, // Enable Gutenberg editor
        'supports'           => array('title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions'),
    );

    register_post_type('portfolio', $args);
}
add_action('init', 'register_portfolio_post_type');

Key Options Explained

  • show_in_rest: Enables the block (Gutenberg) editor
  • has_archive: Creates an archive page at /portfolio/
  • menu_position: Controls where it appears in admin menu (5 = below Posts)
  • supports: Which editor features are available (title, editor, featured image, etc.)
  • rewrite: Customizes the URL slug

Next Steps

After adding this code, remember to:

  1. Flush rewrite rules by visiting Settings > Permalinks
  2. Register custom taxonomies if needed
  3. Create custom templates (single-portfolio.php, archive-portfolio.php)

Related Snippets