WooCommerce: Product Add-Ons (Without a Plugin!)

WooCommerce product add-ons are custom input fields that show on the single product page. They’re called “add-ons” as you can add a product personalization or an upsell (at a cost of course).

For example, you can display a text input to print something on the product. Or radio buttons to select different kinds of product upgrades. Or a checkbox to upsell gift wrapping.

Either way, and of course, there are plugins for that. But first, I want to give you a tutorial to code this by yourself (case study: global custom input text field and no surcharge), so that you can learn something new. Enjoy!

Add a custom input field to each product @ WooCommerce Single Product page

PHP Snippet: Show Custom Input Field @ WooCommerce Single Product Page

/**
 * @snippet       Add input field to products - WooCommerce
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 8
 * @community     https://businessbloomer.com/club/
 */

// -----------------------------------------
// 1. Show custom input field above Add to Cart

add_action( 'woocommerce_before_add_to_cart_button', 'bbloomer_product_add_on', 9 );

function bbloomer_product_add_on() {
    $value = isset( $_POST['custom_text_add_on'] ) ? sanitize_text_field( $_POST['custom_text_add_on'] ) : '';
    echo '<div><label>Custom Text Add-On <abbr class="required" title="required">*</abbr></label><p><input name="custom_text_add_on" value="' . $value . '"></p></div>';
}

// -----------------------------------------
// 2. Throw error if custom input field empty

add_filter( 'woocommerce_add_to_cart_validation', 'bbloomer_product_add_on_validation', 10, 3 );

function bbloomer_product_add_on_validation( $passed, $product_id, $qty ) {
   if ( isset( $_POST['custom_text_add_on'] ) && sanitize_text_field( $_POST['custom_text_add_on'] ) == '' ) {
      wc_add_notice( 'Custom Text Add-On is a required field', 'error' );
      $passed = false;
   }
   return $passed;
}

// -----------------------------------------
// 3. Save custom input field value into cart item data

add_filter( 'woocommerce_add_cart_item_data', 'bbloomer_product_add_on_cart_item_data', 10, 2 );

function bbloomer_product_add_on_cart_item_data( $cart_item, $product_id ){
    if ( isset( $_POST['custom_text_add_on'] ) ) {
        $cart_item['custom_text_add_on'] = sanitize_text_field( $_POST['custom_text_add_on'] );
    }
    return $cart_item;
}

// -----------------------------------------
// 4. Display custom input field value @ Cart

add_filter( 'woocommerce_get_item_data', 'bbloomer_product_add_on_display_cart', 10, 2 );

function bbloomer_product_add_on_display_cart( $data, $cart_item ) {
    if ( isset( $cart_item['custom_text_add_on'] ) ) {
        $data[] = array(
            'name' => 'Custom Text Add-On',
            'value' => sanitize_text_field( $cart_item['custom_text_add_on'] )
        );
    }
    return $data;
}

// -----------------------------------------
// 5. Save custom input field value into order item meta

add_action( 'woocommerce_checkout_create_order_line_item', 'bbloomer_product_add_on_order_item_meta', 10, 4 );
 
function bbloomer_product_add_on_order_item_meta( $item, $cart_item_key, $values, $order ) {
    if ( ! empty( $values['custom_text_add_on'] ) ) {
        $item->add_meta_data( 'Custom Text Add-On', $values['custom_text_add_on'] );
    }
}

Advanced Plugin: WooCommerce Product Options

This article is about how to add WooCommerce product add-ons without a plugin, and the code snippet will allow you to do this. You can use it to add standard field types to your products, such as checkboxes, radio buttons and text input fields.

You’ll need more advanced knowledge to create more complex option types, such as clickable color swatches or images, or custom price formulas. It’s also a bit more complex to assign a price to each add-on, add conditional logic to show and hide options dynamically, and so on. If you need this extra functionality then it might be quicker and easier to use a plugin.

