防止来宾用户在 WooCommerce 中多次订购产品
Prevent guest users from ordering a product multiple times in WooCommerce
我想做的是利用我的子主题 functions.php 中的代码来阻止客人再次订购特定产品。如果他们的购物车中有特定的 product_id(他们之前订购过),他们将被重定向到特定的 url 而不是完成订单。
我们的网站使用 phone 号码(第一位不带零)作为用户名,为了使订购过程尽可能简单,用户在结帐时无需登录。
我们正在尝试找到一种方法 检查 billing_phone 是否是现有用户名,然后检查 user_id 是否购买了特定产品(s) 之前。如果他们这样做了,尝试阻止这种情况,并在他们点击结帐页面上的下订单按钮后将他们重定向到特定的 url、。
灵感来自:
我们试图构建这段代码,但没有成功。订单未被阻止重复:
function action_woocommerce_check_cart_items() {
// Retrieve the current user from billing_phone
// get all the order data
$order = new WC_Order($order_id);
//get the user phone from the order
$order_phone = $order->billing_phone;
//phone without zero in first digit
$phone_nozero = substr($order_phone, 1);
//gets user_id using phone number and saves it to $current_user
$current_user = get_user_by('login', $phone_nozero);
// Initialize
$flag = false;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
$product_id = "916";
// Checks if a user (by email or ID or both) has bought an item
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product_id ) ) {
// Flag becomes true
$flag = true;
// Break loop
break;
}
}
// True
if ( $flag ) {
//Here, we likely require a code to prevent the order from being completed.
//redirect to specific url
wp_redirect( 'https://myspecificurl.com' );
}
}
//hook for after clicking place order button. inspired by :
add_action( 'woocommerce_new_order' , 'action_woocommerce_check_cart_items', 1, 1 );
如有任何建议,我们将不胜感激。
您的代码尝试包含多个错误,所以一些评论:
woocommerce_new_order
将在新创建的订单事件上执行,因此 'too late' 您的问题
- 改为使用
woocommerce_check_cart_items
动作挂钩
$order->billing_phone
是因为 WooCommerce 3.0 替换为 $order->get_billing_phone()
但不适用于这种情况。这是因为$order
对象只有在下单后才知道,我们将使用WC()->session->get( 'customer' )
代替
- 您提到用户名是基于 phone 号码,但您的问题是关于“仅供客人使用”。来宾没有用户名
- 在您的代码尝试中,您仅检查 1 个产品 ID (916),而订单通常包含多个不同的产品
wc_customer_bought_product()
功能只适用于有账号的用户。所以我们就要use/write的一个自定义函数,它是基于已有的wc_customer_bought_product()
函数
- 使用
wp_safe_redirect()
与 wp_redirect()
所以你得到:
function has_bought_items_by_phone_number( $phone_number, $product_ids ) {
global $wpdb;
$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-processing' )
AND pm.meta_key = '_billing_phone'
AND pm.meta_value = '$phone_number'
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;
}
function action_woocommerce_check_cart_items() {
// Only for guests
if ( is_user_logged_in() ) return;
// Get session
$customer = WC()->session->get( 'customer' );
// NOT empty phone field
if ( ! empty( $customer['phone'] ) ) {
// Sanatize
$phone_number = wc_sanitize_phone_number( $customer['phone'] );
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID and push to array
$product_ids[] = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
}
// NOT empty
if ( ! empty ( $product_ids ) ) {
// Call function, and if true
if ( has_bought_items_by_phone_number( $phone_number, $product_ids ) ) {
// Performs a safe redirect
wp_safe_redirect( 'https://yoursite.com/custom-url-1' );
exit;
}
}
}
}
}
add_action( 'woocommerce_check_cart_items' , 'action_woocommerce_check_cart_items', 10 );
注意 1) 仅在他们点击结帐页面上的下订单按钮后应用此操作(重定向)需要使用woocommerce_checkout_process
挂钩与 woocommerce_check_cart_items
挂钩相反。
因为根据我目前的回答,这只会在某些情况下发生,如果 phone 数字(尚)未知。
但是,重定向会显示一条错误消息并且不会被执行。因此,如果您仍然想要这个,您应该通过显示一条消息来替换重定向,其中包含link到第
页
注 2) 我的回答将适用于 所有产品,仅适用于特定产品:
替换:
if ( ! is_null( WC()->cart ) ) {
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID and push to array
$product_ids[] = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
}
有:
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Specific product IDs
$specific_product_ids = array( 30, 823, 53, 57 );
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID
$product_id = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
// Checks if a value exists in an array
if ( in_array( $product_id, $specific_product_ids ) ) {
// Push to array
$product_ids[] = $product_id;
}
}
注3) has_bought_items_by_phone_number()
函数基于答案码
我想做的是利用我的子主题 functions.php 中的代码来阻止客人再次订购特定产品。如果他们的购物车中有特定的 product_id(他们之前订购过),他们将被重定向到特定的 url 而不是完成订单。
我们的网站使用 phone 号码(第一位不带零)作为用户名,为了使订购过程尽可能简单,用户在结帐时无需登录。
我们正在尝试找到一种方法 检查 billing_phone 是否是现有用户名,然后检查 user_id 是否购买了特定产品(s) 之前。如果他们这样做了,尝试阻止这种情况,并在他们点击结帐页面上的下订单按钮后将他们重定向到特定的 url、。
灵感来自:
我们试图构建这段代码,但没有成功。订单未被阻止重复:
function action_woocommerce_check_cart_items() {
// Retrieve the current user from billing_phone
// get all the order data
$order = new WC_Order($order_id);
//get the user phone from the order
$order_phone = $order->billing_phone;
//phone without zero in first digit
$phone_nozero = substr($order_phone, 1);
//gets user_id using phone number and saves it to $current_user
$current_user = get_user_by('login', $phone_nozero);
// Initialize
$flag = false;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
$product_id = "916";
// Checks if a user (by email or ID or both) has bought an item
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product_id ) ) {
// Flag becomes true
$flag = true;
// Break loop
break;
}
}
// True
if ( $flag ) {
//Here, we likely require a code to prevent the order from being completed.
//redirect to specific url
wp_redirect( 'https://myspecificurl.com' );
}
}
//hook for after clicking place order button. inspired by :
add_action( 'woocommerce_new_order' , 'action_woocommerce_check_cart_items', 1, 1 );
如有任何建议,我们将不胜感激。
您的代码尝试包含多个错误,所以一些评论:
woocommerce_new_order
将在新创建的订单事件上执行,因此 'too late' 您的问题- 改为使用
woocommerce_check_cart_items
动作挂钩 $order->billing_phone
是因为 WooCommerce 3.0 替换为$order->get_billing_phone()
但不适用于这种情况。这是因为$order
对象只有在下单后才知道,我们将使用WC()->session->get( 'customer' )
代替- 您提到用户名是基于 phone 号码,但您的问题是关于“仅供客人使用”。来宾没有用户名
- 在您的代码尝试中,您仅检查 1 个产品 ID (916),而订单通常包含多个不同的产品
wc_customer_bought_product()
功能只适用于有账号的用户。所以我们就要use/write的一个自定义函数,它是基于已有的wc_customer_bought_product()
函数- 使用
wp_safe_redirect()
与wp_redirect()
所以你得到:
function has_bought_items_by_phone_number( $phone_number, $product_ids ) {
global $wpdb;
$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-processing' )
AND pm.meta_key = '_billing_phone'
AND pm.meta_value = '$phone_number'
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;
}
function action_woocommerce_check_cart_items() {
// Only for guests
if ( is_user_logged_in() ) return;
// Get session
$customer = WC()->session->get( 'customer' );
// NOT empty phone field
if ( ! empty( $customer['phone'] ) ) {
// Sanatize
$phone_number = wc_sanitize_phone_number( $customer['phone'] );
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID and push to array
$product_ids[] = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
}
// NOT empty
if ( ! empty ( $product_ids ) ) {
// Call function, and if true
if ( has_bought_items_by_phone_number( $phone_number, $product_ids ) ) {
// Performs a safe redirect
wp_safe_redirect( 'https://yoursite.com/custom-url-1' );
exit;
}
}
}
}
}
add_action( 'woocommerce_check_cart_items' , 'action_woocommerce_check_cart_items', 10 );
注意 1) 仅在他们点击结帐页面上的下订单按钮后应用此操作(重定向)需要使用woocommerce_checkout_process
挂钩与 woocommerce_check_cart_items
挂钩相反。
因为根据我目前的回答,这只会在某些情况下发生,如果 phone 数字(尚)未知。
但是,重定向会显示一条错误消息并且不会被执行。因此,如果您仍然想要这个,您应该通过显示一条消息来替换重定向,其中包含link到第
页注 2) 我的回答将适用于 所有产品,仅适用于特定产品:
替换:
if ( ! is_null( WC()->cart ) ) {
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID and push to array
$product_ids[] = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
}
有:
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Specific product IDs
$specific_product_ids = array( 30, 823, 53, 57 );
// Initialize (do not change)
$product_ids = array();
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item ) {
// Get product ID
$product_id = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
// Checks if a value exists in an array
if ( in_array( $product_id, $specific_product_ids ) ) {
// Push to array
$product_ids[] = $product_id;
}
}
注3) has_bought_items_by_phone_number()
函数基于