There is a plugin for creating and removing checkout fields called Checkout Field Editor. But what if you need to add checkout fields that only show up under certain conditions? For example, if Product X is in the cart then you need to add a special checkout field to collect more information from the customer. Ideally in these circumstances, you could collect that information from the customer on the product page using Product Add-ons, but there are some situations where it could make more sense to collect the information at checkout. And that’s the purpose of this quick tutorial.
Creating Checkout Fields
I’m not going to go over how to create checkout fields in the article. If you need help with that, then I suggest reading over this article first, or try the Checkout Field Editor plugin.
Removing a Checkout Field
Let’s start with a very basic function that simply removes a checkout field.
function wc_ninja_remove_checkout_field( $fields ) {
unset( $fields['billing']['billing_company'] );
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'wc_ninja_remove_checkout_field' );
All this snippet is doing is removing the company field from the billing section. To target a specific field, you first need to add what section the field is in – which will either be ‘billing’, ‘shipping’, ‘account’, or ‘order’. Then you specify the exact field. In our case, we targeted the billing section, and then the billing_company field. You can get a complete list off all the default fields and their sections at this WooThemes Guides.
Setting Up the Conditions
Now that we can remove a checkout field, let’s add in some of the magic.
Product Specific Conditional
A common condition to use is whether a certain product is in the cart or not. To get this information, we can set up a function like this:
/**
* Check if a specific product ID is in the cart
*/
function wc_ninja_product_is_in_the_cart() {
// Add your special product IDs here
$ids = array( '45', '70', '75' );;
// Products currently in the cart
$cart_ids = array();
// Find each product in the cart and add it to the $cart_ids array
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$cart_product = $values['data'];
$cart_ids[] = $cart_product->id;
}
// If one of the special products are in the cart, return true.
if ( ! empty( array_intersect( $ids, $cart_ids ) ) ) {
return true;
} else {
return false;
}
}
Now we can find out if products 45, 70, or 75 are in the cart. So we can manipulate our previous function to only remove the company field if those products are not in the cart. So our remove_checkout_field function now looks like this:
/**
* Conditionally remove a checkout field based on products in the cart
*/
function wc_ninja_remove_checkout_field( $fields ) {
if ( ! wc_ninja_product_is_in_the_cart() ) {
unset( $fields['billing']['billing_company'] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'wc_ninja_remove_checkout_field' );
Product Category Conditional
But what if you have a group of products you need to hide a field for? You could just add a massive list of product ID’s to the above function. But that could get messy, and you would have to continually add new IDs to the function when you created new products. In this case, it would be best to toggle the checkout field based on if a product category is in the cart or not. This function will look similar to our earlier one, but a bit more beefy because we need to search for and find each product’s category.
/**
* Check if a specific product category is in the cart
*/
function wc_ninja_category_is_in_the_cart() {
// Add your special category slugs here
$categories = array( 'clothing', 'posters' );
// Products currently in the cart
$cart_ids = array();
// Categories currently in the cart
$cart_categories = array();
// Find each product in the cart and add it to the $cart_ids array
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$cart_product = $values['data'];
$cart_ids[] = $cart_product->id;
}
// Connect the products in the cart w/ their categories
foreach( $cart_ids as $id ) {
$products_categories = get_the_terms( $id, 'product_cat' );
// Loop through each product category and add it to our $cart_categories array
foreach ( $products_categories as $products_category ) {
$cart_categories[] = $products_category->slug;
}
}
// If one of the special categories are in the cart, return true.
if ( ! empty( array_intersect( $categories, $cart_categories ) ) ) {
return true;
} else {
return false;
}
}
And of course, you can update the remove_checkout_field function to use the wc_ninja_category_is_in_the_cart() function instead of wc_ninja_product_is_in_the_cart().
Coupon Conditional
That covers most of the needs for product based conditionals. So now just for fun, let’s add a condition based on if a certain coupon has been used.
/**
* Check if a specific coupon was used
*/
function wc_ninja_coupon_was_used() {
// Add a list of coupons to check for here.
$coupons = array( 'percent_coupon', 'free_shipping' );
// Coupons Used
$coupons_used = WC()->cart->applied_coupons;
// If ones of our special coupons were used, return true.
if ( in_array( $coupons, $coupons_used ) ) {
return true;
} else {
return false;
}
}
Summary
As you can see, there are a countless number of conditions we could add. How many products in the cart, the order total, the customer’s billing country, etc. The list could go on and on. This mini tutorial hopefully helped you get started or pointed in the right direction to getting your checkout fields set up the way you need to.
I know it’s quite a bit of code, and I do plan on releasing a plugin soon for this. So check back in a few weeks and hopefully you’ll see a new plugin over on my plugins page. In the mean time, I’ve turned our tutorial’s snippets into a mini plugin. Feel free to hack away at it to make it work for your needs.
Awesome snippet Caleb! Please note that it will work only with PHP versions > 4.0.1
Good point. As long as it’s above WordPress’ requirement, all should be good: https://wordpress.org/about/requirements/.
Hi Caleb,
nice work! Would it also be possible to manipulate the checkout fields based on the country the user selected?
Hey, thanks! I looked into adding this as an example, but there are some complications. You can get the shipping country using this line, and then set a conditional with it:
$country = WC()->customer->get_shipping_country();
However, the ‘woocommerce_checkout_fields’ hook that lets us remove checkout fields will not be run again when the shipping country is changed. So the page would have to be refreshed after changing the country.
Possible ways around this?
Awesome work Caleb. Came very handy today.
Great with the different examples of how to use it with categories and even coupons.
Thanks
Hi, thank you for your great article. Is it possible to use “unset()” to delete a div in a woocommerce checkout?
Can I use someting like this?
function wc_ninja_remove_checkout_field( $fields ) {
if ( ! wc_ninja_product_is_in_the_cart() ) {
$( “#my_custom_checkout_field” ).remove();
}
return $fields;
}
add_filter( ‘woocommerce_checkout_fields’ , ‘wc_ninja_remove_checkout_field’ );
Hey Andreas,
Uhh, no, not quite. That looks like a mix between PHP and jQuery. This snippet should help you get started on this: https://docs.woothemes.com/document/woocommerce-checkout-add-ons-developer-docs/#section-4
I used exactly that code and is working on my localhost… but i got a server error en production.
I made this for PHP 5.3
I made this por PHP 5.3
function wc_ninja_product_is_in_the_cart() {
global $woocommerce;
$items = array( ’31’ );
// Create array from current cart
$cartitems = $woocommerce->cart->get_cart();
// Count items in cart
$itemcount = count( $cartitems );
foreach($cartitems as $cartitem) {
$productid = $cartitem[product_id];
if(in_array($productid,$items)) {
return true;
} else
{
return false;
}
}
}
/**
* Borra los campos si se cumplen las condiciones indicadas
*/
function wc_ninja_remove_checkout_field( $fields ) {
if ( ! wc_ninja_product_is_in_the_cart() ) {
unset( $fields[‘billing’][‘billing_justify2’] );
}
return $fields;
}
add_filter( ‘woocommerce_checkout_fields’ , ‘wc_ninja_remove_checkout_field’ );
Hi Pedro,
First, I would suggest upgrading to at least PHP 5.4. That’s the minimum required version for WordPress and WooCommerce.
But secondly, I think the issue with your code is some of the quotation marks. You have ‘smart quotes’ all of the place. With code, it is important to use the plain quotes you get when typing in a plain text editor. Try this instead: https://gist.github.com/WPprodigy/aa6b26dce224a43444bd
Hi, I am new to wordpress. I want to hide approx. 10 fields if a product, id=55, is in the cart by itself.
When I follow your “remove checkout field example” from above it works perfectly.
At the “Setting Up the Conditions” sections after I add it to my theme functions.php I get the following error:
Fatal error: Can’t use function return value in write context in E:\web\public_html\…\wp-content\themes\storefront-child\functions.php on line 47
which is the first line of the following part of code:
if ( ! empty( array_intersect( $ids, $cart_ids ) ) ) {
return true;
} else {
return false;
}
Any help you could provide would be great.
Thanks
Roland
Oops, this may be my fault. The code I wrote required PHP version 5.5. You can’t use empty() with a function in it’s parameter below PHP 5.5. You can read more about this here: http://www.php.net/manual/en/function.empty.php
You could update your PHP version (recommended), or just change the code to:
$search = array_intersect( $ids, $cart_ids );
if ( ! empty( $search ) ) {
return true;
} else {
return false;
}
Great article. What call would I make to see if a field has been checked to show another field.
For example:
Field Name: Add VAT (True / False Checkbox)
If TRUE > Show Field VAT
Hiding fields based on other fields requires a different approach. This comment kind of applies here as well: https://calebburks.com/conditionally-showhide-woocommerce-checkout-fields/#comment-16
You will likely need to do this with Javascript. Something like this: https://docs.woothemes.com/document/woocommerce-checkout-add-ons-developer-docs/#section-4
Thanks
Hi
How can I show a custom field based on the quantity products.
================
Product QTY = 1
Custom field:
Text for Engraving
===============
Product QTY = 3
Custom fields:
Text for Engraving 1
Text for Engraving 2
Text for Engraving 3
===============
Thank you
Is there a specific product that you want this quantity rule to apply to, or is this all product’s in the cart?
If it is product specific, you can use the “Product Specific Conditional” from above. And then you can var dump the `$cart_product` variable to find how you can get it’s quantity. To get the whole cart’s quantity, `WC()->cart->cart_contents_count` should do the trick.
However, I don’t think checkout fields are best for this. It would be much better and more user friendly to add a field on the product page instead: https://www.woothemes.com/products/product-add-ons/
Hi Caleb
Thank you for your reply;
I need to use this with Event Tickets ( by Modern Tribe ) to capture the name and email of each attendee, when multiple tickets are bought in one transaction.
When it was still called WooTickets, BuzzMedia created a one file add-on called Wootockets Attendee List which did the job perfectly. http://buzzwebmedia.com.au/wootickets-attendee-list/
I tried the woocommerce product add-ons, but that didn’t work with the quantity field.
Hi Schalk,
Ahh yea, you would need to have the customer add each ticket individually with Product Addons.
Another option could be to construct a Ninja Form and apply it to a product with this: https://www.woothemes.com/products/woocommerce-ninjaforms-product-addons/
With the Ninja Forms Conditional Logic plugin, you could make it so a new name field appears on the product page with each quantity increase (you would want to create your own quantitiy field).
Hi Caleb
Your suggestion worked, but I used Gravity Forms Add Ons.
https://www.woothemes.com/products/gravity-forms-add-ons/
I made my product price $0
Then created a Gravity form price field of $50
And multiplied this by the number attendees selected.
It all works perfectly, except for one thing:
The stock level are always deducted with 1 item, even when 2, 3 or 4 attendees are selected. I can manually rectify this after each order that contain more than one attendee, but it would be nice to have it work right.
Can I commission you to write a function which will make the quantity field read from the Gravity forms attendee value? And what will it cost?
This is a product on the live site:
http://events.moonstone.co.za/product/compliance-report-workshop-stellenbosch/
Should you wish to complete a test purchase, i’ll just reverse it.
This was also requested on Woo Ideas:
http://ideas.woothemes.com/forums/133476-woocommerce/suggestions/6198245-woocommerce-gravity-forms-add-on-inventory
Thank you,
I’m not taking any custom work right now, but one of the Woo Experts should be able to help you with this: http://www.woothemes.com/experts/
Just wanted to say THANKS for the snippet(s) and the walk through explanation. It really came in handy!
Hi Caleb,
Is there any way of setting a custom field to be required only if it appears on the checkout page? At the moment I’ve got a product that I’ve placed into a category and a field only appears on the checkout field if that product is in the cart. I want to make sure those fields are completed by the user as they are important information. However, if I set them to be required then when a person gets to the checkout they cannot complete the transaction because error checking is looking for those fields to be completed.
Hey Mike,
Hmm, I would think that this shouldn’t be an issue, as long as the field is unset correctly.
I just tested by creating a custom required field, and then conditionally unsetting it. As far as I can tell, there is no error when completing checkout when the field has been removed.
Maybe check the priority levels of your hooks and filters?
Caleb,
Do you know how I would create a conditional checkout if a specific payment method is selected?
We want to remove the address & information fields for Cash or Check customers by using the Cash on Delivery payment method (for when customers are paying with cash at our physical shop). We need guest checkout disabled for other reasons, so that won’t work.
So if when we select ‘Cash or Check’ payment method in Checkout, if it could conditionally remove all the contact boxes that’d be incredibly rad.
Dan
Similar to https://calebburks.com/conditionally-showhide-woocommerce-checkout-fields/#comment-16, the ‘woocommerce_checkout_fields’ hook does not get re-fired when the payment method changes at the moment. The best option here would be to use Javascript to remove / hide the fields from the DOM conditionally.
It may be worth noting that the checkout flow is going to be changed in the future: https://github.com/woothemes/woocommerce/issues/10672. So gateways not requiring billing addresses won’t need to ask for one. I’d suggest maybe following that github issue 🙂
Hello Caleb. Thank you very much for your article.
I hope you can help me with my problem:
I need add a new field in the checkout form when change the shipping method radio selector. So, I need to reload the checkout page.
I spent more than 3 hours looking for how can I do this.
Can you help me tell me where is the file to change to force to reload the page??
Thank you very much
Hi,
I’m not entirely sure what the best option is for this. I think your better option would be to write some Javascript that will hide/show the field based on what shipping method is selected.
Thanks for writing this article, Caleb.
I was wondering if you might be able to help me with a slight modification… What I would like to do is completely prevent checkout if no products from a certain category are in the cart.
So let’s say a customer is required to place a product from Category A in their cart in order to checkout — if the customer adds a product from Category B to their cart, but does not have a product from Category A in their cart, the proceed to checkout button is disabled. If a customer adds a product from both Category A and B, or even just a product from Category A, then the proceed to checkout button ill be enabled as per usual.
I can’t quite get this to work for me, so any guidance in the right direction would be much appreciated, thanks.
This is possible, but will take a different type of customization. Instead of just disabling the checkout button, you could maybe make the payment gateways unavailable or not provide any shipping methods.
Just be sure to let customer’s know why they can’t checkout if they aren’t meeting the requirements.
Thanks for that, Caleb.
I will have to look at what I can do.
Hi Caleb,
First of all, congratulations for the code, its awesome.
Its working fine, but i need to hide a field that is not inside the billing fields.
Actually its a custom checkout field to select the delivery date. I’m using an external paid plugin called WooCommerce Delivery Slots.
I tried to replace the the last part of the code
unset( $fields[‘billing’][‘billing_phone’] );
for
unset( $fields[‘jckwds-fields’][‘jckwds-delivery-date’] );
but does not work.
Could you help me get this working?
Thank you!
Best regards,
Fabiano
This plugin is likely still adding it’s custom field to either the billing, shipping, account, or order section. So `$fields[‘jckwds-fields’]` is incorrect.
To find the id of the field and what section it has been added to, you’ll need to look through the plugins code or contact the plugin authors.
Hi Caleb
I want to hide som divs on the checkout page if no coupon code was used. I’ve been googling all day for a solution to my problem and this looks like something that could work. I’m trying to read up on adding css but with my lack of knowledge it’s all guess work at the end.
Can you show an example with inline css added to the false statement and I can take it from there?
Hi
Sorry for the multiple posts but I rearranged the checkout page so I no longer would need a css solution for this. Your tips here should probably do the trick.
I need to hide the order_comments when no coupon is applied. I’ve tried to embed the snippet below (which works) into your snippets but I can’t make it stick.
unset( $fields[‘order’][‘order_comments’] );
add_filter( ‘woocommerce_enable_order_notes_field’, ‘__return_false’ );
Hey,
Sorry, but I can’t provide site customizations here. If it helps, this is how WooCommerce core checks if a coupon has been applied or not:
https://github.com/woothemes/woocommerce/blob/master/templates/checkout/form-coupon.php#L27
Hi Caleb,
This is great but how would it work for a variable product or subscription?
Cheers
Variable and subscription products still have product IDs. There shouldn’t be a problem using the above code for those two items.
I’m not 100% sure, but it may take a little more customization if you need to target a specific variation ID.
Great tutorial. I looked all over for this as I have very limited coding skills. This was the only resource that helped me achieve what I wanted to achieve and it took way less lines of code than other snippets I found on github, which also didn’t work for my needs. The other snippets wouldn’t factor in subscription purchases that contained free trials. Thanks for this article!
I’m using a Turnkey Linux Moodle appliance, and am planning to upgrade the appliance this summer, but right now it is stuck at PHP 3.4.11.1. I was told that it is not recommended to upgrade PHP alone, but to generate a whole new appliance, so I am stuck here for the time being. Would it be too much to ask for a reference as to how to “dial back” your code to work with this version of PHP? Everything works great except (created the custom fields) but the conditional part doesn’t do its thing. Or if that is too much to ask, would you have any (old) references I could look at to get this to work? Thank you.
hi! I was looking for this for a really long time! Thanks God google finally gave me your post! thank you!
And i have one question – how can i give a buyer a certain role by the product he has bought?
That is something more along the lines of WooCommerce Memberships: https://www.woocommerce.com/products/woocommerce-memberships/