Menu

Post Types in WordPress: How to Generate Them

June 3, 2017 - WordPress

Custom post types are a cornerstone of WP REST API. Today we will learn which default post types are already included in WordPress, where we can find them in the database and how to create them.

Default Post Types

All post types are stored in wp_posts database table. They are deferentiated by column named post_type

Default Post Types in Database

Custom Post Types

Custom post types are added in functions.php file in your theme.

In addition to post type names mentioned above you also shouldn’t use action, order, theme as a post type name. Best practice is to always prefix your post type, like 22nds_event to avoid conflicts

The code must be after action after_setup_theme action hook.

// Example
<?php add_action( 'after_setup_theme', 'twentyseventeen_setup' ); ?>

and before admin_menu action hook

// Example
<?php add_action('admin_menu', 'function_name'); ?>

Simple Custom Post Type

// functions.php
add_action( 'init', 'create_posttype' );
function create_posttype() {
  register_post_type( 'acme_product',
    array(
      'labels' => array(
        'name' => __( 'Products' ),
        'singular_name' => __( 'Product' )
      ),
      'public' => true,
      'has_archive' => true,
      'rewrite' => array('slug' => 'products'),
    )
  );
}

Custom Type - Products

Custom Post Type with Post Type Generator

Generator will make your job easier so make sure to use it.

Generator

After you enter all needed parameters, code will be generated and you can copy and paste it to your functions.php. In our example we have used Movies as the post type.

function custom_post_type() {

    $labels = array(
        'name'                  => _x( 'Movies', 'Post Type General Name', 'text_domain' ),
        'singular_name'         => _x( 'Movie', 'Post Type Singular Name', 'text_domain' ),
        'menu_name'             => __( 'Movies', 'text_domain' ),
        'name_admin_bar'        => __( 'Movie', 'text_domain' ),
        'archives'              => __( 'Item Archives', 'text_domain' ),
        'attributes'            => __( 'Item Attributes', 'text_domain' ),
        'parent_item_colon'     => __( 'Parent Item:', 'text_domain' ),
        'all_items'             => __( 'All Items', 'text_domain' ),
        'add_new_item'          => __( 'Add New Item', 'text_domain' ),
        'add_new'               => __( 'Add New', 'text_domain' ),
        'new_item'              => __( 'New Item', 'text_domain' ),
        'edit_item'             => __( 'Edit Item', 'text_domain' ),
        'update_item'           => __( 'Update Item', 'text_domain' ),
        'view_item'             => __( 'View Item', 'text_domain' ),
        'view_items'            => __( 'View Items', 'text_domain' ),
        'search_items'          => __( 'Search Item', 'text_domain' ),
        'not_found'             => __( 'Not found', 'text_domain' ),
        'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
        'featured_image'        => __( 'Featured Image', 'text_domain' ),
        'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
        'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
        'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
        'insert_into_item'      => __( 'Insert into item', 'text_domain' ),
        'uploaded_to_this_item' => __( 'Uploaded to this item', 'text_domain' ),
        'items_list'            => __( 'Items list', 'text_domain' ),
        'items_list_navigation' => __( 'Items list navigation', 'text_domain' ),
        'filter_items_list'     => __( 'Filter items list', 'text_domain' ),
    );
    $args = array(
        'label'                 => __( 'Movie', 'text_domain' ),
        'description'           => __( 'Simple movies database', 'text_domain' ),
        'labels'                => $labels,
        'supports'              => array( ),
        'taxonomies'            => array( 'category', 'post_tag' ),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 2,
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => true,
        'can_export'            => true,
        'has_archive'           => true,
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'capability_type'       => 'page',
    );
    register_post_type( 'my_movies', $args );

}
add_action( 'init', 'custom_post_type', 0 );

Note: When registering a post type, always register your taxonomies using the taxonomies argument.

Now we have Movies available in the admin area and we can add new items.

Custom Post Type - Movies

When we create a couple of new Movies, we can see in the database they are added to wp_posts table.

Custom Type in Database

Menu icons

WordPress suports a couple of options.

DashIcons

A large variety of icons is available in dashicons library
Search for the right icon and copy it’s name in the $args array:

'menu_icon' => 'dashicons-list-view',

image in the theme

'menu_icon' => get_template_directory_uri() . "/images/cutom-icon.png"'

SVG

You can also use any svg.

Here is an example from Font Awesome.
1. Find the icon you like, for example fa-shower
2. Then go to Font Awesome SVG library on GitHub and find the icon by name.
3. Click on the icon name, in our example shower.svg. Shower is located at https://github.com/encharm/Font-Awesome-SVG-PNG/blob/master/black/svg/shower.svg
4. Click on Raw and copy svg

<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1369 249q10 10 10 23t-10 23l-626 626q-10 10-23 10t-23-10l-82-82q-10-10-10-23t10-23l44-44q-72-91-81.5-207t46.5-215q-74-71-176-71-106 0-181 75t-75 181v1280h-256v-1280q0-104 40.5-198.5t109.5-163.5 163.5-109.5 198.5-40.5q106 0 201 41t166 115q94-39 197-24.5t185 79.5l44-44q10-10 23-10t23 10zm-89 263q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 128q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-640 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm192 64q0-26 19-45t45-19 45 19 19 45-19 45-45 19-45-19-19-45zm320-64q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-640 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 128q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-384 256q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-384 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 0q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-128 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-128 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19z"/></svg>
  1. Paste it in menu_icon together with some additional code and add fill="black"
'menu_icon' => 'data:image/svg+xml;base64,' . base64_encode('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1369 249q10 10 10 23t-10 23l-626 626q-10 10-23 10t-23-10l-82-82q-10-10-10-23t10-23l44-44q-72-91-81.5-207t46.5-215q-74-71-176-71-106 0-181 75t-75 181v1280h-256v-1280q0-104 40.5-198.5t109.5-163.5 163.5-109.5 198.5-40.5q106 0 201 41t166 115q94-39 197-24.5t185 79.5l44-44q10-10 23-10t23 10zm-89 263q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 128q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-640 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm192 64q0-26 19-45t45-19 45 19 19 45-19 45-45 19-45-19-19-45zm320-64q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-640 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 128q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-384 256q-26 0-45-19t-19-45 19-45 45-19 45 19 19 45-19 45-45 19zm256-128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-384 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm256 0q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-128 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19zm-128 128q26 0 45 19t19 45-19 45-45 19-45-19-19-45 19-45 45-19z" fill="black"/></svg>

SOURCE

image

Tip for pros: If you add custom types in the theme, any change of the theme will disable custom post types. So some developers advise to add custom post types as a plugin. Even though you will need to edit theme to be able to display the content.

Templates for custom post types

You can also use templates for you custom post types, the names are based on the name of the registered post type. Eg:

single_acme_product.php
archive_acme_product.php

Copy code from single.php to single-products.php and from content-single.php to content-products.php.

In single-products.php change

<?php get template_part( 'content', 'single'); ?>

to

<?php get template_part( 'content', 'products'); ?>

Query

$args = array( 'post_type' => 'product', 'posts_per_page' => 10 );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
  the_title();
  echo '<div class="entry-content">';
  the_content();
  echo '</div>';
endwhile;

Resources

Codex – Post Types
Codex – Register Post Type