Create programmatically a WooCommerce product variation with new attribute values
Update January 2020: Changed to
WC_Product
methodget_name()
instead ofget_title()
Update September 2018: Handling taxonomy creation (Thanks to Carl F. Corneil)
From a defined variable product ID You will find below, a custom function that will add (create) a Product variation. The variable parent product needs to have set for it the needed attributes.
You will need to provide some information as:
- the array of attributes/values
- the Sku, prices and stock….
This data has to be stored in a formatted multi dimensional array (see an example at the end).
This function will check if the attributes values (term name) already exist and if not:
- it create it for the product attribute
- set it in the parent variable product.
The custom function code:
/** * Create a product variation for a defined variable product ID. * * @since 3.0.0 * @param int $product_id | Post ID of the product parent variable product. * @param array $variation_data | The data to insert in the product. */function create_product_variation( $product_id, $variation_data ){ // Get the Variable product object (parent) $product = wc_get_product($product_id); $variation_post = array( 'post_title' => $product->get_name(), 'post_name' => 'product-'.$product_id.'-variation', 'post_status' => 'publish', 'post_parent' => $product_id, 'post_type' => 'product_variation', 'guid' => $product->get_permalink() ); // Creating the product variation $variation_id = wp_insert_post( $variation_post ); // Get an instance of the WC_Product_Variation object $variation = new WC_Product_Variation( $variation_id ); // Iterating through the variations attributes foreach ($variation_data['attributes'] as $attribute => $term_name ) { $taxonomy = 'pa_'.$attribute; // The attribute taxonomy // If taxonomy doesn't exists we create it (Thanks to Carl F. Corneil) if( ! taxonomy_exists( $taxonomy ) ){ register_taxonomy( $taxonomy, 'product_variation', array( 'hierarchical' => false, 'label' => ucfirst( $attribute ), 'query_var' => true, 'rewrite' => array( 'slug' => sanitize_title($attribute) ), // The base slug ), ); } // Check if the Term name exist and if not we create it. if( ! term_exists( $term_name, $taxonomy ) ) wp_insert_term( $term_name, $taxonomy ); // Create the term $term_slug = get_term_by('name', $term_name, $taxonomy )->slug; // Get the term slug // Get the post Terms names from the parent variable product. $post_term_names = wp_get_post_terms( $product_id, $taxonomy, array('fields' => 'names') ); // Check if the post term exist and if not we set it in the parent variable product. if( ! in_array( $term_name, $post_term_names ) ) wp_set_post_terms( $product_id, $term_name, $taxonomy, true ); // Set/save the attribute data in the product variation update_post_meta( $variation_id, 'attribute_'.$taxonomy, $term_slug ); } ## Set/save all other data // SKU if( ! empty( $variation_data['sku'] ) ) $variation->set_sku( $variation_data['sku'] ); // Prices if( empty( $variation_data['sale_price'] ) ){ $variation->set_price( $variation_data['regular_price'] ); } else { $variation->set_price( $variation_data['sale_price'] ); $variation->set_sale_price( $variation_data['sale_price'] ); } $variation->set_regular_price( $variation_data['regular_price'] ); // Stock if( ! empty($variation_data['stock_qty']) ){ $variation->set_stock_quantity( $variation_data['stock_qty'] ); $variation->set_manage_stock(true); $variation->set_stock_status(''); } else { $variation->set_manage_stock(false); } $variation->set_weight(''); // weight (reseting) $variation->save(); // Save the data}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Usage (example with 2 attributes):
$parent_id = 746; // Or get the variable product id dynamically// The variation data$variation_data = array( 'attributes' => array( 'size' => 'M', 'color' => 'Green', ), 'sku' => '', 'regular_price' => '22.00', 'sale_price' => '', 'stock_qty' => 10,);// The function to be runcreate_product_variation( $parent_id, $variation_data );
Tested and works.
Part 2: Create programmatically a variable product and two new attributes in WooCommerce
You will get this in backend:
And it will work perfectly in front end.
Related: Create programmatically a product using CRUD methods in Woocommerce 3
I'm just going to throw this out there, since i couldn't get any of the above examples working. Don't ask me why as other people seem to have success. So, i took the minimalist approach and tried to figure out the bare essentials for a product attribute + variation (by creating it manually in wp and looking at the db) and came up with this.
$article_name = 'Test';$post_id = wp_insert_post( array( 'post_author' => 1, 'post_title' => $article_name, 'post_content' => 'Lorem ipsum', 'post_status' => 'publish', 'post_type' => "product",) );wp_set_object_terms( $post_id, 'variable', 'product_type' );$attr_label = 'Test attribute';$attr_slug = sanitize_title($attr_label);$attributes_array[$attr_slug] = array( 'name' => $attr_label, 'value' => 'alternative 1 | alternative 2', 'is_visible' => '1', 'is_variation' => '1', 'is_taxonomy' => '0' // for some reason, this is really important );update_post_meta( $post_id, '_product_attributes', $attributes_array );$parent_id = $post_id;$variation = array( 'post_title' => $article_name . ' (variation)', 'post_content' => '', 'post_status' => 'publish', 'post_parent' => $parent_id, 'post_type' => 'product_variation');$variation_id = wp_insert_post( $variation );update_post_meta( $variation_id, '_regular_price', 2 );update_post_meta( $variation_id, '_price', 2 );update_post_meta( $variation_id, '_stock_qty', 10 );update_post_meta( $variation_id, 'attribute_' . $attr_slug, 'alternative 1' );WC_Product_Variable::sync( $parent_id );$variation_id = wp_insert_post( $variation );update_post_meta( $variation_id, '_regular_price', 2 );update_post_meta( $variation_id, '_price', 2 );update_post_meta( $variation_id, '_stock_qty', 10 );update_post_meta( $variation_id, 'attribute_' . $attr_slug, 'alternative 2' );WC_Product_Variable::sync( $parent_id );
This is not using global product attributes, but article specific ones. Hope it helps someone as i was about ready to tear my hair out before i got it working.
Not sure why, but none of these solutions worked for me, so I decided to create my own:
<?php/** * Create a variable product on woocommerce * @return int Product ID */function pricode_create_product(){ $product = new WC_Product_Variable(); $product->set_description('T-shirt variable description'); $product->set_name('T-shirt variable'); $product->set_sku('test-shirt'); $product->set_price(1); $product->set_regular_price(1); $product->set_stock_status(); return $product->save();}/** * Create Product Attributes * @param string $name Attribute name * @param array $options Options values * @return Object WC_Product_Attribute */function pricode_create_attributes( $name, $options ){ $attribute = new WC_Product_Attribute(); $attribute->set_id(0); $attribute->set_name($name); $attribute->set_options($options); $attribute->set_visible(true); $attribute->set_variation(true); return $attribute;}/** * [pricode_create_variations description] * @param [type] $product_id [description] * @param [type] $values [description] * @return [type] [description] */function pricode_create_variations( $product_id, $values ){ $variation = new WC_Product_Variation(); $variation->set_parent_id( $product_id ); $variation->set_attributes($values); $variation->set_status('publish'); $variation->set_sku($data->sku); $variation->set_price($data->price); $variation->set_regular_price($data->price); $variation->set_stock_status(); $variation->save(); $product = wc_get_product($product_id); $product->save();}//Adding product$product = pricode_create_product();//Creating Attributes $atts = [];$atts[] = pricode_create_attributes('color',['red', 'green']);$atts[] = pricode_create_attributes('size',['S', 'M']);//Adding attributes to the created product$product->set_attributes( $atts );$product->save();//Create variationspricode_create_variations( $product->get_id(), ['color' => 'red', 'size' => 'M']);
Hope it can help others.