Using Custom Post Types in WordPress

By Voja Janjic

One of the WordPress features that enables powerful customization of the system are custom post types. Let's see what are they and how to implement them.

What Are Custom Post Types?

In object-oriented programming, each entity in the real system is represented by a corresponding class. For example, a product or an order would be represented as PHP classes. In WordPress, product and order would be created as post types. In other words, a post type is a custom data structure that allows you to apply any logic specifically to that post type. You will see how it works in practice shortly.

How to Create a Custom Post Type?

A custom post type can be created in two ways: using a plugin that handles all the work under the hood or directly in the theme. The latter provides more control over customization and allows you to keep the post type configuration consistent between the environments. So, let's see how to create a custom post type directly inside the theme.

Each post type must have its unique name in the system. You can name it anything, as long as it does not interfere with the built-in post types:

  • post
  • page
  • attachment
  • revision
  • nav_menu_item
  • custom_css
  • customize_changeset

or functions:

  • action
  • author
  • order
  • theme

Also, it is a good practice to prefix the name to avoid potential conflict with any installed plugins. Having these in mind, you will create a PHP file in the following location: wp-content/themes/mytheme/post-types/mys_portfolio.php, where mys_portfolio is the name of your custom post type (mys_ is the prefix and can be anything you want).

First, you will hook a PHP function to the WordPress init action:

add_action('init', 'mys_register_portfolio');

function mys_register_portfolio() {

This means that mys_register_portfolio function will be executed during the initialization of the WordPress CMS. Inside that function, you will call the WordPress' built-in function register_post_type:

add_action('init', 'mys_register_portfolio');

function mys_register_portfolio() {
	$args = array();
	register_post_type('mys_portfolio', $args);

After that, add the following line at the beginning of the functions.php:

require_once __DIR__ . '/post-types/mys_portfolio.php'; 

The code from above has created a custom post type called mys_portfolio with the default configuration. Fortunately, the configuration can be customized:


add_action('init', 'mys_register_portfolio');

function mys_register_portfolio() {
    register_post_type('mys_portfolio', array(
        // These labels configure the wordings for your custom post type inside WordPress Admin
        'labels' => array(
            'name' => __('Portfolios', 'exp'),
            'singular_name' => __('Portfolio', 'exp'),
            'add_new_item' => 'Add New Portfolio',
            'new_item' => 'New Portfolio',
            'view_item' => 'View Portfolio',
            'search_item' => 'Search Portfolio'

            // These are only some labels - check reference for more

        // Show the archive page with the list of posts belonging to this post type
        // If disabled, archive page won't be visible to the users
        'has_archive' => true,

        // Shows the post type in admin menu
        'show_in_menu' => true,

        // Allows the post type to be shown in navigation menus
        'show_in_nav_menus'   => true,

        // Position in the menu on the left-hand side
        // Lower value puts the item up in the list
        'menu_position' => 20,

        // Values that are not needed can be removed from this array
        'supports' => array(
            // If enabled, post title can be set

            // Shows the WYSIWYG editor for post content

            // If enabled, post author field can be set

            // Allows the post to have a featured thumbnail

            // Allows the admin to add an excerpt to the post

            // Enables trackbacks

            // Enables commenting on this post type posts

            // Will autosave and store post versions in the database

            // Shows additional post options, such as menu order and parent post

            // Allows post formats to be defined

        // Defines the slug that will be used in the URLs for this post type
        // If not set, it will be equal to the post type name e.g. mys_portfolio
        'rewrite' => array(
            'slug' => 'portfolio'

        // Allows parent page to be specified
        'hierarchical' => true,

        // An array of existing taxonomies that are connected to this post type
        'taxonomies' => array()


Note that the register_post_type options listed above are the most important ones. For the full list, check the documentation.

Querying Custom Post Types

The default template file for showing the list of posts is archive.php, while the default file that shows a single post is called single.php. These files can be overridden to be specific to the custom post type. If you create a file called archive-mys_portfolio.php, it will be loaded when a user tries to open the list of posts for that post type. Similarly, if a file called single-mys_portfolio.php has been created, it will be loaded when a user tries to open a single post that belongs to that custom post type.

It is also possible to get custom post type posts anywhere in the theme using WP_Query:

	$args = [
	    'posts_per_page' => 3,
	    'post_type' => 'mys_portfolio',
	    'post_status' => 'publish',
	    'orderby' => 'date',
	    'order'   => 'DESC'

	$article_query = new WP_Query($args);

	if($article_query->have_posts()) {
		while($article_query->have_posts()) {

			// Do something here


Custom post types make WordPress suitable for creating any type of Web site. Apart from a blog, you can create personal portfolios, corporate presentations, e-commerce sites and much more.

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
Thanks for your registration, follow us on our social networks to keep up-to-date