You are here

nodequeue.module in Nodequeue 5

File

nodequeue.module
View source
<?php

// --------------------------------------------------------------------------
// Drupal Hooks

/**
 * Implementation of hook_perm
 */
function nodequeue_perm() {
  return array(
    'manipulate queues',
    'administer nodequeue',
    'manipulate all queues',
  );
}

/**
 * Implementation of hook_menu
 */
function nodequeue_menu($may_cache) {
  $items = array();
  global $user;
  if ($may_cache) {

    // administrative items
    $access = user_access('administer nodequeue');
    $items[] = array(
      'path' => 'admin/content/nodequeue',
      'title' => t('Node queue'),
      'access' => $access,
      'callback' => 'nodequeue_admin_page',
      'description' => t('Create and maintain simple node queues.'),
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/content/nodequeue/list',
      'title' => t('List'),
      'access' => $access,
      'callback' => 'nodequeue_admin_page',
      'weight' => -1,
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/content/nodequeue/add',
      'title' => t('Add'),
      'access' => $access,
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'nodequeue_queue_form',
      ),
      'type' => MENU_LOCAL_TASK,
    );
  }
  else {
    if ($user && arg(0) == 'node' && is_numeric(arg(1)) && arg(1) > 0 && ($access = user_access('manipulate queues'))) {
      $node = node_load(arg(1));
      if (nodequeue_node_access($node->type)) {
        $items[] = array(
          'path' => 'node/' . arg(1) . '/nodequeue',
          'title' => t('Node queue'),
          'access' => $access,
          'callback' => 'nodequeue_page',
          'callback arguments' => array(
            arg(1),
          ),
          'type' => MENU_LOCAL_TASK,
          'weight' => 5,
        );
      }
    }
    if ($access = user_access('administer nodequeue') && arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'nodequeue' && is_numeric(arg(3)) && ($queue = nodequeue_load(arg(3)))) {
      drupal_set_title("Nodequeue '{$queue->title}'");
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3),
        'title' => t('View'),
        'access' => $access,
        'callback' => 'nodequeue_admin_view',
        'callback arguments' => array(
          $queue,
        ),
        'type' => MENU_CALLBACK,
      );
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3) . '/view',
        'title' => t('View'),
        'access' => $access,
        'callback' => 'nodequeue_admin_view',
        'callback arguments' => array(
          $queue,
        ),
        'weight' => -10,
        'type' => MENU_DEFAULT_LOCAL_TASK,
      );
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3) . '/edit',
        'title' => t('Edit'),
        'access' => $access,
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'nodequeue_queue_form',
          $queue,
        ),
        'type' => MENU_LOCAL_TASK,
      );
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3) . '/delete',
        'title' => t('Delete'),
        'access' => $access,
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'nodequeue_admin_delete',
          $queue,
        ),
        'weight' => 5,
        'type' => MENU_CALLBACK,
      );
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3) . '/clear',
        'title' => t('Clear'),
        'access' => $access,
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'nodequeue_clear_confirm',
          $queue,
        ),
        'type' => MENU_CALLBACK,
      );
      $items[] = array(
        'path' => 'admin/content/nodequeue/' . arg(3) . '/oper',
        'title' => t('Operate'),
        'access' => $access,
        'callback' => 'nodequeue_admin_operate',
        'callback arguments' => array(
          $queue,
        ),
        'type' => MENU_CALLBACK,
      );
    }
  }
  return $items;
}

// --------------------------------------------------------------------------
// Nodequeue Admin pages

/**
 * Display the queue page for a node, allowing the user to control
 * how the node exists in various queues. This controls a couple
 * of different paths.
 */
function nodequeue_page($nid, $op = NULL, $qid = NULL) {
  $node = node_load($nid);
  drupal_set_title(check_plain($node->title));
  if (!nodequeue_node_access($node->type)) {
    return t('No node queue defined for this node type.');
  }
  else {
    if ($op && $qid) {
      $queue = nodequeue_load($qid);
      $js = !empty($_POST['js']);
      if ($queue) {
        if ($op == 'add') {
          _nodequeue_queue_add($queue, $nid);
          if ($js) {
            $return = new stdClass();
            $return->status = 1;
            $return->label = $queue->link_remove;
            $return->href = "node/{$nid}/nodequeue/remove/{$queue->qid}";
          }
        }
        elseif ($op == 'remove') {
          if ($pos = nodequeue_queue_position($qid, $nid)) {
            _nodequeue_queue_remove($queue, $pos);
          }
          if ($js) {
            $return = new stdClass();
            $return->status = 1;
            $return->label = $queue->link;
            $return->href = "node/{$nid}/nodequeue/add/{$queue->qid}";
          }
        }
        if (isset($return)) {
          print drupal_to_js($return);
          exit;
          return;
        }
        drupal_goto("node/{$nid}/nodequeue");
      }
    }
    return drupal_get_form('nodequeue_page_form', $node);
  }
}

/**
 * Display the queue controls for a node.
 */
