I need to display every product, and in case it’s a variable product (e.g. multiple colors), each variation on the shop page.
At first, I wrote my own query to retrieve all variations if the product had them:
$product = get_product();
global $variable_id;
global $color;
if ($product->product_type == "variable") {
$variations = $product->get_available_variations();
foreach ($variations as $variation) {
$color = $variation["attributes"]["attribute_pa_colour"];
$variable_id = $variation['variation_id'];
wc_get_template_part('content', 'product');
}
} else {
$variable_id = null;
$color = null;
wc_get_template_part('content', 'product');
}
I set the global parameter for the variation and got the right image afterwards in another template file with success.
The problem with this solution is that the pagination is broken (1 product appears multiple times).
So, what I need to achieve is manipulating the main product query to select all products, where those who have variations must appear once for each variation with the correct image link and variation value (I need the info of the main product aswell to link to the correct page).
This could be achieved by a Left Join
on the same products table, based on post_parent
.
The key here is to keep the default woocommerce behavior. This is the woocommerce function to retrieve the products:
private function query_products( $args ) {
// Set base query arguments
$query_args = array(
'fields' => 'ids',
'post_type' => 'product',
'post_status' => 'publish',
'meta_query' => array(),
);
if ( ! empty( $args['type'] ) ) {
$types = explode( ',', $args['type'] );
$query_args['tax_query'] = array(
array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => $types,
),
);
unset( $args['type'] );
}
// Filter products by category
if ( ! empty( $args['category'] ) ) {
$query_args['product_cat'] = $args['category'];
}
// Filter by specific sku
if ( ! empty( $args['sku'] ) ) {
if ( ! is_array( $query_args['meta_query'] ) ) {
$query_args['meta_query'] = array();
}
$query_args['meta_query'][] = array(
'key' => '_sku',
'value' => $args['sku'],
'compare' => '='
);
$query_args['post_type'] = array( 'product', 'product_variation' );
}
$query_args = $this->merge_query_args( $query_args, $args );
return new WP_Query( $query_args );
}
So basically, I need to find a way to override this function, so that a WP_Query
object is returned containing all ‘simple’ products and a product for each variation of all ‘variable’ products, while all parameters passed with $args
keep working.
I have found a solution: “Woocommerce Show Single Variations” plugin:
https://iconicwp.com/products/woocommerce-show-single-variations/
Remark: If you already have categories, you have to remove and re-add them. Also, it still does not work for shortcodes, the author is working on it though.
Updated: Changed the link to the plugin