You are here

site_disclaimer.module in Site Disclaimer 6

Same filename and directory in other branches
  1. 7 site_disclaimer.module

This module adds Site Disclaimer to the registration page.

File

site_disclaimer.module
View source
<?php

/**
 * @file
 * This module adds Site Disclaimer to the registration page.
 *
 */

/**
 * @todo: cancel/logout button on the "accept new terms of use" page
 * @todo: remove breadcrumbs on the "accept new terms of use" page
 *
 */
define('SITE_DISCLAIMER_SETTINGS_PATH', 'admin/settings/site_disclaimer');
define('SITE_DISCLAIMER_ACCEPT_PATH', '_legal/accept_new');
define('SITE_DISCLAIMER_DEFAULT_TITLE', t('Terms of Use'));
define('SITE_DISCLAIMER_DEFAULT_CHECKBOX_LABEL', t('I agree with these terms'));

/**
 * Implementation of hook_help().
 */
function site_disclaimer_help($path, $arg) {
  switch ($path) {
    case 'admin/help#site_disclaimer':
      return '<p>' . t('Site Disclaimer form (which includes a Site Disclaimer statement and an [x] checkbox) is displayed on the registration page, and the visitor is required to accept it by checking the [x] checkbox in order to register. If Site Disclaimer statement is revised later, Site Disclaimer form will be displayed after registered user logs in and the user will be required to accept the new version of the terms by checking the [x] checkbox in order to proceed using the website.') . '</p>';
      break;
    case SITE_DISCLAIMER_SETTINGS_PATH:
      return '<p>' . t('Site Disclaimer form (which includes a Site Disclaimer statement and an [x] checkbox) is displayed on the registration page, and the visitor is required to accept it by checking the [x] checkbox in order to register. If Site Disclaimer statement is revised later, Site Disclaimer form will be displayed after registered user logs in and the user will be required to accept the new version of the terms by checking the [x] checkbox in order to proceed using the website.') . '</p>';
      break;
  }
}

/**
 * Implementation of hook_menu().
 */
function site_disclaimer_menu() {
  $items = array();
  $items[SITE_DISCLAIMER_SETTINGS_PATH] = array(
    'description' => 'Add Site Disclaimer to the registration page.',
    'title' => 'Site Disclaimer',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'site_disclaimer_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'site_disclaimer.admin.inc',
  );
  $items['site_disclaimer/autocomplete'] = array(
    'title' => 'Autocomplete node title',
    'page callback' => 'site_disclaimer_autocomplete',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'site_disclaimer.admin.inc',
  );
  $items['site_disclaimer/js'] = array(
    'page callback' => 'site_disclaimer_js',
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'site_disclaimer.admin.inc',
  );
  $items[SITE_DISCLAIMER_ACCEPT_PATH] = array(
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'site_disclaimer_confirm',
    ),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'file' => 'site_disclaimer.pages.inc',
  );
  return $items;
}

/**
 * Get translation of a node for the current language.
 */
function _site_disclaimer_nid_translated($nid) {
  if ($nid != '' && module_exists('translation')) {
    global $language;
    $langcode = $language->language;
    $translations = translation_node_get_translations($nid);
    if (!empty($translations[$langcode])) {
      $nid = $translations[$langcode]->nid;
    }
  }
  return $nid;
}

/**
 * Get an associative array of all node translations (keyed by language code)
 */
function _site_disclaimer_nid_all_translations($nid) {
  global $language;
  $nids = empty($nid) ? array() : array(
    $language->language => $nid,
  );
  if (!empty($nid) && module_exists('translation')) {
    $translations = translation_node_get_translations($nid);
    foreach ($translations as $langcode => $translation) {
      $nids[$langcode] = $translation->nid;
    }
  }
  return $nids;
}

/**
 * Go through the $checkbox_label string, replacing each @"Terms Link" with an actual node link
 *
 * @param $checkbox_label
 *  The label from the admin form saved in the DB.
 * @param $linked_nodes
 *  (Optional) return an array of all linked node nids.
 * @param $linked_errors
 *  (Optional) return an array of all linked node errors.
 * @return
 *  Substituted text output.
 */
