I am trying to add a random string when the order number is created as the default sequential number can be very easily guessed.
I tried this snippet:
function generate_random_string( $length = 16 ) {
return substr( str_shuffle( str_repeat( $x = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil( $length / strlen( $x ) ) ) ), 1, $length );
}
add_filter( 'woocommerce_order_number', 'ct_change_woocommerce_order_number', 1, 2);
function ct_change_woocommerce_order_number( $order_id, $order ) {
$random_string1 = generate_random_string(5);
return $random_string1 . $order->get_id();
}
The problem is that this change the order number every time the order number is requested somewhere.
This would work if I will use a constant prefix and suffix, but in the actual way a different order number is shown each time for the same order. Any advice?
To prevent this you can save the result as meta data, once this exists return the meta data instead of the result of the function
So you get:
function generate_random_string( $length = 16 ) {
return substr( str_shuffle( str_repeat( $x = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil( $length / strlen( $x ) ) ) ), 1, $length );
}
function filter_woocommerce_order_number( $order_number, $order ) {
// Get meta
$random_meta_string = $order->get_meta( '_random_meta_string' );
// When meta empty
if ( empty ( $random_meta_string ) ) {
// Call function
$generate_random_string = generate_random_string( 5 );
// Append
$random_string = $generate_random_string . $order->get_id();
// Add the meta data
$order->update_meta_data( '_random_meta_string', $random_string );
// Return random string
$order_number = $random_string;
} else {
// Return meta
$order_number = $random_meta_string;
}
return $order_number;
}
add_filter( 'woocommerce_order_number', 'filter_woocommerce_order_number', 10, 2 );
Related
I need to remove / disable the coupon effect for products discounted by more than 10%.
At the moment I have something like this:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 'prod_category_name' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
foreach( $cart->get_applied_coupons() as $coupon_code ) {
// Get the WC_Coupon object
$coupon = new WC_Coupon($coupon_code);
$coupon_amount = $coupon->get_amount(); // Get coupon amount
}
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Get promo price
$promo_price = $cart_item['data']->get_price();
// Zniżka
$discount = 100 - (($promo_price * 100) / $regular_price);
$percentage = 10;
$percent_price = $regular_price - ($regular_price * ($percentage / 100));
if ($discount > $coupon_amount ) {
//$coupon->set_amount(0);
$cart->remove_coupon( 'coupon_name' );
}
if ( $percent_price < $promo_price ) {
$cart_item['data']->set_price( $regular_price );
} else {
$cart_item['data']->set_price( $promo_price );
}
}
}
}
}
At the moment, the code removes the coupon for the entire cart:
$cart->remove_coupon( 'coupon_name' );
Is there an option to remove the discount for the selected product from the cart?
I need something like:
$cart_item['data']->remove_coupon( 'coupon_name' );
Thank you so much!
Ok I added filter and it works perfect =)
add_filter( 'woocommerce_coupon_is_valid_for_product', 'exclude_product_from_product_promotions_frontend', 9999, 4 );
function exclude_product_from_product_promotions_frontend( $valid, $product, $coupon, $values ) {
$regular_price = $product->get_regular_price();
$promo_price = $product->get_price();
$discount = 100 - (($promo_price * 100) / $regular_price);
$coupon_amount = 10;
if ($discount > $coupon_amount ) {
$valid = false;
}
return $valid;
}
When a coupon is applied (belonging to a certain type) I change the product discount price to the regular price via:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupons1 = new WC_Coupon( $code );
if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
$coupon = True;
}
}
if ($coupon == True)
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->regular_price;
$cart_item['data']->set_price( $price );
}
}
But if I have a category excluded, the code freaks out because it changes the price from sale to regular in the cart and does not add a discount.
How to work around this so that the excluded category does not change to the regular price?
To exclude certain categories you can use has_term() when loop through the cart items
So you get:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 63, 15, 'categorie-1' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
// True
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Set new price
$cart_item['data']->set_price( $regular_price );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
I'm trying to drop the VAT on my cart items when the subtotal is over a specific amount. But when I use WC()->cart->get_subtotal() to get the subtotal price, it returns 0 and my if statement fails.
add_action( 'woocommerce_product_get_tax_class', 'wp_check_uk_vat', 1, 2 );
function wp_check_uk_vat( $tax_class, $product ) {
$cart_total = WC()->cart->get_subtotal();
// echo $cart_total;
if( $cart_total >= 100 ) {
$tax_class = "Zero rate";
}
return $tax_class;
}
Similar code is used here: https://docs.woocommerce.com/document/setting-up-taxes-in-woocommerce/#section-18
The goal of the code is to drop the VAT on the cart (not shipping) when the order amount is over 135 GBP (to comply with the new Brexit rules for merchants).
Because WC()->cart->get_subtotal() returns 0, the if statement fails, and the VAT is not being dropped.
Try this
add_action( 'woocommerce_product_get_tax_class', 'wp_check_uk_vat', 1, 2 );
function wp_check_uk_vat( $tax_class, $product ) {
if(WC()->cart){
$subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$subtotal += $cart_item[ 'data' ]->get_price( 'edit' ) * $cart_item[ 'quantity' ];
}
if ( $subtotal >= 100 ) {
$tax_class = "Zero rate";
}
}
return $tax_class;
}
This question already has answers here:
Replace woocommerce_add_order_item_meta hook in Woocommerce 3.4
(1 answer)
Woocommerce: Which hook to replace deprecated "woocommerce_add_order_item_meta"
(8 answers)
Closed 3 years ago.
Hello I was using woocommerce_add_order_item_meta to add some additional information for order item. After woocommerce update I got error on ordar pay page. I researched that why it happens. I found this article. and I understood why I'm getting error. I changed action hook name but still get errors. What should I do ?
function addBizDays($item_id, $cart_item ,$start, $add){
$start =current_time( 'mysql' );
$add = get_post_meta( $cart_item[ 'product_id' ], 'dp_kargolanma_suresi', true );
$d = new DateTime($start );
$t = $d->getTimestamp();
// loop for X days
for($i=0; $i<$add; $i++){
// add 1 day to timestamp
$addDay = 86400;
// get what day it is next day
$nextDay = date('w', ($t+$addDay));
// if it's Saturday or Sunday get $i-1
if($nextDay == 0 || $nextDay == 6) {
$i--;
}
// modify timestamp, add 1 day
$t = $t+$addDay;
}
$d->setTimestamp($t);
$teslim_tarihi = $d->format( 'd-m-Y' ). "\n";
$desiveyakg = ( $cart_item['quantity'] * $cart_item['data']->get_weight());
$kargosinifi = $cart_item['data']->get_shipping_class();
wc_update_order_item_meta( $item_id, 'En Gec Kargolanma Tarihi', $teslim_tarihi );
wc_update_order_item_meta( $item_id, '_desi_kg', $desiveyakg );
wc_update_order_item_meta( $item_id, '_alici_onay_durumu', 'Onay Bekliyor' );
if($cart_item['quantity'] >= 100)
{
wc_update_order_item_meta( $item_id, '_kargo_sinifi', 'ucretsiz-kargo' );
}
else{
wc_update_order_item_meta( $item_id, '_kargo_sinifi', $kargosinifi );
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'addBizDays', 10, 5 );
You need to change more than just the hook… The hooked function arguments are wrong in your code and the way to updated data has changed too. Try the following:
add_action( 'woocommerce_checkout_create_order_line_item', 'add_business_days', 10, 4 );
function add_business_days( $order_item, $cart_item_key, $cart_item, $order ){
$now = current_time( 'mysql' );
$add = $cart_item['data']->get_meta( 'dp_kargolanma_suresi' );
$d = new DateTime( $now );
$t = $d->getTimestamp();
$oneDay = 86400;
$nextDay = date('w', ($t + $oneDay));
// loop for X days
for( $i = 0; $i < $add; $i++ ) {
// if it's Saturday or Sunday get $i-1
if($nextDay == 0 || $nextDay == 6) {
$i--;
}
// modify timestamp, add 1 day
$t = $t + $oneDay;
}
$d->setTimestamp($t);
$teslim_tarihi = $d->format( 'd-m-Y' ). "\n";
$desiveyakg = ( $cart_item['quantity'] * $cart_item['data']->get_weight() );
$kargosinifi = $cart_item['data']->get_shipping_class();
$order_item->update_meta_data( 'En Gec Kargolanma Tarihi', $teslim_tarihi );
$order_item->update_meta_data( '_desi_kg', $desiveyakg );
$order_item->update_meta_data( '_alici_onay_durumu', 'Onay Bekliyor' );
if($cart_item['quantity'] >= 100) {
$order_item->update_meta_data( '_kargo_sinifi', 'ucretsiz-kargo' );
} else {
$order_item->update_meta_data( '_kargo_sinifi', $kargosinifi );
}
}
It should work…
I have a product with variations, that is being displayed by the templates/single-product/add-to-cart/variation.php template, which uses JavaScript-based templates {{{ data.variation.display_price }}}. When I have price that end with a zero, for example, € 12.50, the price on the front-end will be displayed as € 12.5 (without the zero). I want to have the price include the trailing zero.
I've tried the following filter, but it does not work.
add_filter( 'woocommerce_price_trim_zeros', 'wc_hide_trailing_zeros', 10, 1 );
function wc_hide_trailing_zeros( $trim ) {
// set to false to show trailing zeros
return false;
}
I've fixed it by checking that when the price has one decimal, add a zero.
// https://stackoverflow.com/a/2430214/3689325
function numberOfDecimals( $value ) {
if ( (int) $value == $value ) {
return 0;
}
else if ( ! is_numeric( $value ) ) {
return false;
}
return strlen( $value ) - strrpos( $value, '.' ) - 1;
}
/**
* Make sure prices have two decimals.
*/
add_filter( 'woocommerce_get_price_including_tax', 'price_two_decimals', 10, 1 );
add_filter( 'woocommerce_get_price_excluding_tax', 'price_two_decimals', 10, 1 );
function price_two_decimals( $price ) {
if ( numberOfDecimals( $price ) === 1 ) {
$price = number_format( $price, 2 );
return $price;
}
return $price;
}