I want to show the price of the products to the user with a little change.
These changes are actually some calculations that are applied to the price of each product.
Everything works fine. And it shows the calculated price correctly.
The only problem is that the price is wrong through the WooCommerce api.
In WooCommerce, we have a price field for each product.
My code applies a calculation on that price And finally it shows to the user.
But when I call the product through rest-api, it only shows the price entered in the product price field. Not the calculation price.
This is my code:
add_filter('woocommerce_get_price_html', 'didoprice_override_price', 200, 2);
function didoprice_override_price($price='', $product){
$gram = $product->get_weight();
if ( empty( $gram ) ){
$gram = 100;
}
$all_tax_rates = [];
$tax_classes = WC_Tax::get_tax_classes(); // Retrieve all tax classes.
if ( !in_array( '', $tax_classes ) ) { // Make sure "Standard rate" (empty class name) is present.
array_unshift( $tax_classes, '' );
}
foreach ( $tax_classes as $tax_class ) { // For each tax class, get all rates.
$taxes = WC_Tax::get_rates_for_tax_class( $tax_class );
$all_tax_rates = array_merge( $all_tax_rates, $taxes );
}
$tax_rate = $all_tax_rates[0]->tax_rate/100;
$reg_price = '';
if($product->is_type( 'variable' ))
{
$variations = $product->get_children();
$reg_prices = array();
$sale_prices = array();
foreach ($variations as $value) {
$single_variation=new WC_Product_Variation($value);
array_push($reg_prices, $single_variation->get_regular_price());
array_push($sale_prices, $single_variation->get_price());
}
sort($reg_prices);
sort($sale_prices);
$min_price = $reg_prices[0];
$min_price = didoprice_calculation( $min_price, $gram );
$min_price += $tax_rate*$min_price;
$max_price = $reg_prices[count($reg_prices)-1];
$max_price = didoprice_calculation( $max_price, $gram );
$max_price += $tax_rate*$max_price;
if($min_price == $max_price)
{
$reg_price = wc_price($min_price);
}
else
{
$reg_price = wc_format_price_range($min_price, $max_price);
}
$min_price = $sale_prices[0];
$min_price = didoprice_calculation( $min_price, $gram );
$min_price += $tax_rate*$min_price;
$max_price = $sale_prices[count($sale_prices)-1];
$max_price = didoprice_calculation( $max_price, $gram );
$max_price += $tax_rate*$max_price;
if($min_price == $max_price)
{
$sale_price = wc_price($min_price);
}
else
{
$sale_price = wc_format_price_range($min_price, $max_price);
}
$suffix = $product->get_price_suffix($price);
return wc_format_sale_price($reg_price, $sale_price).$suffix;
}
$orig_price = wc_get_price_excluding_tax( $product );
$regular = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_regular_price() ) );
$sale = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_sale_price() ) );
$regular = didoprice_calculation( $regular, $gram );
$regular += $regular*$tax_rate;
$sale = didoprice_calculation( $sale, $gram );
$sale += $sale *$tax_rate;
if ( $product->is_on_sale() ) {
return wc_format_sale_price( $regular, $sale );
}else{
return wc_price( $regular );
}
// return $price;
}
/**
* override cart items price based on the Formula.
*/
add_action( 'woocommerce_before_calculate_totals', 'didoprice_alter_price_cart', 9999 );
function didoprice_alter_price_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// IF CUSTOMER NOT LOGGED IN, DONT APPLY DISCOUNT
// if ( ! wc_current_user_has_role( 'customer' ) ) return;
// LOOP THROUGH CART ITEMS & APPLY 20% DISCOUNT
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$price = $product->get_price();
$gram = $product->get_weight();
if ( empty( $gram ) ){
$gram = 100;
}
$price = didoprice_calculation( $price, $gram );
$cart_item['data']->set_price( $price );
}
}
You're using the hook woocommerce_get_price_html, which is to adjust the outputted HTML for the price.
The correct hook(s) to use would be either woocommerce_get_price_excluding_tax or woocommerce_get_price_including_tax, depending on what you prefer.
So the first line would be, for example:
add_filter('woocommerce_get_price_including_tax', 'didoprice_override_price', 200, 2);
You can find more information about the hooks within WooCommerce in the documentation.
Related
I want to make custom sort option and use it into shortcode.
i want to make custom sort by percent discont for sale products.
Here is my code:
add_action('woocommerce_process_product_meta', 'woo_calc_my_discount');
function woo_calc_my_discount( $product_id ) {
$_product = wc_get_product( $product_id );
$regular = (float) $_product->get_regular_price();
$sale = (float) $_product->get_sale_price();
$discount = round( 100 - ( $sale / $regular * 100), 2 );
update_post_meta( $product_id, '_discount_amount', $discount );
}
add_action('woocommerce_product_quick_edit_save', 'sv_woo_calc_my_discount_quickedit');
function sv_woo_calc_my_discount_quickedit( $post ) {
$_product = wc_get_product( $post );
$regular = (float) $_product->get_regular_price();
$sale = (float) $_product->get_sale_price();
$discount = round( 100 - ( $sale / $regular * 100), 2 );
update_post_meta( $_product->get_id(), '_discount_amount', $discount );
}
add_filter( 'woocommerce_get_catalog_ordering_args', 'misha_custom_product_sorting' );
function misha_custom_product_sorting( $args ) {
// Discount percentage: High to Low
if( isset( $_GET['orderby'] ) && '_discount_amount' === $_GET['orderby'] ) {
$args['meta_key'] = '_discount_amount';
$args['order'] = 'desc';
}
return $args;
}
add_filter( 'woocommerce_catalog_orderby', 'misha_add_custom_sorting_options' );
function misha_add_custom_sorting_options( $options ){
$options['_discount_amount'] = 'Sale: High to Low';
return $options;
}
I use also:
[products on_sale="true" orderby="_discount_amount"]
but seems it's without success for now..
Any ideas? thanks!
I've a problem with this code to apply different percentage of discount to product in different category
The function work but is execute n times where n depends on the number of products in cart
add_filter( 'woocommerce_coupon_get_discount_amount', 'alter_shop_coupon_data', 1, 5 );
function alter_shop_coupon_data( $discount, $discounting_amount, $cart_item, $single, $instance ){
$coupons = WC()->cart->get_coupons();
$cart_items = WC()->cart->get_cart();
foreach ( $coupons as $code => $coupon ) {
if ( $coupon->discount_type == 'percent' && $coupon->code == 'newsite' ) {
foreach ($cart_items as $cart_item){
$product_id = $cart_item['data']->id;
if( has_term( 'cat1', 'product_cat', $product_id ) ){
$quantity = $cart_item['quantity'];
$price = $cart_item['data']->price;
$discount_20 = 0.2 * ($quantity * $price); // 20%
}else{
$quantity = $cart_item['quantity'];
$price = $cart_item['data']->price;
$discount_10 = 0.1 * ($quantity * $price); //10%
}
}
}
}
$discounting_amount = ($discount_20 + $discount_10);
return $discounting_amount;
}
Since WooCommerce 3, there are many mistakes in your codeā¦ Also the $cart_item argument is included in the function, so you don't need to loop through cart items.
Also note that $coupon->is_type('percent') (coupon type) is not needed as you target a specific coupon in your code: $coupon->get_code() == 'newsite.
Try the following:
add_filter( 'woocommerce_coupon_get_discount_amount', 'alter_shop_coupon_data', 100, 5 );
function alter_shop_coupon_data( $discount, $discounting_amount, $cart_item, $single, $instance ){
// Loop through applied WC_Coupon objects
foreach ( WC()->cart->get_coupons() as $code => $coupon ) {
if ( $coupon->is_type('percent') && $coupon->get_code() == 'newsite' ) {
$discount = $cart_item['data']->get_price() * $cart_item['quantity'];
if( has_term( 'cat1', 'product_cat', $cart_item['product_id'] ) ){
$discount *= 0.2; // 20%
}else{
$discount *= 0.1; // 10%
}
}
}
return $discount;
}
Code goes in functions.php file of the active child theme (or active theme). It should better work.
I have added a progressive pricing based on the quantity of each cart item. What I am struggling with, is to reflect the $default_price from the product (instead the now manually added price) and also to set the layout of the new price like this (default_price has strikethrough):
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 20, 1);
function add_custom_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $item ) {
$quantity = $item['quantity'];
$discount_price = 0.008333333333;
$default_price = 4.25;
$minimum = 10;
$maximum = 100;
if( $quantity > $minimum ) {
if( $quantity > $maximum ) {
$new_price = $default_price - ($discount_price * ($maximum - $minimum));
}
else {
$new_price = $default_price - ($discount_price * ($quantity - $minimum));
}
$item['data']->set_price( '<del>' . $default_price . '</del> <strong>' . $new_price . '</strong>');
}
}
}
The coded $item['data']->set_price( '<del>' . $default_price . '</del> <strong>' . $new_price . '</strong>'); is wrong, but how do I reflect this so it can accept the html elements?
For what you wish to obtain you can use the following:
While the woocommerce_before_calculate_totals action hook is used to calculate totals
The woocommerce_cart_item_price filter hook ensures the strikethrough of the original price.
explanation via comment tags added in the code
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Settings
$discount_price = 0.008333333333;
$minimum = 10;
$maximum = 100;
// Iterating though each cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Product quantity in cart
$quantity = $cart_item['quantity'];
// Quantity greater than minimum
if ( $quantity > $minimum ) {
// Default price
$default_price = $cart_item['data']->get_price();
// Quantity greater than maximum
if ( $quantity > $maximum ) {
$new_price = $default_price - ( $discount_price * ( $maximum - $minimum ) );
} else {
$new_price = $default_price - ( $discount_price * ( $quantity - $minimum ) );
}
// Set price
$cart_item['data']->set_price( $new_price );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
function filter_woocommerce_cart_item_price( $price_html, $cart_item, $cart_item_key ) {
// Get the product object
$product = $cart_item['data'];
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get reqular price
$regular_price = $product->get_regular_price();
// New price
$new_price = $cart_item['data']->get_price();
// NOT empty and NOT equal
if ( ! empty ( $regular_price ) && $regular_price != $new_price ) {
// Output
$price_html = '<del>' . wc_price( $regular_price ) . '</del> <ins>' . wc_price( $new_price ) . '</ins>';
}
}
return $price_html;
}
add_filter( 'woocommerce_cart_item_price', 'filter_woocommerce_cart_item_price', 10, 3 );
I want to add automatically one variations product into cart when cart total is become more than 25. The automatically adding variation product price need to set as 0 and also customers cant change the qty or need to disable the Qty filed for free product. I added below code and its working fine only the issue when page reloading or cart updating the the Qty of free product is increasing every time.I only want to sell 1 qty of free product. How to do that ? Code is following below.
function aapc_add_product_to_cart() {
global $woocommerce;
$cart_total = 25;
if ( $woocommerce->cart->total >= $cart_total ) {
if ( ! is_admin()) {
$free_product_id = 2696;
$variation_id = 2697;
$arr = array();
$arr['Color'] = 'Blue';// Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $free_product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $free_product_id,1,$variation_id,$arr );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $free_product_id,1,$variation_id,$arr );
}
}
}
}
add_action( 'template_redirect', 'aapc_add_product_to_cart' );
function add_custom_price( $cart_object ) {
$cart_total = 25; // If cart total is more than this value.
$free_product_id = 2697; // Set price to 0 of this free product.
$carttotal = 0;
foreach ( $cart_object->cart_contents as $key => $value ) {
$_product = $value['data'];
if ( $_product->get_id() == $free_product_id ){
continue;
}
$carttotal += $value['line_total'];
}
if ( $carttotal >= $cart_total ) {
$custom_price = 0; // This will be your custome price
foreach ( $cart_object->cart_contents as $key => $value ) {
$_product = $value['data'];
if ( $_product->get_id() == $free_product_id ){
$value['data']->set_price( $custom_price );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
add_filter( 'woocommerce_quantity_input_args', 'hide_quantity_input_field', 20, 2 );
function hide_quantity_input_field( $args, $product ) {
// Here set your product IDs in the array
$product_ids = array(2697);
// Handling product variation
$the_id = $product->is_type('variation') ? $product->get_variation_id() : $product->get_id();
//var_dump($the_id);
// Only on cart page for a specific product category
if( is_cart() && in_array( $the_id, $product_ids ) ){
$input_value = $args['input_value'];
$args['min_value'] = $args['max_value'] = $input_value;
}
return $args;
}
Try adding below code in the functions.php and replace with required product id
add_filter( 'woocommerce_add_to_cart_validation', 'allowed_products_variation_in_the_cart', 10, 5 );
function allowed_products_variation_in_the_cart( $passed, $product_id, $quantity, $variation_id, $variations) {
$product_b = 14091;
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$cart_product_id = $cart_item['product_id'];
if ($cart_item['variation_id']) {
$cart_product_id = $cart_item['variation_id'];
}
if ( ( $variation_id == $product_b) ) {
wc_add_notice(__('You can\'t add this product.', 'domain'), 'error');
$passed = false; // don't add the new product to the cart
// We stop the loop
break;
}
}
return $passed;
}
I am trying to dynamically add to a products price when a user checks out based on what they have entered in the product page. The setting of the price is only working on a non variation product.
I need to be able to set the price on the variations of the products as well.
The code that I am using:
function add_cart_item_data( $cart_item_meta, $product_id, $variation_id ) {
$product = wc_get_product( $product_id );
$price = $product->get_price();
$letterCount = strlen($_POST['custom_name']);
$numberCount = strlen($_POST['custom_number']);
if($letterCount != '0') {
$letterPricing = 20 * $letterCount;
$numberPricing = 10 * $numberCount;
$additionalPrice = $letterPricing + $numberPricing;
$cart_item_meta['custom_price'] = $price + $additionalPrice;
}
return $cart_item_meta;
}
function calculate_cart_total( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value['custom_price'] ) ) {
$price = $value['custom_price'];
$value['data']->set_price( ( $price ) );
}
}
}
I have completely revisited your code:
// Set custom data as custom cart data in the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_data_to_cart_object', 30, 3 );
function add_custom_data_to_cart_object( $cart_item_data, $product_id, $variation_id ) {
if( ! isset($_POST['custom_name']) || ! isset($_POST['custom_number']) )
return $cart_item_data; // Exit
if( $variation_id > 0)
$product = wc_get_product( $variation_id );
else
$product = wc_get_product( $product_id );
$price = $product->get_price();
// Get the data from the POST request and calculate new custom price
$custom_name = sanitize_text_field( $_POST['custom_name'] );
if( strlen( $custom_name ) > 0 )
$price += 20 * strlen( $custom_name );
$custom_number = sanitize_text_field( $_POST['custom_number'] );
if( strlen( $custom_number ) > 0 )
$price += 10 * strlen( $custom_number );
// Set new calculated price as custom cart item data
$cart_item_data['custom_data']['price'] = $price;
return $cart_item_data;
}
// Set the new calculated price of the cart item
add_action( 'woocommerce_before_calculate_totals', 'set_new_cart_item_price', 50, 1 );
function set_new_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach ( $cart->get_cart() as $cart_item ) {
if( isset( $cart_item['custom_data']['price'] ) ) {
// Get the new calculated price
$new_price = (float) $cart_item['custom_data']['price'];
// Set the new calculated price
$cart_item['data']->set_price( $new_price );
}
}
}
This code goes on function.php file of your active child theme (or theme).
Tested and works as well with product variations.