1

I have a list of products which should show variations in it's own row. The code for that works fine so far.

But I couldn't figure out how I could show the SKU of a variation.

Here's my current code:

$args = [
    'status'    => array('publish', 'draft'),
    'orderby'   => 'name',
    'order'     => 'ASC',
    'limit'     => -1,
];
$vendor_products = wc_get_products($args);

$list_array = array();

foreach ($vendor_products as $key => $product) {

    if ($product->get_type() == "variable") {

        foreach ($product->get_variation_attributes() as $variations) {
            foreach ($variations as $variation) {

                $list_array[] = array(
                    'SKU'      => $product->get_sku(),
                    'Name'     => $product->get_title() . " - " . $variation,
                );

            }
        }

    } else {

        $list_array[] = array(
            'SKU'      => $product->get_sku(),
            'Name'     => $product->get_title(),
        );


    }
}

return $list_array;

I tried to display the product attributes and I also tried to get the ID of the variation. Nothing works for me?!

Is there no simple way to get the variation SKU?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Cray
  • 5,307
  • 11
  • 70
  • 166
  • 1
    wc_get_products() is only for "product" type but not for product_variation type – LoicTheAztec Apr 08 '20 at 09:21
  • Ah ok, is there any other way to get to the SKU within my foreach loop? – Cray Apr 08 '20 at 09:28
  • so you want to get all variation skus from the variable products, as your are querying all "product" postype? – LoicTheAztec Apr 08 '20 at 09:32
  • Yes, kind of. I need the SKU of the variation instead the one from the parent product. I have already the addition of the variation in the title but couldn't get any other stuff like ID or SKU – Cray Apr 08 '20 at 09:35

1 Answers1

6

You should better use WC_Product_Variable get_children() method like:

$args = [
    'status'    => array('publish', 'draft'),
    'orderby'   => 'name',
    'order'     => 'ASC',
    'limit'     => -1,
];
$vendor_products = wc_get_products($args);

$list_array = array();

foreach ($vendor_products as $key => $product) {

    if ( $product->is_type( "variable" ) ) {

        foreach ( $product->get_children( false ) as $child_id ) {
            // get an instance of the WC_Variation_product Object
            $variation = wc_get_product( $child_id ); 

            if ( ! $variation || ! $variation->exists() ) {
                continue;
            }

            $list_array[] = array(
                'SKU'      => $variation->get_sku(),
                'Name'     => $product->get_name() . " - " . $child_id,
            );
        }

    } else {

        $list_array[] = array(
            'SKU'      => $product->get_sku(),
            'Name'     => $product->get_name(),
        );

    }

}

return $list_array;

Or even some other available methods like get_available_variations() (which use get_children() method when looking at its source code). It should better work...


Targeting product variations of a variable product with different other post statuses than "publish".

In this case you should replace get_children() method with a custom WP_Query that will handle other post statuses like below:

$statuses = array('publish', 'draft');

// Args on the main query for WC_Product_Query
$args = [
    'status'    => $statuses,
    'orderby'   => 'name',
    'order'     => 'ASC',
    'limit'     => -1,
];

$vendor_products = wc_get_products($args);

$list_array = array();

foreach ($vendor_products as $key => $product) {

    if ($product->get_type() == "variable") {

        // Args on product variations query for a variable product using a WP_Query
        $args2 = array( 
            'post_parent' => $product->get_id(), 
            'post_type'   => 'product_variation', 
            'orderby'     => array( 'menu_order' => 'ASC', 'ID' => 'ASC' ), 
            'fields'      => 'ids', 
            'post_status' => $statuses, 
            'numberposts' => -1, 
        ); 

        foreach ( get_posts( $args2 ) as $child_id ) {
            // get an instance of the WC_Variation_product Object
            $variation = wc_get_product( $child_id ); 

            if ( ! $variation || ! $variation->exists() ) {
                continue;
            }

            $list_array[] = array(
                'SKU'      => $variation->get_sku(),
                'Name'     => $product->get_name() . " - " . $child_id,
            );
        }

    } else {

        $list_array[] = array(
            'SKU'      => $product->get_sku(),
            'Name'     => $product->get_name(),
        );

    }

}

return $list_array;

This time you will get all the product variations of your variable products.

For reference: Product -> Get Children doesn't return all variations #13469

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thanks! That works fine. I tried to work with `get_available_variations()` but couldn't figure out what to do... ;) – Cray Apr 08 '20 at 10:09
  • Hmm, no there is another problem. With your code, there is not every product in the output. Is there any kind of limitation? Like only published products or something else? – Cray Apr 08 '20 at 10:13
  • 1
    Yes may be… So in your case you should better use a WP query instead with both post types product and product_variation… WP_Query are much more flexible than WC_Query which only allows few parameters and only product post type. – LoicTheAztec Apr 08 '20 at 10:17
  • Ah ok, I have no idea how to do that :-) But I figuered out, that the products had no variants (problem there) and it could happen if the variation isn't active: https://github.com/woocommerce/woocommerce/issues/13469 So I guess I could use your code from above. – Cray Apr 08 '20 at 10:28
  • 2
    @Cray I have updated my answer with an addition based on what you mentioned… Try it if you like. – LoicTheAztec Apr 08 '20 at 13:04