Out of Stock feature in Drupal Commerce 2.x

Implementing Out of Stock feature in Drupal Commerce 2.x is easy. Unfortunately, you can't just enable this feature, because Commerce doesn't support it out of the box. You have to get your hands dirty and write some code.

As you may know, there is a contrib stock module for Drupal 8, but it's still in the development phase, so I wouldn't recommend you to use it in production.

Let's see how in three simple steps you can add the Out of Stock feature to your webshop.

Step 1

Go to your Product variation fields configuration (/admin/commerce/config/product-variation-types/default/edit/fields) and add a new integer field. Call it Stock or something like that. The value of this field will dictate if the product is in stock or not.

Step 2

Implement the AvailabilityChecker service. Inside your MODULE_NAME.services.yml file add this:

    class: Drupal\MODULE_NAME\VariationAvailabilityChecker
      - { name: commerce.availability_checker, priority: 100 }

You can now create a class file inside the src directory. The name of this file should be VariationAvailabilityChecker.php


namespace Drupal\MODULE_NAME;

use Drupal\commerce\AvailabilityCheckerInterface;
use Drupal\commerce\Context;
use Drupal\commerce\PurchasableEntityInterface;

 * Class VariationAvailabilityChecker.
class VariationAvailabilityChecker implements AvailabilityCheckerInterface {

   * {@inheritdoc}
  public function applies(PurchasableEntityInterface $entity) {
    return TRUE;

   * {@inheritdoc}
  public function check(PurchasableEntityInterface $entity, $quantity, Context $context) {
    if ($entity->field_stock->value <= 0) {
      return FALSE;
    return TRUE;


As you can see, this is a super simple class. We have only two methods. applies() is used to determine whether the checker applies to the given purchasable entity. Maybe you have several variation types and you want to apply the checker to only one of them. In our case, we just return TRUE. That means that the checker will be always applied.

The second method is check(). This method checks the availability of the given purchasable entity. If we return TRUE that means that the entity is available, and FALSE means that it is unavailable. Logic in our example is quite simple. If the value of the Stock field is equal or less than zero then return FALSE and make the variation unavailable.

Step 3

The last step is to alter the Add to cart form and use the AvailabilityChecker service to enable/disable the Add to cart button. Inside your MODULE_NAME.module file add this:

use Drupal\commerce\Context;
use Drupal\commerce_product\Entity\ProductVariation;
use Drupal\Core\Form\FormStateInterface;

 * Implements hook_form_alter().
function MODULE_NAME_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'commerce_order_item_add_to_cart_form') !== FALSE) {
    $selected_variation_id = $form_state->get('selected_variation');
    $product_variation = ProductVariation::load($selected_variation_id);

    /** @var \Drupal\MODULE_NAME\VariationAvailabilityChecker $variation_availability_checker */
    $variation_availability_checker = \Drupal::service('MODULE_NAME.variation_availability_checker');

    $current_user = \Drupal::currentUser();
    $current_store = \Drupal::service('commerce_store.current_store')->getStore();
    $context = new Context($current_user, $current_store);

    if (!$variation_availability_checker->check($product_variation, 1, $context)) {
      $form['actions']['submit']['#value'] = t('Out of stock');
      $form['actions']['submit']['#disabled'] = TRUE;

In the form alter we are calling the check() method to see if the currently selected variation is available. We are passing three arguments: $product_variation, 1, $context. Since we didn't implement any logic regarding the quantity, we can pass any value, but here we are passing 1.

You don't have to implement step 3. It's optional but it greatly improves the user experience. If you don't disable the Add to cart button, users will be able to click on it and they will get the message that says that product has been added to the cart, but that won't happen. The product won't be added to the cart and in my opinion that is really confusing.

Also, make sure that your products do have some attributes, otherwise, the following line won't work and you will have to refactor my code a little bit:

$selected_variation_id = $form_state->get('selected_variation');

You can vastly improve upon this example and create even better stock management features. You can for example automatically decrease the Stock field value each time someone buys an item. To do this you can subscribe for example to the ORDER_PAID event and add some logic to decrease the stock value for all ordered products.

Please note that Drupal 8 adheres to PSR-4. This means that files must be named in certain ways and placed in specific folders. Here is what the module structure should look like:

├── my_module.info.yml
├── my_module.module
├── my_module.services.yml
└── src
    └── VariationAvailabilityChecker.php

About the Author

Goran Nikolovski is a creator, speaker, open-source contributor, web developer specialized in Drupal and DevOps enthusiast. He is the founder of this website and he enjoys sharing his knowledge and experiences.