【问题标题】:Check if a user has purchased specific products in WooCommerce检查用户是否在 WooCommerce 中购买了特定产品
【发布时间】:2016-12-10 17:27:17
【问题描述】:

我需要检查客户是否早先在 WooCommerce 中购买了特定产品。

情况是这样的:客户不能购买产品“c”、“d”、“e”,除非他们在更早的时间购买了产品“a”或“b”。

如果客户之前购买过产品“a”或“b”,则产品“c”、“d”和“e”的购买按钮被激活并允许他们购买。

如果他们之前没有购买过“a”或“b”,他们将不能购买“c”、“d”、“e”,并且购买按钮会被停用。

我怎样才能做到这一点?

谢谢。

【问题讨论】:

  • 我查看了 wc_customer_bought_product_function,我还在 stackoverflow.com/questions/27306828/… 找到了一个类似的帖子,但我不太确定我将如何进一步推动我的示例工作。
  • 谢谢@LoicTheAztec,我会在今天晚些时候测试它并给你一些反馈。
  • 我有一个新的答案,它具有更轻、更快的功能,可以做同样的事情……如果你能测试它并给我一个反馈。谢谢。

标签: php wordpress woocommerce product orders


【解决方案1】:

处理多个产品 ID 的更轻量级和改进的代码版本 in HERE

更新 (Woocommerce 3+ 的兼容性)

是的,如果当前客户已经购买了特定定义的产品 ID,则可以编写一个返回“true”的条件函数。 此代码位于活动子主题或主题的 function.php 文件中

这里是条件函数:

function has_bought_items() {
    $bought = false;

    // Set HERE ine the array your specific target product IDs
    $prod_arr = array( '21', '67' );

    // 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"
    ) );
    foreach ( $customer_orders as $customer_order ) {
        // Updated compatibility with WooCommerce 3+
        $order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
        $order = wc_get_order( $customer_order );

        // Iterating through each current customer products bought in the order
        foreach ($order->get_items() as $item) {
            // WC 3+ compatibility
            if ( version_compare( WC_VERSION, '3.0', '<' ) ) 
                $product_id = $item['product_id'];
            else
                $product_id = $item->get_product_id();

            // Your condition related to your 2 specific products Ids
            if ( in_array( $product_id, $prod_arr ) ) 
                $bought = true;
        }
    }
    // return "true" if one the specifics products have been bought before by customer
    return $bought;
}

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


用法:
例如,您可以在之前复制到活动子主题或主题的一些 WooCommerce templates 中使用它:

以下是您可以在这些模板中使用的示例(上图)

// Replace the numbers by your special restricted products IDs
$restricted_products = array( '20', '32', '75' );

// compatibility with WC +3
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;

// customer has NOT already bought a specific product for this restricted products
if ( !has_bought_items() && in_array( $product_id, $restricted_products ) ) { 

    // Displaying an INACTIVE add-to-cart button (With a custom text, style and without the link).
    // (AND optionally) an explicit message for example.

// ALL OTHER PRODUCTS OR RESTRICTED PRODUCTS IF COSTUMER HAS ALREADY BOUGHT SPECIAL PRODUCTS
} else { 

    // place for normal Add-To-Cart button code here
}

这里完整的应用示例商店页面上的add-to-cart按钮模板:

<?php
/**
 * Loop Add to Cart
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/loop/add-to-cart.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see         https://docs.woocommerce.com/document/template-structure/
 * @author      WooThemes
 * @package     WooCommerce/Templates
 * @version     2.5.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

global $product;

// Replace the numbers by your special restricted products IDs
$restricted_products = array( '37', '53', '70' );

// compatibility with WC +3
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;

if ( !has_bought_items() && in_array( $product_id, $restricted_products ) ) {

    echo '<a class="button greyed_button">' . __("Disabled", "your_theme_slug") . '</a>';
    echo '<br><span class="greyed_button-message">' . __("Your message goes here…", "your_theme_slug") . '</span>';

} else {

echo apply_filters( 'woocommerce_loop_add_to_cart_link',
    sprintf( '<a rel="nofollow" href="%s" data-quantity="%s" data-product_id="%s" data-product_sku="%s" class="%s">%s</a>',
        esc_url( $product->add_to_cart_url() ),
        esc_attr( isset( $quantity ) ? $quantity : 1 ),
        esc_attr( $product_id ),
        esc_attr( $product->get_sku() ),
        esc_attr( isset( $class ) ? $class : 'button' ),
        esc_html( $product->add_to_cart_text() )
    ),
$product );

}

您将在您的活动子主题或主题的 style.css 文件中使用 greyed_button 类设置非活动按钮的样式。 greyed_button-message 类的消息也是如此。

【讨论】:

【解决方案2】:

2020 年更新: 现在处理来自帐单电子邮件的访客用户。

新版本紧凑、轻巧、速度更快且兼容所有版本的 woocommerce(从 2.4 及更高版本开始)

这是一个新的增强和更轻的条件函数,部分基于内置的 woocommerce 函数wc_customer_bought_product 源代码。

有 2 个可选参数:

  • $user_var 将允许您:
  • 指定定义的用户 ID(当不用于当前登录用户时)
  • 来宾用户的帐单电子邮件
  • $product_ids (array) 将允许指定一个或多个要检查的产品 ID

代码如下:

function has_bought_items( $user_var = 0,  $product_ids = 0 ) {
    global $wpdb;
    
    // Based on user ID (registered users)
    if ( is_numeric( $user_var) ) { 
        $meta_key     = '_customer_user';
        $meta_value   = $user_var == 0 ? (int) get_current_user_id() : (int) $user_var;
    } 
    // Based on billing email (Guest users)
    else { 
        $meta_key     = '_billing_email';
        $meta_value   = sanitize_email( $user_var );
    }
    
    $paid_statuses    = array_map( 'esc_sql', wc_get_is_paid_statuses() );
    $product_ids      = is_array( $product_ids ) ? implode(',', $product_ids) : $product_ids;

    $line_meta_value  = $product_ids !=  ( 0 || '' ) ? 'AND woim.meta_value IN ('.$product_ids.')' : 'AND woim.meta_value != 0';

    // Count the number of products
    $count = $wpdb->get_var( "
        SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts AS p
        INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
        INNER JOIN {$wpdb->prefix}woocommerce_order_items AS woi ON p.ID = woi.order_id
        INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim ON woi.order_item_id = woim.order_item_id
        WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $paid_statuses ) . "' )
        AND pm.meta_key = '$meta_key'
        AND pm.meta_value = '$meta_value'
        AND woim.meta_key IN ( '_product_id', '_variation_id' ) $line_meta_value 
    " );

    // Return true if count is higher than 0 (or false)
    return $count > 0 ? true : false;
}

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

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


使用示例:

示例 1 (登录客户):检测当前用户是否购买了定义的产品之一(产品 Ids 需要是一个数组) em>

// Define the targeted Products IDs
$product_ids = array( 38, 41, 85, 95 );

if( has_bought_items( '', $product_ids ) )
    echo "<p>You have already purchased one of this products</p>";
else
    echo "<p>You have not yet purchased one of this products</p>";

示例 2 (对于定义的 用户 id 检测定义的用户是否购买了定义的产品之一 (产品ids需要在数组中设置)

// Define the user ID
$user_id = 85;

// Define the targeted Products IDs
$product_ids = array( 38, 41, 85, 95 );

if( has_bought_items( $user_id, $product_ids ) )
    echo "<p>This user have already purchased one of this products</p>";
else
    echo "<p>This user have not yet purchased one of this products</p>";

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

示例 3 (针对 guest 用户) 检测 guest 用户 是否从以下网站购买了定义的产品之一他的帐单电子邮件 (需要在数组中设置产品ID)

// Define guest Billing email (string)
$user_email = 'louis.fourteen@gmail.com';

// Define the targeted Products IDs
$product_ids = array( 38, 41, 85, 95 );

if( has_bought_items( $user_email, $product_ids ) )
    echo "<p>This user have already purchased one of this products</p>";
else
    echo "<p>This user have not yet purchased one of this products</p>";

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

示例 4 (已登录客户):检测当前用户是否已经购买

if( has_bought_items() )
    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>';

示例 5 (定义 用户 id - 检测定义的用户是否已经购买

// Define the user ID
$user_id = 85;

if( has_bought_items( $user_id ) )
        echo '<p>customer have already made a purchase</p>';
    else
        echo '<p>Customer with 0 purshases</p>';

现在,如果用户 id 等于 0 且当前用户未登录,此函数将返回 false(如果未为访客用户定义计费电子邮件)。

【讨论】:

  • Loic 我使用这个 sn-p 已经有一段时间了,但它似乎在最新版本的 WooCommerce 中出现故障。结果似乎总是错误的,你知道有什么问题吗?
  • @BoweFrankema 新的更新版本,处理来宾客户并在上一个 WC 4.1+ 版本中工作。
  • 对于那些当前使用此方法的用户,对于已登录的用户,请使用has_bought_items(0, [1, 12, 3] ); 而不是提供空字符串,这将导致 is_numeric() 检查失败。
【解决方案3】:

这种情况下也可以使用内置的woocommerce函数wc_customer_bought_product

查看函数用法here

【讨论】:

    【解决方案4】:

    我会这样做;

    这不会做任何 woocommerce 模板修改,而只会使用过滤器 woocommerce_is_purchasable

    这些都是函数,

    1. 检查当前产品ID是否已经由客户带来,在2.6 +版本中,woocommerce实现了wc_customer_bought_product功能来检查客户是否已经带来了产品,我以前从未使用过它,但基于文档你可以创建一个类似下面的函数来检查一个产品 ID 数组是否已经带入;

      function cmk_check_product_brought( $ids=array() ) {
          if ( ! $ids ) return false;
          foreach ( $ids as $product => $id ) {
              if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $id ) ) {
                  return true;
              }
          }
      }
      

    我之前检查客户是否已经带来了特定产品ID的方法如下,因此您可以使用这些功能中的任何一个,尽管我创建的不是ID数组

    function cmk_product_ordered( $id ) {
        // Get All order of current user
        $orders = get_posts( array(
            'numberposts' => -1,
            'meta_key'    => '_customer_user',
            'meta_value'  => get_current_user_id(),
            'post_type'   => wc_get_order_types( 'view-orders' ),
            'post_status' => array_keys( wc_get_order_statuses() )
        ) );
    
        if ( !$orders ) return false; // return if no order found
    
        $all_ordered_product = array(); // store all products ordered by ID in an array
    
        foreach ( $orders as $order => $data ) { // Loop through each order
            $order_data = new WC_Order( $data->ID ); // create new object for each order
            foreach ( $order_data->get_items() as $key => $item ) {  // loop through each order item
                // store in array with product ID as key and order date a value
                $all_ordered_product[ $item['product_id'] ] = $data->post_date; 
            }
        }
        // check if defined ID is found in array
        if ( isset( $all_ordered_product[ $id ] ) ) return true;
        else return false;
    }
    
    1. 现在我们可以检查产品ID是否已经带了,我们可以简单地在woocommerce_is_purchasable上添加一个过滤器来创建我们自己的条件,下面的这个函数是你想要实现的一个简单的例子,

    刚刚更改了 $required_purchased$conditional_purchase 值。

    function cmk_disable_product_purchase( $purchasable, $product ) {
    
        // array of products required to be purchase first
        $required_purchased = array( 1, 2);
    
        // array of restricted/conditional products to be purchase
        $conditional_purchase = array( 3,4,5);
    
        // Get the ID for the current product
        $product_id = $product->is_type( 'variation' ) ? $product->variation_id : $product->id;
    
        //return default $purchasable if current product ID is not in restricted array
        if ( !in_array($product_id, $conditional_purchase)) return $purchasable;
    
        /**
         ** Check if one required products has been purchase;
         **/
    
        // using cmk_check_product_brought() function, return false if product is not purchase
        if ( ! cmk_check_product_brought( $required_purchased ) ) $purchasable = false;
    
        // using cmk_product_ordered() function, you can use this instead
        /*if ( cmk_product_ordered( 1 )  || cmk_product_ordered( 2 ) ) {
            $purchasable = $purchasable; //return default if one product is purchased
        } else {
            $purchasable = false;
        }*/
    
        // Double-check for variations: if parent is not purchasable, then variation is not
        if ( $purchasable && $product->is_type( 'variation' ) ) {
            $purchasable = $product->parent->is_purchasable();
        }
    
        return $purchasable;
    }
    add_filter( 'woocommerce_variation_is_purchasable', 'cmk_disable_product_purchase', 10, 2 );
    add_filter( 'woocommerce_is_purchasable', 'cmk_disable_product_purchase', 10, 2 );
    

    这应该将产品设置为不可购买(添加到购物车按钮将被自动隐藏)。 现在,如果您想为不可购买的产品添加消息,您可以简单地使用 cmk_disable_product_purchase 的相同条件,添加您的消息并将其挂在 woocommerce_single_product_summary 或您希望它显示的任何位置。

    【讨论】:

      猜你喜欢
      • 2018-03-26
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 2020-11-29
      • 2019-08-12
      • 2017-11-03
      • 1970-01-01
      • 2021-01-27
      相关资源
      最近更新 更多