How to Create Custom Post Types in WordPress

By: Irina Shvaya | November 10, 2025

By default, WordPress gives you two primary ways to organize content: Posts and Pages. While versatile, they are often insufficient for building a truly structured, scalable, and user-friendly website. For any business with unique content needs—from a law firm showcasing case results to a construction company displaying projects—the key to unlocking WordPress's full potential as a true content management system (CMS) lies in Custom Post Types (CPTs).

Custom Post Types allow you to create new, dedicated content types that are completely separate from standard posts and pages. They transform a generic WordPress installation into a tailored platform, enabling you to build highly organized, manageable, and queryable content models. For developers and site owners, mastering CPTs is a fundamental step toward creating sophisticated, professional-grade websites that are both powerful on the back end and intuitive on the front end.

This in-depth guide provides a developer-focused walkthrough for creating, managing, and displaying Custom Post Types. We will cover everything from initial planning and registration to templating, SEO, and security, with practical examples for industries like healthcare, legal, SaaS, and local services.

1. What Are Custom Post Types (And When Should You Use Them)?

A Custom Post Type is a distinct type of content in WordPress, just like a Post or a Page. However, it has its own unique name, its own menu in the WordPress admin, its own set of custom fields (metadata), and its own templates for display.

CPTs vs. Posts, Pages, and Categories

It's crucial to know when a CPT is the right tool for the job.

  • Use a Page when: The content is static, timeless, and hierarchical (e.g., About Us, Services, Contact, Privacy Policy).
  • Use a Post when: The content is chronological, timely, and can be grouped by categories and tags (e.g., blog articles, news updates, company announcements).
  • Use a Custom Post Type when: You have a group of content that is neither a standard post nor a page, and it requires its own unique data structure and presentation.

Ask yourself: "Does this content need its own set of unique properties and its own dedicated management area in the admin?" If the answer is yes, you need a CPT. Using categories to separate different content types (e.g., having a "Case Studies" category on your blog) is a common but flawed approach that leads to a disorganized back end and difficult-to-manage templates.

Planning Your Content Model: Industry Examples

Before writing any code, map out your content model. What information does this content type need?

  • For a Law Firm:
    • CPT: "Case Results"
    • Custom Fields: Date of Verdict, Verdict Amount, Practice Area, Presiding Judge.
    • Custom Taxonomy: "Practice Area" (e.g., Personal Injury, Family Law).
  • For a Construction Company:
    • CPT: "Projects"
    • Custom Fields: Project Location, Completion Date, Square Footage, Project Manager, Photo Gallery.
    • Custom Taxonomy: "Service Type" (e.g., Commercial Remodeling, New Home Construction).
  • For a Healthcare Provider:
    • CPT: "Providers"
    • Custom Fields: Credentials (e.g., MD, DO), Specialties, Office Location, Education, Headshot.
    • Custom Taxonomy: "Specialty" (e.g., Cardiology, Orthopedics).
  • For a SaaS Company:
    • CPT: "Resources" or "Knowledge Base"
    • Custom Fields: Version Number, Related Feature, Video URL.
    • Custom Taxonomy: "Topic" (e.g., Billing, API Integration).
  • For a CPA Firm:
    • CPT: "Team Members"
    • Custom Fields: Title (e.g., Partner, Senior Accountant), CPA License Number, Email, LinkedIn Profile.
    • Custom Taxonomy: "Department" (e.g., Audit, Tax Advisory).

This initial planning phase is a critical component of any professional custom WordPress web design project.

2. How to Register a Custom Post Type

You have two primary methods for registering a CPT: writing the code yourself or using a plugin.

Method 1: The Code-Based Approach (Recommended)

For professional, portable, and performant CPTs, registering them via code in a custom plugin or your theme's functions.php file is the superior method. This ensures your CPTs are part of your codebase, can be version-controlled with Git, and aren't dependent on a third-party plugin.

The core of this process is the register_post_type() function, which should always be called within a function hooked to the init action.

// In a custom plugin or your theme's functions.php
function esespace_register_project_cpt() {
// See argument breakdown below
$args = array( /* ... */ );
register_post_type( 'project', $args );
}
add_action( 'init', 'esespace_register_project_cpt' );

Deconstructing the register_post_type() Arguments

The $args array is where you define every aspect of your CPT. Let's break down the most important arguments using our "Projects" CPT example.