function nodequeue_page_form($node) {

  // Determine which queues are appropriate for this nodetype.
  global $user;
  $roles_where = $roles_join = '';
  $roles = array();
  if (!user_access('manipulate all queues')) {
    $roles = array_keys((array) $user->roles) + array(
      DRUPAL_AUTHENTICATED_RID,
    );
    $role_args = array_fill(0, count($roles), '%d');
    $roles_join = "INNER JOIN {nodequeue_roles} nr ON nr.qid = nq.qid ";
    $roles_where = "AND nr.rid IN (" . implode(',', $role_args) . ") ";
  }

  // db_rewrite_sql should not be used here because the queue info needs
  // to always be correct here.
  $result = db_query("SELECT nq.qid, nq.title, nq.size, MAX(nqn.position) AS num_nodes " . "FROM {nodequeue_queue} nq " . "INNER JOIN {nodequeue_types} nt ON nt.qid = nq.qid " . "LEFT JOIN {nodequeue_nodes} nqn ON nqn.qid = nq.qid " . $roles_join . "WHERE nt.type = '%s' " . $roles_where . "GROUP BY nq.qid, nq.title, nq.size, nqn.position ORDER BY nq.title", array_merge(array(
    $node->type,
  ), $roles));
  $form = array();
  while ($queue = db_fetch_object($result)) {
    $form['title'][$queue->qid] = array(
      '#type' => 'markup',
      '#value' => $queue->title,
    );
    $form['size'][$queue->qid] = array(
      '#type' => 'markup',
      '#value' => $queue->size,
    );
    $form['num_nodes'][$queue->qid] = array(
      '#type' => 'markup',
      '#value' => $queue->num_nodes . ($queue->size && $queue->size == $queue->num_nodes ? ' ' . t('QUEUE FULL') : ''),
    );
    $ops = array(
      l(t('View queue'), "admin/content/nodequeue/{$queue->qid}/view"),
    );
    if (is_numeric($pos = db_result(db_query("SELECT position FROM {nodequeue_nodes} WHERE nid = %d AND qid = %d", $node->nid, $queue->qid)))) {
      $ops[] = l(t("Remove from queue"), "node/{$node->nid}/nodequeue/remove/{$queue->qid}/{$pos}");
    }
    else {
      $ops[] = l(t("Add to queue"), "node/{$node->nid}/nodequeue/add/{$queue->qid}");
    }
    $form['operations'][$queue->qid] = array(
      '#type' => 'markup',
      '#value' => implode(' | ', $ops),
    );
  }
  return $form;
}

/**
 * Theme function for nodequeue_page_form
 */
function theme_nodequeue_page_form($form) {
  $header = array(
    t('Title'),
    t('Max nodes'),
    t('In queue'),
    t('Operation'),
  );
  foreach (element_children($form['title']) as $key) {
    $row = array();
    $row[] = drupal_render($form['title'][$key]);
    $row[] = array(
      'data' => drupal_render($form['size'][$key]),
      'align' => 'right',
    );
    $row[] = array(
      'data' => drupal_render($form['num_nodes'][$key]),
      'align' => 'right',
    );
    $row[] = drupal_render($form['operations'][$key]);
    $rows[] = $row;
  }
  $output .= theme('table', $header, $rows);
  $output .= drupal_render($form);
  return $output;
}

/**
 * Display a list of queues and their status for the administrator.
 */
function nodequeue_admin_page() {
  $result = pager_query('SELECT nq.title, nq.qid, nq.size, COUNT(DISTINCT(nn.nid)) AS nodes FROM {nodequeue_queue} nq LEFT JOIN {nodequeue_nodes} nn ON nq.qid = nn.qid GROUP by nq.title, nq.qid, nq.size', 20, 0, 'SELECT COUNT(q.qid) FROM {nodequeue_queue} q');
  if (db_num_rows($result)) {
    $header = array(
      t('Title'),
      t('Max Nodes'),
      t('In Queue'),
      t('Operation'),
    );
    $rows = array();
    while ($queue = db_fetch_object($result)) {
      $rows[] = array(
        $queue->title,
        array(
          'data' => $queue->size,
        ),
        array(
          'data' => $queue->nodes,
        ),
        array(
          'data' => implode(' | ', array(
            l(t('Edit'), "admin/content/nodequeue/{$queue->qid}/edit"),
            l(t('View'), "admin/content/nodequeue/{$queue->qid}/view"),
            l(t('Delete'), "admin/content/nodequeue/{$queue->qid}/delete"),
          )),
        ),
      );
    }
    $output = theme('table', $header, $rows);
    $output .= theme('pager', NULL, 20);
    return $output;
  }
  else {
    return t('No node queues exist.');
  }
}

/**
 * Add or edit a queue.
 */
function nodequeue_queue_form($queue = NULL) {
  if (!$queue) {
    $queue = new stdClass();
  }
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Title'),
    '#default_value' => $queue->title,
    '#size' => 50,
    '#maxlength' => 64,
    '#description' => t('Enter the name of the queue'),
  );
  $form['size'] = array(
    '#type' => 'textfield',
    '#title' => t('Queue size'),
    '#default_value' => $queue->size,
    '#size' => 2,
    '#maxlength' => 2,
    '#description' => t('The maximum number of nodes will appear in the queue. Enter 0 for no limit'),
  );
  $form['link'] = array(
    '#type' => 'textfield',
    '#title' => t('Link "add to queue" text'),
    '#default_value' => $queue->link,
    '#size' => 40,
    '#maxlength' => 40,
    '#description' => t('If you want a link to add a node to a queue in the "links" section (next to "add new comment"), enter the text here. If left blank no link will be given; note that enabling this feature for any queue will cause an extra query to be run every time a node is loaded.'),
  );
  $form['link_remove'] = array(
    '#type' => 'textfield',
    '#title' => t('Link "remove from queue" text'),
    '#default_value' => $queue->link_remove,
    '#size' => 40,
    '#maxlength' => 40,
    '#description' => t('Enter the text for the corresponding link to remove a node from a queue. This may be blank (in which case no link will appear) but a remove link will only appear if link, above, is set.'),
  );
  $result = db_query("SELECT * FROM {role} ORDER BY name");
  while ($role = db_fetch_object($result)) {
    $roles[$role->rid] = $role->name;
  }
  $form['roles'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Roles'),
    '#default_value' => $queue->roles,
    '#options' => $roles,
    '#description' => t('Check each role that can add nodes to the queue.'),
  );
  foreach (node_get_types() as $type => $info) {
    $nodes[$type] = $info->name;
  }
  $form['types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Types'),
    '#default_value' => $queue->types,
    '#options' => $nodes,
    '#description' => t('Check each node type that can be added to this queue.'),
  );
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  if ($queue->qid) {
    $form[] = array(
      '#type' => 'submit',
      '#value' => t('Delete'),
    );
    $form['qid'] = array(
      '#type' => 'value',
      '#value' => $queue->qid,
    );
    $form['count'] = array(
      '#type' => 'value',
      '#value' => $queue->count,
    );
  }
  return $form;
}

