如何更新购物车项目meta-woocommerce

时间:2015-10-24 20:11:02

标签: wordpress woocommerce

我知道我们可以使用woocommerce_add_cart_item_data钩子为woocommerce购物车项目添加元数据。

有没有办法更新现有购物车商品元。?

4 个答案:

答案 0 :(得分:6)

我知道已经有一段时间了,但由于它仍然没有得到回答,而且我带了很多汗水和一品脱的血液,我在这里分享我的解决方案。

第一

我假设您知道如何将元数据添加到购物车和订单中。如果没有,您可以查看pwnewbie's solution,但我建议您在Wisdm labs

撰写完整文章

Wisdm的方法需要很多步骤。首先,您通过Ajax创建PHP的会话变量。其次,您拦截woocommerce_add_cart_item_data过滤器以将您的Session变量添加到woocommerce会话。

关于woocommerce_add_cart_item_data过滤器的事情是它在add to cart进程的中间执行,因此,如果您将变量添加到主$wooocmmerce对象,在某些时候,它被存储为add-to-cart事件。 (排序)

想法

如果我想编辑该元数据而不是任何标准购物车属性,该怎么办?理想的是获得一个过滤器或一个在保存某些东西的过程中运行的动作。问题在于,只要我们不改变其他任何东西,就没有可以运行的钩子(我尝试使用woocommerce_update_cart_action_cart_updated钩子,在优惠券,推车的数量和清除发生之后运行,但它从未被解雇,因为我从来没有通过了验证)

我的方法

在shell中,尽可能少地重建,尽可能多。我在购物车表单OnSubmit事件中添加了一个同步ajax事件。 (我希望我的UI能够根据我的更改进行更新,因此重新加载必须在我更新后进行)

AJAX:

var myFlag33322805 = true;
$('form').submit(function(e){
if(myFlag33322805){
    myFlag33322805 = false;
    e.preventDefault();     // Flag and prevent default to syncronize submits
    var kart = [];          // Will retrieve every cart item's meta

    $('.cartRow').each(function(){
    //This object will store your meta data and be pushed into kart array
    var kitm = {
        'p' : $(this).data('product_id'),
        'm' : $(this).find('select[name=myMetaData]').val(),
        'k' : $(this).data('key')
    };
    kart.push(kitm);
    });

    var data = {
    'action': 'Ajax_Update_My_MetaData_33322805',
    'k': kart
    };
    $.post(VKVAjax.ajaxurl, data, function (response) {
       // Might do something with the response here
    });
    $('form').submit();  // This time, the form will submit, but AJAX wont run because of myFlag33322805 = false
}
}); 

神奇:

php ajax响应是一个函数,它将接收我的元数据进行更新(实际上,所有这些,更新或不更新),并将使全局$woocommerce对象插入元数据 AND 将其保存到会话中:

PHP:

function fn_Update_My_MetaData_33322805(){
global $woocommerce;
$cart = $woocommerce->cart->cart_contents;
$updt = Array();
foreach ($_POST['k'] AS $item){
    $product = new stdClass();
    $updtCL = new stdClass();
    $product->{'id'} = $item['p'];          //This is product id
    $product->{'mymeta'} = $item['m'];      //This is metadata
    $updtCL->{'krtkey'} = $item['k'];       //This is product key in cart
    $updtCL->{'meta'} = $product;
    $updt[] = $updtCL;
}

// cycle the cart replace the meta of the correspondant key
foreach ($cart as $key => $item) {
    foreach($updt as $updtitem){
        if($key == $updtitem->krtkey){      // if this kart item corresponds with the received, the meta data is updated
            // Update the content of the kart
            $woocommerce->cart->cart_contents[$key]['vkv_AlternCart_value'] = $updtitem->meta;
        }
    }
}

// This is the magic: With this function, the modified object gets saved.
$woocommerce->cart->set_session();

wp_die('{"e":"ok", "Updt": "'.count($arrupdt).'"}');
}

当然,这应该像任何其他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');

Conclussion

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

脚注

这不是理想的方法,与$woocommerce全局直接合作风险很大。我很想知道更好的方法。

答案 1 :(得分:3)

是的,但是看来,只能通过直接访问购物车来实现:

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答案,仅保留回答该问题所需的绝对最小值。

答案 2 :(得分:1)

步骤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();
}

第2步:在WooCommerce Session中添加自定义数据

在此步骤中,已创建WooCommerce会话,现在可供我们添加自定义数据。我们使用以下代码将我们创建的会话中的自定义数据添加到WooCommerce会话中。在此步骤中,我们的会话也未设置,因为其中的数据已被捕获,不再需要它。

add_filter('woocommerce_add_cart_item_data','wdm_add_item_data',1,2);

if(!function_exists('wdm_add_item_data'))
{
    function wdm_add_item_data($cart_item_data,$product_id)
    {
        /*Here, We are adding item in WooCommerce session with, wdm_user_custom_data_value name*/
        global $woocommerce;
        session_start();    
        if (isset($_SESSION['wdm_user_custom_data'])) {
            $option = $_SESSION['wdm_user_custom_data'];       
            $new_value = array('wdm_user_custom_data_value' => $option);
        }
        if(empty($option))
            return $cart_item_data;
        else
        {    
            if(empty($cart_item_data))
                return $new_value;
            else
                return array_merge($cart_item_data,$new_value);
        }
        unset($_SESSION['wdm_user_custom_data']); 
        //Unset our custom session variable, as it is no longer needed.
    }
}

第3步:从WooCommerce会话中提取自定义数据并将其插入购物车对象

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

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会话添加到购物车后的样子。 我的 - 车页

答案 3 :(得分:0)

我是新手,英语也不好,因此答案可能有点令人困惑。

感谢vlad274的建议。

我的方法:

与Daniel Salcedo一样,我也尝试通过编辑woocommerce_sessions来更改元数据,但是存在问题。将商品添加到购物车时,woocommerce将通过md5(product_id + ... +元数据)为其创建一个唯一的cart_item_key,然后查找该cart_item_key是否已存在(如果可用),则该商品将进行数量更新,否则将进行更新。创建一个新项目。

这意味着,如果将帽子产品的元值从蓝色更改为红色,然后添加带有蓝色的帽子产品,不会创建新的蓝色帽子,它只会增加红色帽子的数量,如果要正确更新购物车,则需要更改cart_item_key。< / p>

更改cart_item_key的风险很大,相反,我们只需删除并重新添加产品即可。像这样

// 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后提交购物车表单而不是页面刷新,则在woocommerce update_cart时,set_quantity方法可能会覆盖项目数量。在这种情况下,您只需要返回new_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
    ...
}

AJAX:

$('.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
        }
    })
})

PHP:

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