function esespace_register_project_cpt() {
$labels = array(
'name'                  => _x( 'Projects', 'Post type general name', 'eseospace-custom' ),
'singular_name'         => _x( 'Project', 'Post type singular name', 'eseospace-custom' ),
'menu_name'             => _x( 'Projects', 'Admin Menu text', 'eseospace-custom' ),
'name_admin_bar'        => _x( 'Project', 'Add New on Toolbar', 'eseospace-custom' ),
// ... other labels like 'add_new', 'edit_item', etc.
);
$args = array(
'labels'             => $labels,
'public'             => true,
'publicly_queryable' => true,
'show_ui'            => true,
'show_in_menu'       => true,
'query_var'          => true,
'rewrite'            => array( 'slug' => 'projects' ), // The URL slug for your CPT archive
'capability_type'    => 'post',
'has_archive'        => true, // Enables an archive page at /projects/
'hierarchical'       => false,
'menu_position'      => 5, // Position in the admin menu
'menu_icon'          => 'dashicons-portfolio', // Icon for the admin menu
'supports'           => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'show_in_rest'       => true, // Exposes the CPT to the REST API and Block Editor
);
register_post_type( 'project', $args );
}
add_action( 'init', 'esespace_register_project_cpt' );
  • labels: An array that defines all the text strings used in the admin UI for this CPT. Providing detailed labels is crucial for a user-friendly back end.
  • public: A master switch. Setting this to true makes the CPT visible on the front end and in the admin, automatically setting many other arguments to true.
  • rewrite: Controls the URL structure. _'rewrite' => array( 'slug' => 'projects' )`` means your CPT single pages will have a URL like yoursite.com/projects/my-awesome-project/.
  • has_archive: Setting this to true creates an archive page for all your CPT entries, accessible at yoursite.com/projects/. This is essential for findability.
  • supports: Defines which core WordPress meta boxes are enabled for this CPT (e.g., Title, Editor, Featured Image).
  • show_in_rest: This is critical for modern WordPress. Setting it to true is required for your CPT to be editable with the Gutenberg block editor and accessible via the REST API.

Method 2: Using a Plugin

For those less comfortable with code, plugins like Custom Post Type UI (CPT UI) provide a graphical interface for registering CPTs and taxonomies.

  • Pros: Easy to use, no code required, good for rapid prototyping.
  • Cons: Your CPT definitions are stored in the database and tied to the plugin. If you deactivate the plugin, your CPTs (and all their content) will disappear from WordPress. It also offers less granular control than the code-based method. This can become a long-term maintenance issue.

3. Structuring Your CPTs: Custom Taxonomies and Fields

A CPT on its own is just a container. Its real power comes from the structured data you attach to it.

Adding Custom Taxonomies

Taxonomies are used to group your CPT entries. You register them with the register_taxonomy() function, also hooked to init.

function esespace_register_project_taxonomy() {
$labels = array(
'name' => _x( 'Service Types', 'taxonomy general name', 'eseospace-custom' ),
// ... other labels
);
$args = array(
'hierarchical'      => true, // True for category-style, false for tag-style
'labels'            => $labels,
'show_ui'           => true,
'show_admin_column' => true,
'query_var'         => true,
'rewrite'           => array( 'slug' => 'service-type' ),
'show_in_rest'      => true,
);
// The first argument is the taxonomy name.
// The second argument is the CPT it should be attached to.
register_taxonomy( 'service_type', array( 'project' ), $args );
}
add_action( 'init', 'esespace_register_project_taxonomy' );

Now, when editing a "Project," you'll see a "Service Types" meta box, just like the "Categories" box for standard posts.

Supercharging CPTs with Advanced Custom Fields (ACF)

While WordPress has basic custom fields, the Advanced Custom Fields (ACF) plugin is the industry standard for creating robust, user-friendly data entry forms for your CPTs. With ACF (or using core meta boxes), you can add fields like date pickers, image galleries, text inputs, and more.

You would create a "Field Group" in ACF and assign it to show only when the post type is "Project." This is how you add the "Project Location," "Completion Date," and other custom data from our planning phase.

4. Displaying Your Custom Post Types on the Front End

Once you have content in your CPT, you need to display it. This is where WordPress's template hierarchy shines.

Leveraging the Template Hierarchy for CPTs

