How to Set Up Woocommerce Free Shipping On a Specific Product

The WooCommerce USPS Shipping Method and the UPS Shipping Method extensions makes it easy for you to charge your customers for shipping cost at checkout. The only problem, is that they are both a calculator for all products in the cart, and does not exclude products based on shipping classes. So an order can only use one shipping method.

Recently on a site I was working on for a designer the site needed to offer free shipping within the US on a specific product category and charge the customer for shipping on all other products. The scenario required the ability to have two different shipping methods (Free and Paid) dependent upon the products in the order and shipping location. To accomplish this task we needed the one order divided into two carts.

Create Shipping Class

So all the products that could qualify for free shipping are assigned a shipping class.

Add Shipping Class To Product1


In this example I am calling the shipping class freepromo.

Configure Free Shipping

Then free shipping is enabled in the WooCommerce Shipping Settings. Configure Additional ShippingThen the USPS and UPS shipping methods are enabled and configured. At this point every time a customer is in the US they will get free shipping. If they are not in the US they will be given a choice of UPS and USPS shipping rates.

So we still need to set up:

  • Free shipping only for products being shipped in the US with the freepromo shipping class
  • USPS and UPS shipping options for customers not in the US buying the freepromo products
  • USPS and UPS shipping options for customers purchasing all other products.
  • Free shipping and USPS and UPS shipping options for customers that purchase freepromo and non-freepromo products in one order.

There is a free plugin called Multiple Packages for WooCommerce. The plugin does work but it does not allow for additional shipping options for products with the freepromo shipping class that don’t qualify for free shipping. It also makes free shipping available to the product that does not have the freepromo shipping class.

To allow all four use cases we need to add a little code to functions.php or a site specific plugin.

/** Seperate freepromo products from other Items - forcing multiple carts **/
add_filter( 'woocommerce_cart_shipping_packages', 'ps_two_shipping_methods_in_cart' );

function ps_two_shipping_methods_in_cart( $packages ) {
   $packages = array();
   $freepromo_items = array();
   $regular_items = array();
   $freeshipclass= 'freepromo';
   $shipto = array(
                'country' => WC()->customer->get_shipping_country(),
                'state' => WC()->customer->get_shipping_state(),
                'postcode' => WC()->customer->get_shipping_postcode(),
                'city' => WC()->customer->get_shipping_city(),
                'address' => WC()->customer->get_shipping_address(),
                'address_2' => WC()->customer->get_shipping_address_2()

    // Sort freepromo from regular
    foreach ( WC()->cart->get_cart() as $item ) {
        if ( $item['data']->needs_shipping() ) {
            if ( $item['data']->get_shipping_class() == $freeshipclass ) {
                $freepromo_items[] = $item;
            } else {
                $regular_items[] = $item;

//If product qualifies for free shipping
    if ( $freepromo_items && WC()->customer->get_shipping_country() =='US' ) {
        $packages[] = array(
            'ship_via' => array( 'free_shipping'  ),
            'contents' => $freepromo_items,
            'contents_cost' => array_sum( wp_list_pluck( $freepromo_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto
    }elseif ( $freepromo_items ) { //if product does qualify for free shipping but customer is not in US
        $packages[] = array(
            'ship_via' => array( 'usps','ups'  ), //available shipping methods for international
            'contents' => $freepromo_items,
            'contents_cost' => array_sum( wp_list_pluck( $freepromo_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto

//If product does not qualify for free shipping
    if ( $regular_items ) {
        $packages[] = array(
        	'ship_via' => array( 'usps','ups'  ),
            'contents' => $regular_items,
            'contents_cost' => array_sum( wp_list_pluck( $regular_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto
    return $packages;

In the code shown above you will need to change the shipping class name and the available shipping methods in the ship_via array.

Here are some examples of what the cart looks like in different scenarios:

This image shows the cart for a product that does not belong to the freepromo class.
This image shows the cart for a product that does not belong to the freepromo class.


Based on the freepromo restrictions the customer does not qualify for free shipping of the freepromo product because they are not in the US.


US customer is ordering a  product that has the freepromo shipping class and one product that pays shipping.
US customer is ordering a product that has the freepromo shipping class and one product that pays shipping.


Note: The code shown above is code from the Multiple Packages for WooCommerce plugin that I modified to meet the requirements of the project.


How To Remove The WooCommerce Additional Information Tab

Recently I was working with a designer to complete an eCommerce site using the WooCommerce WordPress plugin. A default WooCommerce product page displays the content entered into the WordPress editor as the content under the product description tab. The review tab displays all the product reviews and allows people to submit reviews. Then there is the additional information tab that only displays the weight, dimensions, and the attributes for a product. If no weight, dimensions, or attributes are entered for a product the additional information tab is not displayed.

There is no option in the WordPress admin to customize the additional information tab content and the necessary information (the dimensions) can be added to the description tab. I considered changing the name of the additional information tab and customizing the content displayed in the additional information tab using the woocommerce_product_tabs filter.  The final solution which I am going to share with you is to completely remove the additional information tab.

To remove the additional Information tab add the following code to your site functionality plugin or your themes functions.php file.

//remove additonal info tab from products
add_filter( 'woocommerce_product_tabs', 'woo_remove_product_tabs', 98 );
function woo_remove_product_tabs( $tabs ) {
    global $product;
	if( $product->has_attributes() || $product->has_dimensions() || $product->has_weight() ) {
        unset( $tabs['additional_information'] );   
    return $tabs;

The code above will change the product page so that there are only two tabs: Description and Reviews.

Woocommerce Product Tabs After



Open WordPress Gallery Images In Lightbox

Woo Commerce already uses Pretty Photo for the product gallery and the product image. When you add a WordPress gallery to the product description the images don’t open using the Pretty Photo Lightbox. So I set on a mission to open WordPress gallery images in a lightbox. According to the Pretty Photo documentation all I needed to do was add the “rel attribute” to each image link. Originally I was looking for a filter to alter the gallery output. I ended up filtering “wp_get_attachment_link” to edit the image link. After viewing the code for the product gallery and the product image I realized I needed to add a “data-rel attribute”. The code I used is below.

add_filter('wp_get_attachment_link', 'ccr_add_rel_attribute');
function ccr_add_rel_attribute($link) {
    $link = str_replace('<a href','<a data-rel="prettyPhoto[gallery]" href',$link);
    return $link;

Solution Inspired by corsonr

Code Snippets jQuery

Replace Smart Quotes With Straight Quotes

I created a web app that uses ckEditor as the rich text editor. It works perfectly except when you copy and paste text that includes smart quotes and other special symbols. CkEditor converts the smart quotes to HTML entities, which would be fine in a normal situation. The Html entities caused a problem when it was time to write the iTunes XML feed. So what I ended up doing is replacing all the html entities with the correct character as soon as I got the content from ckEditor. The code I used to replace smart quotes with straight quotes is below.

function cleanstring(dirty){
	var smartchr = [ "’","‘","“","”","–","—","…", " ", '„', '‚' , '«','»', '‹', '›'];
	var correctchr = ["'", "'", '"', '"', '-', '-', '...', '', '"', "'", '"', '"', "'", "'"];

	var thestring = dirty;
	var regex; 
  	for (var i = 0; i < smartchr.length; i++) {
    	regex = new RegExp(smartchr[i], "g");
    	thestring = thestring.replace(regex, correctchr[i]);

	return thestring;

How To Hide The Controls On A YouTube Video

This is a quick post to explain how to hide the controls on a YouTube Video.

Go to Youtube and copy the embed code for the video you want to use.

Paste the embed code in the WordPress Text editor.
Find the “src” attribute in the embed code.
To the end of the video url add


The parameter autoplay=0 stops the video from automatically playing. If you want it to autoplay add autoplay=1 instead.
The parameter controls=0 hides the video controls.

<iframe width="560" height="315" src="//" frameborder="0" allowfullscreen></iframe>

The final video will work similar to the one below.

You can add more parameters to the url to further control the playback of the video.

  • To have the video automatically replay add loop=1
  • To prevent the related videos from showing at the end add rel=0

Resources for more info: YouTube Embedded Players and Player Parameters