Set meta_query only for specific post type

Quick explanation

Search is search and not an archive.

If you’ll take a look at is_post_type_archive docs, you’ll see that it:

Checks if the query is for an archive page of a given post type(s).

So if you’re using this condition in your pre_get_posts, then it won’t affect search results at all.

On the other hand this meta_query:

$q->set( 'meta_query', array(array(
    'key'       => '_stock_status',
    'value'     => 'outofstock',
    'compare'   => 'NOT IN'
)));

tells that you want to get only posts that have this meta value set and different than outoofstock, so it will exclude all posts and pages (because they don’t have such meta value at all).

Solution

add_action( 'pre_get_posts', 'hide_out_of_stock_from_search' );

function hide_out_of_stock_from_search( $q ) {

    if ( ! is_admin() && $q->is_main_query() && $q->is_search() ) {

        $q->set( 'meta_query', array(
            'relation' => 'OR',
            array(
                'key'       => '_stock_status',
                'value'     => 'outofstock',
                'compare'   => 'NOT IN'
            ),
            array(
                'key'       => '_stock_status',
                'compare'   => 'NOT EXISTS'
            )
        ));

    }
}