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, like title, editor, thumbnail, excerpt, custom-fields and revisions.
  • 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.
«
»