Add CPT to search results non-destructively?

The following amends the core search query to include a custom post type in the results.

function myprefix_amend_search_query($query) {
    if (!$query->is_search) {
        return $query;
    }

    $post_types_to_include = [
        'post',
        'page',
        'my_cpt'
    ];

    $query->set('post_type', $post_types_to_include);

    return $query;

}
add_filter('pre_get_posts', 'myprefix_amend_search_query');

The above does not account for cases where other plugins may have included their own CPTs in the results. To solve for this, we can use any, as follows:

function myprefix_amend_search_query($query) {
    if (!$query->is_search) {
        return $query;
    }

    $query->set('post_type', 'any');

    return $query;

}
add_filter('pre_get_posts', 'myprefix_amend_search_query');

However, it seems like using any may include items that are unintended for search in some cases.

So, the question is: what is the proper way to amend the query to include a few new custom post types while not interfering with any other plugins that may also be adding custom post types to core search?

Just merge your CPTs into whatever is already there:

$my_types = ['my_cpt'];
$their_types = $query->get('post_type');
// @todo: make sure $their_types is an array
$query->set('post_type', array_merge($their_types, $my_types));

(Not tested but should be pretty close to working).

I tried and tried $query->get('post_type'); and it kept coming back empty, so, I thought something wasn’t working quite right. Off on a tangent I went…lol. I realize now it was a simple priority issue. I was testing with a plugin named aaa, so, being the first plugin loaded, $query->get('post_type'); should come back empty since no other plugins had a chance to register their post types for search. I’m going to set a higher priority on the hook to ensure that it fires after others, just in case another plugin didn’t get it right…like I almost didn’t. :slight_smile: Thanks for getting me back on track. Here’s the final working code if anyone else needs it.

function update_search_query($query) {

    // Not a search? Bail.
    if (!$query->is_search) {
        return $query;
    }

    // Currently searchable post types.
    $post_types_in_search = $query->get('post_type');

    // New post types to add to search.
    $post_types_to_include = [
        'my_cool_cpt',
        'my_neat_cpt',
    ];

    // Update the query.
    $query->set('post_type', array_merge($post_types_in_search, $post_types_to_include));

    // Return the query.
    return $query;

}

add_filter('pre_get_posts', 'amend_search_query', 100); // Note the late priority.