news icon

WooCommerce Tips & Tricks – Only allow specific product combinations in cart

This post was written in December 2015. Based on our tests, the code works with with WooCommerce 2.5 and 2.6. Please keep in mind that the code example are provided “as is”, without explicit or implicit warranties. You might have to adjust the code to make it work with your specific configuration.

Update – 01 March 2018

You can find a link to the code for WooCommerce 3.x at the bottom of the article. 

A member of the Advanced WooCommerce group on Facebook presented an interesting challenge. She needed to allow customers to purchase any products freely, except in one case. She had a specific product (let’s calls it Product X) that had to be purchased “alone”, without any other product being present in the cart. In short:

  • If Product X is in the cart, that must be the only product in the cart.
  • If Product X is not in the cart, any other product can be added to it and purchased at the same time.

Our friend Rodolfo, from BusinessBloomer, posted a solution that he adapted from his solution to allow only one product to the cart. It works, but in our opinion, that approach presented a few limitations:

  1. It works by emptying the cart when Product X is added after the other products. If a customer adds Product X to the cart, then he can add other products, and they will stay there.
  2. It doesn’t allow to have combinations of products (e.g. Product X and Product Y allowed together).
  3. It doesn’t make clear to the customer that other products cannot be purchased together with Product X (all products retain their “Add to cart” button, even if they should not).
  4. It empties the cart explicitly. We try to avoid this type of calls whenever possible, and rely on WooCommerce’s internal logic to decide what items should be removed, and when.

Our approach

Taking advantage of the experience gained with the development of our Prices by Country plugin, we prepared a different solution, which, in our opinion, is more flexible and user friendly. It brings the following advantages:

  • It covers the requirement described above, where a specific product (e.g. Product X) must be the only one in the cart.
  • It also allows to have more than one product allowed in the cart (e.g. Product X and Product Y), while excluding all others.
  • It clearly informs the customers that some products can’t be purchased anymore.

You can find it below, described step by step. The code can be added to the theme’s functions.php, or packaged in a plugin, if needed. It has been tested with WooCommerce up to version 2.5.

Step 1 – Keep track of what’s in the cart

The first thing to do is to determine what is in the cart. The content of the cart will dictate what else can be added to it. We do this operation only once per page load, for better performance.

/**
 * Retrieves the cart contents. We can't just call WC_Cart::get_cart(), because
 * such method runs multiple actions and filters, which we don't want to trigger
 * at this stage.
 *
 * @author Aelia <support@aelia.co>
 */
function aelia_get_cart_contents() {
  $cart_contents = array();
  /**
   * Load the cart object. This defaults to the persistant cart if null.
   */
  $cart = WC()->session->get( 'cart', null );

  if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart', true ) ) ) {
    $cart = $saved_cart['cart'];
  } elseif ( is_null( $cart ) ) {
    $cart = array();
  }

  if ( is_array( $cart ) ) {
    foreach ( $cart as $key => $values ) {
      $_product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );

      if ( ! empty( $_product ) && $_product->exists() && $values['quantity'] > 0 ) {
        if ( $_product->is_purchasable() ) {
          // Put session data into array. Run through filter so other plugins can load their own session data
          $session_data = array_merge( $values, array( 'data' => $_product ) );
          $cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
        }
      }
    }
  }
  return $cart_contents;
}

// Step 1 - Keep track of cart contents
add_action('wp_loaded', function() {
  // If there is no session, then we don't have a cart and we should not take
  // any action
  if(!is_object(WC()->session)) {
    return;
  }

  // This variable must be global, we will need it later. If this code were
  // packaged as a plugin, a property could be used instead
  global $allowed_cart_items;
  // We decided that products with ID 737 and 832 can go together. If any of them
  // is in the cart, all other products cannot be added to it
  global $restricted_cart_items;
  $restricted_cart_items = array(
    737,
    832,
  );

  // "Snoop" into the cart contents, without actually loading the whole cart
  foreach(aelia_get_cart_contents() as $item) {
    if(in_array($item['data']->id, $restricted_cart_items)) {
      $allowed_cart_items[] = $item['data']->id;

      // If you need to allow MULTIPLE restricted items in the cart, comment
      // the line below
      break;
    }
  }
});

Step 2 – Prevent disallowed product combinations

