Custom Post Types (CPT) Development in WordPress

Custom Post Types (CPT) Development in WordPress

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1281
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1237
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    977
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1026
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1103
  • image_website-_0.webp
    Website development for Red Pear
    550

Custom Post Types (CPT) Development in WordPress

Imagine a client asks for a "Portfolio" section with a filter by year, but standard posts don't provide a custom URL or custom fields. We face this regularly. WordPress out of the box works with two content types — Posts and Pages. When a site needs Projects, Vacancies, Real Estate, Testimonials, or Products, a custom post type (CPT) is created for each. CPT provides a separate section in /wp-admin, its own URLs, archive pages, and full control over data structure. Registering a CPT with basic settings takes a few hours; full configuration with pretty URLs, custom columns, and search capabilities takes 1–2 days. Our experience: over 50 configured CPTs for various projects, from portfolios to online stores.

How to register a CPT with correct settings?

Registration starts with the init hook. Inside, call register_post_type with required parameters. Consider an example for the "Projects" type:

add_action('init', function () { register_post_type('project', [ 'labels' => [ 'name' => 'Projects', 'singular_name' => 'Project', 'add_new' => 'Add Project', 'add_new_item' => 'New Project', 'edit_item' => 'Edit Project', 'new_item' => 'New Project', 'view_item' => 'View Project', 'search_items' => 'Search Projects', 'not_found' => 'No projects found', 'not_found_in_trash' => 'Trash is empty', 'menu_name' => 'Projects', ], 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true, 'query_var' => true, 'rewrite' => ['slug' => 'projects', 'with_front' => false], 'capability_type' => 'post', 'has_archive' => 'projects', 'hierarchical' => false, 'menu_position' => 5, 'menu_icon' => 'dashicons-portfolio', 'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'], 'show_in_rest' => true, 'rest_base' => 'projects', ]); }); 

has_archive => 'projects' creates an archive page at /projects/ — all posts of this type go there. show_in_rest => true makes the type accessible via REST API and in the Gutenberg editor. After registration, be sure to update permalink rules: in the admin, go to "Settings → Permalinks" and click "Save" or execute flush_rewrite_rules() upon activation.

Custom columns in the post list and sorting

By default, the projects list shows only the title and date. Let's add columns "Client", "Year", and "Featured" — all sortable. Here's a compact code block including column registration, data output, and sorting:

// Register columns and output data add_filter('manage_project_posts_columns', function (array $columns): array { $new = []; foreach ($columns as $key => $title) { $new[$key] = $title; if ($key === 'title') { $new['client'] = 'Client'; $new['year'] = 'Year'; $new['featured'] = 'Featured'; } } unset($new['comments']); return $new; }); add_action('manage_project_posts_custom_column', function (string $column, int $post_id): void { switch ($column) { case 'client': echo esc_html(get_post_meta($post_id, '_project_client', true) ?: '—'); break; case 'year': echo esc_html(get_post_meta($post_id, '_project_year', true) ?: '—'); break; case 'featured': $is_featured = get_post_meta($post_id, '_project_featured', true); echo $is_featured ? '⭐' : '—'; break; } }, 10, 2); add_filter('manage_edit-project_sortable_columns', function (array $columns): array { $columns['year'] = 'year'; return $columns; }); add_action('pre_get_posts', function (WP_Query $query): void { if (!is_admin() || !$query->is_main_query()) return; if ($query->get('orderby') === 'year') { $query->set('meta_key', '_project_year'); $query->set('orderby', 'meta_value_num'); } }); 

Including CPT in WordPress search and filtering by taxonomy

By default, standard search does not include custom CPTs. Fix this via pre_get_posts:

add_action('pre_get_posts', function (WP_Query $query): void { if ($query->is_search() && !is_admin() && $query->is_main_query()) { $post_types = $query->get('post_type') ?: ['post']; if (!is_array($post_types)) { $post_types = [$post_types]; } $query->set('post_type', array_merge($post_types, ['project', 'vacancy'])); } }); 

And for filtering the list by taxonomy (e.g., project category) add a dropdown:

add_action('restrict_manage_posts', function (string $post_type): void { if ($post_type !== 'project') return; $taxonomy = get_taxonomy('project_category'); wp_dropdown_categories([ 'taxonomy' => 'project_category', 'name' => 'project_category', 'show_option_all' => 'All categories', 'selected' => $_GET['project_category'] ?? 0, 'value_field' => 'slug', 'hierarchical' => true, ]); }); 

Comparison: CPT vs taxonomy vs custom field

A common mistake is using a CPT where a taxonomy or field would suffice. The table below helps choose the right tool:

Entity When to use Example
Custom Post Type Need a separate page, archive, content editor Project, testimonial, job vacancy
Taxonomy Need grouping or filtering of posts Project category, service tag
Custom field Store an attribute of an existing post Product price, project year, office address

CPT is better than taxonomy for content-rich entities — it provides a separate URL, editor, and full control. Using a taxonomy instead of CPT means losing SEO potential and limiting content.

Which templates are needed for correct CPT display?

WordPress automatically looks for templates in a specific order. For the project type, the priority is:

Priority Template Purpose
1 single-project.php Single post
2 single.php Fallback for posts
3 archive-project.php Archive (list)
4 archive.php Fallback for archives

If the required template is missing, WordPress falls back to index.php. Creating single-project.php and archive-project.php is a baseline practice for any CPT.

Related posts between different CPTs

The standard way to relate two CPTs is to store IDs of related posts in post meta. For example, link cases to a project:

// Save relations update_post_meta($project_id, '_related_cases', array_map('absint', $case_ids)); // Get related cases $case_ids = get_post_meta($project_id, '_related_cases', true); if (!empty($case_ids)) { $cases = get_posts([ 'post_type' => 'case', 'post__in' => $case_ids, 'orderby' => 'post__in', 'posts_per_page' => -1, ]); } 

For bidirectional relationships (many-to-many), use the Posts 2 Posts plugin or create an intermediate table.

What's included in turnkey CPT setup

Our experience: over 5 years of WordPress development, over 50 configured CPTs for portfolios, online stores, and catalogs. The service includes:

  • CPT registration with full parameter set (pretty URLs, archive, icon, columns);
  • Custom columns with sorting and filtering;
  • Integration with search and REST API;
  • Creation of single-{cpt}.php and archive-{cpt}.php templates;
  • Documentation and access transfer;
  • Training for content managers.

We guarantee all CPTs will work correctly with Gutenberg and W3C validator. Contact us to discuss your project — we'll estimate the task within one business day. Get a consultation: we'll help choose the optimal architecture and implement your CPT faster than you can write a spec.

Why trust CPT setup to professionals?

Incorrect CPT registration leads to 404 errors, broken search, and performance drops. We use proven patterns: registration_hook for rule flushing, custom columns without extra queries, proper capability_type. Your site won't lose speed — we guarantee Core Web Vitals in the green zone.

For a deep understanding of the registration mechanism, refer to the official documentation: register_post_type. Our specialists are always ready to consult and find the right solution for your project.