Custom post types and taxonomies
Posts and pages are just two built-in content types. Books, products, job openings, reviews and events are better kept in types of their own: each gets its own dashboard section, addresses and templates.
Registering a type
// books.php (a plugin)
add_action('init', function () {
register_post_type('book', [
'labels' => [
'name' => 'Books',
'singular_name' => 'Book',
'add_new_item' => 'Add a book',
'edit_item' => 'Edit book',
],
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-book',
'supports' => ['title', 'editor', 'thumbnail', 'excerpt'],
'rewrite' => ['slug' => 'books'],
'show_in_rest' => true,
]);
});A "Books" section appears in the dashboard, the list of books opens at /books/, and a single book at /books/title/.
The main settings
| Setting | Meaning |
|---|---|
public | The type is visible on the site and in the dashboard |
has_archive | There is a list page |
supports | Which fields the editor has |
rewrite | The part of the address |
menu_icon | The icon in the dashboard menu |
show_in_rest | Available in the REST API and the block editor |
hierarchical | Posts can nest inside each other, like pages |
A custom taxonomy
A taxonomy is a way to group posts. Categories and tags are built-in taxonomies; for books let us add genres:
add_action('init', function () {
register_taxonomy('genre', 'book', [
'labels' => [
'name' => 'Genres',
'singular_name' => 'Genre',
],
'public' => true,
'hierarchical' => true,
'rewrite' => ['slug' => 'genre'],
'show_in_rest' => true,
]);
});hierarchical: true makes the taxonomy resemble categories — with nesting; false makes it resemble tags.
Templates
By the template hierarchy the new type gets files of its own:
| File | Used for |
|---|---|
single-book.php | The page of one book |
archive-book.php | The list of books |
taxonomy-genre.php | Books of one genre |
<?php
// single-book.php
get_header();
while (have_posts()) :
the_post();
?>
<article class="book">
<h1><?php the_title(); ?></h1>
<?php the_post_thumbnail('large'); ?>
<p class="genres"><?php the_terms(get_the_ID(), 'genre', 'Genre: ', ', '); ?></p>
<?php the_content(); ?>
</article>
<?php
endwhile;
get_footer();Theme or plugin
Post types are registered in a plugin. If they are declared in a theme, the "Books" section disappears from the dashboard after a change of design, although the posts themselves stay in the database.
Common mistake
Right after a new type is registered, its pages return a 404 error: WordPress has not updated its address rules yet. Open "Settings → Permalinks" and press "Save" — the rules are rebuilt. A plugin does this once on activation:
register_activation_hook(__FILE__, function () {
books_register_types();
flush_rewrite_rules();
});Never call flush_rewrite_rules() on every load of the site: it is a slow operation.