If you've been working with WordPress for any serious length of time, especially on client projects or custom applications, you know the power of Custom Post Types (CPTs). They transform WordPress from a simple blogging platform into a robust content management system capable of handling anything from products and portfolios to event listings or, in my case, detailed notification templates like those in my OpenWA WhatsApp Gateway plugin.
But simply registering a CPT isn't enough in today's WordPress landscape. The real magic happens when you integrate these custom post types seamlessly with the modern Gutenberg block editor. This integration doesn't just make the editing experience smoother for your users; it empowers them to structure rich, dynamic content exactly as needed. In this in-depth guide, I'll walk you through the practical steps to create custom post type Gutenberg block editor support, drawing from my 8+ years of real-world development experience building complex plugins and applications.
I've learned that merely understanding the theory isn't enough. You need actionable steps and examples that reflect common scenarios. Whether it's setting up complex data structures for a School ERP or defining notification messages for WooCommerce orders using OpenWA, mastering CPTs with Gutenberg is crucial.
Why Custom Post Types are Essential for Modern WordPress Development
Before diving into Gutenberg, let's quickly recap why CPTs are indispensable. In my early days, I'd sometimes try to cram everything into pages or posts, maybe using categories and tags to differentiate. It quickly became unmanageable. CPTs provide a structured way to manage different types of content independently. Think about a real-world scenario: for my OpenWA WhatsApp Gateway plugin, I needed a way to store and manage various WhatsApp notification templates — for new orders, order status changes, OTP verification, and more. Creating a CPT called 'whatsapp_template' for these allowed me to define custom fields, assign specific capabilities, and keep them separate from blog posts or pages.
Similarly, for the Frontend File Explorer plugin, I leveraged CPTs to manage virtual files and folders, enabling a robust file system within WordPress. This separation ensures data integrity, improves administration, and allows for specific queries and functionalities tied only to that content type.
But the editing experience for these custom content types often felt lacking with classic meta boxes. That's where Gutenberg steps in.
The Power of Gutenberg Integration for Custom Post Types
The Gutenberg block editor has revolutionized how we create content in WordPress. It moves beyond a simple WYSIWYG editor, offering a visual, block-based system that mirrors the front-end output. For custom post types, this means:
- Enhanced User Experience: Instead of juggling multiple meta boxes and custom fields, users can visually construct content using pre-defined blocks.
- Structured Content: Blocks encourage structured content. You can enforce certain layouts or components for your CPTs, ensuring consistency.
- Developer Control: As developers, we get fine-grained control over what blocks are available for a specific CPT, ensuring content creators stick to the intended design and functionality.
- Reusability: Blocks are inherently reusable, speeding up content creation.
When I was designing the admin interface for OpenWA, I wanted to give merchants an intuitive way to compose their WhatsApp messages. While I initially used custom text areas, envisioning a block-based template builder was always a goal. This is exactly the kind of problem Gutenberg solves — letting users build dynamic content with ease for their custom data structures.
Step-by-Step: How to Register a Custom Post Type and Enable Gutenberg
Let's get practical. The first step to integrate with the Gutenberg block editor is to correctly register your custom post type with the necessary arguments. I typically do this within my plugin's main file or a dedicated CPT file, hooked into init.
1. Registering Your Custom Post Type
Here's a basic example, inspired by how I might set up a 'Template' CPT for a notification system:
function shafat_register_whatsapp_template_cpt() {
$labels = [
'name' => _x( 'WhatsApp Templates', 'Post Type General Name', 'openwa-gateway' ),
'singular_name' => _x( 'WhatsApp Template', 'Post Type Singular Name', 'openwa-gateway' ),
'menu_name' => __( 'WhatsApp Templates', 'openwa-gateway' ),
'name_admin_bar' => __( 'WhatsApp Template', 'openwa-gateway' ),
'archives' => __( 'Template Archives', 'openwa-gateway' ),
'attributes' => __( 'Template Attributes', 'openwa-gateway' ),
'parent_item_colon' => __( 'Parent Template:', 'openwa-gateway' ),
'all_items' => __( 'All Templates', 'openwa-gateway' ),
'add_new_item' => __( 'Add New Template', 'openwa-gateway' ),
'add_new' => __( 'Add New', 'openwa-gateway' ),
'new_item' => __( 'New Template', 'openwa-gateway' ),
'edit_item' => __( 'Edit Template', 'openwa-gateway' ),
'update_item' => __( 'Update Template', 'openwa-gateway' ),
'view_item' => __( 'View Template', 'openwa-gateway' ),
'view_items' => __( 'View Templates', 'openwa-gateway' ),
'search_items' => __( 'Search Templates', 'openwa-gateway' ),
'not_found' => __( 'Not found', 'openwa-gateway' ),
'not_found_in_trash' => __( 'Not found in Trash', 'openwa-gateway' ),
'featured_image' => __( 'Featured Image', 'openwa-gateway' ),
'set_featured_image' => __( 'Set featured image', 'openwa-gateway' ),
'remove_featured_image' => __( 'Remove featured image', 'openwa-gateway' ),
'use_featured_image' => __( 'Use as featured image', 'openwa-gateway' ),
'insert_into_item' => __( 'Insert into template', 'openwa-gateway' ),
'uploaded_to_this_item' => __( 'Uploaded to this template', 'openwa-gateway' ),
'items_list' => __( 'Templates list', 'openwa-gateway' ),
'items_list_navigation' => __( 'Templates list navigation', 'openwa-gateway' ),
'filter_items_list' => __( 'Filter templates list', 'openwa-gateway' ),
];
$args = [
'label' => __( 'WhatsApp Template', 'openwa-gateway' ),
'description' => __( 'Custom WhatsApp notification templates.', 'openwa-gateway' ),
'labels' => $labels,
'supports' => ['title', 'editor', 'custom-fields'], // 'editor' is crucial for Gutenberg!
'hierarchical' => false,
'public' => false, // Often CPTs for settings/internal data are not public
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 5, // Just below Posts
'menu_icon' => 'dashicons-whatsapp', // A nice WhatsApp icon
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => false,
'exclude_from_search' => true,
'publicly_queryable' => false,
'capability_type' => 'post',
'show_in_rest' => true, // THIS IS THE KEY FOR GUTENBERG BLOCK EDITOR INTEGRATION!
];
register_post_type( 'whatsapp_template', $args );
}
add_action( 'init', 'shafat_register_whatsapp_template_cpt', 0 );
The most critical argument for Gutenberg integration here is 'show_in_rest' => true. This makes your CPT available via the WordPress REST API, which is what Gutenberg relies on to fetch and save content. Without it, you'll be stuck with the classic editor. Also, ensure 'supports' includes 'editor'.
2. Controlling Allowed Blocks for Your CPT
Once Gutenberg is enabled for your CPT, you might not want all available blocks to be usable. For a specific CPT like 'WhatsApp Template', you might only want a 'Heading' block for the template title, a 'Paragraph' block for the message body, and perhaps a custom block for inserting dynamic variables. This is where the allowed_block_types_for_post_type filter comes in handy.
function shafat_allowed_whatsapp_template_blocks( $allowed_blocks, $editor_context ) {
if ( ! empty( $editor_context->post->post_type ) && 'whatsapp_template' === $editor_context->post->post_type ) {
// Define which blocks are allowed for 'whatsapp_template' CPT.
// 'core/paragraph' is essential for text.
// 'core/heading' for titles.
// 'openwa/template-variable' would be a custom block I'd create for OpenWA.
$allowed_blocks = [
'core/paragraph',
'core/heading',
'core/list',
'core/shortcode',
// 'openwa/template-variable', // Example of a custom block for OpenWA
// 'openwa/media-attachment', // If template supports media
];
}
return $allowed_blocks;
}
add_filter( 'allowed_block_types_for_post_type', 'shafat_allowed_whatsapp_template_blocks', 10, 2 );
This snippet demonstrates how you can whitelist specific blocks. I've used this principle in various projects to ensure that content creators stick to the design guidelines. For instance, in an ERP system where student profiles are CPTs, I'd only allow blocks relevant to displaying student data, not arbitrary image galleries.




