Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Remove or replace the add to cart message in Drupal Commerce 2.x

Parent Feed: 

Commerce ships with a default success message after adding a product to the shopping cart. This is done via an event subscriber, in order to be easy customizable. However, removing, replacing or extending existing services in Drupal 8 is a thing, not every developer is used to do. I'll show you, how easy this is.

I've seen the need for this requirement a couple of times during the last few days - once I needed it myself for muting the add to cart message on my ajaxified add to cart links. The same time I saw what Commerce Cart Flyout module is doing regarding this. And today someone asked for this in the Commerce Slack Channel.

I'll show you two use cases here: the one is completely removing the original cart event subscriber, the second one is extending and replacing the existing one, in order to stay silent on Ajax requests and keep the existing logic on static calls.

Setup

In both cases, we need to implement a custom module. I'm assuming that you're already familiar with creating custom modules, if not here's the official documentation on doing this. Let's assume that we call our module 'my_module'.

As we're modifying an existing service, we do not need to define a service within the module's service.yml file. Instead we need to implement a service provider. Defining a service provider is done with some little magic. We don't define it as a service (as it is providing services, it's one level above them), but we have to follow a strict naming policy in order to get it discovered. We have to place it in your module's top level namespace (Drupal\my_module in our case) and therefore directly in the "src" directory of our module. Additionally the name of this class is required to be a CamelCase version of your module's machine name followed by ServiceProvider, so in our case this is MyModuleServiceProvider. And we'll extend the ServiceProviderBase class. If you're interested in this topic, read more about service providers in Drupal 8 here.

Completely remove the original cart event subsriber

This approach is e.g. done by Commerce Cart Flyout module until version 1.4:


namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

/**
 * Removes the add to cart message.
 */
class MyModuleServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    // Remove the server side add to cart messaging.
    if ($container->hasDefinition('commerce_cart.cart_subscriber')) {
      $container->removeDefinition('commerce_cart.cart_subscriber');
    }
  }

}

It implements the alter() function and checks, if the container has a service definition called 'commerce_cart.cart_subscriber'. If so, it will be removed completely.

Extend and replace the existing service

This approach is less radical. We want to silent the message only on Ajax calls. So our plan is to replace the service instead of removing it. This is how our service provider will look like:


namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Replaces the add to cart message.
 */
class MyModuleServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    // Replace the server side add to cart messaging.
    if ($container->hasDefinition('commerce_cart.cart_subscriber')) {
      $definition = $container->getDefinition('commerce_cart.cart_subscriber');
      $definition->setClass('Drupal\my_module\EventSubscriber\CartEventSubscriber')
        ->addArgument(new Reference('request_stack'));
    }
  }

}

As you can see, we are not removing the definition, but setting a different class instead. And because we will need the request stack in order to distinct between Ajax and static calls, we will add an additional constructor argument and inject the request_stack service.

Next, we'll create the CartEventSubscriber class and place it into the directory src/EventSubscriber within our module's directory:


currentRequest = $request_stack->getCurrentRequest();
  }

  /**
   * {@inheritdoc}
   */
  public function displayAddToCartMessage(CartEntityAddEvent $event) {
    $is_ajax = $this->currentRequest->isXmlHttpRequest();
    if (!$is_ajax) {
      parent::displayAddToCartMessage($event);
    }
  }

}

We are extending the \Drupal\commerce_cart\EventSubscriber\CartEventSubscriber class and override its displayAddToCartMessage() function. Inside we first check, if the current request is an Ajax request. If it is, we do nothing. If it's a static call instead, we simply call the parent displayAddToCartMessage() function. That's it :)

Alternative solution

There's another way to extend existing services. You may also implement a decorator instead.

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web