以编程方式创建具有新属性值的 WooCommerce 产品变体

Posted

技术标签:

【中文标题】以编程方式创建具有新属性值的 WooCommerce 产品变体【英文标题】:Create programmatically a WooCommerce product variation with new attribute values 【发布时间】:2018-05-11 03:00:36 【问题描述】:

我在 WooCommerce 版本 3+ 中创建了一个可变产品(“父”产品)。从 WordPress 插件,我想以编程方式创建具有新属性值的产品变体(“儿童”产品)。

变体属性已在 WooCommerce 中设置。 因此,每次创建一个变体时,也应以编程方式创建新属性的值并在父变量产品中设置。

如何做到这一点?有可能吗?


更新:我已经写了更多我希望的代码行,并尝试了很多方法来解决它,使用 woocommerce 对象,并添加了有关术语、术语元、术语与帖子的关系的缺失数据,在使用 WordPress 数据库对象的数据库 - 但没有任何东西足以让它工作。而且我无法指出哪里出错了——这就是为什么我不能提供一个更窄的问题——*** 更适合的问题。

【问题讨论】:

分享您的研究对每个人都有帮助。告诉我们您尝试了什么以及为什么它不能满足您的需求。这表明您已经花时间尝试帮助自己,它使我们免于重复明显的答案,最重要的是它可以帮助您获得更具体和相关的答案!另见:How to Ask 你应该关闭其中一个 - ***.com/questions/47518333/… 虽然我个人认为这是一个公平的问题,但至少提供您最好的尝试会更有用。这不仅可以指导其他人帮助您,还可以指导那些面临同样问题的人 @MikeA 我明白,这就是我在 *** 上写问题时通常会做的事情。但是对于这个特定的,在这种情况下,提供我最好的尝试会导致 2 大块代码,这对社区来说肯定会适得其反。你可以相信我! 【参考方案1】:

我只是要把它扔在那里,因为我无法让上述任何示例正常工作。不要问我为什么其他人似乎取得了成功。所以,我采取了极简主义的方法,试图找出产品属性+变体的基本要素(通过在 wp 中手动创建并查看数据库)并想出了这个。

$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 );

这不是使用全局产品属性,而是使用特定于文章的属性。希望它对某人有所帮助,因为我正准备在我开始工作之前把头发扯下来。

编辑:我会说只有在您无法使用官方方法时才使用它。他们会随着时间改变这些东西(字段名称,如“_regular_price”等),这样做可能不是超级未来的证明。

【讨论】:

我正在使用此脚本,但收到错误“为属性发布的值无效”并且产品未添加到购物车。我们该如何解决这个问题? 这有点超出了这个答案的范围,但如果我不得不猜测,我会说特定变体的变体属性与您分配的属性不匹配(比如“备选方案 1 |备选方案 2”)。无论哪种方式,我们都在这里直接在帖子级别处理更新元字段,老实说,这(我的解决方案)应该是最后的手段,除非你真的无法使用官方 WooCommerce API 提供的方法。尝试在数据库级别(phpmyadmin 等)查看产品。 我使用与您类似的策略取得了最大的成功(插入“product_variation”帖子,然后设置其元数据)。 如何在此处添加变体图片 我最好的猜测是,您需要结合使用普通的 wordpress API 将图像添加到媒体库,然后使用这种变体的 set_image_id 方法; woocommerce.github.io/code-reference/classes/…【参考方案2】:

2020 年 1 月更新:更改为 WC_Product method get_name(),而不是 get_title()2018 年 9 月更新:处理分类创建(感谢 Carl F.科尼尔)

从定义的变量产品 ID 您将在下面找到一个自定义函数,该函数将添加(创建)产品变体。可变父产品需要为其设置所需的属性。

您需要提供以下信息:

属性/值数组 Sku、价格和库存......

这些数据必须存储在一个格式化的多维数组中(见最后的例子)

此函数将检查属性值(术语名称)是否已存在,如果不存在:

它为产品属性创建它 将其设置在父变量产品中。

自定义功能代码:

/**
 * 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

代码进入您的活动子主题(或主题)的 function.php 文件或任何插件文件中。

用法(具有 2 个属性的示例):

$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 );

经过测试并且有效。

第 2 部分: Create programmatically a variable product and two new attributes in WooCommerce

你会在后端得到这个:

它会在前端完美运行。

相关: Create programmatically a product using CRUD methods in Woocommerce 3

【讨论】:

@LiocTheAztec 我发现一些代码通常是可以接受的,但可以肯定的是,没问题。我已将我的建议作为新答案发布,希望您或其他人会发现它有用。感谢您的代码,效果很好! @RichardMišenčík 将其简单地更改为 'post_title' => $product->get_name()... 在 WC_Product related method documentation 上查看它 @SaadAbbasi Product Attributes 是一种非常特殊的自定义分类法,无法将它们附加到 SQL 查询中,因为要包含在变量 product 中的数据是 _product_attributes 元键下的索引多维数组 这需要PHP对WC_Product_Attribute对象数组中的数据进行格式化,并通过set_product_attributes()方法+save()方法将其设置在变量product中 @LoicTheAztec 我给了你提到的变体产品 id 和属性数组,但是在产品编辑页面上没有显示属性,也没有进行变体。你能帮帮我吗?【参考方案3】:

不知道为什么,但这些解决方案都不适合我,所以我决定创建自己的:

<?php
/**
 * Create a variable product on woocommerce
 * @return int Product ID
 */
function pricode_create_product()
    $product = new WC_Product_Variable();
    $product->set_description('T-shirt variable description');
    $product->set_name('T-shirt variable');
    $product->set_sku('test-shirt');
    $product->set_price(1);
    $product->set_regular_price(1);
    $product->set_stock_status();
    return $product->save();


/**
 * Create Product Attributes 
 * @param  string $name    Attribute name
 * @param  array $options Options values
 * @return Object          WC_Product_Attribute 
 */
function pricode_create_attributes( $name, $options )
    $attribute = new WC_Product_Attribute();
    $attribute->set_id(0);
    $attribute->set_name($name);
    $attribute->set_options($options);
    $attribute->set_visible(true);
    $attribute->set_variation(true);
    return $attribute;


/**
 * [pricode_create_variations description]
 * @param  [type] $product_id [description]
 * @param  [type] $values     [description]
 * @return [type]             [description]
 */
function pricode_create_variations( $product_id, $values )
    $variation = new WC_Product_Variation();
    $variation->set_parent_id( $product_id );
    $variation->set_attributes($values);
    $variation->set_status('publish');
    $variation->set_sku($data->sku);
    $variation->set_price($data->price);
    $variation->set_regular_price($data->price);
    $variation->set_stock_status();
    $variation->save();
    $product = wc_get_product($product_id);
    $product->save();


//Adding product
$product = pricode_create_product();

//Creating Attributes 
$atts = [];
$atts[] = pricode_create_attributes('color',['red', 'green']);
$atts[] = pricode_create_attributes('size',['S', 'M']);

//Adding attributes to the created product
$product->set_attributes( $atts );
$product->save();

//Create variations
pricode_create_variations( $product->get_id(), ['color' => 'red', 'size' => 'M']);

希望它可以帮助其他人。

【讨论】:

确认,其他解决方案对我不起作用。我在 Woocommerce 5.5.2 和 Wordpress 5.8 上,这个解决方案就像一个魅力。谢谢@alejandro-giraldo! 这与分类法有问题(产品 -> 属性)。对于预定义属性:php $taxName = 'colour'; $id = wc_attribute_taxonomy_id_by_name($taxName); $taxonomy = 'pa_colour'; // The taxonomy $term_name = "black"; // The term $term_id = get_term_by( 'name', $term_name, $taxonomy )-&gt;term_id; $atts[] = pricode_create_attributes( $taxonomy ,[$term_id], $id); pricode_create_variations( $product-&gt;get_id(), ['pa_colour' =&gt; 'black', 'pa_size' =&gt; 'm']); 您可能是对的,我这样做是为了解决我遇到的一个特定问题,并且不需要基本属性,但对于自定义分类法来说完全有用。感谢您的反馈!【参考方案4】:

上面的答案 (LoicTheAztec) 帮了我很多,但有一些问题,而不是使用

update_post_meta( $variation_id, 'attribute_'.$taxonomy, $term_slug );

使用:update_post_meta( $variation_id, 'attribute_'.$attribute, $term_name );

因为分类已经被修改,这会导致在更改此更新值后更新帖子元数据并且在此更改后无法在管理产品变体编辑中自动选择它工作得很好!

【讨论】:

这是否解决了在管理员变体中未选择术语名称的问题?【参考方案5】:

它可以工作,但需要一些更正(函数数组中的 2 个逗号),我确实根据需要编辑了一些代码。

(正在开发 wp 4.9 | wc 3.5)

首先产品需要具有已创建和关联的属性,我的分类是“pa_r”友好名称“R” backend attribute associeated img

修正函数

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

我用变体 [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]
);

和 foreach 动态创建我的产品的所有变体

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 );

【讨论】:

如果有产品 id 属性名称、选项、加号或减号、价格 1647 Copper Gskt No + 0.0000 1647 Copper Gskt Yes + 14.9500,我如何从给定数据创建变体数据1647 排水管 否 + 0.0000 1647 排水管 是 + 3.0000 1647 馈电管 否 + 0.0000 1647 馈电管 是 + 45.0000 1647 排水管 否 + 0.0000 1647 排水管 是 + 45.0000 在你的数组 [id_post, attribute, sku, regular_price, stock] 例如属性值怎么样。颜色是属性,黑红白是属性值 我必须使用哪个 add_action? 对我不起作用,我收到 未捕获错误:调用 wp-content/themes/x/functions.php:308 中布尔值的成员函数 get_title() /b>。第 308 行是这个 'post_title' => $product->get_title(),【参考方案6】:

如果您想在 WooCommerce 中生成用于测试的产品,您可以使用 WooCommerce 自己制作的 WooCommerce Smooth Generator

https://github.com/woocommerce/wc-smooth-generator

例子:

// 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();

源:https://github.com/woocommerce/wc-smooth-generator/blob/master/includes/Generator/Product.php

如果您想以编程方式创建产品,您可以根据需要对产品进行分类。

【讨论】:

这是最好的解决方案,使用 WooCommerce 标准。【参考方案7】:

如果产品的分类没有事先在其他地方注册,您可能会在此处遇到问题。如果您想确保分类存在,您可以在 LoicTheAztec 的答案中添加一个条件。

类似的东西。

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 
                ),
            )  
        ); 

    
...

【讨论】:

如何准备variation_data?【参考方案8】:

扩展 LoicTheAztec 的答案,您可以通过对其代码进行以下修改来检查属性组合是否存在。

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 );

    

    // ...


示例用法

// 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 );

【讨论】:

如果你能告诉我如何创建 $variation_data 如果我有这种方式的数据imgur.com/cT1sFGJ,那就太好了 很好的补充,但没有找到带空格的属性(例如颜色:“皇家蓝”),因为 postmeta 存储为 slug。修复:'value' =&gt; sanitize_title($value)(将 $value 转换为 slug)

以上是关于以编程方式创建具有新属性值的 WooCommerce 产品变体的主要内容,如果未能解决你的问题,请参考以下文章

在 ADAM 中以编程方式管理自定义属性

如何搜索 xml 节点值,然后在 c# 中为该元素创建新属性

添加具有 nil 值的新动态属性

从具有相同属性名称的多个 UITextField 中保存文本

创建具有甘特图的 Sharepoint 列表 - 以编程方式

EF 6:添加具有默认值的新属性不起作用[重复]