Drupal Hook needed, hook_message_alter

As I have been working on the functional implementation for a new community Drupal site, I have been seeing the need to customize many of the core Drupal messages (the drupal_set_message function), as required by the needs of the site. A typical example would be when a contact message has been sent, the default message is 'The message has been sent.' An small change might be to 'Thank you, your message has been sent.' A more dynamic change would be 'Thank you Greg, your message has been sent'.

The first change could be accomplished using the locale module methodologies found in http://drupal.org/node/58030. But there are two short-comings to this method. First, even though all core modules use t() for the text to make it translation ready, many contributed modules do not. Second, the translation method only allows for string replacements, not dynamic insertions. Granted some of the messages place the user's name or other dynamic information into the message, but the basic idea is that you can only change what is given you, you can't add to it. The contact message is a perfect example, there is no way to add the user's name to the message.

That is why I am going to propose a new drupal hook, hook_message_alter($message_id = NULL, $message = NULL, $type = 'status'). This function would return the new $message. It would hook into the drupal_set_message function. All messages would invoke this hook, giving designers and developers the ability to customize those messages completely to suit their site.

Since the purpose of hooks is to 'Allow modules to interact with the Drupal core', then this hook is needed for any time that the core (or any contributed) messages are not composed the way a site owner would want them to be.

This hook would most likely be used as part of theming/customization of site, and thus not used much in a contibuted module, though it may be used in a contibuted theme if the designer wanted to update the message prose. Personally I would use such a hook to dynamically insert text into the messages at key points in the user experience (especially if I am seeking to make certian conversion points of a client's site personalized).

The new drupal_set_message would pass the $message by reference and change to:

function drupal_set_message($message_id, $message = NULL, $type = 'status') {
if ($message) {
if (!isset($_SESSION['messages'])) {
$_SESSION['messages'] = array();
}

if (!isset($_SESSION['messages'][$type])) {
$_SESSION['messages'][$type] = array();
}
module_invoke_all('message_alter', $message_id, $message, $type);
$_SESSION['messages'][$type][] = $message;
}

// messages not set when DB connection fails
return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL;
}

With an implementation of a hook looking like:

Return value

The return value is discarded. Modify the parameters directly.

function example1_message_alter ($message_id, &$message = NULL, $type = 'status') {
if ($message_id == 'contact_mail_page') {
global $user;
$message = 'Thank you ' . $user->name . ' for contacting us. You message has been sent.';
}

All 280+ messages set in the core modules would have to be updated to include a unique message_id (can usually be the form_id if present, standard 'module_' convention would apply). Also a note for all Drupal HEAD modules would have to be updated to include message_id's. The message id could also be made optional with a bypass of the module_invoke_all if not present (but that would defeat the purpose of the hook).

Please let me know any of your thoughts, as I will present this as an issue at Drupal.org once I have better composed this idea. -Greg

I like this. This could be

I like this. This could be yet another step in making Drupal a bit more friendly and less terse.

Thank you for the positive

Thank you for the positive feedback. One offline note thought that maybe there would not be a need for a message_id. Maybe it can be discussed when I make an 'issue' out of this, but without an id, a string compare would need to be implemented. But such a tactic presupposes that the message text never changes. In each release of Drupal some of the core messages may be changed slightly, breaking the compares. More so for contributed modules which evolve faster, the messages may be tweaked with each release. A message_id would be a more permenant linking of the specific message to the hook implementation, that should be presevered even if slight changes to the text persist, which should keep from breaking the code upon small updates.

On some advice, I will also be looking at hook_form_alter for a slightly different way to implement this idea.

The idea of a $message_id

The idea of a $message_id may be extraneous, so here is the updated code with the id removed and the better call by reference borrowed from hook_form_alter.

Updated code is as follows:

function drupal_set_message($message = NULL, $type = 'status') {
if ($message) {
if (!isset($_SESSION['messages'])) {
$_SESSION['messages'] = array();
}

if (!isset($_SESSION['messages'][$type])) {
$_SESSION['messages'][$type] = array();
}

foreach (module_implements('message_alter) as $module) {
$function = $module .'_message_alter';
$function($message);
}

$_SESSION['messages'][$type][] = $message;
}

// messages not set when DB connection fails
return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL;
}

function example1_message_alter (&$message = NULL) {
if (strcmp($message_id, 'The message has been sent.') {
global $user;
$message = 'Thank you ' . $user->name . ' for contacting us. Your message has been sent.';
}

Great idea :) I would find

Great idea :) I would find this hook very useful. Would it be possible to remove/unset messages as well? I have come across the need to do this before, and ended up hacking the $_SESSION['messages'] array as far as I can remember.

I forgot to say that

I forgot to say that hook_menu_alter() is another function I'd like to see, I've seen some talk about it, hoping for it to show up in Drupal 6.

If you need to consistently

If you need to consistently unset messages, I think that you could just create a function in your theme, that does the checking and purging. Then instead of just printing the $messages variable in your theme, you print your function. Something like this in your page.tpl.php file.

print trim_messages($messages)

The drupal.org issue has

The drupal.org issue has been made at http://drupal.org/node/127262. Some talk of using either a $messagekey. Most updates will be placed in the issue from now on.

Things have slowed down in

Things have slowed down in the queue. I will keep trying to raise this issue before the code freeze in June.