WordPress looks for specific template files to display your CPTs. For a CPT named project:

  • Archive Page (/projects/): WordPress looks for archive-project.php. If not found, it falls back to archive.php, then index.php.
  • Single Page (/projects/my-project/): WordPress looks for single-project.php. If not found, it falls back to single.php, then index.php.

By creating these files in your theme, you can have complete control over the layout and display of your CPT content. Inside these templates, you'll use a standard WordPress Loop to query and display the posts, and functions like get_field() (for ACF) to display your custom field data.

Creating CPT Templates in Modern Block Themes

In a modern block theme, the same hierarchy applies, but with .html files in your theme's /templates directory.

  • Create archive-project.html and single-project.html.
  • Inside these files, you can design the layout using the block editor. You can use core blocks like "Post Title," "Post Featured Image," and "Post Content."
  • To display custom field data from ACF, you can use ACF's own block-based tools or custom blocks that fetch and render the metadata.

This block-based approach allows for visually designing your CPT templates, giving you immense power and flexibility. This is a core competency for any modern WordPress development agency.

5. Optimizing the Admin Experience

A professional CPT setup considers the client's experience in the WordPress admin.

Customizing the Admin Columns

By default, the CPT list screen only shows the title and date. You can add columns to display important custom data, like a project's completion date or a provider's specialty.

// Add the custom column to the 'project' post type.
add_filter( 'manage_project_posts_columns', 'esespace_set_custom_edit_project_columns' );
function esespace_set_custom_edit_project_columns($columns) {
$columns['completion_date'] = __( 'Completion Date', 'eseospace-custom' );
return $columns;
}
// Add the data to the custom column.
add_action( 'manage_project_posts_custom_column', 'esespace_custom_project_column', 10, 2 );
function esespace_custom_project_column( $column, $post_id ) {
if ( $column == 'completion_date' ) {
echo get_post_meta( $post_id, 'completion_date', true );
}
}

Get a FREE Audit

We'll perform a comprehensive SEO, AEO, GEO & CRO audit of your website — completely free — and show you exactly how to outrank your competitors.

Don't have a site yet? Get in touch →

Adding Custom Filters

You can also add dropdown filters to the admin screen, allowing users to filter CPT entries by custom taxonomy terms (e.g., filter "Providers" by "Specialty").

Changing the Menu Icon

In your register_post_type() arguments, the _'menu_icon'_ parameter lets you choose from any of the built-in WordPress Dashicons, or you can provide a URL to a custom SVG icon for a fully branded experience.

6. Advanced Considerations for Professional CPTs

SEO for Custom Post Types

Properly configured CPTs are excellent for SEO, but you need to get the details right.

  • Permalinks: Ensure you set a clean, logical slug in your rewrite argument.
  • Archives: Enable archives ('has_archive' => true) to create landing pages for your content types, which can be optimized to rank for key terms.
  • Titles and Metas: Use an SEO plugin like Yoast or Rank Math to control the SEO titles and meta descriptions for your CPT singles and archives.
  • Schema Markup: CPTs are perfect for implementing specific schema. A "Provider" CPT could use Physician schema, a "Project" could use RealEstateListing schema, and a "Case Result" could use LegalCase schema. This provides rich context to search engines. A comprehensive SEO strategy should always include a plan for CPTs.

Security, Performance, and Scalability

  • Security: Always sanitize and validate any data from custom fields before saving it to the database or outputting it on the front end.
  • Performance: For sites with thousands of CPT entries, ensure your archive queries are efficient. Use caching and avoid complex meta_query calls on high-traffic pages.
  • Scalability: The code-based approach is far more scalable than a plugin-based one, as it can be easily managed, version-controlled, and deployed across multiple environments.

Exposing CPTs to the REST API

Setting _'show_in_rest' => true_ makes your CPT content available via the WordPress REST API. This is essential for building "headless" or decoupled applications, or for integrating your WordPress content with other applications and services.

Final CPT Setup Checklist

Before deploying a new Custom Post Type, run through this checklist:

Custom Post Types are the key to unlocking WordPress's true power as a flexible and scalable CMS. By moving beyond posts and pages, you can build highly structured, manageable, and valuable digital assets for any industry.

Need to architect a complex content model or migrate existing content into a new CPT structure? Contact ESEOspace. Our WordPress development experts specialize in building robust, scalable, and SEO-friendly CPT solutions.

Make Your Website Competitive.

Leverage our expertise in Website Design + SEO Marketing, and spend your time doing what you love to do!

You Might Also like to Read