How to combine two WP_Query objects?

What about just querying for both terms and increasing the posts_per_page count.

$category_query = new WP_Query([
   'posts_per_page' => 36,
    'post_type' => 'product',
    'tax_query' => [
       [
         'taxonomy' => 'product_cat',
         'terms' => [ 120, 121 ],
         'field' => 'id',
         'include_children' => false
      ]
    ]
 ]);

EDIT:

Running a query with more that one term and guarantees 18 for each term ( assuming there are at least 18 items for each ) is not possible as far as I know.

My recommendation would be to run two separate queries, merge the results together and then cache that post list. This would allow you to only hit the database once the cache is invalidated.

Example: ( I’ve left the args out for brevity as the only thing that changes is the term id. )

// Look for the cached posts
$merged_items = get_transient( 'my_category_query' );

// If we don't have them, get and cache them
if( false === $merged_items ) {
    $cat_query_one = new WP_Query( $args_with_the_first_term );
    $cat_query_two = new WP_Query( $args_with_the_seccond_term );
    $merged_items = array_merge( $cat_query_one->posts, $cat_query_two->posts );
    set_transient( 'my_category_query', $merged_items, DAY_IN_SECONDS );
}

// Display your posts
foreach ( $merged_items as $post ) {
   // ...
}

Something to consider is that is to adjust your query to only get the post IDs using the fields => 'ids' parameter. This will make the query faster and also you can use the ID to retrieve most of the data you want to display.

Some other performance tips with WP_Query:

  • 'no_found_rows' => true: useful when pagination is not needed by not doing the calculations to determine how many post there are in total for the query.
  • 'update_post_meta_cache' => false: useful when post meta will not be utilized.
  • update_post_term_cache' => false: useful when taxonomy terms will not be utilized.

You should also be refreshing the cache when new content is added that will affect this query.