We are using Woocommerce and we are trying to retrieve the vendor name for a product that has been added to a cart.
We are using the Cocart plugin to make the RestAPI work.
Our marketplace plugin is Dokan.
That is our code:
$cart_contents[ $item_key ]['product_author'] = apply_filters( 'cocart_product_author', $_product->getAuthor(), $_product, $cart_item, $item_key );
We got the below error
<b>Fatalerror</b>: UncaughtError: CalltoundefinedmethodWC_Product_Simple: : getAuthor()
My entire code
* Return cart contents.
*
* #access public
* #since 2.0.0
* #version 3.5.0
* #param array $data
* #param array $cart_contents
* #param string $cart_item_key
* #param bool $from_session
* #return array $cart_contents
*/
public function return_cart_contents( $data = array(), $cart_contents = array(), $cart_item_key = '', $from_session = false ) {
if ( CoCart_Count_Items_Controller::get_cart_contents_count( array( 'return' => 'numeric' ), $cart_contents ) <= 0 || empty( $cart_contents ) ) {
/**
* Filter response for empty cart.
*
* #since 2.0.8
*/
$empty_cart = apply_filters( 'cocart_return_empty_cart', array() );
return $empty_cart;
}
$show_thumb = ! empty( $data['thumb'] ) ? $data['thumb'] : false;
// Find the cart item key in the existing cart.
if ( ! empty( $cart_item_key ) ) {
$cart_item_key = $this->find_product_in_cart( $cart_item_key );
return $cart_contents[ $cart_item_key ];
}
foreach ( $cart_contents as $item_key => $cart_item ) {
// If product data is missing then get product data and apply.
if ( ! isset( $cart_item['data'] ) ) {
$cart_item['data'] = wc_get_product( $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'] );
$cart_contents[ $item_key ]['data'] = $cart_item['data'];
}
$_product = apply_filters( 'cocart_item_product', $cart_item['data'], $cart_item, $item_key );
// If product is no longer purchasable then don't return it and notify customer.
if ( ! $_product->is_purchasable() ) {
/* translators: %s: product name */
$message = sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'cart-rest-api-for-woocommerce' ), $_product->get_name() );
/**
* Filter message about item removed from the cart.
*
* #since 2.1.0
* #param string $message Message.
* #param WC_Product $_product Product data.
*/
$message = apply_filters( 'cocart_cart_item_removed_message', $message, $_product );
WC()->cart->set_quantity( $item_key, 0 ); // Sets item quantity to zero so it's removed from the cart.
wc_add_notice( $message, 'error' );
} else {
// Adds the product name and title as new variables.
$cart_contents[ $item_key ]['product_name'] = apply_filters( 'cocart_product_name', $_product->get_name(), $_product, $cart_item, $item_key );
$cart_contents[ $item_key ]['product_title'] = apply_filters( 'cocart_product_title', $_product->get_title(), $_product, $cart_item, $item_key );
$cart_contents[ $item_key ]['product_author'] = apply_filters( 'cocart_product_author', $_product->getAuthor(), $_product, $cart_item, $item_key );
Related
I have to do the following reflection code because the WooCommerce version I have available has a bug (v4.9.2).
Please see the comments in the code below:
// checked before the existence of the class with class_exists
$rp = new ReflectionProperty('WC_Product_Variable_Data_Store_CPT', 'prices_array');
$rp->setAccessible(true);
var_dump('start'); // echoes something to the html code
$protected_prices_array = $rp->getValue($ths); // crashes the PHP script instance
var_dump('stop'); // this is not printed anymore
If requested, I can offer more code.
Currently I am attempting to inherit the given class to see if I can walk around the bug.
On staging site I have PHP 7.4.16.
Update 1
I have this code in my own function my_read_price_data( $ths, &$product, $for_display = false ) { ... which does the same as WC's data store's read_price_data public method which accesses the prices_array property which is protected.
Update 2
/**
* Modified function from WC.
*
* #param WC_Product_Variable_Data_Store_CPT $ths
* #param WC_Product_Variable $product
* #param boolean $for_display
* #return void
*/
function my_read_price_data( $ths, &$product, $for_display = false ) {
/**
* Transient name for storing prices for this product (note: Max transient length is 45)
*
* #since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
*/
$transient_name = 'wc_var_prices_' . $product->get_id();
$transient_version = WC_Cache_Helper::get_transient_version( 'product' );
$price_hash = my_get_price_hash($ths, $product, $for_display); // with this it does not crash (*)
// NOTE: maybe inherit from WC_Product_Variable_Data_Store_CPT to not use reflection.
$rp = new ReflectionProperty('WC_Product_Variable_Data_Store_CPT', 'prices_array'); // the class exists
$rp->setAccessible(true);
var_dump('start');
$protected_prices_array = $rp->getValue($ths); // (*) until this
var_dump('stop');
// Check if prices array is stale.
if ( ! isset( $protected_prices_array['version'] ) || $protected_prices_array['version'] !== $transient_version ) {
$rp->setValue($ths, array(
'version' => $transient_version,
));
}
$protected_prices_array = $rp->getValue($ths);
/**
* $this->prices_array is an array of values which may have been modified from what is stored in transients - this may not match $transient_cached_prices_array.
* If the value has already been generated, we don't need to grab the values again so just return them. They are already filtered.
*/
if ( empty( $protected_prices_array[ $price_hash ] ) ) {
$transient_cached_prices_array = array_filter( (array) json_decode( strval( get_transient( $transient_name ) ), true ) );
// If the product version has changed since the transient was last saved, reset the transient cache.
if ( ! isset( $transient_cached_prices_array['version'] ) || $transient_version !== $transient_cached_prices_array['version'] ) {
$transient_cached_prices_array = array(
'version' => $transient_version,
);
}
// If the prices are not stored for this hash, generate them and add to the transient.
if ( empty( $transient_cached_prices_array[ $price_hash ] ) ) {
$prices_array = array(
'price' => array(),
'regular_price' => array(),
'sale_price' => array(),
);
$variation_ids = $product->get_visible_children();
if ( is_callable( '_prime_post_caches' ) ) {
_prime_post_caches( $variation_ids );
}
foreach ( $variation_ids as $variation_id ) {
$variation = wc_get_product( $variation_id );
if ( $variation ) {
$price = apply_filters( 'woocommerce_variation_prices_price', $variation->get_price( 'edit' ), $variation, $product );
$regular_price = apply_filters( 'woocommerce_variation_prices_regular_price', $variation->get_regular_price( 'edit' ), $variation, $product );
$sale_price = apply_filters( 'woocommerce_variation_prices_sale_price', $variation->get_sale_price( 'edit' ), $variation, $product );
// Skip empty prices.
if ( '' === $price ) {
continue;
}
// If sale price does not equal price, the product is not yet on sale.
if ( $sale_price === $regular_price || $sale_price !== $price ) {
$sale_price = $regular_price;
}
// If we are getting prices for display, we need to account for taxes.
if ( $for_display ) {
if ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
$price = '' === $price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $price,
)
);
$regular_price = '' === $regular_price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $regular_price,
)
);
$sale_price = '' === $sale_price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $sale_price,
)
);
} else {
$price = '' === $price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $price,
)
);
$regular_price = '' === $regular_price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $regular_price,
)
);
$sale_price = '' === $sale_price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $sale_price,
)
);
}
}
$prices_array['price'][ $variation_id ] = wc_format_decimal( $price, wc_get_price_decimals() );
$prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, wc_get_price_decimals() );
$prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, wc_get_price_decimals() );
$prices_array = apply_filters( 'woocommerce_variation_prices_array', $prices_array, $variation, $for_display );
}
}
// Add all pricing data to the transient array.
foreach ( $prices_array as $key => $values ) {
$transient_cached_prices_array[ $price_hash ][ $key ] = $values;
}
set_transient( $transient_name, wp_json_encode( $transient_cached_prices_array ), DAY_IN_SECONDS * 30 );
}
/**
* Give plugins one last chance to filter the variation prices array which has been generated and store locally to the class.
* This value may differ from the transient cache. It is filtered once before storing locally.
*/
$protected_prices_array = $rp->getValue($ths);
$protected_prices_array[$price_hash] = apply_filters( 'woocommerce_variation_prices', $transient_cached_prices_array[ $price_hash ], $product, $for_display );
$rp->setValue($ths, $protected_prices_array);
}
return $rp->getValue($ths)[ $price_hash ];
}
Update 3
The function above, my_read_price_data, is called by:
/**
* Function modified from WC.
*
* #param WC_Product_Variable $p
* #param boolean $for_display
* #return void
*/
function my_get_variation_prices( $p, $for_display = false ) {
$ds = $p->get_data_store(); // $p->data_store;
$prices = my_read_price_data($ds, $p, $for_display);
foreach ( $prices as $price_key => $variation_prices ) {
$prices[ $price_key ] = asort( $variation_prices );
}
return $prices;
}
This is called by the following function which is a modified version of a WC function, but this time the modification is done to change the output to something the client wants:
function my_get_price_html( $price = '' ) {
global $product;
$prices = my_get_variation_prices($product, true);
if ( empty( $prices['price'] ) ) {
$price = apply_filters( 'woocommerce_variable_empty_price_html', '', $product );
} else {
$min_price = current( $prices['price'] );
$max_price = end( $prices['price'] );
$min_reg_price = current( $prices['regular_price'] );
$max_reg_price = end( $prices['regular_price'] );
if ( $min_price !== $max_price ) {
$price = wc_format_price_range( $min_price, $max_price );
} elseif ( $product->is_on_sale() && $min_reg_price === $max_reg_price ) {
$price = my_wc_format_sale_price( $prices['regular_price'] , $prices['price'] );
} else {
$price = wc_price( $min_price );
}
$price = apply_filters( 'woocommerce_variable_price_html', $price . $product->get_price_suffix(), $product );
}
return apply_filters( 'woocommerce_get_price_html', $price, $product );
}
As you can see above, I use my_wc_format_sale_price which is here:
/**
* Format a sale price for display.
*
* #since 3.0.0
* #param float $regular_price Regular price.
* #param float $sale_price Sale price.
* #return string
*/
function my_wc_format_sale_price( $regular_price, $sale_price ) {
$price = '<span>' . get_my_percent($regular_price, $sale_price) . '</span> <ins>' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '</ins>';
return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price );
}
Here is the last function that matters, I think (it has a doc comment that says it returns a string):
function get_my_percent($regular_price, $sale_price) {
$a = ($regular_price - $sale_price) / $regular_price * 100;
return "$a% reducere";
}
Update 4
I discovered the following through https://stackoverflow.com/a/21429652/258462.
It seems that the object given to the reflection mechanism is of a different type than the expected type.
From the source code of WooCommerce 4.9.2:
/**
* WC Variable Product Data Store: Stored in CPT.
*
* #version 3.0.0
*/
class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Product_Variable_Data_Store_Interface {
/**
* Cached & hashed prices array for child variations.
*
* #var array
*/
protected $prices_array = array()
...
So the question is how to convert the WC_Data_Store into something that has the $prices_array property?
I've used the awesome snippet of https://jeroensormani.com/custom-stock-quantity-reduction/ to add an additional setting to variations that reduces the main inventory stock by the set amount in the variation.
The problem I'm facing now is that it doesn't check if those variations are out of stock (for example main inventory is 10, and the bundle setting is set to 12 bottles).
The code I've used to add the the multiplier for the total stock reduction is:
// For implementation instructions see: https://aceplugins.com/how-to-add-a-code-snippet/
/**
* Simple product setting.
*/
function ace_add_stock_inventory_multiplier_setting() {
?><div class='options_group'><?php
woocommerce_wp_text_input( array(
'id' => '_stock_multiplier',
'label' => __( 'Inventory reduction per quantity sold', 'woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Enter the quantity multiplier used for reducing stock levels when purchased.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'min' => '1',
'step' => '1',
),
) );
?></div><?php
}
add_action( 'woocommerce_product_options_inventory_product_data', 'ace_add_stock_inventory_multiplier_setting' );
/**
* Add variable setting.
*
* #param $loop
* #param $variation_data
* #param $variation
*/
function ace_add_variation_stock_inventory_multiplier_setting( $loop, $variation_data, $variation ) {
$variation = wc_get_product( $variation );
woocommerce_wp_text_input( array(
'id' => "stock_multiplier{$loop}",
'name' => "stock_multiplier[{$loop}]",
'value' => $variation->get_meta( '_stock_multiplier' ),
'label' => __( 'Inventory reduction per quantity sold', 'woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Enter the quantity multiplier used for reducing stock levels when purchased.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'min' => '1',
'step' => '1',
),
) );
}
add_action( 'woocommerce_variation_options_pricing', 'ace_add_variation_stock_inventory_multiplier_setting', 50, 3 );
/**
* Save the custom fields.
*
* #param WC_Product $product
*/
function ace_save_custom_stock_reduction_setting( $product ) {
if ( ! empty( $_POST['_stock_multiplier'] ) ) {
$product->update_meta_data( '_stock_multiplier', absint( $_POST['_stock_multiplier'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'ace_save_custom_stock_reduction_setting' );
/**
* Save custom variable fields.
*
* #param int $variation_id
* #param $i
*/
function ace_save_variable_custom_stock_reduction_setting( $variation_id, $i ) {
$variation = wc_get_product( $variation_id );
if ( ! empty( $_POST['stock_multiplier'] ) && ! empty( $_POST['stock_multiplier'][ $i ] ) ) {
$variation->update_meta_data( '_stock_multiplier', absint( $_POST['stock_multiplier'][ $i ] ) );
$variation->save();
}
}
add_action( 'woocommerce_save_product_variation', 'ace_save_variable_custom_stock_reduction_setting', 10, 2 );
The code that reduces the quantity then is the following:
// For implementation instructions see: https://aceplugins.com/how-to-add-a-code-snippet/
/**
* Reduce with custom stock quantity based on the settings.
*
* #param $quantity
* #param $order
* #param $item
* #return mixed
*/
function ace_custom_stock_reduction( $quantity, $order, $item ) {
/** #var WC_Order_Item_Product $product */
$multiplier = $item->get_product()->get_meta( '_stock_multiplier' );
if ( empty( $multiplier ) && $item->get_product()->is_type( 'variation' ) ) {
$product = wc_get_product( $item->get_product()->get_parent_id() );
$multiplier = $product->get_meta( '_stock_multiplier' );
}
if ( ! empty( $multiplier ) ) {
$quantity = $multiplier * $quantity;
}
return $quantity;
}
add_filter( 'woocommerce_order_item_quantity', 'ace_custom_stock_reduction', 10, 3 );
What I've tried to do is add an "If" Snippet to check the quantity
add_filter( ‘woocommerce_variation_is_active’, ‘my_jazzy_function’, 10, 2 );
function my_jazzy_function( $active, $variation ) {
// Get Multiplier
$multiplier = $item->get_product()->get_meta( '_stock_multiplier' );
$var_stock_count = $variation->get_stock_quantity();
// if there are 5 or less, disable the variant, could always just set to 0.
if( $var_stock_count <= $multiplier ) {
return false;
}
else {
return true;
}
}
But this doesn't work, I think it only checks the variations quantity (if you set the variation to its own quantity instead of global).
How can I compare the total stock count to the newly added setting $multiplier?
Any help would be great.
Compare the total stock quantity to the newly added setting $multiplier
Comment with explanation added to the code
function filter_woocommerce_variation_is_active( $active, $variation ) {
// Get multiplier
$multiplier = get_post_meta( $variation->get_variation_id(), '_stock_multiplier', true );
// NOT empty
if ( ! empty( $multiplier ) ) {
// Get stock quantity
$var_stock_count = $variation->get_stock_quantity();
// Stock quantity < multiplier
if( $var_stock_count < $multiplier ) {
$active = false;
}
}
return $active;
}
add_filter( 'woocommerce_variation_is_active', 'filter_woocommerce_variation_is_active', 10, 2 );
It doesn't work because:
$item variable is not defined in your code.
your custom field is defined in the parent variable product.
So you need to replace:
$multiplier = $item->get_product()->get_meta( '_stock_multiplier' );
by the folling (getting the data from the parent variable product):
$multiplier = get_post_meta( $variation->get_parent_id(), '_stock_multiplier', true );
So in your code:
add_filter( 'woocommerce_variation_is_active', 'my_jazzy_function', 10, 2 );
function my_jazzy_function( $active, $variation ) {
// Get multiplier
if( $multiplier = get_post_meta( $variation->get_parent_id(), '_stock_multiplier', true ) {
// Get stock quantity
$var_stock_count = (int) $variation->get_stock_quantity();
// if there are 5 or less, disable the variant, could always just set to 0
return $var_stock_count <= $multiplier ? false : $active;
}
return $active;
}
It should work now.
I am trying to set a discount for when BOTH products are in the cart no matter what other products are also in there.
As of now, all it takes is one of the two within the array.
add_action( 'woocommerce_cart_calculate_fees', 'discount_for_ab_products' );
function discount_for_ab_products( $cart ) {
$product_ids = array(34,35);
foreach ($product_ids as $product_id => $product) {
$product_cart_id = WC()->cart->generate_cart_id( $product );
$product_ab_in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $product_ab_in_cart ) {
$discount = $cart->subtotal * 0.1;
$cart->add_fee( __( 'Discount', 'woocommerce' ) , -$discount );
}
}
}
Try the following instead, that will make a discount when all defined product ids are in cart (so two in your case):
add_action( 'woocommerce_cart_calculate_fees', 'x_products_discount' );
function x_products_discount( $cart ) {
// Settings below
$product_ids = array(34, 35); // <== Your defined product Ids
$percentage = 10; // <== discount in percentage (10% here)
$found_ids = array();
// Loop through cart items
foreach (WC()->cart->get_cart() as $cart_item ) {
// Loop through defined product Ids
foreach( $product_ids as $product_id ) {
if( in_array( $product_id, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
$found_ids[$product_id] = $product_id;
break;
}
}
}
// Discount part
if( count( $found_ids ) === count( $product_ids ) ) {
$cart->add_fee( __( 'Discount', 'woocommerce' ), -( $cart->subtotal * $percentage / 100 ) );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I Would like to set a custom price when product is added to cart, based on an input hidden field located in the single product page.
I have tried to use this code to change the product price in cart:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = $_POST['_custom_price'];
foreach ( $cart_object->cart_contents as $key => $value ) {
// for WooCommerce version 3+ use:
$value['data']->set_price($custom_price);
}
}
But I get a zero price.
Here is my test page. Any help is appreciated.
Thanks for help but it dosent work...it give an error
this is my function.php
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
if(isset($_POST['_custom_price'] )){
$custom_price = $_POST['_custom_price'];
foreach ( $cart_object->cart_contents as $key => $value ) {
// for WooCommerce version 3+ use:
$value['data']->set_price($custom_price);
$_SESSION['custom_price']=$custom_price;
}
}else{
}
}
// STACK HELP CODE
/*
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_price', 20, 2 );
function add_custom_price( $cart_item_data, $product_id ){
// Only when option is passed through the URL
if( ! isset($_POST['_custom_price']) && empty($_POST['_custom_price']) )
return $cart_item_data;
$cart_item_data['custom_price'] = sanitize_text_field( $_POST['_custom_price'] );
return $cart_item_data;
}
add_action( 'woocommerce_before_calculate_totals', 'set_custom_price' );
function set_custom_price( $cart ) {
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cart_item['custom_price']) ){
$value['data']->set_price($cart_item['custom_price']);
}
}
}
*/
?>
<?php
/*
* Display input on single product page
* #return html
*/
function kia_custom_option(){
$value = isset( $_POST['_custom_option'] ) ? sanitize_text_field( $_POST['_custom_option'] ) : '';
printf( '<label>%s</label><input id="hotel_chambre_selected" name="_custom_option" value="%s" />', __( '', 'kia-plugin-textdomain' ), esc_attr( $value ) );
}
add_action( 'woocommerce_before_add_to_cart_button', 'kia_custom_option', 9 );
/*
* Validate when adding to cart
* #param bool $passed
* #param int $product_id
* #param int $quantity
* #return bool
*/
function kia_add_to_cart_validation($passed, $product_id, $qty){
if( isset( $_POST['_custom_option'] ) && sanitize_text_field( $_POST['_custom_option'] ) == '' ){
$product = wc_get_product( $product_id );
wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter some custom text.', 'kia-plugin-textdomain' ), $product->get_title() ), 'error' );
return false;
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'kia_add_to_cart_validation', 10, 3 );
/*
* Add custom data to the cart item
* #param array $cart_item
* #param int $product_id
* #return array
*/
function kia_add_cart_item_data( $cart_item, $product_id ){
if( isset( $_POST['_custom_option'] ) ) {
$cart_item['custom_option'] = sanitize_text_field( $_POST['_custom_option'] );
}
return $cart_item;
}
add_filter( 'woocommerce_add_cart_item_data', 'kia_add_cart_item_data', 10, 2 );
/*
* Load cart data from session
* #param array $cart_item
* #param array $other_data
* #return array
*/
function kia_get_cart_item_from_session( $cart_item, $values ) {
if ( isset( $values['custom_option'] ) ){
$cart_item['custom_option'] = $values['custom_option'];
}
return $cart_item;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'kia_get_cart_item_from_session', 20, 2 );
/*
* Add meta to order item
* #param int $item_id
* #param array $values
* #return void
*/
function kia_add_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['custom_option'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'custom_option', $values['custom_option'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'kia_add_order_item_meta', 10, 2 );
/*
* Get item data to display in cart
* #param array $other_data
* #param array $cart_item
* #return array
*/
function kia_get_item_data( $other_data, $cart_item ) {
if ( isset( $cart_item['custom_option'] ) ){
$other_data[] = array(
'name' => __( 'Votre chambre ', 'kia-plugin-textdomain' ),
'value' => sanitize_text_field( $cart_item['custom_option'] )
);
}
return $other_data;
}
add_filter( 'woocommerce_get_item_data', 'kia_get_item_data', 10, 2 );
/*
* Show custom field in order overview
* #param array $cart_item
* #param array $order_item
* #return array
*/
function kia_order_item_product( $cart_item, $order_item ){
if( isset( $order_item['custom_option'] ) ){
$cart_item_meta['custom_option'] = $order_item['custom_option'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_item_product', 'kia_order_item_product', 10, 2 );
/*
* Add the field to order emails
* #param array $keys
* #return array
*/
function kia_email_order_meta_fields( $fields ) {
$fields['custom_field'] = __( 'Votre chambre ', 'kia-plugin-textdomain' );
return $fields;
}
add_filter('woocommerce_email_order_meta_fields', 'kia_email_order_meta_fields');
/*
* Order Again
* #param array $cart_item
* #param array $order_item
* #param obj $order
* #return array
*/
function kia_order_again_cart_item_data( $cart_item, $order_item, $order ){
if( isset( $order_item['custom_option'] ) ){
$cart_item_meta['custom_option'] = $order_item['custom_option'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_again_cart_item_data', 'kia_order_again_cart_item_data', 10, 3 );
this is the result of print_r($_POST) in my function
I want to Alter function validate_coupon_minimum_amount() adding a condition that if a user use coupon "refresh18", check to see if subtotal in cart for a product category is greater than the coupon's minimum amount.
How could I do that?
Here is my code below that doesn't work:
function check_minimum_parts_amount_in_cart($coupon) {
$cart_parts_subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
$terms = get_the_terms( $product_id, 'product_cat' );
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) && has_term( 'ice-shaving-parts', 'product_cat', $product_id ) ) {
//echo '<pre>' . print_r($cart_item , 1) . '</pre>';
//echo $cart_item['quantity'];
$cart_parts_subtotal = $cart_parts_subtotal + ( $_product->get_price() * $cart_item['quantity'] );
}
}
$subtotal = wc_remove_number_precision( $this->get_object_subtotal() );
if( $coupon->get_name() == 'refresh2018' ){
if( $coupon->get_minimum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_minimum_amount', $coupon->get_minimum_amount() > $cart_parts_subtotal, $coupon, $cart_parts_subtotal )){
/* translators: %s: coupon minimum amount */
throw new Exception( sprintf( __( 'The minimum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_minimum_amount() ) ), 108 );
}else{
return true;
}
}else{
if ( $coupon->get_minimum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_minimum_amount', $coupon->get_minimum_amount() > $subtotal, $coupon, $subtotal )) {
/* translators: %s: coupon minimum amount */
throw new Exception( sprintf( __( 'The minimum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_minimum_amount() ) ), 108 );
}else{
return true;
}
}
}
add_filter('validate_coupon_minimum_amount', 'check_minimum_parts_amount_in_cart');
Updated:
Since Woocommerce 3.2+ use instead woocommerce_coupon_validate_minimum_amount filter hook… So you should try this revisited code (Where you will have to set your product category):
add_filter( 'woocommerce_coupon_validate_minimum_amount', 'custom_check_minimum_amount_in_cart', 10, 3 );
function custom_check_minimum_amount_in_cart( $valid, $coupon, $subtotal ) {
// HERE below your settings (Coupon code and product category)
$coupon_code = 'refresh18';
$product_category = 'clothing'; // <== To be replaced by your targeted product category
$cat_subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ){
if( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) )
$cat_subtotal += $cart_item['line_subtotal'];
}
if( $coupon->get_code() == $coupon_code && $coupon->get_minimum_amount() > $cat_subtotal ){
throw new Exception( sprintf( __( 'The minimum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_minimum_amount() ) ), 108 );
}
return $valid;
}
This code goes on function.php file of your active child theme (or theme). It should work.
Note: For everybody, remember to set in this function the coupon code in lowercase.