function _site_disclaimer_checkbox_label_substitute_links($checkbox_label, &$linked_nodes = NULL, &$linked_errors = NULL) {
  $linked_nodes = array();
  $linked_errors = array();

  // Go through the $output string, replacing @"Terms Link" with an actual node link
  $output = str_replace('&quot;', '"', $checkbox_label);
  $i = 0;
  while ($i < drupal_strlen($output)) {
    if (drupal_substr($output, $i, 2) == '@"') {
      $start = $i + 2;
      $end = strpos($output, '"', $start);
      while (drupal_substr($output, $end - 1, 1) == "\\") {
        $end = strpos($output, '"', $end + 1);
      }
      $title = drupal_substr($output, $start, $end - $start);
      $node = node_load(array(
        'title' => str_replace('\\"', '"', $title),
      ));
      if (empty($node)) {
        $linked_errors[$title] = t('No post was found with "!title" title.', array(
          '!title' => $title,
        ));
      }
      else {
        $linked_nodes[] = $node->nid;
        $link = l($node->title, 'node/' . $node->nid);
        $output = str_replace('@"' . $title . '"', $link, $output);
        $i += drupal_strlen($link) - 1;
      }
    }
    $i++;
  }
  return $output;
}

/**
 * Implementation of hook_form_form_id_alter().
 */
function site_disclaimer_form_user_register_alter(&$form, $form_state, $langcode = NULL, $preview = FALSE) {
  $args = isset($form['#parameters']) ? $form['#parameters'] : array(
    '',
  );
  $form_id = array_shift($args);

  // Administrative users can skip site_disclaimer on admin/user/user/create page.
  if (user_access('administer users') && !$preview && $form_id == 'user_register') {
    return;
  }
  $height = variable_get('site_disclaimer_node_height', '');
  if ($height) {
    $css = '#site-disclaimer { height:' . check_plain($height) . '; overflow:auto; }';

    // Revert the styling so print shows the full text.
    $css2 = '#site-disclaimer { height:auto; overflow:visible; }';
    drupal_set_html_head('<style type="text/css">' . $css . '</style>');
    drupal_set_html_head('<style type="text/css" media="print">' . $css2 . '</style>');
  }

  // Getting the node that contains the Site Disclaimer.
  $nid = _site_disclaimer_nid_translated(variable_get('site_disclaimer_node_id', ''));
  $node = NULL;
  if (!empty($nid)) {
    $node = node_load($nid);
    if (empty($node)) {
      watchdog('Site Disclaimer', 'The Site Disclaimer node !nid could not be loaded. Please check the settings and the node.', array(
        '!nid' => $nid,
      ), WATCHDOG_ALERT, l(t('Administer Site Disclaimer'), SITE_DISCLAIMER_SETTINGS_PATH));
    }
  }

  // Will we show the full text of the Terms or only provide a link to the Terms.
  // Reading the checkbox label to find out.
  $checkbox_label = filter_xss_admin(variable_get('site_disclaimer_checkbox_label', SITE_DISCLAIMER_DEFAULT_CHECKBOX_LABEL));
  $use_link = strpos($checkbox_label, '@link') !== FALSE;
  $use_named_links = strpos($checkbox_label, '@&quot;') !== FALSE;
  $show_node = $node && !$use_link && !$use_named_links;

  // If there is no node to show and no links in the $checkbox_label, we don't show the terms form.
  // Same logic as in _site_disclaimer_enabled()
  if (!$use_link && !$use_named_links && !$node) {
    return;
  }
  $checkbox_label = theme('site_disclaimer_checkbox_label', $checkbox_label, $node);
  $fieldset_en = variable_get('site_disclaimer_fieldset', 1);
  if ($fieldset_en) {

    // Adding the fieldset.
    $form['site_disclaimer'] = array(
      '#type' => 'fieldset',
      '#title' => check_plain(variable_get('site_disclaimer_title', SITE_DISCLAIMER_DEFAULT_TITLE)),
      '#weight' => 10,
    );
    $fieldset =& $form['site_disclaimer'];
  }
  else {
    $fieldset =& $form;
  }

  // Adding the Site Disclaimer to the fieldset.
  if ($show_node) {
    $node = node_prepare($node);
    if (!empty($node->body)) {
      $fieldset['site_disclaimer_text'] = array(
        '#value' => theme('site_disclaimer', $node->body, $node),
        '#weight' => 9,
      );
    }
    else {
      watchdog('Site Disclaimer', 'The body field of the Site Disclaimer node !nid is empty. Please check the the node content.', array(
        '!nid' => $nid,
      ), WATCHDOG_ALERT, l(t('Administer Site Disclaimer'), SITE_DISCLAIMER_SETTINGS_PATH));
    }
  }

  // Adding the checkbox to the fieldset.
  $fieldset['I_agree'] = array(
    '#type' => 'checkbox',
    '#title' => $checkbox_label,
    '#required' => TRUE,
    // The following adds "required" validation to the checkbox (patches core missing functionality as of D6.16)
    '#element_validate' => array(
      '_site_disclaimer_validate_checkbox',
    ),
    '#return_value' => variable_get('site_disclaimer_version', 1),
    '#weight' => 10,
  );
  return $form;
}

/**
 * Validation callback; verify that checkbox is checked.
 */
