Hooks around add to cart for Woocommerce - php

I am running a WooCommerce store with WC Marketplace. What I am trying to achieve with the hook below is to prevent a new item being added to a basket if there is already a product in the basket from a different vendor. e.g. If a shopper adds product x from vendor y to his basket, if they were to add product a from vendor b, then the item will not be added and the user will be informed of the error.
I have 2 questions:
- firstly when does a hook run, is it before the main function fired or after? I have a hook for the function woocommerce_add_to_cart. So I want to know will the hook fire after the function woocommerce_add_to_cart runs or before.
- My second question is, I have attached the hook below, in your opinion would this work?
function action_woocommerce_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
$same_vendor = 1;
$empty = WC_Cart::is_empty();
//If there is an item in the cart then,
if (!$empty) {
//Get the VendorId of the product being added to the cart.
$vendor = get_wcmp_product_vendors($product_id);
$vendor_id = $vendor->id;
foreach( WC()->cart->get_cart() as $cart_item ) {
//Get the vendor Id of the item
$cart_product_id = $cart_item['product_id'];
$cart_vendor = get_wcmp_product_vendors($product_id);
$cart_vendor_id = $cart_vendor->id;
//If two products do not have the same Vendor then set $same_vendor to 0
if($vendor_id !== $cart_vendor_id) {
$same_vendor = 0;
}
}
if ($same_vendor === 0) {
WC()->cart->remove_cart_item( $cart_item_key );
//How do I show a message to tell the customer.
}
}
}
Regards

Here below are the hooks involved in WC_Cart add_to_cart() method:
A) Before an item is added to cart:
Validation filter hook woocommerce_add_to_cart_validation
Item Quantity change filter hook woocommerce_add_to_cart_quantity (not with ajax)
Item Data change filter hook woocommerce_add_cart_item_data (not with ajax)
and some others related to "sold individually" products (see here)
A) After an item is added to cart:
Change cart Item filter hook woocommerce_add_cart_item
Add an event, action hook woocommerce_add_to_cart
To be clear in your case:
As you can see now woocommerce_add_to_cart is not a function but only an action hook.
Hook location: It's located inside WC_Cart add_to_cart() method (at the end of the source code).
When the hook is fired: It's fired once the WC_Cart add_to_cart() method is executed.
What is the purpose: To execute some custom code when this method is executed (event).
Regarding your code:
It should be better to use the dedicated filter hook woocommerce_add_to_cart_validation that will stop customer that want to add a new item to the cart if there is already a product in cart from a different vendor, displaying optionally a custom message:
add_filter( 'woocommerce_add_to_cart_validation', 'filter_add_to_cart_validation', 10, 3 );
function filter_add_to_cart_validation( $passed, $product_id, $quantity ) {
if ( WC()->cart->is_empty() ) return $passed;
// Get the VendorId of the product being added to the cart.
$current_vendor = get_wcmp_product_vendors($product_id);
foreach( WC()->cart->get_cart() as $cart_item ) {
// Get the vendor Id of the item
$cart_vendor = get_wcmp_product_vendors($cart_item['product_id']);
// If two products do not have the same Vendor
if( $current_vendor->id != $cart_vendor->id ) {
// We set 'passed' argument to false
$passed = false ;
// Displaying a custom message
$message = __( "This is your custom message", "woocommerce" );
wc_add_notice( $message, 'error' );
// We stop the loop
break;
}
}
return $passed;
}
Code goes in function.php file of your active child theme (or active theme) or in any plugin file.
Tested and works.

Related

How do I programatically & DOM (checkout page) remove shipping from a WordPress order if the order contains a specific product type?

I'm trying to do a special logic for my custom plugin. If the user has added a specific product type in their cart, in the checkout page there must be radio inputs that determine whether the user wants the specific product type to be shipped or stored in vault. I've done everything for the frontend part (creating the radio inputs, built the JavaScript logic to remove from the DOM what's not necessary and so on...) but I now need to programatically remove the shipping from the order and remove the "Shipping" row inside the order preview in the checkout page. I tried the following filter
add_filter( 'woocommerce_cart_shipping_method_full_label', 'remove_shipping_labels', 10, 2 );
function remove_shipping_labels( $label, $method ) {
return '';
}
But it's removing just the label text "Free Shipping" but not the entire shipping row inside the order preview in the checkout page. How can I programatically remove the shipping availability from an order through AJAX and update the user interface inside the checkout page?
function hide_shipping_based_on_prod_type( $rates ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach ( $items as $item => $values ) {
$product_id = $values['data']->get_id();
$product_type = WC_Product_Factory::get_product_type( $values['data']->get_id() );
if ( 'simple' === $product_type ) { //check product types of woocommerce to add more conditions
unset( $rates['free_shipping:1'] );
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'hide_shipping_based_on_prod_type', 100 );
add_action(
'after_setup_theme',
function() {
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
);

what is the add to cart hook in woocommerce [duplicate]

I am running a WooCommerce store with WC Marketplace. What I am trying to achieve with the hook below is to prevent a new item being added to a basket if there is already a product in the basket from a different vendor. e.g. If a shopper adds product x from vendor y to his basket, if they were to add product a from vendor b, then the item will not be added and the user will be informed of the error.
I have 2 questions:
- firstly when does a hook run, is it before the main function fired or after? I have a hook for the function woocommerce_add_to_cart. So I want to know will the hook fire after the function woocommerce_add_to_cart runs or before.
- My second question is, I have attached the hook below, in your opinion would this work?
function action_woocommerce_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
$same_vendor = 1;
$empty = WC_Cart::is_empty();
//If there is an item in the cart then,
if (!$empty) {
//Get the VendorId of the product being added to the cart.
$vendor = get_wcmp_product_vendors($product_id);
$vendor_id = $vendor->id;
foreach( WC()->cart->get_cart() as $cart_item ) {
//Get the vendor Id of the item
$cart_product_id = $cart_item['product_id'];
$cart_vendor = get_wcmp_product_vendors($product_id);
$cart_vendor_id = $cart_vendor->id;
//If two products do not have the same Vendor then set $same_vendor to 0
if($vendor_id !== $cart_vendor_id) {
$same_vendor = 0;
}
}
if ($same_vendor === 0) {
WC()->cart->remove_cart_item( $cart_item_key );
//How do I show a message to tell the customer.
}
}
}
Regards
Here below are the hooks involved in WC_Cart add_to_cart() method:
A) Before an item is added to cart:
Validation filter hook woocommerce_add_to_cart_validation
Item Quantity change filter hook woocommerce_add_to_cart_quantity (not with ajax)
Item Data change filter hook woocommerce_add_cart_item_data (not with ajax)
and some others related to "sold individually" products (see here)
A) After an item is added to cart:
Change cart Item filter hook woocommerce_add_cart_item
Add an event, action hook woocommerce_add_to_cart
To be clear in your case:
As you can see now woocommerce_add_to_cart is not a function but only an action hook.
Hook location: It's located inside WC_Cart add_to_cart() method (at the end of the source code).
When the hook is fired: It's fired once the WC_Cart add_to_cart() method is executed.
What is the purpose: To execute some custom code when this method is executed (event).
Regarding your code:
It should be better to use the dedicated filter hook woocommerce_add_to_cart_validation that will stop customer that want to add a new item to the cart if there is already a product in cart from a different vendor, displaying optionally a custom message:
add_filter( 'woocommerce_add_to_cart_validation', 'filter_add_to_cart_validation', 10, 3 );
function filter_add_to_cart_validation( $passed, $product_id, $quantity ) {
if ( WC()->cart->is_empty() ) return $passed;
// Get the VendorId of the product being added to the cart.
$current_vendor = get_wcmp_product_vendors($product_id);
foreach( WC()->cart->get_cart() as $cart_item ) {
// Get the vendor Id of the item
$cart_vendor = get_wcmp_product_vendors($cart_item['product_id']);
// If two products do not have the same Vendor
if( $current_vendor->id != $cart_vendor->id ) {
// We set 'passed' argument to false
$passed = false ;
// Displaying a custom message
$message = __( "This is your custom message", "woocommerce" );
wc_add_notice( $message, 'error' );
// We stop the loop
break;
}
}
return $passed;
}
Code goes in function.php file of your active child theme (or active theme) or in any plugin file.
Tested and works.

Allow specific products to be purchased only if a coupon is applied in Woocommerce

I am working on a woocommerce website and I am trying to restrict a product to be purchased only if a coupon is applied for it, so it should not be processed without adding a coupon code. User must enter a coupon code to be able to order this specific product (not on all other products).
Any help is appreciated.
For defined products, the following code will not allow checkout if a coupon is not applied, displaying an error message:
add_action( 'woocommerce_check_cart_items', 'mandatory_coupon_for_specific_items' );
function mandatory_coupon_for_specific_items() {
$targeted_ids = array(37); // The targeted product ids (in this array)
$coupon_code = 'summer2'; // The required coupon code
$coupon_applied = in_array( strtolower($coupon_code), WC()->cart->get_applied_coupons() );
// Loop through cart items
foreach(WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids and applied coupon
if( in_array( $cart_item['product_id'], $targeted_ids ) && ! $coupon_applied ) {
wc_clear_notices(); // Clear all other notices
// Avoid checkout displaying an error notice
wc_add_notice( sprintf( 'The product"%s" requires a coupon for checkout.', $cart_item['data']->get_name() ), 'error' );
break; // stop the loop
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
And in checkout:

Set a custom cart item price value from a GET variable In Woocommerce 3

I have a function on my Woocommerce website that enables customers to set a custom amount to pay for a specific product, based on a value I'm passing through the URL.
I'm using the woocommerce_before_calculate_totals hook, and up until I upgraded to WC 3.3.5, it was working fine. Now, when I run the code, the checkout initially shows the custom amount.
However, once the loader has finished updating, it resets the price to '0' (i.e. displaying £0.00 the checkout page's total fields).
Here's that code:
add_action( 'woocommerce_before_calculate_totals', 'pay_custom_amount', 99);
function pay_custom_amount() {
$payment_value = $_GET['amount'];
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if($cart_item['data']->id == 21 ){
$cart_item['data']->set_price($payment_value);
}
}
}
Well, colour me baffled. I've trawled Stack Overflow for solutions but can't see any similar problems. I see the hook runs multiple times but gather this is normal.
If anyone know what might be happening here, it would be great if you could share.
You can't get a price from an URL and set it in woocommerce_before_calculate_totals action hook. This needs to be done differently.
In the below code:
the first hooked function will get that "amount" from the URl and will set it (register it) in cart item object as custom data.
the 2nd hooked function will read that amount from custom cart item data and will set it as the new price.
Now your the target product ID in your code need to be the same ID that the added to cart product.
The code:
// Get the custom "amount" from URL and save it as custom data to the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_pack_data_to_cart_item_data', 20, 2 );
function add_pack_data_to_cart_item_data( $cart_item_data, $product_id ){
if( ! isset($_GET['amount']) )
return $cart_item_data;
$amount = esc_attr( $_GET['amount'] );
if( empty($amount) )
return $cart_item_data;
// Set the custom amount in cart object
$cart_item_data['custom_price'] = (float) $amount;
$cart_item_data['unique_key'] = md5( microtime() . rand() ); // Make each item unique
return $cart_item_data;
}
// Alter conditionally cart item price based on product ID and custom registered "amount"
add_action( 'woocommerce_before_calculate_totals', 'change_conditionally_cart_item_price', 30, 1 );
function change_conditionally_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE set your targeted product ID
$targeted_product_id = 21;
foreach ( $cart->get_cart() as $cart_item ) {
// Checking for the targeted product ID and the registered "amount" cart item custom data to set the new price
if($cart_item['data']->get_id() == $targeted_product_id && isset($cart_item['custom_price']) )
$cart_item['data']->set_price($cart_item['custom_price']);
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Which Hook to alter quantity update in WooCommerce cart page?

I'm trying to fire a function when the quantity of a product is changed in cart.
More specifically I want to run this function when a customer modify the amount in a cart.
I'm looking to find the amount left in a cart then to intercept the update cart event
Currently I'm using:
add_action( 'woocommerce_remove_cart_item', 'my function');
When I press "update_cart", it doesn't seem to work.
Any advice?
Thank you!
You should use woocommerce_after_cart_item_quantity_update action hook that has 4 arguments. But when quantity is changed to zero, woocommerce_before_cart_item_quantity_zero action hook need to be used instead (and has 2 arguments).
Below is a working example that will limit the updated quantity to a certain amount and will display a custom notice:
add_action( 'woocommerce_after_cart_item_quantity_update', 'limit_cart_item_quantity', 20, 4 );
function limit_cart_item_quantity( $cart_item_key, $quantity, $old_quantity, $cart ){
if( ! is_cart() ) return; // Only on cart page
// Here the quantity limit
$limit = 5;
if( $quantity > $limit ){
// Change the quantity to the limit allowed
$cart->cart_contents[ $cart_item_key ]['quantity'] = $limit;
// Add a custom notice
wc_add_notice( __('Quantity limit reached for this item'), 'notice' );
}
}
This code goes on function.php file of your active child theme (or theme). Tested and works.
As this hook is located in WC_Cart set_quantity() method, is not possible to use that method inside the hook, as it will throw an error.
To trigger some action when quantity is set to Zero use:
add_action( 'woocommerce_before_cart_item_quantity_zero', 'action_before_cart_item_quantity_zero', 20, 4 );
function action_before_cart_item_quantity_zero( $cart_item_key, $cart ){
// Your code goes here
}
Maybe this hook? do_action( 'woocommerce_after_cart_item_quantity_update', $cart_item_key, $quantity, $old_quantity );
http://hookr.io/actions/woocommerce_after_cart_item_quantity_update/

Categories