How to Print All Variations of a Product in WooCommerce

Quick Summary
- Fetch every variation with get_posts using post_type product_variation and post_parent set to the product ID, since each variation is its own post.
- Loading each one with new WC_Product_Variation gives get_image for its image tag and get_price_html for the formatted price with sale markup.
- The query includes disabled variations, which WooCommerce saves as private; keep only publish in post_status to list enabled ones.
WooCommerce saves every variation of a variable product as its own post, with the post type product_variation and the parent product as its post_parent. So you can fetch all variations with a normal get_posts() query, then load each one as a WooCommerce object to read its image, price and custom fields. That is useful when you want to build your own variation list or table on the single product page.
Use the code in a template where the current post is the product, such as a single product template override in your theme, because it relies on get_the_ID() to find the parent product.
$args = array(
'post_type' => 'product_variation',
'post_status' => array( 'private', 'publish' ),
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'asc',
'post_parent' => get_the_ID() // Product ID
);
$variations = get_posts( $args );
foreach ( $variations as $variation ) {
// get variation ID
$variation_ID = $variation->ID;
// get variations meta
$product_variation = new WC_Product_Variation( $variation_ID );
// get variation featured image
$variation_image = $product_variation->get_image();
// get variation price
$variation_price = $product_variation->get_price_html();
// get variation custom field
$date_expire = get_post_meta( $variation_ID , '_text_field_date_expire', true );
// print the variation
echo '<div class="product-variation">';
echo $variation_image;
echo $variation_price;
echo esc_html( $date_expire );
echo '</div>';
}How it works
'post_parent' => get_the_ID()limits the query to the variations of the current product. Outside the loop, put a product ID there instead.'post_status' => array( 'private', 'publish' )also returns disabled variations, because WooCommerce saves a disabled variation as private. Keep only'publish'if you want enabled variations only.'numberposts' => -1returns all variations, and ordering bymenu_orderkeeps the order you set by dragging them in the product editor.new WC_Product_Variation()loads the variation, so you can callget_image()for its image as an<img>tag andget_price_html()for the formatted price, including sale price markup. On the parent product the same method returns the min–max price range, as in displaying the variable product price range.get_post_meta()reads a custom field saved on the variation._text_field_date_expireis a field from the original project, so replace it with your own meta key.
Printing the values
At the end of each pass, the loop prints the variation’s image, price and custom field inside a div; change that markup to fit your template. get_image() and get_price_html() return HTML built by WooCommerce, while the custom field is plain text, so it’s escaped with esc_html().
For variation tables and custom product layouts built into your theme, see my WooCommerce development services.
Related articles
- showing each variation’s SKU under the title: a lighter loop over the same variation data
- stock status next to each variation option: when the list belongs in the dropdown itself
