You are here

publishcontent.module in Publish Content 6

Add button to publish or unpublish a node, with access control based on the node type

File

publishcontent.module
View source
<?php

/**
 * @file
 * Add button to publish or unpublish a node,
 * with access control based on the node type
 */

/**
 * Implements of hook_menu().
 */
function publishcontent_menu() {
  $items = array();
  $items['admin/settings/publishcontent'] = array(
    'title' => 'Publish content settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'publishcontent_config_form',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer site configuration',
    ),
    'description' => 'Show/hide the publish/unpublish tabs on nodes.',
    'file' => 'publishcontent.admin.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['node/%publishcontent_tab/publish/%publishcontent_security_token'] = array(
    'title' => 'Publish',
    'page callback' => 'publishcontent_toggle_status',
    'page arguments' => array(
      1,
    ),
    'access callback' => '_publishcontent_publish_access',
    'access arguments' => array(
      1,
      3,
    ),
    'weight' => 5,
    'type' => MENU_LOCAL_TASK,
  );
  $items['node/%publishcontent_tab/unpublish/%publishcontent_security_token'] = array(
    'title' => 'Unpublish',
    'page callback' => 'publishcontent_toggle_status',
    'page arguments' => array(
      1,
    ),
    'access callback' => '_publishcontent_unpublish_access',
    'access arguments' => array(
      1,
      3,
    ),
    'weight' => 5,
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Decide to show the (un)publish tab or not.
 */
function publishcontent_tab_load($nid) {
  if (is_numeric($nid)) {
    $node = node_load($nid);
    if (variable_get('publishcontent_tabs', TRUE)) {
      return $node;
    }
  }
  return FALSE;
}

/**
 * Used to append a security token to prevent XSS.
 *
 * @see Dynamic argument replacement (wildcard) for hook_menu at
 *      http://drupal.org/node/109153
 */
function publishcontent_security_token_to_arg($arg, $map, $index) {
  return drupal_get_token();
}

/**
 * DEPRECATED: This function will be going away. publish_content_menu_alter was
 * using this function. Leaving in place to avoid fatal errors due to outdated
 * menu cache.
 */
function _publishcontent_view_access($node) {
  return user_access('un/publish ' . check_plain($node->type) . ' content') || user_access('un/publish *all* content') || node_access('view', $node);
}

/**
 * Access callback for publish action. Only allow access based on permissions 
 * and current node status = unpublished
 */
function _publishcontent_publish_access($node, $token = FALSE) {
  if ($token && !drupal_valid_token($token)) {
    return FALSE;
  }
  if (!variable_get('publishcontent_' . $node->type, TRUE)) {
    return FALSE;
  }
  global $user;
  return !$node->status && (user_access('publish any content') || user_access('publish own content') && $user->uid == $node->uid || user_access('publish editable content') && node_access('update', $node) || user_access('publish own ' . check_plain($node->type) . ' content', $user) && $user->uid == $node->uid || user_access('publish any ' . check_plain($node->type) . ' content') || user_access('publish editable ' . check_plain($node->type) . ' content') && node_access('update', $node));
}

/**
 * Access callback for unpublish action. Only allow access based on permissions
 * and current node status = published
 */
function _publishcontent_unpublish_access($node, $token = FALSE) {
  if ($token && !drupal_valid_token($token)) {
    return FALSE;
  }
  if (!variable_get('publishcontent_' . $node->type, TRUE)) {
    return FALSE;
  }
  global $user;
  return $node->status && (user_access('unpublish any content') || user_access('unpublish own content') && $user->uid == $node->uid || user_access('unpublish editable content') && node_access('update', $node) || user_access('unpublish own ' . check_plain($node->type) . ' content', $user) && $user->uid == $node->uid || user_access('unpublish any ' . check_plain($node->type) . ' content') || user_access('unpublish editable ' . check_plain($node->type) . ' content') && node_access('update', $node));
}

/**
 * Implements hook_perm().
 */
function publishcontent_perm() {
  $perms = array(
    'publish any content',
    'unpublish any content',
    'publish own content',
    'unpublish own content',
    'publish editable content',
    'unpublish editable content',
  );
  foreach (node_get_types() as $type) {
    if (isset($type->type)) {
      $perms[] = 'publish any ' . check_plain($type->type) . ' content';
      $perms[] = 'publish editable ' . check_plain($type->type) . ' content';
      $perms[] = 'publish own ' . check_plain($type->type) . ' content';
      $perms[] = 'unpublish any ' . check_plain($type->type) . ' content';
      $perms[] = 'unpublish editable ' . check_plain($type->type) . ' content';
      $perms[] = 'unpublish own ' . check_plain($type->type) . ' content';
    }
  }
  return $perms;
}

/**
 * Menu callback node/%/publish/% and node/%/unpublish/%
 *
 * @param $node a node object
 */
function publishcontent_toggle_status($node) {

  // XOR the current status with 1 to get the opposite value.
  $node->status = $node->status ^ 1;

  // If this content type specifies that a new revision should be created on
  // editing, then make sure to respect this option.
  $node_options = variable_get('node_options_' . $node->type, array());
  if (in_array('revision', $node_options)) {
    $node->revision = 1;
  }
  node_save($node);
  drupal_set_message(_publishcontent_get_message($node->nid, $node->title, $node->status));
  drupal_goto('node/' . $node->nid);
}

/**
 * Helper function to generate user feedback after status toggle.
 */
function _publishcontent_get_message($nid, $title, $status) {
  $status = $status ? t('published') : t('unpublished');
  return t('"@title" [@nid] has been !status', array(
    '@title' => $title,
    '@nid' => $nid,
    '!status' => $status,
  ));
}

/**
 * Implements of hook_form_alter().
 *
 * - Enable / Disable publishcontent for specific node types
 * - Allow to use the 'Publishing options' on the edit/add page
 */
function publishcontent_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'node_type_form') {
    $form['workflow']['publishcontent'] = array(
      '#type' => 'checkbox',
      '#title' => t('Enable publishcontent permissions for this node type.'),
      '#default_value' => variable_get('publishcontent_' . $form['#node_type']->type, TRUE),
      '#description' => t('Unchecking this option will disable publish and unpublish links for this node type.'),
    );
  }
  elseif (user_access('administer nodes') || empty($form['type']['#value']) || empty($form['#node']) || $form['type']['#value'] . '_node_form' != $form_id || !_publishcontent_unpublish_access($form['#node']) && !_publishcontent_publish_access($form['#node'])) {
    return;
  }
  $form['options']['status']['#access'] = TRUE;
  if (!empty($form['options']['#access'])) {
    return;
  }
  else {
    $form['options']['#access'] = TRUE;
  }
  foreach (element_children($form['options']) as $key) {

    // If another form has afforded access to a particular option, do not
    // override that access. Otherwise, disable it.
    $form['options'][$key]['#access'] = isset($form['options'][$key]['#access']) ? $form['options'][$key]['#access'] : FALSE;
  }
}

