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

About the author

Remi Hey! My name is Rémi Corson, I'm a French WordPress Developer, I code stuff and I write from time to time ;-) Buy a coffee
Show your support

Related Posts

40 comments

  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.

  2. Aryo:

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

    Thanks!

  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

  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

  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!

    • Remi:

      strange because there’s no space…

      • 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.

      • 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

  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

  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;
    }

  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