Programmatically added variations not showing until clicking Update button

This is starting to give me a headache so hope someone here can help me and together we can help others with the same problem!

I built a plugin which generates product variations for WooCommerce automatically. This all seems to work fine except for one thing. New variations are not visible in the frontend and when I look at the product edit page they are listed like this:

Product variations wrong

When I hit the Update button and save the product, it gets magically fixed. Variations are visible in the frontend and in the back they look like this now:

Product variations correct

The code

// Get the Variable product object (parent)
$product = wc_get_product($parent_id);

$variation_post = array(
    'post_title'  => $product->get_title(),
    'post_name'   => 'product-'.$parent_id.'-variation',
    'post_status' => ($enable_variations == "yes") ? 'publish' : 'private',
    'post_parent' => $parent_id,
    'post_type'   => 'product_variation',
    'guid'        => $product->get_permalink()
);

// Creating the product variation
$variation_id = wp_insert_post( $variation_post, true );

$fields = array(
    '_manage_stock'                 => 'yes',
    '_backorders'                   => $backorders,
    '_stock_status'                 => $stock_status,
    '_stock'                        => $stock,
    '_regular_price'                => $price,
    '_price'                        => $price,
);

foreach ( $fields as $meta_key => $meta_value ) {
    update_post_meta($variation_id, $meta_key, $meta_value);
}

// Add attribute 1 to variation
wp_set_post_terms( $variation_id, sanitize_title($attribute_value), "pa_attribute_1", true );
update_post_meta( $variation_id, 'attribute_pa_attribute_1', sanitize_title($attribute_value));

// Add attribute 2 to variation
wp_set_post_terms( $variation_id, sanitize_title($attribute_value), "pa_attribute_2", true );
update_post_meta( $variation_id, 'attribute_pa_attribute_2', sanitize_title($attribute_value));

// Add attribute 3 to variation
wp_set_post_terms( $variation_id, sanitize_title($attribute_value), "pa_attribute_3", true );
update_post_meta( $variation_id, 'attribute_pa_attribute_3', sanitize_title($attribute_value));

wc_delete_product_transients($variation_id);

What am I missing? What happens when you click Update at a product? Already tried to use $product->save() and deleting transients like answered in most topics on the web.

1 Answer
1

I figured out that this happened because the attributes did not exist in WooCommerce yet. First you have to add all attributes and their values, then generate and add variations. Then it should work:

// Create an array of the attributes we want to add
$attributes = array(
    "attribute_1" => array(
        "slug"  => "attribute_1",
        "label" => "Name of attribute 1",
    ),
    "attribute_2" => array(
        "slug"  => "attribute_2",
        "label" => "Name of attribute 2",
    ),
    "attribute_3" => array(
        "slug"  => "attribute_3",
        "label" => "Name of attribute 3",
    ),
);

// Add the attributes to WooCommerce
foreach($attributes as $attribute){

    if(!get_taxonomy("pa_" . $attribute["slug"])) {
        $result = wc_create_attribute(array(
            "name" => $attribute["label"],
            "slug" => $attribute["slug"], 
            "type" => "select",
        ));
    }
    
}

// Create an array with all the terms
$attributes_values["attribute_1"] = array("value 1", "value 2", "value 3");
$attributes_values["attribute_2"] = array("value 1", "value 2", "value 3");
$attributes_values["attribute_3"] = array("value 1", "value 2", "value 3");

// Iterate over our attributes map,containing attributes that we want to sync
foreach($attributes_values as $attribute => $values ){
    // Iterate over possible values for the attribute and insert them. 
    foreach($values as $value) {
        if(!term_exists($value, wc_attribute_taxonomy_name($attribute))){
            wp_insert_term($value, wc_attribute_taxonomy_name($attribute), array('slug' => sanitize_title($term)));
        }
    }
}

Update march 2021
The above stopped working after a WooCommerce update earlier this year and figured out that it’s actually possible and a lot safer to manage a varation through the WooCommerce class:

// Get the Variable product object (parent)
$product = wc_get_product($variableProductID);
   
$variation_post = array(
    'post_title'  => $product->get_title(),
    'post_name'   => 'product-'.$variableProductID.'-variation',
    'post_status' => 'publish',
    'post_parent' => $variableProductID,
    'post_type'   => 'product_variation',
    'guid'        => $product->get_permalink()
);

// Creating the product variation
$variation_id = wp_insert_post($variation_post, true);

if (is_wp_error($variation_id)) {
    // Error handling
}

// Get an instance of the WC_Product_Variation object
$variation = new \WC_Product_Variation($variation_id);

// Add attributes to variation
update_post_meta($variation_id, 'attribute_pa_device_brand', sanitize_title($action["arguments"]["device_brand"]));
update_post_meta($variation_id, 'attribute_pa_device_model', sanitize_title($action["arguments"]["device_model"]));
update_post_meta($variation_id, 'attribute_pa_case_type_colour', sanitize_title($action["arguments"]["case_type_colour"]));

$variation->set_price($action['arguments']['price']);
$variation->set_regular_price($action['arguments']['price']);
$variation->set_stock_quantity($action['arguments']['stock']);
$variation->set_manage_stock(true);
$variation->set_stock_status();
$variation->set_backorders($action['arguments']['backorders']);

$variation->save();

Leave a Comment