How to allow users to manage their own Message Stack messages?

1
+2
-1

The Message Stack is an amazing set of contributed modules that can take care of all sorts of messaging in a Drupal site. At its core is the Message module to deliver messages to (registered) users. However, it's a bit challenging to find out how to use it (take advantage of it). Moreover, it's not really site building friendly.

Question: how can a logged in user view and manage those messages from with a Drupal site, in such a way that:

  • The messages can be browsed from within the site by authorized users.
  • Selected messages can be marked as "read", and if needed also be marked "unread" again.
  • If there are new (unread) messages, some sort of notification within the site should alert the user, similar to "you have new mail" in an eMail client.
  • There is no custom code involved (only site building techniques).

Topics: 

Category: 

1 answer

1
+1
-1

Step 1 - Create a flag

There is nothing in the Message module equivalent to the "new content" indicator for nodes. However, messages created by the Message module are entities, so messages can be flagged (using the Flag module), which is what can be used to implement the equivalent of such new content indicator.

So to indicate if a message is read or unread, introduce a (non global) flag:

  • with machine name (say) message_viewed.
  • labeled (say) Message viewed.
  • only role authenticated user may use this flag.

The usage of this flag will be like so:

  • flagged messages are consider as read.
  • all other messages are considered as unread.

Here is an export of the Message viewed flag:

    $flags = array();
    // Exported flag: "Message viewed".
    $flags['message_viewed'] = array (
      'entity_type' => 'message',
      'title' => 'Message viewed',
      'global' => '0',
      'types' => 
      array (
      ),
      'flag_short' => 'Mark message as viewed',
      'flag_long' => 'Use this link to mark a message as viewed',
      'flag_message' => 'Message marked as viewed',
      'unflag_short' => 'Mark message as not yet viewed',
      'unflag_long' => 'Use this link to mark a message as not yet viewed',
      'unflag_message' => 'Message marked as not yet viewed',
      'unflag_denied_text' => '',
      'link_type' => 'toggle',
      'weight' => 0,
      'show_in_links' => 
      array (
        'full' => 'full',
        'message_notify_email_subject' => 0,
        'message_notify_email_body' => 0,
      ),
      'show_as_field' => 0,
      'show_on_form' => 0,
      'access_author' => '',
      'show_contextual_link' => 0,
      'api_version' => 3,
    );
    return $flags;

Step 2 - Create a view Messages by user (Message)

Add a new view

  • View name "Messages by user".
  • Show Message.
  • Type All.
  • Create a page (not a block)

Create 3 table displays of this view

  • All messages
  • Read messages
  • Unread messages

Add Contextual Filters for all 3 displays

  • Message: User uid, and for "When the filter value is NOT in the URL" use "Provide default value" with Type "User ID from logged in user".

Add Relationships for all 3 displays

  • Message: User uid
  • Flags: message_viewed (by current user)

Add Fields for all 3 displays

  • Message: Message ID (Msg ID)
  • Message: Timestamp (Created on)
  • Message: Render message (Get text) (Text)
  • (User) User: Name (User) ( 1 )

    ( 1 ) : Use "Exclude from display" for this field, which is only needed to add a "Global: Text area" to the views headers which contains something like Messages for user [name].

Add Sort criteria for all 3 displays

  • Message: Timestamp (desc)

Refine display All messages

  • Extra fields:

    • (flag) Flags: Flagged (Read Y/N)
    • (flag) Flags: Flagged time (Read on)
  • Filter criteria: none

  • Page settings:

    • Path: /user/%/messages
    • Menu tab: Messages

Refine display Read messages

  • Extra fields:

    • (flag) Flags: Flagged time (Read on)
  • Filter criteria:

    • (flag) Flags: Flagged (True)
  • Page settings:

    • Path: /user/%/messages/read
    • Menu tab: Read Messages

Refine display Unread messages

  • Extra fields: none

  • Filter criteria:

    • (flag) Flags: Flagged (False)
  • Page settings:

    • Path: /user/%/messages/unread
    • Menu tab: Unread Messages

Step 3 - Use Rules to flag/unflag messages

To actually mark a message as read (or unread), use the Rules module to flag (or unflag) a message with the Message viewed flag (from step 1). For this, create 2 (extremely basic) Rules Components as further detailed below (both of them use a "Message" as a variable).

To mark Unread msgs as Read

Here is the Rules Component (in Rules export format) to let the currently logged in user flag a message (using the Message viewed flag):

{ "rules_flag_a_message" : { "LABEL" : "Flag a message", "PLUGIN" : "rule", "OWNER" : "rules", "REQUIRES" : [ "flag" ], "USES VARIABLES" : { "message_to_flag" : { "label" : "Message to be flagged", "type" : "message" } }, "DO" : [ { "flag_flagmessage" : { "flag" : "message_viewed", "message" : [ "message-to-flag" ], "flagging_user" : [ "site:current-user" ], "permission_check" : "1" } } ] } }

If you have the Rules UI submodule enabled, you should be able to import the above rule in your own site, provided you first defined the flag as in step 1 (with same machine name, or after you adapted that name in the exported rule above).

To mark Read msgs as Unread