/**
 * Submit function for the nodequeue_queue form.
 */
function nodequeue_queue_form_submit($formid, $form) {
  if ($_POST['op'] == t('Delete')) {
    return "admin/content/nodequeue/{$form['qid']}/delete";
  }
  $queue = (object) $form;

  // fix checkboxes; sigh
  foreach ($queue->roles as $role => $value) {
    if ($value) {
      $roles[] = $role;
    }
  }
  $queue->roles = $roles;
  foreach ($queue->types as $type => $value) {
    if ($value) {
      $types[] = $type;
    }
  }
  $queue->types = $types;
  nodequeue_save($queue);
  if ($queue->size) {

    // 0 means "don't care"
    _nodequeue_check_queuesize($queue);
  }
  drupal_set_message(t('The queue has been updated.'));
  return 'admin/content/nodequeue';
}

/**
 * Confirm form to delete a queue
 */
function nodequeue_admin_delete($queue) {
  $form['qid'] = array(
    '#type' => 'value',
    '#value' => $queue->qid,
  );
  return confirm_form($form, t('Are you sure you want to delete "%title"?', array(
    '%title' => $queue->title,
  )), $_GET['destination'] ? $_GET['destination'] : 'admin/content/nodequeue', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Submit function for nodequeue delete
 */
function nodequeue_admin_delete_submit($formid, $form) {
  if ($form['confirm']) {
    nodequeue_delete($form['qid']);
    drupal_set_message("The queue has been deleted.");
  }
  return 'admin/content/nodequeue';
}

/**
 * Page callback to operate on a queue, moving items up or down if 
 * javascript is disabled.
 */
function nodequeue_admin_operate($queue, $op = NULL, $pos = NULL) {
  switch ($op) {
    case 'up':
      nodequeue_queue_up($queue, $pos);
      break;
    case 'front':
      nodequeue_queue_front($queue, $pos);
      break;
    case 'down':
      nodequeue_queue_down($queue, $pos);
      break;
    case 'back':
      nodequeue_queue_back($queue, $pos);
    case 'remove':
      _nodequeue_queue_remove($queue, $pos);
  }
  return drupal_goto("admin/content/nodequeue/{$qid}/view");
}

/**
 * Page callback to view a queue.
 */
function nodequeue_admin_view($queue) {
  $qid = $queue->qid;
  $output = '';
  $output = '<p class="nodequeue-js-hide" style="display: none;">';
  $output .= t('Changes made to the queue order and queue removals will not be active until you click Save, below.');
  $output .= '</p>';
  $sql = "SELECT DISTINCT(n.nid), n.title, n.uid, u.name, n.created, nq.position FROM {node} n LEFT JOIN {users} u on n.uid = u.uid LEFT JOIN {nodequeue_nodes} nq ON nq.nid = n.nid WHERE nq.qid = {$qid} ORDER BY nq.position";

  // Don't rewrite because a queue manager has to be able to move items up
  // and down in the queue even if they can't be viewed.
  //  $sql = db_rewrite_sql($sql);
  $result = pager_query($sql, 25, 0);
  $list = array();
  $nids = array();
  if (db_num_rows($result) > 0) {
    while ($node = db_fetch_object($result)) {
      $buttons = l(theme('image', drupal_get_path('module', 'nodequeue') . '/go-up.png', t('Move up')), "admin/content/nodequeue/{$qid}/oper/up/{$node->position}", array(
        'title' => t('Move up'),
        'class' => 'nodequeue-move-up',
      ), NULL, NULL, FALSE, TRUE);
      $buttons .= l(theme('image', drupal_get_path('module', 'nodequeue') . '/go-down.png', t('Move down')), "admin/content/nodequeue/{$qid}/oper/down/{$node->position}", array(
        'title' => t('Move down'),
        'class' => 'nodequeue-move-down',
      ), NULL, NULL, FALSE, TRUE);
      $buttons .= l(theme('image', drupal_get_path('module', 'nodequeue') . '/go-top.png', t('Move to front')), "admin/content/nodequeue/{$qid}/oper/front/{$node->position}", array(
        'title' => t('Move to front'),
        'class' => 'nodequeue-move-front',
      ), NULL, NULL, FALSE, TRUE);
      $buttons .= l(theme('image', drupal_get_path('module', 'nodequeue') . '/go-bottom.png', t('Move to back')), "admin/content/nodequeue/{$qid}/oper/back/{$node->position}", array(
        'title' => t('Move to back'),
        'class' => 'nodequeue-move-back',
      ), NULL, NULL, FALSE, TRUE);
      $buttons .= l(theme('image', drupal_get_path('module', 'nodequeue') . '/user-trash.png', t('Remove from queue')), "admin/content/nodequeue/{$qid}/oper/remove/{$node->position}", array(
        'title' => t('Remove from queue'),
        'class' => 'nodequeue-remove',
      ), NULL, NULL, FALSE, TRUE);
      $list[] = array(
        'id' => 'nodequeue-row-' . $node->nid,
        'class' => 'nodequeue-row',
        'data' => array(
          l($node->title, "node/{$node->nid}"),
          theme('username', $node),
          format_date($node->created),
          $buttons,
        ),
      );
      $nids[] = $node->nid;
    }
    $header = array(
      t('Node'),
      t('Author'),
      t('Date'),
      t('Operation'),
    );
    $output .= theme('table', $header, $list, array(
      'width' => '100%',
      'id' => 'nodequeue-table',
    ));
    $output .= drupal_get_form('nodequeue_queue_admin', $qid, $nids);
    drupal_add_js(drupal_get_path('module', 'nodequeue') . '/nodequeue.js');
  }
  else {
    $output .= t('<p>Queue is empty!</p>');
  }
  return $output;
}

/**
 * Form used for administrating a queue
 */
function nodequeue_queue_admin($qid, $nids) {
  $form['qid'] = array(
    '#type' => 'value',
    '#value' => $qid,
  );
  $form['order'] = array(
    '#type' => 'hidden',
    '#id' => 'nodequeue-order',
    '#default_value' => implode(',', $nids),
  );
  $form['save'] = array(
    '#type' => 'submit',
    '#attributes' => array(
      'class' => 'nodequeue-js-hide nodequeue-save',
      'style' => 'display: none',
    ),
    '#value' => t('Save'),
  );
  $form['clear'] = array(
    '#type' => 'submit',
    '#value' => t('Clear queue'),
  );
  return $form;
}

/**
 * Submit function for nodequeue_queue_admin
 */
function nodequeue_queue_admin_submit($form_id, $form_values) {
  if ($form_values['op'] == t('Clear queue')) {
    return 'admin/content/nodequeue/' . $form_values['qid'] . '/clear';
  }
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d", $form_values['qid']);
  if ($form_values['op'] == t('Save') && $form_values['order']) {
    $counter = 1;
    $now = time();
    foreach (explode(',', $form_values['order']) as $nid) {
      db_query("INSERT INTO {nodequeue_nodes} (qid, nid, position, timestamp) VALUES (%d, %d, %d, %d)", $form_values['qid'], $nid, $counter++, $now);
    }
  }
  drupal_set_message(t('The queue has been updated'));
}

/**
 * Confirm form to clear a queue.
 */
function nodequeue_clear_confirm($queue) {
  $form['qid'] = array(
    '#type' => 'value',
    '#value' => $queue->qid,
  );
  return confirm_form($form, t('Clearing queue "%s" is irreversible. You sure?', array(
    '%s' => $queue->title,
  )), $_GET['destination'] ? $_GET['destination'] : "admin/content/nodequeue/{$queue->qid}/view", t('This action cannot be undone.'), t('Clear Queue'), t('Cancel'));
}

/**
 * Submit function for nodequeue clear confirm
 */
function nodequeue_clear_confirm_submit($formid, $form) {
  if ($form['confirm']) {
    nodequeue_queue_clear($form['qid']);
    return "admin/content/nodequeue/{$form['qid']}/view";
  }
}

/**
 * Implementation of hook_nodeapi
 */
function nodequeue_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'delete':

      // If a node is being deleted, ensure it's also removed from any queues.
      $result = db_query("SELECT * FROM {nodequeue_nodes} WHERE nid = %d", $node->nid);
      while ($obj = db_fetch_object($result)) {
        nodequeue_queue_remove($obj->qid, $obj->position);
      }
      break;
  }
}

