Last updated on October 10th, 2023 at 09:13 am

This quick workaround allows you to avoid buying some expensive add-ons.

Cargo delivery, courier and truck with boxes

This post contains affiliate links. We may earn a commission if you purchase an item through our links. It costs you nothing and helps us to fund this blog. Please see our Affiliate Disclosure & Notification for details.

WooCommerce is one of the most popular eCommerce platforms in use today. The platform consists of a free WordPress plugin that includes the core. WooCommerce makes their money by selling extensions that add functionality to the free core.

The Core Does A Lot for Free

Ever since I started using and configuring WooCommerce for my own web store and my clients, I’ve been amazed at all the great features that come with it at no cost. You can sell unlimited products, variable products, downloadable products, virtual products – you name it.

Connecting your site to Jetpack and gives you access to live shipping rates in the US & Canada (UPDATE March 1st, 2019: The live shipping rates are no longer a free service but you can buy the official USPS Shipping Method here). You can also purchase and print shipping labels for orders right within the back end of your store and you actually save money because WooCommerce gets commercial shipping rates instead of retail.

…But it Misses Some Basics

As much as WooCommerce does for free, there are some seemingly simple things it does not do without buying an extension.

One of the limitations is for free shipping options. While WooCommerce does offer a free shipping setting, it applies to an entire order. If you have a single item in your store that offers free shipping, a customer will be offered the free shipping method for their entire order even if it contains other items that should not be shipped for free.

Doesn’t make much sense, does it? Fortunately, there’s a popular workaround: configure items for free shipping as virtual items instead of simple items. Since virtual items aren’t tangible, WooCommerce skips them in the order when calculating shipping. In effect, you get a free shipping item.

virtual product woocommerce
Marking an item as Virtual is as simple as checking the box in WooCommerce

For 90% of online stores, this workaround is adequate. But I recently had a client who needed a bit more.

Online shopping concept

Shipping Addresses for Virtual Products

This client sold virtual products (downloadable software), but their sales department was required to mail out thank you cards to all customers including ones who bought virtual items. WooCommerce doesn’t collect a shipping address for virtual items and cannot be natively configured to do so.

There is an extension called Per Product Shipping by WooCommerce but it costs $79/yr. and the client wasn’t willing to pay that for what seemed to be a simple request.

In addition to that, the client required the new order emails to display the shipping address for all orders because these emails were used by the sales department who wouldn’t have access to the back end of the site. WooCommerce also doesn’t offer this function.

A 2-Step Solution

Step 1: Force WooCommerce to collect a shipping address on every order

The first part of my solution was to force WooCommerce to collect a shipping address for every order regardless of what the product was. Fortunately, this part can be done with a simple line of code:

add_filter( 'woocommerce_cart_needs_shipping_address', '__return_true', 50 );

This code should be placed in your child theme’s functions.php file. Alternatively, we’ve made a little plugin that does it for you that you can download for free on the CGS Computers Cyber Store.

Step 2: Force WooCommerce to display a shipping address on every new order email

The second step, which takes a tiny bit more energy, is to edit the WooCommerce email address template to ensure that the shipping address is always displayed in the order emails.

FTP into your web server (or use CPanel) and navigate through your website’s directory structure to /wp-content/plugins/woocommerce/templates/emails/. In this folder, you’ll find a file called email-addresses.php. Place a copy of this file into your child theme’s /woocommerce/emails/ folder. There’s a good chance you’ll have to create this folder unless you’ve already modified the WooCommerce email templates.

Once you’ve placed the email-addresses.php file in there you’ll need to modify it. Search for this line:

 <?php if ( ! wc_ship_to_billing_address_only() && $order->needs_shipping_address() && $shipping ) : ?> 

and replace it with this:

 <?php if ( ! wc_ship_to_billing_address_only() && $shipping ) : ?> 

Once you’ve made those changes, every new order email will contain both a shipping and billing address.

Final Thoughts

While WooCommerce includes a ton of useful features out of the box, the reality is that some things which seem to be pretty basic are sometimes missing. But frequently, with just a tiny bit of code, you can get the features you want.

Sharif Jameel is a business owner, IT professional, runner, & musician. His professional certifications include CASP, Sec+, Net+, MCSA, & ITIL and others. He’s also the guitar player for the Baltimore-based cover bands, Liquifaction and Minority Report.

7 thoughts on “How to Add a Shipping Address to Virtual Products in WooCommerce”

  1. Is it possible to add shipping options to a virtual product? We have courses that the system sees as virtual and must be marked that way to add them to the students accounts, but we also want to be able to give them an option to purchase the book with their course. When we do this the virtual is automatically disabled and the courses don’t go into their account.

    1. Thanks for stopping by and checking out the site! I’m sure with enough coding skills there’s a way to make the shipping address optional, but in my use case that wasn’t necessary – my client needed to collect a shipping address for every order regardless of type. You’d likely have to register a brand new function and likely a custom field to select the option for a shipping address – which is all beyond the scope of this post. I’m sure if you dig deep enough you can figure it out though!

  2. This is really nice and works! Thank you!

    I am looking further for the option to show also the Shipping options (i know it sounds odd). But for the virtual Event is Food Delivered or picking up locally necessary (before the event).

    The Virtual Product Setting comes from the Events Plugin which switches the Setting to virtual back, everytime when i change it to a simple product…

    Maybe do you have a snippet for such a usecase, too? 😉

    i tried it with disabling the Options for Virtual & Downloable products (which removes the setting in the backend), but Shipping options are still not shown for the (virtual) Products.

    add_filter( 'product_type_options', function( $options ) {

    // remove "Virtual" checkbox
    if( isset( $options[ 'virtual' ] ) ) {
    unset( $options[ 'virtual' ] );

    // remove "Downloadable" checkbox
    if( isset( $options[ 'downloadable' ] ) ) {
    unset( $options[ 'downloadable' ] );

    return $options;

    } );

    Thanks in advance.

    1. Thanks for reading my article. I’m afraid I’m not familiar with the Events Plugin you mention, so I don’t have any snipppets that match your use case. You’ll have to keep researching, I’m sure you can figure it out!

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to Our Mailing List

If you found the information in this post helpful, we'd love to have you join our mailing list. We promise we won't spam you, we only send out emails once a month or less.

You May Also Like:

This site requires the use of cookies to ensure you get the best experience.

Scroll to Top
Available for Amazon Prime