Woocommerce Minimum Order by User Role - php

Somebody previously asked a question similar to mine, but the solutions offered do not seem to help me.
I am working on a wholesale website. For first time buyers, the minimum order is $500. For returning buyers / reorders there is no minimum. I am assuming I need to make 2 different wholesale user roles - one for first time buyers and the other for returning / reorder buyers. I was thinking Wholesale New and Wholesale Reorder would work. How do I apply this to the functions.php? This is the code I am currently using:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
// Set this variable to specify a minimum order value
$minimum = 500;
if ( WC()->cart->total < $minimum ) {
if( is_cart() ) {
wc_print_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error'
);
} else {
wc_add_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error'
);
}
}
Any help would be greatly appreciated.

You need current_user_can() to test the current user's capability to do something.
Create a Role
First, you would need to create a new role for users who don't have any restrictions. The Members plugin is genius for creating roles and editing their capabilities.
For example, you could create a Returning Wholesaler role.
Define the new Role's capabilities
You should duplicate the "Customer" role's capabilities... so read , edit_posts, and delete_posts.
And then, add a new capability called wholesale_reorder
Modify your conditional logic
Then you can convert your if statement from:
if ( WC()->cart->total < $minimum )
to:
if ( WC()->cart->total < $minimum && ! current_user_can( 'wholesale_reorder' ) )
Simplification in the case of no new roles
If you don't have any existing customers, don't need multiple levels of wholesale, don't have wholesale in conjunction with regular customers, and you don't have a way to register without ordering, then ostensibly you could skip adding new roles and just test current_user_can('customer') as the only people who would be customers would be those who have ordered something already.

Related

Change the Label on the shop page to display stock quantity

Right now, my shop only displays only 2 badges on my shop page. Special Offer and out of stock. I would also want to include stock quantity below 10 and Allow for back order. I have looked at multiple plugins as well as php code, but nothing seems to work. What I want to do is display "Only {QTY} Is Available" is the stock drops below 10 and if it is 0 then "available on back order". Website is built in WooCommerce and WordPress
I would like these messages to replace the special offer badge if these conditions are met. I have attached a screenshot below:-
Any assistance is greatly appriciated
There are in fact two parts to your question: how to change the stock availability text and how to remove the sale badge, when some criteria on the product stock level is met.
Changing the stock availability text should be easily achieved by hooking in the woocommerce_get_availability filter. Get the product stock quantity and amend the text accordingly. E.g.:
add_filter( 'woocommerce_get_availability', 'custom_override_get_availability', 10, 2 );
function custom_override_get_availability( $availability, $_product ) {
$stock_quantity = $_product->get_stock_quantity();
if ( 0 === $stock_quantity ) {
$availability['availability'] = 'Available on backorder';
} elseif ( $stock_quantity < 10 ) {
$availability['availability'] = sprintf( 'Only %s available', $stock_quantity );
} else {
$availability['availability'] = sprintf( '%s left in stock', $stock_quantity );
}
return $availability;
}
As for removing the sale badge, I think the plugin you're using provides templates that can be overridden. Have a look in the Views folder, you should find the sale-flash.php templates. You can then override those templates in your theme and apply a similar logic, as you have access to the product. E.g. this shows the sale badge only when the product is on sale and the stock quantity is greater than or equal to 10:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $post, $product;
?>
<?php if ( $product->is_on_sale() && $product->get_stock_quantity() >= 10 ) : ?>
<?php echo apply_filters( 'woocommerce_sale_flash', '<span class="onsale wdr-onsale">' . esc_html__( 'Sale!', 'woocommerce' ) . '</span>', $post, $product ); ?>
<?php endif;
Although I'm not really sure if you want to remove the sale badge when the product stock quantity is less than 10.

Get order items stock status when order was created in WooCommerce

