I have a script that create a progress bar to show "Spend another XX € for free shipping!" based on a minimal amount to be spent, but I would like to avoid this text if there are ONLY products in cart from a specific product type. This because people could also buy an "Appointment" product, that are not physical products, but are under the custom product type "Appointment".
Here is my current code:
add_filter( 'woocommerce_package_rates', 'ecommercehints_free_shipping_for_specific_products', 10, 2 );
function ecommercehints_free_shipping_for_specific_products($rates, $package, $order) {
// Loop through order items
foreach ( $order->get_items() as $item ) {
// Get an instance of the WC_Product Object from the WC_Order_Item_Product
$product = $item->get_product();
$cart_total = WC()->cart->get_subtotal();
if( $product->is_type('Appointment') ){
echo 'You\'ve unlocked free shipping!';
} else if ( $cart_total < 50 ) {
unset( $rates['free_shipping:21'] ); // The shipping method radio button value
}
break; // We stop the loop and keep the first item
}
return $rates;
}
// Show 'Spend another X amount' on checkout.
add_filter( 'woocommerce_checkout_before_order_review', 'ecommercehints_checkout_page_progress_bar', 10 );
function ecommercehints_checkout_page_progress_bar() {
$cart_total = WC()->cart->get_subtotal();
$cart_remaining = 50 - $cart_total;
$product = $item->get_product();
if ($cart_total < 50 ) {
echo 'Spend another ' . get_woocommerce_currency_symbol() . $cart_remaining . ' for free shipping!<br><progress id="freeshippingprogress" max="50" value="'.$cart_total.'"></progress>';
} else if ( $product->is_type('Appointment') {
echo 'You\'ve unlocked free shipping!';
}
}
There are some mistakes in your code like:
$order
variable doesn't exist for woocommerce_package_rates
filter hook.Also, you need to be sure that "Appointment" is a valid product type. In general, product types are always in lowercase, so I used "appointment" (in lowercase) below.
Try the following revised code:
// Conditional function that checks if there are only "appointment" product types in cart
function has_only_appointments() {
$others_found = false; // Initializing
// Loop through cat items
foreach ( WC()->cart->get_cart() as $item ) {
if ( ! $item['data']->is_type('appointment') ) {
$others_found = true;
break;
}
}
return !$others_found;
}
// Filter shipping methods
add_filter( 'woocommerce_package_rates', 'ecommercehints_free_shipping_for_specific_products', 10, 2 );
function ecommercehints_free_shipping_for_specific_products( $rates, $package ) {
// check if there are only "appointment" product types in cart
if( has_only_appointments() ){
return $rates;
}
// If there is shippable products remove free shipping if cart subtotal is under specific amount
if ( WC()->cart->get_subtotal() < 50 ) {
unset( $rates['free_shipping:21'] ); // The targeted Free shipping method rate ID
}
return $rates;
}
// Show 'Spend another X amount' on checkout.
add_filter( 'woocommerce_checkout_before_order_review', 'ecommercehints_checkout_page_progress_bar', 10 );
function ecommercehints_checkout_page_progress_bar() {
$subtotal = WC()->cart->get_subtotal();
// check if there are only "appointment" product types in cart or If cart subtotal is up to 50
if( has_only_appointments( WC()->cart->get_cart() ) || $subtotal >= 50 ){
echo __("You've unlocked free shipping!", "woocommerce");
} elseif ( $subtotal < 50 ) {
printf( __('Spend another %s for free shipping!', 'woocommerce'), wc_price( 50 - $subtotal ) );
printf('<br><progress id="freeshippingprogress" max="50" value="%d"></progress>', intval($subtotal) );
}
}
It should work…
Important: Empty your cart to refresh the shipping methods cached data.
Addition (for virtual products):
Now as your custom product type "Appointments" is not a "Physical" product, it should be "virtual" by default…
So you can try the following instead:
// Conditional function that checks if there are only virtual products in cart
function has_only_virtual_products() {
$physical_found = false; // Initializing
// Loop through cat items
foreach ( WC()->cart->get_cart() as $item ) {
if ( ! $item['data']->is_virtual() ) {
$others_found = true;
break;
}
}
return !$others_found;
}
// Filter shipping methods
add_filter( 'woocommerce_package_rates', 'ecommercehints_free_shipping_for_specific_products', 10, 2 );
function ecommercehints_free_shipping_for_specific_products( $rates, $package ) {
// check if there are only virtual products in cart
if( has_only_virtual_products() ){
return $rates;
}
// If there is shippable products remove free shipping if cart subtotal is under specific amount
if ( WC()->cart->get_subtotal() < 50 ) {
unset( $rates['free_shipping:21'] ); // The targeted Free shipping method rate ID
}
return $rates;
}
// Show 'Spend another X amount' on checkout.
add_filter( 'woocommerce_checkout_before_order_review', 'ecommercehints_checkout_page_progress_bar', 10 );
function ecommercehints_checkout_page_progress_bar() {
$subtotal = WC()->cart->get_subtotal();
// check if there are only virtual products in cart or If cart subtotal is up to 50
if( has_only_virtual_products() || $subtotal >= 50 ){
echo __("You've unlocked free shipping!", "woocommerce");
} elseif ( $subtotal < 50 ) {
printf( __('Spend another %s for free shipping!', 'woocommerce'), wc_price( 50 - $subtotal ) );
printf('<br><progress id="freeshippingprogress" max="50" value="%d"></progress>', intval($subtotal) );
}
}
It could work…
Important: Empty your cart to refresh the shipping methods cached data.