You are here

weight.module in Weight 5

File

weight.module
View source
<?php

/**
 * @file
 * This module uses the sticky column of the node table
 * to add weighting to nodes.
 */
if (module_exists('views')) {
  include drupal_get_path('module', 'weight') . '/weight.views.inc';
}

/**
 * Implementation of hook_help().
 */
function weight_help($section) {
  switch ($section) {
    case 'admin/setting/weight':
    case 'admin/modules#description':
      return t('Add weight-based sorting to nodes.');
    case 'admin/help#weight':
      return t('
        <p><strong>Description:</strong> The weight module adds a weight option
        to enabled node types. It uses the "sticky" field in the database to
        store weights as well as sticky information (so that feature is not
        lost). Nodes will be sorted first by stickiness, then by weight
        (lightest to heaviest), then by creation date.</p>

        <p><strong>Setup:</strong> To enable weight sorting on existing nodes,
        visit the <a href="@setup">weight db setup page</a> and click
        "Setup Database" to convert old sticky values to new weight-encoded values for
        proper sorting.</p>

        <p><strong>Permissions:</strong> Users with "administer nodes"
        permission will always be able to adjust weight for enabled node types.
        However, enabling "assign node weight" will allow non-node-admin users
        to adjust weight on their own nodes. Find these settings <a
        href="@access">here</a>.</p>

        <p><strong>Bulk weight management:</strong> You may easily manage the
        weight of multiple nodes simultaneously by using the <a href="@node_admin">
        node admin page</a>.</p>
      ', array(
        '@setup' => url('admin/settings/weight/setup'),
        '@access' => url('admin/user/access'),
        '@node_admin' => url('admin/content/node'),
      ));
  }
}
function weight_perm() {
  return array(
    'assign node weight',
  );
}

/**
 * Implementation of hook_menu().
 */
function weight_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $access = user_access('administer site configuration');

    // ajax callback for weight changer page
    $items[] = array(
      'path' => 'admin/node/weight/_change_weight',
      'callback' => '_change_weight',
      'access' => user_access('administer nodes'),
      'type' => MENU_CALLBACK,
    );

    // top level settings
    $items[] = array(
      'title' => t('Weight'),
      'path' => 'admin/settings/weight',
      'access' => $access,
      'description' => t('Add weight-based sorting to nodes.'),
      'callback' => 'weight_settings_page',
    );

    // 2nd level nav (tabs)
    $items[] = array(
      'title' => t('settings'),
      'path' => 'admin/settings/weight/settings',
      'access' => $access,
      'callback' => 'weight_settings_page',
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'title' => t('db setup'),
      'path' => 'admin/settings/weight/setup',
      'access' => $access,
      'callback' => 'weight_enable_page',
      'type' => MENU_LOCAL_TASK,
      'weight' => 4,
    );

    // 3rd level
    $items[] = array(
      'title' => t('enable'),
      'path' => 'admin/settings/weight/setup/enable',
      'access' => $access,
      'callback' => 'weight_enable_page',
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -2,
    );
    $items[] = array(
      'title' => t('disable'),
      'path' => 'admin/settings/weight/setup/disable',
      'access' => $access,
      'callback' => 'weight_disable_page',
      'type' => MENU_LOCAL_TASK,
      'weight' => 2,
    );
  }
  return $items;
}
function weight_nodeapi(&$node, $op) {
  switch ($op) {
    case 'submit':

      // non-weighted nodes have a weight of zero
      if (is_null($node->node_weight)) {
        $node->node_weight = 0;
      }

      // If the admin wants to use the menu weight, see if there is one.
      if (variable_get('weight_use_menu', FALSE)) {
        $node->node_weight = isset($node->menu['title']) && !empty($node->menu['title']) ? $node->menu['weight'] : $node->node_weight;
      }

      // here we're 'encoding' weight into the sticky value for the database
      // stickiness is the inverse of weight
      // - stickiness is sorted DESC while weight is sorted ASC so we invert
      // the weight before saving... if sticky box is checked, add 100 to
      // weight unweighted sticky nodes will have a value of 100
      _weight2encoded_sticky($node);
      break;
    case 'load':
      _encoded_sticky2weight($node);
      break;
  }
}

