Apply a coupon programmatically in Woocommerce
First, create a discount coupon (via http://docs.woothemes.com/document/create-a-coupon-programatically/):
$coupon_code = 'UNIQUECODE'; // Code - perhaps generate this from the user ID + the order ID
$amount = '10'; // Amount
$discount_type = 'percent'; // Type: fixed_cart, percent, fixed_product, percent_product
$coupon = array(
'post_title' => $coupon_code,
'post_content' => '',
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'shop_coupon'
);
$new_coupon_id = wp_insert_post( $coupon );
// Add meta
update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
update_post_meta( $new_coupon_id, 'individual_use', 'no' );
update_post_meta( $new_coupon_id, 'product_ids', '' );
update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
update_post_meta( $new_coupon_id, 'usage_limit', '1' );
update_post_meta( $new_coupon_id, 'expiry_date', '' );
update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
Then apply that coupon to your order:
if (!$woocommerce->cart->add_discount( sanitize_text_field( $coupon_code )))
$woocommerce->show_messages();
That last function returns a BOOL value: TRUE if the discount was successful, FALSE if it fails for any one of a variety of reasons.
Programmatically apply a coupon in WooCommerce 3.0+ for first order made by a customer
The code you are using no longer works in current WooCommere versions because it contains outdated code, shortcomings and some superfluous steps:
- It is not necessary to use
get_posts()
with multiple arguments, usewc_get_customer_order_count()
instead $tmp_order->ID
changed to$tmp_order->get_id()
since WooCommerce 3- Your code does not take guest users into account, so they can manually apply the coupon
- The coupon is not automatically awarded, your code assumes that the customers have apply this coupon
- The
woocommerce_after_checkout_validation
hook contains 2 parameters - You don't need to return true\false as it's an action hook not a filter.
This updated version takes into account:
- If the coupon been applied, but the customer is NOT logged in, coupon will be removed
- If the coupon been applied, the customer is logged in, but NOT the first order, the coupon will be removed
- If the coupon been applied, the customer is logged in and it is the first order, the coupon remains
- If the coupon NOT been applied, the customer is logged in and it is the first order, the coupon is applied
So you get:
function action_woocommerce_after_checkout_validation( $data, $error ) {
// Change the name to your coupon
$new_cust_coupon_code = 'coupon1';
// Initialize
$coupon_been_applied = false;
$remove_coupon = false;
// Get applied coupons
$applied_coupons = WC()->cart->get_applied_coupons();
// Has coupon already been applied by the customer
if ( in_array( $new_cust_coupon_code, $applied_coupons ) ) {
$coupon_been_applied = true;
// Coupon has been applied, but customer is a guest user
if ( ! is_user_logged_in() ) {
$remove_coupon = true;
}
}
// Customer is logged in
if ( is_user_logged_in() ) {
// Check if the customer has bought before
$has_bought_before = wc_get_customer_order_count( get_current_user_id() ) >= 1 ? true : false;
// Coupon been applied, but customer has bought before
if ( $coupon_been_applied && $has_bought_before ) {
$remove_coupon = true;
// NOT been applied AND NOT has bought before
} elseif ( ! $coupon_been_applied && ! $has_bought_before ) {
// Apply coupon
WC()->cart->apply_coupon( $new_cust_coupon_code );
}
}
// When true
if ( $remove_coupon ) {
// Remove coupon
WC()->cart->remove_coupon( $new_cust_coupon_code );
// Show message
$error->add( 'validation', sprintf( __( 'Coupon code: "%s" is only applicable for logged in new customers. So the coupon has been removed', 'woocommerce' ), $new_cust_coupon_code ) );
}
}
add_action( 'woocommerce_after_checkout_validation', 'action_woocommerce_after_checkout_validation', 10, 2 );
Applying coupon to WooCommerce order programmatically
Here you can add the coupon by this way please change the content according to your need
add_action( 'woocommerce_before_cart', 'apply_coupons' );
function apply_coupons() {
$coupon_code = 'freeweek';
if ( WC()->cart->has_discount( $coupon_code ) ) return;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// this is your product ID
$autocoupon = array( 745 );
if( in_array( $cart_item['product_id'], $autocoupon ) ) {
WC()->cart->add_discount( $coupon_code );
wc_print_notices();
}
}
}
Create a coupon programmatically since WooCommerce 3+
Since WooCommerce 3, your code is a bit outdated as for example apply_before_tax
is not used anymore. You should better use all available WC_Coupon
setter methods, for coupon creation.
In the code below I just use the necessary setter methods (related to your code):
// Get an empty instance of the WC_Coupon Object
$coupon = new WC_Coupon();
// Set the necessary coupon data (since WC 3+)
$coupon->set_code( $coupon_code ); // (string)
// $coupon->set_description( $description ); // (string)
$coupon->set_discount_type( $discount_type ); // (string)
$coupon->set_amount( $coupon_amount ); // (float)
// $coupon->set_date_expires( $date_expires ); // (string|integer|null)
// $coupon->set_date_created( $date_created ); // (string|integer|null)
// $coupon->set_date_modified( $date_created ); // (string|integer|null)
// $coupon->set_usage_count( $usage_count ); // (integer)
$coupon->set_individual_use( true ); // (boolean)
// $coupon->set_product_ids( $product_ids ); // (array)
// $coupon->set_excluded_product_ids( $excl_product_ids ); // (array)
$coupon->set_usage_limit( 0 ); // (integer)
// $coupon->set_usage_limit_per_user( $usage_limit_per_user ); // (integer)
// $coupon->set_limit_usage_to_x_items( $limit_usage_to_x_items ); // (integer|null)
// $coupon->set_free_shipping( $free_shipping ); // (boolean) | default: false
// $coupon->set_product_categories( $product_categories ); // (array)
// $coupon->set_excluded_product_categories( $excl_product_categories ); // (array)
// $coupon->set_exclude_sale_items( $excl_sale_items ); // (boolean)
// $coupon->set_minimum_amount( $minimum_amount ); // (float)
// $coupon->set_maximum_amount( $maximum_amount ); // (float)
// $coupon->set_email_restrictions( $email_restrictions ); // (array)
// $coupon->set_used_by( $used_by ); // (array)
// $coupon->set_virtual( $is_virtual ); // (array)
// Create, publish and save coupon (data)
$coupon->save();
Now to update coupons you can use the following hooked function with any setter method like:
add_action( 'woocommerce_coupon_options_save', 'action_coupon_options_save', 10, 2 );
function action_coupon_options_save( $post_id, $coupon ) {
$coupon->set_usage_limit( 0 );
$coupon->save();
}
Code goes in functions.php file of the active child theme (or active theme).
Applying programmatically a coupon to an Order in WooCommerce3
OK, so I played about a little longer and it looks like in V3 things are a little more manual.
Adding a WC_Order_Item_Coupon
item to a woo order does simply that. It adds the coupon object to the order object. No calculations are made and the product line items remain unchanged. You have to iterate over the product items manually and apply the coupon yourself by calculating the line item totals and subtotals. calculate_totals()
then does as expected.
// Create the coupon
global $woocommerce;
$coupon = new WC_Coupon($coupon_code);
// Get the coupon discount amount (My coupon is a fixed value off)
$discount_total = $coupon->get_amount();
// Loop through products and apply the coupon discount
foreach($order->get_items() as $order_item){
$product_id = $order_item->get_product_id();
if($this->coupon_applies_to_product($coupon, $product_id)){
$total = $order_item->get_total();
$order_item->set_subtotal($total);
$order_item->set_total($total - $discount_total);
$order_item->save();
}
}
$order->save();
I wrote a helper function to make sure the coupon applies to the product in question coupon_applies_to_product()
. Strictly not needed given I'm creating the order entirely in code.. but I use it it other places so added it.
// Add the coupon to the order
$item = new WC_Order_Item_Coupon();
$item->set_props(array('code' => $coupon_code, 'discount' => $discount_total, 'discount_tax' => 0));
$order->add_item($item);
$order->save();
You now get the nicely formatted order in wp-admin with line items showing the specific discount + the coupon code etc.
Check programmatically if a coupon is valid for a user in WooCommerce
The WC_Coupon
method is_valid()
does everything itself, as it uses WC_Discount
method is_coupon_valid()
that checks if coupon is valid for the user.
So you doesn't need anything more than you have already done in your code.
Add free product when a certain coupon is applied in WooCommerce
Your current code contains some mistakes or could be optimized:
global $woocommerce
can be replaced byWC()
$woocommerce->cart->get_applied_coupons()
is not necessary, as the coupon that have been applied is passed to the callback function.
Instead, use the last available argument in WC_Cart::add_to_cart() method, which will allow you to add any custom cart item data. Then you will be able to get that data easily from the cart object.
So you get:
function action_woocommerce_applied_coupon( $coupon_code ) {
// Settings
$product_id = 131468;
$quantity = 1;
$free_price = 0;
$coupon_codes = array( 'coupon1', 'mybday' );
// Compare
if ( in_array( $coupon_code, $coupon_codes ) ) {
// Add product to cart
WC()->cart->add_to_cart( $product_id, $quantity, 0, array(), array( 'free_price' => $free_price ) );
}
}
add_action( 'woocommerce_applied_coupon', 'action_woocommerce_applied_coupon', 10, 1 );
// Set free price from custom cart item data
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Loop through cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
if ( isset( $cart_item['free_price'] ) ) {
$cart_item['data']->set_price( $cart_item['free_price'] );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
Note: in addition to using woocommerce_applied_coupon
, you must also use woocommerce_removed_coupon
for when the coupon is removed, the product is removed as well
function action_woocommerce_removed_coupon( $coupon_code ) {
// Settings
$product_id = 131468;
$coupon_codes = array( 'coupon1', 'mybday' );
// Compare
if ( in_array( $coupon_code, $coupon_codes ) ) {
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
// When product in cart
if ( $cart_item['product_id'] == $product_id ) {
// Remove cart item
WC()->cart->remove_cart_item( $cart_item_key );
break;
}
}
}
}
add_action( 'woocommerce_removed_coupon', 'action_woocommerce_removed_coupon', 10, 1 );
woocommerce apply coupon programmatically bug
Based on your explanation, it sounds like you should be using the woocommerce_add_to_cart
hook, which is run when a product is successfully added to the cart. I also don't think you should be using is_admin()
, since that just checks if you're on an admin page...not if the current user is an admin.
I would do something like the following:
add_action( 'woocommerce_add_to_cart', 'apply_matched_coupons' );
function apply_matched_coupons() {
// If the current user is a shop admin
if ( current_user_can( 'manage_woocommerce' ) ) return;
// If the user is on the cart or checkout page
if ( is_cart() || is_checkout() ) return;
$coupon_code = 'somecodehere';
if ( WC()->cart->has_discount( $coupon_code ) ) return;
WC()->cart->add_discount( $coupon_code );
}
Related Topics
Overwrite Line in File with PHP
Call to Undefined Method Maatwebsite\Excel\Excel::Load()
PHP Try-Catch Blocks: Are They Able to Catch Invalid Arg Types
PHP Warning: Exec() Unable to Fork
How to Select Multiple Rows from MySQL with One Query and Use Them in PHP
PHP Run Once and Insert Twice in MySQL Database
Get the Hierarchy of a Directory with PHP
Using Fetch_Assoc on Prepared Statements
Mod_Rewrite, PHP and the .Htaccess File
How to Install Composer on App Service
Convert Lat/Longs to X/Y Co-Ordinates
Simple Way to Read Single Record from MySQL
Get Last Executed Query in PHP Pdo
PHP Files Are Downloaded by Browser Instead of Processed by Local Dev Server (Mamp)