Es muy normal que cuando trabajas con un comercio electrónico con WooCommerce ofrezcas envío disponible «a partir de cierta cantidad de compra». De hecho, es algo realmente frecuente en cualquier tipo de comercio electrónico, hasta los gigantes de este mundo como Amazon es algo que ofrecen.
Ofrecer envío gratuito a partir de un mínimo en el carrito es algo interesante porque te ayuda a que la media de los carritos suba. El usuario busca «algo con lo que completar su compra» para ahorrarse los portes. Tú ganas un carrito mayor, más ingresos, y lo que pierdes en el coste de envío que ahora no cobras lo consigue por tener más margen en la venta y porque la gestión de un envío con dos productos, es menor en proporción a la gestión de dos envíos con un producto.
Productos virtuales
Los productos virtules son aquellos que no requieren de un envío. Dependiendo de vuestro sector los habréis usado o no, pero ejemplos de productos de este tipo hay muchos:
- Entradas a un evento
- Un curso
- Un servicio que estás cobrando
- Un seguro
Y así podríamos seguir… Aparte están los productos descargables, que son todos aquellos que tienen una descarga asociada. Casi todos los productos descargables son virtuales, pero vaya no siempre es así (imaginad un producto físico que incluya un manual en PDF, en ese caso NO sería virtual porque el producto se envía, pero sí sería descargable porque se descarga un PDF al comprarlo).
Hay un problema con lo que hablábamos antes del envío gratuito a partir de una cantidad y los productos virtuales. En tiendas donde conviven, puede darse el siguiente caso:
- Envío gratis a partir de 100€
- El cliente elige una crema de 5€
- Y un vídeo curso de 95€
- El envío le sale gratis pero el envío realmente solo es de la crema… así que puede dejar de tener sentido ofrecer envío gratis en estos casos
Solución usando un pequeño snippet
Así que nada, la solución es usar un pequeño snippet que actúa sobre el hook que determina en última instanacia si debe ofrecerse o no el envío gratuito.
add_filter( 'woocommerce_shipping_free_shipping_is_available', function( $is_available, $package, $wc_shipping_method ){ $total = WC()->cart->get_displayed_subtotal(); if ( WC()->cart->display_prices_including_tax() ) { $total = $total - WC()->cart->get_discount_tax(); } foreach( WC()->cart->get_cart() as $cart_item ) if( $cart_item['data']->is_virtual() ) $total -= $cart_item['line_total']; $total = Automattic\WooCommerce\Utilities\NumberUtil::round( $total, wc_get_price_decimals() ); if ( $total >= $wc_shipping_method->min_amount ) { $has_met_min_amount = true; } $is_available = $has_met_min_amount; return $is_available; }, 10, 3 );
Si os fijáis, el método tiene mucho que ver con lo que hace WooCommerce en su propio código fuente, pero se incluye un bucle que resta el total de cada una de las líneas que sean producto virtual.
Elena Fernández
Hola!
Estoy probando este código pero no me funciona. Lo he puesto en el functions del child theme. ¿Lo estoy haciendo mal?
Gracias!
Francisco Javier Carazo Gil
Ese es el sitio para ponerlo. Haz unos cuantos var_export en el código a ver qué está fallando en tu caso.