/**
 * Implementation of hook_form_alter().
 *
 * This is where we tweak the admin/content/node to include our weight
 * selector; hide the 'sticky' filter (it won't work when using weight module),
 * and add some help text to the form.
 */
function weight_form_alter($form_id, &$form) {
  $weight_node_types = variable_get('weight_node_types', array_flip(node_get_types('names')));
  $weight_node_type_names = array();
  foreach ($weight_node_types as $type) {
    $weight_node_type_names[] = node_get_types('name', $type);
  }

  // The admin node page does not use the nodeapi for getting lists of nodes, so
  // I never have a chance to convert the sticky flag to 0/1. and trying to
  // filter on that field will not work. Therefore, I am going to hide the
  // 'filter on sticky status' altogether when weight_module is enabled
  if ($form_id == 'node_filter_form') {

    // no comment
    unset($form['filters']['status']['status']['#options']['sticky-1']);
    unset($form['filters']['status']['status']['#options']['sticky-0']);
    $form['weight_help'] = array(
      '#type' => 'markup',
      '#value' => t('<strong>Note:</strong> When the weight module is enabled, it is not possible to filter based on sticky status.'),
    );
  }
  if ($form_id == 'node_admin_nodes') {

    // I can't add a table header for weight, so instead I'm going to explain
    // the weight dropdown to the user. Also, to position my help text
    // appropriately, I'm using this '#suffix' hack rather than adding
    // a form property as i'd like to do.
    $form['options']['#suffix'] .= t('<strong>Weight:</strong> To change the weight of a node, select a value from the corresponding dropdown box under <i>@operations</i>. Node weights are submitted immediately. Selectors are only available for node types configured on the <a href="@weight_admin">weight admin page</a>.', array(
      '@weight_admin' => url('admin/settings/weight'),
      '@operations' => t('Operations'),
    ));

    // add my weight selector under the operations section of the admin node
    // overview page (admin/content/node)
    if (!empty($form['operations'])) {
      foreach ($form['operations'] as $nid => $title) {

        // only add weight selector if weight is enabled for this node type
        if (in_array($form['name'][$nid]['#value'], $weight_node_type_names)) {
          $selector = weight_node_selector($nid);
          $form['operations'][$nid]['weight_selector']['#value'] = $selector['selector'];
          $form['status'][$nid]['#value'] .= $selector['status'];
        }
      }
    }
  }

  // node edit page weight selector
  if (isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id) {
    if (user_access('assign node weight') || user_access('administer nodes')) {
      $node = $form['#node'];
      if (in_array($node->type, $weight_node_types)) {
        $range = variable_get('weight_range', 20);
        $form['weight_fieldset'] = array(
          '#type' => 'fieldset',
          '#title' => t('Node Weight'),
          '#collapsible' => TRUE,
          '#collapsed' => $node->node_weight == 0,
          '#weight' => 2,
        );
        $form['weight_fieldset']['node_weight'] = array(
          '#type' => 'weight',
          '#title' => t("Node Weight"),
          '#default_value' => $node->node_weight,
          '#delta' => $range,
          '#description' => t('In a node list context (such as the front page or term pages), list items (e.g. "teasers") will be ordered by "stickiness" then by "node weight" then by "authored on" datestamp. Items with a lower (lighter) node weight value will appear above those with a higher (heavier) value.'),
        );
        if (variable_get('weight_use_menu', FALSE)) {
          $form['weight_fieldset']['node_weight']['#description'] .= '<br /> ' . t('<strong>Note</strong>: If this node is used in a menu, then this weight will be ignored.');
        }
      }
    }
  }
}
function weight_enable_page() {
  if ($_POST['op'] == t('Setup Database')) {
    weight_old_nodes();
    drupal_goto('admin/settings/weight');
  }
  $count = db_num_rows(db_query('SELECT DISTINCT nid FROM {node} WHERE sticky IN (0,1)'));
  $output = t('<p>The weight module uses the node table\'s "sticky" column to
    store weight information for each node. New and updated nodes will
    automatically have their sticky and weight information remapped. However if
    you have pre-existing nodes, you will need to update your database so that
    these nodes sort correctly with new nodes.</p> <p>%count nodes need to be
    updated.</p>', array(
    '%count' => $count,
  ));
  $output .= drupal_get_form('weight_setup_form');
  return $output;
}
function weight_setup_form() {
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Setup Database'),
  );
  return $form;
}
function weight_disable_page() {
  if ($_POST['op'] == t('Remove weights')) {
    weight_disable();
    drupal_goto('admin/modules');
  }
  $output .= t('<p>Before disabling the weight module, you will want to click
    this button to change the database back to Drupal\'s conventional sticky
    system.</p> <p><strong>NOTE: Clicking this button will erase any node weights
    that have been set.</strong></p>');
  $output .= drupal_get_form('weight_disable_form');
  return $output;
}
function weight_disable_form() {
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Remove weights'),
  );
  return $form;
}
function weight_settings_page() {
  if ($_POST['op'] == t('Update')) {
    $weight_range = check_plain($_POST['weight_range']);
    $weight_node_types = array_keys($_POST['weight_node_types']);
    $weight_use_menu = $_POST['weight_use_menu'];
    variable_set('weight_range', $weight_range);
    variable_set('weight_node_types', $weight_node_types);
    variable_set('weight_use_menu', $weight_use_menu);
    drupal_set_message(t('Settings updated.'));
  }
  $output .= drupal_get_form('weight_settings_form');
  return $output;
}
function weight_settings_form() {
  $form = array();
  $types = node_get_types('names');
  $form['weight_range'] = array(
    '#type' => 'select',
    '#title' => t('Node Weight Range'),
    '#default_value' => variable_get('weight_range', 20),
    '#options' => array(
      5 => 5,
      10 => 10,
      20 => 20,
      30 => 30,
      40 => 40,
      50 => 50,
      60 => 60,
      70 => 70,
      80 => 80,
      90 => 90,
    ),
    '#description' => t('<p>This will be the +/- range for node weight.</p>'),
  );
  $form['weight_use_menu'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use Menu Weight'),
    '#default_value' => variable_get('weight_use_menu', FALSE),
    '#description' => t('<p>If the node has not been weighted, should we use the menu item weight?</p>'),
  );
  $form['weight_node_types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Display On'),
    '#default_value' => variable_get('weight_node_types', $types),
    '#options' => $types,
    '#description' => t('<p>Add node weighting to these content types.</p>
      <p><i>Note:</i> Unselecting a node type after having changed weights
      for nodes of that type will leave these nodes with the current weight.
      You may want to check the <a href="@posts_page">Post page</a>. Before
      unsetting any node types.', array(
      '@posts_page' => url('admin/content/node'),
    )),
  );
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
  );
  return $form;
}

