Adding `supports` array to WordPress custom post type

Use 'supports' => [ 'title', 'editor', 'thumbnail' ] – different values, not keys.

If we look into register_post_type(), we find these lines:

if ( ! empty( $args->supports ) ) {
    add_post_type_support( $post_type, $args->supports );
    unset( $args->supports );
} elseif ( false !== $args->supports ) {
    // Add default features
    add_post_type_support( $post_type, array( 'title', 'editor' ) );
}

In add_post_type_support(), we see that the the values are converted to array keys with the value true:

function add_post_type_support( $post_type, $feature ) {
    global $_wp_post_type_features;

    $features = (array) $feature;
    foreach ($features as $feature) {
        if ( func_num_args() == 2 )
            $_wp_post_type_features[$post_type][$feature] = true;
        else
            $_wp_post_type_features[$post_type][$feature] = array_slice( func_get_args(), 2 );
    }
}

register_post_type() is calling add_post_type_support() with just two arguments, so the else in the latter function cannot be reached.

You can however, call add_post_type_support() directly and pass custom support features:

add_post_type_support(
    'my_campaigns',
    'subheadline',
    [
        'min_length' => 30,
        'max_length' => 300,
    ]
);

But then you have to call the function for each feature separately.

Side note: Please do not use 'name' => __( 'Campaigns' ). Without a text domain, this string is not translatable at all, but it triggers a look-up in WordPress default translation, which is rather huge – and slow. See How to Internationalize Your Plugin for details.