/**
 * Implementation of hook_link
 */
function nodequeue_link($type, $node, $teaser) {
  if ($type == 'node' && variable_get('nodequeue_links', FALSE) && user_access('manipulate queues')) {
    $roles_join = $roles_where = '';
    $roles = array();
    if (!user_access('manipulate all queues')) {
      $roles_join = "INNER JOIN {nodequeue_roles} nr ON nr.qid = nq.qid ";
      $roles = array_keys((array) $user->roles) + array(
        DRUPAL_AUTHENTICATED_RID,
      );
      $role_args = array_fill(0, count($roles), '%d');
      $roles_where .= "AND nr.rid IN (" . implode(',', $role_args) . ")";
    }
    $sql = 'SELECT nq.qid, nq.link, nq.link_remove, nqn.position FROM {nodequeue_queue} nq ' . 'INNER JOIN {nodequeue_types} nt ON nt.qid = nq.qid ' . $roles_join . 'LEFT JOIN {nodequeue_nodes} nqn ON nqn.qid = nq.qid AND nqn.nid = %d ' . "WHERE link <> '' AND nt.type = '%s' " . $roles_where;
    $result = db_query($sql, array_merge(array(
      $node->nid,
      $node->type,
    ), $roles));
    $links = array();
    while ($queue = db_fetch_object($result)) {
      if (!$queue->position) {
        $links['nodequeue-ajax-toggle-' . $queue->qid] = array(
          'title' => $queue->link,
          'href' => "node/{$node->nid}/nodequeue/add/{$queue->qid}",
          'attributes' => array(
            'class' => 'nodequeue-ajax-toggle',
          ),
          'query' => drupal_get_destination(),
        );
      }
      else {
        if ($queue->link_remove) {
          $links['nodequeue-ajax-toggle-' . $queue->qid] = array(
            'title' => $queue->link_remove,
            'href' => "node/{$node->nid}/nodequeue/remove/{$queue->qid}",
            'attributes' => array(
              'class' => 'nodequeue-ajax-toggle',
            ),
            'query' => drupal_get_destination(),
          );
        }
      }
    }
    drupal_add_js(drupal_get_path('module', 'nodequeue') . '/nodequeue.js');
  }
  return $links;
}

// --------------------------------------------------------------------------
// Database manipulation functions

/**
 * Return TRUE if $user can
 * control the queue for this node.
 */
function nodequeue_node_access($type) {
  global $user;
  $roles_join = $roles_where = '';
  $roles = array();

  // superuser always has access.
  if (!user_access('manipulate all queues')) {
    $roles_join = "INNER JOIN {nodequeue_roles} nr ON nr.qid = nq.qid ";
    $roles = array_keys((array) $user->roles) + array(
      DRUPAL_AUTHENTICATED_RID,
    );
    $role_args = array_fill(0, count($roles), '%d');
    $roles_where .= "AND nr.rid IN (" . implode(',', $role_args) . ")";
  }
  $sql = 'SELECT nq.qid FROM {nodequeue_queue} nq ' . 'INNER JOIN {nodequeue_types} nt ON nt.qid = nq.qid ' . $roles_join . "WHERE nt.type = '%s' " . $roles_where;
  $result = db_query($sql, array_merge(array(
    $type,
  ), $roles));
  return db_num_rows($result);
}
function _nodequeue_load($qid, $nodes = false) {

  // passthrough for compatibility
  return nodequeue_load($qid, $nodes);
}
function nodequeue_load($qid, $nodes = false) {
  $queue = db_fetch_object(db_query("SELECT * FROM {nodequeue_queue} WHERE qid = %d", $qid));
  if ($queue) {
    $result = db_query("SELECT rid FROM {nodequeue_roles} WHERE qid = %d", $qid);
    while ($obj = db_fetch_object($result)) {
      $queue->roles[] = $obj->rid;
    }
    $result = db_query("SELECT type FROM {nodequeue_types} WHERE qid = %d", $qid);
    while ($obj = db_fetch_object($result)) {
      $queue->types[] = $obj->type;
    }
    $queue->count = db_result(db_query("SELECT count(*) from {nodequeue_nodes} where qid = %d", $qid));
    if ($nodes) {
      $result = db_query("SELECT nid FROM {nodequeue_nodes} WHERE qid = {$qid} ORDER BY position");
      while ($obj = db_fetch_object($result)) {
        $queue->nodes[] = $obj->nid;
      }
    }
  }
  return $queue;
}
function _nodequeue_save($queue, $nodes = false) {

  // passthrough for compatibility with older versions
  return nodequeue_save($queue, $nodes);
}
function nodequeue_save($queue, $nodes = false) {
  $queue->size = intval($queue->size);
  $title = db_escape_string($queue->title);
  if (!$queue->qid) {
    $queue->qid = db_next_id("{nodequeue_queue}_qid");
    db_query("INSERT INTO {nodequeue_queue} (qid, title, size, link, link_remove) VALUES (%d, '%s', %d, '%s', '%s')", $queue->qid, $title, $queue->size, $queue->link, $queue->link_remove);
    if (function_exists('views_invalidate_cache')) {
      views_invalidate_cache();
    }
  }
  else {
    $queue->qid = intval($queue->qid);
    db_query("UPDATE {nodequeue_queue} set size = %d, title = '%s', link = '%s', link_remove = '%s' WHERE qid = %d", $queue->size, $title, $queue->link, $queue->link_remove, $queue->qid);
    db_query("DELETE FROM {nodequeue_roles} WHERE qid = %d", $queue->qid);
    db_query("DELETE FROM {nodequeue_types} WHERE qid = %d", $queue->qid);
    if ($nodes) {
      db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d", $queue->qid);
    }
  }
  if (is_array($queue->roles)) {
    foreach ($queue->roles as $rid) {
      db_query("INSERT INTO {nodequeue_roles} (qid, rid) VALUES (%d, %d)", $queue->qid, $rid);
    }
  }
  if (is_array($queue->types)) {
    foreach ($queue->types as $type) {
      db_query("INSERT INTO {nodequeue_types} (qid, type) VALUES (%d, '%s')", $queue->qid, $type);
    }
  }
  if ($nodes && is_array($queue->nodes)) {
    foreach ($queue->nodes as $nid) {
      db_query("INSERT INTO {nodequeue_roles} (qid, nid, position) VALUES (%d, %d, %d)", $queue->qid, $nid, ++$position);

      // Stop if we somehow have more nodes in the queue than are allowed.
      if ($queue->size && $position >= $queue->size) {
        break;
      }
    }
  }

  // set our global that tells us whether or not we need to activate hook_link
  if (db_result(db_query("SELECT COUNT(*) FROM {nodequeue_queue} WHERE link != ''"))) {
    variable_set('nodequeue_links', TRUE);
  }
  else {
    variable_set('nodequeue_links', FALSE);
  }
  return $queue->qid;
}
function _nodequeue_delete($qid) {

  // passthrough
  return nodequeue_delete($qid);
}
function nodequeue_delete($qid) {
  db_query("DELETE FROM {nodequeue_queue} WHERE qid = %d", $qid);
  db_query("DELETE FROM {nodequeue_roles} WHERE qid = %d", $qid);
  db_query("DELETE FROM {nodequeue_types} WHERE qid = %d", $qid);
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d", $qid);
}

