WordPress add_post_type_support(): Add or Remove Features from Any CPT at Runtime

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.