/**
 * Update "old" nodes where sticky is 1 or 0
 * And resave them with new values so that they will sort correctly
 * with new and updated nodes
 *
 */
function weight_old_nodes() {
  $count = db_num_rows(db_query('SELECT DISTINCT nid FROM {node} WHERE sticky IN (0,1)'));
  db_query('UPDATE {node} SET sticky = 100 WHERE sticky = 1');
  db_query('UPDATE {node} SET sticky = -100 WHERE sticky = 0');
  if ($count > 0) {
    drupal_set_message($count . t(' nodes updated to support weight.module'));
  }
  else {
    drupal_set_message(t('No nodes needed to be updated.'));
  }
}

/**
 * This function is not called from the module
 * It is here to show how to set the database back to "normal"
 * when deactivating the weight.module
 */
function weight_disable() {
  db_query('UPDATE {node} SET sticky = 1 WHERE sticky > 0');
  db_query('UPDATE {node} SET sticky = 0 WHERE sticky <= 0');
  drupal_set_message(t('All node weights have been removed. Please deactivate weight module now.'));
}

/**
 * Generate JS code for selecting individual node weights on admin page
 */
function weight_node_selector($nid) {
  static $js_included;
  if (!$js_included) {
    $path = drupal_get_path('module', 'weight');
    drupal_add_js($path . '/httpRequest.js', 'module', 'header', TRUE);
    $js_included = TRUE;
    drupal_add_css($path . '/weight.css');
  }
  $selector_template = "\n" . "<form><select style=\"margin: 0;\"\n    onchange='httpRequest(\"GET\", \"" . base_path() . "admin/node/weight/_change_weight/\" + [NID] + \"/\" +\n    this.options[this.selectedIndex].value,true)' >";

  //  $sticky = db_result(db_query('SELECT sticky FROM {node} WHERE nid = %d', $nid));
  $node = node_load($nid);

  // Convert to our weight range.
  //  _encoded_sticky2weight($node);
  $weight = $node->node_weight;

  // ugly bit of javascript we use for each dropdown to submit weight changes
  // in the background. Relies on even uglier httpRequest.js file that comes
  // with this module. Ironically, Ajax makes me feel dirty
  $weight_range = variable_get('weight_range', 20);
  for ($i = 0 - $weight_range; $i <= $weight_range; $i++) {
    $selector_template .= "<option value='{$i}'>{$i}</option>";
  }
  $selector_template .= '</select></form>';
  $weight_selector = $selector_template;

  // TODO: need node weight to be able to choose this!
  $weight_selector = preg_replace("/(value='{$weight}')/", "\$1 selected='selected'", $weight_selector);
  $weight_selector = preg_replace("/\\[NID\\]/", $nid, $weight_selector);
  $weight_selector = '<div class="weight-selector">' . $weight_selector . '</div>';
  $status = NULL;
  $status .= $node->sticky ? '<br />' . t('sticky') : NULL;
  $status .= $node->promote ? '<br />' . t('promoted') : NULL;
  $status .= $node->translate ? '<br />' . t('translate') : NULL;
  $status .= $node->moderate ? '<br />' . t('moderated') : NULL;
  return array(
    'selector' => $weight_selector,
    'status' => $status,
  );
}

