When you register a custom post type with register_post_type(), the supports argument determines which built-in WordPress features are enabled for it. But after the initial registration — which you might not control if the CPT is registered by another plugin — you can still add or remove support for individual features using add_post_type_support() and remove_post_type_support(). These functions modify the global $_wp_post_type_features registry at runtime. This is the correct way to retroactively add excerpt support to WooCommerce products, add custom field support to a CPT registered by a third-party plugin, enable the revisions panel for a CPT that disabled it, or add trackback support to a non-standard content type. The inverse — remove_post_type_support() — removes features from any CPT, including built-in ones like post and page.
Problem: A WooCommerce site needs: (1) the excerpt metabox enabled on the product CPT (WooCommerce registers products without excerpt support by default), (2) the comments metabox removed from page, and (3) a custom capability support type 'my-gallery' checked in a template to conditionally render a gallery metabox.
Solution: Use add_post_type_support() and remove_post_type_support() in the init hook. Check custom support types with post_type_supports() before rendering UI.
<?php
// ── Run on init at priority 20 to ensure CPTs are already registered ──
add_action( 'init', function () {
// ── 1. Add excerpt to WooCommerce products ────────────────────────
add_post_type_support( 'product', 'excerpt' );
// ── 2. Add custom-fields metabox to WooCommerce products ──────────
add_post_type_support( 'product', 'custom-fields' );
// ── 3. Remove comments metabox from pages ────────────────────────
remove_post_type_support( 'page', 'comments' );
remove_post_type_support( 'page', 'trackbacks' );
// ── 4. Register a custom support type for my gallery feature ─────
// Any string can be a support type — used as a flag for other code
add_post_type_support( 'portfolio', 'my-gallery' );
add_post_type_support( 'product', 'my-gallery' );
}, 20 );
// ── Check support type before adding metabox ──────────────────────────
add_action( 'add_meta_boxes', function () {
$types_with_gallery = get_post_types_by_support( 'my-gallery' );
foreach ( $types_with_gallery as $post_type ) {
add_meta_box(
'my-gallery-box',
__( 'Gallery Images', 'textdomain' ),
'render_gallery_metabox',
$post_type,
'normal',
'high'
);
}
} );
// ── Conditional check anywhere in your code ───────────────────────────
function render_gallery_metabox( WP_Post $post ): void {
if ( ! post_type_supports( $post->post_type, 'my-gallery' ) ) {
return;
}
// render gallery UI...
}
// ── Core support types reference ──────────────────────────────────────
// 'title' — title input
// 'editor' — content editor (TinyMCE / Gutenberg)
// 'author' — author dropdown
// 'thumbnail' — featured image metabox
// 'excerpt' — excerpt metabox
// 'trackbacks' — send trackbacks metabox
// 'custom-fields' — custom fields metabox
// 'comments' — comments metabox
// 'revisions' — revisions panel
// 'page-attributes' — page order and parent dropdown
// 'post-formats' — post format metabox
// ── List all post types that support a feature ────────────────────────
$cpts_with_revisions = get_post_types_by_support( 'revisions' );
NOTE: add_post_type_support() must run after the target CPT is registered — use priority 20 or later on init. For WooCommerce-registered CPTs, this is guaranteed to be after WooCommerce's own init at default priority 10. Removing the 'editor' support from a post type in the Gutenberg era can have unexpected effects — it replaces the block editor with a plain text area, not just hides it. To keep Gutenberg but hide specific panels, use the remove_meta_box() function or the allowed_block_types_all filter instead. Custom support types (any arbitrary string) are a lightweight way to implement feature flags for your own plugin's UI without adding a separate post meta or option.