function _site_disclaimer_validate_checkbox($form, &$form_state) {
  $value = $form_state['values']['I_agree'];
  if ($value != variable_get('site_disclaimer_version', 1)) {
    form_set_error('I_agree', t('You must agree with the !terms to get an account.', array(
      '!terms' => check_plain(variable_get('site_disclaimer_title', SITE_DISCLAIMER_DEFAULT_TITLE)),
    )));
  }
}

/**
 * Implementation of hook_user().
 */
function site_disclaimer_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    case 'insert':
      if (isset($edit['I_agree'])) {
        $edit['site_disclaimer'] = $edit['I_agree'];
        unset($edit['I_agree']);
      }
      break;
  }
}
function _site_disclaimer_i18n() {
  $variables = array(
    // Rely on node translations.
    //    'site_disclaimer_node_title',
    //    'site_disclaimer_node_id',
    'site_disclaimer_title',
    'site_disclaimer_checkbox_label',
    'site_disclaimer_version_details',
  );
  $i18n_variables = variable_get('i18n_variables', array());
  if (in_array($variables[0], $i18n_variables)) {
    return;
  }
  $i18n_variables = array_merge($i18n_variables, $variables);
  variable_set('i18n_variables', $i18n_variables);
}

/**
 * Determine if site_disclaimer is enabled.
 */
function _site_disclaimer_enabled() {

  // Will we show the full text of the Terms or only provide a link to the Terms.
  // Reading the checkbox label to find out.
  $nid = _site_disclaimer_nid_translated(variable_get('site_disclaimer_node_id', ''));
  $checkbox_label = filter_xss_admin(variable_get('site_disclaimer_checkbox_label', SITE_DISCLAIMER_DEFAULT_CHECKBOX_LABEL));
  $use_link = strpos($checkbox_label, '@link') !== FALSE;
  $use_named_links = strpos($checkbox_label, '@&quot;') !== FALSE;

  // If there is no node to show and no links in the $checkbox_label, we don't show the terms form.
  $site_disclaimer_enabled = $use_link || $use_named_links || !empty($nid);
  return $site_disclaimer_enabled;
}

/**
 * Implementation of hook_init().
 */
function site_disclaimer_init() {
  global $user;

  // http://drupal.org/node/313272#comment-2786004
  // This is a performance hit. We need it here because $conf in settings.php
  // overrides database variable value in variable_init().
  // Faster performance will be achieved if the variables in
  // _site_disclaimer_i18n() are added to $conf in settings.php.
  _site_disclaimer_i18n();
  if ($user->uid > 1 && !user_access('administer site configuration')) {
    $site_disclaimer_enabled = _site_disclaimer_enabled();
    $site_disclaimer_version = variable_get('site_disclaimer_version', 1);
    if ($site_disclaimer_enabled && (!isset($user->site_disclaimer) || $user->site_disclaimer < $site_disclaimer_version)) {
      $allow_nodes = variable_get('site_disclaimer_allow_nodes', array());

      // Allowed paths, array path components mean logical or (any of)
      $allow_paths = array(
        explode('/', SITE_DISCLAIMER_ACCEPT_PATH),
        array(
          'logout',
        ),
      );

      // Any links in the Site Disclaimer node or in the checkbox should also be allowed.
      if (!empty($allow_nodes)) {
        $allow_paths[] = array(
          'node',
          $allow_nodes,
        );

        // Special case for print.module - allow the user to also print the allowed nodes.
        $allow_paths[] = array(
          'print',
          'node',
          $allow_nodes,
        );
        $allow_paths[] = array(
          'printpdf',
          'node',
          $allow_nodes,
        );
      }

      // @todo: implement hook_site_disclaimer_allowed_paths_alter() here, so paths like print, printpdf can belong to print module
      // Check if the path is in the allowed list
      foreach ($allow_paths as $allow_path) {

        // This while loop ends in "return" if the path matches.
        // If the path does not match, break 2 will loop to the next allowed path
        while (1) {
          $i = 0;

          // Array path components mean logical or (any of)
          foreach ($allow_path as $part) {
            if (is_array($part) && !in_array(arg($i), $part)) {
              break 2;
            }
            if (!is_array($part) && arg($i) != $part) {
              break 2;
            }
            $i++;
          }

          // The arg() path matches the one in the $allow_path
          return;
        }
      }
      drupal_goto(SITE_DISCLAIMER_ACCEPT_PATH, drupal_get_destination());
    }
  }
}

/**
 * Implementation of hook_theme().
 */
function site_disclaimer_theme() {
  return array(
    'site_disclaimer' => array(
      'arguments' => array(
        'terms' => NULL,
        'node' => NULL,
      ),
    ),
    'site_disclaimer_checkbox_label' => array(
      'arguments' => array(
        'checkbox_label' => '',
        'node' => NULL,
      ),
    ),
  );
}

