You can try using $wpdb, like this:
// Use the global variable $wpdb;
global $wpdb;
// :: Define SQL command ::
// You can request for the IDs only,
// and then get the properties later on via get_post_meta or WC_Product()
$q = 'SELECT wp_posts.ID ';
$q .= 'FROM wp_posts ';
// Attach wp_postmeta table
$q .= 'JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) ';
// Attach taxonomy and term tables
$q .= 'JOIN wp_term_relationships ON ( wp_posts.ID = wp_term_relationships.object_id ) ';
$q .= 'JOIN wp_term_taxonomy ON ( wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id ) ';
$q .= 'JOIN wp_terms ON ( wp_term_taxonomy.term_id = wp_terms.term_id ) ';
// WHERE statements
$q .= 'WHERE ';
// Post should be published
$q .= 'wp_posts.post_status = "publish" ';
$q .= 'AND ';
// Post should have either product or product_variation as post_type
$q .= '(';
$q .= 'wp_posts.post_type = "product" ';
$q .= 'OR ';
$q .= 'wp_posts.post_type = "product_variation" ';
$q .= ')';
$q .= 'AND ';
// Post should have ##color_meta_key## = ##color_meta_value##
$q .= '(';
$q .= 'wp_postmeta.meta_key = "##color_meta_key##" ';
$q .= 'AND ';
$q .= 'wp_postmeta.meta_value = "##color_meta_value##" ';
$q .= ')';
$q .= 'AND ';
// Post should belong to taxonomy_term with ##taxonomy_term_id## as ID
$q .= 'wp_term_taxonomy.term_id IN ( ##taxonomy_term_id## ) ';
// Ordered according to date, descending
$q .= 'ORDER BY wp_posts.post_date DESC ';
// Limit the result to 18
$q .= 'LIMIT 18 '
// Will return an object
$wpdb->get_results($q);