【问题标题】:Checking if customer has already bought something in WooCommerce检查客户是否已经在 WooCommerce 中购买过东西
【发布时间】:2016-12-16 21:12:52
【问题描述】:

我想创建一个 WooCommerce 插件来为客户(有购买历史)添加一些优惠。

如何查看用户之前购买过的东西?

谢谢。

【问题讨论】:

    标签: php wordpress woocommerce product orders


    【解决方案1】:

    2021 更新 - 处理客人“账单电子邮件” - 改进和安全的 SQL 查询

    这是一个更轻便、更快速的条件函数,如果客户已经购买,它将返回 true。

    它处理来自用户 ID 的注册用户 guest 和来自帐单电子邮件的 guest:

    • 对于注册用户:如果可选参数未设置用户 ID,则将使用当前用户 ID。
    • 对于客人:帐单电子邮件将作为函数中的参数。

    这个更轻巧和改进的函数(部分基于wc_customer_bought_product()函数源代码)将根据订单数返回一个布尔值(O订单为false,至少有订单时为true一个已付款订单)

    function has_bought( $value = 0 ) {
        if ( ! is_user_logged_in() && $value === 0 ) {
            return false;
        }
    
        global $wpdb;
        
        // Based on user ID (registered users)
        if ( is_numeric( $value) ) { 
            $meta_key   = '_customer_user';
            $meta_value = $value == 0 ? (int) get_current_user_id() : (int) $value;
        } 
        // Based on billing email (Guest users)
        else { 
            $meta_key   = '_billing_email';
            $meta_value = sanitize_email( $value );
        }
        
        $paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
    
        $count = $wpdb->get_var( $wpdb->prepare("
            SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts AS p
            INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
            WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )
            AND p.post_type LIKE 'shop_order'
            AND pm.meta_key = '%s'
            AND pm.meta_value = %s
            LIMIT 1
        ", $meta_key, $meta_value ) );
    
        // Return a boolean value based on orders count
        return $count > 0;
    }
    

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

    此代码在 Woocommerce 3+ 上经过测试并且可以工作(它应该也可以在以前的版本上工作)。

    对于多个产品: Check if a user has purchased specific products in WooCommerce


    使用示例1 (登录客户)

    if( has_bought() )
        echo '<p>You have already made a purchase</p>';
    else
        echo '<p>Welcome, for your first purchase you will get a discount of 10%</p>';
    

    使用示例2 (设置用户ID)

    // Define the user ID
    $user_id = 85;
    
    if( has_bought( $user_id ) )
            echo '<p>customer have already made a purchase</p>';
        else
            echo '<p>Customer with 0 purchases</p>';
    

    如果$user_id未定义且当前用户未登录,该函数将返回false

    使用示例 3 - 对于客人 (设置结算电子邮件)

    // Define the billing email (string)
    $email = 'louis.fourteen@gmail.com';
    
    if( has_bought( $email ) )
            echo '<p>customer have already made a purchase</p>';
        else
            echo '<p>Customer with 0 purchases</p>'
    

    该函数的代码部分基于WooCommerce内置函数wc_customer_bought_product()源码。

    【讨论】:

    • 关于如何将其转换为简码以便我可以用它包装内容的想法?
    • 是的,它可以在很短的代码中轻松完成……您需要什么规格? (如果你喜欢/想要你可以为这个有用的答案投票)
    【解决方案2】:

    您可以使用内置的woocommerce订单查询通过电子邮件/电话/等方式查询...

    $args = [
        //'customer_id' => $user_id, // can used for query by users
        'billing_phone'  => $phone, // you can also query by 'billing_email', 'billing_first_name' and etc.
        'status' => ['wc-processing', 'wc-completed'],
        'limit' => -1,
    ];
    
    $query = new WC_Order_Query($args);
    $orders = $query->get_orders();
    
    return count($orders) > 1 ? true : false;
    

    有关 WC_Order_Query 的更多详细信息可在此处找到: https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query

    【讨论】:

      【解决方案3】:

      对于任何在 WC 中编码的人来说,这是一项非常常见的任务。也许管理它的类(并在将来使检查更容易)是一个好主意。尤其是因为 WC_Customer 类有几个方法可用于为此目的返回布尔值。

      https://wp-helpers.com/2021/03/19/woocommerce-a-much-better-way-of-checking-if-an-user-has-purchases/

      【讨论】:

      • 虽然您发送的链接包含有效且相关的信息,但考虑到链接将来可能会断开,它们并不总是回答问题的最佳方式。有趣的是,您描述了建议的解决方案,并在可能的情况下添加相关代码。 meta.stackexchange.com/a/8259/458251
      【解决方案4】:

      具有缓存层的版本(使用临时 API 密钥,为期一周)。未登录的用户返回 false。

      function has_bought() {
      
        if(!is_user_logged_in()) return false;
      
        $transient = 'has_bought_'.get_current_user_id();
        $has_bought = get_transient($transient);
      
        if(!$has_bought) {
      
        // Get all customer orders
        $customer_orders = get_posts( array(
          'numberposts' => 1, // one order is enough
          'meta_key'    => '_customer_user',
          'meta_value'  => get_current_user_id(),
          'post_type'   => 'shop_order', // WC orders post type
          'post_status' => 'wc-completed', // Only orders with "completed" status
          'fields'      => 'ids', // Return Ids "completed"
        ) );
      
          $has_bought = count($customer_orders) > 0 ? true : false;
      
          set_transient($transient, $has_bought, WEEK_IN_SECONDS);
      
        }
      
        // return "true" when customer has already at least one order (false if not)
        return $has_bought;
      }
      

      【讨论】:

        【解决方案5】:

        从@Antonio Novak 的简化版本开始,我对覆盖所有可能表明用户已经购买的订单状态进行了一些改进。

        状态列表

        WooCommerce 提供有关状态的详细文档。看看吧:https://docs.woocommerce.com/document/managing-orders/

        但是,我在这里使用 slugs 转录列表:

        $order_statuses = array(
            'wc-pending'    => _x( 'Pending payment', 'Order status', 'woocommerce' ),
            'wc-processing' => _x( 'Processing', 'Order status', 'woocommerce' ),
            'wc-on-hold'    => _x( 'On hold', 'Order status', 'woocommerce' ),
            'wc-completed'  => _x( 'Completed', 'Order status', 'woocommerce' ),
            'wc-cancelled'  => _x( 'Cancelled', 'Order status', 'woocommerce' ),
            'wc-refunded'   => _x( 'Refunded', 'Order status', 'woocommerce' ),
            'wc-failed'     => _x( 'Failed', 'Order status', 'woocommerce' ),
        );
        

        另外,我决定添加 wc-shipped 状态。当然,是自定义状态,但通常由电子商务使用,对吧?

        我没有问我用户是否已经购买了,假设最大的兴趣可能是提供更多激励来赢得新用户,我冒昧地颠倒了问题和函数的答案。

        当使用提议的函数时,当用户第一次购买时返回 true,当他已经有订单在查询中列出的状态时返回 false。

        此外,我还将用户 id 参数设为可选,因此该函数可以在多种情况下重复使用,而不仅仅是在用户的会话中。

        函数

        function is_the_first_purchase( $user_id = 0) {
          
          if( $user_id == 0 ){
            $user_id = get_current_user_id();
          }
          
          if( ! $user_id ){
            return true;
          }
          
          $customer_orders = get_posts( array(
            'numberposts' => -1,
            'post_type'   => 'shop_order',
            'post_status' => array(
              'wc-completed', 
              'wc-on-hold', 
              'wc-processing', 
              'wc-shipped', 
              'wc-refunded'
            ),
            'meta_query' => array(
              array(
                'key'         => '_customer_user',
                'meta_value'  => $user_id,
              )
            )
          ));
          
          // return "true" when customer 
          // does not have an completed order
        
          return count( $customer_orders ) > 0 ? false : true;
        }
        

        【讨论】:

          【解决方案6】:

          2020 年更新New updated improved, light and faster version HERE that handle also guests from billing email


          是的,可以创建一个条件函数返回true,当客户已经有至少一个订单,状态为完成

          这是这个条件函数的代码:

          function has_bought() {
              // Get all customer orders
              $customer_orders = get_posts( array(
                  'numberposts' => 1, // one order is enough
                  'meta_key'    => '_customer_user',
                  'meta_value'  => get_current_user_id(),
                  'post_type'   => 'shop_order', // WC orders post type
                  'post_status' => 'wc-completed', // Only orders with "completed" status
                  'fields'      => 'ids', // Return Ids "completed"
              ) );
          
              // return "true" when customer has already at least one order (false if not)
             return count($customer_orders) > 0 ? true : false; 
          }
          

          此代码已经过测试并且可以工作。

          此代码位于活动子主题或主题的 function.php 文件中,或位于插件 php 文件中。


          用法(作为条件)

          • 您可以在之前复制到活动子主题或主题的某些 WooCommerce templates 中使用它
          • 在您的主题 php 文件中。
          • 在插件 php 文件中
          • 任何 php 函数或 WordPress/WooCommerce。

          参考文献

          【讨论】:

          • 有什么方法可以同时显示/返回最近一次购买的日期?
          • @RodrigoM 如果客户一次成功购买,则返回 true
          • 这个功能帮助很大。目前我需要检查客户是否已经购买。如果他没有,我想申请折扣,我如何更改购买的当前价值? (确认购买/购物车后会调用此函数)
          • 我们为什么要查询所有的订单,我们不只需要'numberposts' =&gt; 1, 吗?
          • @LoicTheAztec 如何在结账页面使用此功能?
          【解决方案7】:

          如果启用了访客检查,那么此功能可能会有所帮助

          只需发送 $customer_email 作为参数,函数将检查该电子邮件的所有订单并返回真或假。

          function has_bought($customer_email){
          
            $orders = get_posts(array(
            'numberposts' => -1,
            'post_type' => 'shop_order',
            'post_status' => array('wc-processing', 'wc-completed'),
            ));
          
          $email_array = array();
          
          foreach($orders as $order) {
          
          $order_obj = wc_get_order($order->ID);
          $order_obj_data = $order_obj->get_data();
          
          array_push($email_array, $order_obj_data['billing']['email']);
          
          }
          
          
          if (in_array($customer_email, $email_array)) {
          return true;
          } else {
          return false;
          }
          
          }
          

          【讨论】:

            【解决方案8】:

            带有付费状态或仅状态不可知查询的增强版本,还改进了一点代码输入,适用于 PHP 5.4+:

            function has_bought(int $user_id = 0, bool $paid = true ) {
            
                global $wpdb;
            
                $user_id = (empty($user_id)) ? get_current_user_id() : $user_id;
            
                $sql_str = "
                    SELECT p.ID FROM ".$wpdb->posts." AS p
                    INNER JOIN 
                        ".$wpdb->postmeta." AS pm ON p.ID = pm.post_id
                    WHERE 
                        p.post_type LIKE 'shop_order'
                    AND pm.meta_key = '_customer_user'
                    AND pm.meta_value = %d
                ";
            
                $args = [(int) $user_id];
            
                if ($paid === true) {
                    $paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
                    $sql_str .= "AND p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )";
                }
            
                $sql = $wpdb->prepare($sql_str, $args);
            
                return (bool) $wpdb->get_var( $sql );
            }
            

            【讨论】:

              【解决方案9】:

              简化版:

              function has_bought() {
                  // Get all customer orders
                  $customer_orders = get_posts( array(
                      'numberposts' => -1,
                      'meta_key'    => '_customer_user',
                      'meta_value'  => get_current_user_id(),
                      'post_type'   => 'shop_order', // WC orders post type
                      'post_status' => 'wc-completed' // Only orders with status "completed"
                  ) );
                  // return "true" when customer has already one order
                  return count( $customer_orders ) > 0 ? true : false;
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2022-12-21
                • 2021-05-29
                • 2021-01-27
                • 1970-01-01
                • 2019-11-05
                • 1970-01-01
                • 2011-12-23
                • 2012-08-31
                相关资源
                最近更新 更多