Notifications/Developer guide

From mediawiki.org

Notifications, as enabled by the Echo Extension, give MediaWiki users quick updates about actions that affect them. These notifications can help users become more aware of events that relate to them and take quick action if they want to.

This document is intended for MediaWiki extension developers and describes how to extend a MediaWiki extension to use the Notifications system. Currently, the following MediaWiki extensions are using the Echo extension to send notifications:

  • Thanks, to send thanks notifications to users for specific revisions.
  • PageTriage, to send notifications that indicate whether a page is reviewed and approved, reviewed with issues, or reviewed and nominated for deletion.
  • Flow
  • OpenStackManager (Only on WikiTech)
  • LoginNotify

Message contents are listed at Echo (Notifications)/Message audit.

For more information about the Notification system, please see the project home page.

See also: Echo (Notifications)/API

Implementing notifications: Step-by-step[edit]

  1. Do you need notifications?
    Although any extension can use the Notification system to send messages, please do not do so unless necessary. Make sure that your notification will not spam users, or overlap with another notification. Notifications should not duplicate each other, and one should bow out if there is an overlap.
  2. Choose or create a notification category
    Each notification must be assigned to a category, which defines the notification preferences (e.g., opt-in or opt-out; on-wiki or email notification). The notification can be assigned to an existing category or to a new category. See #Notification categories for more information.
  3. Define the notification
    Each notification is defined with an array of keys and values. Please see #Defining a notification for more information.
  4. Choose or create a notification formatter class
    The formatter class is the engine that defines how to turn an event into a message that the end-user reads. It is specified in the notification definition and should be set to the name of a PHP class (either one predefined in Echo or a custom class in your extension). See the #Notification formatter classes section for more information.
  5. Hook the notification into Echo
    Once the notification is defined, it can be hooked into Echo with the BeforeCreateEchoEvent and EchoGetDefaultNotifiedUsers hooks. Please see #Hook the notification into the Echo extension for more information.
  6. Set up a trigger for the notification
    To trigger the notification, use the EchoEvent::create function call, either as part of the extension code (if the extension creates an interface) or in a hook to an existing part of the MediaWiki software. For more information, please see #Create the notification via the Echo extension.
  7. Monitor the notification
    Once the notification has been implemented, monitor its behavior to ensure that it is not spamming users. If it seems to be generating an excessive number of notifications, you might want to rate-limit the event that is generating the notification or ensure that the notification is opt-in only.

Notification categories[edit]

Every notification must be assigned to a category, which defines the notification preferences (e.g., opt-in or opt-out; on-wiki or email notification). The notification category can also be used to specify user groups that are eligible to receive the notification, the priority of the notification, and a help tip. Note that multiple notifications can be assigned to a single category.

The assigned category can be one that is predefined by the Echo extension, or a customized category. Predefined categories include:

Category Description
reverted Notifications about edits being reverted or undone.
edit-user-talk Notifications about edits to a user's talk page.
article-linked Notifications about a page being linked from another page.
mention Notifications about a user being mentioned in a discussion.
system Notifications about events that are not triggered by another MediaWiki user (e.g., account creation or email registration). Note that events in the system category cannot be turned off via notification preferences so it should be used with caution.
other Do not use this category! If no category has been assigned to a notification, the ‘other’ category is assigned by default. The other category has no associated preferences, cannot be dismissed, and is not useful in analytics.

Creating a new category[edit]

Each category definition consists of an array of keys and values. The following is an example of a category definition used by the Thanks extension:

$notificationCategories['edit-thank'] = [
    'priority' => 3,
    'tooltip' => 'echo-pref-tooltip-edit-thank',
];

You'll also need to set the title of the category in your i18n file - the message key must be of the form "echo-category-title-<category-key>":

$messages['en'] = [
    /* ... */
    'echo-category-title-edit-thank' => 'Thanks',
    'echo-pref-tooltip-edit-thank' => 'Notify me when someone thanks me for an edit I made.',
    /* ... */
];

$messages['qqq'] = [
    /* ... */
    'echo-category-title-edit-thank' => 'Name of the notification category for the Thanks extension.',
    'echo-pref-tooltip-edit-thank' => 'Further explanation of the user preference for enabling notifications on Thanks events.',
    /* ... */
];

Notification category parameters[edit]

Note that all category parameters are optional.

Parameter Required? Value
priority no The priority determines the precedence of the notification in email digest, preferences, and other contexts. The value is an integer between 1 and 10. The default is 10, the lowest priority. Usually, there is no need to set this parameter.
no-dismiss no If set, the no-dismiss parameter specifies that a notification cannot be turned off with a user’s notification preferences. We strongly recommend that notifications can be dismissed. The value is an array of output formats or an array containing ‘all’, e.g., 'no-dismiss' => array( 'all' ) or 'no-dismiss' => array( 'web' ). The following output formats are currently used: web, email.
tooltip no The tooltip defines the help message that appears when users mouse-over the question mark icon that appears beside the notification category in the preferences interface. The value is an i18n string key.
usergroups no The usergroups parameter specifies an array of user group (e.g. admins) who are eligible to receive the notifications in the category. If unspecified, all groups are eligible.

Defining a notification[edit]

Each notification consists of, at minimum, a title and a timestamp. In addition, a notification may also include a payload and primary and secondary action links.

Title: The title is a simple string that conveys a piece of information to a user. It may include links, or may have no data or link associated.

Timestamp: The timestamp reflects the time the notification was generated.

Primary action link: A link designated as the main action that the user should take in response to a notification. In the flyout interface (the overlay revealed when you click the red notifications badge), the entire notification is clickable and the destination the user is sent to when clicking the notification is defined as the primary link.

Secondary action link: An additional link that may be needed for a notification. Most notifications will not have a secondary link and the use of secondary links is discouraged (to keep the interface simple).

Payload: The payload contains secondary data that augments the notification, e.g., an edit summary or a snippet of content such as the first few words of a contribution.

The notification appears in the flyout menu beside the user name as well as on the user’s Notification page and, if email notification preference is set to on, as an email message. Note that the notification can be customized for each of these instances via the notification parameters.

TODO: Explain more about customizing for different views

Each notification definition consists of an array of keys and values. The following is an example of the Thanks notification definition. Note that the notification and the category have the same name (‘edit-thank’), as the Thanks notification is the only notification for this category:

 $notifications['edit-thank'] = array(
     'primary-link' => array( 'message' => 'notification-link-text-respond-to-user', 'destination' => 'agent' ),
     'secondary-link' => array( 'message' => 'notification-link-text-view-edit', 'destination' => 'diff' ),
     'category' => 'edit-thank',
     'group' => 'positive',
     'formatter-class' => 'EchoThanksFormatter',
     'title-message' => 'notification-thanks',
     'title-params' => array( 'agent', 'difflink', 'title' ),
     'flyout-message' => 'notification-thanks-flyout2',
     'flyout-params' => array( 'agent', 'title' ),
     'payload' => array( 'summary' ),
     'email-subject-message' => 'notification-thanks-email-subject',
     'email-subject-params' => array( 'agent' ),
     'email-body-batch-message' => 'notification-thanks-email-batch-body',
     'email-body-batch-params' => array( 'agent', 'title' ),
     'icon' => 'thanks',
 );

Notification parameters[edit]

Parameter Required? Value
category no The notification category defines the preferences for the notification (e.g., opt-in or opt-out, on-wiki or email notification). The Echo extension has several predefined categories, or you may define a new category. It is strongly recommended to set a category for your notification. See #Notification categories for more information.
group no The group parameter is used for analytical purposes and does not affect the behavior of the notification. Its value may be set to:
  • positive - for an encouraging notification (e.g. welcome or thanks message)
  • negative - for negative feedback (e.g. edit reverted)
  • neutral - neither good nor bad (e.g. page linked)
  • interactive - for notifications related to interaction between two users (e.g. talk page posts)

The default is neutral.

formatter-class no The formatter class is the engine that defines how to turn an event into a message that the end-user reads. The value should be set to the name of a PHP class (either predefined or customized). If not specified, it defaults to EchoBasicFormatter. See the #Notification formatter classes section for more information.
title-message yes The title-message defines the main message (a.k.a., title) of the notification. The value is an i18n key.
title-params yes* The title-params parameter defines an array of data used in the notification title. (e.g., 'title-params' => array( 'agent', 'difflink', 'title' ). Predefined title parameters include:
  • agent (the user responsible for triggering the notification, e.g. the user who sent thanks)
  • difflink (the link to the diff view of a revision) - note that this requires EchoEditFormatter to be selected in formatter-class.
  • title (title of article)

You can define your own title params in the formatter class.

flyout-message no The flyout-parameter is an optional parameter that defines the content of the notification title when it appears in the flyout overlay (after clicking the red badge in the personal toolbar). If set, the value of this parameter will override the format specified by the title-message parameter. The flyout-message should never contain more than one link (the 'primary action link') since the entire notification in the flyout is clickable. The value is an i18n key.
flyout-params no The flyout-params parameter defines an array of data that gets plugged into the flyout-notification message. These will usually be similar to the parameters used in the title-params parameter.
primary-link no The primary call to action for the flyout and email. Consists of an array including an i18n message and a link destination, for example array( 'message' => 'notification-link-text-view-edit', 'destination' => 'diff' ).
secondary-link no The secondary call to action for the flyout and email.
payload no The payload parameter describes the kind of data in the payload section of the notification (e.g., ‘summary’ is an edit summary). The value should be set to the name of a payload type (either predefined or customized). See the #Payloads section for more information.
email-subject-message yes The email-subject-message parameter defines the content of the subject line used when the notification is sent by email.
email-subject-params yes The email-subject-params define an array of data that gets plugged into the email-subject-message. These will usually be similar to the parameters used in the title-params parameter.
email-body-batch-message yes The email-body-batch-message is used in both individual and batched email: it defines the content of the notification when it appears in a batched email notification, it also defines the content of an email intro section when it appears in individual email notification. See the #Batched email notification and #Individual email notificationsection for more information. The value is an i18n key.
email-body-batch-params no The email-body-batch-params define an array of data that gets plugged into the email-body-batch-message.
bundle no The bundle parameter controls the bundling behavior. If set, related notifications are grouped together. The value is an array of delivery formats in which the notification can be bundled, e.g. 'bundle' => array( 'web' => true, 'email' => true ). If not set, the notification will not be bundled. See the #Bundled notifications section for more information.
bundle-message no The bundle-message defines the content of the notification title when it appears in a bundled notification. See the #Bundled notifications section for more information. The value is an i18n key.
bundle-params no The bundle-params define an array of data that gets plugged into the bundle-message.
icon no The icon parameter defines the icon used with the notification. The value is either a path to the icon image or a full url. If a path is specified, it should be relative to $wgExtensionAssetsPath. The icon may be a pre-existing one defined in Echo or a custom one. See #Icons for more information.
section yes Which section it belongs in, 'alert' or 'message'. On the standard UI, this controls which badge/popup it shows in.
notify-type-availability no ?

* Will become optional soon

Icons[edit]

Predefined icons[edit]

The following icons are defined by the Echo extension and may be used by additional notifications.

Icon Name Usage
Generic.png Default icon for notifications
Talk.png On-wiki discussions (except deletion discussions)
Deletion.png Deletion events or deletion discussions
CrossReferenced.png A page was linked
Featured.png A page was featured or highlighted
Reviewed.png A page was reviewed
ReviewedWithTags.png A page needs work
Revert.png An edit was reverted
Gratitude.png A heart for expressing gratitude

From: https://github.com/wikimedia/mediawiki-extensions-Echo/tree/master/modules/icons

Additional icons[edit]

The following icons are used by other extensions deployed on Wikimedia sites.

Icon Name Usage
ThankYou.png Icon for Extension:Thanks

Creating a new icon[edit]

Notification icons should be 30x30 pixel monochrome graphics that use the following color scheme:

  • Black for negative actions
  • Green for positive actions
  • Blue for neutral actions

Adding an icon[edit]

Add icons in hook

public static function onBeforeCreateEchoEvent( &$notifications, &$notificationCategories, &$icons ) {
    // You can use either a path or a url, but not both.
    // The value of 'path' is relative to $wgExtensionAssetsPath.
    //
    // The value of 'url' should be a URL.
     
    //adding a custom icon
    $icons += [
        'myext-customicon' => [
           'path' => "my/icon/path/customicon.png"
        ],
        'myext-anothericon' => [
           'url' => 'http://www.example.org/images/anothericon.png'
        ]
    ];
    // register some echo events
    return true;  
}

Add icons in global variable

$wgEchoNotificationIcons['myext-customicon'] = [
    'path' => "my/icon/path/customicon.png"
];

Payloads[edit]

A payload adds more descriptive detail to a notification, it is usually located below the notification title in flyout/archive page/email.

Predefined payloads[edit]

Payload Description
summary Text snippet of a revision, which is generated during notification creation and saved in event 'extra' param with key 'section-text'
comment-text The text of the revision comment

Creating/Overwriting a payload[edit]

 class MyCoolExtensionEchoFormatter extends EchoBasicFormatter {
     protected function formatPayload( $payload, $event, $user ) {
          switch ( $payload ) {
               case 'summary': 
                    // generate the $summary
                    return $summary;
                    break;
               default:
                    return parent::formatPayload( $payload, $event, $user );
                    break;
          }
     }
 }

Notification formatter classes[edit]

The formatter class is the engine that defines how to turn an event into a message that the end-user reads. The value should be set to the name of a PHP class (either predefined or customized).

Predefined formatter classes[edit]

Formatter class provides an abstraction to format and display notification message for all distribution types: flyout, archive page, email and any other future distribution types. A notification only needs to define the messages and parameter tokens for each distribution type, all the formatting work will be handled automatically by the formatter class. There are three pre-defined concrete formatter classes: EchoBasicFormatter, EchoEditFormatter and EchoCommentFormatter, the basic formatter defines common and general parameter tokens for flytout, archive, and email while edit and comment formatter have more specific tokens for edit and comment related actions

Class Description
EchoNotificationFormatter An abstract class with only the most generic formatting functionality
EchoBasicFormatter Formatter class that provides most of the formatting functionality
EchoEditFormatter Formatter class for edit related action
EchoCommentFormatter Formatter class for comment related action

Creating a new formatter class[edit]

New formatter classes can be developed as part of your extension and referred to via the notification’s 'formatter-class' parameter.

New classes should extend one of the predefined formatter classes and should have a processParam function, which defines how to handles the message parameters unique to your notification.

The following example is from the Thanks extension:

 class EchoThanksFormatter extends EchoBasicFormatter {
    /**
     * @param EchoEvent $event
     * @param string $param
     * @param Message $message
     * @param User $user
     */
    protected function processParam( $event, $param, $message, $user ) {
        if ( $param === 'difflink' ) {
            $eventData = $event->getExtra();
            if ( !isset( $eventData['revid'] ) ) {
                $message->params( '' );
                return;
            }
            $this->setTitleLink(
                $event,
                $message,
                [
                    'class' => 'mw-echo-diff',
                    'linkText' => wfMessage( 'notification-thanks-diff-link' )->text(),
                    'param' => [
                        'oldid' => $eventData['revid'],
                        'diff' => 'prev',
                    ]
                ]
            );
        } else {
            parent::processParam( $event, $param, $message, $user );
        }
    }
 }

Email notification[edit]

Individual email notification[edit]

A typical individual email notification consists of four major components: intro, summary, call-to-action and footer

  • intro: the message defined in either 'email-body-batch-message' or 'email-body-batch-bundle-message' for the notification
  • summary: by default, it's the revision snippet if there is any. A notification could provide it to event 'extra' param with 'section-text' key. A notification could also overwrite getRevisionSnippet() method to provide some other custom summary.
  • call-to-action: the message defined in 'primary-link' and 'secondary-link' if any
  • footer: the message defined in either 'echo-email-footer-default-html' or 'echo-email-footer-default'

HTML email also contains an icon component

Batched email notification[edit]

A user can request to receive notification summary in email once in a day or a week. For the summary section in the notification, the message defined in 'email-body-batch-message' is used. For a bundled message, the message defined in 'email-body-batch-bundle-message' is used

Bundled notifications[edit]

Notification can be triggered anywhere from the code. We definitely do not want to spam the user with notifications. In this case, we may want to enable notification bundling. For example, page-link notification is triggered when a page is linked from another page, a popular page may trigger a lot of unwanted notifications. Bundling will help resolving the problem

Define bundling rule[edit]

  public static function onEchoGetBundleRules( $event, &$bundleString ) {
      switch ( $event->getType() ) {
          case 'edit-user-talk':
              $bundleString = 'edit-user-talk';
              if ( $event->getTitle() ) {
                  $bundleString .= '-' . $event->getTitle()->getNamespace() . '-' . $event->getTitle()->getDBkey();
              }
              break;
      }
  }

Hook the notification into the Echo extension[edit]

To hook your notification to the Echo extension, use the following two hooks:

BeforeCreateEchoEvent - Used to pass Echo your definition for the notification category and the notification itself (as well as any custom icons).

Example from Thanks:

 public static function onBeforeCreateEchoEvent( &$notifications, &$notificationCategories, &$icons ) {
        $notificationCategories['edit-thank'] = [
            'priority' => 3,
            'tooltip' => 'echo-pref-tooltip-edit-thank',
        ];
        $notifications['edit-thank'] = [
            'category' => 'edit-thank',
            'group' => 'positive',
            'formatter-class' => 'EchoThanksFormatter',
            'title-message' => 'notification-thanks',
            'title-params' => [ 'agent', 'difflink', 'title' ],
            'flyout-message' => 'notification-thanks-flyout',
            'flyout-params' => [ 'agent', 'difflink', 'title' ],
            'payload' => [ 'summary' ],
            'email-subject-message' => 'notification-thanks-email-subject',
            'email-subject-params' => [ 'agent' ],
            'email-body-batch-message' => 'notification-thanks-email-batch-body',
            'email-body-batch-params' => [ 'agent', 'title' ],
            'icon' => 'gratitude',
        ];
        return true;
    }

EchoGetDefaultNotifiedUsers - Used to define who gets the notifications (for example, the user who performed the edit)

Example from Thanks:

 public static function onEchoGetDefaultNotifiedUsers( $event, &$users ) {
 	switch ( $event->getType() ) {
 		case 'edit-thank':
 			$extra = $event->getExtra();
 			if ( !$extra || !isset( $extra['thanked-user-id'] ) ) {
 				break;
 			}
 			$recipientId = $extra['thanked-user-id'];
 			$recipient = User::newFromId( $recipientId );
 			$users[$recipientId] = $recipient;
 			break;
 	}
 	return true;
 }

Remember to register the above hooks to your myCoolExtension.php file. Example from BounceHandler:

$wgHooks['BeforeCreateEchoEvent'][] = 'BounceHandlerHooks::onBeforeCreateEchoEvent';
$wgHooks['EchoGetDefaultNotifiedUsers'][] = 'BounceHandlerHooks::onEchoGetDefaultNotifiedUsers';

Create the notification via the Echo extension[edit]

To trigger the notification, use the EchoEvent::create function call, either as part of the extension code (if the extension creates an interface) or in a hook to an existing part of the MediaWiki software. The EchoEvent::create function defines what data gets passed in to the notification.

The following example is used by the Thanks extension:

 EchoEvent::create( [
     'type' => 'edit-thank',
     'title' => $title,
     'extra' => [
         'revid' => $rev->getId(),
         'thanked-user-id' => $recipient,
         'source' => $source,
     ],
     'agent' => $agent,
 ] );

All create function calls must have a 'type' parameter; the rest of the parameters are optional and depend on the notification.

EchoEvent::create parameters[edit]

Parameter Required? Value Description
type yes string Name of the notification (as defined in the $notifications array)
agent no User object User who triggered the notification
title no Title object Page the notification relates to
extra no array Anything else. The ‘extra’ parameter supports any additional data required (e.g., the revision id of a page)

Conventions[edit]

Opt-in is best[edit]

In general, notifications should be opt-in unless they are a critical component of site building and it’s imperative that everyone get them.

You can set defaults for opt-in or opt-out via $wgDefaultUserOptions .

For example your category has the name myCategory the definition would look like:

Categorydefinition

    $wgEchoNotificationCategories['myCategory'] = [
        'priority' => 3,
        'tooltip' => 'message-key-for-myCategory-tooltip'
    ];

The value for useroptions is echo-subscriptions-typeOfNotification-categoryOfNotification.

Opt-out

$wgDefaultUserOptions['echo-subscriptions-web-myCategory'] = true;

Opt-in

    $wgDefaultUserOptions['echo-subscriptions-email-myCategory'] = false;

Rate-limit notification-generating events[edit]

To prevent users from getting spammed by your notification, you can rate-limit the event that generates the notification (e.g., limit a user to 10 or fewer thanks events per minute).

Monitoring[edit]

Echo uses EventLogging to track data about notifications. Some graphs of notification data might be available, check m:Statistics.


Add notification to preference[edit]

To add your extension to echosubscriptions section (section with subheading 'Notify me about these events' ) of Notifications tab in Special:Preferences which allows users to select type of notification, all you need to do is to define Creating a new category inside the onBeforeCreateEchoEvent hook function.

The following code would add the notification preference for Thanks in Special:Preferences#mw-prefsection-echo

public static function onBeforeCreateEchoEvent( &$notifications, &$notificationCategories, &$icons ) {
    $notificationCategories['edit-thank'] = [
		'priority' => 3,
		'tooltip' => 'echo-pref-tooltip-edit-thank',
	];
}