// ajax callback for weight manager page
function _change_weight($nid, $weight) {

  // Doing it this way preserves the revision information.
  $node = node_load($nid);
  $node->node_weight = $weight;
  node_submit($node);
  node_save($node);
}

// Convert our weight to 'encoded' sticky value for DB.
function _weight2encoded_sticky(&$node) {
  if ($node->sticky) {
    $node->sticky = 100 - $node->node_weight;
  }
  else {
    $node->sticky = -($node->node_weight + 100);
  }
}

// Convert our weight back out of sticky.
function _encoded_sticky2weight(&$node) {
  if ($node->sticky > 0) {
    $node->node_weight = $node->sticky == 1 ? 0 : 100 - $node->sticky;
    $node->sticky = 1;
  }
  else {
    $node->node_weight = $node->sticky == 0 ? 0 : -($node->sticky + 100);
    $node->sticky = 0;
  }
}

Functions

Namesort descending Description
weight_disable This function is not called from the module It is here to show how to set the database back to "normal" when deactivating the weight.module
weight_disable_form
weight_disable_page
weight_enable_page
weight_form_alter Implementation of hook_form_alter().
weight_help Implementation of hook_help().
weight_menu Implementation of hook_menu().
weight_nodeapi
weight_node_selector Generate JS code for selecting individual node weights on admin page
weight_old_nodes Update "old" nodes where sticky is 1 or 0 And resave them with new values so that they will sort correctly with new and updated nodes
weight_perm
weight_settings_form
weight_settings_page
weight_setup_form
_change_weight
_encoded_sticky2weight
_weight2encoded_sticky