Drupal Notes 7: module custom content type, hook_filter(), custom hook, mail API, sends themed email to all members, creates an action and a trigger

a few of the hooks utilized in this module:

hook_help(), hook_node_info(), hook_form(), hook_filter(), hook_filter_tips(),
hook_action_info(), hook_theme(), hook_mail(), hook_install()

Biggest concept herein: module_invoke_all()

Step 1: sitenews.info

; $Id$
name = “sitenews”
description = “Sends an email news message to all members”
core = 6.x
php = 5.1
; dependencies = “trigger”

Step 2: sitenews.module

// $Id$
/**
* sitenews Module
* Adds a content type
* Provides an action for admininstrators
* Sends emails to all members
* Defines a new hook and a new filter as well
* @file
*/
/**
* Implementation of hook_help()
*/

function sitenews_help($path, $arg){
if($path == ‘admin/help#sitenews’){
$txt = ‘Keep members current via email.’
. ‘You will need a trigger to the corresponding action.’
. ‘Recommendation: the node publish event should be tied to the action.’;
$replace = array();
return ‘<p>’ . t($txt, $replace) . ‘</p>’;
}
}
/**
* Create the sitenewsbrief’ content type
* Implements hook_node_info()
*/

function sitenews_node_info(){
return array(
‘newsbrief’ => array(
‘module’ => ‘sitenews’,
‘name’ => t(‘News Brief’),
‘description’ => t(“A newsletter to all members”),
‘has_title’ => TRUE,
‘title_label’ => t(‘Title’),
‘has_body’ => TRUE,
‘body_label’ => t(‘News Brief’),
)
);
}
/**
* Create the form for editing sitenewsbrief nodes
* Implements hook_form()
*/

function sitenews_form(&$node){
$type = node_get_types(‘type’, $node);
if($type->has_title){
$form[‘title’] = array(
‘#type’ => ‘textfield’,
‘#title’ => check_plain($type->title_label),
‘#required’ => true,
‘#default_value’ => $node->title,
‘#weight’ => -5,
);
}
if($type->has_body){
$form[‘body_field’] = node_body_field(
$node,
$type->body_label,
$type->min_word_count
);
}
return $form;
}
/**
* Implements hook_filter()
*/

function sitenews_filter($op, $delta = 0, $format = -1, $text = ”){
global $user;

if($op == ‘list’){
$list = array(
0 => t(‘Newsletter Brief Placeholders’),
1 => t(‘Remove ALL HTML/XML Tags’),
);
return $list;
}

switch($delta){
// Delta 0 is for replacing placeholders
case 0:
switch ($op)
{
case ‘description’:
return t(‘Replaces {{salutation}} with newsletter brief ‘
. ‘salutation, and {{brief name}} with the newsletter brief ‘
. ‘name.’);
case ‘prepare’:
return $text;
case ‘process’:
$text = str_replace(
{{salutation}}‘,
variable_get(‘sitenews_salutation’, ‘Dear Community Member’),
$text
);
$text = str_replace(
{{brief name}}‘,
variable_get(‘sitenews_name’, ‘Site News’),
$text
);
return $text;
case ‘settings’:
$form[‘sitenews_filter’] = array(
‘#type’ => ‘fieldset’,
‘#title’ => t(‘Site Newsletter Filters’),
‘#collapsible’ => true,
‘#collapsed’ => false,
);
$form[‘sitenews_filter’][‘sitenews_salutation’] = array(
‘#type’ => ‘textfield’,
‘#description’ => t(‘The greeting’),
‘#title’ => t(‘Salutation’),
‘#default_value’ => variable_get(‘sitenews_salutation’, ‘Dear Community Member,’),
);
$form[‘sitenews_filter’][‘sitenews_name’] = array(
‘#type’ => ‘textfield’,
‘#description’ => t(‘Title of the site newsletter’),
‘#title’ => t(‘Site Newsletter Name’),
‘#default_value’ => variable_get(‘sitenews_name’, ‘Site Newsletter’),
);
return $form;
}
case 1:
switch($op)
{
case ‘description’:
return t(‘Removes all tags (HTML or XML elements).’);
case ‘prepare’:
return $text;
case ‘process’:
return strip_tags($text);
} // end switch for $op
} // end outer switch
}
/**
* Formatting instruction tips for content creators
* Implements hook_format_info()
*/

function sitenews_filter_tips($delta, $format, $long){
switch($delta){
case 0:
$text = “Instances of {{brief name}} will be ”
. “replaced by the global name for site newsletter.”
. ” {{salutation}} will be replaced with the global ”
. “greeting message.”;
if($long){
$text .= “Site Newsletter name and salutation text ”
. “can be configured from the administration interface.”;
}
return $text;
case 1:
$text = “HTML and XML tags will be removed from the final output”;
return $text;
}
}
/**
* Get a format ID by name
* This returns an Input Format ID that can be passed to check_marckup() to filter content
* If a matching format isn’t found, the default format is returned
* @param $name
* String name of the format
* @return
* The ID (an integer) of the format
*/

