How To Register A Custom Post Type In WordPress
A custom post type, or CPT, is a new type of content besides posts and pages, such as portfolio items, products, events or testimonials. Register it with register_post_type() on the init hook.
Register a Portfolio post type
function lotgrafix_register_portfolio() {
$labels = array(
'name' => __( 'Portfolio', 'lotgrafix' ),
'singular_name' => __( 'Project', 'lotgrafix' ),
'add_new_item' => __( 'Add New Project', 'lotgrafix' ),
'edit_item' => __( 'Edit Project', 'lotgrafix' ),
'all_items' => __( 'All Projects', 'lotgrafix' ),
'search_items' => __( 'Search Projects', 'lotgrafix' ),
);
register_post_type( 'lotgrafix_portfolio', array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'rewrite' => array( 'slug' => 'portfolio' ),
'menu_icon' => 'dashicons-portfolio',
'menu_position' => 5,
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
'show_in_rest' => true,
) );
}
add_action( 'init', 'lotgrafix_register_portfolio' );
Key arguments
public: makes the type visible on the front end and in the admin.has_archive: creates an archive page at the rewrite slug.rewrite: controls the URL slug.supports: the editor features, liketitle,editor,thumbnail,excerpt,custom-fieldsandrevisions.show_in_rest: required for the block editor and the REST API.menu_icon: a Dashicons class or a custom icon URL.
Flush the permalinks
After registering a new post type, go to Settings, Permalinks and click Save Changes. Otherwise the new URLs may show a 404 error.
Display it with a template
Create these files in your theme and WordPress will use them automatically.
archive-lotgrafix_portfolio.php: the archive page.single-lotgrafix_portfolio.php: a single item page.
Important notes
- The post type name can have a maximum of 20 characters, lowercase letters, numbers and underscores.
- If you register the post type inside a theme, the content disappears from the admin when you change the theme. For client sites, put it in a plugin.