Here is the (similar) Rules Component (in Rules export format) to let the currently logged in user unflag a message (using the Message viewed flag):

    { "rules_unflag_a_message" : {
        "LABEL" : "Unflag a message",
        "PLUGIN" : "rule",
        "OWNER" : "rules",
        "REQUIRES" : [ "flag" ],
        "USES VARIABLES" : { "message_to_unflag" : { "label" : "Message to be unflagged", "type" : "message" } },
        "DO" : [
          { "flag_unflagmessage" : {
              "flag" : "message_viewed",
              "message" : [ "message-to-unflag" ],
              "flagging_user" : [ "site:current-user" ],
              "permission_check" : "1"
            }
          }
        ]
      }
    }

If you have the Rules UI submodule enabled, you should be able to import the above rule in your own site, provided you first defined the flag as in step 1 (with same machine name, or after you adapted that name in the exported rule above).

Step 4 - Trigger the Rules Component to mark messages

About the only thing left to start marking messages as read (or unread), is to have some mechanism to trigger the appropriate Rules Component from step 3, and this from within the views display Unread messages (or Read messages) created in step 2.

Using the Views Bulk Operations (VBO) module is a possible approach for triggering Rules Components. It facilitates processing messages one by one, or a list of selected messages, or even all messages in a single operation. Read on for further details about this approach.

Add VBO processing to mark Unread messages as Read

Enhance the views display Unread messages (from step 2), by adding a VBO field like so:

  • Add a field to the view, and filter the available fields to "Bulk Operations" only. Then select "Bulk operations: Message".
  • Further refine the configuration of this field like so:

    • Create a label "Mark as read".
    • For "Selected bulk operations", only check the one that says "Flag a message" ( 2 ). While doing so, also override the label of if, and use a label like "Mark selected message(s) as read".
    • Within "Bulk operations settings" pick the options you prefer. My recommendation are these options: (a) Each action as a separate button (b) Enable "Select all items on all pages".

Add VBO processing to eventually mark Read messages as Unread

Enhance the views display Read messages (from step 2), by adding a VBO field like so:

  • Add a field to the view, and filter the available fields to "Bulk Operations" only. Then select "Bulk operations: Message".
  • Further refine the configuration of this field like so:

    • Create a label "Mark as unread".
    • For "Selected bulk operations", only check the one that says "Unflag a message" ( 2 ). While doing so, also override the label of if, and use a label like "Mark selected message(s) as unread".
    • Within "Bulk operations settings" pick the options you prefer. My recommendation are these options: (a) Each action as a separate button (b) Enable "Select all items on all pages".

( 2 ): this is actually a reference to one of the 2 Rules Components from step 3, and which is what in the end will make it all work automagically!

Step 5 - Create notifications about Unread Messages

Enable the Menu Badges module

Enable the Menu Badges module to show the number of Unread Messages via a (red) counter related to the Unread messages view (from step 2), which will look similar to this screenprint:


enter image description here


Refer to "How to create a basic message - notifications system displaying a real time message counter badge?" for more details about this (great) module.

Create Messages counter Views display

Improve the view created in step 2 before, by adding an extra views display which, at any time, will contain (only!) a counter of the number of messages contained in the Unread messages views display.

Here is how to do so:

  • Add a new views display, named (say) "Unread msgs badge".
  • Make sure to select "Menu Badge" for its display (that's part of the magic ...).
  • Add field "Message: Message ID (Msg ID)"
  • As Contextual filters add "Message: User uid", and for "When the filter value is NOT in the URL" use "Provide default value" with Type "User ID from logged in user".
  • As Relationships add "Flags: message_viewed (by current user)".
  • Filter criteria: "(flag) Flags: Flagged (False)".
  • Enable aggregation (Use aggregation: Yes) and change the aggregation type for field "Message: Message ID (Msg ID)" to COUNT.
  • Attention: with the above setup, when there are 0 unread messages, the notification badge will be shown with a 0 in it. If in this case you don't want any badge at all, then check the option "Hide if empty" when configuring this "Message: Message ID (Msg ID)" field.

Configure menu tab "Unread messages" for the Menu Badges

If the views configuration of the "Unread msgs badge" display (as described above) is done correct, then the Views preview result should (only) show a number that matches the amount of messages that are unflagged (= number of Unread messages).

All that's left is this:

  • navigate to relative path admin/structure/menu/menu-badges-tabs.
  • within the search box (at the top), in the "Menu path" field, enter part of the path used for the views display Unread messages, eg something like "unread", to find the entry with path user/%/messages/unread.
  • for this entry, select "Messages by user: Unread msgs badge" (that is then name of our view, followed by the name of the views display) from the selection list related to "Menu Badge".

After you hit the Save button, the (red) notification button should start showing up (if you do have at least 1 unflagged message ...).

Step 6 - Possible variations

The approach described above can be used for any entity for which you want to create a similar Views based solution to allow each user to manage their own entity based data. Just change any occurence of "Message" to "YourEntityOfChoice" in the solution described above.

Yet another variation is to use similar/additional flags: in this case the flag was just to indicate read versus unread. But as per the spirit of the Flag module, you could use it for things such as:

  • entities a user likes or doesn't like.
  • users that a user wants to follow or mute.
  • ...

Voilà ...

No custom coding required, only using the joint power of a few popular contributed modules such as Views, Flag, Rules, Message (=VFRM) and VBO, with Menu Badges as a hidden gem added to it.