/**
 * Theme the Site Disclaimer section.
 *
 * @param $terms
 *  The Site Disclaimer, already formatted.
 * @param $node
 *  The $node object, in case we need it.
 * @return
 *  HTML output.
 * @ingroup themeable
 */
function theme_site_disclaimer($terms, $node = NULL) {

  // id to match our css (#site-disclaimer) for setting Site Disclaimer form height
  $output = '<div id="site-disclaimer" class="content clear-block">';
  $output .= $terms;
  $output .= '</div>';
  return $output;
}

/**
 * Theme the Site Disclaimer checkbox label.
 *
 * @param $checkbox_label
 *  The label from the admin form saved in the DB.
 * @param $node
 *  The Site Disclaimer $node.
 * @return
 *  HTML output.
 * @ingroup themeable
 */
function theme_site_disclaimer_checkbox_label($checkbox_label = '', $node = NULL) {
  if (!drupal_strlen($checkbox_label)) {
    return '';
  }
  $output = $checkbox_label;
  if (!empty($node)) {

    //We are linking to the terms instead, replace the link.
    $output = str_replace('@link', l($node->title, 'node/' . $node->nid), $output);
  }
  $output = _site_disclaimer_checkbox_label_substitute_links($output);

  // The following adds "required" styling to the checkbox (patches core missing functionality as of D6.16)
  // Checkbox validate handles denoting required checkboxes for us
  if (!module_exists('checkbox_validate')) {
    $output .= '&nbsp;<span class="form-required" title="' . t('This field is required.') . '">*</span>';
  }
  return $output;
}

/*
 * Worker code for hook_nodeapi().
 */
function _site_disclaimer_nodeapi_work($node, $op) {
  $nid = variable_get('site_disclaimer_node_id', '');
  $nids = $nid != '' ? _site_disclaimer_nid_all_translations($nid) : array();
  $nids += variable_get('site_disclaimer_allow_nodes', array());

  // Figure out translation relationships of the node
  if (!empty($node->tnid)) {
    $node_tnid = $node->tnid;
  }
  elseif (!empty($node->translation_source)) {
    $node_tnid = $node->translation_source->tnid ? $node->translation_source->tnid : $node->translation_source->nid;
  }

  //?  if (!$node_tnid) {

  //    $node_tnid = $_GET['translation'];
  //  }
  if (isset($node->nid) && in_array($node->nid, $nids) || !empty($node_tnid) && in_array($node_tnid, $nids)) {
    module_load_include('inc', 'site_disclaimer', 'site_disclaimer.admin');
    _site_disclaimer_prep_allowed_paths($nid, $op == 'delete' ? $node->nid : NULL);
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function site_disclaimer_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'insert':
    case 'update':
    case 'delete':
      _site_disclaimer_nodeapi_work($node, $op);
    case 'prepare':
      break;
  }
}

/**
 * Implementation of hook_views_api().
 */
function site_disclaimer_views_api() {
  return array(
    'api' => 2.0,
    'path' => drupal_get_path('module', 'site_disclaimer') . '/views',
  );
}

Functions

Namesort descending Description
site_disclaimer_form_user_register_alter Implementation of hook_form_form_id_alter().
site_disclaimer_help Implementation of hook_help().
site_disclaimer_init Implementation of hook_init().
site_disclaimer_menu Implementation of hook_menu().
site_disclaimer_nodeapi Implementation of hook_nodeapi().
site_disclaimer_theme Implementation of hook_theme().
site_disclaimer_user Implementation of hook_user().
site_disclaimer_views_api Implementation of hook_views_api().
theme_site_disclaimer Theme the Site Disclaimer section.
theme_site_disclaimer_checkbox_label Theme the Site Disclaimer checkbox label.
_site_disclaimer_checkbox_label_substitute_links Go through the $checkbox_label string, replacing each @"Terms Link" with an actual node link
_site_disclaimer_enabled Determine if site_disclaimer is enabled.
_site_disclaimer_i18n
_site_disclaimer_nid_all_translations Get an associative array of all node translations (keyed by language code)
_site_disclaimer_nid_translated Get translation of a node for the current language.
_site_disclaimer_nodeapi_work
_site_disclaimer_validate_checkbox Validation callback; verify that checkbox is checked.

Constants

Namesort descending Description
SITE_DISCLAIMER_ACCEPT_PATH
SITE_DISCLAIMER_DEFAULT_CHECKBOX_LABEL
SITE_DISCLAIMER_DEFAULT_TITLE
SITE_DISCLAIMER_SETTINGS_PATH @todo: cancel/logout button on the "accept new terms of use" page @todo: remove breadcrumbs on the "accept new terms of use" page