WooCommerce: Hide Checkout Fields For Virtual Products

Remi | October 29, 2013 | in WooCommerce

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

The author

About the author Remi:

Hey! My name is Rémi Corson, i’m a WordPress Expert Developer, i create high level themes and plugins, and i provide free stuff every week on this website!

40 Comments

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

      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?

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

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

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

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

  5. 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?

  6. 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. Destroy All Monsters

        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

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

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

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

  10. 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']);

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