Customize the order's activity log with Drupal Commerce 2

A log book

By default, Drupal Commerce 2 provides an activity log on the life of each order: the add to cart event, the checkout entry, the order placed, its possible shipment and its conlusion.

Each status of the command corresponds to an entry in a log that is generated. This provides a complete history for each order.

Default order activity

Having needed to customize this activity log, to allow managers of the online store to enter in this log various comments related to the management of the order, I discovered on this occasion the small module, used to generate this log, developed by the maintainers of Drupal Commerce 2. A small but extremely powerful module, titled Commerce log. My favorite modules.

We will discover how to use this module to insert additional log entries. These entries can be generated automatically as well as correspond to an user input.

The Commerce log module

This module declares 2 Plugin types : LogCategory and LogTemplate. The first allows us to declare log categories, while the second allows us to create log templates, which we will assign to previously created categories. Its operation is extremely similar to State Machine: no GUI (hence also less code, and therefore maintenance), and thus creation / declaration of the plugins using YAML configuration files.

But because a good example is sometimes better than a long speech, let's get right to the point right away. We will allow order managers to leave comments in this activity log.

A customized activity journal

Let's create a small MYMODULE module and declare our Log template right away.

The structure of our module will look like this

├── MYMODULE.commerce_log_categories.yml
├── MYMODULE.commerce_log_templates.yml
├── MYMODULE.install
├── MYMODULE.module

The category of a Log allows us to specify for which entity type the Log will be generated. Here we declare the MYMODULE_order category which will concern the Drupal Commerce Orders entities:

  label: Order comment
  entity_type: commerce_order


Then we declare our template, here order_comment that we assign to our category. Here we could have used the category already created by the commerce log module.

  category: commerce_order
  label: 'Comment'
  template: "<p><b>{{ 'Comment'|t }} :</b> {{ comment }}</p>"

The key information of the LogTemplate Plugin is its template that is declared. It's actually a simple Twig inline template. Here we declare our inline template which will use a variable comment.

And it's done !

Well almost. It only remains to generate our log entries at the right time. Since we want to record comments from the online store managers input, we will intervene before the order is saved.

We take care to create beforehand a simple text field, for example field_order_note, on the order entity type, and polish a little the order edit form to obtain this result.

Order form comment

Then we implement hook_entity_presave(), to intervene before saving an order. We will simply check if this field is filled in, and if necessary we will generate the corresponding log entry.

 * Implements hook_entity_presave().
function MYMODULE_entity_presave(EntityInterface $entity) {
  if ($entity instanceof OrderInterface) {
    if ($entity->hasField('field_order_note')) {
      if (!$entity->get('field_order_note')->isEmpty()) {
        // Get the comment, clear it from the order, and log it.
        $comment = $entity->get('field_order_note')->value;
        $entity->set('field_order_note', '');
        /** @var \Drupal\commerce_log\LogStorageInterface $logStorage */
        $logStorage = \Drupal::entityTypeManager()->getStorage('commerce_log');
        $logStorage->generate($entity, 'order_comment', ['comment' => $comment])->save();

The key method here for generating the log entry is the generate() method from the LogStorage class.

This method expects as arguments, the entity itself, the identifier of the template to use, and finally an array of parameters to pass to the Twig inline template. We can therefore pass as many parameters as necessary to the Twig template to generate the log entry.

And then we can from the edit form, enter a comment.

un commentaire sur une commande

And we now find this note in the order activity log.

Un commentaire dans le journal de la commande

To go further with Commerce Log

Commerce log is used to generate the Drupal Commerce Order Activity Log. But its design allows us to generate logs for any entity type of Drupal 8. For example generate activity logs for some users, depending on some actions performed on the contents of a project, according to conditions based for example on user roles and / or common taxonomy terms. As well, the Message stack covers this need, but if you already have Drupal Commerce 2 on the project, it may not be useful to install these other modules for this. Give a try with commerce log. You will be surprised. But this will be the subject of another ticket.



Soumis par Goz (non vérifié) le 15/02/2018 à 08:11 - Permalien

Nice as usual. Thanks for this ticket.

One thing concerning the use of hook_entity_presave(). Even if this still works, we should recommend the use of event subscribers. Commerce 2.x implements a lot of events for commerce entities manipulations, and that helps a lot.
Using event subscribers instead of hooks, you can use the powerful dependency injection. Plus code will be more readable, avoiding to put all the code in a single .module file.

At the end (drupal 9.x ?), we should not need .module anymore.

Soumis par Alex (non vérifié) le 31/05/2018 à 16:21 - Permalien

En réponse à par Goz (non vérifié)


Would it be possible to have a working example of code that is triggering when an order is complete ? I tried everything without make it works. The entity_presave solution have the advantage to looks like Drupal 7 hooks. Cause the event system is really hard to master, and badly documented

Soumis par Fonant (non vérifié) le 10/05/2021 à 20:29 - Permalien

I think the example is wrong:

category: MYMODULE_order
label: 'Comment'
template: "<p><b>{{ 'Comment'|t }} :</b> {{ comment }}</p>"

Ajouter un commentaire