HOWTO build an add-on for Subscriptions module

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

The Subscriptions module provides a range of subscription types. Users can subscribe to individual content items, to all items of a particular content type, to all posts in a particular blog, or to all items tagged with a particular taxonomy term. The range of subscription types can be extended by additional add-on modules. This guide describes the hooks a module needs to implement to provide new subscription types.

In the examples given below we have a module called 'myplugin' which implements a single new subscription type called 'mytype'.

User Interface

In order to let users manage their subscriptions and administrators manage user and global settings, an add-on should implement the following hooks:

_hook_types()

This is a key function for providing useful information about your module. The returned information is used by the subscriptions module to:

  • Construct a sub-tab for each new subscription type on the Subscriptions settings pages.
  • Create an access permission for each new subscription type.

The function should return an array with one entry for each subscription type that your module creates, indexed by the machine-readable name of the subscription type. The value of each entry is itself an array with the following fields:

  • 'title' The user-friendly name for the subscription type. It is used for example as the label of the sub-tab that each subscription type gets on the user and admin subscription pages.
  • 'access' The name of the permission for creating subscriptions of this type.
  • 'page' The function in charge of displaying the list of subscriptions of this type.
  • 'fields' Used for mailvars(Subscriptions_Mail) this is an array of two strings which you can choose freely for this subscription type. It does not matter what you choose as long as it is unique to this subscription type, so you could use machine-readable name of the subscription type.
  • 'weight' This determines the order in which subscription types are displayed in the user interface.

Example 1:

<?php
function _myplugin_types() {
 
$types['mytype'] = array(
   
'title' => t('My type'),
   
'access' => 'subscribe to my type',
   
'page' => 'myplugin_page_mytype',
   
'fields' => array('myplugin', 'mytype'),
   
'weight' => 0,
  );
  return
$types;
}
?>

hook_count_user_subscriptions()

Used in order of provide a count of subscriptions a user has of a particular type, ie: amount of blogs a user is subscribed to, amount of threads (posts) a user is subscribed to, and so on.

The function should return an array in the form:

<?php
array(
 
'myplugin' => array(
   
'mytype' => #count
 
)
);
?>

Example 2:

<?php
 
function myplugin_count_user_subscriptions($count, $uid) {
   
$type   = _myplugin_types();
   
$fields = $type['mytype']['fields'];
   
$query = "
  SELECT count(*)
  FROM {subscriptions}
  WHERE
    module = 'node' AND
    field = 'mytype' AND
    recipient_uid = %d
    "
;
   
$count[$fields[0]][$fields[1]] = db_result(db_query($query, $uid));
    return
$count;
  }
?>

Notice at previous example:
- Dependency on own _myplugin_types() which returns the types defined by your add-on, so $fields is used to provide a valid array structure of counts.
- Subscriptions table stores your plug-in data using string 'mytype' (previously defined in _hook_types) as value for column: field
- 'node' is the name of the module providing the data.

_hook_node_options()

Subscriptions_UI module provides a User Interface for users to manage subscriptions displaying a form in every node (a.k.a subscriptions controls or node form). Implement this function if you want to add options for your plug-in. See also: hook_form_alter(), in order of customize the node form before render.

This function should return an array with a row for every type and every type with a row for each option.

Example 3:

<?php
function _myplugin_node_options($account, $content) {
 
$options['mytype'] = array(
    array(
     
'name' => 'The label of this option'
      'params'
=> array('value' => $content_id),
     
'links' => 'node/'. $content_id,
    ),
  );
  return
$options;
}
?>

