wordpress custom post type

How To Create WordPress Custom Post Type

WordPress Custom post type (CPT) allows you to create different content types for your website even different templates for your custom post type manually and with a plugin. WordPress comes with five post types: post, page, attachment, revision, and menu by default. In this article, we are going to discuss what is the WordPress custom post type and how to create the custom one.

Besides the usual “pages” and “posts”, you can generate your own custom post types for all manner of purposes. Once a custom post type is registered, it gets a new top-level administrative screen that can be used to manage and create posts of that type.

What is a WordPress custom post type?

Post types are used to help distinguish between different content types in WordPress. Posts and pages are both post types but are made for various purposes.

While developing your plugin or theme, you may need to create your own specific content type: for example, products for an e-commerce website, assignments for an e-learning website, or movies for a review website. The most widely used custom post type in WordPress is probably “portfolio”.

WordPress custom post types have been around for a long time, since WordPress 1.5 added support for static pages, creating the post_type database field.

All custom post types in WordPress will be saved in the wp_posts table in the database. Custom post types can have different custom fields and their own custom category structure.

Why use custom post types in WordPress?

Because when building sites, you’ll sometimes find that you’re constrained by the limitations of the WordPress default “Post Types”. In some situations, this will simply be that you’re looking to create something clearly different than either of those things.

Another place that the need for new “post” or content types reveals itself is when you’ve created a deeply nested hierarchy within your default Pages content type to get the kind of permalinks you want.

Before you start creating custom post types on your WordPress site, it’s important to evaluate your needs.

Apart from these, you can modify countless options, such as where the custom post type should be placed in the menu, whether should it be searchable, which user level can access it, whether should it be hierarchical, custom rewrite rules, etc.

How to add custom post types in WordPress

You can create custom post types in many different ways: manually and by plugins. Manually you can register your custom post type in your theme or in your plugin in WordPress.

To effectively create and use custom post types, you’ll need to be familiar with the following:

  • Creating custom post types,
  • Creating custom taxonomies,
  • Creating custom meta boxes.

How to add and create a custom WordPress post type manually without a plugin

A custom post type is nothing more than a regular post with a different post_type value in the database.

Creating a custom post type requires you to add code to your theme’s functions.php file. If you are using another developer’s theme, the best way is, to create a child theme and add the code in its functions.php file otherwise If you update the theme, your codes will be gone.

Open the functions.php file and add the following codes there.

function hs_custom_post_type() {
	register_post_type('hs_post_type',
		array(
			'labels'      => array(
				'name'          => __('Post Types', 'textdomain'),
				'singular_name' => __('Post Type', 'textdomain'),
			),
			'public'      => true,
			'has_archive' => true,
		)
	);
}
add_action('init', 'hs_custom_post_type');

WordPress has a built-in function register_post_type() to register a custom post type.

If you go to your WordPress Dashboard you could see the menu of the post type in the menu list.

wordpress custom post type

This example is the simplest custom post type. But you can add more customization to your post type.

function hs_custom_post_type() {
	register_post_type('hs_post_type',
		array(
			'labels'      => array(
				'name'               => _x( 'Post Types', 'post type general name' ),
				'singular_name'      => _x( 'Post Type', 'post type singular name' ),
				'add_new'            => _x( 'Add New', 'book' ),
				'add_new_item'       => __( 'Add New Post Type' ),
				'edit_item'          => __( 'Edit Post Type' ),
				'new_item'           => __( 'New Post Type' ),
				'all_items'          => __( 'All Post Type' ),
				'view_item'          => __( 'View Post Type' ),
				'search_items'       => __( 'Search Post Types' ),
				'update_item'        => __( 'Update Post Type' ),
				'not_found'          => __( 'No Post Types found' ),
				'not_found_in_trash' => __( 'No Post Types found in the Trash' ), 
				'parent_item_colon'  => __( 'Parent Post Type' ),
				'menu_name'          => _x( 'Post Types', 'post type general name' ),
			),
			'label'       => __( 'post type' ),
			'description'   => 'Holds our Post Types and Post Type specific data',
			'public'      => true,
			'menu_position' => 5,
			'supports'      => array( 'title', 'editor', 'excerpt', 'author', 'thumbnail', 'comments', 'revisions', 'custom-fields', 'trackbacks', 'page-attributes', 'post-formats' ),
			'has_archive' => true,
			'taxonomies'  => array( 'hscategory','hstag' ),
			'hierarchical'        => false,
			'show_ui'             => true,
			'show_in_menu'        => true,
			'show_in_nav_menus'   => true,
			'show_in_admin_bar'   => true,
			'can_export'          => true,
			'exclude_from_search' => false,
			'publicly_queryable'  => true,
			'capability_type'     => 'post',
			'show_in_rest' => true,
		)
	);	
}
add_action('init', 'hs_custom_post_type');

The important options are:

  • labels The labels option should be an array defining the different labels that a custom post type can have.
  • description A short explanation of your custom post type.
  • public Setting this to true will set a bunch of other options (all to do with visibility) to true. For example, it is possible to have the custom post type visible but not queryable.
  • menu_position Defines the position of the custom post type menu in the back end. Setting it to “5” places it below the “posts” menu.
  • supports This option sets up the default WordPress controls that are available in the edit screen for the custom post type. By default, only the title field and editor are shown. For a full list take a look at the arguments section in the Codex.
  • has_archive If set to true, rewrite rules will be created for you, enabling a post type archive at https://mysite.com/posttype/ (by default)

You should be able to add posts, view the post list in the admin, and also visit the published posts on the website.

In this picture, you can see the Categories and Tags sections. If you execute the above example you won’t see them. You will learn about how to add the category and tag to your custom post type in this article.

The post types URL

A custom post type gets its own slug within the site URL structure.

A post of type hs_post_type will use the following URL structure by default:

http://example.com/hs_post_type/%post_type_name%.

hs_post_type is the slug of your custom post type and %post_type_name% is the slug of your particular product.

You can see the permalink on the edit screen for your custom post type, just like with default post types.

Register category and tag section to custom post type

In the registering post type section, you didn’t add taxonomies to your post type. In this section, you are going to add custom taxonomies to your post type.

To add categories to your post type you could use the below code.

function hs_category_post_type() {
	$labels = array(
        "name" => __( "Categories", "" ),
        "singular_name" => __( "Categories", "" ),
    );

    $args = array(
        "label" => __( "Categories", "" ),
        "labels" => $labels,
        "public" => true,
        "hierarchical" => true,
        "label" => "Categories",
        "show_ui" => true,
        "show_in_menu" => true,
        "show_in_nav_menus" => true,
        "query_var" => true,
        "rewrite" => array( 'slug' => 'hs-category', 'with_front' => true, ),
        "show_admin_column" => true,
        "show_in_rest" => true,
        "rest_base" => "",
        "show_in_quick_edit" => false,
    );
    register_taxonomy( "hscategory", 'hs_post_type', $args );
}
add_action( 'init', 'hs_category_post_type', 0 );

You have to sure you set “show_in_rest”, “show_admin_column” and “show_ui” to true.

In the following code, you can add the tag section to your custom post type.

function hs_tag_post_type() {
	$labels = array(
        "name" => __( "Tags", "" ),
        "singular_name" => __( "Tags", "" ),
    );

    $args = array(
        "label" => __( "Tags", "" ),
        "labels" => $labels,
        "public" => true,
        "hierarchical" => false,
        "label" => "Tags",
        "show_ui" => true,
        "show_in_menu" => true,
        "show_in_nav_menus" => true,
        "query_var" => true,
        "rewrite" => array( 'slug' => 'hs-tag', 'with_front' => true, ),
        "show_admin_column" => true,
        "show_in_rest" => true,
        "rest_base" => "",
        "show_in_quick_edit" => false,
    );

	register_taxonomy('hstag', 'hs_post_type', $args);
}
add_action( 'init', 'hs_tag_post_type', 0 );

The only item that is different in category and tag is the “hierarchical” item. In category it is true and in the tag it is false.

But if you have a custom post type already and you want to register a category or tag to the post type you can use the following codes.

function hs_taxonomies_post_type() {
    $labels = array(
        "name" => __( "Categories", "" ),
        "singular_name" => __( "Categories", "" ),
    );

    $args = array(
        "label" => __( "Categories", "" ),
        "labels" => $labels,
        "public" => true,
        "hierarchical" => true,
        "label" => "Categories",
        "show_ui" => true,
        "show_in_menu" => true,
        "show_in_nav_menus" => true,
        "query_var" => true,
        "rewrite" => array( 'slug' => 'category', 'with_front' => true, ),
        "show_admin_column" => false,
        "show_in_rest" => false,
        "rest_base" => "",
        "show_in_quick_edit" => false,
    );
    register_taxonomy( "category", 'hs_post_type', $args );
  }
  
  add_action( 'init', 'hs_taxonomies_post_type', 0 );

And for tag:

function hs_taxonomies_post_type() {
	register_taxonomy_for_object_type('post_tag', 'hs_post_type');
}
  
add_action( 'init', 'hs_taxonomies_post_type', 0 );

WordPress Custom post type templates

You can create your custom WordPress post type with custom templates. In the same way posts and their archives can be displayed using single.php and archive.php, you can create the templates:

  • single-{post_type}.php – for single posts of a custom post type
  • archive-{post_type}.php – for the archive

According to the example we created previously, you can create single-hs_post_type.php and archive-hs_post_type.php to display the content of the custom post type. The files must be in the root folder of your theme.

Display custom post type content in WordPress

This task can be done in two ways. If you are going to display your content in the post type single page like single-hs_post_type.php file, you can use the normal syntax of the WordPress content display.

get_header();

while ( have_posts() ) :
	the_post();?>

	<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>

	<header class="entry-header">
		<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
		<figure class="post-thumbnail">
			<?php the_post_thumbnail( 'post-thumbnail' ); ?>
		</figure>
	</header>

	<div class="entry-content">
		<?php the_content(); ?>
	</div>
</article>

<?php
endwhile;

get_footer();

Or you may want to display your custom post content in another place like a WordPress widget that you can use WP_Query to display it.

$args = array(
	'post_type'      => 'hs_post_type',
	'posts_per_page' => 10,
);
$loop = new WP_Query($args);
while ( $loop->have_posts() ) {
	$loop->the_post();
	?>
	<div class="entry-content">
		<?php the_title(); ?>
		<?php the_content(); ?>
	</div>
	<?php
}

If you have created a custom post type in Dashboard, if you click the “view” on one of your posts you will be redirected to the single-hs_post_type.php template. But there is a little trick. You may see the 404 Error but don’t worry. If you change your website permalink in the Settings in Dashboard to “Post name”, you can see your content.

Alternatively, you can use the is_post_type_archive() function in any template file to check if the query shows an archive page of a given post type, and the post_type_archive_title()  function to display the post type title.

if ( is_post_type_archive( 'hs_post_type' ) ) {
    // Do stuff
}

post_type_archive_title('hs_post_type');

Sometimes you may want to alter the content of your custom post type, to do that you can use the following code.

function hs_add_custom_post_types($query) {
	if ( is_home() && $query->is_main_query() ) {
		$query->set( 'post_type', array( 'post', 'page', 'hs_post_type' ) );
	}
	return $query;
}
add_action('pre_get_posts', 'hs_add_custom_post_types');

Create a taxonomy template for your theme

Like custom post type you can use WordPress hierarchy to display the taxonomy content.

  • taxonomy-{taxonomy}-{slug}.php We could use this to create a theme template for a particular location, such as taxonomy-library-book.php for the term “book.”
  • taxonomy-{taxonomy}.php If the taxonomy were location, WordPress would look for taxonomy-library.php.
  • taxonomy.php This template is used for all custom taxonomies.
  • archive.php If no taxonomy-specific template is found, then the taxonomy that lists pages will use the archive template.
  • index.php If no other template is found, then this will be used.

For example create taxonomy-hs-category.php in your root folder of your theme and add the following code.

<?php
get_header();
$term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
?>
<div class="wrapper">
  <div class="primary-content">
    <h1 class="archive-title"><?php echo apply_filters( 'the_title', $term->name ); ?> News</h1>

    <?php if ( !empty( $term->description ) ): ?>
    <div class="archive-description">
      <?php echo esc_html($term->description); ?>
    </div>
    <?php endif; ?>

    <?php if ( have_posts() ): while ( have_posts() ): the_post(); ?>

    <div id="post-<?php the_ID(); ?>" <?php post_class('post clearfix'); ?>>
      <h2 class="post-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
        <div class="post-info">
          <p><?php the_time(get_option('date_format')); ?> by <?php the_author_posts_link(); ?></p>
        </div>
        <div class="entry">
          <?php the_content( __('Full story…') ); ?>
        </div>
    </div>

    <?php endwhile; ?>

    <?php else: ?>

    <h2 class="post-title">No Post Type in <?php echo apply_filters( 'the_title', $term->name ); ?></h2>
    <div class="content clearfix">
      <div class="entry">
        <p>It seems there isn't anything happening in <strong><?php echo apply_filters( 'the_title', $term->name ); ?></strong> right now. Check back later, something is bound to happen soon.</p>
      </div>
    </div>

    <?php endif; ?>
  </div>

<?php get_footer(); ?>

Add meta box to WordPress custom post type

Meta boxes are the draggable boxes you see in the WordPress edit screen for a post. There are numerous built-in meta boxes like the publishing controls, the taxonomies, the author box, etc., but you can create some for yourself.

To add a meta box, use the following code:

add_action( 'add_meta_boxes', 'hs_post_type_box' );
function hs_post_type_box() {
    add_meta_box( 
        'hs_post_type_box',
        __( 'HS Meta Box' ),
        'hs_post_type_box_content',
        'hs_post_type',
        'side',
        'high'
    );
}

function hs_post_type_box_content( $post ) {
    echo '<label for="hs_meta_box"></label>';
    echo '<input type="text" id="hs_meta_box" name="hs_meta_box" placeholder="enter a content" />';
}
post type in wordpress

Custom interaction messages

WordPress generates a number of messages triggered by user actions. Updating, publishing, searching, etc., in the back end all lead to messages that — by default — are tailored to regular posts. You can change the text of these messages easily by using the post_updated_messages hook.

function hs_custom_post_type_messages( $messages ) {
    global $post, $post_ID;
    $messages['hs_post_type'] = array(
        0 => '’', 
        1 => sprintf( __('Post Type updated. <a href="%s">View Post Type</a>'), esc_url( get_permalink($post_ID) ) ),
        2 => __('Custom field updated.'),
        3 => __('Custom field deleted.'),
        4 => __('Post Type updated.'),
	5 => isset($_GET['revision']) ? sprintf( __('Post Type restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
	6 => sprintf( __('Post Type published. <a href="%s">View Post Type</a>'), esc_url( get_permalink($post_ID) ) ),
	7 => __('Post Type saved.'),
	8 => sprintf( __('Post Type submitted. <a target="_blank" href="%s">Preview Post Type</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
	9 => sprintf( __('Post Type scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview Post Type</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
	10 => sprintf( __('Post Type draft updated. <a target="_blank" href="%s">Preview Post Type</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
    );
    return $messages;
}
add_filter( 'post_updated_messages', 'hs_custom_post_type_messages' );

Creating a custom WordPress post type With a Plugin

Another easy way to create a custom post type in WordPress is by using a plugin. In this section, we are going to introduce plugins to create and add custom post types to your WordPress website.

You may like

Registering Custom Post Types

Shopping Cart