Now that we know what’s in the cart, we can prevent some products from being added to it if any of the “restricted” products are present. Emptying the cart would not work, as we would risk to throw away one of the allowed products. Instead, we simply make the disallowed products unavailable. This will have several effects:

  • If any of the disallowed products is already in the cart, WooCommerce will remove it.
  • The Add to Cart button will be replaced by a Read More button on the disallowed products. Customers won’t be able to add the products back, and will instead get a note explaining that they cannot be purchased.
// Step 2 - Make disallowed products "not purchasable"
add_filter('woocommerce_is_purchasable', function($is_purchasable, $product) {
  global $restricted_cart_items;
  global $allowed_cart_items;

  // If any of the restricted products is in the cart, any other must be made
  // "not purchasable"
  if(!empty($allowed_cart_items)) {
    // To allow MULTIPLE products from the restricted ones, use the line below
    //$is_purchasable = in_array($product->id, $allowed_cart_items) || in_array($product->id, $restricted_cart_items);

    // To allow a SINGLE  products from the restricted ones, use the line below
    $is_purchasable = in_array($product->id, $allowed_cart_items);
  }
  return $is_purchasable;
}, 10, 2);

At this stage, we have the code that fulfils the original requirements. However, we need one extra step to make it more elegant.

Step 3 – Explain customers why some products cannot be purchased anymore

As we have seen, the code in step 2 prevents some products from being added to the cart if Product X and/or Product Y are already present, but it doesn’t explain customers why. We just need to show them a message with some information about the restrictions, to make things clearer.

// Step 3 - Explain customers why they can't add some products to the cart
add_filter('woocommerce_get_price_html', function($price_html, $product) {
  if(!$product->is_purchasable() && is_product()) {
    $price_html .= '<p>' . __('This product cannot be purchased together with "Product X" or "Product Y". If you wish to buy this product, please remove the other products from the cart.', 'woocommerce') . '</p>';
  }
  return $price_html;
}, 10, 2);

Step 4 – Combining the code

For the snippets above to work together, we must combine them in the correct order. More specifically, the code from step 2 should go inside the code from step 1. Here’s the complete code, ready to be pasted in the functions.php file: http://pastebin.com/BRU1BP2E.

Update – 01 March 2018

We prepared an example of how the code can be adapted for WooCommerce 3.x. You can find the code here: https://pastebin.com/tRbJKt37.

Step 5, 6, 7, etc – Improvements

The above solution is fully functional, but it would be possible to make it more elegant and flexible. Further improvements to the code could include the following:

  • Packaging the code as a plugin. This will help avoiding global variables and could make the code tidier and easier to read.
  • Adding support for groups of restricted products (e.g. Product X and Y or Product A and B, etc).
  • Adding a dynamically generated message, showing exactly which restricted products are in the cart, instead of relying on static text.
  • Adding formatting to the message displayed to the customers.

Should you need assistance adapting the solution to your needs, or implementing any of the above optimisations, please feel free to contact us. We will review your specifications and provide you with a quote for your customisation.

The Aelia Team

