Edit my Add to cart button for variable product - wordpress

I have three versions of this code in my site to product 3 buttons ( 1x quantity, 3x quantity and 10x quantity). My products are variable. The code didn't work until I removed this line if( ! $product->is_type('simple') ) return; . With this line removed, should it be replaced with something else for variable products to ensure the code is complete properly?
add_action( 'woocommerce_after_add_to_cart_button', 'additional_simple_add_to_cart_10', 20 );
function additional_simple_add_to_cart_10() {
global $product;
// Only for simple product type
if( ! $product->is_type('simple') ) return; // Removed this line
$href = '?add-to-cart=' . esc_attr( $product->get_id() ) . '&quantity=10';
$class = 'ingle_add_to_cart_button-10 button alt';
$style = 'display: inline-block; margin-top: 12px;';
$button_text = __( "10 Tickets", "woocommerce" );
// Output
echo '<br><a rel="no-follow" href="'.$href.'" class="'.$class.'" style="'.$style.'">'.$button_text.'</a>';
}
// Redirect to checkout after add to basket
add_filter( 'woocommerce_add_to_cart_redirect', 'misha_skip_cart_redirect_checkout' );
function misha_skip_cart_redirect_checkout( $url ) {
return wc_get_checkout_url();
}

Related

Woocommerce product with custom price based on custom fields [duplicate]

In Woocommerce, I used jQuery to calculate a custom price on a single product pages, and now need to pass this value to the cart.
The desired behavior is to pass the new price retrieved from the hidden field to the cart item price.
Here is my actual code:
// Hidden input field in single product page
add_action( 'woocommerce_before_add_to_cart_button', 'custom_hidden_product_field', 11, 0 );
function custom_hidden_product_field() {
echo '<input type="hidden" id="hidden_field" name="custom_price" class="custom_price" value="">';
}
// The code to pass this data to the cart:
add_action( 'woocommerce_add_cart_item_data', 'save_custom_fields_data_to_cart', 10, 2 );
function save_custom_fields_data_to_cart( $cart_item_data, $product_id ) {
if( ! empty( $_REQUEST['custom_price'] ) ) {
// Set the custom data in the cart item
$cart_item_data['custom_data']['custom_price'] = $_REQUEST['custom_price'];
$data = array( 'custom_price' => $_REQUEST['custom_price'] );
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_data', $data );
}
return $cart_item_data;
}
And check both $data and $cart_item_data to see that they both return the custom_price data that is calculated on the page.
However, I go to view cart, and the value of the line item is still 0.
I set a var equal to the WC()->session->set( 'custom_data', $data ); and then var_dump to check it, but this returns NULL which might just be what it returns, I'm not entirely sure because I've never used it.
I should also add that I have the regular_price in the product backend set to 0. When I erase this (and leave it blank) I get back the error:
Warning: A non-numeric value encountered in
C:\xampp\htdocs\my-transfer-source\wp-content\plugins\woocommerce\includes\class-wc-discounts.php on line 85
I'm wondering if I've missed something here, and if someone could lend some light onto this? Thanks
Update 2021 - Handling custom price item in mini cart
First for testing purpose we add a price in the hidden input field as you don't give the code that calculate the price:
// Add a hidden input field (With a value of 20 for testing purpose)
add_action( 'woocommerce_before_add_to_cart_button', 'custom_hidden_product_field', 11 );
function custom_hidden_product_field() {
echo '<input type="hidden" id="hidden_field" name="custom_price" class="custom_price" value="20">'; // Price is 20 for testing
}
Then you will use the following to change the cart item price (WC_Session is not needed):
// Save custom calculated price as custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_fields_data_to_cart', 10, 2 );
function save_custom_fields_data_to_cart( $cart_item_data, $product_id ) {
if( isset( $_POST['custom_price'] ) && ! empty( $_POST['custom_price'] ) ) {
// Set the custom data in the cart item
$cart_item_data['custom_price'] = (float) sanitize_text_field( $_POST['custom_price'] );
// Make each item as a unique separated cart item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
// For mini cart
add_action( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
if ( isset($cart_item['custom_price']) ) {
$args = array( 'price' => floatval( $cart_item['custom_price'] ) );
if ( WC()->cart->display_prices_including_tax() ) {
$product_price = wc_get_price_including_tax( $cart_item['data'], $args );
} else {
$product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
}
return wc_price( $product_price );
}
return $price;
}
// Updating cart item price
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price', 30, 1 );
function change_cart_item_price( $cart ) {
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Set the new price
if( isset($cart_item['custom_price']) ){
$cart_item['data']->set_price($cart_item['custom_price']);
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Remove a category or categories from Breadcrumbs Woocommerce [duplicate]

Please pardon me if there's a better way to do this as I am not very familiar with this code. I would like to display only the link to the homepage and the current product on the breadcrumb.
Desire result:
Currently:
I found the code for the breadcrumb, is there a way to only display the first and last crumb regardless of the hierarchy?
foreach ( $breadcrumb as $key => $crumb ) {
echo $before;
if ( ! empty( $crumb[1] ) && sizeof( $breadcrumb ) !== $key ) {
echo '' . esc_html( $crumb[0] ) . '';
} else if(!is_product() && !flatsome_option('wc_category_page_title')) {
echo esc_html( $crumb[0] );
}
echo $after;
// Single product or Active title
if(is_product() || flatsome_option('wc_category_page_title')){
$key = $key+1;
if ( sizeof( $breadcrumb ) > $key) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
} else{
// Category pages
if ( sizeof( $breadcrumb ) !== $key + 1 ) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
}
}
The reason why I am doing this is that some of the products have multiple categories and by default, it will only show the breadcrumb for the primary category. I would rather make a truncated version as suggested by the owner.
I was also wondering if I can simply dynamically retrieve the product title and link + static homepage link, make it into a shortcode so that I can paste it in the product page.
Hi – the first example in the answer above, also removes the shop from woocommerce breadcrumb. Here is a working example, that only removes the category:
// remove only the category from woocommerce breadcrumbs
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
//print the array and look for the key with the category
//echo '<pre>';
//print_r($crumbs);
//echo '</pre>';
//unset($crumbs[2]); in my case it is key 2
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
} else {
unset($crumbs[2]); // this isn't enough, it would leave a trailing delimiter
$newBreadC = array_values($crumbs); //therefore create new array
return $newBreadC; //return the new array
}
}
If you want to remove categories and subcategories from product breadcrumbs on the product page you can use the woocommerce_get_breadcrumb hook.
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.
A good alternative is to set the primary product category for each product. You can do this by installing the Yoast SEO plugin.
You can use the _yoast_wpseo_primary_product_cat product meta to set the id of the primary product category.
After setting the primary category id by editing the product in the
backend or importing a .csv file you will only need to change the
permalink and breadcrumbs based on the primary product category.
To update the product permalink:
// update the product permalink based on the primary product category
add_filter( 'wc_product_post_type_link_product_cat', 'change_product_permalink_by_cat', 10, 3 );
function change_product_permalink_by_cat( $term, $terms, $post ) {
// get the primary term as saved by Yoast
$primary_cat_id = get_post_meta( $post->ID, '_yoast_wpseo_primary_product_cat', true );
// if there is a primary and it's not currently chosen as primary
if ( $primary_cat_id && $term->term_id != $primary_cat_id ) {
// find the primary term in the term list
foreach ( $terms as $term_key => $term_object ) {
if ( $term_object->term_id == $primary_cat_id ) {
// return this as the primary term
$term = $terms[ $term_key ];
break;
}
}
}
return $term;
}
To update the product breadcrumbs on the product page:
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
global $product;
$new_crumbs = array();
if ( $product->get_meta( '_yoast_wpseo_primary_product_cat', true ) ) {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the id of the primary product category
$primary_cat_id = $product->get_meta( '_yoast_wpseo_primary_product_cat', true );
// create an array with all parent categories (based on the id of the primary product category)
$parent_categories = get_ancestors( $primary_cat_id, 'product_cat' );
$parent_categories = array_reverse($parent_categories);
$parent_categories[] = $primary_cat_id;
// for each product category it gets the name and the permalink
foreach ( $parent_categories as $cat_id ) {
$term = get_term_by( 'id', $cat_id, 'product_cat' );
$new_crumbs[] = array(
0 => $term->name,
1 => esc_url( get_term_link( $term, 'product_cat' ) )
);
}
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
} else {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
}
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.

Show the name of the chosen variation under the product title on the My Account > Downloads page

By default WooCommerce shows the attribute of a variable product in the title and I'm using this code to show the attribute below the title in the cart and checkout pages:
add_filter( 'woocommerce_product_variation_title_include_attributes', '__return_false' );
add_filter( 'woocommerce_is_attribute_in_product_name', '__return_false' );
But that doesn't work in My Account page, users see the full product name with no attribute.
To fix it I'm using the code below to show the attribute in the product title:
function show_attributes_outside_title_1( $enabled ) {
if ( !is_account_page() ) {
$enabled = false;
}
return $enabled;
}
add_filter( 'woocommerce_product_variation_title_include_attributes', 'show_attributes_outside_title_1' );
function show_attributes_outside_title_2( $enabled ) {
if ( !is_account_page() ) {
$enabled = false;
}
return $enabled;
}
add_filter( 'woocommerce_is_attribute_in_product_name', 'show_attributes_outside_title_2' );
But I'd like to show the attribute below the title (or a new column), it's easier to read and goes with the same desing you see in the cart and checkout pages.
There is some confusion in the initial part of the question.
You say you want to show the attribute under the product title on the cart and checkout page but then return __return_false, do you intend to do the opposite?
SOLUTION #1
You may want to reverse the check to make sure that your chosen product variation attribute is shown under the product name on your account page under Downloads (as evidenced by your comment above):
add_filter( 'woocommerce_product_variation_title_include_attributes', '__return_false' );
add_filter( 'woocommerce_is_attribute_in_product_name', '__return_false' );
add_filter( 'woocommerce_product_variation_title_include_attributes', 'show_attributes_outside_title_1' );
function show_attributes_outside_title_1( $enabled ) {
if ( is_account_page() ) {
$enabled = true;
}
return $enabled;
}
add_filter( 'woocommerce_is_attribute_in_product_name', 'show_attributes_outside_title_2' );
function show_attributes_outside_title_2( $enabled ) {
if ( ! is_account_page() ) {
$enabled = false;
}
return $enabled;
}
SOLUTION #2
If you want to leave the code in your question unchanged you can use the woocommerce_account_downloads_column_download-product hook where download-product is the id of the product name column (in the /my-account/downloads/ page). Here the documentation.
Finally, with the wc_get_formatted_variation function you can get the name of the chosen variation. For more information on parameters read the documentation.
// shows the variation chosen in the product name in the download table of the my-account page
add_action( 'woocommerce_account_downloads_column_download-product', 'change_product_download_name', 10, 1 );
function change_product_download_name( $download ) {
// gets the product object
$product = wc_get_product( $download['product_id'] );
// gets the name of the produc
$product_name = $download['product_name'];
// if the product is a variation
if ( $product->is_type( 'variation' ) ) {
// gets the name of the product with the chosen variation
$product_name = $product->get_name() . " - " . wc_get_formatted_variation( $product, true, false, false );
}
// print the product name (with or without product url)
if ( $download['product_url'] ) {
echo '' . esc_html( $product_name ) . '';
} else {
echo esc_html( $product_name );
}
}
The code has been tested and works. Add it to your active theme's functions.php.
I changed Vincenzo's answer a bit to make it look the same way I see the attributes in my Cart and Checkout pages. Here's the code in case anybody else needs it:
// Shows the variation chosen in the product name in the download table of the my-account page
add_action( 'woocommerce_account_downloads_column_download-product', 'change_product_download_name', 10, 1 );
function change_product_download_name( $download ) {
// gets the product object
$product = wc_get_product( $download['product_id'] );
// gets the name of the product
$product_name = $download['product_name'];
// define variable
$product_attributes = '';
// if the product is a variation
if ( $product->is_type( 'variation' ) ) {
// gets the name of the product with the chosen variation
$product_name = $product->get_name();
$product_attributes = wc_get_formatted_variation( $product, true, true, false );
}
// print the product name (with or without product url)
if ( $download['product_url'] ) {
echo '' . esc_html( $product_name ) . '<p>' . esc_html( $product_attributes ) . '</p>';
} else {
echo esc_html( $product_name ) . '<p>' . esc_html( $product_attributes ) . '</p>';
}
}
// Shows variation outside title in cart and checkout pages
add_filter( 'woocommerce_product_variation_title_include_attributes', '__return_false' );
add_filter( 'woocommerce_is_attribute_in_product_name', '__return_false' );
The last two filters replace my code and the first part solves the issue in the Downloads page.

Add "sub-total" to my-account/orders table

Trying to add the order subtotal in woocommerce my-account/orders table but I can't seem to get it to display. Currently it adds the column and the label but its not displaying the orders sub total. I am currently using the code below :
add_filter( 'woocommerce_account_orders_columns',
'add_account_orders_column', 10, 1 );
function add_account_orders_column( $columns ){
$columns['item_subtotal_tax_excl'] = __( 'Sub-total', 'woocommerce' );
return $columns;
}
add_action( 'woocommerce_my_account_my_orders_column_custom-column',
'add_account_orders_column_rows' );
function add_account_orders_column_rows( $order ) {
// Example with a custom field
if ( $value = $order->get_meta( 'item_subtotal_tax_excl' ) ) {
echo esc_html( $value );
}
}
Subtotal like in cart doesn't exist in WooCommerce Orders meta data, so you need to get it and calculate it from order items:
add_filter( 'woocommerce_account_orders_columns', 'add_account_orders_column', 10, 1 );
function add_account_orders_column( $columns ){
$columns['item_subtotal_tax_excl'] = __( 'Sub-total', 'woocommerce' );
return $columns;
}
add_action( 'woocommerce_my_account_my_orders_column_custom-column', 'display_account_orders_column_rows_value' );
function display_account_orders_column_rows_value( $order ) {
$subtotal = 0; // Initializing
// Loop through order items (line items)
foreach ( $order->get_items() as $item ) {
// Sum item subtotal excluding taxes and not discounted
$subtotal += $item->get_subtotal();
}
echo $subtotal;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related:
Get Order items and WC_Order_Item_Product in WooCommerce 3
How to get WooCommerce order details
Get the metadata of an order item in woocommerce 3
Edit: the following code worked for me: (answer provided by helgatheviking on woocommerce slack)
//show sub total in order page
add_filter( 'woocommerce_account_orders_columns',
'add_account_orders_column', 10, 1 );
function add_account_orders_column( $columns ){
$columns['item_subtotal_tax_excl'] = __( 'Sub-Total',
'woocommerce' );
return $columns;
}
add_action(
'woocommerce_my_account_my_orders_column_item_subtotal_tax_excl',
'add_account_orders_column_rows' );
function add_account_orders_column_rows( $order ) {
// Example with a custom field
if ( $value = $order->get_subtotal() ) {
echo esc_html( $value );
}
}

Disable Place Order button conditionally in Woocommerce

I have some code in a function that displays a message to the end user when the total added value of a custom field exceeds a certain value. Basically its a message telling the customer that they have ordered too much furniture to fit into a 68m3 container.
I also have code which is suppose to disable the add to cart button on products - this doesn't seem to work.
So is there a visible issue in the code below to disable the add to cart button when my custom field total value exceeds 68 and is there a way to totally disable the submit order so it's not possible to submit the order until the value of the custom field total is below 68?
The code to display the message is as follows and works fine.
// display message when cart volume exceeds 68mcube
add_action('woocommerce_before_calculate_totals', 'display_custom_notice',
50, 1);
function display_custom_notice( $cart ) {
if ( is_admin() && !defined('DOING_AJAX') )
return;
$total_volume = 0;
// Loop through cart items and calculate total volume
foreach( WC()->cart->get_cart() as $cart_item ){
$product_volume = (float) get_post_meta( $cart_item['product_id'],
'_item_volume', true );
$total_volume += $product_volume * $cart_item['quantity'];
}
if( $total_volume > 68 && $total_volume != 0 ){
// Display a custom notice
wc_add_notice( __("Note: Your order total volume has reached a full 40ft
container - 68 m3 - Please submit order with volume no greater than 68m3",
"woocommerce"), 'notice' );
}
}
The function below are not appearing to work
// function to disable add to cart when volume exceeds 68m3
function get_total_volume(){
$total_volume = 0;
// Loop through cart items and calculate total volume
foreach( WC()->cart->get_cart() as $cart_item ){
$product_volume = (float) get_post_meta( $cart_item['product_id'],
'_item_volume', true );
$total_volume += $product_volume * $cart_item['quantity'];
}
return $total_volume;
}
// Replacing the button add to cart by a link to the product in Shop and
archives pages
add_filter( 'woocommerce_loop_add_to_cart_link',
'replace_loop_add_to_cart_button', 10, 2 );
function replace_loop_add_to_cart_button( $button, $product ) {
if( get_total_volume() > 68 ){
$button_text = __( "View product", "woocommerce" );
$button = '<a class="button" href="' . $product->get_permalink() . '">'
. $button_text . '</a>';
}
return $button;
}
add_action( 'woocommerce_single_product_summary',
'remove_add_to_cart_button', 1 );
function remove_add_to_cart_button() {
// Only when total volume is up to 68
if( get_total_volume() <= 68 ) return;
global $product;
// For variable product types (keeping attribute select fields)
if( $product->is_type( 'variable' ) ) {
remove_action( 'woocommerce_single_variation',
'woocommerce_single_variation_add_to_cart_button', 20 );
add_action( 'woocommerce_single_product_summary',
'innactive_add_to_cart_button', 20 );
}
// For all other product types
else {
remove_action( 'woocommerce_single_product_summary',
'woocommerce_template_single_add_to_cart', 30 );
add_action( 'woocommerce_single_product_summary',
'innactive_add_to_cart_button', 30 );
}
}
To replace "Place Order" button in checkout page when total cart volume exceed 68 m3 we will need to use your utility function get_total_volume() in the following code:
// Utility function to disable add to cart when volume exceeds 68m3
function get_total_volume(){
$total_volume = 0;
// Loop through cart items and calculate total volume
foreach( WC()->cart->get_cart() as $cart_item ){
$product_volume = (float) get_post_meta( $cart_item['product_id'], '_item_volume', true );
$total_volume += $product_volume * $cart_item['quantity'];
}
return $total_volume;
}
// Replacing the Place order button when total volume exceed 68 m3
add_filter( 'woocommerce_order_button_html', 'replace_order_button_html', 10, 2 );
function replace_order_button_html( $order_button ) {
// Only when total volume is up to 68
if( get_total_volume() <= 68 ) return $order_button;
$order_button_text = __( "Max volume reached", "woocommerce" );
$style = ' style="color:#fff;cursor:not-allowed;background-color:#999;"';
return '<a class="button alt"'.$style.' name="woocommerce_checkout_place_order" id="place_order" >' . esc_html( $order_button_text ) . '</a>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
When total volume exceed 68 m3, you will get an inactive custom button instead:
Check that the utility function get_total_volume() is defined only once, to avoid errors…
Now, to disable add to cart buttons, there is some missing things in your code like the function inactive_add_to_cart_button() and other little things… Try this:
// display message when cart volume exceeds 68mcube
add_action('woocommerce_before_calculate_totals', 'display_custom_notice', 50, 1);
function display_custom_notice( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$total_volume = 0;
// Loop through cart items and calculate total volume
foreach( WC()->cart->get_cart() as $cart_item ){
$product_volume = (float) get_post_meta( $cart_item['product_id'], '_item_volume', true );
$total_volume += $product_volume * $cart_item['quantity'];
}
if( $total_volume > 68 && $total_volume != 0 ){
// Display a custom notice
wc_clear_notices();
wc_add_notice( __("Note: Your order total volume has reached a full 40ft container - 68 m3 - Please submit order with volume no greater than 68m3", "woocommerce"), 'notice' );
}
}
// Utility function to disable add to cart when volume exceeds 68m3
function get_total_volume(){
$total_volume = 0;
// Loop through cart items and calculate total volume
foreach( WC()->cart->get_cart() as $cart_item ){
$product_volume = (float) get_post_meta( $cart_item['product_id'], '_item_volume', true );
$total_volume += $product_volume * $cart_item['quantity'];
}
return $total_volume;
}
// Replacing the button add to cart by a link to the product in Shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_link', 'replace_loop_add_to_cart_button', 10, 2 );
function replace_loop_add_to_cart_button( $button, $product ) {
// Only when total volume is up to 68
if( get_total_volume() <= 68 ) return $button;
$small_text = '<br><em style="font-size:85%;">(' . __( "Max volume reached", "woocommerce" ) . ')</em>';
$button_text = __( "View product", "woocommerce" ) . $small_text;
return '<a class="button" href="' . $product->get_permalink() . '">' . $button_text . '</a>';
}
// Replacing the button add to cart by an inactive button on single product pages
add_action( 'woocommerce_single_product_summary', 'remove_add_to_cart_button', 1 );
function remove_add_to_cart_button() {
// Only when total volume is up to 68
if( get_total_volume() <= 68 ) return;
global $product;
// For variable product types (keeping attribute select fields)
if( $product->is_type( 'variable' ) ) {
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
add_action( 'woocommerce_single_product_summary', 'inactive_add_to_cart_button', 20 );
}
// For all other product types
else {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
add_action( 'woocommerce_single_product_summary', 'inactive_add_to_cart_button', 30 );
}
}
// Utility function: displays a custom innactive add to cart button replacement
function inactive_add_to_cart_button(){
global $product;
$style = 'style="color:#fff;cursor:not-allowed;background-color:#999;"';
echo '<a class="button" '.$style.'>' . __ ( 'Max volume reached', 'woocommerce' ) . '</a>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Check that the utility function get_total_volume() is defined only once, to avoid errors…
When the total cart volume is up to 68m3 you will get:
1) On shop and archives pages:
2) On single product pages:

Resources