// --------------------------------------------------------------------------
// Queue position control
function nodequeue_queue_swap($queue, $pos1, $pos2) {

  // Grab the nid off one of the positions so we can more easily swap.
  $nid = db_result(db_query("SELECT nid FROM {nodequeue_nodes} WHERE qid = %d AND position = %d", $queue->qid, $pos1));
  if (!$nid) {
    return;
  }
  db_query("UPDATE {nodequeue_nodes} SET position = %d WHERE position = %d AND qid = %d", $pos1, $pos2, $queue->qid);
  db_query("UPDATE {nodequeue_nodes} SET position = %d WHERE nid = %d AND qid = %d", $pos2, $nid, $queue->qid);
}
function nodequeue_queue_up($queue, $position) {
  if ($position < 2 || $position > $queue->count) {
    return;
  }
  nodequeue_queue_swap($queue, $position - 1, $position);
}
function nodequeue_queue_down($queue, $position) {
  if ($position < 1 || $position >= $queue->count) {
    return;
  }
  nodequeue_queue_swap($queue, $position + 1, $position);
}
function nodequeue_queue_front($queue, $position) {
  if ($position < 2 || $position > $queue->count) {
    return;
  }
  $entry = db_fetch_object(db_query("SELECT * FROM {nodequeue_nodes} WHERE qid= %d AND position = %d", $queue->qid, $position));
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d AND position = %d", $queue->qid, $position);
  db_query("UPDATE {nodequeue_nodes} SET position = position + 1 WHERE qid= %d AND position < %d", $queue->qid, $position);
  db_query("INSERT INTO {nodequeue_nodes} (qid, nid, position, timestamp) VALUES (%d, %d, 1, %d)", $queue->qid, $entry->nid, $entry->timestamp);
}
function nodequeue_queue_back($queue, $position) {
  if ($position < 1 || $position >= $queue->count) {
    return;
  }
  $entry = db_fetch_object(db_query("SELECT * FROM {nodequeue_nodes} WHERE qid = %d AND position = %d", $queue->qid, $position));
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d AND position = %d", $queue->qid, $position);
  db_query("UPDATE {nodequeue_nodes} SET position = position - 1 WHERE qid = %d AND position > %d", $queue->qid, $position);
  db_query("INSERT INTO {nodequeue_nodes} (qid, nid, position, timestamp) VALUES (%d, %d, %d, %d)", $queue->qid, $entry->nid, $queue->count, $entry->timestamp);
}
function _nodequeue_queue_remove(&$queue, $start, $end = 0) {
  if (!$end) {
    $end = $start;
  }
  $diff = $end - $start + 1;
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d AND position >= %d AND position <= %d", $queue->qid, $start, $end);
  db_query("UPDATE {nodequeue_nodes} SET position = position - %d WHERE qid = %d AND position > %d", $diff, $queue->qid, $end);
  $queue->count -= $diff;
}
function _nodequeue_queue_add(&$queue, $nid) {

  // Check for uniqueness
  if (db_result(db_query("SELECT nid from {nodequeue_nodes} WHERE qid = %d AND nid = %d", $queue->qid, $nid))) {
    return;
  }

  // Really, it should never happen that a queue gets bigger than is possible,
  // but just in case.
  if ($queue->size) {

    // 0 means infinity so never do this if false
    _nodequeue_check_queuesize($queue, $queue->size - 1);
  }
  $nid = intval($nid);
  $queue->count++;
  db_query("INSERT INTO {nodequeue_nodes} (qid, nid, position, timestamp) VALUES (%d, %d, %d, %d)", $queue->qid, $nid, $queue->count, time());
}
function nodequeue_queue_clear($qid) {
  db_query("DELETE FROM {nodequeue_nodes} WHERE qid = %d", $qid);
}
function _nodequeue_check_queuesize(&$queue, $size = FALSE) {
  if ($size === FALSE) {
    $size = $queue->size;
  }
  if ($queue->count > $size) {
    _nodequeue_queue_remove($queue, 1, $queue->count - $size);
  }
}

/**
 * Get the position of a node in a queue, or 0 if not found.
 */
function nodequeue_queue_position($qid, $nid) {
  return db_result(db_query("SELECT position FROM {nodequeue_nodes} WHERE qid = %d AND nid = %d", $qid, $nid));
}

// --------------------------------------------------------------------------
// Actions module
function action_nodequeue_add($op, $edit = array(), $node) {
  switch ($op) {
    case 'metadata':
      return array(
        'description' => t('Add to Node Queue'),
        'type' => t('node'),
        'batchable' => true,
        'configurable' => true,
      );
      break;
    case 'do':
      $qid = $edit['qid'];
      nodequeue_queue_add($qid, $node->nid);
      break;

    // return an HTML config form for the action
    case 'form':

      // default values for form
      if (!isset($edit['qid'])) {
        $edit['qid'] = '';
      }
      $result = db_query("SELECT * from {nodequeue_queue} ORDER BY title");
      while ($obj = db_fetch_object($result)) {
        $queues[$obj->qid] = $obj->title;
      }

      // add form components
      $form['qid'] = array(
        '#type' => 'select',
        '#title' => t("Queue"),
        '#default_value' => $edit['qid'],
        '#options' => $queues,
      );
      return $form;

    // validate the HTML form
    // process the HTML form to store configuration
    case 'submit':
      $params = array(
        'qid' => $edit['qid'],
      );
      return $params;
      break;
  }
}
function action_nodequeue_remove($op, $edit = array(), $node) {
  switch ($op) {
    case 'metadata':
      return array(
        'description' => t('Remove from Node Queue'),
        'type' => t('node'),
        'batchable' => true,
        'configurable' => true,
      );
      break;
    case 'do':
      $qid = $edit['qid'];
      nodequeue_queue_remove_node($qid, $node->nid);
      break;

    // return an HTML config form for the action
    case 'form':

      // default values for form
      if (!isset($edit['qid'])) {
        $edit['qid'] = '';
      }
      $result = db_query("SELECT * from {nodequeue_queue} ORDER BY title");
      while ($obj = db_fetch_object($result)) {
        $queues[$obj->qid] = $obj->title;
      }

      // add form components
      $form['qid'] = array(
        '#type' => 'select',
        '#title' => t("Queue"),
        '#default_value' => $edit['qid'],
        '#options' => $queues,
      );
      return $form;
      break;

    // validate the HTML form
    // process the HTML form to store configuration
    case 'submit':
      $params = array(
        'qid' => $edit['qid'],
      );
      return $params;
      break;
  }
}

// --------------------------------------------------------------------------
// External queue fetching

/**
 * in general it's preferable to use Views for this functionality.
 */