There is an issue when including "stock status" of the purchased items on the client email.
If the client orders the last unit of an item, even though when he ordered it was clearly instock (available for immediate shipping), then the stock status turns to outofstock/onbackorder and the email that is sent to the client (which I assume is sent/generated a few seconds after the stock value is updated from the clients own order) shows this status updated to outofstock/onbackorder, so after completing the purchase now the client thinks the product is out of stock when in fact it was not.
I'm using this code hooked onto my emails:
$product = $item->get_product();
$stockstatus = get_post_meta( $product->get_id(), '_stock_status', true );
if ($stockstatus == 'instock') { 'Available for immediate shipping'; }
elseif ($stockstatus == 'onbackorder') { 'On Preorder - slow shipping';}
We use Stock status to define shipping time of our products, it's simple, if it's in stock = immediate shipping, if it's outofstock/onbackorder = Preorder ( slow shipping )
Clients can view this information individually for each product on the product page and on the cart, however to make it as clear as possible and also keep a record of the Stock Status of when the order was made (so we know and can show to a client if a product was or not in stock when ordered) we also send this information to the client email. The issue being it displays the stock status at the time the email is sent and not at the time of the order (So if it was the last unit and the product turns to out of stock, then clients get the wrong message)
What would be the correct way to go about this situation and instead of displaying the current stock status, displaying the correct stock status at the time that the order was placed, so that the customers get the correct information?
Thank you in advance for the attention and advice
Edit:
Here you can find the full code on how I apply this upper snippet to my emails,
I apologize I did not share all the code above (the part for editing custom woocommerce email), my intention was to simplify as I felt it would be unrelated/filler/distracting from the main point as there are a few posts already covering how to customize woocommerce emails.
These are I believe the main posts that cover this:
Credits #Loictheaztec & #7uc1f3r
Customize order item meta only for WooCommerce admin email notifications
Display product ACF fields on a specific WooCommerce email
Here is the full code I am using :
// Setting the "sent_to_admin" as a global variable
function email_order_id_as_a_global($order, $sent_to_admin, $plain_text, $email) {
$GLOBALS['email_data'] = array(
'sent_to_admin' => $sent_to_admin, // <== HERE we set "$sent_to_admin" value
'email_id' => $email->id, // The email ID (to target specific email notification)
);
}
add_action('woocommerce_email_before_order_table', 'email_order_id_as_a_global', 1, 4);
function custom_order_item_name( $item_name, $item ) {
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
// Getting the custom 'email_data' global variable
$refNameGlobalsVar = $GLOBALS;
$email_data = $refNameGlobalsVar['email_data'];
// Only for new order
if( is_array( $email_data ) && $email_data['email_id'] == 'new_order' ) {
// Get the WC_Product object (from order item)
$product = $item->get_product();
$product = $item->get_product();
$stockstatus = get_post_meta( $product->get_id(), '_stock_status', true );
if ($stockstatus == 'instock') { 'Available for immediate shipping'; }
elseif ($stockstatus == 'onbackorder') { 'On Preorder - slow shipping';}
}
}
}
return $item_name;
}
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 ); ```
You can use the following that will save the product stock status as custom order item meta data when customer place an order (so you will always get the stock status when the order was placed):
add_action('woocommerce_checkout_create_order_line_item', 'save_stock_status_order_item_meta', 10, 4 );
function save_stock_status_order_item_meta( $item, $cart_item_key, $values, $order ) {
$item->update_meta_data( '_stock_status', $values['data']->get_stock_status() );
}
Code goes in functions.php file of the active child theme (or active theme).
Then you will replace your "code hooked onto your emails" by this one:
$stock_status = $item->get_meta('_stock_status');
if ( 'instock' === $stock_status ) {
echo __('Available for immediate shipping');
} elseif ( 'onbackorder' === $stock_status ) {
echo __('On Preorder - slow shipping');
}
It should work.

Woocommerce set minimum order for a specific user role

I have a php code that sets a 100 minimum order site wide, that works good.
I want to set a different minimum order of 250 for a specific role 'company' using the same code or by cloning it and wrapping it in an if() statement, only I have no idea how to write it. Would appreciate any kind of help.
This it the currant code (don't mind the Hebrew text, its just the error messages, when the condition is not met):
// Set a minimum dollar amount per order
add_action( 'woocommerce_check_cart_items', 'spyr_set_min_total' );
function spyr_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Set minimum cart total
$minimum_cart_total = 100;
// Total we are going to be using for the Math
// This is before taxes and shipping charges
$total = WC()->cart->subtotal;
// Compare values and add an error is Cart's total
// happens to be less than the minimum required before checking out.
// Will display a message along the lines of
// A Minimum of 10 USD is required before checking out. (Cont. below)
// Current cart total: 6 USD
if( $total <= $minimum_cart_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>לקוח יקר, יש צורך במינימום הזמנה
של %s %s₪ על מנת לבצע רכישה באתר.</strong>'
.'<br />סכום הביניים בעגלה הינו: %s %s₪',
$minimum_cart_total,
get_option( 'woocommerce_currency_symbol'),
$total,
get_option( 'woocommerce_currency_symbol') ),
'error' );
}
}
}
Thanks!
Try the following using current_user_can(), so in your code:
// Set a minimum amount per order (and user role)
add_action( 'woocommerce_check_cart_items', 'set_min_total_per_user_role' );
function set_min_total_per_user_role() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
// Set minimum cart total
$minimum_cart_total = current_user_can('company') ? 250 : 100;
// Total (before taxes and shipping charges)
$total = WC()->cart->subtotal;
// Add an error notice is cart total is less than the minimum required
if( $total <= $minimum_cart_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>Dear customer, minimum order of %s is required to make a purchase on your site.</strong> <br>
Your actual cart amount is: %s',
wc_price($minimum_cart_total),
wc_price($total)
), 'error' );
}
}
}
Code goes on function.php file of your active child theme (or active theme). It should works.
To format prices for display you can use the dedicated wc_price() formatting function.
Related: Apply a discount for a specific user role in Woocommerce
First you have to retrieve the roles of the current user.
$roles = is_user_logged_in() ? (array) wp_get_current_user()->roles : [];
Now you want to check if the role company is in the user's roles to determine the minimum.
$minimum_cart_total = in_array('company', $roles) ? 250 : 100;

woocommerce - string query for all coupons starting with 'nm'

Question: how to call on all coupons starting with 'nm' that exempt the minimum cart purchase requirement.
I added this code to my functions.php file in wordpress to make it so that a customer has to have a minimum purchase of $15 in their cart before they can complete their purchase.
// SET CART TO MINIMUM ORDER OF 15
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
// Set this variable to specify a minimum order value
$minimum = 15;
// No minimum purchase if a specific coupon code is used
if ( WC()->cart->has_discount( 'nm' ) ) {
return;
}
if ( WC()->cart->total < $minimum ) {
if( is_cart() ) {
wc_print_notice(
sprintf( 'You must have an order with a minimum of %s to place
your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error'
);
} else {
wc_add_notice(
sprintf( 'You must have an order with a minimum of %s to place
your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error'
);
}
}
}
However, when I have certain coupon codes for free shipping and/or free product, I don't want the minimum requirement. I added the following in the above code.
// No minimum purchase if a specific coupon code is used
if ( WC()->cart->has_discount( 'nm' ) ) {
return;
}
This works fine if I'm using a coupon called 'nm', but I will have various coupons and I would like it to utilize any coupons that start with 'nm'. How do I do that?
Thanks for your help!

Woocommerce: How to Add extra fee for First Order

I am trying to add Extra Fee in the total of cart/order amount only if this is first order of Customer.
I searched a lot online but I still did not find any specific solution yet.
Please someone suggest/guide the best solution to perferm this.
Thanks
You use the cart class' add_fee() method to add a fee. There's no built-in way to know how many orders a customer has made, so we can try to track that via a user meta field called _number_order.
function so_27969258_add_cart_fee() {
$orders = intval( get_user_meta( get_current_user_id(), '_number_orders', true ) );
if( $orders < 1 ){
WC()->cart->add_fee( __( 'First time fee', 'your-plugin'), 100 );
}
}
add_action( 'woocommerce_before_calculate_totals', 'so_27969258_add_cart_fee' );
If we don't actually update the _number_orders key, then it will always be null/empty/zero and the user will always be charged the first time fee. So we can try to update that key when the user completes payment.
function so_27969258_track_orders_per_customer(){
$orders = intval( get_user_meta( get_current_user_id(), '_number_orders', true ) );
$orders = $orders + 1;
update_user_meta( get_current_user_id(), '_number_orders', $orders );
}
add_action( 'woocommerce_payment_complete', 'so_27969258_track_orders_per_customer' );
This is totally untested, so use at your own risk. Also, you might want to look into changing the number of orders total in case of refunds/cancellations, etc, but this seems like the general gist.

Categories