What I'm trying to do is utilize a code in my child theme's functions.php to block guests from ordering a specific product again. If they had a specific product_id in their cart (that they've ordered before), they would be redirected to a specific url instead of the order being completed.
Our website uses phone number (without a zero in the first digit) as username and to make the order process as simple as possible, the user is not required to login during checkout.
We're trying to find a way to check if the billing_phone is an existing username, then checking if the user_id have bought specific product(s) before. If they did, trying to prevent that and redirect them to specific url, after they click place order button on checkout page.
Inspired by:
We tried to construct this piece of code, but without success. The order was not prevented from repeating:
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 );
Any suggestions would be greatly appreciated.
CodePudding user response:
Your code attempt contains multiple mistakes, so some remarks:
- The
woocommerce_new_order
will be executed on newly created order event, and is therefore 'too late' for your question - Use the
woocommerce_check_cart_items
action hook instead $order->billing_phone
is since WooCommerce 3.0 replaced with$order->get_billing_phone()
but does not apply in this case. This is because the$order
object is only known after the order is placed, we will useWC()->session->get( 'customer' )
instead- You mention that the username is based on a phone number, but your question is about "only for guests". Guests do not have a username
- In your code attempt you only check for 1 product ID (916), while order(s) usually consist of several different products
- The
wc_customer_bought_product()
function only applies to users with an account. So we will have to use/write of a custom function, which is based on the existingwc_customer_bought_product()
function - Use
wp_safe_redirect()
vswp_redirect()
So you get:
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 );
Note 1) to apply this action (the redirect) only after they click place order button on checkout page would require using the woocommerce_checkout_process
hook opposite the woocommerce_check_cart_items
hook.
Because with my current answer, this will only happen in certain cases, if the phone number is not (yet) known.
However, the redirect would then display an error message and not be executed. So if you still want this, you should replace the redirect by displaying a message, which then contains the link to the page
Note 2) my answer will be applied to ALL products, to only apply this to specific products:
Replace:
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'];
}
With:
// 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;
}
}
Note 3) the has_bought_items_by_phone_number()
function is based on Check if a user has purchased specific products in WooCommerce answer code