function nodequeue_node_titles($qid, $title = '', $backward = true, $from = 0, $count = 0) {
  $orderby = $backward ? "DESC" : "ASC";
  $sql = db_rewrite_sql("SELECT n.nid, n.title FROM {node} n LEFT JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.qid = %d AND n.status = 1 ORDER BY nn.position {$orderby}");
  if ($count) {
    $result = db_query_range($sql, $qid, $from, $count);
  }
  else {
    $result = db_query($sql, $qid);
  }
  return node_title_list($result, $title);
}
function nodequeue_nodes($qid, $backward = true, $teaser = true, $links = true, $from = 0, $count = 0) {
  $orderby = $backward ? "DESC" : "ASC";
  $sql = db_rewrite_sql("SELECT n.nid FROM {node} n INNER JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.qid = %d AND n.status = 1 ORDER BY nn.position {$orderby}");
  if ($count) {
    $result = db_query_range($sql, $qid, $from, $count);
  }
  else {
    $result = db_query($sql, $qid);
  }
  while ($nid = db_fetch_object($result)) {
    $node = node_load($nid->nid);
    $output .= node_view($node, $teaser, false, $links);
  }
  return $output;
}
function nodequeue_fetch_front($qid, $teaser = true, $links = true) {
  return nodequeue_nodes($qid, false, $teaser, $links, 0, 1);
}
function nodequeue_fetch_back($qid, $teaser = true, $links = true) {
  return nodequeue_nodes($qid, true, $teaser, $links, 0, 1);
}
function nodequeue_fetch_random($qid, $teaser = true, $links = true) {
  $count = db_result(db_query("SELECT count(*) FROM {nodequeue_nodes} WHERE qid = %d", $qid));
  return nodequeue_nodes($qid, false, $teaser, $links, rand(0, $count - 1), 1);
}
function nodequeue_queue_add($qid, $nid) {
  $queue = _nodequeue_load($qid);
  if ($queue) {
    _nodequeue_queue_add($queue, $nid);
  }
}
function nodequeue_queue_remove($qid, $start, $end = 0) {
  $queue = _nodequeue_load($qid);
  if ($queue) {
    _nodequeue_queue_remove($queue, $start, $end);
  }
}
function nodequeue_queue_remove_node($qid, $nid) {
  if ($pos = nodequeue_queue_position($qid, $nid)) {
    nodequeue_queue_remove($qid, $pos);
  }
}

// ---------------------------------------------------------------------------
// Views support
function nodequeue_views_tables() {
  $tables['nodequeue_nodes'] = array(
    "name" => "nodequeue_nodes",
    "join" => array(
      "left" => array(
        "table" => "node",
        "field" => "nid",
      ),
      "right" => array(
        "field" => "nid",
      ),
    ),
    "fields" => array(
      'timestamp' => array(
        'name' => t('NodeQueue: Timestamp'),
        'sortable' => true,
        'handler' => views_handler_field_dates(),
        'option' => 'string',
        'help' => t('Display the time the node was added to a given node queue.') . ' ' . t('The option field may be used to specify the custom date format as it\'s required by the date() function or if "as time ago" has been chosen to customize the granularity of the time interval.'),
      ),
    ),
    "filters" => array(
      "qid" => array(
        'name' => "NodeQueue: Queue",
        'list' => 'nodequeue_handler_queuelist',
        'operator' => 'views_handler_operator_andor',
        'help' => t('Filter the view to a specific Node Queue.'),
      ),
      "position" => array(
        'name' => "NodeQueue: Queue Position",
        'field' => 'position',
        'operator' => 'views_handler_operator_gtlt',
        'help' => t('Filter by where in the queue an item is.'),
      ),
      "timestamp" => array(
        'name' => t('NodeQueue: Queue Timestamp'),
        'operator' => 'views_handler_operator_gtlt',
        'value' => views_handler_filter_date_value_form(),
        'handler' => 'views_handler_filter_timestamp',
        'option' => 'string',
        'help' => t('This filter allows nodes to be filtered by the time they were added to a given NodeQueue.') . ' ' . views_t_strings('filter date'),
      ),
    ),
    "sorts" => array(
      "position" => array(
        'name' => "NodeQueue: Queue Position",
        'field' => 'position',
        'help' => t('When sorting by queue position, be sure the view is filtered to a single queue or the sort will not work very well.'),
      ),
      'timestamp' => array(
        'name' => t('NodeQueue: Timestamp'),
        'handler' => 'views_handler_sort_date',
        'option' => views_handler_sort_date_options(),
        'help' => t('Sort by the time the node was added to a node queue.'),
      ),
    ),
  );
  $tables['nodequeue_queue'] = array(
    "name" => "nodequeue_queue",
    "join" => array(
      "left" => array(
        "table" => "nodequeue_nodes",
        "field" => "qid",
      ),
      "right" => array(
        "field" => "qid",
      ),
    ),
  );
  return $tables;
}
function nodequeue_views_arguments() {
  $arguments = array(
    'nodequeue_qid' => array(
      'name' => t("NodeQueue: Queue ID"),
      'handler' => "nodequeue_handler_arg_qid",
      'help' => t('The Queue ID argument allows users to filter a view by specifying a Node Queue ID.'),
    ),
    'nodequeue_qtitle' => array(
      'name' => t("NodeQueue: Queue Title"),
      'handler' => "nodequeue_handler_arg_qtitle",
      'help' => t('The Queue Title argument allows users to filter a view by specifying a Node Queue Title.'),
    ),
  );
  return $arguments;
}
function nodequeue_views_default_views() {
  $result = db_query("SELECT * FROM {nodequeue_queue}");
  while ($queue = db_fetch_object($result)) {
    $view = new stdClass();
    $view->name = "nodequeue_{$queue->qid}";
    $view->disabled = TRUE;
    $view->description = t('View node queue ') . check_plain($queue->title);
    $view->access = array();
    $view->view_args_php = '';
    $view->page = TRUE;
    $view->page_title = check_plain($queue->title);
    $view->page_header = '';
    $view->page_header_format = '1';
    $view->page_footer = '';
    $view->page_footer_format = '1';
    $view->page_empty = '';
    $view->page_empty_format = '1';
    $view->page_type = 'teaser';
    $view->url = 'nodequeue/' . $queue->qid;
    $view->use_pager = TRUE;
    $view->nodes_per_page = '10';
    $view->block = TRUE;
    $view->block_title = check_plain($queue->title);
    $view->block_header = '';
    $view->block_header_format = '1';
    $view->block_footer = '';
    $view->block_footer_format = '1';
    $view->block_empty = '';
    $view->block_empty_format = '1';
    $view->block_type = 'list';
    $view->nodes_per_block = '5';
    $view->block_more = TRUE;
    $view->block_use_page_header = FALSE;
    $view->block_use_page_footer = FALSE;
    $view->block_use_page_empty = FALSE;
    $view->sort = array(
      array(
        'tablename' => 'nodequeue_nodes',
        'field' => 'position',
        'sortorder' => 'ASC',
        'options' => '',
      ),
    );
    $view->argument = array();
    $view->field = array(
      array(
        'tablename' => 'node',
        'field' => 'title',
        'label' => '',
        'handler' => 'views_handler_field_nodelink',
        'options' => 'link',
      ),
    );
    $view->filter = array(
      array(
        'tablename' => 'nodequeue_nodes',
        'field' => 'qid',
        'operator' => 'OR',
        'options' => '',
        'value' => array(
          $queue->qid,
        ),
      ),
    );
    $view->exposed_filter = array();
    $view->requires = array(
      'nodequeue_nodes',
      'node',
    );
    $views[$view->name] = $view;
  }
  return $views;
}
function nodequeue_handler_queuelist() {
  $result = db_query("SELECT * FROM {nodequeue_queue} ORDER BY title");
  while ($queue = db_fetch_object($result)) {
    $items[$queue->qid] = $queue->title;
  }
  return $items;
}
function nodequeue_handler_arg_qid($op, &$query, $argtype, $arg = '') {
  switch ($op) {
    case 'summary':
      $query
        ->ensure_table('nodequeue_queue', true);
      $query
        ->add_field('title', 'nodequeue_queue');
      $query
        ->add_field('qid', 'nodequeue_queue');
      $query
        ->add_where('nodequeue_queue.qid IS NOT NULL');
      $fieldinfo['field'] = "nodequeue_queue.title";
      return $fieldinfo;
      break;
    case 'sort':
      $query
        ->add_orderby('nodequeue_queue', 'title', $argtype);
      break;
    case 'filter':
      $qid = intval($arg);
      $query
        ->ensure_table('nodequeue_queue', true);
      $query
        ->add_where("nodequeue_queue.qid = %d", $qid);
      break;
    case 'link':
      return l($query->title, "{$arg}/" . intval($query->qid));
    case 'title':
      $queue = db_fetch_object(db_query("SELECT title FROM {nodequeue_queue} WHERE qid = %d", $query));
      return $queue->title;
  }
}
function nodequeue_handler_arg_qtitle($op, &$query, $argtype, $arg = '') {
  switch ($op) {
    case 'summary':
      $query
        ->ensure_table('nodequeue_queue', true);
      $query
        ->add_field('title', 'nodequeue_queue');
      $query
        ->add_field('qid', 'nodequeue_queue');
      $query
        ->add_where('nodequeue_queue.qid IS NOT NULL');
      $fieldinfo['field'] = "nodequeue_queue.title";
      return $fieldinfo;
      break;
    case 'sort':
      $query
        ->add_orderby('nodequeue_queue', 'title', $argtype);
      break;
    case 'filter':
      $qtitle = $arg;
      $query
        ->ensure_table('nodequeue_queue', true);
      $query
        ->add_where("nodequeue_queue.title = '%s'", $qtitle);
      break;
    case 'link':
      return l($query->title, "{$arg}/" . intval($query->qid));
    case 'title':
      return check_plain($query);
  }
}