93 replies
  1. WillyVB91 says:

    Hello,

    Sorry for the disturb I have some questions to do, is possible speak with you by email or on a social page/forum?

    Reply
    • diego says:

      Hi Willy, your comment was filtered by mistake by our antispam system. I see that you already found our support portal. 🙂

      Reply
  2. vincenzo says:

    Hi thanks for your article it is really helpful. Is it possible to use products categories instead of single products? I’ve created two categories one with products I can buy with real money and another one with products I can by with points. Woo Commerce doesn’t permit any payment if these products are together in the cart because the plugin can’t split the cart with two different payment gateway. Unless you have any other solution i think i need to use your snippet.
    Many thanks for your help

    Reply
      • vincenzo says:

        Hi many thanks for your help.
        If i can ask, how do you send email to inform user their comments is awaiting for approval after they post a comment? It’s really amazing. Many thanks

        Reply
        • diego says:

          I think it’s done by the Akismet plugin. We haven’t configured anything specific to send that notification, it’s sent automatically. 🙂

          Reply
          • vincenzo says:

            Hi Diego, thanks for your answer.
            Is there any way to avoid a user to purchase a product if he has already mouth another product? For example i’ve got two products A and B. If user has bought product A he can’t buy product B
            Many thanks

          • diego says:

            That should also be possible, you will simply have to check customer’s previous purchases. You can check if the customer bought a product by calling the aptly named function wc_customer_bought_product(). Simply check, for Product A, if customer already bought Product B, and vice-versa, and you will be able to make the products available, or unavailable, dynamically.

          • vincenzo says:

            Hi Diego,
            Many thanks for your answer. Unfortunately i’m not very good with coding in php. I thought i had to use the function you suggested but i can’t find anything on the web. Do you think you can help me?
            Many many thanks

          • diego says:

            If you need a full, ready made customisation, we can definitely write one for you. The only “wrinkle” is that it might take some work and we might not be able to do it free of charge. If you are interested in discussing it, please feel free to get in touch. We will be closed tomorrow (it’s St Patrick’s, here in Ireland), but we will get back to you as soon as possible.

    • John Hoff says:

      Hi vincenzo 🙂 I’m writing to find out if you were able to make the adjustment from product ID to product category. I would greatly appreciate any insight you may be able to provide on how to make this adjustment.

      Thank you!

      Reply
  3. Zakaria Shahed says:

    Hello sir
    I Have 4 product suppose A,B,C,D,E,F,G,H and here i want If i add A in my cart then It will restrict for B,C,D only and shows massage.That User Need to buy separately but they can buy this A and F together

    Reply
    • diego says:

      The article describes exactly how to do that. You just have to look at the $restricted_cart_items element in the code. In that array you can enter the products that can go together in the cart (in your case, A and F).

      Reply
        • diego says:

          The code is already there, ready to be used. You just need to set the correct product IDs and it will work, out of the box. 🙂
          If you need assistance implementing a specific customisation, we offer consultancy services as well. If you wish to avail of our services, our standard rate is 80 EUR/hour, plus applicable VAT.

          Reply
  4. Roz says:

    This is exactly what I am looking for, to not allow a specific product to be in cart with any other products from our store, yet your code gives me multiple red flag syntax errors when I paste it into my functions.php (I do this in dreamweaver)

    Reply
    • diego says:

      Hi Roz,
      The code works fine on our servers. Make sure that you copy it from the pastebin link, as the article itself may contain formatting elements that are not valid PHP code. Also, the code is tested on PHP 5.3 or later. If your editor uses an older version for parsing, then it will show you some errors, but the code may run fine on your site.

      Reply
    • diego says:

      I’m afraid that I can’t say what the exact issue could be. The code from http://pastebin.com/raw/BRU1BP2E is correct, the issue you see seems to be caused by something else. The message indicates line 247, which is above the code you show in your screenshot. Most likely there is an error somewhere else, and this causes a “cascade” of syntax errors down the line.

      Reply
  5. Roz says:

    Ive even pasted it as the top, and as the only code in the file and it still gives me the same syntax errors. I tried pasting it in an online sytax checker and it says its ok so its definitely dreamweavers problem. I’ll give the customization a try. thanks!

    Reply
  6. Roz says:

    I found the perfect addition to your script. The latest version of WC doesn’t seem to show your error message but if users install this plugin, they can make changes to any error message they want, which will tie in your awesome script and allow for explanations of product removals, etc.

    https://wordpress.org/plugins/say-what/faq/

    Thanks again for your quick replies!

    Reply
    • diego says:

      Hi Roz,
      Thanks for the update. That’s right, we haven’t tested the snippet with WooCommerce 2.6 (if you look in the code, it specifies that it was tested up to WooCommerce 2.5). I would be surprised if they broke the way that error messages are displayed, but it may be worth having a look at that later. Thanks again for your feedback.

      Reply
  7. Iara says:

    I love it, thank you!
    But it does not seem to work in the woocommerce new version (Fatal error). T________________T

    Reply
    • diego says:

      Hi Iara,
      Your comment was filtered by our system as spam by mistake, sorry about that.

      The code you found on our article works fine in WooCommerce 2.6, it doesn’t cause any fatal error. Perhaps you made some mistake in implementing it. One of the most common issues is pasting it after a closing PHP tag (i.e. ?>), or using only part of it. Another relatively common issue is pasting multiple copies of the code (we had a few users who did it, in the past, thus causing errors due to duplicate functions).
      If you use the complete code from Pastebin, it should work just fine.

      Reply
  8. Daniel says:

    Hi,

    I put the code inside wp-content/plugins/myfolder/myfile.php.

    When i activate it, its output all the code in the top of the wp-admin.

    Can you help please,
    Daniel

    Reply
  9. Kedar says:

    Hi there! This snippet works great, but if the user adds a non-restricted product FIRST, then they’re still able to add restricted items. Would there be a way to prevent that?

    Reply
    • diego says:

      Hi Kedar,
      You’re right: the checks only verify if a restricted product is in the cart. If none of the restricted products are in the cart, the existing logic assumes that any product can be added to it (restricted or not). You should be able to extend the check by modifying the woocommerce_is_purchasable function in the snippet. The check should be something like the following (off the top of my head, I haven’t implemented it): if the cart is not empty and doesn’t contain restricted products, and the product being checked is restricted, then that product should not be purchasable.

      Reply
  10. Andy Hinkle says:

    Hello, this does not work with the latest version of WordPress. I was able to add different categories after I added the Pastebin to functions.php

    Reply
    • diego says:

      The code doesn’t check for product categories, but for single product IDs. If you need to allow specific product categories, then you will have to adapt the code for that purpose. You can find a code snippet to retrieve the categories for a product here: WooCommerce Tips & Tricks – Get all the categories to which a product belongs.

      Please also keep in mind that are several elements that come into play when a product is added to the cart (other plugins, other custom code, etc), and some of them might interfere with the code we wrote. If you need a custom solution tailored to your needs, please feel free to contact us to request a consultation.

      Reply
  11. Reese says:

    Hello, and good afternoon 🙂

    I am using WC v. 3.0.4, and I would like to use this plugin to only allow certain products B & C, in the cart IF the customer already has added product A. I have already set B & C as up-sells for A, and B&C area also hidden from the catalog view, but I do not want the customer to be able to add them unless A is already in cart, and if possible, that B&C are removed from cart if A is removed.

    Thank you 🙂
    — Reese

    Reply
    • diego says:

      This custom code is designed to prevent customers from adding a product to the cart if specific ones are already in the cart. What you are trying to do is the opposite, i.e. preventing the purchase if some specific product() is not in the cart. For that purpose, you will need a different customisation. If you wish, you can contact our support and consultancy service, and they can prepare an estimate to implement this customisation.

      Reply
  12. Dan says:

    Thanks so much for this snippet. I’m struggling because I keep getting “Call to undefined function WC()” on line 50 and all my troubleshooting doesn’t seem to help. Any thoughts? Thanks!

    Reply
    • diego says:

      The `WC()` function is part of WooCommerce core. If you use the code from our Pastebin, then it will run when the wp_loaded event is triggered. That event runs after WooCommerce has been fully initialised, therefore function `WC()` is guaranteed to be exist. If that is not the case, I would guess that either WooCommerce is not configured, or not loaded correctly.

      Also, we are not aware of any conflicts with the Stripe payment gateways. The custom code runs before any payment gateway code is used, and should not cause any conflict. However, as the article explains, we wrote the code in December 2015. It might need some adjustments to work with WooCommerce 3.0.x (we haven’t prepared a revised version for it, yet).

      Reply
  13. Ricardo says:

    Hello Diego

    Thank you for your code, it’s really helpfull and you are the only to talk about that.

    However in my case i can’t figure how to modify your function for my needs.

    I have bunch of “physical” products and 2 subscription products call “premium” and “premium+”
    I add “add to cart button” for each of them below the cart directly (it’s options like amazon premium service).

    “Premium” give a certain amount of services
    “Premium +” offer all services provide by “premium” with extra.

    My scenario: Customers can add as “physical” products as they want in their cart but can add only one of these 2 premium services (premium OR premium plus).

    If they already add “premium” to the cart and then want to add “premium plus” on the same cart, it must display a message telling “sorry but you must remove the other premium service before”

    Thank you for your help

    Reply
    • diego says:

      The code is designed to do what you describe. If you add the IDs of the two “premium” and “premium+” products to variable $restricted_cart_items (see Step 1), only one of the two can be added to the cart at any given time. Then you can customise the message in Step 3 to invite the user to remove the premium service from the cart before adding the other one.

      Please keep in mind that the code was designed for WooCommerce 2.5 and 2.6, as indicated at the top of the article. We haven’t tested it with WooCommerce 3.x, it might require some adjustments for those versions. If you would like to have the custom code tailored to your specific needs, please feel free to get in touch. We can review your specifications and schedule a consultation to package the code into a standalone plugin that you can install to your site.

      Reply
      • Dick says:

        What you write as an answer is not what is happening, as when you add the 2 memberships (i have 4 on my website) you can only add 1 (which is correct) however you cannot add ANY other product as well (in the case of this example all the other physical products!)
        So how can you achieve that?
        To explain clearly:
        – the customer can ONLY choose 1 membership
        – the customer can add as many OTHER PRODUCTS to his cart as he wishes
        As now it gives the message if you add any other product to the cart…

        Thanks for your help.

        Reply
        • diego says:

          What you describe is correct, it’s what the code is supposed to do. The purpose of the code is to exclude all other products when one of the restricted ones is in the cart. As described at the very beginning of the article, the logic is the following:
          – If Product X is in the cart, that must be the only product in the cart (therefore, exclude all other products, just like you saw happening).
          – If Product X is not in the cart, any other product can be added to it and purchased at the same time.

          Your requirements are different from what the code does. You need to have a list of products and ensure that only one of them is added to the cart at any given time. Any products that are not in the list can be added freely, regardless of the cart content. That will require a different approach, therefore different code. We don’t have a ready made example of how to do that, but I think you will have modify the filter for hook woocommerce_is_purchasable and perform the following checks:
          – Check if the product is in the list of the restricted items. If it’s not, do nothing.
          – If the product IS restricted, check if any of the restricted products other than the current one is already in the cart. If that’s the case, return false, so that the customer won’t be able to purchase another restricted product at the same time.

          If you need assistance implementing your custom logic, please feel free to get in touch. We can review your specifications and prepare an estimate for the implementation of your custom logic.

          Reply
  14. Melissa Boverhof says:

    So the array function is not working for me. (See Below) Once one of the restricted products is added to the cart, it will not allow any more products to be added. Any ideas why this is happening?

    // This variable must be global, we will need it later. If this code were
    // packaged as a plugin, a property could be used instead
    global $allowed_cart_items;
    // We decided that products with ID 737 and 832 can go together. If any of them
    // is in the cart, all other products cannot be added to it
    global $restricted_cart_items;
    $restricted_cart_items = array(
    1000778,
    1000779,
    );

    Reply
    • diego says:

      That’s correct. The code is designed to prevent customers from adding any other product to the cart, if any of the products in the $restricted_cart_items list is present. With your code, it means that you can add product 1000778 and 1000779 to the cart at the same time. The code will prevent you from adding any other product, as long as either of the two is in the cart.

      Reply
  15. Marcvill says:

    Hi, would just like to ask if this code/solution still works without issues using the latest WordPress and WooCommerce versions? Thanks 🙂

    Reply
    • diego says:

      The WordPress version should not make any difference. We haven’t tested the code with WooCommerce 3.x, but it could still work. We would just recommend to replace calls like `$product->id` with `$product->get_id()`, as accessing properties directly is a deprecated approach in WooCommerce 3.0 and newer.

      Reply
  16. Shujaa says:

    Can you please update this code for WooCommerce version 3.3
    This is exactly what I need but its not working with my current version of woocommerce.

    Reply
    • diego says:

      Although we haven’t tested the code with WooCommerce 3.x, it should still work fine. The only change you should have to make to prevent WC 3.3 from raising notices and warnings should be to replace all occurrences of `->id` with `->get_id()`. The rest of the logic should still work as it did before.

      Reply
  17. Paul says:

    Is there an update to this code? I copied and pasted it in functions.php and the whole thing screwed and i couldnt save!

    Here is the debug

    Your PHP code changes were rolled back due to an error on line 80 of file C:\xampp\htdocs\test\wp-content\themes\corporatesource-child\functions.php. Please fix and try saving again.

    Uncaught Error: Call to undefined function aelia_get_cart_contents() in C:\xampp\htdocs\test\wp-content\themes\corporatesource-child\functions.php:80
    Stack trace:
    #0 C:\xampp\htdocs\test\wp-includes\class-wp-hook.php(286): {closure}(”)
    #1 C:\xampp\htdocs\test\wp-includes\class-wp-hook.php(310): WP_Hook->apply_filters(NULL, Array)
    #2 C:\xampp\htdocs\test\wp-includes\plugin.php(453): WP_Hook->do_action(Array)
    #3 C:\xampp\htdocs\test\wp-settings.php(471): do_action(‘wp_loaded’)
    #4 C:\xampp\htdocs\test\wp-config.php(89): require_once(‘C:\\xampp\\htdocs…’)
    #5 C:\xampp\htdocs\test\wp-load.php(37): require_once(‘C:\\xampp\\htdocs…’)
    #6 C:\xampp\htdocs\test\wp-blog-header.php(13): require_once(‘C:\\xampp\\htdocs…’)
    #7 C:\xampp\htdocs\test\index.php(17): require(‘C:\\xampp\\htdocs…’)
    #8 {main}
    thrown

    Reply
    • diego says:

      That error indicates that function `aelia_get_cart_contents` is missing, which means that the code is incomplete. If you scroll towards the bottom of the article, you will find the links to the complete code, which you can adapt to your requirements.
      Should you need assistance with the implementation of the customisation, please feel free to contact us. We will review your specifications and prepare an estimate for the work. Thanks.

      Reply
  18. Jmarck says:

    Hi,
    Is this working for category? Category TEST cannot be mix in other category. Also what if there are two items already in the cart then I change the category of one product to TEST category, is there a way to disable the checkout button and add warning message that they cant be mixed and need to remove the item?
    Thanks

    Reply
  19. Shujaa says:

    I would like to use your code but instead of PRODUCT ID’s, I need it modified to use CATEGORY ID’s.

    Reply
  20. Tanmoy Kundu says:

    Snippets works as expected. But I’ve a concern if you can help me out.

    Let’s say I’ve three products P1, P2, P3 . I made P1 restricted so when I added it to cart, it’s showing that warning message to other products page which is perfect so far. But when I first added P2 or P3 into cart and trying to add P1 into cart, it just forcefully delete already added item to cart and adds itself. Here what I need is when P2 or P3 is added to cart and I am into P1 details, it should also show me warning message and will disable the add to cart option.

    Thanks so much!

    Reply
    • diego says:

      Hi Tanmor,
      The code doesn’t remove products from the cart, it flags products as “not purchasable” when the cart contains some “restricted” products. WooCommerce then removes such “not purchasable” products from the cart. The “product not available” message is displayed on the page of products that are unavailable due to the purchase restrictions, and it appears as long as such restrictions are in place. That is:
      – If P1 contains restricted products, P2 and P3 will show the “product not available” message.
      – If you add P2, P3, then P1, WooCommerce will remove P2 and P3, because they become “not purchasable”. If you go to the product pages of P2 and P3, you will see the “product not available” message. Additionally, WooCommerce will show a message like “Product XYZ has been removed from your cart because it can no longer be purchased“.

      If you need to display some other message when a product is removed, you can intercept event `woocommerce_remove_cart_item_from_session`. That event receives the details of the cart item that has just been removed, and you can use them to display a custom message, by using function `wc_add_notice()`.

      Reply
      • Tanmoy Kundu says:

        Actually instead of removing the existing product from the cart, can’t I not show same ‘product not available’ message when I am visiting the restricted product’s single page like it does for non restricted product?

        Reply
        • diego says:

          The message will appear for all products that are not allowed to be added to the cart.
          – Any product that is not in the list you enter in the code will become unavailable when one of those products is added to the cart.
          – Any product that is in the list will still be allowed. The list is supposed to contain IDs of products that can go together in the cart.

          Reply
          • Tanmoy Kundu says:

            Hi Diego,

            I completely understand how the code works and what does it do but I was looking for solution for the above mentioned point i.e. instead of forcefully removing the product from cart, can we not show the unavailable message like it does for other case

          • diego says:

            I’m not sure what you mean with “the other case”. The code makes a product “not purchasable” when one of the restricted products is in the cart. As soon as a product becomes not purchasable, WooCommerce removes it from the cart automatically. This is not controlled by the custom code, it’s how WooCommerce core works. All products that become unavailable then show the “unavailable” message.

          • Tanmoy Kundu says:

            ::with refer to the previous comment since that doesn’t have reply button::
            So what I meant is instead of forcefully removing the added item, can’t we also show a warning message to single product page of restricted product when others(which are not restricted) are already into cart?

          • diego says:

            If I understand correctly, you would like to do the following:

            • When products A, B or C are in the cart, products X, Y and Z can’t be added.
            • When products X, Y or Z are in the cart, products A, B and C can’t be added.

            That can be done, but it requires a different approach, as the code in the article is not designed to handle that scenario. Unfortunately, we don’t have a ready-made example for that. If you need assistance with the implementation, we can prepare an estimate for it.

      • Tanmoy Kundu says:

        Hi Diego,

        Also I am getting to see that I am able to make product id into restricted not product category, am I doing anything wrong?

        Reply
  21. Jelo says:

    Hi diego,

    I entered 3 product IDs but if I add to cart one of the 3 products, the other two can’t be added also. I think the code only reads 1 product ID. How can I resolve this? Thanks!! 🙂

    Reply
    • diego says:

      The behaviour you describe is correct. Out of the box, the code excludes all other products when a restricted one is added to the cart. There’s a line, in the code to allow multiple restricted items to be added at the same time. If you scroll towards the bottom of the code, you should see a line saying To allow MULTIPLE products from the restricted ones, use the line below. If you uncomment that line, you should be able to add multiple products.

      Reply
  22. Ryan Bonnell says:

    This is code snippet exactly what I was looking for. Thanks Aelia! I saw Rodolfo’s post on businessbloomer with the quick solution and thought it was a little limited.This helps me a great deal with the WordPress site we are developing.

    Reply
    • diego says:

      Hi Ted,
      We weren’t aware of the Product Dependencies plugin. It seems a promising solution, we will keep an eye on it. 👍

      Reply
  23. Dave Filchak says:

    So, can you make this work with category_id? I need to add restrictions for example, that if there is a product already in the cart from a specific category, not other categories can be added. On the flip side, if products not in the restricted category are already in the cart, products from the restricted category cannot be added to the cart unless the the unrestrict category products already in cart are removed. has this been done? Is there a plugin, a cost?

    Reply
    • diego says:

      Hi Dave,
      Unfortunately, we don’t have a ready-made solution to restrict products by category. There are a few comments, on this article, related to this topic, which explain how to fetch the categories from a product. You can use that information to replace the product IDs with category IDs, then alter the code snippet slightly to check for the category of each product in the cart and compare it with the “restricted” category IDs. If you need assistance with that, we also offer consultation services to implement this kind of custom solutions.

      Reply
  24. Tim says:

    Hi Diego,
    great work on this code! I am trying to get the code, that you adapted for WooCommerce 3.x. but pastebin.com seems to be down. Would you mind sending me the code via email?
    Thanks a lot!

    Reply
  25. Enrique says:

    Hi Diego,
    We succesfully applied your old code for WC 2.5 more than a year ago but it recently started to fail after updating to WC 3.5 and later versions. Then we tried your updated code for 3.x without success.
    It always shows the word “Array” instead of our customized explanation that used to show weeks ago when the customer tried to add a restricted product to the cart.
    We’ve also changed some $product->id to $product->get_id() as you cleverly advice.
    Maybe some needed code tweaking after WC 3.5 upgrade?

    Thanx a lot,
    Enrique

    Reply
  26. Enrique says:

    Hi Diego,

    We’ve tried by isolating the code alone in the functions.php and by deactivating the other plugins but we always get the error. We have set PHP 7.3 on the sever.
    Could you have a look to the functions.php and provide an estimate for fixing it when you find the problem?

    Regards

    Reply
    • diego says:

      Thanks for getting in touch. We haven’t tested the code snippet on WooCommerce 4.x, but it should still work, as the cart logic is the same as 3.x versions.

      Reply
    • diego says:

      Thanks for getting in touch. We haven’t tested the code snippet on WooCommerce 4.3, but there haven’t been significant changes in the cart logic since version 3.6, which the last one we tested. Due to that, the snippet should still work.

      Reply
  27. Aryan says:

    Amazing solution. Thank you!

    While it worked perfectly for me to avoid adding two memberships in the checkout, it beautifully restricted second membership adding in the cart while first was there. Now, apart from the two memberships all other products should be ALLOWED, as per your code, it’s denying anything getting added. How do I allow all other products if user wants?

    Sorry, I am not a coder but can try to use a readymade code with few changes. Please advise what to do in your script so that I allow-

    1. Only 1 membership to be added (already working)
    2. Do not restrict but allow all other products if user wants.

    Thank you!
    Aryan

    NOTE: While submitting this form, I am getting this error: https://prnt.sc/to70io
    Please check and confirm if you received this form message.

    Reply
    • diego says:

      Hi Aryan,
      Thanks for your feedback. The article is designed to allow only specific products in the cart. That is:
      – If Product X is in the cart, that must be the only product in the cart.
      – If Product X is not in the cart, any other product can be added to it and purchased at the same time.

      If you wish to allow all non-membership products to be added to the cart, you could add their IDs to the list of allowed products (see variable $restricted_cart_items). That should allow all these products to be in the cart at the same time.

      If you have many products, you could extend the code to use the product categories instead (see WooCommerce Tips & Tricks – Get all the categories to which a product belongs). Unfortunately, we don’t have a ready-made example showing how to do that, you will have to implement the custom logic yourself. If you need assistance with this implementation, we would recommend to post your task on Codeable (https://aelia.co/hire_expert), where an expert can extend and test the code for you.

      Reply
  28. Imran Khan says:

    Hi, I have created a product category in which I am offering customers to buy 5 products at a 90% discount. I have set the minimum order amount so that customers have to buy other products also. now I want to allow the customer to choose only 1 product from above 5 discounted products. please help me.

    Reply
    • diego says:

      Hi Imran,
      What you describe requires a custom solution. The code in the article won’t help you much, as it’s designed do do something that is almost the opposite. That is:

      • If one or more products from a specific list are in the cart, then no other products can be purchased.
      • If none of the products from a specific list are in the cart, then all other products can be purchased as well.

      In your case, you need to find the category of a product (see WooCommerce Tips & Tricks – Get all the categories to which a product belongs), as well as the categories of all the products in the cart. If the cart contains any products from the “90% off” category, then any other product belonging to it would have to be set as “not purchasable” (see filter woocommerce_is_purchasable, in the code snippet from the article).

      Unfortunately, we don’t have a ready made example of how to do the above. It’s not a trivial customisation, either, it would take some time to plan, develop and test it. If you need a developer to assist you with this implementation, we would recommend to create a task on Codeable. It’s a platform of vetted experts, who can review your requirements and give you an estimate to write the custom code you need.

      Reply
  29. David says:

    We sell our products to various countries. Now we want to sell some products that we will only ship within the UK. I set up a test product and tested it. If I choose that test product only and say I am outside the UK, then the checkout says it does not have a shipping option. That’s expected behaviour and its OK. But when I add a product that we do ship to many countries to the basket and also add a product that we only ship within the UK, then WooCommerce overrides the ‘UK only’ rule and charges shipping based on the products that can be shipped abroad. That is not what we want. Question:
    Before I get into the snippet, is that the way Woo works by default and is the problem inevitable with Woo without a piece of code, or have I made a mistake in the set up? / Thanks

    Reply
    • diego says:

      We haven’t tested the specific scenario you described, but it looks like WooCommerce could indeed be designed the way you see. We would recommend to post your question on the official WooCommerce Support forum (https://wordpress.org/support/plugin/woocommerce/). The WooCommerce Team should be able to check if the behaviour is indeed by design, or if it’s due to some incorrect setup.

      Reply
  30. Jeff says:

    Hi, the code works exactly like i wanted it to work! Thanks for that.
    The only problem is that the error message from step 3 is nog showing, is this a common problem?

    Reply
    • diego says:

      Our tests indicate that the code still shows the “not available” message on single product pages. If it doesn’t appear, perhaps there’s some other code, running on the site, which could be interfering with it.

      Reply
  31. Dean Forde says:

    I noticed that if i add normal products to the cart and then try add a restricted product it empties the cart of all the normal products and adds the restricted item by itself which is probably expected behavior however is it possible to throw a notice that you cant add the restricted items if normal items are in the cart instead of just emptying the cart of all the normal items?

    Reply
    • diego says:

      The behaviour you described, with the products being removed from the cart automatically, is by design in WooCommerce. When a product is set as “not purchasable”, WooCommerce removes it from the cart and prevents it from being added back. This is automatic.

      To avoid this behaviour, you will need to change the code quite a bit. The first change would be to remove the filter for woocommerce_is_purchasable, so that products are always purchasable, then inspect the cart contents, show a notice when specific product combinations are not allowed, and stop the checkout process. It’s a fairly different process from what the code in the article does, you will need a specific customisation for it.

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.