Can you show me what I'm doing wrong?
My code to add a new product to Woocommerce looks like this right now:
function newProduct( $idERP, $titulo, $conteudo, $preco, $precoDesconto, $sku, $peso, $comprimento, $largura, $altura, $estoque, $variacoes, $categorias ){
global $woocommerce;
$titulo = utf8_encode($titulo);
$conteudo = utf8_encode($conteudo);
$my_post = array(
'post_title' => $titulo,
'post_content' => $conteudo,
'post_status' => 'pending',
'post_author' => 6,
'post_type' =>'product'
);
$product_ID = wp_insert_post( $my_post );
if ( $product_ID ){
if( $preco == $precoDesconto){
add_post_meta($product_ID, '_price', $precoDesconto );
}else{
add_post_meta($product_ID, '_regular_price', $preco );
add_post_meta($product_ID, '_price', $precoDesconto );
add_post_meta($product_ID, '_sale_price', $precoDesconto );
}
add_post_meta($product_ID, '_sku', $sku );
add_post_meta($product_ID, '_weight', $peso );
add_post_meta($product_ID, '_length', $comprimento );
add_post_meta($product_ID, '_width', $largura );
add_post_meta($product_ID, '_height', $altura );
add_post_meta($product_ID, '_stock', $this->estoque($estoque) );
add_post_meta($product_ID, '_idERP', $idERP ); //ID from erp
wp_set_object_terms( $product_ID, 'variable', 'product_type' );
//wp_set_object_terms( $product_ID, $categorias, 'product_cat');
$guardaVariacoes = array();$i = 1;
foreach($variacoes as $v){
$vid = wp_insert_post(
array(
'post_title' => 'Variacao #' . $i,
'post_name' => 'product-' . $product_ID . '-variation-' . $i,
'post_status' => 'publish',
'post_parent' => $product_ID,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $product_ID . '-variation-' . $i
)
);
if( $v[1] == $v[2] ){
update_post_meta( $vid, '_regular_price', $v[1]);
}else{
update_post_meta( $vid, '_price', $v[2] );
update_post_meta( $vid, '_regular_price', $v[1]);
update_post_meta( $vid, '_sale_price', $v[2] );
}
update_post_meta( $vid, '_stock', $this->estoque($v[0]) );
update_post_meta( $vid, '_weight', $v[3]);
update_post_meta( $vid, '_width', $v[4]);
update_post_meta( $vid, '_height', $v[5]);
update_post_meta( $vid, '_length', $v[6]);
update_post_meta( $vid, '_sku', $v[8]);
update_post_meta( $vid, '_idERP', $v[9]);
foreach($v[7] as $nAtr=>$vAtr){
$nomeAtributo = strtolower(trim($nAtr));
$tt = $nomeAtributo;
if(strtolower($tt) == 'tamanho')$tt = 'pa_tamanho';
if(strtolower($tt) == 'cor')$tt = 'pa_cor';
update_post_meta( $vid, 'attribute_'.$tt, trim($vAtr));
$temp = $tt.'|'.$nAtr;
if( !array_key_exists($temp,$guardaVariacoes) ) $guardaVariacoes[$temp] = array();
$guardaVariacoes[$temp][] = $vAtr;
}
$i++;
}
$product_attributes = array();
foreach($guardaVariacoes as $r=>$s){
$r = explode('|',$r);
$temp = array();
foreach($s as $w){
$w = trim($w);
if( strtoupper($w) == 'UNICA' ){
$w = 'Única';
}
if( strtoupper($w) == 'UNICO' ){
$w = 'Único';
}
if( array_search( $w,$temp)===false){
if( strtoupper(trim($r[1])) == 'COR'){
$temp[] = ucfirst(strtolower($w));
}else{
$temp[] = $w;
}
}
}
$s = array_unique($temp);
$tt = $r[1];
if(strtolower($tt) == 'tamanho')$tt = 'pa_tamanho';
if(strtolower($tt) == 'cor')$tt = 'pa_cor';
$product_attributes[$r[0]] = array(
'name' => $tt,
'value' => implode(' | ', $s ),
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 1 //MY PROBLEM IS HERE
);
}
update_post_meta($product_ID, '_product_attributes', $product_attributes);
}
return $product_ID;
}
When I change the code like so...
'is_taxonomy' => 1
...it works, but it doesn't work for "search layered filters", which means I have to use taxonomy.
How do I do that without losing the "attributes" inside my product?
Sounds to me like you are trying to set Categories for products, and correct me if I'm wrong please. If this is the case, you don't want to use taxonomies. First, you are missing a ton of meta_keys for the product and all of it's variations. I suggest you install a fresh copy of WooCommerce plugin on a Fresh copy of Wordpress. Create a product manually in the back-end with 2 variations, and take a look at the wp_posts and wp_postmeta (post_id, meta_key, and meta_values). For variations, there are more values for the actual product id in the wp_postmeta table than that of the variations. _max_variation_sale_price_id, _max_variation_sale_price, _min_variation_sale_price_id, _min_variation_sale_price, etc. etc. etc. There is also another serialized array, _default_attributes, that you can just make an empty array and serialize it, for the product so that it has it's defaults set.
So, if you are referring to Categories and want to assign products to categories so that you can click on a category and see that product in there... than do the following:
Keep is_taxonomy set to 0
is_visible doesn't matter, if you want to see it under Additional Info, than set to 1, otherwise, it should still show all different variations, but I suppose it depends on your theme's way of handling this.
position needs to start at 1 and be incremented each time, so use a variable for this, example:
$position = 1;
foreach($guardaVariacoes as $r=>$s) {
// your top code... down to where the _product_attributes array begins...
$product_attributes[$r[0]] = array(
'name' => $tt,
'value' => implode(' | ', $s),
'position' => $position,
'is_visible' => count($s) > 1 ? 0 : 1,
'is_variation' => count($s) > 1 ? 1 : 0,
'is_taxonomy' => 0
);
$position++;
}
To create and assign categories on the fly for products you use: term_exists (will return 0 or NULL if term doesn't exist, you can check with empty()), wp_insert_term (if the term doesn't exist), insert it so that you can assign the category to the product. Example below if you want to insert a sub-brand category into a parent brand category, just an example of how I add categories to products (wp_term_relationships table assigns the categories to each product, via the products/posts ID value):
// Check if Brand exists or not...
$brand = term_exists('brand', 'product_cat', 0);
$category = 'new category';
$cat_name = addslashes(ucwords(strtolower($category)));
$cats['brand'] = array(
'name' => $cat_name,
'slug' => sanitize_title_with_dashes($category)
);
if (!empty($brand))
{
$subbrand = term_exists($cats['brand']['slug'], 'product_cat', $brand['term_id']);
if (empty($subbrand))
{
$subbrand = wp_insert_term(
$cats['brand']['name'],
'product_cat',
array(
'slug' => $cats['brand']['slug'],
'parent'=> $brand['term_id']
)
);
}
} else {
$brand = wp_insert_term(
'Brand',
'product_cat',
array(
'slug' => 'brand',
'parent'=> 0 // This means it will be at the first level!
)
);
$subbrand = term_exists($cats['brand']['slug'], 'product_cat', $brand['term_id']);
if (empty($subbrand))
{
$subbrand = wp_insert_term(
$cats['brand']['name'],
'product_cat',
array(
'slug' => $cats['brand']['slug'],
'parent'=> $brand['term_id']
)
);
}
}
$categories = array(
'product_id' => // put the product id value in here!
'terms' => array()
);
if (!empty($subbrand))
{
$categories['terms']['subbrands'] = $subbrand;
}
// Now insert into term_relationships table for that product and that's all folks...
foreach($categories['terms'] as $type => $nfo)
{
$wpdb->insert(
$wpdb->prefix . "term_relationships",
array(
'object_id' => $categories['product_id'],
'term_taxonomy_id' => intval($nfo['term_taxonomy_id']),
'term_order' => 0
),
array('%d', '%d', '%d')
);
}
So, hopefully this helps you to build categories for your products, while still keeping your product attributes in tact in the search filter. Good Luck.
Related
I've been racking my brain for a few days on this issue and can't figure out why my code to import is creating duplicate product categories.
Problem: I am pulling in about 30,000 products from the third party API in JSON format it is then is inserted into a custom database, from which I pull each product's data and format for importing into WooCommerce, these processes are working fine the problem comes when I am inserting the category terms. When categories are inserted using wp_insert_term some categories are duplicated but have a different URL slug.
ie...
— Ranges, Cooktops & Ovens
— — Range Hoods & Downdraft Ventilation (slug: range-hoods-downdraft-ventilation )
— — Range Hoods & Downdraft Ventilation (slug: range-hoods-downdraft-ventilation-ranges-cooktops-ovens)
The child category gets duplicated but with a different slug.
This is the Category array I'm looping through to create the hierarchical category paths:
"categoryPath":[{"id":"cat00000","name":"Company Name"},{"id":"abcat0900000","name":"Appliances"},{"id":"abcat0904000","name":"Ranges, Cooktops & Ovens"},{"id":"abcat0904002","name":"Range Hoods & Downdraft Ventilation"}]
Here is my single product import code the relevant category portion in at the bottom starting with $categoryPath, just wanted to give some context of what Im doing:
$result= $wpdb->get_var( "SELECT `results_array`
FROM $table_name
WHERE `arr_serialize2` = $textProductSku
AND `update_type` = 'create'
");
$final_product_formate_arrays = json_decode($result, true);
$post = array(
'post_title' => $final_product_formate_arrays['parent_or_simple_product']['title'],
'post_content' => $final_product_formate_arrays['parent_or_simple_product']['longDescription'],
'post_excerpt' => isset( $final_product_formate_arrays['parent_or_simple_product']['shortDescription']) ? $final_product_formate_arrays['parent_or_simple_product']['shortDescription'] : '' ,
'post_status' => "publish",
'post_parent' => '',
'post_type' => "product",
);
$post_id = wp_insert_post( $post );
if (!$post_id)
{
return false;
}
update_post_meta($post_id,'_complete_product_data',json_encode($final_product_formate_arrays));
update_post_meta($post_id, '_sku', $final_product_formate_arrays['parent_or_simple_product']['sku']);
update_post_meta( $post_id, '_visibility', 'visible' );
if($final_product_formate_arrays['parent_or_simple_product']['inStoreAvailability'] > 0)
{
update_post_meta( $post_id, '_manage_stock', "yes" );
update_post_meta( $post_id, '_stock', $final_product_formate_arrays['parent_or_simple_product']['stockQuantity'] );
update_post_meta( $post_id, '_stock_status', 'instock');
} elseif($final_product_formate_arrays['is_variation']){
update_post_meta( $post_id, '_manage_stock', "no" );
update_post_meta( $post_id, '_stock_status', 'instock');
} else {
update_post_meta( $post_id, '_manage_stock', "yes" );
update_post_meta( $post_id, '_stock_status', 'outofstock');
update_post_meta( $post_id, '_stock', 0 );
}
update_post_meta( $post_id, '_regular_price', $final_product_formate_arrays['parent_or_simple_product']['regularPrice'] );
update_post_meta( $post_id, '_sale_price', $final_product_formate_arrays['parent_or_simple_product']['salePrice'] );
update_post_meta( $post_id, '_price', $final_product_formate_arrays['parent_or_simple_product']['salePrice'] );
update_post_meta( $post_id, '_weight', $final_product_formate_arrays['parent_or_simple_product']['weight'] );
update_post_meta( $post_id, '_length', $final_product_formate_arrays['parent_or_simple_product']['depth'] );
update_post_meta( $post_id, '_width', $final_product_formate_arrays['parent_or_simple_product']['width'] );
update_post_meta( $post_id, '_height', $final_product_formate_arrays['parent_or_simple_product']['height'] );
update_post_meta( $post_id, '_wc_average_rating', $final_product_formate_arrays['parent_or_simple_product']['reviewAverage'] );
**$categoryPath = $final_product_formate_arrays['parent_or_simple_product']['categoryPath'];
if(!empty($categoryPath))
{
$parent_id='';
foreach ($categoryPath as $key => $value) {
if($key!=0) {
$new_str = str_replace( array( ',', '&' ), '-', $value['name'] );
$new_str = sanitize_title( $new_str );
$parent_term = term_exists( $parent_id, 'product_cat' ); // array is returned if taxonomy is given
if( isset( $parent_term )) {
$parent_id = $parent_term['term_id']; // get numeric term id
} else{
$parent_id = 0;
}
$term = wp_insert_term( $value['name'], 'product_cat', [
'description'=> $value['name'],
'parent' => intval( $parent_id ),
'slug' => $new_str,
]
);
if( is_wp_error( $term ) && isset( $term->error_data['term_exists'] ) )
{
$term_id = isset( $term->error_data['term_exists'] ) ? $term->error_data['term_exists'] :'';
$term_error = $term->get_error_message();
$term_error .="\n";
error_log($term_error, 3, $pluginlog);
} else if ( !is_wp_error( $term ) ) {
$new_term_id = isset( $term['term_id']) ? $term['term_id'] : '';
$term_id = $new_term_id;
}
$term_id = intval($term_id);
$parent_id = !empty($term_id)?$term_id:'';
wp_set_post_terms($post_id, $term_id, 'product_cat');**
// wp_set_object_terms($post_id, $term_id, 'product_cat');
} else {
continue;
}
}
}
I've created a custom rest route in Wordpress which takes a product category id and will send products which are in that category.
My Problem is I can't figure out a way to get variable product min and max prices inside my custom loop.
Can anyone help me with this issue?
Thanks
I've tried to get variation price using get_variation_prices() but it seems that I'm missing something.
add_action( 'rest_api_init' , 'wt_rest_api');
function wt_rest_api(){
register_rest_route('wtrest','products',array(
'methods' => WP_REST_SERVER::READABLE,
'callback' => 'wtProductResults'
));
}
function wtProductResults($data){
$products = new WP_Query([
'post_type' => 'product',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id', //can be set to ID
'terms' => $data['cat'] //if field is ID you can reference by cat/term number
)
)
]);
$productsResults = [];
global $woocommerce;
global $product;
$currency = get_woocommerce_currency_symbol();
while($products->have_posts()){
$products->the_post();
$product_cat = get_term( $data['cat'], 'product_cat', 'category', "OBJECT" );
$regularPrice = get_post_meta( get_the_ID(), '_regular_price', true);
$sale = get_post_meta( get_the_ID(), '_sale_price', true);
$price = get_post_meta( get_the_ID(), '_price', true );
array_push($productsResults , [
'title' => get_the_title(),
'productId' => get_the_id(),
'permalink' => get_the_permalink(),
'thumbnail' => get_the_post_thumbnail(),
'excerpt' => get_the_excerpt(),
'regularPrice' => $regularPrice,
'price' => $price,
'salePrice' => $sale,
'category' => $product_cat->name,
'variationPrice' => get_variation_prices()//**Here is My problem**
]);
}
wp_reset_postdata();
return $productsResults;
}
Here is my Code and when I used get_variation_prices() I didn't get any response from my rest route
The function get_variation_prices() is a method of WC_Product_Variable Class and it works exclusively as a method on a variable product instance object. It gives a multi dimensional array of all variations prices.
To get Min and Max variation prices, you have to use WC_Product_Variable methods:
get_variation_regular_price() or get_variation_regular_price('max')
get_variation_sale_price() or get_variation_sale_price('max')
get_variation_price() or get_variation_price('max')
Now in your code:
you will need first to get the WC_Product instance object.
check products type.
remove global $product; as it's empty and not useful.
(you might need to make other changes, based on your requirements)
Now there is multiple ways to query products:
1) Using a WP_Query (just as you are doing actually):
function wtProductResults($data){
global $woocommerce;
$products = new WP_Query([
'post_type' => 'product',
'tax_query' => array( array(
'taxonomy' => 'product_cat',
'field' => 'term_id', //can be set to ID
'terms' => $data['cat'] //if field is ID you can reference by cat/term number
) )
]);
$productsResults = [];
$currency = get_woocommerce_currency_symbol();
if ( $products->have_posts() ) :
while ( $products->have_posts() ) : $products->the_post();
$product_cat = get_term( $data['cat'], 'product_cat', 'category', "OBJECT" );
// Get an instance of the WC_Product object
$product = wc_get_product( get_the_ID() );
if( $product->is_type('variable') ) {
// Min variation price
$regularPriceMin = $product->get_variation_regular_price(); // Min regular price
$salePriceMin = $product->get_variation_sale_price(); // Min sale price
$priceMin = $product->get_variation_price(); // Min price
// Max variation price
$regularPriceMax = $product->get_variation_regular_price('max'); // Max regular price
$salePriceMax = $product->get_variation_sale_price('max'); // Max sale price
$priceMax = $product->get_variation_price('max'); // Max price
// Multi dimensional array of all variations prices
$variationsPrices = $product->get_variation_prices();
$regularPrice = $salePrice = $price = '';
$variationPrice = [
'min' => $product->get_variation_price(),
'max' => $product->get_variation_price('max')
];
}
// Other product types
else {
$regularPrice = $product->get_regular_price();
$salePrice = $product->get_sale_price();
$price = $product->get_price();
$variationPrice = ['min' => '', 'max' => ''];
}
array_push( $productsResults , [
'title' => get_the_title(),
'productId' => get_the_id(),
'permalink' => get_the_permalink(),
'thumbnail' => get_the_post_thumbnail(),
'excerpt' => get_the_excerpt(),
'regularPrice' => $regularPrice,
'price' => $price,
'salePrice' => $salePrice,
'category' => $product_cat->name,
'variationPrice' => $variationPrice,
]);
endwhile;
wp_reset_postdata();
endif;
return $productsResults;
}
2) Using a WC_Product_Query instead like:
function wtProductResults($data){
global $woocommerce;
$products = wc_get_products( array(
'status' => 'publish',
'limit' => -1,
'category' => array($data['cat']),
) );
$productsResults = [];
$currency = get_woocommerce_currency_symbol();
if ( sizeof($products) > 0 ) :
foreach ( $products as $product ) :
$term_name = get_term( $data['cat'], 'product_cat' )->name;
if( $product->is_type('variable') ) {
// Min variation price
$regularPriceMin = $product->get_variation_regular_price(); // Min regular price
$salePriceMin = $product->get_variation_sale_price(); // Min sale price
$priceMin = $product->get_variation_price(); // Min price
// Max variation price
$regularPriceMax = $product->get_variation_regular_price('max'); // Max regular price
$salePriceMax = $product->get_variation_sale_price('max'); // Max sale price
$priceMax = $product->get_variation_price('max'); // Max price
// Multi dimensional array of all variations prices
$variationsPrices = $product->get_variation_prices();
$regularPrice = $salePrice = $price = '';
$variationPrice = [
'min' => $product->get_variation_price(),
'max' => $product->get_variation_price('max')
];
}
// Other product types
else {
$regularPrice = $product->get_regular_price();
$salePrice = $product->get_sale_price();
$price = $product->get_price();
$variationPrice = ['min' => '', 'max' => ''];
}
array_push( $productsResults , [
'title' => $product->get_name(),
'productId' => $product->get_id(),
'permalink' => $product->get_permalink(),
'thumbnail' => $product->get_image(),
'excerpt' => $product->get_short_description(),
'regularPrice' => $regularPrice,
'price' => $price,
'salePrice' => $salePrice,
'category' => $term_name,
'variationPrice' => $variationPrice,
]);
endforeach;
endif;
return $productsResults;
}
The Answer that #LoicTheAztec gave was very good and I liked the way he write the code
but in my case I found on simple change that worked perfectly the way I want it to be both normal product price if it's normal product and variable product price if variable product
This is the change I made and I used both wc_get_product(get_the_id()) and get_price_html()
$product = wc_get_product( get_the_id() );
array_push($productsResults , [
'title' => get_the_title(),
'productId' => get_the_id(),
'permalink' => get_the_permalink(),
'thumbnail' => get_the_post_thumbnail(),
'excerpt' => get_the_excerpt(),
'category' => get_the_terms(get_the_id(),'product_cat'),
'price' => $product->get_price_html(),
]);
this code should be inside while loop that I used with WP_Query()
add_filter( 'woocommerce_variable_price_html', 'bbloomer_variation_price_format_min', 9999, 2 );
function bbloomer_variation_price_format_min( $price, $product ) {
$prices = $product->get_variation_prices('min', true );
$maxprices = $product->get_variation_price( 'max', true ) ;
$min_price = current( $prices['price'] );
//$max_price = current( $maxprices['price'] );
$minPrice = sprintf( __( 'from: %1$s', 'woocommerce' ), wc_price( $min_price ) );
$maxPrice = sprintf( __( 'to: %1$s', 'woocommerce' ), wc_price( $maxprices ) );
return $minPrice .' ' .$maxPrice ;
}
I would like to set all variable products, when created, with the same six different variations using an already defined attribute ("bidragsstorlek"). The six variations should have different prices.
With my current code I succeded with all steps except the last one. I succefully added an attribute, six diffrent terms and six different variations. When I look in the back end panel the product variations have the prices I want, the only thing missing is to set the right term to each variation.
I know similar questions been asked before and been trying to implement those answers, but can't get it right.
$taxonomy = 'pa_bidragsstorlek';
$arrtermnames = array('50 kronor', '100 kronor', '250 kronor', '500 kronor', '1000 kronor', '5000 kronor');
$attr_data = Array(
$taxonomy=>Array(
'name' => $taxonomy,
'value' => '',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1'
)
);
$newproduct = new WC_Product($product_id);
update_post_meta( $product_id, '_product_attributes', array_merge($newproduct->get_attributes(), $attr_data) );
foreach ($arrtermnames as &$value) {
$term_name = $value; // The term "NAME"
$term_slug = sanitize_title($term_name); // The term "slug"
// Check if the term exist and if not it create it (and get the term ID).
if( ! term_exists( $term_name, $taxonomy ) ){
$term_data = wp_insert_term( $term_name, $taxonomy );
$term_id = $term_data['term_id'];
} else {
$term_id = get_term_by( 'name', $term_name, $taxonomy )->term_id;
}
// get an instance of the WC_Product Object
$product = wc_get_product( $product_id );
$attributes = (array) $product->get_attributes();
// 1. If the product attribute is set for the product
if( array_key_exists( $taxonomy, $attributes ) ) {
foreach( $attributes as $key => $attribute ){
if( $key == $taxonomy ){
$options = (array) $attribute->get_options();
$options[] = $term_id;
$attribute->set_options($options);
$attributes[$key] = $attribute;
break;
}
}
$product->set_attributes( $attributes );
}
// 2. The product attribute is not set for the product
else {
$attribute = new WC_Product_Attribute();
$attribute->set_id( sizeof( $attributes) + 1 );
$attribute->set_name( $taxonomy );
$attribute->set_options( array( $term_id ) );
$attribute->set_position( sizeof( $attributes) + 1 );
$attribute->set_visible( true );
$attribute->set_variation( false );
$attributes[] = $attribute;
$product->set_attributes( $attributes );
}
$product->save();
// Append the new term in the product
if( ! has_term( $term_name, $taxonomy, $product_id ))
wp_set_object_terms($product_id, $term_slug, $taxonomy, true );
}
unset($value);
$parent_id = $product_id;
$arrprice = array(50, 100, 250, 500, 1000, 5000);
for ($x = 0; $x <= 5; $x++) {
$variation = array(
'post_title' => 'Product #' . $parent_id. $arrprice[$x],
'post_content' => '',
'post_status' => 'publish',
'post_parent' => $parent_id,
'post_type' => 'product_variation'
);
// The variation id
$variation_id = wp_insert_post( $variation );
update_post_meta( $variation_id, '_regular_price', $arrprice[$x] );
update_post_meta( $variation_id, '_price', $arrtermnames[$x] );
update_post_meta( $variation_id, '_virtual', '1' );
// Assign the size and color of this variation
update_post_meta( $variation_id, 'attribute_'.$taxonomy, $arrtermnames[$x] );
WC_Product_Variable::sync( $parent_id );
}
Right now with this code, when checking in the panel, I have a drop-down at each variation with all the terms - but none is choosen. Any idea what is missing to make each variation to be set to the right term?
I know this is probably super easy and I am overlooking something here.
I have a form on the front-end of our website where users can upload an image via a form and it creates a product in our shop. We are using Wordpress and Woocommerce but I felt this question was general enough to ask on here.
Currently everything works fine when uploading one image, How would I make this work for when a user uploads multiple images?
In the form I changed
<input type="file" name="thumbnail" id="thumbnail" />
to
<input type="file" name="thumbnail" id="thumbnail" multiple />and I thought wrapping the below in something like this would work:
if ($_FILES) {
foreach ($_FILES as $file => $array) {
// do necessary code
}
}
But it doesn't.
Here is what I have that creates the post. Im not sure why wrapping it in the foreach $FILES won't work?
$current_user = wp_get_current_user();
if(isset($_POST['submitted']) && isset($_POST['post_nonce_field']) && wp_verify_nonce($_POST['post_nonce_field'], 'post_nonce')) {
$postTitle = trim($_POST['postTitle']);
if($post_id)
{
wp_redirect(home_url());
exit;
}
//random sku
$skuu = rand();
$new_post = array(
'post_title' => $skuu,
'post_content' => '', //add anything here like link to vendor or whatever
'post_status' => 'publish',
'post_type' => 'product'
);
//insert and update post
$post_id = wp_insert_post($new_post);
update_post_meta($post_id, '_sku', $skuu );
if ($_FILES) {
foreach ($_FILES as $file => $array) {
$newupload = insert_attachment($file,$post_id);
}
}
//find available attributes
$avail_attributes = Array(
'high-resolution',
'medium-resolution',
'low-resolution'
);
//set terms (variations and attributes)
wp_set_object_terms ($post_id, 'variable', 'product_type');
wp_set_object_terms( $post_id, $avail_attributes, 'pa_resolution' );
//Categories
wp_set_object_terms( $post_id, array(esc_attr(strip_tags($_POST['postCat'])), esc_attr(strip_tags($_POST['raceCat']))), 'product_cat' );
// set variable data
$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', 'visible' );
update_post_meta( $post_id, '_stock_status', 'instock');
//update_post_meta( $post_id, '_product_vendors_commission', '25');
//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,
'post_author' => $vendor_data->term_id
);
// Insert the post into the database
wp_insert_post( $my_post );
$variable_id = $post_id + 2;
$variable_two = $variable_id + 1;
$variable_three = $variable_two + 1;
//get user prices
global $current_user;
$low_price = get_user_meta($current_user->ID, '_low_price', true);
$medium_price = get_user_meta($current_user->ID, '_medium_price', true);
$high_price = get_user_meta($current_user->ID, '_high_price', true);
//downloadable file paths
$download_id = get_post_thumbnail_id( $post_id );
$lowRes_src = wp_get_attachment_image_src( $download_id, 'low-resolution' );
$medRes_src = wp_get_attachment_image_src( $download_id, 'medium-resolution' );
$highRes_src = wp_get_attachment_image_src( $download_id, 'high-resolution' );
$low_downloadable_images = array();
$medium_downloadable_images = array();
$high_downloadable_images = array();
foreach ($lowRes_src as $lowRes_url) {
$lowRes_url = $lowRes_src[0];
$low_downloadable_images[md5( $lowRes_url )] = $lowRes_url;
}
foreach ($medRes_src as $medRes_url) {
$medRes_url = $medRes_src[0];
$medium_downloadable_images[md5( $medRes_url )] = $medRes_url;
}
foreach ($highRes_src as $highRes_url) {
$highRes_url = $highRes_src[0];
$high_downloadable_images[md5( $highRes_url )] = $highRes_url;
}
//echo $rand;
update_post_meta( $variable_id, 'attribute_pa_resolution', 'high-resolution');
update_post_meta( $variable_id, '_price', $high_price );
update_post_meta( $variable_id, '_regular_price', $high_price);
update_post_meta( $variable_id, '_virtual', 'yes');
update_post_meta( $variable_id, '_downloadable', 'yes');
update_post_meta( $variable_id, '_file_paths', $high_downloadable_images);
update_post_meta( $variable_two, 'attribute_pa_resolution', 'medium-resolution');
update_post_meta( $variable_two, '_price', $medium_price );
update_post_meta( $variable_two, '_regular_price', $medium_price);
update_post_meta( $variable_two, '_virtual', 'yes');
update_post_meta( $variable_two, '_downloadable', 'yes');
update_post_meta( $variable_two, '_file_paths', $medium_downloadable_images);
update_post_meta( $variable_three, 'attribute_pa_resolution', 'low-resolution');
update_post_meta( $variable_three, '_price', $low_price );
update_post_meta( $variable_three, '_regular_price', $low_price);
update_post_meta( $variable_three, '_virtual', 'yes');
update_post_meta( $variable_three, '_downloadable', 'yes');
update_post_meta( $variable_three, '_file_paths', $low_downloadable_images);
$i++;
}
}
//attach vendor to product
$vendor = get_user_vendor();
if( isset( $vendor->slug ) && strlen( $vendor->slug ) > 0 ) {
wp_set_object_terms( $post_id, $vendor->slug, 'shop_vendor', false );
}
In short I just need a way for the above code to create the post for each file uploaded, instead of just one file uploaded like it currently does.. Im all out of ideas
Got it, so I changed the name of the file input from thumbnail to thumbnail[]. Then I wrapped the above paste in a function and added this part at the top of the file and it works perfectly:
if ( $_FILES ) {
$files = $_FILES['thumbnail'];
foreach ($files['name'] as $key => $value) {
if ($files['name'][$key]) {
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key]
);
$_FILES = array("" => $file);
foreach ($_FILES as $file => $array) {
//call my function
create_var_product($file, $post_id);
}
}
}
}
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?