Functions

Namesort descending Description
action_nodequeue_add
action_nodequeue_remove
nodequeue_admin_delete Confirm form to delete a queue
nodequeue_admin_delete_submit Submit function for nodequeue delete
nodequeue_admin_operate Page callback to operate on a queue, moving items up or down if javascript is disabled.
nodequeue_admin_page Display a list of queues and their status for the administrator.
nodequeue_admin_view Page callback to view a queue.
nodequeue_clear_confirm Confirm form to clear a queue.
nodequeue_clear_confirm_submit Submit function for nodequeue clear confirm
nodequeue_delete
nodequeue_fetch_back
nodequeue_fetch_front
nodequeue_fetch_random
nodequeue_handler_arg_qid
nodequeue_handler_arg_qtitle
nodequeue_handler_queuelist
nodequeue_link Implementation of hook_link
nodequeue_load
nodequeue_menu Implementation of hook_menu
nodequeue_nodeapi Implementation of hook_nodeapi
nodequeue_nodes
nodequeue_node_access Return TRUE if $user can control the queue for this node.
nodequeue_node_titles in general it's preferable to use Views for this functionality.
nodequeue_page Display the queue page for a node, allowing the user to control how the node exists in various queues. This controls a couple of different paths.
nodequeue_page_form Display the queue controls for a node.
nodequeue_perm Implementation of hook_perm
nodequeue_queue_add
nodequeue_queue_admin Form used for administrating a queue
nodequeue_queue_admin_submit Submit function for nodequeue_queue_admin
nodequeue_queue_back
nodequeue_queue_clear
nodequeue_queue_down
nodequeue_queue_form Add or edit a queue.
nodequeue_queue_form_submit Submit function for the nodequeue_queue form.
nodequeue_queue_front
nodequeue_queue_position Get the position of a node in a queue, or 0 if not found.
nodequeue_queue_remove
nodequeue_queue_remove_node
nodequeue_queue_swap
nodequeue_queue_up
nodequeue_save
nodequeue_views_arguments
nodequeue_views_default_views
nodequeue_views_tables
theme_nodequeue_page_form Theme function for nodequeue_page_form
_nodequeue_check_queuesize
_nodequeue_delete
_nodequeue_load
_nodequeue_queue_add
_nodequeue_queue_remove
_nodequeue_save