Change Shipping total in woocommerce Programmatically [duplicate] - php

I currently charge a flat fee for shipping using the default WooCommerce shipping setup. I want to offer free shipping for the entire order if the user purchases "x" products from a single category. I have some code that I put together but I need a bit of help to get it working.
// Free shipping if you purchase 12 or more from selected category
function wcs_my_free_shipping( $is_available ) {
global $woocommerce;
// HERE set your product categories in the array (can be IDs, slugs or names)
$categories = array('t-shirts');
// Initializing
$found = false;
$count = 0;
// 1st Loop: get category items count
foreach ( WC()->cart->get_cart() as $cart_item ) {
// If product categories is found
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$count += $cart_item['quantity'];
}
}
// get cart contents
$cart_items = $woocommerce->cart->get_cart();
// loop through the items looking for one in the eligible array
foreach ( $cart_items as $key => $item ) {
if( in_array( $item['product_id'], $eligible ) ) {
return true;
}
}
if ( $count > 11 ) {
// Apply free shipping
$shipping = 0;
}
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'wcs_my_free_shipping', 20 );

The use of 2 loops is not necessary
Take into account the product quantity per product
comment with explanation added in the code
function filter_woocommerce_shipping_free_shipping_is_available( $is_available, $package, $shipping_method ) {
// Set categories
$categories = array ( 't-shirts' );
// Set minimum
$minimum = 12;
/* END settings */
// Counter
$count = 0;
// Loop through cart items
foreach( $package['contents'] as $cart_item ) {
// If product categories is found
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$count += $cart_item['quantity'];
}
}
// Condition
if ( $count >= $minimum ) {
$notice = __( 'free shipping', 'woocommerce' );
$is_available = true;
} else {
$notice = __( 'NO free shipping', 'woocommerce' );
$is_available = false;
}
// Display notice
if ( isset( $notice ) ) {
wc_add_notice( $notice, 'notice' );
}
// Return
return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'filter_woocommerce_shipping_free_shipping_is_available', 10, 3 );
Additional question: hide other shipping methods when free shipping is available
function filter_woocommerce_package_rates( $rates, $package ) {
// Set categories
$categories = array ( 't-shirts' );
// Set minimum
$minimum = 11;
/* END settings */
// Counter
$count = 0;
// Loop through line items
foreach( $package['contents'] as $line_item ) {
// Get product id
$product_id = $line_item['product_id'];
// Check for category
if ( has_term( $categories, 'product_cat', $product_id ) ) {
$count += $line_item['quantity'];
}
}
// Condition
if ( $count > $minimum ) {
// Set
$free = array();
// Loop
foreach ( $rates as $rate_id => $rate ) {
// Rate method id = free shipping
if ( $rate->method_id === 'free_shipping' ) {
$free[ $rate_id ] = $rate;
break;
}
}
}
return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );
Based on:
How to disable shipping method based on item count and a certain category
WooCommerce - Hide other shipping methods when FREE SHIPPING is available

Related

How to add fees based on product categories and quantity in WooCommerce

I have some product in WooCommerce and two categories are:
Name: ORG Test
Slug: org-test
Name: ORG Prod
Slug: org-prod
I want to calculate shipping fee per quantity ($15 per quantity) if the product matches org-prod category:
My code attempt:
add_action('woocommerce_cart_calculate_fees', 'add_fees_on_ids');
function add_fees_on_ids() {
$total_act_fee = 0;
$business_plan_exist = false;
if (is_admin() && !defined('DOING_AJAX')) {return;}
foreach( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$quantity = $cart_item['quantity'];
$categories = wc_get_product_category_list( $product->get_id() );
if (strstr($categories, 'org-prod')) {
$business_plan_exist = true;
$total_act_fee = $total_act_fee + 15;
}
if ($business_plan_exist) {
WC()->cart->add_fee(__('Shipping Fees '), $total_act_fee);
}
}
}
But this does not give the desired result. The fee is applied but the total is wrong? Can you assist in figuring out why not?
Your code contains some mistakes and/or could be optimized:
When calculating the totals, you do not take into account the quantity
Your if condition for adding the fee, is in your foreach loop, so it is overwritten every loop
The use of WC()->cart is not necessary, as $cart is already passed to the callback function
Use has_term() versus wc_get_product_category_list() and strstr()
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$categories = array( 'org-prod', 'categorie-1', 83 );
// Initialize
$total_act_fee = 0;
$amount = 15;
// Gets cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
// Has certain category
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
// Get quantity
$quantity = $cart_item['quantity'];
// Addition to the total
$total_act_fee += $amount * $quantity;
}
}
// Greater than
if ( $total_act_fee > 0 ) {
// Add fee
$cart->add_fee( __( 'Shipping Fees', 'woocommerce' ), $total_act_fee, true );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

How to add woocommerce product in cart based on subtotal and categories

I am creating a woocommerce function that allows me to add a specific product to the cart based on the following conditions:
specific categories
total cost of the products higher than a value that I have defined
in $ min_price
I was able to get that based on the category, woocommerce adds the indicated product.
Unfortunately I can't describe the flow that does this when the total value of the products is higher than the $ min_price.
Can anyone help me? Thanks
add_action( 'woocommerce_before_calculate_totals', 'auto_add_item_based_on_product_category', 10, 1 );
function auto_add_item_based_on_product_category( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$min_price = 77.47; // The minimal cart amount
$required_categories = array('computer-based', 'esami-paper-based'); // Required product category(ies)
$added_product_id = 5065; // Specific product to be added automatically
$matched_category = false;
$matched_subtotal = false;
// Loop through cart items
foreach ( $cart->get_cart() as $item_key => $item ) {
// Check for product category
if( has_term( $required_categories, 'product_cat', $item['product_id'] ) ) {
$matched_category = true;
}
// Check if specific product is already auto added
if( $item['data']->get_id() == $added_product_id ) {
$saved_item_key = $item_key; // keep cart item key
}
// Check it the minimum subtotal is reached
if ( !empty( $product_subtotal > $min_price ) ) {
$matched_subtotal = true;
}
}
// If specific product is already auto added but without items from product category and minimun subtotal is not reached
if ( isset($saved_item_key) && ! $matched_category && ! $matched_subtotal ) {
$cart->remove_cart_item( $saved_item_key ); // Remove specific product
}
// If there is an item from defined product category and subtotal reached and specific product is not in cart
elseif ( ! isset($saved_item_key) && $matched_category && $matched_subtotal ) {
$cart->add_to_cart( $added_product_id ); // Add specific product
}
}
please check below code works for me. I am just a beginner in this
add_action( 'woocommerce_check_cart_items', 'check_cart_outlet_items' );
function check_cart_outlet_items() {
$categories = array('computer-based', 'esami-paper-based'); // Defined targeted product categories
$threshold = 500; // Defined threshold amount
$added_product_id = 24589; // Incentive product we are giving away
$product_id = 24589;
///$added_product_id = WC()->cart->generate_cart_id( $free_product ); //
(equivalent to $prod_unique_id)
$cart = WC()->cart;
$cart_items = $cart->get_cart();
$subtotal = $cart->subtotal;
$subtotal += $item['line_total'] + $item['line_tax'];
$found = false;
foreach( $cart_items as $cart_item_key => $cart_item ) {
// Check for specific product categories
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true; // A category is found
break; // Stop the loop
}
}
if ( $found && $subtotal < $threshold ) {
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $cart_item_key ) WC()->cart->remove_cart_item( $cart_item_key );
}
elseif ($found && $subtotal > $threshold )
{
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
if ( !($cart_item_key) ){
$cart->add_to_cart( $added_product_id ); // Add specific product
}
}
}

Offer free shipping if user purchases "x" products from a single category

I currently charge a flat fee for shipping using the default WooCommerce shipping setup. I want to offer free shipping for the entire order if the user purchases "x" products from a single category. I have some code that I put together but I need a bit of help to get it working.
// Free shipping if you purchase 12 or more from selected category
function wcs_my_free_shipping( $is_available ) {
global $woocommerce;
// HERE set your product categories in the array (can be IDs, slugs or names)
$categories = array('t-shirts');
// Initializing
$found = false;
$count = 0;
// 1st Loop: get category items count
foreach ( WC()->cart->get_cart() as $cart_item ) {
// If product categories is found
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$count += $cart_item['quantity'];
}
}
// get cart contents
$cart_items = $woocommerce->cart->get_cart();
// loop through the items looking for one in the eligible array
foreach ( $cart_items as $key => $item ) {
if( in_array( $item['product_id'], $eligible ) ) {
return true;
}
}
if ( $count > 11 ) {
// Apply free shipping
$shipping = 0;
}
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'wcs_my_free_shipping', 20 );
The use of 2 loops is not necessary
Take into account the product quantity per product
comment with explanation added in the code
function filter_woocommerce_shipping_free_shipping_is_available( $is_available, $package, $shipping_method ) {
// Set categories
$categories = array ( 't-shirts' );
// Set minimum
$minimum = 12;
/* END settings */
// Counter
$count = 0;
// Loop through cart items
foreach( $package['contents'] as $cart_item ) {
// If product categories is found
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$count += $cart_item['quantity'];
}
}
// Condition
if ( $count >= $minimum ) {
$notice = __( 'free shipping', 'woocommerce' );
$is_available = true;
} else {
$notice = __( 'NO free shipping', 'woocommerce' );
$is_available = false;
}
// Display notice
if ( isset( $notice ) ) {
wc_add_notice( $notice, 'notice' );
}
// Return
return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'filter_woocommerce_shipping_free_shipping_is_available', 10, 3 );
Additional question: hide other shipping methods when free shipping is available
function filter_woocommerce_package_rates( $rates, $package ) {
// Set categories
$categories = array ( 't-shirts' );
// Set minimum
$minimum = 11;
/* END settings */
// Counter
$count = 0;
// Loop through line items
foreach( $package['contents'] as $line_item ) {
// Get product id
$product_id = $line_item['product_id'];
// Check for category
if ( has_term( $categories, 'product_cat', $product_id ) ) {
$count += $line_item['quantity'];
}
}
// Condition
if ( $count > $minimum ) {
// Set
$free = array();
// Loop
foreach ( $rates as $rate_id => $rate ) {
// Rate method id = free shipping
if ( $rate->method_id === 'free_shipping' ) {
$free[ $rate_id ] = $rate;
break;
}
}
}
return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );
Based on:
How to disable shipping method based on item count and a certain category
WooCommerce - Hide other shipping methods when FREE SHIPPING is available

Add fee based on product category and shipping method WooCommerce

I'm trying to add a fee of £3 per product if any of the products in the basket have the category ID "160".
This is working great but I also only want this fee to apply if certain shipping methods are chosen.
What I have so far:
function df_add_ticket_surcharge( $cart_object ) {
global $woocommerce;
$specialfeecat = 160; // category id for the special fee
$spfee = 3.00; // initialize special fee
$spfeeperprod = 3.00; //special fee per product
foreach ( $cart_object->cart_contents as $key => $value ) {
$proid = $value['product_id']; //get the product id from cart
$quantiy = $value['quantity']; //get quantity from cart
$itmprice = $value['data']->price; //get product price
$terms = get_the_terms( $proid, 'product_cat' ); //get taxonamy of the prducts
if ( $terms && ! is_wp_error( $terms ) ) :
foreach ( $terms as $term ) {
$catid = $term->term_id;
if($specialfeecat == $catid ) {
$spfee = $spfee * $quantiy;
}
}
endif;
}
if($spfee > 0 ) {
$woocommerce->cart->add_fee( 'Ticket Concierge Charge', $spfee, true, 'standard' );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'df_add_ticket_surcharge' );
I have tried integrating the function from this post: https://stackoverflow.com/a/47732732/12019310 but can't seem to get it functioning without a critical notice.
Any advice would be greatly appreciated!
The following code
add A fee of 3 per product in the basket if it belongs to the category ID "160"
If "local_pickup" is chosen
function df_add_ticket_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
$chosen_shipping_method = explode(':', $chosen_shipping_method_id)[0];
/* SETTINGS */
$special_fee_cat = 160; // category id for the special fee
$fee_per_prod = 3; //special fee per product
/* END SETTINGS */
// Total
$total = 0;
// Only for Local pickup chosen shipping method
if ( strpos( $chosen_shipping_method_id, 'local_pickup' ) !== false ) {
// Loop though each cart items and set prices in an array
foreach ( $cart->get_cart() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Quantity
$product_quantity = $cart_item['quantity'];
// Check for category
if ( has_term( $special_fee_cat, 'product_cat', $product_id ) ) {
$total += $fee_per_prod * $product_quantity;
}
}
// Add the discount
$cart->add_fee( __('Ticket Concierge Charge', 'woocommerce'), $total );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'df_add_ticket_surcharge', 10, 1 );
This post served me fully, but the script did not work for me if I have other cities with fixed shipping costs.
so this worked for me!
add_action( 'woocommerce_cart_calculate_fees','custom_pcat_fee');
function custom_pcat_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
$chosen_shipping_method = explode(':', $chosen_shipping_method_id)[0];
// Set HERE your categories (can be term IDs, slugs or names) in a coma separated array
$categories = array('181');
$fee_amount = 0;
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
if( has_term( $categories, 'product_cat', $cart_item['product_id']) )
$fee_amount = 35000;
}
// Only for Local pickup chosen shipping method
if ( strpos( $chosen_shipping_method_id, 'flat_rate' ) !== false || strpos( $chosen_shipping_method_id, 'filters_by_cities_shipping_method' ) !== false ) {
// Loop though each cart items and set prices in an array
foreach ( $cart->get_cart() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Quantity
$product_quantity = $cart_item['quantity'];
// Check for category
if ( has_term( $special_fee_cat, 'product_cat', $product_id ) ) {
$total += $fee_per_prod * $product_quantity;
}
}
// Adding the fee
if ( $fee_amount > 0 ){
// Last argument is related to enable tax (true or false)
WC()->cart->add_fee( __( "Costo de trasteo de mobiliario", "woocommerce" ), $fee_amount, false );
}
}
}

Add Variable product into cart automatically when cart total is more than 25

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;
}

Categories