Notice at previous example:
- $account is a parameter you can use for validation.
- $content is an object (commonly a node).
- 'params' is an option property. Must keep the form: array('value' => #ID).
- #ID or $content_id(in the example) is stored into subscriptions table in the column: value.

hook_mailkeys()

Used in order of let Mail Editor manage your plug-in's mail templates, since Subscriptions_Mail module depends on mail_edit.

Example 4:

<?php
function _myplugin_node_options($account, $node) {
 
$options = array();
  foreach (
$node->taxonomy as $my_id => $term) {
   
// Taxonomy term
   
$options['my_id'][] = array(
     
'name' => t('To posts in %myplugin', array('%myplugin' => $term->name)),
     
'params' => array('value' => $my_id),
     
'link' => 'myplugin/'. $my_id,
    );
   
$options['my_id']['weight'] = -1;
  }
  return
$options;
}
?>

SUBSCRIPTIONS FRAMEWORK

Once You know how to construct an UI for our add-on, it is time to deal with queue, subscription types and fields for mailvars.

hook_subscriptions()

It is on charge of rooting sub-hooks determined by param $op, those are:
- _subhook_types please refer to _hook_types(above)
- _subhook_node_options please refer to _hook_types(above)
- _subhook_queue
- _subhook_fields
- _subhook_stypes
- _subhook_stype

Notice: _subhook_types and _subhook_node_options are defined in single functions, but _subhook_queue, _subhook_stypes, _subhook_stype, _subhook_fields were defined internally and managed using switch:

Example 5:

<?php
function myplugin_subscriptions($op, $arg0 = NULL, $arg1 = NULL, $arg2 = NULL) {
 
// $stypes Is used later in subhooks: stype and stypes
 
static $stypes = array('mykey' => array('node', 'mytype'));
?>

Example 6:
Sub-hook handler, you should copy it as is.

<?php
  $function
= '<em>myplugin</em>'. $op;
 
// <!-- WARNING! COPY AS IS
 
if (function_exists($function)) {
    return
$function($arg0, $arg1, $arg2);
  }
 
// END -->
?>

Example 7:
BEGIN OF SWITCH

<?php
 
switch ($op) {
?>

_subhook_queue()

Occurs when a notification event is going to be added.
$arg0 must be an array in the following form.
Example 8:

array(
  'module' => 'node',
  'node' => (A node object),
  'type' => 'node',
  'action' => 'update', // Used in conjunction of 'type' to filter by send_updates
);
You can replace 'node' by 'comment' according to your needs.

$arg1 not used.
$arg2 not used.

Example 9:

<?php
   
case 'queue':
     
// $arg0 is $event array.
     
if ($arg0['module'] == 'node') {
       
$node = $arg0['node'];
       
$params['node']['mytype'] = array(
         
'join' => 'INNER JOIN {mytable} a ON s.value = a.mytype',
         
'where' => 'a.nid = %d',
         
'args' => array($node->nid),
        );
        if (
$arg0['type'] == 'comment') {
         
$where = ' AND s.send_comments = 1';
        }
        elseif (
$arg0['type'] == 'node' && $arg0['action'] == 'update') {
         
$where  = ' AND s.send_updates = 1';
        }
        if (isset(
$where)) {
         
$params['node']['mytype']['where'] .= $where;
        }
        return
$params;
      }
      break;
?>

_subhook_fields()

Occurs when notification emails are generated.
$arg0 must be 'node' or 'comment'.
$arg1 not used.
$arg2 not used.

Example 10:

<?php
   
case 'fields': // Parameter is module
     
if ($arg0 == 'node' || $arg0 == 'comment') {
       
$t = get_t();
        return array(
         
'group_nid' => array(
           
'mailvars_function' => '_subscriptions_content_node_mailvars',
           
'!type' => $t('category'),
          ),
        );
      }
      break;
?>

_subhook_stypes()

Alternative call to retrieve all subscription types a plugin may have.
Example 11:

<?php
   
case 'stypes':
      return
$stypes;
      break;
?>

_subhook_stype()

Occurs when a subscription is added. Retrieves an specific subscription type.
$arg0 must be an array key of $stypes.
$arg1 must be merged with selected subscription type.
$arg2 must be merged with selected subscription type.

Example 12:

<?php
   
case 'stype':
      return (isset(
$stypes[$arg0]) ? array_merge( $stypes[$arg0], array($arg1, $arg2)) : NULL);
      break;
?>

END OF SWITCH AND FUNCTION

<?php
 
}
}
?>

Blessings!

Mail

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: