Wordpress 如何更新购物车项目元商务

Wordpress 如何更新购物车项目元商务,wordpress,woocommerce,Wordpress,Woocommerce,我知道我们可以使用woocmerce\u add\u cart\u item\u datahook为woocmerce购物车项目添加meta 是否有任何方法更新现有购物车项目元数据?步骤1:在自定义会话中添加数据,在“添加到购物车”按钮上单击 对于那些曾经与WooCommerce合作过的人来说,他们可能知道,单击“添加到购物车”按钮,产品页面将刷新,用户数据将丢失。因此,我们应该将产品页面中的自定义数据添加到使用Ajax创建的自定义会话中。在创建WooCommerce会话之前调用此代码 <

我知道我们可以使用
woocmerce\u add\u cart\u item\u data
hook为woocmerce购物车项目添加meta


是否有任何方法更新现有购物车项目元数据?

步骤1:在自定义会话中添加数据,在“添加到购物车”按钮上单击

对于那些曾经与WooCommerce合作过的人来说,他们可能知道,单击“添加到购物车”按钮,产品页面将刷新,用户数据将丢失。因此,我们应该将产品页面中的自定义数据添加到使用Ajax创建的自定义会话中。在创建WooCommerce会话之前调用此代码

<?php
add_action('wp_ajax_wdm_add_user_custom_data_options', 'wdm_add_user_custom_data_options_callback');
add_action('wp_ajax_nopriv_wdm_add_user_custom_data_options', 'wdm_add_user_custom_data_options_callback');

function wdm_add_user_custom_data_options_callback()
{
      //Custom data - Sent Via AJAX post method
      $product_id = $_POST['id']; //This is product ID
      $user_custom_data_values =  $_POST['user_data']; //This is User custom value sent via AJAX
      session_start();
      $_SESSION['wdm_user_custom_data'] = $user_custom_data_values;
      die();
}
步骤3:从WooCommerce会话提取自定义数据并将其插入购物车对象

在这个阶段,我们在WooCommerce会话中有默认的产品详细信息和自定义数据。由于插件提供的功能,默认数据被添加到购物车对象中。但是,我们需要显式地从WooCommerce会话提取自定义数据,并将其插入cart对象。这可以通过以下代码实现

add_filter('woocommerce_get_cart_item_from_session', 'wdm_get_cart_items_from_session', 1, 3 );
if(!function_exists('wdm_get_cart_items_from_session'))
{
    function wdm_get_cart_items_from_session($item,$values,$key)
    {
        if (array_key_exists( 'wdm_user_custom_data_value', $values ) )
        {
        $item['wdm_user_custom_data_value'] = $values['wdm_user_custom_data_value'];
        }       
        return $item;
    }
}
步骤4:在购物车和结账页面上显示用户自定义数据

现在我们在购物车对象中有了自定义数据,我们现在需要做的就是在购物车和结帐页面中显示这些数据。这是您的购物车页面在自定义数据从WooCommerce会话添加到购物车后的外观。
我的购物车页面

我知道这已经有一段时间了,但由于它仍然没有得到回答,我付出了大量的汗水和一品脱的鲜血,我在这里分享我的解决方案

首先 我假设您知道如何将元数据添加到购物车和订单中。如果没有,你可以看看,但我建议你在

Wisdm的方法需要很多步骤。首先,通过Ajax创建PHP的会话变量。其次,截取
woocmerce\u add\u cart\u item\u数据
过滤器,将会话变量添加到woocmerce会话中

<>代码> WooCuffixAddioCARTITIOMEDATA < /COD>过滤器,它是在<代码>中间添加到购物车过程中,因此,如果将变量添加到主<代码> $WooOcMyCys对象,在某个点,它被存储为Add to CART事件。(有点)

想法 如果我想编辑元数据而不是任何标准购物车属性,该怎么办。最理想的方法是获得一个过滤器或一个在保存东西的过程中运行的动作。问题是,只要我们不更改任何其他内容,就没有钩子可以运行(我尝试了
woocommerce\u update\u cart\u action\u cart\u updated
钩子,它在优惠券、数量和从购物车中移除之后运行,但它从未启动,因为我从未通过验证)

