I am trying to show a custom message to new all customer (not returning customer) in Thankyou page and I am using "Checking if customer has already bought something in WooCommerce" answer code.
The issue is that can't detect if a customer has bought before. For example if I use the current code in thank You page the new customer become older customer.
SO my question is: How can I check if a customer bought earlier any product not in the current order?
Here is my code attempt, that doesn't work as it should:
function has_bought_before( $user_id = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 ? get_current_user_id() : $user_id;
$paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$results = $wpdb->get_col( "
SELECT 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 = '_customer_user'
AND pm.meta_value = $customer_id
" );
// Count number of orders and return a boolean value depending if higher than 0
return count( $results ) > 0 ? true : false;
}
add_filter('woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 10, 2 );
function woo_change_order_received_text( $str, $order ) {
if( has_bought_before() ){
$new_str = $str . ' Welcome Back Again.';
}else{
$new_str = $str . ' Welcome To our site You will get 10% discount on your next order.';
}
return $new_str;
}
On thankyou page you are targeting the next paid order, so you need to make a little change in the conditional function has_bought_before(), at the end, replacing the line:
return count( $results ) > 0 ? true : false;
by:
return count( $results ) > 1 ? true : false;
It should be working as you expect now.
May be rename this conditional function thankyou_has_bought_before().
Related
I am setting up a wordpress/woocommerce website and would like users to only purchase a certain number of items just once per 30 days due to the price of the items but in a certain catergory which is 'microwaves', I have found this code on here and it works really really well but for ALL products I really just want ot to work for 'microwaves' catergory but keep all the other functions.
`
// Utility conditional function (Check if user has purchased in the passed week)
function has_week_purshases( $user_id = 0 ){
global $wpdb;
$customer_id = $user_id > 0 ? $user_id : get_current_user_id();
$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
WHERE p.post_type LIKE 'shop_order'
AND pm.meta_key LIKE '_customer_user'
AND pm.meta_value = $customer_id
AND UNIX_TIMESTAMP(p.post_date) >= (UNIX_TIMESTAMP(NOW()) - (86400 * 30))
" );
return $count > 0 ? true : false;
}
// Cart and checkout validation
add_action( 'woocommerce_check_cart_items', 'conditionally_allowing_checkout' );
add_action( 'woocommerce_checkout_process', 'conditionally_allowing_checkout' );
function conditionally_allowing_checkout() {
if ( is_user_logged_in() && has_week_purshases() ) {
// Display an error notice when customer is not allowed yet
wc_add_notice( __("You are not allowed yet to make purchases"), 'error' );
}
}
`
There is a custom post named 'project' and has acf fields.
The tile of the each post is user name.
user name is from logged in users' email id.
Eg, post title is jeff (jeff#gmail.com).
When a user Jeff purchased a product, I need to automatically add ‘50’ in the ACF field ‘field_690d1eis5xx89’ of the Jeff post.
The code to check whether a user purchased a product or not, works well:
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 ? true : false;
}
This code doesn't update 50 to the acf field of the logged in user's post after the user purchased a product.
I tried both title and post_title but it still doesn't update.
I'm not sure but, maybe due to the $post->ID?
if( has_bought() ){
$current_user = wp_get_current_user();
$current_user_id = $current_user->display_name;
// query to get a post with the user
$args = array(
'post_type' => 'project',
'posts_per_page' => -1,
'title' =>$current_user_id
); // end $args
$query = new WP_Query($args);
// if posts are returned, update field
if ($query->have_posts()) {
global $post;
update_field('field_690d1eis5xx89', '50', $post->ID);
} else {
return;
}
} // end if have_posts
I’m a beginner, would you please help me?
Thank you
As per the documentation the update_field function accepts three parameter i.e. $selector $value and $post_id but it looks like in you code you are using $current_user_id which I think might not work.
Try to add $post_id in place of $current_user_id
Check: https://www.advancedcustomfields.com/resources/update_field/
This code will check if the customer is logged in, if he/she purchased the product and if those statements are true, it will display a message.
I would like to include one more check before the message is shown and that is if the customer already left a review/ wrote a review for the product and if so, do not show the message.
In other words, if the customer did not write a review for the product, show message. If customer left a review, do not show message.
Here is the code:
add_action( 'woocommerce_before_single_product_summary', 'woo_review_discount_message');
function woo_review_discount_message() {
if ( is_user_logged_in() ) {
global $product;
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->get_id() && $order->status->complete ) ) echo '<div class="user-bought"><span style="color:#CA364D;font-weight:bold;font-size:18px;"><i class="wishlist-icon icon-heart-o"></i></span> Hi ' . $current_user->first_name . '! Please write a review below.</a></div>';
}
}
Any help on this is very much appreciated.
To check if a customer has posted a review on the current product, you will use this custom conditional function (using a very light SQL query):
// Utility function to check if a customer has posted a review in a product
function has_reviewed_product( $product_id ) {
global $wpdb;
$user = wp_get_current_user();
if( $user->ID == 0 )
return false;
// Count the number of products
$count = $wpdb->get_var( "
SELECT COUNT(comment_ID) FROM {$wpdb->prefix}comments
WHERE comment_post_ID = $product_id
AND comment_author_email = '{$user->user_email}'
" );
return $count > 0 ? true : false;
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
So in your code (from this answer) you will use it as following:
// Utility function to check if a customer has bought a product (Order with "completed" status only)
function customer_has_bought_product( $product_id, $user_id = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 || $user_id == '' ? get_current_user_id() : $user_id;
$status = 'wc-completed';
if( ! $customer_id )
return false;
// Count the number of products
$count = $wpdb->get_var( "
SELECT COUNT(woim.meta_value) 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 = '$status'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = $customer_id
AND woim.meta_key IN ( '_product_id', '_variation_id' )
AND woim.meta_value = $product_id
" );
// Return a boolean value if count is higher than 0
return $count > 0 ? true : false;
}
add_action( 'woocommerce_before_single_product_summary', 'woo_review_discount_message');
function woo_review_discount_message() {
global $product;
if ( customer_has_bought_product( $product->get_id() ) && ! $product->is_type('variable') && ! has_reviewed_product( $product->get_id() ) ) {
$user = wp_get_current_user();
echo '<div class="user-bought"><span style="color:#CA364D;font-weight:bold;font-size:18px;"><i class="wishlist-icon icon-heart-o"></i></span> Hi ' . $user->first_name . '! Please write a review below.</a></div>';
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
Related answer: Display a custom text if user has already bought the current product In Woocommerce
In woocommerce I use wc_customer_bought_product() function to display a custom text message in single product pages when customer has already bought the current product. but I would like to check that the product(s) bought are on orders with "completed" status.
The message is not supposed to be shown unless the following criteria is met:
user is logged in
user has purchased the product
At least one placed order for the current product is set to complete (what I cannot figure out how to get done).
Here is my code:
add_action( 'woocommerce_before_single_product_summary', 'woo_review_discount_message');
function woo_review_discount_message() {
if ( is_user_logged_in() ) {
global $product;
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->get_id() && $order->status->complete ) )
echo '<div class="user-bought"><span style="color:#CA364D;font-weight:bold;font-size:18px;"><i class="wishlist-icon icon-heart-o"></i></span> Hi ' . $current_user->first_name . '! Please write a review below.</a></div>';
}
}
I tried adding && $order->status->complete but that did not work.
If you want to target only Orders with a complete status, you can use the following custom conditional function based on wc_customer_bought_product() source code:
// Utility function to check if a customer has bought a product (Order with "completed" status only)
function customer_has_bought_product( $product_id, $user_id = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 || $user_id == '' ? get_current_user_id() : $user_id;
$status = 'wc-completed';
if( ! $customer_id )
return false;
// Count the number of products
$count = $wpdb->get_var( "
SELECT COUNT(woim.meta_value) 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 = '$status'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = $customer_id
AND woim.meta_key IN ('_product_id','_variation_id')
AND woim.meta_value = $product_id
" );
// Return a boolean value if count is higher than 0
return $count > 0 ? true : false;
}
add_action( 'woocommerce_before_single_product_summary', 'woo_review_discount_message');
function woo_review_discount_message() {
global $product;
if ( customer_has_bought_product( $product->get_id() ) && ! $product->is_type('variable') ) {
$user = wp_get_current_user();
echo '<div class="user-bought"><span style="color:#CA364D;font-weight:bold;font-size:18px;"><i class="wishlist-icon icon-heart-o"></i></span> Hi ' . $user->first_name . '! Please write a review below.</a></div>';
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
If customer is not logged in nothing will be displayed.
Like Woocommerce function wc_customer_bought_product(), this will not work on variable products single pages.
I am new to WooCommerce and wanted to check if a user has purchased a specific product (product id # 514) within the past 60 days. This is a product I let people purchase monthly, so it will reoccur a lot. I wanted to just see if they purchased a recent one (that I consider active)
The way I was thinking of doing it now was:
Get all orders from a user
For each order, check if it occurred in the past 60 days
and and get all products for this order
For each product, see if the id is x
While I'm sure this will work, I have a funny feeling there is a really concise get_posts(apply_filters( query that will save me some looping time.
Would anyone be wiling to share a few ideas or a solution?
Thanks!
Here is a conditional function partially based on the built-in woocommerce function wc_customer_bought_product source code query:
There is an 3 optional argument $user_id, $product_ids and $days:
$user_id will allow you to specify a defined user ID (when is not used for current logged in user);
$product_ids (string or an array) will allow to specify defined product Ids to check
$dayswill allow you to specify the number of days to search for (or the period if you prefer)…
The code function:
function has_bought_multi( $user_id = 0, $product_ids = 0, $days = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 || $user_id == '' ? get_current_user_id() : $user_id;
$statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$date = date('Y-m-d H:i:s', strtotime("-$days day") );
if ( is_array( $product_ids ) )
$product_ids = implode(',', $product_ids);
if ( $product_ids != ( 0 || '' ) )
$query_line = "AND woim.meta_value IN ($product_ids)";
else
$query_line = "AND woim.meta_value != 0";
// Count the number of products
$product_count_query = $wpdb->get_col( "
SELECT COUNT(woim.meta_value) 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-", $statuses ) . "' )
AND p.post_date > '$date'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = $customer_id
AND woim.meta_key IN ( '_product_id', '_variation_id' )
$query_line
" );
// Set the count in a string
$count = reset($product_count_query);
// Return a boolean value if count is higher than 0
return $count > 0 ? true : false;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works.
Similar answer: Check if a customer has purchased a specific products in WooCommerce
USAGE EXAMPLE (Customer is logged in):
Detecting if current user has bought your product id # 514 in past 60 days:
if( has_bought_multi( '', 514, 60 ) ){
echo "<p>Customer has bought product id # 514 in past 60 days</p>";
// do something
} else {
echo "<p>Customer <strong>HAS NOT</strong> bought product id # 514 in past 60 days</p>";
// do something else
}