Set up a notification system on Drupal 8

tree logs

For many Drupal 8 projects that have minimal interaction with their users, the need to set up a notification system quickly comes to the forefront. Being notified of a new comment, a response to a comment, a new publication on a particular subject, or a user, are recurring needs.

To satisfy this type of need, we can rely on the Message module (and the Message stack) which can allow us to achieve this type of result with the help of the Flag module. But we are not going to talk here about these two generic modules, which can do much more, but about a new module Entity Activity whose sole purpose is to log all types of actions performed, by users, according to their subscriptions, on a project.

The Entity Activity module will allow us to generate any type of message, on any type of content entity on the tree main operations of the content life cycle: its creation, its update and its deletion.

Global configuration

The initial configuration of the module is quite quick to set up. The majority of the configuration to be done is done from the menu Configuration > Content authoring > Entity Activity

First, you need to activate on which types of entities you want to be able to generate notifications. And so of course allow users to subscribe to these entities.

Entity Activity Settings

At the same time, you can configure a purge of the different notifications (based either on overall time or a maximum number of notifications per user) if necessary.

Multilingual support

For multilingual projects, subscriptions are also multilingual in the sense that a user can subscribe to content for each of his or her independently available translations. Notification messages are then generated in the current language when the operation is performed. You can force the generation of a log message in the user's preferred language (if defined), by checking the corresponding option in the general settings.

User preferred language option

Warning. This option is costly in performance because each log message must be regenerated for each owner of a subscription. Use it only if you really need log messages to be generated in the user's preferred language.

Configuration of activated content entities

In a second step, we will configure the display modes of the entities we have activated, to display a Subscribe on widget that will allow users to subscribe (or unsubscribe) on each of the entities.

Article subscribe on

You can then display on the different view modes required, on the different content types, this Subscribe on button, as above with the example of the Article content type.

From now on, users, with the appropriate permission, will be able to subscribe and unsubscribe on each activated and configured entity. And they will be able to find from their account a summary of all their subscriptions.

User's subscriptions

Note that the Remove button on each subscription is present because it has been activated in the Subscription entity view mode from the Configuration > Content Authoring > Entity Activity > Subscriptions settings > Manage display configuration page.

Configuration of notification generators.

Thirdly, we must configure which messages will be generated from which operation and for which subscriptions. To this end, we can create as many Generators as necessary according to the needs of a project.

Entity Activity Generators

Each notification generator has a base of four plugin types corresponding to the four main content entity types of a Drupal 8 project, namely content, taxonomy term, user and comment. It is possible to add as many plugins as necessary for specific project needs, but we will have the opportunity to look at this later.

The configuration of these Plugins is identical and follows the same logic.

Plugin log generator

The possible configuration options are as follows.

  • Enable: whether the plugin is active or not
  • Published: option to generate a notification only if the target entity is published
  • Operation: the type of operation from which the plugin must generate a notification (insert / update / delete)
  • Bundles: it is possible to limit the action of a plugin to only one or more bundles of a content entity type. You can leave blank to apply the plugin to all bundles regardless.
  • Subscribed on: this is the configuration option in a way master. It allows you to define from which subscriptions the plugin will generate the notification. The two possible options are Source Entity and Entity Referenced. The first (Source Entity) is the most basic and allows you to select the subscriptions that have been made on the entity itself (content, user, etc.). The second option (Entity Referenced) will allow you to select the subscriptions made on a referenced entity (from an Entity Reference field so) by the current entity. The typical use case is to be able to generate a notification for all users subscribing to an Alpha theme (Taxonomy Term) when new content is published on that theme, or another use case is the generation of a notification when publishing a comment about a content. But the possibilities here are extremely varied and countless use cases can be covered with this second option. In the example above we have chosen here to generate a notification when publishing content to all users who have subscribed to the author of the content.
  • Include parent term: this option allows to include all parent terms in case the entity on which subscriptions are searched is a taxonomy term. Useful if you want a user who has subscribed to the taxonomy term Fruit, for example, to also be notified if content is published with the taxonomy term Orange, which would be a child of the term Fruit.
  • Log message: This is of course the message that will be generated and notified to users. You can configure the text format to use, and of course you can use all the tokens related to the target entity type of the plugin.
  • Use cron: this option allows you to disable the generation of the actual notifications of the operation performed on the entity. Indeed, depending on the number of subscriptions, generating all notifications can be a long and costly process in terms of performance. This option then allows to delegate to the scheduled tasks the generation of these notifications, so as not to penalize the user who performs the operation in question. This option is highly recommended.

You can then create and activate as many notification generators to cover all the business needs of your project, each notification generator can itself have several plugins in charge of generating the notification itself.

Configuring notifications

To finalize the implementation of your notification system, you can then configure two elements on the Log entities of the module that carry these notifications.

From the Configuration > Content authoring > Entity Activity > Log settings > Manage Display

Log manage display

You can activate the extra field Remove log, which will expose a button allowing the owner of the notification (the user who subscribed) to delete this notification (if he has the appropriate permission).

And you can also configure the base field Read, with the Log read / unread field formatter, which will expose a button allowing the notification's owner to change the status from Not Read to Read or vice versa.

Inform the user of new notifications

All this is only really useful if users can be easily informed of the presence of new notifications. To this end, the module offers a block called User log block, which must be placed and configured in the appropriate region of the project theme.

User log block settings