我的方法 在shell中,根据需要尽可能少地重建。我在购物车表单OnSubmit事件中添加了一个同步ajax事件。(我想用我的更改更新我的UI,因此必须在更新后重新加载)

阿贾克斯:

魔法: php ajax响应是一个函数,它将接收我要更新的元数据(实际上,所有元数据,无论是否已更新),并将使用全局
$woocommerce
对象插入元数据,并将其保存到会话中:

PHP:

当然,这应该和其他ajax事件一样挂钩

add_action('wp_ajax_nopriv_Ajax_Update_My_MetaData_33322805', 'fn_Ajax_Update_My_MetaData_33322805');
add_action('wp_ajax_Ajax_Update_My_MetaData_33322805',  'fn_Ajax_Update_My_MetaData_33322805');
结论 您可以使用同步Ajax调用更新购物车项目的元数据,将对象直接覆盖到
$woocommerce
全局变量,并使用
$woocommerce->cart->set_session()保存它方法

脚注 这不是一种理想的方法,直接使用
$woocommerce
global非常危险。我很想知道更好的方法。

我是新手,英语不好,所以答案可能有点混乱

谢谢你的建议

我的方法:

foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
    ...
    ?>
    <!-- place it anywhere within the foreach -->
    <div class="box-type-field">
        <select class="box-type" name="box-type" cart_item_key="<?php echo $cart_item_key ?>">
            <option <?php echo $cart_item['box-type']=='boxes'?"selected":""; ?> value="boxes"><?php _e( 'Boxes', 'woocommerce' ); ?></option>
            <option <?php echo $cart_item['box-type']=='bags'?"selected":""; ?> value="bags"><?php _e( 'Bags', 'woocommerce' ); ?></option>
        </select>
    </div>
    <?php
    ...
}
与Daniel Salcedo一样,我也尝试通过编辑woocommerce\u会话来更改元数据,但存在一个问题。将商品添加到购物车时,woocommerce将通过md5(产品id+…+元数据)为其创建唯一的购物车商品密钥,然后查找此购物车商品密钥是否已存在,如果可用,此商品将在数量上更新,否则将创建新商品

这意味着如果您将帽子产品的元值从蓝色更改为红色,然后添加带有蓝色的帽子产品,而不是创建一个新项目蓝色帽子,它只会增加红色帽子的数量,如果希望正确更新购物车,则需要更改购物车\项目\键

更改购物车项目密钥非常危险,相反,我们可以简单地删除并重新添加产品。像这样

// get cart_item_key of item you want to change
$cart_item_key_old = $_POST['cart_item_key']; 

// retrieve its information
$cart_item_old = WC()->cart->cart_contents[ $cart_item_key_old ];
$product_id_old = $cart_item_old['product_id'];
$quantity_old = $cart_item_old['quantity'];
$variation_id_old = $cart_item_old['variation_id'];
$variation_old = $cart_item_old['variation'];

// creating a cart_item_key with the same information except metadata
$cart_item_key_new = WC()->cart->generate_cart_id( $product_id_old, $variation_id_old, $variation_old, ['color'=>'red'] );
// check new cart_item_key already exists
$found = WC()->cart->find_product_in_cart( $cart_item_key_new );

// if true, update its quantity
if ($found != '') {
    $new_quantity = $cart_item_old['quantity'] + WC()->cart->cart_contents[ $cart_item_key_new ]['quantity'];
    WC()->cart->set_quantity( $cart_item_key_new, $new_quantity );
}
// else, re-add with new metadata
else {
    WC()->cart->add_to_cart($product_id_old, $quantity_old, $variation_id_old, $variation_old, ['color'=>'red'] );
}

// finally delete the old item
WC()->cart->remove_cart_item($cart_item_key_old);

wp_die();
注意:如果您希望在运行上述ajax后提交购物车表单而不是页面刷新,则在更新购物车时,商品数量可能会被set\u quantity方法覆盖。在这种情况下,您只需返回新的_数量,并在提交表单之前通过js更改输入值

完整代码:

foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
    ...
    ?>
    <!-- place it anywhere within the foreach -->
    <div class="box-type-field">
        <select class="box-type" name="box-type" cart_item_key="<?php echo $cart_item_key ?>">
            <option <?php echo $cart_item['box-type']=='boxes'?"selected":""; ?> value="boxes"><?php _e( 'Boxes', 'woocommerce' ); ?></option>
            <option <?php echo $cart_item['box-type']=='bags'?"selected":""; ?> value="bags"><?php _e( 'Bags', 'woocommerce' ); ?></option>
        </select>
    </div>
    <?php
    ...
}

是的,但似乎只有通过直接访问购物车:

global $woocommerce;
$woocommerce->cart->cart_contents[$cart_item_key]['whatever_meta'] = 'testing';
$woocommerce->cart->set_session();   // when in ajax calls, saves it.
我建议删除并重新添加该产品,因为其他元数据可能会丢失(如Phong Tran的回答)


基于@DanielSalcedos答案,只保留回答问题所需的绝对最小值

感谢您的解释,我已经使用“woocommerce\u add\u cart\u item\u data”操作添加了购物车项目元,我需要的是在更新购物车(购物车页面)或更新配送(结帐页面)时更新这些购物车项目元,如何做到这一点。这个答案可以从对提议的一般方法/解决方案的一些额外解释中受益。此外,给出了详细的其他答案,提供更多信息说明为什么这与现有解决方案不同,会很有帮助。很好的方法!你救了一个孩子
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
    ...
    ?>
    <!-- place it anywhere within the foreach -->
    <div class="box-type-field">
        <select class="box-type" name="box-type" cart_item_key="<?php echo $cart_item_key ?>">
            <option <?php echo $cart_item['box-type']=='boxes'?"selected":""; ?> value="boxes"><?php _e( 'Boxes', 'woocommerce' ); ?></option>
            <option <?php echo $cart_item['box-type']=='bags'?"selected":""; ?> value="bags"><?php _e( 'Bags', 'woocommerce' ); ?></option>
        </select>
    </div>
    <?php
    ...
}
$('.box-type-field .box-type').live('change', function () {
    var cartItemKey = $(this).attr("cart_item_key");
    var boxType = $(this).val();
    $.ajax({
        type : "post", 
        url : '<?php echo admin_url('admin-ajax.php');?>',
        datatype: 'json',
        data : {
            action : "update_cart_boxtype",
            cart_item_key : cartItemKey,
            box_type : boxType,
        },
        success: function(cartItem) {
            cartItemKey = cartItem[0];
            cartItemQty = cartItem[1];
            if (cartItem) $('input[name="cart['+cartItemKey+'][qty]"]').val(cartItemQty); // update quantity 

            $('.woocommerce-cart-form button[type="submit"]').click(); // submit form
        }
    })
})
add_action( 'wp_ajax_update_cart_boxtype', 'update_cart_boxtype_init' );
add_action( 'wp_ajax_nopriv_update_cart_boxtype', 'update_cart_boxtype_init' );
function update_cart_boxtype_init() {
    if ( ! WC()->cart->is_empty() ) {
        $cart_item_key = (isset($_POST['cart_item_key']))?$_POST['cart_item_key'] : '';
        $cart_item = WC()->cart->cart_contents[ $cart_item_key ];
        $box_type = (isset($_POST['box_type']))?$_POST['box_type'] : '';
        $cart_updated = false;

        $cart_item_key_new = WC()->cart->generate_cart_id( $cart_item['product_id'], $cart_item['variation_id'], $cart_item['variation'], ['box-type'=>$box_type] );

        $found = WC()->cart->find_product_in_cart( $cart_item_key_new );

        if ($found != '') {
            $new_qty = $cart_item['quantity'] + WC()->cart->cart_contents[ $cart_item_key_new ]['quantity'];
            WC()->cart->remove_cart_item($cart_item_key);
            wp_send_json_success([$cart_item_key_new, $new_qty]);
        } else {
            WC()->cart->add_to_cart($cart_item['product_id'], $cart_item['quantity'], $cart_item['variation_id'], $cart_item['variation'], ['box-type' => $box_type]);
            $cart_updated = true;
            WC()->cart->remove_cart_item($cart_item_key);
            wp_send_json_success(false);
        }
    }
    wp_die();
}
global $woocommerce;
$woocommerce->cart->cart_contents[$cart_item_key]['whatever_meta'] = 'testing';
$woocommerce->cart->set_session();   // when in ajax calls, saves it.