Related
I have created a variable product ("parent" product) in WooCommerce version 3+. From a WordPress plugin, I would like to programmatically create the product variations ("children" product) with new attribute values.
The variation attributes are already set in WooCommerce.
So every time one variation is created, the new attribute's values should be created programmatically too and set in the parent Variable product.
How can this be done? is it possible?
Update : I had written more lines of code on this that I wished, and tried many things to solve it, using woocommerce objects, and added missing data about terms, termmeta, the relationship from term with post, in the database using the WordPress database object - but nothing has sufficed to make it work. And I couldn't pin-point where I went wrong - that is why I couldn't provide a narrower problem - things for which stackoverflow is more made for.
Update January 2020: Changed to WC_Product method get_name() instead of get_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 run
create_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.
EDIT: I'd say only use this if you can't get the official methods working. They change these things with time (field names such as '_regular_price" and so on) and chances are it's not super future proof to do it this way.
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();
$product->save();
return $product;
}
/**
* 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, $data ){
$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();
//Setting data (following Alexander's rec
$data = new stdClass();
$data->sku = 'sku-123';
$data->price = '10';
//Create variations
pricode_create_variations( $product->get_id(), ['color' => 'red', 'size' => 'M'], $data );
Hope it can help others.
Expanding on LoicTheAztec's answer, you can check if the attribute combination exists with the following modification to his code.
function create_update_product_variation( $product_id, $variation_data ){
if(isset($variation_data['variation_id'])) {
$variation_id = $variation_data['variation_id'];
} else {
// if the variation doesn't exist then create it
// Get the Variable product object (parent)
$product = wc_get_product($product_id);
$variation_post = array(
'post_title' => $product->get_title(),
'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 );
}
// ...
}
Example usage
// The variation data
$variation_data = array(
'attributes' => array(
'size' => 'M',
'color' => 'Green',
),
'sku' => '',
'regular_price' => '22.00',
'sale_price' => '1',
'stock_qty' => 1,
);
// check if variation exists
$meta_query = array();
foreach ($variation_data['attributes'] as $key => $value) {
$meta_query[] = array(
'key' => 'attribute_pa_' . $key,
'value' => $value
);
}
$variation_post = get_posts(array(
'post_type' => 'product_variation',
'numberposts' => 1,
'post_parent' => $parent_id,
'meta_query' => $meta_query
));
if($variation_post) {
$variation_data['variation_id'] = $variation_post[0]->ID;
}
create_update_product_variation( $product_id, $variation_data );
If you want to generate products for testing in WooCommerce, you can use WooCommerce Smooth Generator, made by WooCommerce itself.
https://github.com/woocommerce/wc-smooth-generator
Example:
// Generate WC_Product object and save it to database
// 70% change generated product is simple
// 30% chance generated product is variable
$product = \WC\SmoothGenerator\Generator\Product::generate();
// Returns WC_Product object of Simple product and don't save it to database
$product = \WC\SmoothGenerator\Generator\Product::generate_simple_product();
// Returns WC_Product object of Variable Product and saves it to database
$variable_product = \WC\SmoothGenerator\Generator\Product::generate_variable_product();
Src: https://github.com/woocommerce/wc-smooth-generator/blob/master/includes/Generator/Product.php
If you want to create products programatically, you can Product class with your needs.
it works but needs a little corrections (2 commas in the fuctions array), I did edit some of the code to my needs.
(working on wp 4.9 | wc 3.5)
First the products needs to have the attribute already created and associated, my taxonomy is "pa_r" friendly name "R"
backend attribute associeated img
the function with the correction
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_title(),
'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( $taxonomy ),
'query_var' => true,
'rewrite' => array( 'slug' => '$taxonomy') // 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
}
I made an array with the data I need in the variations [id_post, attribute, sku, regular_price, stock]
$hijos = array(
[9623,'265/70 R16','NE-CT-CO-USA-016-005','0',53],
[9624,'235/65 R17','NE-AU-CO-EUR-017-050','189000',56]
);
and the foreach to create dynamically all the variations to my products
foreach ($hijos as $vari) {
// The variation data
$variation_data = array(
'attributes' => array(
'r' => $vari[1],
),
'sku' => $vari[2],
'regular_price' => str_replace('.', '', $vari[3]),
'stock_qty' => $vari[4]
);
// var_dump($variation_data);
create_product_variation( $vari[0], $variation_data );
}
You might run into a problem here if the the taxonomy of the product is not registered beforehand somewhere else. If you want to make sure the taxonomy exists, you could add a conditional to LoicTheAztec's answer.
Something like this.
foreach ($variation_data['attributes'] as $attribute => $term_name )
{
//echo 'attribute ' . $attribute . ' term name ' . $term_name;
$taxonomy = 'pa_' . $attribute; // The attribute taxonomy
// Check if the Taxonomy exists, and if not we create it.
if (! taxonomy_exists($taxonomy)){
register_taxonomy(
$taxonomy, //The name of the taxonomy. Name should be in slug form (must not contain capital letters or spaces).
'product', //post type name
array(
'hierarchical' => false,
'label' => ucfirst($taxonomy), //Display name
'query_var' => true,
'rewrite' => array(
'slug' => $taxonomy, // This controls the base slug that will display before each term
'with_front' => false // Don't display the category base before
),
)
);
}
...
above answer (LoicTheAztec) helped me a lot but there was some issues instead of using
update_post_meta( $variation_id, 'attribute_'.$taxonomy, $term_slug );
use :
update_post_meta( $variation_id, 'attribute_'.$attribute, $term_name );
because taxonomy is already is been modified and this is causing problem to update post meta after changing this update values and not selecting automatically in admin product variation edit after this changes it work great !
In addition to Alejandro Giraldo answer to use taxonomies instead of custom product attributes you can use this modified version
<?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 ){
$attributes = array();
if(!empty($options)){
if(is_string($options)){
$term = wp_create_term(
$options,
wc_attribute_taxonomy_name($name)
);
if(is_array($term)){
$attributes[] = (int)$term['term_id'];
}
}
else{
for($i = 0; $i < count($options); $i++){
$term = wp_create_term(
$options[$i],
wc_attribute_taxonomy_name($name)
);
if(is_array($term)){
$attributes[] = (int)$term['term_id'];
}
}
}
}
$attribute = new WC_Product_Attribute();
/*
Set the attribute id to the id of the taxonomy to use
with wc_attribute_taxonomy_id_by_name you get the id of the taxonomy stored in {$wpdb->prefix}woocommerce_attribute_taxonomies
with wc_attribute_taxonomy_name you convert the Attribute name to the attribute name woocommerce use
#see https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_attribute_taxonomy_id_by_name
#see https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_attribute_taxonomy_name
/*
$attribute->set_id(wc_attribute_taxonomy_id_by_name(wc_attribute_taxonomy_name($name)));
$attribute->set_name(wc_attribute_taxonomy_name($name));
$attribute->set_options($attributes);
$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 variations
pricode_create_variations( $product->get_id(), [wc_attribute_taxonomy_name('color') => sanitize_title('red'), wc_attribute_taxonomy_name('size') => sanitize_title('M')]);
Coming in late to the party but adding to the answer from LoicTheAztec (which works perfectly) if your new variation does not end up with a selected attribute, use the following line just before the save method:
$variation->set_weight(''); //LoicTheAztec
$variation->set_attributes($variation_data["attributes"]); // Select the attributes
$variation->save(); //LoicTheAztec
The accepted article works like a charm. If you manage to create the variations but it comes out without an option selected in the variation and when you try to save a single one resets to empty, I highly suggest checking this thread Creating WooCommerce product variation adds an empty attribute value , I ve been struggling with the same issue for over 2 hours. Happy coding
This is the write way to create variable product
// Name and image would be enough
$product = new WC_Product_Variable();
$product->set_name( 'Wizard Hat' );
$product->set_image_id( 90 );
// one available for variation attribute
$attribute = new WC_Product_Attribute();
$attribute->set_name( 'Magical' );
$attribute->set_options( array( 'Yes', 'No' ) );
$attribute->set_position( 0 );
$attribute->set_visible( true );
$attribute->set_variation( true ); // here it is
$product->set_attributes( array( $attribute ) );
// save the changes and go on
$product->save();
// now we need two variations for Magical and Non-magical Wizard hat
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'magical' => 'Yes' ) );
$variation->set_regular_price( 1000000 ); // yep, magic hat is quite expensive
$variation->save();
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'magical' => 'No' ) );
$variation->set_regular_price( 500 );
$variation->save();
I have created a variable product ("parent" product) in WooCommerce version 3+. From a WordPress plugin, I would like to programmatically create the product variations ("children" product) with new attribute values.
The variation attributes are already set in WooCommerce.
So every time one variation is created, the new attribute's values should be created programmatically too and set in the parent Variable product.
How can this be done? is it possible?
Update : I had written more lines of code on this that I wished, and tried many things to solve it, using woocommerce objects, and added missing data about terms, termmeta, the relationship from term with post, in the database using the WordPress database object - but nothing has sufficed to make it work. And I couldn't pin-point where I went wrong - that is why I couldn't provide a narrower problem - things for which stackoverflow is more made for.
Update January 2020: Changed to WC_Product method get_name() instead of get_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 run
create_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.
EDIT: I'd say only use this if you can't get the official methods working. They change these things with time (field names such as '_regular_price" and so on) and chances are it's not super future proof to do it this way.
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();
$product->save();
return $product;
}
/**
* 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, $data ){
$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();
//Setting data (following Alexander's rec
$data = new stdClass();
$data->sku = 'sku-123';
$data->price = '10';
//Create variations
pricode_create_variations( $product->get_id(), ['color' => 'red', 'size' => 'M'], $data );
Hope it can help others.
Expanding on LoicTheAztec's answer, you can check if the attribute combination exists with the following modification to his code.
function create_update_product_variation( $product_id, $variation_data ){
if(isset($variation_data['variation_id'])) {
$variation_id = $variation_data['variation_id'];
} else {
// if the variation doesn't exist then create it
// Get the Variable product object (parent)
$product = wc_get_product($product_id);
$variation_post = array(
'post_title' => $product->get_title(),
'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 );
}
// ...
}
Example usage
// The variation data
$variation_data = array(
'attributes' => array(
'size' => 'M',
'color' => 'Green',
),
'sku' => '',
'regular_price' => '22.00',
'sale_price' => '1',
'stock_qty' => 1,
);
// check if variation exists
$meta_query = array();
foreach ($variation_data['attributes'] as $key => $value) {
$meta_query[] = array(
'key' => 'attribute_pa_' . $key,
'value' => $value
);
}
$variation_post = get_posts(array(
'post_type' => 'product_variation',
'numberposts' => 1,
'post_parent' => $parent_id,
'meta_query' => $meta_query
));
if($variation_post) {
$variation_data['variation_id'] = $variation_post[0]->ID;
}
create_update_product_variation( $product_id, $variation_data );
If you want to generate products for testing in WooCommerce, you can use WooCommerce Smooth Generator, made by WooCommerce itself.
https://github.com/woocommerce/wc-smooth-generator
Example:
// Generate WC_Product object and save it to database
// 70% change generated product is simple
// 30% chance generated product is variable
$product = \WC\SmoothGenerator\Generator\Product::generate();
// Returns WC_Product object of Simple product and don't save it to database
$product = \WC\SmoothGenerator\Generator\Product::generate_simple_product();
// Returns WC_Product object of Variable Product and saves it to database
$variable_product = \WC\SmoothGenerator\Generator\Product::generate_variable_product();
Src: https://github.com/woocommerce/wc-smooth-generator/blob/master/includes/Generator/Product.php
If you want to create products programatically, you can Product class with your needs.
it works but needs a little corrections (2 commas in the fuctions array), I did edit some of the code to my needs.
(working on wp 4.9 | wc 3.5)
First the products needs to have the attribute already created and associated, my taxonomy is "pa_r" friendly name "R"
backend attribute associeated img
the function with the correction
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_title(),
'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( $taxonomy ),
'query_var' => true,
'rewrite' => array( 'slug' => '$taxonomy') // 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
}
I made an array with the data I need in the variations [id_post, attribute, sku, regular_price, stock]
$hijos = array(
[9623,'265/70 R16','NE-CT-CO-USA-016-005','0',53],
[9624,'235/65 R17','NE-AU-CO-EUR-017-050','189000',56]
);
and the foreach to create dynamically all the variations to my products
foreach ($hijos as $vari) {
// The variation data
$variation_data = array(
'attributes' => array(
'r' => $vari[1],
),
'sku' => $vari[2],
'regular_price' => str_replace('.', '', $vari[3]),
'stock_qty' => $vari[4]
);
// var_dump($variation_data);
create_product_variation( $vari[0], $variation_data );
}
You might run into a problem here if the the taxonomy of the product is not registered beforehand somewhere else. If you want to make sure the taxonomy exists, you could add a conditional to LoicTheAztec's answer.
Something like this.
foreach ($variation_data['attributes'] as $attribute => $term_name )
{
//echo 'attribute ' . $attribute . ' term name ' . $term_name;
$taxonomy = 'pa_' . $attribute; // The attribute taxonomy
// Check if the Taxonomy exists, and if not we create it.
if (! taxonomy_exists($taxonomy)){
register_taxonomy(
$taxonomy, //The name of the taxonomy. Name should be in slug form (must not contain capital letters or spaces).
'product', //post type name
array(
'hierarchical' => false,
'label' => ucfirst($taxonomy), //Display name
'query_var' => true,
'rewrite' => array(
'slug' => $taxonomy, // This controls the base slug that will display before each term
'with_front' => false // Don't display the category base before
),
)
);
}
...
above answer (LoicTheAztec) helped me a lot but there was some issues instead of using
update_post_meta( $variation_id, 'attribute_'.$taxonomy, $term_slug );
use :
update_post_meta( $variation_id, 'attribute_'.$attribute, $term_name );
because taxonomy is already is been modified and this is causing problem to update post meta after changing this update values and not selecting automatically in admin product variation edit after this changes it work great !
In addition to Alejandro Giraldo answer to use taxonomies instead of custom product attributes you can use this modified version
<?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 ){
$attributes = array();
if(!empty($options)){
if(is_string($options)){
$term = wp_create_term(
$options,
wc_attribute_taxonomy_name($name)
);
if(is_array($term)){
$attributes[] = (int)$term['term_id'];
}
}
else{
for($i = 0; $i < count($options); $i++){
$term = wp_create_term(
$options[$i],
wc_attribute_taxonomy_name($name)
);
if(is_array($term)){
$attributes[] = (int)$term['term_id'];
}
}
}
}
$attribute = new WC_Product_Attribute();
/*
Set the attribute id to the id of the taxonomy to use
with wc_attribute_taxonomy_id_by_name you get the id of the taxonomy stored in {$wpdb->prefix}woocommerce_attribute_taxonomies
with wc_attribute_taxonomy_name you convert the Attribute name to the attribute name woocommerce use
#see https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_attribute_taxonomy_id_by_name
#see https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_attribute_taxonomy_name
/*
$attribute->set_id(wc_attribute_taxonomy_id_by_name(wc_attribute_taxonomy_name($name)));
$attribute->set_name(wc_attribute_taxonomy_name($name));
$attribute->set_options($attributes);
$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 variations
pricode_create_variations( $product->get_id(), [wc_attribute_taxonomy_name('color') => sanitize_title('red'), wc_attribute_taxonomy_name('size') => sanitize_title('M')]);
Coming in late to the party but adding to the answer from LoicTheAztec (which works perfectly) if your new variation does not end up with a selected attribute, use the following line just before the save method:
$variation->set_weight(''); //LoicTheAztec
$variation->set_attributes($variation_data["attributes"]); // Select the attributes
$variation->save(); //LoicTheAztec
The accepted article works like a charm. If you manage to create the variations but it comes out without an option selected in the variation and when you try to save a single one resets to empty, I highly suggest checking this thread Creating WooCommerce product variation adds an empty attribute value , I ve been struggling with the same issue for over 2 hours. Happy coding
This is the write way to create variable product
// Name and image would be enough
$product = new WC_Product_Variable();
$product->set_name( 'Wizard Hat' );
$product->set_image_id( 90 );
// one available for variation attribute
$attribute = new WC_Product_Attribute();
$attribute->set_name( 'Magical' );
$attribute->set_options( array( 'Yes', 'No' ) );
$attribute->set_position( 0 );
$attribute->set_visible( true );
$attribute->set_variation( true ); // here it is
$product->set_attributes( array( $attribute ) );
// save the changes and go on
$product->save();
// now we need two variations for Magical and Non-magical Wizard hat
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'magical' => 'Yes' ) );
$variation->set_regular_price( 1000000 ); // yep, magic hat is quite expensive
$variation->save();
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'magical' => 'No' ) );
$variation->set_regular_price( 500 );
$variation->save();
I have custom products and i have added the products in the cart but it should be quantity based calculation for those products. how to change the product subtotal price in woocomerce. the product subtotal should override with my price. how to override it. Please check with my below code
$values = array();
$post_values = array();
$i=0;
foreach($_POST['post_quantity'] as $key =>$value){
$values[] = "('{$_POST['product_id'][$key]}', '{$_POST['post_quantity'][$key]}',
'{$_POST['product_price'][$key]}',
'{$_POST['product_duplicate_price'][$key]}',
'{$_POST['product_description'][$key]}',
'{$_POST['product_material'][$key]}')";
$wpdb->insert('wp_posts', array(
'post_title' => 'xxxx '.$_POST['quoted_sid'].'Quote ID: '.$_POST['quoted_sid'][$key].' - Product ID: '.$_POST['product_id'][$key],
'post_content' => $_POST['product_description'][$key],
'post_date' => date('Y-m-d H:i:s'),
'post_status' => 'publish',
'post_author' => 1,
'post_type' =>'product'
));
$lastid[$i] = $wpdb->insert_id;
$date[$i] = date('Y-m-d H:i:s');
//calculation for quantity
$regular_price =
$_POST['product_price'][$key] + $_POST['product_duplicate_price'][$key]*($_POST['post_quantity'][$key]-1);
//$regular_price /$_POST['post_quantity'][$key];
//echo number_format((float)$regular_price,2,'.','').'</br>';
add_post_meta($lastid[$i], '_regular_price', number_format((float)$regular_price,2,'.',''));
add_post_meta($lastid[$i], '_price', number_format((float)$_POST['product_price'][$key],2,'.',''));
add_post_meta($lastid[$i],'_visibility','visible');
add_post_meta($lastid[$i], '_stock_status', 'instock' );
add_post_meta($lastid[$i], '_weight', '11' );
add_post_meta($lastid[$i], '_sku', 'Quoted Stencil_'.$_POST['product_id'][$key] );
add_post_meta($lastid[$i], '_duplicate_price', $_POST['product_duplicate_price'][$key] );
add_post_meta($lastid[$i], '_material', $_POST['product_material'][$key] );
$post_values['product_id'][] = $lastid[$i];
$post_values['product_quantity'][] = $_POST['post_quantity'][$key];
$i++;
}
//print_r($post_values);
$j=0;
foreach ( $post_values as $product_id ) {
$woocommerce->cart->add_to_cart( $post_values['product_id'][$j] ,$post_values['product_quantity'][$j],$cart_item_data);
$j++;
}
//exit;
exit( wp_redirect( home_url( "cart" ) ) );
There is a filter called "woocommerce_cart_subtotal" for this. It is a filter for final string ( currency+subtotal+vat text). If you have some custom calculation for subtotal, inject it to this filter.
First test it and make sure it works.
add_filter('woocommerce_cart_subtotal','subtotalchanger',0);
function subtotalchanger($subtotal){
return $subtotal.' - it worked';
}
If everything is ok, then place your custom calculation to this filter and return your own subtotal:
add_filter('woocommerce_cart_subtotal','subtotalchanger',0);
function subtotalchanger($subtotal){
//your own calculations based on cart products and their quantities
return $your_custom_subtotal
}
I am trying to update a specific field for all variations in a product, but unfortunately, I am unable to get variation ids to go further.
Basically what I am doing is, I am trying to get each variation's stock value and if the stock value is less than zero, then I am updating a particular field with certain values (as mentioned in my code below).
I have tested this by manually inputting any custom post / variation id and is working fine, updates that particular variation id based on its stock value. All I am stuck here is I am unable to fetch the variation id by itself.
Below is the code that I am using:
global $post, $woocommerce;
$post_id = $variation->ID;
// Get specific data from the certain custom fields using get_post_meta( $post_id, $key, $single );
$stock = get_post_meta( $post_id, '_stock', true );
if ($stock < 1) {
update_post_meta( $post_id, 'cuzd-prod-general-v', '20,25' );
} else {
update_post_meta( $post_id, 'cuzd-prod-general-v', '1,5' );
}
I don't know where I am wrong to get the variation ids for this.
I was able to solve this by using below code changes:
// Values to be updated
$in_stock = '1,5';
$out_of_stock = '20,30';
// Get variations
$args = array(
'post_type' => 'product_variation',
'post_status' => array( 'private', 'publish' ),
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'asc',
'post_parent' => $post->ID
);
$variations = get_posts( $args );
foreach ( $variations as $variation ) {
$variation_id = absint( $variation->ID );$variable_id = $this['variation_id'];
$variation_post_status = esc_attr( $variation->post_status );
$variation_data = get_post_meta( $variation_id );
$variation_data['variation_post_id'] = $variation_id;
// Get specific data from the certain custom fields using get_post_meta( $post_id, $key, $single );
$stock = get_post_meta( $variation_data['variation_post_id'], '_stock', true );
if ($stock < 1) {
update_post_meta( $variation_data['variation_post_id'], 'cuzd-prod-general-v', $out_of_stock );
} else {
update_post_meta( $variation_data['variation_post_id'], 'cuzd-prod-general-v', $in_stock );
}
}
I have a front-end form I am creating to allow users to publish a variable product to my shop from the front end with predefined attributes and variations.
I have found this very helpful question: here Which shows me how to set the product type as variable and assign my predefined attributes in the attributes section of the product data.
However when I am on the backend of Wordpress/Woocommerce and editing the product I click on variations and none are set, I look at the attributes and my "resolution" attribute is set with my 3 items.
How do I make this to where it will actually set those attributes to variations of my form? Do I need to use wp_insert_post? Looking in phpmyadmin it just looks like product variations are assigned to a parent_id (product id) and post type is product_varition and so on.
$new_post = array(
'post_title' => esc_attr(strip_tags($_POST['postTitle'])),
'post_content' => esc_attr(strip_tags($_POST['postContent'])),
'post_status' => 'publish',
'post_type' => 'product',
'tags_input' => array($tags)
);
$skuu = rand();
$post_id = wp_insert_post($new_post);
update_post_meta($post_id, '_sku', $skuu );
//my array for setting the attributes
$avail_attributes = array(
'high-resolution',
'medium-resolution',
'low-resolution'
);
//Sets the attributes up to be used as variations but doesnt actually set them up as variations
wp_set_object_terms ($post_id, 'variable', 'product_type');
wp_set_object_terms( $post_id, $avail_attributes, 'pa_resolution' );
$thedata = array(
'pa_resolution'=> array(
'name'=>'pa_resolution',
'value'=>'',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1'
)
);
update_post_meta( $post_id,'_product_attributes',$thedata);
update_post_meta( $post_id, '_visibility', 'search' );
update_post_meta( $post_id, '_stock_status', 'instock');
So just to be clear (I tend to be confusing) the above does create my variable product from the front end, and when I look at the product in the backend it is a variable product, it has the resolution attribute set and has my 3 terms (high-res, medium-res, low-res) as attributes. I just need to take this a step further where they are actually set as variations so people can place an order.
I got it working for my situation by using update_post_meta and wp_insert_post. Because I already setup my attributes and terms all I needed was a way to add to the above code so that when the product is created it not only will assign the attributes to the product but insert them as variations in the database.
Here is my solution:
//insert variations post_type
$i=1;
while ($i<=3) {
$my_post = array(
'post_title' => 'Variation #' . $i . ' of ' . esc_attr(strip_tags($_POST['postTitle'])),
'post_name' => 'product-' . $post_id . '-variation-' . $i,
'post_status' => 'publish',
'post_parent' => $post_id,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $post_id . '-variation-' . $i
);
// Insert the post into the database
wp_insert_post( $my_post );
$variable_id = $post_id + 1;
$variable_two = $variable_id + 1;
$variable_three = $variable_two + 1;
update_post_meta( $variable_id, 'attribute_pa_resolution', 'high-resolution');
update_post_meta( $variable_id, '_price', 8.50 );
update_post_meta( $variable_id, '_regular_price', '8.50');
update_post_meta( $variable_two, 'attribute_pa_resolution', 'medium-resolution');
update_post_meta( $variable_two, '_price', 5.50 );
update_post_meta( $variable_two, '_regular_price', '5.50');
update_post_meta( $variable_three, 'attribute_pa_resolution', 'low-resolution');
update_post_meta( $variable_three, '_price', 3.50 );
update_post_meta( $variable_three, '_regular_price', '3.50');
$i++;
}
I have been struggling for the last two days on implementing in my plugin the ability to set up product variation in Woocommerce.
I managed to get all correct data in DB but Woocommerce wasn't retrieving as I thought it would.
The problem were the 'transient' stored in wp_options table.
This is the code that had me up and running with WC 2.6.0:
CREATING VARIATION BASED UPON SELECTED ATTRIBUTES ($_POST['term_id_arr'] are a list of all attributes chosen from frontend for creating product. I'm sorry but I am not yet allowed to post images on stack.. Front-end form with variations created)
$opzioni_arr=$_POST['term_id_arr'];
$qta = count($opzioni_arr);
if ($qta>0){
$ID = $post_id;
//make product type be variable:
wp_set_object_terms ($ID,'variable','product_type');
foreach ($opzioni_arr as $opzioni_val){
$new_arr = explode("/",$opzioni_val);
$att_taxonomy = $new_arr[0];
$att_slug = $new_arr[1];
$att_id =$new_arr[2];
$att_arr[$att_taxonomy][$att_id]=$att_slug;
$att_due_arr[$att_taxonomy][$att_taxonomy.'*'.$att_id]=$att_slug;
}
//################### Add attributes to main product: ####################
foreach ($att_arr as $att_arr_key=>$att_arr_val){
//Array for setting attributes
unset ($avail_attributes);
foreach ($att_arr_val as $key_two=>$val_two){
$avail_attributes[] = $val_two;
}
wp_set_object_terms($ID, $avail_attributes, $att_arr_key);
$thedata [$att_arr_key]= Array(
'name'=>$att_arr_key,
'value'=>'',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 1,
'position' => '1'
);
}
update_post_meta( $ID,'_product_attributes',$thedata);
//########################## Done adding attributes to product #################
//function to create combinations from attributes
$combinations=lasap_get_combinations($att_due_arr);
foreach ($combinations as $key=>$val){
// Start creating variations
// The variation is simply a post
// with the main product set as its parent
// you might want to put that in a loop or something
// to create multiple variations with multiple values
$parent_id = $ID;
$variation = array(
'post_title' => 'Prodotto #' . $parent_id . ' Variante',
'post_content' => '',
'post_status' => 'publish',
'post_parent' => $parent_id,
'post_type' => 'product_variation'
);
// The variation id
$variation_id = wp_insert_post( $variation );
// Regular Price ( you can set other data like sku and sale price here )
update_post_meta($variation_id, '_sku', $sku);
update_post_meta($variation_id, '_regular_price', $regular_price);
update_post_meta($variation_id, '_sale_price', $sale_price);
update_post_meta($variation_id, '_sale_price_dates_from', $datasaldodal_time);
update_post_meta($variation_id, '_sale_price_dates_to', $datasaldoal_time);
if (($sale_price!='' AND ($sale_price<=$regular_price))){$price=$sale_price;} else {$price=$regular_price;}
update_post_meta($variation_id, '_price', $price);
update_post_meta($variation_id, '_thumbnail_id', $thumbnail_id);
update_post_meta($variation_id, '_manage_stock', $manage_stock);
update_post_meta($variation_id, '_stock_status', $stock_status);
update_post_meta($variation_id, '_stock', $stock);
update_post_meta($variation_id, '_stock_soglia', $stock_soglia);
update_post_meta($variation_id, '_backorders', $backorders);
foreach ($val as $chiave=>$valore){
$exp = explode ("*", $chiave);
$attributo_nome = $exp[0];
update_post_meta( $variation_id, 'attribute_' . $attributo_nome, $valore );
$split_attributo = explode("_", $attributo_nome);
$attributo_nome_due = $split_attributo[1];
echo "<p>Variante #$variation_id: $attributo_nome_due ($valore)</p>";
}
}
do_action( 'product_variation_linked', $variation_id );
// Update parent if variable so price sorting works and stays in sync with the cheapest child
lasap_woo_sync_varianti ($post_id, $stock_status_before);
}
delete_transient( 'wc_product_children_' . $parent_id );
UPDATING VARIATIONS (SUCH AS PRICE, SALE PRICE AND SO ON...).
$sku_arr = $_POST['sku'];
$prezzolistino_arr = $_POST['prezzolistino']; //regular_price
$prezzosaldo_arr = $_POST['prezzosaldo']; //sale_price
$datasaldoal_arr = $_POST['datasaldoal']; //sale_date_to
$datasaldodal_arr = $_POST['datasaldodal']; //sale_date_from
$manage_stock_arr = $_POST['manage_stock'];
$stock_arr = $_POST['stock'];
$stock_soglia_arr = $_POST['stock_soglia'];
$backorders_arr = $_POST['backorders'];
foreach ($sku_arr as $varID=>$sku){
$prezzolistino = $prezzolistino_arr[$varID];
$prezzosaldo = $prezzosaldo_arr[$varID];
if (($prezzosaldo!='' AND ($prezzosaldo<=$prezzolistino))){$prezzoesposto=$prezzosaldo;} else {$prezzoesposto=$prezzolistino;}
$prezzoesposto = $prezzoesposto * 1;
$datasaldoal = $datasaldoal_arr[$varID];
$datasaldodal = $datasaldodal_arr[$varID];
$manage_stock = $manage_stock_arr[$varID];
$stock = $stock_arr[$varID];
$stock_soglia = $stock_soglia_arr[$varID];
$backorders = $backorders_arr[$varID];
switch ($manage_stock){
case "on": $manage_stock = "yes"; break;
default : $manage_stock = "no";
}
switch ($backorders){
case "on": $backorders = "yes"; break;
default : $backorders = "no";
}
update_post_meta ($varID, '_sku', $sku);
update_post_meta ($varID, '_regular_price', $prezzolistino);
update_post_meta ($varID, '_sale_price', $prezzosaldo);
update_post_meta ($varID, '_price', $prezzoesposto);
update_post_meta ($varID, '_sale_price_dates_to', $datasaldoal);
update_post_meta ($varID, '_sale_price_dates_from', $datasaldodal);
update_post_meta ($varID, '_manage_stock', $manage_stock);
update_post_meta ($varID, '_stock', $stock);
update_post_meta ($varID, '_stock_soglia', $stock_soglia);
update_post_meta ($varID, '_backorders', $backorders);
}
// Update parent if variable so price sorting works and stays in sync with the cheapest child
$tipo = $_POST['tipo'];//this is a value to check if I am updating main product or its children
if ($tipo != 'parent'){
lasap_woo_sync_varianti ($post_id, $stock_status_before);
}
DELETING VARIATION(S)
$ID_arr = $_POST['ID'];
foreach ($ID_arr as $ID){
$res = wp_delete_post($ID, true);
}
$variazioni = lasap_woo_check_variazioni($post_id);
if ($variazioni > 0){
// Update parent if variable so price sorting works and stays in sync with the cheapest child
lasap_woo_sync_varianti ($post_id, $stock_status_before);
} else {
//clean up main product
delete_post_meta($post_id, '_product_attributes');
delete_post_meta($post_id, '_min_variation_price');
delete_post_meta($post_id, '_max_variation_price');
delete_post_meta($post_id, '_min_price_variation_id');
delete_post_meta($post_id, '_max_price_variation_id');
delete_post_meta($post_id, '_min_variation_regular_price');
delete_post_meta($post_id, '_max_variation_regular_price');
delete_post_meta($post_id, '_min_regular_price_variation_id');
delete_post_meta($post_id, '_max_regular_price_variation_id');
delete_post_meta($post_id, '_min_variation_sale_price');
delete_post_meta($post_id, '_max_variation_sale_price');
delete_post_meta($post_id, '_min_sale_price_variation_id');
delete_post_meta($post_id, '_max_sale_price_variation_id');
update_post_meta($post_id, '_stock_status', 'instock');
wp_set_object_terms ($post_id,'simple','product_type');
wc_delete_product_transients( $post_id );
}
FUNCTION CALLED FOR SYNCING....
function lasap_woo_sync_varianti ($post_id, $stock_status_before){
//https://docs.woocommerce.com/wc-apidocs/class-WC_Product_Variable.html
//WC_Product_Variable::variable_product_sync( $post_id );//sync variable product prices with the children lowest/highest (calls :sync)
//WC_Product_Variable::sync_stock_status( $post_id );//sync the variable product stock status with children
//WC_Product_Variable::sync_attributes( $post_id );//sync the variable product's attributes with the variations (called by :sync)
WC_Product_Variable::sync( $post_id );//sync the variable product with it's children
wc_delete_product_transients( $post_id );
lasap_get_variation_prices ($post_id);
$stock_status_after = get_post_meta($post_id, '_stock_status', true);
update_post_meta($post_id, '_stock_status', $stock_status_before);
}
FUNCTION FOR SETTING TRANSIENT (EXTRACTED FROM woocommerce\includes\class-wc-product-variable.php)
function lasap_get_variation_prices( $post_id, $display = false ) {
global $wp_filter, $woocommerce, $wpdb;
$_product = wc_get_product( $post_id );
/**
* Transient name for storing prices for this product (note: Max transient length is 45)
* #since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
*/
$transient_name = 'wc_var_prices_' . $post_id;
/**
* Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
* DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
* #var string
*/
if ( $display ) {
$price_hash = array( get_option( 'woocommerce_tax_display_shop', 'excl' ), WC_Tax::get_rates() );
} else {
$price_hash = array( false );
}
$filter_names = array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' );
foreach ( $filter_names as $filter_name ) {
if ( ! empty( $wp_filter[ $filter_name ] ) ) {
$price_hash[ $filter_name ] = array();
foreach ( $wp_filter[ $filter_name ] as $priority => $callbacks ) {
$price_hash[ $filter_name ][] = array_values( wp_list_pluck( $callbacks, 'function' ) );
}
}
}
$price_hash = md5( json_encode( apply_filters( 'woocommerce_get_variation_prices_hash', $price_hash, $_product, $display ) ) );
// If the value has already been generated, we don't need to grab the values again.
if ( empty( $post_id->prices_array[ $price_hash ] ) ) {
// Get value of transient
$prices_array = array_filter( (array) json_decode( strval( get_transient( $transient_name ) ), true ) );
// If the product version has changed, reset cache
if ( empty( $prices_array['version'] ) || $prices_array['version'] !== WC_Cache_Helper::get_transient_version( 'product' ) ) {
$post_id->prices_array = array( 'version' => WC_Cache_Helper::get_transient_version( 'product' ) );
}
// If the prices are not stored for this hash, generate them
//if ( empty( $prices_array[ $price_hash ] ) ) {
if ( 1>0 ) {
$prices = array();
$regular_prices = array();
$sale_prices = array();
$variation_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type='product_variation' AND post_status='publish' AND post_parent=$post_id", 0);
foreach ( $variation_ids as $variation_id ) {
$post_meta = get_post_meta($variation_id);
$price = $post_meta['_price'][0];
$regular_price = $post_meta['_regular_price'][0];
$sale_price = $post_meta['_sale_price'][0];
// Skip empty prices
if ( '' === $price ) {
continue;
}
// If sale price does not equal price, the product is not yet on sale
if ( $sale_price === $regular_price || $sale_price !== $price ) {
$sale_price = $regular_price;
}
// If we are getting prices for display, we need to account for taxes
if ( $display ) {
if ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
$price = '' === $price ? '' : $variation->get_price_including_tax( 1, $price );
$regular_price = '' === $regular_price ? '' : $variation->get_price_including_tax( 1, $regular_price );
$sale_price = '' === $sale_price ? '' : $variation->get_price_including_tax( 1, $sale_price );
} else {
$price = '' === $price ? '' : $variation->get_price_excluding_tax( 1, $price );
$regular_price = '' === $regular_price ? '' : $variation->get_price_excluding_tax( 1, $regular_price );
$sale_price = '' === $sale_price ? '' : $variation->get_price_excluding_tax( 1, $sale_price );
}
}
$prices[ $variation_id ] = wc_format_decimal( $price, wc_get_price_decimals() );
$regular_prices[ $variation_id ] = wc_format_decimal( $regular_price, wc_get_price_decimals() );
$sale_prices[ $variation_id ] = wc_format_decimal( $sale_price . '.00', wc_get_price_decimals() );
}
asort( $prices );
asort( $regular_prices );
asort( $sale_prices );
$prices_array[ $price_hash ] = array(
'price' => $prices,
'regular_price' => $regular_prices,
'sale_price' => $sale_prices,
);
echo "<br> 659) ";mostra_array($prices_array);
set_transient( $transient_name, json_encode( $prices_array ), DAY_IN_SECONDS * 30 );
}
/**
* Give plugins one last chance to filter the variation prices array which has been generated.
*/
$post_id->prices_array[ $price_hash ] = apply_filters( 'woocommerce_variation_prices', $prices_array[ $price_hash ], $post_id, $display );
}
}
FUNCTION I USE TO CHECK IF PRODUCT HAS VARIATIONS (RETURN QTY)
function lasap_woo_check_variazioni($post_id){
global $wpdb;
$qry_var=" SELECT COUNT(ID) FROM $wpdb->posts WHERE
post_type='product_variation' AND
post_parent=$post_id AND
post_status='publish'";
$res_var=$wpdb->get_var($qry_var);
return $res_var;
}
After all this, another problem rose up (it NEVER happens, doesn'it?): I haven't figured it out why but after updating variations, parent product post_meta '_stock_status' was always set as 'outofstock'.
I have patched this retrieving at the beginning the correct status with get_post_meta and passing its value to the function lasap_woo_sync_varianti.
Any improvements are greatly appreciated and hope this will help someone to save his/her time!
Tested and working on WC 2.6.13. See link here
update_post_meta( $post_id, '_visibility', PARAM' )
It will have 3 or 4 parameters: hidden | search | catalog | visible
Try to set your _visibility to "visible" param.
With the last actualization of woocommerce, This code does not work.
When I use this code :
$my_post = array(
'post_title' => 'Variation #' . $i . ' of ' . esc_attr(strip_tags($_POST['postTitle'])),
'post_name' => 'product-' . $post_id . '-variation-' . $i,
'post_status' => 'publish',
'post_parent' => $post_id,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $post_id . '-variation-' . $i
);
wp_insert_post( $my_post );
three variations are inserted by default, and I am not able to delete or insert another variation.
Any solution?