SponsoredHosinger Special Offer

WP+ WordPress Plugin Development

Build WordPress plugins from scratch: actions and filters, shortcodes, settings pages, custom post types, meta boxes, AJAX, REST endpoints, custom tables, cron and blocks.

Custom Post Types

WordPress Plugin Development Lesson 14 of 27 ~4 min read

Overview

A custom post type is a new kind of content — books, products, events — registered with register_post_type() so it gets its own admin menu, editor, URLs and archive just like posts and pages.

Registering the Book post type

<?php
function gdc_books_register_post_type() {
    $labels = array(
        'name'               => _x( 'Books', 'post type general name', 'gdc-books' ),
        'singular_name'      => _x( 'Book', 'post type singular name', 'gdc-books' ),
        'add_new_item'       => __( 'Add New Book', 'gdc-books' ),
        'edit_item'          => __( 'Edit Book', 'gdc-books' ),
        'new_item'           => __( 'New Book', 'gdc-books' ),
        'view_item'          => __( 'View Book', 'gdc-books' ),
        'search_items'       => __( 'Search Books', 'gdc-books' ),
        'not_found'          => __( 'No books found.', 'gdc-books' ),
        'not_found_in_trash' => __( 'No books found in Trash.', 'gdc-books' ),
        'all_items'          => __( 'All Books', 'gdc-books' ),
        'menu_name'          => __( 'Books', 'gdc-books' ),
    );

    register_post_type(
        'gdc_book',
        array(
            'labels'        => $labels,
            'public'        => true,
            'has_archive'   => 'books',                  // Archive at /books/.
            'rewrite'       => array( 'slug' => 'book' ), // Single at /book/the-hobbit/.
            'menu_icon'     => 'dashicons-book',
            'menu_position' => 20,
            'supports'      => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ),
            'show_in_rest'  => true,                     // Required for the block editor.
            'capability_type' => 'post',
        )
    );
}
add_action( 'init', 'gdc_books_register_post_type' );

The arguments that matter

ArgumentEffect
Post type key gdc_bookUp to 20 characters, lowercase, no spaces. Prefix it — book alone will clash with other plugins.
publicVisible on the front end and in the admin.
has_archiveCreates an archive page. A string sets its URL slug.
rewriteThe URL slug for single items.
supportsWhich editor panels appear: title, editor, featured image, excerpt…
show_in_restExposes the type to the REST API. Without it, the block editor is not used — you get the classic editor.
hierarchicaltrue for page-like parent/child items.
menu_iconA Dashicon name or an SVG data URI.

Flush rewrite rules — once

After registering, visiting /books/ gives a 404 until WordPress rebuilds its URL rules. Do it on activation, as in lesson 7 — never on every init:

<?php
register_activation_hook( __FILE__, function () {
    gdc_books_register_post_type();
    flush_rewrite_rules();
} );
Tip: While developing, you can flush manually by visiting Settings → Permalinks and clicking Save.

Showing books in the main blog feed

Custom post types do not appear in the main posts list by default. Add them with pre_get_posts:

<?php
function gdc_books_in_home_query( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        $query->set( 'post_type', array( 'post', 'gdc_book' ) );
    }
}
add_action( 'pre_get_posts', 'gdc_books_in_home_query' );

Displaying books

The plugin registers the type; the theme decides how it looks with single-gdc_book.php and archive-gdc_book.php. The WordPress Theme Development path covers those templates. A plugin can also ship default templates and let themes override them — the template_include filter makes that possible.

Practice

  • Register gdc_book with the labels above, activate the plugin and add three books.
  • Visit /books/ and a single book. If you get a 404, flush permalinks.
  • Set show_in_rest to false temporarily and notice the editor change to the classic editor.
Create a free account to save which lessons you've finished. Save my progress