I researched the options and the best product add-ons plugin that I found is WooCommerce Product Options by Barn2. This comes with a huge range of option types and styles, plus advanced functionality such as price options and measurement price calculators.

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 Visual Hook Guide: Single Product Page
    Here’s a visual hook guide for the WooCommerce Single Product Page. This is part of my “Visual Hook Guide Series“, through which you can find WooCommerce hooks quickly and easily by seeing their actual locations (and you can copy/paste). If you like this guide and it’s helpful to you, let me know in the comments! […]
  • WooCommerce: Disable Variable Product Price Range $$$-$$$
    You may want to disable the WooCommerce variable product price range which usually looks like $100-$999 when variations have different prices (min $100 and max $999 in this case). With this snippet you will be able to hide the highest price, and add a “From: ” prefix in front of the minimum price. At the […]
  • WooCommerce: Hide Price & Add to Cart for Logged Out Users
    You may want to force users to login in order to see prices and add products to cart. That means you must hide add to cart buttons and prices on the Shop and Single Product pages when a user is logged out. All you need is pasting the following code in your functions.php (please note: […]
  • WooCommerce: Add Custom Field to Product Variations
    Adding and displaying custom fields on WooCommerce products is quite simple. For example, you can add a “RRP/MSRP” field to a product, or maybe use ACF and display its value on the single product page. Easy, yes. Unfortunately, the above only applies to “simple” products without variations (or the parent product if it’s a variable […]
  • WooCommerce: Show Number Of Products Sold @ Product Page
    WooCommerce database already stores the number of products sold for you. Therefore, you may want to show such number on the product page, close to the Add To Cart button. As we’ve seen in my book Ecommerce and Beyond, showing the number of sales for each product can increase your sales conversion rate. All you […]

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

69 thoughts on “WooCommerce: Product Add-Ons (Without a Plugin!)

  1. Hi,

    I’ve read that the woocommerce_add_to_cart_validation filter has been deprecated. What would be the best replacement for validating a custom form before adding something to the cart instead?
    Couldn’t find anything on Google.

    Cheers,
    Stefan

    1. Where did you read that?

      1. Hello,
        Thank you for your interesting post.
        However, I have the same question as Stefan.

        If you look at the CartController.php (WooCommerce 8.7.0), you will read this:

        “Filters if an item being added to the cart passed validation checks.

        Allow 3rd parties to validate if an item can be added to the cart. This is a legacy hook from Woo core.
        This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to exceptions instead.”

        But, nowhere I could find a replacement suggestion…

        What do you think about?

        KR,

        Pierre

        1. It’s too early to do Woo blocks customization (because the devs are still working on it) – which is the reason I still use the default cart/checkout shortcodes

  2. Hi Rodolfo,
    I just tested this code for add a custom input field (required). But this doesn’t work with direct link like : https://yourdomain.com/?add-to-cart=XX
    or : https://yourdomain.com/?add-to-cart=XX&custom_text_add_on=TEST
    Do you have another article that covers this topic?
    BR

    1. Hello Uman, 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!

  3. The validation doesn’t seem to work if a customer was to add the product to their cart straight from the shop page

    It only runs if the customer added the item to cart from the single product page

    1. Maybe the add to cart button, in this case, should be hidden, because all the logic is on the single product page

  4. Hi, it worked well but now with the new woocommerce 8.4 it throws an error when I try to finish an order:

    Fatal error: Uncaught Error: Cannot use object of type WC_Product_Simple as array ….. in bbloomer_product_add_on_display_order

    1. Doesn’t seem related to my snippet to be honest. Can I have the whole error stack trace please?

  5. Hi, thanks for your code, I am thinking is it possible to add a custom value to that text field programmatically with a custom add-to-cart url?

    Example: https://domain.com/cart/?add-to-cart=10376&variation_id=1133&quantity=1&frequency=1year

    1. Hello Amit, 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!

  6. Just added this code using ‘Code Snippets’ plugin. but get the following error, when pressing save:

    ———-
    Don’t Panic

    The code snippet you are trying to save produced a fatal error on line 11:
    syntax error, unexpected ‘ ‘ (T_STRING)

    The previous version of the snippet is unchanged, and the rest of this site should be functioning normally as before.

    Please use the back button in your browser to return to the previous page and try to fix the code error. If you prefer, you can close this page and discard the changes you just made. No changes will be made to this site.
    ———-

    I don’t see anything wrong with the PHP, but I’m not that good with it yet…?

    1. Weird. What’s on line 11?

  7. Hi Rodolfo,

    I am such a fan of your work. I tested this snippet today with some additional complexity (options based on images) and it stills works!
    Great great job!

  8. Great code. Is it possible to edit it to store the custom text in the product title? My shipping program does not recognize the extra field. It only pulls information from the title.

    1. Hi Josh 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!

  9. Thanks for the snippet, saved my day.

    Is it possible to extend its functionality to include added cost for custom fields. Like when a custom field is checked / selected or filled with specific value, a pre-determined extra price is applied to the product price. Is it to be done with PHP or JS or both. I am curious how it could get implemented.

    Thanks

    1. Thanks for your comment Shawn! As of now, this snippet does not come with custom pricing. I’ll see if in the future I can provide an add-on to make it work the way you want. Stay tuned!

  10. Hi. This code is really awesome. Thank you for sharing it. I’m looking to do exactly this, but with a bit of a twist. I have a few variations set for my product, and I want the custom field to only appear if a particular option is chosen from one of my variations. How complicated would it be to do this?

    1. Hi Don, 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!

  11. Hi. Awesome code! How could I add this for a downloadable file add on?

    1. Hi Jennie, 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!

  12. Dear, would it be possible to limit this snippet to just 1 particular product?
    Could I add the

    if ( $product->get_id() !== 21 ) {
    return;

    somewhere? There’s only 1 product that needs the engraving option on my website…
    Thomas

    1. Absolutely. I suggest you take a look at “conditional logic”: https://businessbloomer.com/woocommerce-conditional-logic-ultimate-php-guide/. Enjoy 🙂

  13. Hello,

    Thank you very much for the great tutorial and code!!

    I am working on the first function (

    bbloomer_product_add_on()

    ), adding a

    <script>

    in javascript to preview the text, but I have a trouble with the code. The point is, if I keep

    echo' ';

    line as in your example, the javascript doesn’t run properly. However, if I add the label

    <form>

    and

    </form>

    in the same

    echo' ';

    line of your example, after and before the

    <div>

    , the javascript code works perfectly, but the rest of the php code doesn’t. The value is not saved in the variable

    $value

    and the button Add to Cart doesn’t work.

    Is there any way to solve it? I have been searching on the internet but I haven’t found nothing about incompatibilites between php and javascript nor problems with the label .

    Thank you in advance!
    Phil

    1. Hi Phil, 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!

  14. Hi
    First thanks for great tutorials.

    i have a problem with this snippet (unchanged) it generates error: Notice: Undefined index: _custom_text_add_on
    from this line of code: $value = isset( $_POST[‘custom_text_add_on’] ) ? sanitize_text_field( $_POST[‘_custom_text_add_on’] ) : ”;
    this appears when text field is not used (no text entered) when trying to buy product. any fix for this?

    WP and Woo are fully updated where i try this snippet.

    1. That must be a bug – there is an extra underscore at the beginning here: “_custom_text_add_on”. I’ve now revised the snippet, test again please 🙂

  15. How can I use text field instead of radio button on my single product page?

    1. Hi Reza, 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!

  16. Hi, thank you very much for your very valuable material. I have a question for you. Can your code be displayed in a different place with a different snippet than “woocommerce_before_add_to_cart_button” ?

  17. Anyway to ensure the style of this field matches the rest of the page? No class gets applied to the DIV

    1. Hey Shiva, 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!

  18. woocommerce_add_order_item_meta is deprecated since version 3.0.0

    Can you update it?

    1. I’m now using “wc_add_order_item_meta” here. That ok?

      1. Hi Rodolfo,

        The hook “woocommerce_add_order_item_meta” is now deprecated, not the wc_add_order_item_meta function.

        I get the following message in my logs:
        woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead.

        But I’m struggling to understand the new hook. Can you help please?

        1. Hi Rajeev! Not fully sure about this statement:

          The hook “woocommerce_add_order_item_meta” is now deprecated, not the wc_add_order_item_meta function.

          My snippet doesn’t use the woocommerce_add_order_item_meta function any longer, so not fully sure why you’re getting the error in the logs?

  19. Hello,
    I want to get word file instead of text in product page.
    How can i place browse field option on product page.?

    1. Hi Asad, 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!

  20. Thank you for this. It’s very helpful!

    // 6. Display custom input field value into order table

    $cart_item_meta is not defined. Should it be $cart_item?

    1. Yes, well spotted! Thanks

  21. Great! Works perfect, but is it possible to add as many fields as you like? I need about 6 on my page.

    1. Hello Dan, 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!

  22. Hello,

    on product page everything display perfect but in cart I have this “Warning: Invalid argument supplied for foreach()”

    What should I do?

    1. Hi Monika, did you use my exact code?

  23. Hello sir,
    I want to replace text field by checkbox field, how can I do that?
    Thanks.

    1. Hi Bakintek, 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!

  24. Great code Sir!

    Thank You very much.

    I have 1 question regarding the product input field: is it possible to check (via Ajax?) if desired entry for a specific product already exist and if so notify customer to input some other value?

    Thanks in advance

    1. Hello Simo, 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!

  25. Great post, thank you very much for the time and effort.
    Could you give us a hint on how to add a surcharge depending on product add-ons such as the text field of this snippet?
    I´m guessing there must be some filter hooks that allow it, but I am having difficulties finding them among all the info of the WooCommerce documentation.

    1. This should work, put it between „Save custom input field value into cart item data” and „Display custom input field value at Cart” section:

      // 3,5. Add fee ;)
      
      add_action( 'woocommerce_cart_calculate_fees', 'bbloomer_add_checkout_fee' );
        
      function bbloomer_add_checkout_fee() {
         foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
              if (!empty( $cart_item['custom_text_add_on'] ) ) {
              	WC()->cart->add_fee( 'Product Add-on fee', 55 );
                  break;
              }
          }
      }
      1. Hello,

        Jumping over this great code 🙂

        Thank you for this. Any idea now on how to multiply the surcharge linked to a product variation ?

        However, I wish to add a radio checkbox with “Add some eggs (+10$)” but depending on the length of the chosen variation it would be a higher price than 10$.

        Is it possible to link this function to a product variation ?

        Many thanks for your help.

        1. Hi Gauthier, 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!

          1. With the help of the above script I managed to calculate an amount for adding text. However, when I pay for two or three or more products by entering text, I will only be charged once. Can this be solved by having to calculate costs for each product?

            1. I guess can you not multiply the amount by the product quantity?

  26. Your page is a greate help to understand how woocommerce / php work and to modify.
    Just have the problem that I have 2 languages. Normal pages and products are translated with WPML but if I do something in function.php how can I check the language or give different content for each language – for example the field description?

  27. Hi, this is great!
    However, I’ve tested it on a couple of sites and doesn’t seem to save/show the field’s value on the cart, checkout or confirmation email. Is this code saving the value in the database?
    Thank you!!

    1. Hi, having the same problem: the field is shown on the details page but not when it comes to checkout or paywall.

      Btw: thanks for the work you are doing here!

      1. Did you customize my snippet?

  28. it doesn’t carry the text over to the cart and neither does it save it to the order or display the text on the thank you page.

    1. You’re right Jess, sorry, I got confused between “_custom_text_add_on” and “custom_text_add_on” in part 3. Should work now, please let me know 🙂

  29. I think this is a great addition to products such as nameplate necklaces. I’ve added a custom field to the checkout page for such instances. BUT… how would you implement this code to show up only on certain product pages and not all of them?

    1. Hello Alexander, I suggest you take a look at “conditional logic”: https://businessbloomer.com/conditional-logic-woocommerce-tutorial/ and https://businessbloomer.com/woocommerce-conditional-logic-ultimate-php-guide/. Let me know 🙂

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 *