WooCommerce: Hide Checkout Fields For Virtual Products

I’ve been asked many times how to remove specific fields on the checkout page when the cart contains virtual (downloadable) products only. By default if the cart contains virtual products only, the shipping fields are automatically removed, but some users want to remove some of the billing fields too. That’s understandable, there’s no need to collect the billing address or the billing zipcode in most cases. The snippet i wrote below, checks the number of products in the cart, and compare the result to the number of virtual products in the cart. If all products are virtual, then checkout fields are removed, if the cart contains one virtual product and at least one physical product, checkout fields are kept. Does that make sense?

The code below has a function called woo_cart_has_virtual_product(). That’s the one checking for the virtual products in the cart. It returns true if all products in the cart are virtual, and false, if none of them are virtual or if there’s at least one non virtual product in the cart. Then the second function, woo_remove_billing_checkout_fields(), is hooked to woocommerce_checkout_fields and delete the unwanted checkout fields.

Here is the result when your cart contains virtual products only:

woocommerce-virtual-products-checkout-fields

The code

40 responses to “WooCommerce: Hide Checkout Fields For Virtual Products”

  1. Dan

    This is just what I’m looking for. However I’m new to this and not sure where to paste the code. (I’m using a theme with a child theme). Thanks.

    1. in functions.php in the theme folder.

      1. steve

        Hi,
        Can you be a little more specific for me please as I am unfamiliar with coding.
        Where is the folder and which at which point should I paste the code.
        I tried already and had to restore my site due to errors.
        I am using the Frisco theme.
        Much appreciated.
        Steve.

        1. you need to paste the code in functions.php in the theme folder.

          1. steve

            Hi Remi,
            Just tried that, I went to;
            themes – frisco – admin – functions,
            opened the empty functions.php folder and copied and paste the txt.
            It still has all of the fields in place.
            Can you help me out?
            Cheers.
            Steve.

          2. you’re not in the right file, use wp-content/theme/frisco/functions.php instead

  2. Aryo

    Hello Remi,
    is there possible to upload image, or some input text before the ‘add to cart’ button?

    Thanks!

      1. Aryo

        Nice!.. thanks Remi..
        but I’m still wondering to put it into single product page (before the ad to cart’s button) , and how about put the input field at the frontend, so the visitors could input the text or upload image if they request for custom product by them self?
        is there any represent plugin or addons to handle it?

  3. tdbiii

    Hi Remi,

    I have tried this code, and it does not seem to work.

    I did some playing around, and it seems that woo_cart_has_virtual_product() is not returning true. If I change:
    if( woo_cart_has_virtual_product() == true ) {
    to
    if( woo_cart_has_virtual_product() == false ) {
    then the form is shorter.

    Could it be that the woo_cart_has_virtual_product() function does not support the current version of WooCommerce?

    Thanks!

    Tom

    1. that’s interesting, on my side it seems to work.

      1. tdbiii

        Any ideas how I can solve it or debug it?

        1. tdbiii

          It seems as if $is_virtual == 'yes' is never true.

  4. davido

    Hi Remi,

    Yeah same here, not working. I’m on the latest version of Woocommerce. Any ideas?

    Dave

  5. davido

    Could it be the line that contains:
    ‘_virtual’,
    (it hasn’t pasted exactly how it looks in the code)
    ??

  6. davido

    Yep – changed..

    $is_virtual = get_post_meta( $product_id, ‘_virtual’, true );

    to

    $is_virtual = get_post_meta( $product_id, ‘_virtual’, true );

    and it works a treat!

    Thanks,
    Dave

    1. it’s the exact same code

  7. davido

    I’m on ie11 and the first one reads:

    ‘[OBJ]_Virtual’ – where [OBJ] is a small rectangular symbol.

    If you’re not seeing it in my comment above it may be a browser quirk. When I browse your site’s html, it shows as:
    ‘?_virtual’

    I’ll email you a screenshot as can’t post one here.

  8. tdbiii

    Well, I spent an afternoon on this, and have written other code that works fine for me. It has no extra function calls, which is always an added bonus.


    function woo_remove_billing_checkout_fields( $fields ) {
    global $woocommerce;

    $needs_shipping = $woocommerce->cart->needs_shipping();
    if( !$needs_shipping ) {
    unset($fields['billing']['billing_company']);
    unset($fields['billing']['billing_address_1']);
    unset($fields['billing']['billing_address_2']);
    unset($fields['billing']['billing_city']);
    unset($fields['billing']['billing_postcode']);
    unset($fields['billing']['billing_country']);
    unset($fields['billing']['billing_state']);
    unset($fields['billing']['billing_phone']);
    unset($fields['order']['order_comments']);
    unset($fields['billing']['billing_address_2']);
    unset($fields['billing']['billing_postcode']);
    unset($fields['billing']['billing_company']);
    unset($fields['billing']['billing_city']);
    }

    return $fields;
    }

  9. mcp005

    I want to customise the checkout process of a virtual product so that woocommerce can be used to take bookings for a restaurant. The idea is to remove all references that you are paying for a product and just make it look like a booking system (which will be free). The
    if( woo_cart_has_virtual_product() == true ) statement looks promising to modify the checkout process. Is this possible? what are the biggest stumbling blocks to look out for?

  10. Destroy All Monsters

    To all those having problems – check that there’s not a space between the opening quote and _virtual in the get_post_meta line.

    The line should be like this:

    $is_virtual = get_post_meta( $product_id, '_virtual', true );

    For some reason when cut & pasted from Github it’s like this:

    $is_virtual = get_post_meta( $product_id, ' _virtual', true );

    Note the space between the opening quote and _virtual. Remove that and the function will work as expected.

    I’m guessing this is what Davido was trying to communicate but the space was stripped from his comment. Hopefully it looks right in this one!

    1. strange because there’s no space…

      1. Yep, really odd. On screen there’s definitely no space but when you highlight, copy and paste there is.

        Just double-checked and it’s definitely there. In Notepad++ it just looks like a space, but in regular Windows Notepad it’s a strange character – OBJ surrounded by a dashed border.

        If it’s helpful I’m running the latest version of Chrome on Windows 7.

      2. esscreative

        Hi guys, yes definitely a space there. I too couldn’t get this to work until I removed the space.

        I copied the code from Raw – Latest version of Chrome on Mac.

        Anyway, thanks for the code :-)

        Dave

  11. rbryn

    Hi Remi,

    I’ve tried this using WP/Woocommerce and book-store responsive theme. (and the Katamo variation found at gist.githumb.com. He says: There’s an uptade for the function to check if a product is a digital variation of a standard product. https://gist.github.com/Katamo/10243188).

    Since I’m a reckless noob I pasted your snippet (and tried Katamo’s too) onto the bottom of the functions.php file. I still get all the required fields.

    Am I missing something?

    Thanks,

    Rbryn

    1. if you use a child theme, paste the code in the child theme functions.php file ;-)

      1. rbryn

        Thanks for the response Remi.
        Crunch Press’ “book-store” responsive does not use/allow child themes. This was very surprising (and I only found out accidentally after purchasing and installing).
        Any other suggestions?

        Thanks,

        Rob

        1. All themes can have a field theme, you just need to create it: http://codex.wordpress.org/Child_Themes

          1. rbryn

            So, here’s a first. Child themes don’t work with “book-store responsive. ”

            On the other hand, this plugin did the trick:
            [link removed]

            I was able to remove fields and “required”.

            Thanks,
            Rob

          2. rbryn

            Sorry. Blew that link.

            It is Woo Commerce Checkout Manager
            and is available at
            [link removed]

            Rbryn

  12. janestone08

    Hi Remi,

    Happy New Year!

    Is there any way to remove or disable all payment gates/payment methods for my site that only shows the catalog pages?

    Thanks,

    Jane

    1. There are two ways to do it: use custom templates, or use an existing solution like catalog visibility option: http://www.woothemes.com/products/catalog-visibility-options/

  13. BFTrick

    Hey Remi,

    What do you think about using the cart’s needs_shipping method? Here’s what I came up with:

    // Remove unwanted checkout fields
    add_filter( 'woocommerce_checkout_fields' , 'woo_remove_billing_checkout_fields' );

    /**
    * Remove unwanted checkout fields
    *
    * @return $fields array
    */
    function woo_remove_billing_checkout_fields( $fields ) {

    // check if the cart needs shipping
    if ( false == WC()->cart->needs_shipping() ) {

    // hide the billing fields
    unset($fields['billing']['billing_company']);
    unset($fields['billing']['billing_address_1']);
    unset($fields['billing']['billing_address_2']);
    unset($fields['billing']['billing_city']);
    unset($fields['billing']['billing_postcode']);
    unset($fields['billing']['billing_country']);
    unset($fields['billing']['billing_state']);
    unset($fields['billing']['billing_phone']);

    // hide the additional information section
    add_filter('woocommerce_enable_order_notes_field', '__return_false');
    }

    return $fields;
    }

    1. Hey Patrick, this is clever! ;-) Well done!

    2. muzza78

      Like your work BFTrick

  14. janestone08

    I’m trying to customize the templates. Can you pls advise how?

    Thanks!

  15. shainanz

    Hi Remi,
    Thanks for sharing! I use the WooCommerce Custom Fields Editor plugin to add a couple of extra fields to my checkout. If I wanted to target these fields the same way, how do I add them?

    I’m not sure what to put in here instead of “billing” (or “order” or “shipping”):
    unset($fields['billing']['name-of-my-field']);

  16. erivier

    Your code works for does not display the fields, but when the checkout process, required fields show their error message.

  17. StaceyJ

    Hi Remi,

    Thanks for this code! It works a treat on the billing but I have a few additional fields from the Woocommerce checkout fields plugin that I would like removed ONLY on the virtual products. I don’t know much about code so I tried replacing the word ‘billing’ with ‘additional’ but is didn’t work. I would love to know what I did wrong and how to make this work.

    Kind Regards
    Stacey

    add_filter( ‘woocommerce_checkout_fields’ , ‘woo_remove_additional_checkout_fields’ );
    /**
    * Remove unwanted checkout fields
    *
    * @return $fields array
    */
    function woo_remove_additional_checkout_fields( $fields ) {

    if( woo_cart_has_virtual_product() == true ) {
    unset($fields[‘additional’][‘my_field_name’]);
    unset($fields[‘additional’][‘my_field_name’]);
    unset($fields[‘additional’][‘my_field_name’]);
    unset($fields[‘additional’][‘my_field_name’]);
    }
    return $fields;
    }
    /**
    * Check if the cart contains virtual product
    *
    * @return bool
    */
    function woo_cart_has_virtual_product() {

    global $woocommerce;

    // By default, no virtual product
    $has_virtual_products = false;

    // Default virtual products number
    $virtual_products = 0;

    // Get all products in cart
    $products = $woocommerce->cart->get_cart();

    // Loop through cart products
    foreach( $products as $product ) {

    // Get product ID and ‘_virtual’ post meta
    $product_id = $product[‘product_id’];
    $is_virtual = get_post_meta( $product_id, ‘_virtual’, true );

    // Update $has_virtual_product if product is virtual
    if( $is_virtual == ‘yes’ )
    $virtual_products += 1;
    }

    if( count($products) == $virtual_products )
    $has_virtual_products = true;

    return $has_virtual_products;
    }

Leave a Reply