array( 'title' => t('administer newsletters'), 'description' => t('TODO Add a description for administer newsletters'), ), 'administer simplenews subscriptions' => array( 'title' => t('administer simplenews subscriptions'), 'description' => t('TODO Add a description for administer simplenews subscriptions'), ), 'administer simplenews settings' => array( 'title' => t('administer simplenews settings'), 'description' => t('TODO Add a description for administer simplenews settings'), ), 'send newsletter' => array( 'title' => t('send newsletter'), 'description' => t('TODO Add a description for send newsletter'), ), 'subscribe to newsletters' => array( 'title' => t('subscribe to newsletters'), 'description' => t('TODO Add a description for subscribe/unsubscribe to newsletters'), ), ); } /** * Implementation of hook_init(). * @todo Check parameters of drupal_add_css: http://drupal.org/node/224333#drupal_add_js_options * TODO move this to a specific form theme function ? */ function simplenews_init() { drupal_add_css(drupal_get_path('module', 'simplenews') . '/simplenews.css'); } /** * Implementation of hook_menu(). * @todo Add $form to drupal_get_form() callback functions: http://drupal.org/node/224333#hook_forms_signature * @todo Review admin path due to D7's changed information architecture */ function simplenews_menu() { $items['admin/content/simplenews'] = array( 'title' => 'Newsletters', 'description' => 'List newsletters and newsletter sent status.', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_newsletter_issues'), 'access arguments' => array('administer newsletters'), 'file' => 'includes/simplenews.admin.inc', ); $items['admin/structure/simplenews'] = array( 'title' => 'Newsletters', 'description' => 'List, add and edit newsletter categories.', 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_categories'), 'access arguments' => array('administer newsletters'), 'file' => 'includes/simplenews.admin.inc', ); /* // TODO Don't need this? $items['admin/content/simplenews/list'] = array( 'title' => 'List newsletters', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); */ $items['admin/structure/simplenews/%simplenews_category/edit'] = array( 'title' => 'Newsletters', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_category_form', 3), 'access arguments' => array('administer newsletters'), 'file' => 'includes/simplenews.admin.inc', ); $items['admin/structure/simplenews/%simplenews_category/delete'] = array( 'title' => 'Newsletters', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_category_delete', 3), 'access arguments' => array('administer newsletters'), 'file' => 'includes/simplenews.admin.inc', ); $items['admin/structure/simplenews/add'] = array( 'title' => 'Add newsletter category', 'type' => MENU_LOCAL_ACTION, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_category_form'), 'access arguments' => array('administer newsletters'), 'file' => 'includes/simplenews.admin.inc', 'weight' => -9, ); $items['admin/content/simplenews/subscriptions/delete'] = array( 'title' => 'Delete', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_subscription_multiple_delete_confirm'), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.admin.inc', ); $items['admin/people/simplenews'] = array( 'title' => 'Newsletter subscriptions', 'description' => 'Newsletter subscription management.', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_subscription'), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.admin.inc', ); $items['admin/people/simplenews/list'] = array( 'title' => 'List', 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items['admin/people/simplenews/users/edit/%'] = array( 'title' => 'Subscriptions', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_admin_users_form', 5), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.subscription.inc', ); $items['admin/people/simplenews/import'] = array( 'title' => 'Mass subscribe', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_subscription_list_add'), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.admin.inc', 'weight' => 8, ); $items['admin/people/simplenews/unsubscribe'] = array( 'title' => 'Mass unsubscribe', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_subscription_list_remove'), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.admin.inc', 'weight' => 9, ); $items['admin/people/simplenews/export'] = array( 'title' => 'Export', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_subscription_list_export'), 'access arguments' => array('administer simplenews subscriptions'), 'file' => 'includes/simplenews.admin.inc', 'weight' => 10, ); // Configuration links. $items['admin/config/simplenews'] = array( 'title' => 'Simplenews', 'description' => 'Manage simplenews configuration.', 'position' => 'right', 'weight' => -10, 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('access administration pages'), 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['admin/config/simplenews/general'] = array( 'title' => 'General', 'description' => 'Simplenews vocabulary setting.', 'page callback' => 'drupal_get_form', 'weight' => -20, 'page arguments' => array('simplenews_admin_settings'), 'access arguments' => array('administer simplenews settings'), 'file' => 'includes/simplenews.admin.inc', 'file path' => drupal_get_path('module', 'simplenews'), ); $items['admin/config/simplenews/newsletter'] = array( 'title' => 'Newsletter', 'description' => 'Newsletter default settings and sender data.', 'page callback' => 'drupal_get_form', 'weight' => -15, 'page arguments' => array('simplenews_admin_settings_newsletter'), 'access arguments' => array('administer simplenews settings'), 'file' => 'includes/simplenews.admin.inc', 'file path' => drupal_get_path('module', 'simplenews'), ); $items['admin/config/simplenews/subscription'] = array( 'title' => 'Subscription', 'description' => 'Subscription settings, opt-in/out confirmation email text.', 'page callback' => 'drupal_get_form', 'weight' => -10, 'page arguments' => array('simplenews_admin_settings_subscription'), 'access arguments' => array('administer simplenews settings'), 'file' => 'includes/simplenews.admin.inc', 'file path' => drupal_get_path('module', 'simplenews'), ); $items['admin/config/simplenews/mail'] = array( 'title' => 'Send mail', 'description' => 'Send mail, cron and debug options.', 'page callback' => 'drupal_get_form', 'weight' => -5, 'page arguments' => array('simplenews_admin_settings_mail'), 'access arguments' => array('administer simplenews settings'), 'file' => 'includes/simplenews.admin.inc', 'file path' => drupal_get_path('module', 'simplenews'), ); $items['newsletter/confirm'] = array( 'title' => 'Confirm newsletter subscriptions', 'type' => MENU_CALLBACK, 'page callback' => 'simplenews_confirm_subscription', 'access arguments' => array('subscribe to newsletters'), 'file' => 'includes/simplenews.subscription.inc', ); $items['newsletter/subscriptions'] = array( 'title' => 'Manage newsletter subscriptions', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('simplenews_subscription_manager_form'), 'access arguments' => array('subscribe to newsletters'), 'file' => 'includes/simplenews.subscription.inc', ); $items['node/%node/simplenews'] = array( 'title' => 'Newsletter', 'type' => MENU_LOCAL_TASK, 'access callback' => 'simplenews_node_tab_access', 'access arguments' => array(1), 'page callback' => 'simplenews_node_tab_page', 'page arguments' => array(1), 'weight' => 2, ); return $items; } /** * Menu item access callback. * * Access for both newsletter and subscriber admins. */ function simplenews_newsletter_access() { return user_access('administer newsletters') || user_access('administer simplenews subscriptions'); } /** * Implements hook_node_type_delete. */ function simplenews_node_type_delete($info) { simplenews_get_content_types(TRUE); } /** * Implements hook_node_type_update. */ function simplenews_node_type_update($info) { simplenews_get_content_types(TRUE); } /** * Implements hook_node_view_alter. */ /* function simplenews_node_view_alter($build) { if (!simplenews_check_node_types(array($build['#node']->type))) { return; } } */ /** * Implements hook_node_view. */ function simplenews_node_view($node, $view_mode) { if (!simplenews_check_node_types($node->type)) { return; } //dpm($view_mode); // Replace the tokens when view mode is 'email_*'. if (strpos($view_mode, 'email_') === 0) { if (isset($build['body'])) { // TODO Where to perform the token replacement? //$build['body'] = token_replace($build['body'], array('node' => $node)); } if (isset($build['teaser'])) { // TODO Where to perform the token replacement? //$build['teaser'] = token_replace($build['teaser'], array('node' => $node)); } } } /** * Get simplenews category term values from a node object. */ function simplenews_get_term_values($node) { $category_field = simplenews_get_category_field($node->type); if (isset($node->{$category_field['field_name']}[$node->language])) { return $node->{$category_field['field_name']}[$node->language]; } return FALSE; } /** * Implements hook_node_validate. */ function simplenews_node_validate($node, $form) { if (!simplenews_check_node_types($node->type)) { return; } // Check if a taxonomy term field is present in the node. $field = simplenews_get_category_field($node->type); if (!$field) { form_set_error('', t('No newsletter category field is configured. Check ... @todo')); } else { // Check if a newsletter category term is selected. $terms = simplenews_get_term_values($node); if (!$terms) { form_set_error($field['field_name'], t('A newsletter category term is required.')); watchdog('simplenews', '@todo ... newsletter taxonomy is required, change settings.', array(), WATCHDOG_ERROR); } elseif (count($terms) > 1) { form_set_error($field['field_name'], t('Only one newsletter category term is allowed.')); watchdog('simplenews', '@todo ... newsletter taxonomy must be single value, change settings.', array(), WATCHDOG_ERROR); } } } /** * Implements hook_node_presave. */ function simplenews_node_presave($node) { if (!simplenews_check_node_types($node->type)) { return; } // Note that $node is NO full node object, see node_form_validate(). // Complete $node! $newsletter = simplenews_newsletter_load($node->nid); //$newsletter = simplenews_newsletter_load($node->nid, $node->vid); if (!$newsletter) { $newsletter = (object)simplenews_newsletter_defaults($node); } $node->simplenews = $newsletter; } /** * Implements hook_node_insert. * * // TODO simplenews_node_insert() and simplenews_node_update() have a lot in common. * // Solve this in a better way. */ function simplenews_node_insert($node) { if (!simplenews_check_node_types($node->type)) { return; } $newsletter = $node->simplenews; $newsletter->nid = $node->nid; $newsletter->vid = $node->vid; $newsletter->status = SIMPLENEWS_STATUS_SEND_NOT; $terms = simplenews_get_term_values($node); $newsletter->tid = $terms[0]['tid']; simplenews_newsletter_save($newsletter); } /** * Return default newsletter. */ function simplenews_newsletter_defaults($node = NULL) { $newsletter = array( 'nid' => NULL, 'vid' => NULL, 'tid' => NULL, 'status' => SIMPLENEWS_STATUS_SEND_NOT, 'sent_subscriber_count' => 0, ); if ($node) { $newsletter['nid'] = $node->nid; $newsletter['vid'] = $node->vid; $terms = simplenews_get_term_values($node); $newsletter['tid'] = $terms[0]['tid']; } return $newsletter; } /** * Implements hook_node_update. */ // TODO can we combine simplenews_node_update() and simplenews_node_insert() ? function simplenews_node_update($node) { if (!simplenews_check_node_types($node->type)) { return; } // TODO Check if this is an actual 'submit' action and not update as part of e.g. 'unpublish' on the node admin page $newsletter = $node->simplenews; if (!$newsletter) { $newsletter = (object)simplenews_newsletter_defaults($node); } simplenews_newsletter_save($newsletter); } /** * Implements hook_node_delete. */ function simplenews_node_delete($node) { if (!simplenews_check_node_types($node->type)) { return; } simplenews_newsletter_delete($node); drupal_set_message(t('Newsletter %title was deleted.', array('%title' => $node->title))); } /** * Implements hook_node_load. */ function simplenews_node_load($nodes, $types) { // We only support Simplenews enabled content types. if (!simplenews_check_node_types($types)) { return; } $newsletters = simplenews_newsletter_load_multiple(array_keys($nodes)); foreach ($nodes as $nid => $node) { // We can have multiple nodes where not all of them are simplenews enabled // content type. So we need to check for each individual node is it // simplenews enabled. if (!simplenews_check_node_types($node->type)) { continue; } // Make sure every $node has valid newsletter data as object $newsletter = array(); if (isset($newsletters[$nid])) { $newsletter = $newsletters[$nid]; } if (!$newsletter) { $newsletter = (object)simplenews_newsletter_defaults($node); } if ($nodes[$nid]->vid == $newsletter->vid) { $nodes[$nid]->simplenews = $newsletter; } } } /** * Check if content type(s) is enabled for use as Simplenews newsletter. * * @param $types * Array of content types or single content type string. * @return boolean * TRUE if at least one of $types is enabled for Simplenews. */ function simplenews_check_node_types($types) { if (!is_array($types)) { $types = array($types); } if ($sn_types = simplenews_get_content_types()) { foreach ($types as $type) { if (in_array($type, $sn_types)) { return TRUE; } } } return FALSE; } /** * Get all node types supported by Simplenews. * * @param $reset * TRUE: reset internal cache. * * @return * Array of node-types which can be used a simplenews newsletter. */ function simplenews_get_content_types($reset = FALSE) { static $simplenews_types; if (!isset($simplenews_types) || $reset) { foreach (node_type_get_types() as $name => $type) { if (variable_get('simplenews_content_type_' . $name, FALSE)) { $simplenews_types[] = $name; } } } return $simplenews_types; } /** * Add the taxonomy term field for the newsletter category. * * @param $type * A node type object. */ function simplenews_add_term_field($type) { $field = field_info_field('field_simplenews_term'); $instance = field_info_instance('node', 'field_simplenews_term', $type->type); if (empty($field)) { $field = array( 'field_name' => 'field_simplenews_term', 'type' => 'taxonomy_term_reference', 'cardinality' => 1, //'entity_types' => array(), 'translatable' => TRUE, 'settings' => array( 'allowed_values' => array( array( 'parent' => 0, 'vocabulary' => 'newsletter', ), ), ), ); $field = field_create_field($field); } if (empty($instance)) { $instance = array( 'label' => t('Newsletter category'), 'field_name' => 'field_simplenews_term', 'bundle' => $type->type, 'entity_type' => 'node', 'required' => TRUE, 'widget' => array( 'type' => 'options_buttons', ), //'settings' => array(), 'display' => array( 'default' => array( 'label' => 'hidden', 'type' => 'taxonomy_term_reference_link', ), 'teaser' => array( 'label' => 'hidden', 'type' => 'hidden', ), 'email_plain' => array( 'label' => 'hidden', 'type' => 'hidden', ), 'email_html' => array( 'label' => 'hidden', 'type' => 'hidden', ), 'email_textalt' => array( 'label' => 'hidden', 'type' => 'hidden', ), ), ); field_create_instance($instance); } } /** * Get the fieldname(s) from a content type that hold the newsletter category term. * * @param $bundle_name * The content type of which to return the field. * @return field definition * Field name of the field containing the newsletter category term. * FALSE if no field is selected. */ function simplenews_get_category_field($bundle_name) { $fields_info = field_info_fields(); $field_name = variable_get('simplenews_category_field', 'field_simplenews_term'); $instances = field_info_instances('node', $bundle_name); if (isset($instances[$field_name])) { return $fields_info[$field_name]; } else { return FALSE; } } /** * Implements hook_field_extra_fields(). */ /* function simplenews_field_extra_fields() { $extra = array(); foreach (node_type_get_types() as $type) { // if ($type->simplenews) { $extra['node'][$type->type] = array( 'title' => array( 'label' => t('Simplenews'), 'description' => t('Newsletter category.'), 'weight' => 5, ), ); // } } return $extra; } */ /** * Implements hook_form_FORM_ID_alter(). * * Add checkbox to the content type form to use the content type as newsletter. */ function simplenews_form_node_type_form_alter(&$form, $form_state) { // Add option to use content type as simplenews newsletter. $form['workflow']['simplenews_content_type'] = array( '#type' => 'checkbox', '#title' => t('Use as simplenews newsletter'), '#default_value' => variable_get('simplenews_content_type_' . $form['#node_type']->type, 0), ); } /** * Implements hook_form_FORM_ID_alter(). * * Add a warning message to taxonomy term delete form. * * @todo move this function to a .inc file. */ function simplenews_form_taxonomy_form_term_alter(&$form, $form_state) { if (isset($form_state['confirm_delete']) && $form_state['confirm_delete']) { if ($form['#term']->vid == variable_get('simplenews_vid', 0)) { $category = simplenews_category_load($form['#term']->tid); $form['description']['#markup'] = '
' . t('This taxonomy term is part of simplenews newsletter category %category_name. Deleting this term will delete the newsletter category and all subscriptions to category %category_name. This action cannot be undone.', array('%category_name' => $category->name)) . '
' . $form['description']['#markup']; } } } /** * Implements hook_taxonomy_term_delete(). * * Delete simplenews category if taxonomy term is delete. * * @todo move this function to a .inc file. */ function simplenews_taxonomy_term_delete($term) { // A simplenews newsletter category can not exist without the associated // taxonomy term. So we delete the category. simplenews_category_delete() // will also delete the subscriptions to the category. if ($term->vid == variable_get('simplenews_vid', 0)) { simplenews_category_delete($term->tid); } } /** * Implements hook_form_alter(). */ function simplenews_form_alter(&$form, &$form_state, $form_id) { // Add Simplenews settings to simplenews newsletter node form. if (!empty($form['#node_edit_form'])) { if (in_array($form['type']['#value'], simplenews_get_content_types())) { _simplenews_node_form($form, $form_state); } } } /** * @todo */ function _simplenews_node_form(&$form, $form_state) { $form['simplenews_token_help'] = array( '#title' => t('Replacement patterns'), '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('These tokens can be used in all text fields and will be replaced on-screen and in the email. Note that receiver-* tokens are not suitable for on-screen use.'), ); $form['simplenews_token_help']['help'] = array( '#markup' => _simplenews_get_token_info(array('simplenews-newsletter', 'simplenews-category', 'site')), ); } /** * Implements hook_entity_info_alter(). */ function simplenews_entity_info_alter(&$info) { // Add the 'Plain', 'HTML' and 'Text alternative' view mode for nodes in email. $info['node']['view modes'] += array( 'email_plain' => array( 'label' => t('Email: Plain'), 'custom settings' => FALSE, ), 'email_html' => array( 'label' => t('Email: HTML'), 'custom settings' => FALSE, ), 'email_textalt' => array( 'label' => t('Email: HTML text alternative'), 'custom settings' => FALSE, ), ); } /** * Implements hook_field_ui_view_modes_tabs(). */ function simplenews_field_ui_view_modes_tabs() { $modes = array( 'email' => array( 'title' => t('Email'), 'view modes' => array('email_plain', 'email_html', 'email_textalt'), ), ); return $modes; } /** * Implementation of hook_cron(). */ function simplenews_cron() { module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); simplenews_mail_spool(); simplenews_clear_spool(); // Update sent status for newsletter admin panel. simplenews_send_status_update(); } /** * Implements hook_simplenews_category_delete(). * * For the time being we use mailing list and category in sync. * Deletes the newsletter list when category is deleted. */ function simplenews_simplenews_category_delete($category) { // Delete subscriptions simplenews_subscription_delete(array('tid' => $category->tid)); drupal_set_message(t('All subscriptions to newsletter %newsletter have been deleted.', array('%newsletter' => $category->name))); // Delete subscription block db_delete('block') ->condition('module', 'simplenews') ->condition('delta', $category->tid) ->execute(); } /** * Implements hook_form_FORMID_alter(). * * Add simplenews subscription fields to user register form. * @todo: mode this function to another place in the module. */ function simplenews_form_user_register_form_alter(&$form, &$form_state) { $options = $default_value = $hidden = array(); // Determine the lists to which a user can choose to subscribe. // Determine to which other list a user is automatically subscribed. foreach (simplenews_get_mailing_lists(TRUE) as $list) { $subscribe_new_account = $list->new_account; $opt_inout_method = $list->opt_inout; if (($subscribe_new_account == 'on' || $subscribe_new_account == 'off') && ($opt_inout_method == 'single' || $opt_inout_method == 'double')) { $options[$list->tid] = check_plain($list->name); $default_value[$list->tid] = $subscribe_new_account == 'on'; } else { if ($subscribe_new_account == 'silent' || ($subscribe_new_account == 'on' && $opt_inout_method == SIMPLENEWS_OPT_INOUT_HIDDEN)) { $hidden[] = $list->tid; } } } if (count($options)) { // TODO Change this text: use less words; $form['simplenews'] = array( '#type' => 'fieldset', '#description' => t('Select the newsletter(s) to which you wish to subscribe.'), '#weight' => 5, ); // TODO Change 'newsletters' to 'list'. $form['simplenews']['newsletters'] = array( '#type' => 'checkboxes', '#options' => $options, '#default_value' => $default_value, ); } if (count($hidden)) { $form['simplenews_hidden'] = array( '#type' => 'hidden', '#value' => implode(',', $hidden), ); } } /** * Implements hook_user_insert. * * Update uid and preferred language when the new account was already subscribed. */ function simplenews_user_insert(&$edit, $account, $category) { // Use the email address to check if new account is already subscribed. $subscriber = new stdClass(); $subscriber->mail = $edit['mail']; $subscription = simplenews_get_subscription($subscriber); // If the user is subscribed, we update the subscriber with uid and language. if ($subscription->snid) { // TODO Write a function to save/update a subscription and use it here. $subscriber->uid = $edit['uid']; $subscriber->language = $edit['language']; $subscriber->activated = 1; $subscriber->snid = $subscription->snid; simplenews_subscriber_save($subscriber); } // Process subscription check boxes. if (isset($edit['newsletters'])) { $nl_tids = array_keys(array_filter($edit['newsletters'])); $newsletters = simplenews_categories_load_multiple($nl_tids, array('show_all' => TRUE)); foreach ($newsletters as $newsletter) { simplenews_subscribe_user($account->mail, $newsletter->tid, FALSE, 'website', $edit['language']); drupal_set_message(t('You have been subscribed to %newsletter.', array('%newsletter' => $newsletter->name))); } } // set inactive if not created by an administrator. this needs a cleaner API. if (!user_access('administer users')) { // this user will be activated on first login (see simplenews_user_login) db_query(" UPDATE {simplenews_subscriber} SET activated = :a WHERE uid = :uid", array( ':a' => 0, ':uid' => $account->uid, ) ); } // $edit['newsletter'] contains newsletters the user should be subscribed to. // But we leave this untouched because we only subscribe a new account // after account confirmation. In the meantime the content of $edit['newsletter'] // will be stored in $edit['data'] by user module. } /** * Implements hook_user_login. * * Subscribe user to a newsletter as per registration form. * @todo Check if $account->data is cleaned up by this function. */ function simplenews_user_login(&$edit, $account) { // The user registration form may contain (hidden) form element to // subscribe to newsletters. Data of these elements are stored in // the $account->data variable. // We subscribe the user according to the (hidden) form elements. // Subscriptions of users that did sign up by themselves have to be // activated first at their first login (-> account::access = 0) if ($account->access == 0){ db_query(" UPDATE {simplenews_subscriber} SET activated = :a WHERE uid = :uid", array( ':a' => 1, ':uid' => $account->uid, ) ); } if (isset($account->data)) { $data = $account->data; $processed = FALSE; // Process hidden (automatic) subscriptions. if (isset($data['simplenews_hidden'])) { foreach (explode(',', $data['simplenews_hidden']) as $tid) { simplenews_subscribe_user($account->mail, $tid, FALSE, 'automatically'); } $data['simplenews_hidden'] = NULL; $processed = TRUE; } // Process subscription check boxes. if (isset($data['newsletters'])) { foreach (array_keys(array_filter($data['newsletters'])) as $tid) { simplenews_subscribe_user($account->mail, $tid, FALSE, 'website'); $newsletters = simplenews_get_mailing_lists(TRUE); drupal_set_message(t('You have been subscribed to %newsletter.', array('%newsletter' => $newsletters[$tid]->name))); } $data['newsletters'] = NULL; $processed = TRUE; } // If subscription data is processed, we update the user data to remove it. if ($processed) { user_save($account, $data); } } } /** * Implements hook_user_presave. * * User data (mail, status, language) is synchronized with subscriber. * This function handles existing user account, simplenews_user_insert takes * care of new accounts. * @see simplenews_user_insert */ function simplenews_user_presave(&$edit, $account, $category) { switch ($category) { case 'account': // We only process existing accounts. if ($account->uid) { $subscription = simplenews_get_subscription((object)array('uid' => $account->uid)); // Only process existing subscriptions. if ($subscription->snid) { // Update mail, status and language if they are changed. // TODO convert this code to simplenews_subscriber_save(). $fields = array(); if (isset($edit['mail'])) { $fields['mail'] = $edit['mail']; } if (isset($edit['status']) && variable_get('simplenews_sync_account', TRUE)) { $fields['activated'] = $edit['status']; } if (isset($edit['language'])) { $fields['language'] = $edit['language']; } if (!empty($fields)) { $query = db_update('simplenews_subscriber') ->condition('snid', $subscription->snid) ->fields($fields) ->execute(); } } } break; case 'simplenews': if (user_access('subscribe to newsletters')) { foreach (simplenews_get_mailing_lists() as $item) { $tid = $item->tid; if ($edit['newsletter-' . $tid] == 1) { simplenews_subscribe_user($account->mail, $tid, FALSE, 'website'); } else { simplenews_unsubscribe_user($account->mail, $tid, FALSE, 'website'); } } } break; } } /** * Implements hook_user_cancel. */ function simplenews_user_cancel($edit, $account, $method) { // Deactivate subscriber when account is disabled via cancel user. if ($account) { db_query(" UPDATE {simplenews_subscriber} SET activated = :a WHERE uid = :uid", array( ':a' => 0, ':uid' => $account->uid, ) ); } } /** * Implements hook_user_delete. */ function simplenews_user_delete($edit, $account, $method) { // Delete subscription and all newsletter subscriptions when account is removed. // We don't use simplenews_get_subscription() here because the user is already // deleted from the {user} table. $subscribers = simplenews_subscribers_load_multiple(array(), array('mail' => $account->mail)); $subscriber = $subscribers ? reset($subscribers) : FALSE; if ($subscriber) { simplenews_subscription_delete(array('snid' => $subscriber->snid)); simplenews_subscriber_delete($subscriber); } } /** * Implements hook_user_categories. */ function simplenews_user_categories() { $output[] = array( 'name' => 'simplenews', 'title' => t('Newsletters'), 'weight' => 10, 'access callback' => 'user_access', // TODO Need custom access control to restrict users own for only? 'access arguments' => array('subscribe to newsletters'), ); return $output; } /** * Implements hook_form_FORMID_alter(). * * Add simplenews subscription management form to account category 'Newsletters' */ function simplenews_form_user_profile_form_alter(&$form, &$form_state) { if ($form['#user_category'] == 'simplenews') { // TODO Can users access each others form? $subscription = simplenews_get_subscription((object)$form['#user']); $form += _simplenews_subscription_manager_form($subscription); $form['subscriptions']['#title'] = t('Newsletter subscriptions'); unset($form['update'], $form['subscriptions']['mail']); } } /** * Implements hook_user_view. * * @todo Check if hidden newsletters are not listed. */ function simplenews_user_view($account, $build_mode) { global $user; if ($user->uid == $account->uid || user_access('administer users')) { $account->content['simplenews'] = array( '#type' => 'user_profile_category', '#title' => t('Newsletters'), ); // Collect newsletter to which the current user is subscribed. // 'hidden' newsletters are not listed. $newsletters = simplenews_get_mailing_lists(); $subscription = simplenews_get_subscription($account); foreach ($newsletters as $newsletter) { if (isset($subscription->newsletter_subscription[$newsletter->tid]) && $subscription->newsletter_subscription[$newsletter->tid]->status == TRUE) { $links[] = l($newsletter->name, 'taxonomy/term/' . $newsletter->tid); } } if (isset($links)) { // TODO replace with theme('links', $links) to form a list of newsletters? $links = implode(', ', $links); } else { $links = t('None'); } // When a user has no permission to subscribe and is not subscribed // we do not display the 'no subscriptions' message. if (user_access('subscribe to newsletters') || $links != t('None')) { $account->content['simplenews']['subscriptions'] = array( '#type' => 'user_profile_item', '#title' => t('Subscribed to'), '#markup' => $links, ); } if (user_access('subscribe to newsletters')) { $account->content['simplenews']['my_newsletters'] = array( '#type' => 'user_profile_item', '#title' => '', '#markup' => t('Manage subscriptions', array('!url' => url('user/' . $account->uid . '/edit/simplenews'))), ); } } } /** * Implementation of hook_block(). * @todo break-up by $op: http://drupal.org/node/224333#remove_op */ function simplenews_block_OLD($op = 'list', $delta = 0, $edit = array()) { } /** * Implements hook_block_info(). */ function simplenews_block_info() { $blocks = array(); // Only list a block if the newsletter is not 'hidden' and marked to provide a block. foreach (simplenews_categories_load_multiple(array(), array('block' => '1', 'show_all' => FALSE)) as $category) { //TODO: 1. without form -> by role; 2. with form -> user caching with refresh on subscribe/unsubscribe (option as setting) or no caching $blocks[$category->tid] = array( 'info' => t('Newsletter: @title', array('@title' => $category->name)), // TODO Use block's own settings? 'cache' => variable_get('simplenews_block_f_' . $category->tid, 1) ? DRUPAL_NO_CACHE : DRUPAL_CACHE_PER_ROLE, ); } return $blocks; } /** * Implements hook_block_configure(). */ function simplenews_block_configure($delta = '') { $form['simplenews_block_' . $delta]['simplenews_block_m_' . $delta] = array( '#type' => 'textfield', '#title' => t('Block message'), '#size' => 60, '#maxlength' => 128, '#default_value' => variable_get('simplenews_block_m_' . $delta, t('Stay informed on our latest news!')), ); $form['simplenews_block_' . $delta]['simplenews_block_f_' . $delta] = array( '#type' => 'radios', '#title' => t('Subscription interface'), '#options' => array('1' => t('Subscription form'), '0' => t('Link to form')), '#description' => t("Note: this requires permission 'subscribe to newsletters'."), '#default_value' => variable_get('simplenews_block_f_' . $delta, 1), ); $form['simplenews_block_' . $delta]['simplenews_block_l_' . $delta] = array( '#type' => 'checkbox', '#title' => t('Display link to previous issues'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_l_' . $delta, 1), ); $form['simplenews_block_' . $delta]['simplenews_block_i_status_'. $delta] = array( '#type' => 'checkbox', '#title' => t('Display previous issues'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_i_status_'. $delta, 0), ); $form['simplenews_block_' . $delta]['simplenews_block_i_' . $delta] = array( '#type' => 'select', '#title' => t('Number of issues to display'), '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), '#default_value' => variable_get('simplenews_block_i_' . $delta, 5), ); $form['simplenews_block_' . $delta]['simplenews_block_r_' . $delta] = array( '#type' => 'checkbox', '#title' => t('Display RSS-feed icon'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_r_' . $delta, 1), ); return $form; } /** * Implements hook_block_save(). */ function simplenews_block_save($delta = '', $edit = array()) { variable_set('simplenews_block_m_' . $delta, $edit['simplenews_block_m_' . $delta]); variable_set('simplenews_block_f_' . $delta, $edit['simplenews_block_f_' . $delta]); variable_set('simplenews_block_l_' . $delta, $edit['simplenews_block_l_' . $delta]); variable_set('simplenews_block_i_status_' . $delta, $edit['simplenews_block_i_status_' . $delta]); variable_set('simplenews_block_i_' . $delta, $edit['simplenews_block_i_' . $delta]); variable_set('simplenews_block_r_' . $delta, $edit['simplenews_block_r_' . $delta]); } /** * Implements hook_block_view(). */ function simplenews_block_view($delta = '') { global $language; $newsletters = simplenews_get_mailing_lists(); // Only display a block if $delta is a valid newsletter term id. if (in_array($delta, array_keys($newsletters))) { // $delta is validated, the block can be displayed. $block = array( 'subject' => check_plain($newsletters[$delta]->name), 'content' => theme(array('simplenews_block__' . $delta, 'simplenews_block'), array('tid' => $delta)), ); return $block; } } /** * Implementation of hook_forms(). * * All form blocks are build using simplenews_block_form(). * hook_forms() is required to provide unique form id for each block form. */ function simplenews_forms($form_id, $args) { $forms = array(); foreach (simplenews_get_mailing_lists(TRUE) as $newsletter) { $forms['simplenews_block_form_' . $newsletter->tid] = array( 'callback' => 'simplenews_block_form', 'callback arguments' => array($newsletter->tid), ); } return $forms; } /** * Load a user or creates a dummy anonymous user. * * @return account * object ( * mail, email address * uid, uid or 0 for anonymous * ) * @todo Rewrite to use the new user_load(): http://drupal.org/node/224333#user_load_multiple */ function _simplenews_user_load($mail) { $account = user_load_by_mail($mail); if ($account === FALSE) { // Construct anonymous user since we don't have a user that matches that e-mail. $account = new stdClass(); $account->uid = 0; $account->mail = $mail; } return $account; } /** * Subscribe a user to a newsletter or send a confirmation mail. * * The $confirm parameter determines the action: * FALSE = The user is subscribed * TRUE = User receives an email to verify the address and complete the subscription * A new subscription account is created when the user is subscribed to the first newsletter * * @param string $mail * The email address to subscribe to the newsletter. * @param integer $tid * The term ID of the newsletter. * @param boolean $confirm * TRUE = send confirmation mail; FALSE = subscribe immediate to the newsletter * @param string $preferred_language * The language code (i.e. 'en', 'nl') of the user preferred language. * Use '' for the site default language. * Use NULL for the language of the current page. * @param string $source * Indication for source of subscription. Simplenews uses these sources: * website: via any website form (with or without confirmation email) * mass subscribe: mass admin UI * mass unsubscribe: mass admin UI * action: Drupal actions */ function simplenews_subscribe_user($mail, $tid, $confirm = TRUE, $source = 'unknown', $preferred_language = NULL) { global $language; // Get current subscriptions if any. $account = (object) array( 'mail' => $mail, ); $subscriber = simplenews_get_subscription($account); // If user is not subscribed to ANY newsletter, create a subscription account if ($subscriber->snid == 0) { // To subscribe a user: // - Fetch the users uid. // - Determine the user preferred language. // - Add the user to the database. // - Get the full subscription object based on the mail address. // Note that step 3 gets subscription data based on mail address because the uid can be 0 (for anonymous users) $account = _simplenews_user_load($mail); // If the site is multilingual: // - Anonymous users are subscribed with their preferred language // equal to the language of the current page. // - Registered users will be subscribed with their default language as // set in their account settings. // By default the preferred language is not set. if (variable_get('language_count', 1) > 1) { if ($account->uid) { $preferred_language = $account->language; } else { $preferred_language = isset($preferred_language) ? $preferred_language : $language->language; } } else { $preferred_language = ''; } $subscriber->mail = $mail; $subscriber->uid = $account->uid; $subscriber->language = $preferred_language; $subscriber->activated = 1; simplenews_subscriber_save($subscriber); } if ($confirm) { // Send confirmation email to user to complete subscription or to tell // them that he or she is already subscribed. // Confirmation mail is in the user preferred language which is by default the language_default(). module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); $params['from'] = _simplenews_set_from(); $params['context']['category'] = simplenews_category_load($tid); $params['context']['account'] = $subscriber; drupal_mail('simplenews', 'subscribe', $mail, $subscriber->language, $params, $params['from']['address']); } elseif (!isset($subscriber->tids[$tid])) { // Subscribe the user if not already subscribed. // TODO rewrite if subscription object is loaded in $subscriber->tids[$tid] // TODO See simplenews_get_subscription() $subscription = new stdClass(); $subscription->snid = $subscriber->snid; $subscription->tid = $tid; $subscription->status = SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED; $subscription->timestamp = REQUEST_TIME; $subscription->source = $source; simplenews_subscription_save($subscription); $subscriber->tids[$tid] = $tid; // Execute simplenews subscribe trigger. simplenews_call_actions('subscribe', $subscriber); } return TRUE; } /** * Unsubscribe a user from a mailing list or send a confirmation mail. * * The $confirm parameter determines the action: * FALSE = The user is unsubscribed * TRUE = User receives an email to verify the address and complete the subscription cancellation * * @param string $mail The email address to unsubscribe from the mailing list. * @param integer $tid The term ID of the list. * @param boolean $confirm TRUE = send confirmation mail; FALSE = unsubscribe immediate from the list * @param string $source * Indication of the unsubscribe source. Simplenews uses these sources: * website: via any website form (with or without confirmation email) * mass subscribe: mass admin UI * mass unsubscribe: mass admin UI * action: Drupal actions */ function simplenews_unsubscribe_user($mail, $tid, $confirm = TRUE, $source = 'unknown') { $account = (object) array( 'mail' => $mail, ); $subscriber = simplenews_get_subscription($account); // The unlikely case that a user is unsubscribed from a non existing mailing list is logged if (!$category = simplenews_category_load($tid)) { watchdog('simplenews', 'Attempt to unsubscribe from non existing mailing list ID %id', array('%id' => $tid), WATCHDOG_ERROR); return FALSE; } if ($confirm) { // Send confirmation email to user to complete unsubscriber // or to tell them that he or she is not subscribed // Confirmation mail is in the user preferred language. module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); $params['from'] = _simplenews_set_from(); $params['context']['category'] = $category; $params['context']['account'] = $subscriber; drupal_mail('simplenews', 'unsubscribe', $mail, $subscriber->language, $params, $params['from']['address']); } elseif (isset($subscriber->tids[$tid])) { // Unsubscribe the user from the mailing list. // TODO rewrite if subscription object is loaded in $subscriber->tids[$tid] // TODO See simplenews_get_subscription() $subscription = new stdClass(); $subscription->snid = $subscriber->snid; $subscription->tid = $tid; $subscription->status = SIMPLENEWS_SUBSCRIPTION_STATUS_UNSUBSCRIBED; $subscription->timestamp = REQUEST_TIME; $subscription->source = $source; simplenews_subscription_save($subscription); $subscriber->tids[$tid] = $tid; // Execute simplenews unsubscribe trigger simplenews_call_actions('unsubscribe', $subscriber); } return TRUE; } /** * Check if the email address is subscribed to the given mailing list. * * @param string $mail email address * @param integer $tid mailing list id * * @return boolean TRUE = email address is subscribed to given mailing list id */ // TODO only return active subscriptions. // TODO This function can do without caching. simplenews_get_subscription() should cache. function simplenews_user_is_subscribed($mail, $tid, $reset = FALSE) { static $subscribed = array(); if ($reset) { $subscribed = array(); } if (!isset($subscribed[$mail][$tid])) { $subscription = simplenews_get_subscription((object)array('mail' => $mail)); $subscribed[$mail][$tid] = isset($subscription->tids[$tid]); } return $subscribed[$mail][$tid]; } /** * Return a default subscriber object. */ function simplenews_subscriber_defaults($account = NULL) { $subscriber = new stdClass(); $subscriber->snid = NULL; $subscriber->name = ''; $subscriber->activated = 0; $subscriber->uid = NULL; $subscriber->mail = NULL; $subscriber->language = language_default()->language; $subscriber->tids = array(); $subscriber->newsletter_subscription = array(); if ($account) { $subscriber->uid = $account->uid ? $account->uid : NULL; $subscriber->mail = $account->mail ? $account->mail : NULL; $subscriber->language = user_preferred_language($account)->language; } return $subscriber; } /** * Get the subscription object for the given account. * * Account is defined by (in order of preference) snid, email address or uid. * If the account is not subscribed a default subscription object is returned * containing all available account info. * * @param object $account account details. Containing one or none of these items: * object( * snid : subscription id * mail : email address * uid : user id * ) * * @return subscription object * object( * snid : subscription id. 0 if account is not subscribed * tids : array of tid's of active subscriptions * newsletter_subscriptions : array of newsletter subscription objects * uid : user id. 0 if account is anonymous user * mail : user email address. empty if email is unknown * name : always empty. Added for compatibility with user account object * language : language object. User preferred or default language * ) * * TODO: Consider changing the subscription object: * subscribed : array of subscription objects of newsletters the user is subscribed to * unsubscribed : array of subscription objects of newsletters the user is unsubscribed from * Both arrays have newsletter ID (tid) as key. * Drop 'tids' and 'newsletter_subscriptions' * TODO: Cache the $subscription * TODO: Combine the two queries into one. * TODO: Load subscription object into tids[]. */ function simplenews_get_subscription($account) { // Load subscription data based on available account information // NOTE that the order of checking for snid, mail and uid is critical. mail must be checked *before* uid. See simplenews_subscribe_user() $query = db_select('simplenews_subscriber', 's'); $query->leftJoin('users', 'u', 'u.uid = s.uid'); $query->fields('s') ->fields('u', array('name')); if (isset($account->snid)) { $query->condition('s.snid', $account->snid); } elseif (isset($account->mail)) { $query->where('LOWER(s.mail) = LOWER(:mail)', array(':mail' => $account->mail)); } elseif (isset($account->uid) && $account->uid > 0) { $query->condition('s.uid', $account->uid); } else { // No conditions applied! return simplenews_subscriber_defaults($account); } $query->range(0, 1); $result = $query->execute(); if ($result->rowCount()) { $subscription = $result->fetch(); $newsletter_subscriptions = db_query("SELECT * FROM {simplenews_subscription} WHERE snid = :snid", array(':snid' => $subscription->snid)); $subscription->tids = array(); foreach ($newsletter_subscriptions as $newsletter_subscription) { if ($newsletter_subscription->status == SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED) { $subscription->tids[$newsletter_subscription->tid] = $newsletter_subscription->tid; } $subscription->newsletter_subscription[$newsletter_subscription->tid] = $newsletter_subscription; } $subscription->language = user_preferred_language($subscription)->language; } else { // Account is unknown in subscription table. Create default subscription object return simplenews_subscriber_defaults($account); } return $subscription; } /** * TODO */ function simplenews_get_subscriptions_by_list($tid) { $subscriptions = array(); $query = db_select('simplenews_subscriber', 'sn'); $query->innerJoin('simplenews_subscription', 'ss', 'ss.snid = sn.snid'); $query->fields('sn', array('mail', 'uid', 'language', 'snid')) ->fields('ss', array('status')) ->condition('sn.activated', 1) ->condition('ss.tid', $tid) ->condition('ss.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED); foreach ($query->execute() as $subscriber) { $subscriptions[$subscriber->mail] = $subscriber; } return $subscriptions; } /** * Update subscriber objects in the database. * * @param $conditions * Array of selection conditions. e.g. array('tid' => 5, 'snid' => 12). * @param $data * Associative array of database fields to be updated. */ //TODO Replace with simplenews_subscription_save() ? function simplenews_subscription_update($conditions = array(), $data) { $query = db_update('simplenews_subscription'); foreach ($conditions as $key => $condition) { $query->condition($key, $condition); } $query->fields($data); $query->execute(); } /** * TODO */ function simplenews_subscription_save($subscription) { db_merge('simplenews_subscription') ->key(array('tid' => $subscription->tid)) ->key(array('snid' => $subscription->snid)) ->fields(array( 'snid' => $subscription->snid, 'tid' => $subscription->tid, 'status' => $subscription->status, 'timestamp' => $subscription->timestamp, 'source' => $subscription->source, )) ->execute(); } /** * Delete subscriptions. * * @param $conditions * Associative array of conditions matching the records to be delete. * Example: array('tid' => 5, 'snid' => 12) * Delete the subscription of subscriber 12 to newsletter tid 5. */ function simplenews_subscription_delete($conditions = array()) { $query = db_delete('simplenews_subscription'); foreach ($conditions as $key => $condition) { $query->condition($key, $condition); } $query->execute(); } /** * Get a simplenews newsletter subscriber object. * * @param $snid * Simplenews subscriber ID. * @return * Newsletter subscriber object. * FALSE if subscriber does not exist. */ function simplenews_subscriber_load($snid, $reset = FALSE) { $subscribers = simplenews_subscribers_load_multiple(array($snid), $reset); return $subscribers ? reset($subscribers) : FALSE; } /** * TODO */ function simplenews_subscribers_load_multiple($snids = array(), $conditions = array(), $reset = FALSE) { static $subscribers; // Only cache if we load all records from the database. // TODO Caching could be improved. if ($subscribers || $snids || $conditions || $reset) { $subscribers = array(); $query = db_select('simplenews_subscriber', 'ss') ->fields('ss'); if ($snids) { $query->condition('snid', $snids); } if ($conditions) { foreach ($conditions as $key => $condition) { $query->condition($key, $condition); } } $result = $query->execute(); foreach ($result as $subscriber) { $subscribers[$subscriber->snid] = $subscriber; } } return $subscribers; } /** * Store subscriber object in the database. */ function simplenews_subscriber_save(&$subscriber) { if (!empty($subscriber->snid)) { db_update('simplenews_subscriber') ->condition('snid', $subscriber->snid) ->fields(array( 'snid' => $subscriber->snid, 'activated' => $subscriber->activated, 'mail' => $subscriber->mail, 'uid' => $subscriber->uid, 'language' => $subscriber->language, )) ->execute(); module_invoke_all('simplenews_subscriber_update', $subscriber); } elseif (empty($subscriber->snid)) { $query = db_insert('simplenews_subscriber') ->fields(array( 'activated' => $subscriber->activated, 'mail' => $subscriber->mail, 'uid' => $subscriber->uid, 'language' => $subscriber->language, )); $last_insert_id = $query->execute(); if ($last_insert_id !== FALSE) { $subscriber->snid = $last_insert_id; module_invoke_all('simplenews_subscriber_insert', $subscriber); } } } /** * Delete subscriber from the database. * * @param $snid * Simplenews subscriber object or subscriber ID. */ function simplenews_subscriber_delete($subscriber) { if (!is_object($subscriber)) { } if ($subscriber) { db_delete('simplenews_subscriber') ->condition('snid', $subscriber->snid) ->execute(); module_invoke_all('simplenews_subscriber_delete', $category); } } /** * Build subscription manager form. * * @param object $subscription subscription object */ function _simplenews_subscription_manager_form($subscription) { $form = array(); $options = array(); $default_value = array(); global $language; $form['subscriptions'] = array( '#type' => 'fieldset', '#description' => t('Select the newsletter(s) to which you want to subscribe or unsubscribe.'), ); // Get newsletters for subscription form checkboxes. // Newsletters with opt-in/out method 'hidden' will not be listed. foreach (simplenews_get_mailing_lists() as $newsletter) { $form['subscriptions']['newsletter-' . $newsletter->tid] = array( '#type' => 'checkbox', '#title' => check_plain($newsletter->name), '#description' => $newsletter->description, '#default_value' => in_array($newsletter->tid, $subscription->tids), ); } // If current user is logged in, just display email. // Anonymous users see an email box and will receive confirmations if ($subscription->mail) { $form['subscriptions']['#title'] = t('Subscriptions for %mail', array('%mail' => $subscription->mail)); $form['subscriptions']['mail'] = array( '#type' => 'value', '#value' => $subscription->mail, ); $form['update'] = array( '#type' => 'submit', '#value' => t('Update'), '#weight' => 20, ); } else { $form['subscriptions']['#title'] = t('Manage your newsletter subscriptions'); $form['subscriptions']['mail'] = array( '#type' => 'textfield', '#title' => t('Email'), '#size' => 20, '#maxlength' => 128, '#weight' => 10, '#required' => TRUE, ); $form['subscribe'] = array( '#type' => 'submit', '#value' => t('Subscribe'), '#weight' => 20, ); $form['unsubscribe'] = array( '#type' => 'submit', '#value' => t('Unsubscribe'), '#weight' => 30, ); } return $form; } /** * Create a list of recent newsletters. * * @param integer $tid * Newsletter category id * @param integer $count * Number of newsletters * @todo Replace 'class' string by array: http://drupal.org/node/224333#class_attribute_array * TODO Replace this list by a View. */ function simplenews_recent_newsletters($tid, $count = 5) { $titles = ''; if (!empty($nids)) { $query = db_select('node', 'n'); $query->innerJoin('simplenews_newsletter', 'sn', 'n.nid = sn.nid'); $query->fields('n', array('nid', 'title')) ->condition('n.nid', $nids) ->condition('sn.tid', $tid) ->condition('n.status', NODE_PUBLISHED) ->condition('sn.status', SIMPLENEWS_STATUS_SEND_NOT, '<>') ->orderBy('n.created', 'DESC') ->range(0, $count); $titles = array(); foreach ($query->execute() as $item) { $titles[$item->nid]['data'] = l($item->title, 'node/' . $item->nid); } } return $titles; } /** * Newsletter (un)subscription form for authenticated and anonymous users. * * @param $tid term id of selected newsletter. * * @see simplenews_block_form_validate() * @see simplenews_block_form_submit() * @todo Add $form to drupal_get_form() callback functions: http://drupal.org/node/224333#hook_forms_signature */ function simplenews_block_form($form, &$form_state, $tid) { global $user; $form = array(); if ($user->uid) { if ($temp = simplenews_user_is_subscribed($user->mail, $tid)) { $submit_text = t('Unsubscribe'); $form['action'] = array( '#type' => 'value', '#value' => 'unsubscribe', '#attributes' => array('class' => 'simplenews-unsubscribe'), ); } else { $submit_text = t('Subscribe'); $form['action'] = array( '#type' => 'value', '#value' => 'subscribe', '#attributes' => array('class' => 'simplenews-subscribe'), ); } // TODO display the label inline with the user name. $form['display_mail'] = array( '#type' => 'item', '#title' => t('User'), '#markup' => check_plain($user->name), ); $form['mail'] = array( '#type' => 'value', '#value' => $user->mail, ); } else { $form['mail'] = array( '#type' => 'textfield', '#title' => t('Email'), '#size' => 20, '#maxlength' => 128, '#required' => TRUE, ); $submit_text = t('Subscribe'); $form['action'] = array( '#type' => 'value', '#value' => 'subscribe', '#attributes' => array('class' => 'simplenews-subscribe'), ); } // All block forms use the same validate and submit function. // #tid carries the tid for processing of the right newsletter issue term. $form['#tid'] = $tid; $form['#validate'][] = 'simplenews_block_form_validate'; $form['#submit'][] = 'simplenews_block_form_submit'; $form['submit'] = array( '#type' => 'submit', '#value' => isset($submit_text) ? $submit_text : t('Save'), ); return $form; } function simplenews_block_form_validate($form, &$form_state) { if (!valid_email_address($form_state['values']['mail'])) { form_set_error('mail', t("The email address you supplied is not valid.")); } } function simplenews_block_form_submit($form, &$form_state) { global $user; $tid = $form['#tid']; $account = _simplenews_user_load($form_state['values']['mail']); // If email belongs to the current registered user, don't send confirmation. // Other addresses receive a confirmation if double opt-in is selected. if ($account->uid && $account->uid == $user->uid) { $confirm = FALSE; } else { $confirm = variable_get('simplenews_opt_inout_' . $tid, 'double') == 'double'; } switch ($form_state['values']['action']) { case 'subscribe': simplenews_subscribe_user($form_state['values']['mail'], $tid, $confirm, 'website'); if ($confirm) { drupal_set_message(t('You will receive a confirmation email shortly containing further instructions on how to complete your subscription.')); } else { drupal_set_message(t('You have been subscribed.')); } break; case 'unsubscribe': simplenews_unsubscribe_user($form_state['values']['mail'], $tid, $confirm, 'website'); if ($confirm) { drupal_set_message(t('You will receive a confirmation email shortly containing further instructions on how to cancel your subscription.')); } else { drupal_set_message(t('Your subscription has been cancelled.')); } break; } } /** * Implementation of hook_mail(). * * Send simplenews mails using drupal mail API * @see drupal_mail() * * @param $key: node | test | subscribe | unsubscribe * @param array $message message array * [from] * [headers][From] * [language] : preferred message language * @param array $params parameter array * [context][node] : node object of message to be sent * [context][snid] : used for $key = subscribe or unsubscribe * [context][from_name] : name of mail sender or site name (optional) * [context][account] : account details of recipient * [from] : array('address' => 'noreply@example.org', 'formatted' => 'site name" . t('Simplenews publishes and sends newsletters to lists of subscribers. Both anonymous and authenticated users can opt-in to different mailing lists.') . "
\n"; $help .= "" . t('Simplenews uses nodes for newsletter issues. Newsletter issues are grouped by a newsletter taxonomy term. Node type and vocabulary are selectable. A newsletter is send to all email addresses which are subscribed to the newsletter. Newsletter issues can be sent only once. Large mailings should be sent by cron to balance the mailserver load.') . "
\n"; $help .= "" . t('Simplenews adds elements to the newsletter node add/edit form to manage newsletter format and sending of the newsletter issue. A newsletter issue can be sent for test before sending officially.') . "
\n"; $help .= "" . t('Both anonymous and authenticated users can opt-in and opt-out to a newsletter. A confirmation message is sent to anonymous users when they (un)subscribe. Users can (un)subscribe using a form and a block. A subscription block is available for each newsletter offering a subscription form, a link to recent newsletters and RSS feed. Email addresses can also be imported and exported via the subscription administration pages.') . "
\n"; $help .= "" . t('For more information, see the online handbook entry for Simplenews.', array('@handbook', 'http://drupal.org/node/197057')) . "
\n"; return $help; case 'node/add/simplenews': $help = '' . t('This is a Multilingual website. Enter text for confirmation subject and body in the default site language (@language).', array('@language' => $language_default->name)) . "
\n"; } else { $help = '' . t('This is a Multilingual website. Enable the String translation module to enable translation of the confirmation subject and body.', array('@url' => url('admin/modules'))) . "
\n"; } return $help; } break; case 'admin/structure/simplenews/add': $help = '' . t('You can create different newsletters (or subjects) to categorize your news (e.g. Cats news, Dogs news, ...).') . "
\n"; return $help; case 'admin/structure/types/manage/simplenews/display': $help = '' . t("'Plain' display settings apply to the content of emails send in plain text format. 'HTML' display settings apply to both HTML and plain text alternative content of emails send in HTML format.") . "
\n"; return $help; } } /** * Helper function to translate a newsletter name if required. * * @param