/**
 * Implements views_data_alter() to add items to the node table that are
 * relevant to publishcontent.
 */
function publishcontent_views_data_alter(&$data) {

  // new comments
  $data['node']['publishcontent'] = array(
    'title' => t('Publish link'),
    'help' => t('Display a link to publish the node.'),
    'field' => array(
      'handler' => 'publishcontent_views_handler_field_node_link',
    ),
  );
}

/**
 * Implements hook_views_handlers().
 */
function publishcontent_views_handlers() {
  return array(
    'info' => array(
      'path' => drupal_get_path('module', 'publishcontent'),
    ),
    'handlers' => array(
      // field handlers
      'publishcontent_views_handler_field_node_link' => array(
        'parent' => 'views_handler_field',
      ),
    ),
  );
}

Functions

Namesort descending Description
publishcontent_form_alter Implements of hook_form_alter().
publishcontent_menu Implements of hook_menu().
publishcontent_perm Implements hook_perm().
publishcontent_security_token_to_arg Used to append a security token to prevent XSS.
publishcontent_tab_load Decide to show the (un)publish tab or not.
publishcontent_toggle_status Menu callback node/%/publish/% and node/%/unpublish/%
publishcontent_views_data_alter Implements views_data_alter() to add items to the node table that are relevant to publishcontent.
publishcontent_views_handlers Implements hook_views_handlers().
_publishcontent_get_message Helper function to generate user feedback after status toggle.
_publishcontent_publish_access Access callback for publish action. Only allow access based on permissions and current node status = unpublished
_publishcontent_unpublish_access Access callback for unpublish action. Only allow access based on permissions and current node status = published
_publishcontent_view_access DEPRECATED: This function will be going away. publish_content_menu_alter was using this function. Leaving in place to avoid fatal errors due to outdated menu cache.