WooCommerce

一次添加多个产品到WooCommerce购物车

WooCommerce默认无法一次添加多个产品到购物车,这需要写程序或装插件实现。插件有Multiple Products to Cart等。本文介绍代码的方法,去除复杂的修饰,只看原理。

一次添加多个产品就是把添加一个产品的过程重复多次

WooCommerce内置的添加购物车的函数如下所示,我们要做的就是把这个函数调用好几遍,直到把产品加完为止。

WC()->cart->add_to_cart( $product_id = 0, $quantity = 1, $variation_id = 0, $variation = array(), $cart_item_data = array() );

添加一个产品的过程并不简单,要从头到脚的验证这个产品,比如库存还够不够,产品有没有特殊售卖规则,是什么类型的产品、是否处于可销售状态。通过了复杂的检查后,就会为产品生成一个$cart_item_key,并将这个key添加到购物车里,简单描述就是下面这样:

// array里存放该产品的所有信息
WC()->cart->cart_contents[$cart_item_key] = array(...)

这还没完,产品加进去了还要算一下总价,比如运费、税费、额外费用等等,这里会有个问题,我们最后讲。

加购物车的过程很复杂,但你也只能耐着性子一个一个的加,因为woocommerce有很多产品规则,不可能让你多线程去操作购物车,万一产生时间竞争问题,最后结果是啥就不可控了。

下面是一次添加多个产品的函数:

function add_multiple_products_to_cart( $products ){

  if( is_array($products) && sizeof($products) ){

    // 在全部产品添加完之前不要计算总价(包括产品总价、运费、额外费用、税费等)
    remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );

    foreach( $products as $product_to_add ){

      if ( ! isset( $product_to_add['product_id'] ) ) {
        continue;
      }

      // 获取产品ID、数量等信息
      $product_id        = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_to_add['product_id'] ) );
      $product           = wc_get_product( $product_id );
      $quantity          = empty( $product_to_add['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $product_to_add['quantity'] ) );
      $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
      $product_status    = get_post_status( $product_id );
      $variation_id      = 0;
      $variation         = array();

      // 如果是variation,需要获取他的父级产品信息
      if ( $product && 'variation' === $product->get_type() ) {
        $variation_id = $product_id;
        $product_id   = $product->get_parent_id();
        $variation    = $product->get_variation_attributes();
      }

      // 调用woocommerce的内置函数将产品添加到购物车里
      $cart_item_key =  WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation);

      // 简单先试一下结果,如果用在ajax里,应该用wp_json_send()函数返回结果。
      $added_product_id = $variation_id ? $variation_id : $product_id;

      if ( $passed_validation && false !== $cart_item_key && 'publish' === $product_status ) {

        wc_add_notice( '成功添加了产品 - ' .$added_product_id );

      } else {

        wc_add_notice( '产品添加失败 - ' . $added_product_id, 'error' );
      }
    }

    // 现在可以计算总价了
    WC()->cart->calculate_totals();
  }
}

简单测试的话,找个测试站点,在主题的functions.php里写点代码就行,每次刷新页面都会执行。如果要加一个variation产品,则product_id应填写variation_id

add_action( 'template_redirect', function(){
  $products = array(
    array(
      'product_id' => 801,
      'quantity' => 10,
    ),
    array(
      'product_id' => 802,
      'quantity' => 10,
    )
  );
  add_multiple_products_to_cart($products);
});

计算总价会影响加购物的速度

每加一个产品都会计算总价,这对原始逻辑不是问题。但假设我们做一个可以一次添加几十个产品的界面,如果加一个产品要话1s,那加20个就是20s的时间,有点恐怖。

有的网站会出现添加购物车极慢的情况,可能是数据量太大,用了太多的variations、或者服务器性能不好,但不要忽略这个计算总价的问题。

什么情况下计算总价会影响加购物车的速度呢?运费和税费有时会很复杂,可能要从第三方网站直接查询结果。添加购物车时缓存是无效的,那么去其它站点查询这个速度就不能忽略了,毕竟访问网站再快也会花掉几百毫秒,一次添加多个产品时这个时间会很影响速度。

所以代码中通过remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );禁止计算总价,待产品全部加完了再计算,这样不管加多少产品,都只会计算一次总价。

2条评论

  1. 不知道是不是最近WooCommerce的更新还是一直都有,我发现
    WC()->cart->add_to_cart() 和 WC()->cart->remove_cart_item() 以及WC()->cart->set_quantity() 这些执行完毕后
    即使不调用方法
    WC()->cart->calculate_totals()
    重新查询总价依旧会刷新的
    但是
    WC()->cart->remove_coupons()和WC()->cart->apply_coupons() 这俩运行后还是需要calculate_totals,要不然总价不会变

    1. 你说的没错,更改购物车的产品、产品数量就会触发价格计算,这个一直都有。但有些带优惠的产品,通过程序加到购物车里,mini cart里的价格会不带优惠,需要调用calculate_totals。

评论已关闭。