Register a Custom Post Type with REST & Archive in WordPress
When building a WordPress site, you often need to create custom content types beyond posts and pages. Registering a custom post type (CPT) with REST API support and archive pages enables you to manage and display this content efficiently, especially when using headless setups or custom themes. This tutorial shows you how to register a custom post type with REST and archive capabilities using clean, copy-paste-ready code.
When to Use a Custom Post Type with REST & Archive
- Custom Content Organization: When you want to separate content like portfolios, testimonials, products, or events from regular posts.
- REST API Integration: If you plan to use the WordPress REST API to fetch or manipulate your custom content in JavaScript apps or external systems.
- Archive Pages: When you want an automatically generated archive page listing all items of your custom post type.
Quick Fix: Register a Custom Post Type with REST & Archive
- Add the provided PHP code snippet to your theme’s
functions.php
file or create a mini-plugin. - Visit the WordPress admin to confirm the new post type menu appears.
- Test the REST API endpoint and archive page.
Why This Happens
By default, WordPress supports posts and pages. To handle other content types, you must register a custom post type using register_post_type()
. Enabling 'show_in_rest' => true
makes the CPT accessible via the REST API. Setting 'has_archive' => true
tells WordPress to generate an archive page for this CPT, allowing visitors to browse all items.
Step-by-step: Registering a Custom Post Type with REST & Archive
Below is a complete example registering a custom post type called book
. This CPT supports REST API access and has an archive page.
<?php
function register_book_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. Added in 4.3', 'textdomain' ),
'set_featured_image' => _x( 'Set cover image', 'Overrides the “Set featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
'remove_featured_image' => _x( 'Remove cover image', 'Overrides the “Remove featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
'use_featured_image' => _x( 'Use as cover image', 'Overrides the “Use as featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
'archives' => _x( 'Book archives', 'The post type archive label used in nav menus. Default “Post Archives”. Added in 4.4', 'textdomain' ),
'insert_into_item' => _x( 'Insert into book', 'Overrides the “Insert into post”/”Insert into page” phrase (used when inserting media into a post). Added in 4.4', 'textdomain' ),
'uploaded_to_this_item' => _x( 'Uploaded to this book', 'Overrides the “Uploaded to this post”/”Uploaded to this page” phrase (used when viewing media attached to a post). Added in 4.4', 'textdomain' ),
'filter_items_list' => _x( 'Filter books list', 'Screen reader text for the filter links heading on the post type listing screen. Default “Filter posts list”/”Filter pages list”. Added in 4.4', 'textdomain' ),
'items_list_navigation' => _x( 'Books list navigation', 'Screen reader text for the pagination heading on the post type listing screen. Default “Posts list navigation”/”Pages list navigation”. Added in 4.4', 'textdomain' ),
'items_list' => _x( 'Books list', 'Screen reader text for the items list heading on the post type listing screen. Default “Posts list”/”Pages list”. Added in 4.4', 'textdomain' ),
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'books' ),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 5,
'menu_icon' => 'dashicons-book',
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
'show_in_rest' => true,
'rest_base' => 'books',
'rest_controller_class' => 'WP_REST_Posts_Controller',
);
register_post_type( 'book', $args );
}
add_action( 'init', 'register_book_post_type' );
How to Add This Code
You can add the above code in two ways:
- functions.php: