WooCommerce: Hide Checkout Fields if Virtual Product @ Cart

If you sell downloadable/virtual products and need to simplify your WooCommerce checkout when such product type is in the Cart, you’ve come to the right place!

Here’s a simple snippet, as well as a handy mini-plugin, that checks if there are only “virtual” products in the Cart and hides all the billing fields and order notes (except name and email).

The mini-plugin also allows you to enable this for free virtual orders only, and to move the relevant billing fields under a toggle instead of removing them all together.


Simplify the WooCommerce checkout by removing billing fields if cart contains virtual products

1) PHP Snippet: Remove Billing Fields if Cart Contains Virtual Products @ WooCommerce Checkout

 * @snippet       Hide Fields if Virtual @ WooCommerce Checkout
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 8
 * @community     https://businessbloomer.com/club/

add_filter( 'woocommerce_checkout_fields', 'bbloomer_simplify_checkout_virtual' );
function bbloomer_simplify_checkout_virtual( $fields ) {
   $only_virtual = true;
   foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
      // Check if there are non-virtual products
      if ( ! $cart_item['data']->is_virtual() ) $only_virtual = false;
   if ( $only_virtual ) {
      add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
   return $fields;

2) Mini-Plugin: Business Bloomer WooCommerce Hide Checkout Fields For Virtual Products

You don’t feel confident with coding? You don’t want to purchase yet another bloated, expensive plugin? Great!

Business Bloomer WooCommerce Hide Checkout Fields For Virtual Products Mini-Plugin comes without the usual WordPress plugin hassles. One feature. Lifetime license. No annoying subscriptions. 1 plugin file. A few lines of code. No banners. No up-sells. No WordPress notifications. Use it on as many websites as you like. Lifetime support. 1-page documentation. Super simple settings.

Speaking of which, here’s a screenshot of the settings:

Quick demo:

As you can see the plugin is straight forward. Install it, decide when to enable the functionality, hide or move the relevant billing fields and save. Simple!

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

  • WooCommerce: How to Fix the “Cart is Empty” Issue
    For some reason, sometimes you add products to cart but the cart page stays empty (even if you can clearly see the cart widget has products in it for example). But don’t worry – it may just be a simple cache issue (and if you don’t know what cache is that’s no problem either) or […]
  • WooCommerce: “You Only Need $$$ to Get Free Shipping!” @ Cart
    This is a very cool snippet that many of you should use to increase your average order value. Ecommerce customers who are near the “free shipping” threshold will try to add more products to the cart in order to qualify for free shipping. It’s pure psychology. Here’s how we show a simple message on the […]
  • WooCommerce: Cart and Checkout on the Same Page
    This is your ultimate guide – complete with shortcodes, snippets and workarounds – to completely skip the Cart page and have both cart table and checkout form on the same (Checkout) page. But first… why’d you want to do this? Well, if you sell high ticket products (i.e. on average, you sell no more than […]
  • WooCommerce: Disable Payment Method If Product Category @ Cart
    Today we take a look at the WooCommerce Checkout and specifically at how to disable a payment gateway (e.g. PayPal) if a specific product category is in the Cart. There are two tasks to code in this case: (1) based on all the products in the Cart, calculate the list of product categories in the […]
  • WooCommerce: Add Privacy Policy Checkbox @ Checkout
    Here’s a snippet regarding the checkout page. If you’ve been affected by GDPR, you will know you now need users to give you Privacy Policy consent. Or, you might need customer to acknowledge special shipping requirements for example. So, how do we display an additional tick box on the Checkout page (together with the existing […]

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

103 thoughts on “WooCommerce: Hide Checkout Fields if Virtual Product @ Cart

  1. I’ve used this many times but for some reason on a new website I’m working on it’s not working. Can you confirm it’s working on the latest Woo version (7.6.1)?

    Thank you

      1. Tried your code and it seems to work, using latest version of WordPress, Woocommerce.
        When I try to add a new page the page editor crashes. I disabled all plugins to find ou the problem has to do with Woo Payments plugin.

        Tested on my development site dev2.soundshop.online
        Problem is also on production site.
        Best regards,

        1. WooPayments has way too many bugs I’m afraid

  2. Hi

    Very nice snippet, but it does not work together with “WC – APG SMS Notifications” https://wordpress.org/plugins/woocommerce-apg-sms-notifications/.

    They use “apply_filters( ‘woocommerce_checkout_fields’, …” and It does not like we use “add_filter( ‘woocommerce_checkout_fields’, …”.

    I need to use that plugin it is a very nice solution for sending SMS’s. I don’t know enough to compatabilize the two expressions.

    Thanks. Anyway I have to say your site is my reference!

    1. Did you talk to the plugin support? I suppose they should fix that

      1. Hi

        Yes I talk to them, but really there was a PHP error, once I noticed I was able to fix it, very simple:

         if ( is_null( WC()->cart ) ) wc_load_cart(); 

        I inserted the above the above line just before the for loop. Fixed!


  3. The code works but then my payment method overrides it saying ‘There are no available payment methods per state’

    1. Oeh! Removed the Country line. So left it in for the checkout page and now payments go through again. So I now have the following on checkout:
      – First Name
      – Last Name
      – Country
      – E-mailadres

      So happy person again. Even if it needs to chow the country.

  4. Great!
    Just one thing – now when I have a non-virtual product in the cart the unset fields get a text of “undefined” as default:


    1. Unset fields should not be visible… so you have some other sort of error

      1. Hi,
        I have the same problem.
        To see the error:
        I first add a virtual product to the basket, then I click on the validation button to land on the checkout page;
        I come back to the shop (for exemple by first clicking on the site logo…)
        I then add a physical product (for which the address fields are of course required for shipping) to the cart;
        On the basket and on checkout page, the text “undefined” appears in the address fields (in any case with the plugin Colissimo shipping methods for WooCommerce; otherwise it appears on the checkout page).
        This error occurs since woocommerce version 7.5.0. Downgrading to 7.4.1 everything works fine.
        I specify that I have also tested different plugins for editing order fields, and the problem is exactlty the same.
        So I think there is a compatibility issue with woocommerce version 7.5.

        1. Must be a WooCommerce bug, never seen that before honestly

          1. Hi,
            Thank you for your reply.
            I reported it to woocommerce… who tell me that it’s a code problem, and therefore to see this with the developers concerned ( https://wordpress.org/support/topic/undefined-text-on/#post-16602971).
            The same problem occurs with different checkout field editor plugins that I tested…
            To date, no one is able to provide a solution.
            Anyway, I’m stuck with this issue…

            1. They actually changed their mind 3 days ago and created a GitHub bug report, so they will fix it (sooner or later). Keep us posted!

              1. Hi,
                For information, the problem is solved with version 7.6.1 of woocommerce.

  5. Works perfectly and I really like it, but it crashes the system when I go to ‘customise’ in Appearance. At this stage I have to delete it from php in order to make other changes on the site, then reinstall the code. Can’t figure out the clash issue.

    1. Dan, thanks so much for your comment! I just retested this on the latest version of WooCommerce and it still works. Unfortunately this looks like custom troubleshooting work and I cannot help here via the blog comments. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding! ~R

  6. this is wrong.

    Why you dont put break in this line:

    if ( ! $cart_item['data']->is_virtual() ) $only_virtual = false;

    So if the current item is not virtual, it will be marked as false. Then if the last item is virtual, it will be marked as true again

    Everyone use the wrong code until now? why nobody notice it for 4years?

    1. Code is not wrong and works perfectly 🙂 Anyone is free to improve it, so if you have a faster/better snippet feel free to share it!

  7. Found the error, the tip suggest for the user DingoDaisy

    add_filter( ‘woocommerce_enable_order_comments_field’, ‘__return_false’ );

    Does not work on the PHP8 Version instead use this

     add_filter( 'woocommerce_enable_order_notes_field', '__return_true' );
    1. Great, glad that helped

  8. Hi. This snippet was working perfectly, I update my PHP version to 8.1 and now I get a critical error.

  9. Now is Oct 2022, my Woo is 6.9.4, WP is 6.0.2, Theme is Twenty Twenty-Two, the billing fields are hided but checkout still validate them, I got “Error processing checkout. Please try again.” when I enable this snippet.

    1. Can you disable all other plugins except WooCommerce? Because on latest Woo + WP + Storefront theme works perfectly

  10. It works! Although I wanna keep the comment field in the check out. What do I need to change in the code, to keep that field?

    1. Found the solution myself. Just changes this line:

      add_filter( ‘woocommerce_enable_order_notes_field’, ‘__return_false’ );

      to this:

      add_filter( ‘woocommerce_enable_order_comments_field’, ‘__return_false’ );

  11. Hey Rodolfo,

    This still works with WooCommerce 5.9.0 and Divi 4.14.1. I used a modified version of it to check whether only a product with a specific ID – in this use case, a café reservation – is in the cart. Sharing it below in case it’s useful to anyone. 🙂

    // Remove billing fields from checkout when café product is in the cart 
    function cln_simplify_checkout_cafe( $fields ) {
    	// Set variable to true
    	$only_cafe = true;
    	// Loop through the cart
    	foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
    		// Check for products that do NOT match the ID of the café reservations product
    		// If a product like that is found, set the variable to false
    		if ( $cart_item['product_id'] !== 31 ) $only_cafe = false; 
    	// Check if variable is set to true
    	if( $only_cafe ) {
    		// Unset billing fields
    		add_filter( 'woocommerce_enable_order_notes_field', '__return_false' ); 
    	// Return the checkout fields
    	return $fields; 
    add_filter( 'woocommerce_checkout_fields' , 'cln_simplify_checkout_cafe' );
  12. Thank you so much, Rodolfo Melogli.

    You are a genius and businessbloomer.com is now my go-to website for all WooCommerce related snippets. They all work like a charm.

    Keep doing the good work.


  13. I added the above snippet but doesn’t work, it always prompts “Something went wrong. Please try again or choose another payment source.” but there is no error find from error_log

    My Woo is Version 5.7.1, is my Woo version not compatible with this snippet?

    1. Worked for me on latest WooCommerce, so it must be a conflict with your theme or another plugin

  14. I love stuff that actually works! Used two of your snippets. No trouble at all. Awesome sauce! Thanks!!

  15. It just works, brilliant

  16. Hi,
    Will this work with WooCommerce Blocks (a plugin by Automattic, makers of WC, that gives more options for the checkout format)?
    I have not gotten it to work yet, and wondering if that is the reason.

    1. Not sure, haven’t tested it yet. Let me know

  17. Hi, how about base on product category? My woocommerce is integrated with Learndash. And I want to hide the billing details if course product data is selected.

  18. Still working great in 2021!!

    1. Great!

  19. what happened if the user selected a physical product with a digital product.
    is this gonna show the billing address field in that case?

    1. Yes in case of a “mixed cart” the code won’t trigger so you get the default checkout

  20. Thanks for publishing this, worked perfectly.

    1. Great!

  21. It works perfectly — you da best! 😉

    1. Yeah!

      1. Awesome, exactly what I was looking! Pretty stupid they don’t have this implemented on default.

  22. how to remove billing address for the second time if the user logins with first time account created

    1. Anand, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  23. Thank You. It works for me

    1. Nice!

  24. Still works, thank you

    1. Excellent!

  25. Thanks very much, this worked with my GreenMart theme

    1. Great!

  26. Yes! Yes! yes yes yes yeses yes!
    Thank you! Worked like a charm!!

    1. Eheh glad it helped

  27. The code works,
    However, when I check-out, the transaction goes through but does not redirect the page.

    1. Code works,
      However it hangs on the checkout page. Transaction still goes through and order shows up in the account, but there is no redirect nor does the cart get emptied after the order

      1. Andreas, thanks for your comment! I just tested this again with Storefront theme and it works perfectly. Maybe your theme (or another plugin) is messing/conflicting with my snippet.

        To troubleshoot, disable all plugins but WooCommerce and also switch temporarily to “Twentytwenty” theme (load the snippet there in functions.php) – does it work? If yes, you have a problem with your current theme or one of the plugins.

        Hope this helps!


  28. Hi,
    In Peru we need Departamento, Provincia and Distrito to bill our customers.
    We sell a virtual product (gift card) and have a special field created for District: ‘billing_gowoo_place’. This field disappears when buying a virtual product.
    How can I force it to appear?

    1. Hi Samir, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  29. Hello

    I’m selling virtual product, is it possible if a customer choose pay by bitcoin gateway, hide all Billing Fields only show email field. On the other hand if choose pay by credit card or Paypal, show all billing fields? (Default show all)

    1. Hello, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  30. Works like a charm!

    1. Thanks!

  31. No luck yet, let me try again

  32. Beautiful, thank you – and unbelievable that Woo displays shipping address fields for virtual products. I can’t think of a use case for that, unless someone wants to harvest addresses.

    1. True!

  33. thanks a lot man .. its magic.

    1. Great!

  34. I love it! Thank you!

    1. Yay!

  35. This is brilliant, thank you!

    How would you also remove the ‘ship to different address’ tick box?


    1. Hi Adam – I guess you’re talking about “mixed” carts, where you have virtual and non-virtual products at the same time? Because if you only have virtual ones the shipping form won’t display at all. Let me know

  36. How would I change this if I wanted to remove billing fields on free products?

    1. Hi Pat, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  37. This code works perfectly.

    We are only selling downloadable virtual products and I think hiding the billing fields is a good idea. However, the question arises whether these fields are needed for credit/debit card payment methods. We plan to use Stripe and PayPal, but have only tested in test mode and not in live or production mode. Since this is our first time using WooCommerce, we would like to know, before we go live, whether we can use this snippet.


    1. Technically if it works on test mode it should work on live mode. However, I recommend you enable this snippet on your live site and immediately do a real test purchase. After that, based on your results, you can leave the snippet there or you can remove it. Hope this helps

  38. thank you! You’re awesome for sharing the code.

    1. Cheers!

  39. This is Awesome function. Thank you! And yes it still works

    1. Great!

  40. Thanks the code work only if I am logged in doesn’t work if not logged in then it ask to login to the account first to checkout.

    1. Thanks for your comment Nidhi. It works for me, so please test with a different theme / no plugins to see if it works

  41. I don’t have a child theme. I put my code in the parent’s theme’s “functions.php”. I put the code at the end of the file. But after saving and refreshing, my site doesn’t display anything. It just keeps on loading

    1. Hey Himanshu, thanks for your comment! Try using https://wordpress.org/plugins/code-snippets/ instead

  42. Hi Rodolfo
    Nice piece of code, simple and easy 😉
    How would I change your snippet, if there was a physical product in the cart as well, to exclude the cost of the virtual product from the subtotal, to allow free shipping, but still take the total through to checkout?
    I’m hoping this is something really simple to do but cannot figure it out.

  43. Hi, found your code and tested it, still can be use. Thank you very much. Really appreciated it.

    1. Awesome 🙂

  44. Hey,

    i am new to your page and I am very thankful for your content. I looked through your checkout page tips and I cant find how you put the “My Order” table on the right side? My order and payment options are under the billing details, how can I make them so beautiful like yours? thank you

    1. Hello Serhat! I get that checkout layout thanks to my theme, Storefront. Otherwise you can use simple CSS to make a 2-columns checkout layout. Hope this helps!

  45. Sweet Code Rodolofo. Thank you, works a charm.

    1. Great 🙂

Questions? Feedback? Customization? Leave your comment now!

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

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