Blog
How to Create Custom Post Types in WordPress

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 totruemakes the CPT visible on the front end and in the admin, automatically setting many other arguments totrue.rewrite: Controls the URL structure._'rewrite' => array( 'slug' => 'projects' )`` means your CPT single pages will have a URL likeyoursite.com/projects/my-awesome-project/.has_archive: Setting this totruecreates an archive page for all your CPT entries, accessible atyoursite.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 totrueis 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 forarchive-project.php. If not found, it falls back toarchive.php, thenindex.php. - Single Page (
/projects/my-project/): WordPress looks forsingle-project.php. If not found, it falls back tosingle.php, thenindex.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.htmlandsingle-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
rewriteargument. - 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
Physicianschema, a "Project" could useRealEstateListingschema, and a "Case Result" could useLegalCaseschema. 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_querycalls 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:
- Planning: Is the content model clearly defined (CPT name, fields, taxonomies)?
- Registration: Is the CPT registered via code in a custom plugin or child theme?
- Arguments: Are all labels, rewrite rules, and support features correctly configured?
- REST API: Is
'show_in_rest'set totruefor block editor compatibility? - [ ] Taxonomies: Are all necessary custom taxonomies registered and assigned?
- [ ] Custom Fields: Have you created the ACF field group and assigned it to the CPT?
- [ ] Templates: Have you created the
archive-{cpt-slug}.phpandsingle-{cpt-slug}.phptemplate files? - [ ] SEO: Have you flushed your permalinks (Settings > Permalinks > Save Changes) and checked your URL structure?
- [ ] Admin UI: Have you improved the admin experience with custom columns or icons?
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!