The purpose of this block is to display the total number of unread notifications. For this purpose you can add a (short) text that will be displayed next to this number, you can use an icon font to display an icon next to this number (using the classes of this font), but also configure the maximum number of notifications that will be embedded as well as the view mode used to display them, as well as add a link to the user's page listing all his notifications, whatever their status. Of course you can overload the Twig template to customize the rendering of this block.

Extension of the Entity Activity module

Since notification generators rely on a  plugin type, it is possible to create easily your own plugin to add a very specific logic to a project, overloading the basic methods used, or simply to support a new content entity type from a contributed module.

Plugins must be placed on the Plugin/LogGenerator namespace and may look like this for example if you want to overload and add a very particular logic on one or more of the methods of this Plugin type. 

 * @LogGenerator(
 *   id = "my_custom_node",
 *   label = @Translation("My custom Node Log Generator"),
 *   description = @Translation("Generate custom log for the entity type Node or for related entities referenced."),
 *   source_entity_type = "node",
 *   bundles = {}
 * )
class MyCustomNodeLogGenerator extends LogGeneratorBase {

  public function getEntitiesSubscribedOn(ContentEntityInterface $entity) {
    // Stuff.
  public function preGenerateLog(ContentEntityInterface $entity, AccountProxyInterface $current_user = NULL) {
    // Stuff.

  public function generateLog(array $settings) {
    // Stuff.


The module also exposes two parameters that can be overridden from the settings.php file of a project.

$settings['entity_activity_max_log'] = 100;

This setting overrides the maximum number of notifications (default 50) that can be bulk marked as read by a user. Indeed, it has a button on its page listing its notifications which allows you to mark all its notifications as read. This parameter therefore defines the number of notifications that will be processed per pass in the update process that will then be launched.

$settings['entity_activity_purge_user_always'] = TRUE;

This parameter allows you to force the purge per user (maximum number of notifications per user) each time a cron task is executed. Indeed, this method of purging can be very costly in terms of time and performance, depending on the number of users to be treated. Also by default, this method is only executed once a day, at night. This parameter therefore overrides this default behavior.

In addition, the notifications and subscriptions provided by this module are themselves content entities. As such, they can be customized by adding additional fields. In this case, it is up to the project to define the value of these fields in a programmatic way according to business needs. To this end, events are dispatched for each hook implemented by Drupal on the CRUD cycle (presave, postsave, update, insert, delete, etc.).

Finally, the entities provided by this module (Log and Subscription) have a basic rendering that can be used in many cases. The rendering of these entities is heavily based on a Twig template that you can then override to meet your needs.

Possible developments

To date, Entity Activity allows you to quickly configure a project to generate notifications for users based on their subscriptions. It can also be easily extended using Plugins to add specific business logic if necessary. A natural evolution would be to be able to generate and send by email (according to a frequency chosen by the user) a list of the last unread notifications, even if for the moment this feature is not part of the functional scope of the module. But a Drupal 8 developer can easily add this functionality (either in the module itself or in another contributed module), the foundations laid opening up many possibilities in relation to this recurring theme on community projects.


To conclude, Entity Activity is a simple configuration module, as it focuses exclusively on generating notifications, or logging events occurring on a Drupal 8 project. But this simplicity is not at the expense of the necessary modularity as to the generation (and their underlying conditions) of the different notifications to cover most, if not all, of the recurring use cases and needs.



Soumis par Mathieu (non vérifié) le 23/05/2019 à 06:35 - Permalien

Merci, ca fait des mois que je galère avec Message, Flag et Views pour mettre sur ma page d'accueil une timeline. Je vais tester votre module.
Par contre dans mon cas c'est compliqué. J'ai un site sur Drupal 8 avec Commerce et Group. Voici ce que je veux faire :
- un utilisateur souscrit à un groupe, il recevra une notification de tous les contenus publiés dedans.
- un utilisateur souscrit à un magasin, il recevra une notification de tous les produit publiés dedans.
- un utilisateur souscrit à un contenu, il recevra une notification de tous les commentaires publiés dedans.
- un utilisateur souscrit à un produit, il recevra une notification de tous les commentaires publiés dedans.

Est ce possible avec votre module ? Voici mon site :


Soumis par Francesco (non vérifié) le 22/08/2019 à 18:34 - Permalien

Hello, thank you for your module,
it's nice but when I add a generator I receive this error and I can't find any log.
Could you help me?

Notice: Undefined index: status in Drupal\entity_activity\Plugin\LogGeneratorBase->isEnabled() (line 556 of modules/entity_activity/src/Plugin/LogGeneratorBase.php).
Drupal\entity_activity\Plugin\LogGeneratorBase->isEnabled() (Line: 375)
Drupal\entity_activity\Plugin\LogGeneratorBase->validateConfigurationForm(Array, Object) (Line: 223)
Drupal\entity_activity\Form\GeneratorForm->validateForm(Array, Object)
call_user_func_array(Array, Array) (Line: 82)
Drupal\Core\Form\FormValidator->executeValidateHandlers(Array, Object) (Line: 275)
Drupal\Core\Form\FormValidator->doValidateForm(Array, Object, 'entity_activity_generator_edit_form') (Line: 118)
Drupal\Core\Form\FormValidator->validateForm('entity_activity_generator_edit_form', Array, Object) (Line: 576)
Drupal\Core\Form\FormBuilder->processForm('entity_activity_generator_edit_form', Array, Object) (Line: 319)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 93)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Ajouter un commentaire