Hi,
I'm newish to Drupal (thanks Steve for putting me in touch with this group) and wonder whether anyone can point me in the right direction please?
I want to create a view that allows you to select a number of nodes using checkboxes (I have VBO) then allows entry of an email recipient(s) using a text box on the same page as the view. A submit button then validates the email address then calls a custom function I will write that builds one email with a list of node details in the body.
The part I am unsure about is the best way of adding/validating the recipient field. I have managed to create a new module with my hook_node_operation and made my view do a callback to it but that doesn't allow for my recipient field on the view page. Is there a module or example article out there?
Thanks,
Karim.
Comments
More info...
Hi Karim,
Simplenews module does something similar to this if there is a pattern to the nodes you're selecting:
http://drupal.org/project/simplenews
What is it you're trying to do? Perhaps a little more explanation will help - I've already mentioned editable fields and actions to you which will do what you want, but without knowing the real-life scenario it's hard to say which is the best approach...
Hi Steve, I agree with you.
Hi Steve,
I agree with you. The real life problem is to provide a page that allows the user to find product stockists within a given radius (in miles) of a postcode, display them as a list on a page, further refine the list manually using check boxes, enter an email recipient(or list of recipients) into a text input field, then send an email listing the selected stockists to each recipient.
I'm using Drupal 6 and have so far used the Location (hacked to make proximity search work!) and Views modules to produce initial list of stockists by postcode/miles radius. By the way, each Stockist is a node with one attached locative field.
Thanks for your tip of using editable fields but that seems to be applicable to editing individual node fields in a wysiwyg style which isn't what I'm trying to do here.
K
Initial thoughts
May be wrong but two possible ways:
hack: add the email form as a custom footer to the view (use VBO for the view) so they check the boxes, enter the email addresses and click 'send'
better hack: possibly use http://drupal.org/project/viewsforms to include the view (using VBO) in a form - http://drupal.org/project/webform has lots of functions so look at that
hth
Thanks again Steve but after
Thanks again Steve but after looking at the core code I've discovered the "proper" (non-hacky) solution.
I created a new Views Bulk Operations action file: email.nodes.action.inc and put it in the views_bulk_operations folder (probably not where custom code should go but just getting it working). The "magic" is in the "aggregate" and "configurable" parameters which tell Drupal to call the action just once and that the action needs parameters from a form.
Do you know where my custom VBO action file should properly go?
<?php
// $Id:$
/
* @file
* Emails selected objects to a recipient as a list
*/
/
* Implementation of hook_action_info().
*/
function views_bulk_operations_email_nodes_action_info() {
return array(
'views_bulk_operations_email_nodes_action' => array(
'description' => t('Email list of nodes to a recipient'),
'type' => 'system', // this should probably be changed to something else!
'aggregate' => TRUE, // tell Drupal this action operates on all nodes at once (not one by one)
'configurable' => TRUE, // tell Drupal this action requires form input
'hooks' => array(),
),
);
}
/
* Implementation of a Drupal action.
* Passes selected nodes as arguments to a view.
* @param $objects array of node IDs
* @param $context array of other parameters
/
function views_bulk_operations_email_nodes_action(
$objects,
$context = array()
) {
global $user;
// $objects is an array of object IDs, since the action includes aggregate.
/
* @todo Build the email containing the node descriptions here.
* We need to loop through getting the nodes from the $objects ID array and
* building the body of the email into $params['context']['body'] and subject into $params['context']['subject']
*/
$recipient = $context['recipient'];
$account = $user;
$language = user_preferred_language($account);
$params = array('account' => $account, 'context' => $context);
if (drupal_mail('view_bulk_operations_email_nodes', 'action_send_email', $recipient, $language, $params)) {
watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient));
}
else {
watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient));
}
}
/
* Implementation of hook_mail().
*/
function view_bulk_operations_email_nodes_mail(
$key,
&$message,
$params
) {
$account = $params['account'];
$context = $params['context'];
$variables = array(
'%site_name' => variable_get('site_name', 'Drupal'),
'%username' => $account->name,
);
$subject = strtr($context['subject'], $variables);
$body = strtr($context['message'], $variables);
$message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
$message['body'][] = drupal_html_to_text($body);
}
function views_bulk_operations_email_nodes_action_form($context) {
$form['recipient'] = array(
'#title' => t('Email Recipient'),
'#type' => 'textfield',
'#description' => t('Enter an email address to send the list of nodes to.'),
'#default_value' => @$context['recipient'],
'#required' => TRUE,
);
return $form;
}
/
* Validate system_send_email_action form submissions.
*/
function views_bulk_operations_email_nodes_action_validate($form, $form_state) {
$form_values = $form_state['values'];
// Validate the configuration form.
if (!valid_email_address_list($form_values['recipient'] ) ) {
form_set_error('recipient', t('Please enter valid email addresses.'));
}
}
/
* Verify the syntax of the given comma-delimited list of e-mail addresses.
*
* @param $mail
* A string containing comma-delimited list of e-mail addresses.
* @return
* TRUE if all the addresses are in a valid format.
* @todo
* Put this function in the correct place for user functions.
*/
function valid_email_address_list($mail) {
$ret = true;
$email_array = explode(',', $mail);
foreach ( $email_array as $key => $email_address ){
if ( !valid_email_address( $email_address ) ){
$ret = false;
break;
}
}
return $ret;
}
function views_bulk_operations_email_nodes_action_submit($form, $form_state) {
return array('recipient' => $form_state['values']['recipient']);
}
UPDATE: I have rewritten my
UPDATE: I have rewritten my email_nodes action as a module called email_nodes_action:
<?php
// $Id:$
/
* @file
* Emails selected objects to a recipient as a list
*/
/
* Implementation of hook_perm().
*/
function email_nodes_action_perm() {
return array('access email_nodes_action', 'create email_nodes_action', 'administer email_nodes_action');
}
/
* Display help and module information
* @param path which path of the site we're displaying help
* @param arg array that holds the current path as would be returned from arg() function
* @return help text for the path
*/
function email_nodes_action_help($path, $arg) {
$output = ''; //declare your output variable
switch ($path) {
case "admin/help#email_nodes_action":
$output = '<p>'. t("Sends an email to given recipient listing all the stockists selected in the view") .'</p>';
break;
}
return $output;
}
/
* Implementation of hook_action_info().
*/
function email_nodes_action_action_info() {
return array(
'email_nodes_action' => array(
'description' => t('Email list of nodes to a recipient'),
'type' => 'system', // this should probably be changed to something else!
'aggregate' => TRUE, // tell Drupal this action operates on all nodes at once (not one by one)
'configurable' => TRUE, // tell Drupal this action requires form input
'hooks' => array(),
),
);
}
/
* Implementation of a Drupal action.
* Passes selected nodes as arguments to a view.
* @param $objects array of node IDs
* @param $context array of other parameters
/
function email_nodes_action(
$objects,
$context = array()
) {
global $user;
// $objects is an array of object IDs, since the action includes aggregate.
/
* @todo Build the email containing the node descriptions here.
* We need to loop through getting the nodes from the $objects ID array and
* building the body of the email into $params['context']['body'] and subject into $params['context']['subject']
*/
$recipient = $context['recipient'];
$account = $user;
$language = user_preferred_language($account);
$params = array('account' => $account, 'context' => $context);
if (drupal_mail('email_nodes_action', 'action_send_email', $recipient, $language, $params)) {
watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient));
}
else {
watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient));
}
}
/
* Implementation of hook_mail().
*/
function email_nodes_action_mail(
$key,
&$message,
$params
) {
$account = $params['account'];
$context = $params['context'];
$variables = array(
'%site_name' => variable_get('site_name', 'Drupal'),
'%username' => $account->name,
);
$subject = strtr($context['subject'], $variables);
$body = strtr($context['message'], $variables);
$message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
$message['body'][] = drupal_html_to_text($body);
}
function email_nodes_action_form($context) {
$form['recipient'] = array(
'#title' => t('Email Recipient'),
'#type' => 'textfield',
'#description' => t('Enter an email address to send the list of nodes to.'),
'#default_value' => @$context['recipient'],
'#required' => TRUE,
);
return $form;
}
/
* Validate email_nodes_action form submissions.
*/
function email_nodes_action_validate($form, $form_state) {
$form_values = $form_state['values'];
// Validate the configuration form.
if (!valid_email_address_list($form_values['recipient'] ) ) {
form_set_error('recipient', t('Please enter valid email addresses.'));
}
}
/
* Verify the syntax of the given comma-delimited list of e-mail addresses.
*
* @param $mail
* A string containing comma-delimited list of e-mail addresses.
* @return
* TRUE if all the addresses are in a valid format.
* @todo
* Put this function in the correct place for user functions.
*/
function valid_email_address_list($mail) {
$ret = true;
$email_array = explode(',', $mail);
foreach ( $email_array as $key => $email_address ){
if ( !valid_email_address( $email_address ) ){
$ret = false;
break;
}
}
return $ret;
}
function email_nodes_action_submit($form, $form_state) {
return array('recipient' => $form_state['values']['recipient']);
}
Did it work ok?
I haven't played with VBO, I just knew what it did. Did your code work ok?
It works perfectly! I can
It works perfectly and I now have it sending emails that list all the stockist details. I can imagine lots of neat solutions you could build around this combo of modules. Quite often you need to do something further with your result set don't you?
Excellent!
Excellent - glad it all worked!
It takes a lot to keep up with what modules are out there but when I get chance I like to try them out, only if to find if there's functionality there I could use or at least remember is there for future reference - I don't think I've had to code much from scratch!
bulk operations not listed on views created with data module
Just need some help from you regarding the following issue.
I have a created a view from a drupal database table using the data module with views and VBO.
The data module allows you to create a view from the adopted table.
But,
when I go to the views and edit the view added through the data module, i see no multi-checkbox list under selected operations.
I want to have all the operations that are available under the node view type to be available here, for my view created with data module. (views created with data module have a view type data table)
Any help greatly appreciated.
Please help me ...it's really urgent.
Thanks,
Nilesh Barve
Updated for Drupal 7
@karimahmed - Thanks for posting your code! Here is an updated version for Drupal 7:
<?php
/**
* @file
* Emails selected nodes to a recipient as a list
*/
/**
* Implements hook_permission().
*/
function email_nodes_action_permission() {
return array(
'access email_nodes_action' => array(
'title' => t('Access email_nodes_action'),
),
'administer email_nodes_action' => array(
'title' => t('Administer email_nodes_action'),
),
);
}
/**
* Implements hook_help().
*/
function email_nodes_action_help($path, $arg) {
switch ($path) {
case "admin/help#email_nodes_action":
return '<p>' . t("Sends an email to given recipient(s) listing all the nodes selected in the view") . '</p>';
}
}
/**
* Implements hook_action_info().
*/
function email_nodes_action_action_info() {
return array(
'email_nodes_action' => array(
'type' => 'system',
'label' => t('Email list of nodes to a recipient'),
'configurable' => TRUE,
'aggregate' => TRUE,
'triggers' => array(),
),
);
}
/**
* Implementation of a Drupal action.
*
* Passes selected nodes as arguments to a view.
*
* @param array $objects
* Array of node IDs
* @param array $context
* Array of other parameters
*/
function email_nodes_action($objects, $context = array()) {
global $user;
$language = user_preferred_language($user);
// Optional header so recipient can reply to user.
$context['replyto'] = $user->mail;
$params = array('account' => $user, 'context' => $context);
// $objects is an array of object IDs, since the action includes aggregate.
/* @todo Build the email containing the node descriptions here.
* We need to loop through getting the nodes from the $objects ID array and
* building the body of the email into $params['context']['body'] and subject
* into $params['context']['subject']
*/
foreach ($objects as $one_node) {
// Do something
}
if (drupal_mail('email_nodes_action', 'action_send_email', $context['recipient'], $language, $params)) {
watchdog('action', 'Sent email to %recipient', array('%recipient' => $context['recipient']));
}
else {
watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $context['recipient']));
}
}
/**
* Implements hook_mail().
*/
function email_nodes_action_mail($key, &$message, $params) {
$account = $params['account'];
$context = $params['context'];
$variables = array(
'%site_name' => variable_get('site_name', 'Drupal'),
'%username' => format_username($account),
);
$subject = strtr($context['subject'], $variables);
$body = strtr($context['message'], $variables);
$message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
$message['body'][] = drupal_html_to_text($body);
$message['headers']['Reply-To'] = $context['replyto'];
}
/**
* Implements hook_form().
*/
function email_nodes_action_form($context) {
$form['recipient'] = array(
'#title' => t('Recipient'),
'#type' => 'textfield',
'#description' => t('The email address to which the message should be sent. Separate multiple email addresses with a comma.'),
'#default_value' => @$context['recipient'],
'#required' => TRUE,
);
$form['subject'] = array(
'#title' => t('Subject'),
'#type' => 'textfield',
'#description' => t('The subject of the message.'),
'#default_value' => @$context['subject'],
'#required' => TRUE,
);
$form['message'] = array(
'#title' => t('Message'),
'#type' => 'textarea',
'#description' => t('The message to be sent.'),
'#default_value' => @$context['message'],
'#required' => TRUE,
'#cols' => 60,
'#resizable' => TRUE,
'#rows' => 10,
);
return $form;
}
/**
* Validate email_nodes_action form submissions.
*/
function email_nodes_action_validate($form, $form_state) {
$form_values = $form_state['values'];
// Validate the configuration form.
if (!valid_email_address_list($form_values['recipient'])) {
form_set_error('recipient', t('Please enter valid email addresses.'));
}
}
/**
* Verify the syntax of the given comma-delimited list of e-mail addresses.
*
* @param string $mail
* A string containing comma-delimited list of e-mail addresses.
*
* @return bool
* TRUE if all the addresses are in a valid format.
*
* @todo
* Put this function in the correct place for user functions.
*/
function valid_email_address_list($mail) {
$ret = TRUE;
$email_array = explode(',', $mail);
foreach ($email_array as $key => $email_address) {
if (!valid_email_address($email_address)) {
$ret = FALSE;
break;
}
}
return $ret;
}
/**
* Implements hook_submit().
*/
function email_nodes_action_submit($form, $form_state) {
return array(
'recipient' => $form_state['values']['recipient'],
'subject' => $form_state['values']['subject'],
'message' => $form_state['values']['message'],
);
}
?>