function sitenews_get_format($name){
$res = db_query(
SELECT format FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$format = db_fetch_object($res);
if($format){
return $format->format;
} else {
return FILTER_FORMAT_DEFAULT;
}
}
/**
* Implements hook_action_info()
*/

function sitenews_action_info(){
watchdog(‘action‘,”Called sitenews_action_info”);
$actions[‘sitenews_send_action’] = array(
‘type’ => ‘node’,
‘description’ => t(‘Send site news as email to all users.’),
‘configurable’ => FALSE,
‘hooks’ => array(
‘nodeapi’ => array(‘insert’,’update’,’presave’),
)
);
return $actions;
}
/**
* Action: Send an email message to all users
*/

function sitenews_send_action(&$object, $context){
// If not a published sitenews, skip
if(!$object->status || $object->type != ‘newsbrief’){
return;
}
// Get addresses
$q = “SELECT mail, status FROM {users} ”
. “WHERE status != 0 AND uid > 0
“;
$results = db_query($q);
$addresses = array();
while($obj = db_fetch_object($results)){
$addresses[] = $obj->mail;
}
if(count($addresses) == 0){
watchdog(
‘sitenews’,
‘No user email addresses were found’,
array(),
WATCHDOG_ERROR
);
return;
}
// Execute hook_sitenews()
$content = module_invoke_all(‘sitenews’);
// Build params
$params = array(
‘node’ => $object,
‘to’ => implode(‘, ‘, $addresses),
‘subject’ => $object->title,
‘context’ => $context,
‘additional content’ => $content,
);
$message = _sitenews_do_message($object, $params);
watchdog(
actions‘,
‘Site News “Send action fired. Sending to !mail’,
array(‘!mail’ => $params[‘to’])
);
}
/**
* Internal function to prepare a message and pass it on to the mailer
* @param $node
* The news brief node
* @param $params
* An array of params
*/

function _sitenews_do_message(&$node, $params){
$node = $params[‘node’];
$content = $params[‘additional content’];
// Theme the main node:
$params[‘body’] = theme(‘sitenews_newsbrief’, $node);
// See common.inc (element_sort() and drupal_render()
uasort($content, ‘element_sort’);
// Render each block of content;
foreach($content as $item){
$params[‘body’] .= theme(‘sitenews_msgblock’, $item);
}
// Send the mail:
drupal_mail(
‘sitenews’,
‘sendsitenews’,
$params[‘to’],
language_default(),
$params,
variable_get(‘site_mail’,NULL),
TRUE
);
}
/**
* Implements hook_theme()
*/

function sitenews_theme(){
return array(
‘sitenews_msgblock’ => array(
‘arguments’ => array(‘block’ => NULL),
),
‘sitenews_newsbrief’ => array(
‘arguments’ => array(‘node’ => NULL),
),
);
}
/**
* Theme to display a news brief in a sitenews message block
* @param $node
* The news brief node object
*/

function theme_sitenews_newsbrief($node){
$format = sitenews_get_format(‘Tagless text’);
$text = strtoupper(check_markup($node->title, $format)) . “\n\n”;
$text .= check_markup($node->body, $format) . “\n\n”;
return $text;
}
/**
* Theme for email messages
* @param $block
* A block with #title and #body set
*/

function theme_sitenews_msgblock($block){
$msg = array();
if(!empty($block[‘#title’])){
$title = strtoupper($block[‘#title’]);
for ($i = 0; $i < strlen($title); ++$i){
$underline .= ‘=’;
}
$msg[] = $title;
$msg[] = $underline;
}
$msg[] = $block[‘#body’] .”\n”; // <– extra newline
return implode(“\n”, $msg);
}
/**
* Implementation of hook_mail()
*/

function sitenews_mail($key, &$message, $params){
switch($key){
case ‘sendsitenews’:
$message[‘to’] = $params[‘to’];
$message[‘subject’] = $params[‘subject’];
$message[‘body’] = $params[‘body’];
}
}

Step 3: sitenews.install

// $Id$
/**
* Install the newsletter module
* @file
*/
/**
* Implements hook_intall()
*/
function sitenews_install(){
$name = ‘Tagless text’;
// Check to see if the format already exists
$res = db_query(
SELECT name FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$has_format = db_result($res);
// Create format
if (!$has_format){
db_query(
INSERT INTO {filter_formats} (name) VALUES (‘%s’)“,
$name
);
}
$res = db_query(
SELECT format FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$format = db_fetch_object($res);
$q = “INSERT INTO {filters} (format, module, delta, weight) ”
. “VALUES(%d, ‘newsletter’, %d, %d)
“;
// First, insert the “Newsletter Brief Placeholders” filter:
db_query($q, $format->format, 0, 10);
// Second, insert the “Remove ALL HTML/XML Tags” filter:
db_query($q, $format->format, 1, 0);
}

Step 4: add to module_sitenews() to any modules that will be contributing content to these automatically generated email newsletters, example from personality module (Drupal Notes 6) follows:

function personality_theme(){
return array(
‘personality_info’ => array(
‘template’ => ‘personality_info’,
‘arguments’ => array(
‘dates’ => NULL,
‘life’ => NULL,
‘works’ => NULL,
),
),
// NEW
‘personality_sitenews’ => array(
‘arguments’ => array(‘node’ => NULL),
),
);
}
/**
* Theme function for sitenews
*/

function theme_personality_sitenews($node){
$options = array(‘absolute’ => TRUE);
$url = url(‘node/’. $node->nid, $options);
$title = strip_tags($node->title);
$body = strip_tags($node->teaser); // <– Summary
$text = implode(“\n”, array($title, $body, $url));
$text .= “\n”;
return $text;
}

/*
* Implements hook_sitenews() in sitenews module
*/

function personality_sitenews(){
$q = “SELECT nid, created FROM {node} ”
. “WHERE status = 1 AND type = ‘personality’ ”
. “ORDER BY created DESC
“;
$results = db_query_range($q, 0, 3);
$new_bios = array();
while ($row = db_fetch_object($results)){
$node = node_load($row->nid);
$new_bios[] = theme(‘personality_sitenews’, $node);
}
$content[‘personality’] = array(
‘#weight’ => 0,
‘#title’ => t(‘Recent Biographies’),
‘#body’ => implode(“\n”, $new_bios),
);
return $content;
}

Comments are closed.