You are here

rabbit_hole.module in Rabbit Hole 6

Main module file for Rabbit Hole.

This is a module that will prevent users from viewing the full node. This is configurable per content type or node.

File

rabbit_hole.module
View source
<?php

/**
 * @file
 * Main module file for Rabbit Hole.
 *
 * This is a module that will prevent users from viewing the full node. This is
 * configurable per content type or node.
 */
define('RABBIT_HOLE_USE_DEFAULT', -1);
define('RABBIT_HOLE_DISPLAY_CONTENT', 0);
define('RABBIT_HOLE_ACCESS_DENIED', 1);
define('RABBIT_HOLE_PAGE_NOT_FOUND', 2);
define('RABBIT_HOLE_PAGE_REDIRECT', 3);
define('RABBIT_HOLE_PAGE_REDIRECT_RESPONSE_DEFAULT', 301);

/**
 * Implements hook_perm().
 */
function rabbit_hole_perm() {
  return array(
    'administer rabbit hole',
    'bypass rabbit hole',
  );
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * This will add Rabbit Hole options to the node type form. These settings will
 * be used as default for every node of this node type.
 */
function rabbit_hole_form_node_type_form_alter(&$form, $form_state) {
  if (!user_access('administer rabbit hole')) {

    // The user doesn't have access.
    return;
  }
  if (isset($form['#node_type'])) {
    drupal_add_js(drupal_get_path('module', 'rabbit_hole') . '/rabbit-hole.js', 'theme');
    drupal_add_js(array(
      'rabbitHole' => array(
        'redirectValue' => RABBIT_HOLE_PAGE_REDIRECT,
      ),
    ), 'setting');
    $form['rabbit_hole'] = array(
      '#type' => 'fieldset',
      '#title' => t('Rabbit Hole settings'),
      '#collapsed' => TRUE,
      '#collapsible' => TRUE,
      '#group' => 'additional_settings',
      '#attributes' => array(
        'class' => 'rabbit-hole-settings-form',
      ),
    );
    $form['rabbit_hole']['rabbit_hole_action'] = array(
      '#type' => 'radios',
      '#title' => t('Behavior'),
      '#options' => array(
        RABBIT_HOLE_DISPLAY_CONTENT => t('Display the content (regular behavior)'),
        RABBIT_HOLE_ACCESS_DENIED => t('Access denied'),
        RABBIT_HOLE_PAGE_NOT_FOUND => t('Page not found'),
        RABBIT_HOLE_PAGE_REDIRECT => t('Page redirect'),
      ),
      '#default_value' => variable_get('rabbit_hole_action_' . $form['#node_type']->type, RABBIT_HOLE_DISPLAY_CONTENT),
      '#description' => t('What should happen when someone tries to visit the node page?'),
    );
    $form['rabbit_hole']['redirect'] = array(
      '#type' => 'fieldset',
      '#title' => t('Redirect settings'),
      '#attributes' => array(
        'class' => 'rabbit-hole-redirect-options',
      ),
    );
    $form['rabbit_hole']['redirect']['rabbit_hole_redirect'] = array(
      '#type' => 'textfield',
      '#title' => t('Redirect path'),
      '#size' => 40,
      '#default_value' => variable_get('rabbit_hole_redirect_' . $form['#node_type']->type, ''),
      '#description' => t('The relative path to were the user should be redirected. Leave this empty, or use %front to redirect to the front page. You may enter tokens in this field.', array(
        '%front' => '<front>',
      )),
    );

    // Display a list of tokens if the Token module is enabled.
    if (module_exists('token')) {
      $form['rabbit_hole']['redirect']['token_info'] = array(
        '#theme' => 'token_tree',
        '#token_types' => array(
          'node',
        ),
      );
    }
    $form['rabbit_hole']['redirect']['rabbit_hole_redirect_response'] = array(
      '#type' => 'select',
      '#title' => t('Response code'),
      '#options' => array(
        301 => t('301 (Moved Permanently)'),
        302 => t('302 (Found)'),
        303 => t('303 (See other)'),
        304 => t('304 (Not modified)'),
        305 => t('305 (Use proxy)'),
        307 => t('307 (Temporary redirect)'),
      ),
      '#default_value' => variable_get('rabbit_hole_redirect_response_' . $form['#node_type']->type, RABBIT_HOLE_PAGE_REDIRECT_RESPONSE_DEFAULT),
      '#description' => t('The response code that should be sent to the users browser. Follow !link for more information on response codes.', array(
        '!link' => l(t('this link'), 'http://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_goto/6'),
      )),
    );
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * This will add Rabbit Hole options to the node form. The user will be able to
 * override the default Rabbit Hole options.
 */
function rabbit_hole_form_alter(&$form, &$form_state, $form_id) {
  if (!user_access('administer rabbit hole') || strpos($form_id, 'node_form') === FALSE) {

    // The user doesn't have access, or this isn't a node form.
    return;
  }
  drupal_add_js(drupal_get_path('module', 'rabbit_hole') . '/rabbit-hole.js', 'theme');
  drupal_add_js(array(
    'rabbitHole' => array(
      'redirectValue' => RABBIT_HOLE_PAGE_REDIRECT,
    ),
  ), 'setting');
  $node = $form['#node'];
  $form['rabbit_hole'] = array(
    '#type' => 'fieldset',
    '#title' => t('Rabbit Hole settings'),
    '#collapsed' => TRUE,
    '#collapsible' => TRUE,
    '#group' => 'additional_settings',
    '#attributes' => array(
      'class' => 'rabbit-hole-settings-form',
    ),
  );
  $form['rabbit_hole']['rabbit_hole_action'] = array(
    '#type' => 'radios',
    '#title' => t('Behavior'),
    '#options' => array(
      RABBIT_HOLE_USE_DEFAULT => t('Content type default'),
      RABBIT_HOLE_DISPLAY_CONTENT => t('Display the content (regular behavior)'),
      RABBIT_HOLE_ACCESS_DENIED => t('Access denied'),
      RABBIT_HOLE_PAGE_NOT_FOUND => t('Page not found'),
      RABBIT_HOLE_PAGE_REDIRECT => t('Page redirect'),
    ),
    '#default_value' => isset($node->rabbit_hole_action) ? $node->rabbit_hole_action : RABBIT_HOLE_USE_DEFAULT,
    '#description' => t('What should happen when someone tries to visit the node page?'),
  );
  $form['rabbit_hole']['redirect'] = array(
    '#type' => 'fieldset',
    '#title' => t('Redirect settings'),
    '#attributes' => array(
      'class' => 'rabbit-hole-redirect-options',
    ),
  );
  $form['rabbit_hole']['redirect']['rabbit_hole_redirect'] = array(
    '#type' => 'textfield',
    '#title' => t('Redirect path'),
    '#size' => 40,
    '#default_value' => isset($node->rabbit_hole_redirect) ? $node->rabbit_hole_redirect : variable_get('rabbit_hole_redirect_' . $node->type, ''),
    '#description' => t('The relative path to were the user should be redirected. Leave this empty, or use %front to redirect to the front page.', array(
      '%front' => '<front>',
    )),
  );

  // Display a list of tokens if the Token module is enabled.
  if (module_exists('token')) {
    $form['rabbit_hole']['redirect']['token_info'] = array(
      '#theme' => 'token_tree',
      '#token_types' => array(
        'node',
      ),
    );
  }
  $form['rabbit_hole']['redirect']['rabbit_hole_redirect_response'] = array(
    '#type' => 'select',
    '#title' => t('Response code'),
    '#options' => array(
      301 => t('301 (Moved Permanently)'),
      302 => t('302 (Found)'),
      303 => t('303 (See other)'),
      304 => t('304 (Not modified)'),
      305 => t('305 (Use proxy)'),
      307 => t('307 (Temporary redirect)'),
    ),
    '#default_value' => isset($node->rabbit_hole_redirect_response) ? $node->rabbit_hole_redirect_response : variable_get('rabbit_hole_redirect_response_' . $node->type, RABBIT_HOLE_PAGE_REDIRECT_RESPONSE_DEFAULT),
    '#description' => t('The response code that should be sent to the users browser, e.g. 301. Follow !link for more information on response codes.', array(
      '!link' => l(t('this link'), 'http://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_goto/6'),
    )),
  );

  // Add a custom submit function. This is used to disable the redirect to
  // node/123 if Rabbit Hole is enabled.
  $form['buttons']['submit']['#submit'][] = 'rabbit_hole_node_form_submit';
}

/**
 * Custom submit function for the node form.
 *
 * This will fire after the regular submit function, and it's purpose is to make
 * sure that the user doesn't get redirected to node/123 after saving the node,
 * if any Rabbit Hole action is enabled. This works by redirecting the user to
 * node/123/edit, if a destination parameter hasn't been set.
 *
 * @see node_form_submit().
 */
function rabbit_hole_node_form_submit($form, &$form_state) {

  // Get the action. Either the one specified for this node, or the default
  // value for the content type.
  $action = $form_state['values']['rabbit_hole_action'] != RABBIT_HOLE_USE_DEFAULT ? $form_state['values']['rabbit_hole_action'] : variable_get('rabbit_hole_action_' . $form_state['values']['type'], RABBIT_HOLE_DISPLAY_CONTENT);

  // If the action says anything else than to display the content, make sure
  // that the user doesn't land on the node view page. We'll check if a custom
  // redirect path has been set, otherwise, we'll redirect the user to the edit
  // page again.
  if ($action != RABBIT_HOLE_DISPLAY_CONTENT && $form_state['redirect'] == 'node/' . $form_state['values']['nid']) {
    $form_state['redirect'] = 'node/' . $form_state['values']['nid'] . '/edit';
  }
}

/**
 * Implements hook_nodeapi().
 */
function rabbit_hole_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'view':
      if (arg(1) != $node->nid || !preg_match('/node\\/' . $node->nid . '(\\/view|)$/', $_GET['q']) || user_access('bypass rabbit hole')) {

        // The node is not being viewed at it's own page, or the user is able to
        // bypass Rabbit Hole, exit early.
        return;
      }

      // Get the action. Use the one specified for this node, or fallback to the
      // default value for the content type.
      $action = isset($node->rabbit_hole_action) ? $node->rabbit_hole_action != RABBIT_HOLE_USE_DEFAULT ? $node->rabbit_hole_action : variable_get('rabbit_hole_action_' . $node->type, RABBIT_HOLE_DISPLAY_CONTENT) : variable_get('rabbit_hole_action_' . $node->type, RABBIT_HOLE_DISPLAY_CONTENT);

      // If we should perform a redirect, we will also get the path and response.
      if ($action == RABBIT_HOLE_PAGE_REDIRECT) {
        if (isset($node->rabbit_hole_action) && $node->rabbit_hole_action != RABBIT_HOLE_USE_DEFAULT) {

          // Get the redirect path and response from the node.
          $redirect_path = $node->rabbit_hole_redirect;
          $redirect_response = $node->rabbit_hole_redirect_response;
        }
        else {

          // Get the redirect path and response from the content type.
          $redirect_path = variable_get('rabbit_hole_redirect_' . $node->type, '<front>');
          $redirect_response = variable_get('rabbit_hole_redirect_response_' . $node->type, RABBIT_HOLE_PAGE_REDIRECT_RESPONSE_DEFAULT);
        }
      }

      // Replace the tokens in the provided redirect path if the tokens module
      // exists.
      if (module_exists('token')) {
        $redirect_path = token_replace($redirect_path, 'node', $node);
      }

      // Now, let's see what we should do.
      switch ($action) {
        case RABBIT_HOLE_ACCESS_DENIED:

          // TODO: Is this the proper way to deliver an access denied page?
          drupal_access_denied();
          exit;
        case RABBIT_HOLE_PAGE_NOT_FOUND:

          // TODO: Is this the proper way to deliver a not found page?
          drupal_not_found();
          exit;
        case RABBIT_HOLE_PAGE_REDIRECT:

          // Redirect the user to the specified path.
          drupal_goto($redirect_path, NULL, NULL, $redirect_response);
      }
      break;
  }
}

/**
 * Implements hook_node_type().
 */
function rabbit_hole_node_type($op, $info) {
  switch ($op) {
    case 'delete':

      // Delete variables connected to this content type.
      variable_del('rabbit_hole_action_' . $info->type);
      variable_del('rabbit_hole_redirect_' . $info->type);
      variable_del('rabbit_hole_redirect_response_' . $info->type);
      break;
  }
}