过去两天我一直在努力在我的插件中实现在 Woocommerce 中设置产品变体的能力。
我设法在 DB 中获取了所有正确的数据,但 Woocommerce 并没有像我想象的那样检索。
问题是存储在 wp_options 表中的“瞬态”。
这是让我启动并运行 WC 2.6.0 的代码:
基于所选属性创建变化($_POST['term_id_arr'] 是从前端选择的用于创建产品的所有属性的列表。很抱歉,我还不能在堆栈上发布图像。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 );
更新变化(例如价格、销售价格等...)。
$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);
}
删除变体
$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 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);
}
设置瞬态的函数(从 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 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;
}
在这一切之后,又出现了另一个问题(它永远不会发生,不是吗?):我还没弄清楚为什么,但在更新变体之后,父产品 post_meta '_stock_status' 总是设置为 'outofstock'。
我已修补此问题,在开始时使用 get_post_meta 检索正确状态并将其值传递给函数 lasap_woo_sync_varianti。
非常感谢任何改进,希望这将帮助某人节省他/她的时间!
在 WC 2.6.13 上经过测试和工作。见链接here