I would like to sort nodes based on nodequeue position in a View based on a Search API index.
But
- I can't add a Nodequeue relationship in my view
- I can't add the "nodequeue position" field to my search index

Is there a way to use Nodequeue module with views based on Search API module?

Thanks

Comments

kevster’s picture

I would love to do the same thing but not sure how - this would be very useful...

jody lynn’s picture

I needed this for a queue so I implemented it in a custom module for a specific queue. This could be expanded to work for all available queues.

/**
 * Implements hook_entity_property_info_alter().
 */
function custom_entity_property_info_alter(&$info) {
 $bundles = &$info['node']['bundles'];

  $bundles['BUNDLE_NAME']['properties']['queue_position'] = array(
    'type' => 'integer',
    'label' => 'Queue position',
    'getter callback' => 'custom_queue_position',
    'description' => t('Position in the nodequeue'),
    'entity views field' => TRUE,
  );
}

/**
 * Entity property getter callback: Returns the relevant nodequeue position for the queue.
 */
function custom nodequeue_position($entity, $options, $name, $entity_type, $info) {
  if ($pos = nodequeue_get_subqueue_position(MY_QUEUE_ID, $entity->nid)) {
    $subqueue = subqueue_load(MY_QUEUE_ID);
    // Easier to reverse the queue ordering so that we can order in a way that NULL/0 comes last.
    return -1 * (1+ $subqueue->count - $pos);
  }
}
mrharolda’s picture

@Jody Lynn thanks for the example! I had to extend it so that items are re-indexed after the nodequeue's sorting is changed:

/**
 * Implements hook_nodequeue_sort_alter().
 */
function MY_MODULE_nodequeue_sort_alter($nodes, $sqid) {
  $subqueue = subqueue_load($sqid);
  $queue = nodequeue_load($subqueue->qid);
  if ($queue->name != 'my_queue') {
    return;
  }

  $ids = array();
  foreach ($nodes as $pos => $node) {
    if (is_numeric($node['nid']) && $node['nid'] > 1) {
      $ids[] = $node['nid'];
    }
  }
  search_api_track_item_change('node', $ids);
}
tanc’s picture

Issue summary: View changes

Just wanted to say thank you to Jody Lynn and MrHaroldA for posting that code. Made the process quite painless.

charginghawk’s picture

For anybody stumbling across this, here's how I pulled it off most recently, based off the code above:

/**
 * Implements hook_entity_property_info_alter().
 */
function mymodule_core_entity_property_info_alter(&$info) {
  $info['node']['bundles']['client']['properties']['queue_position'] = array(
    'type' => 'integer',
    'label' => 'Queue position',
    'getter callback' => 'custom_queue_position',
    'description' => t('Position in the nodequeue'),
    'entity views field' => TRUE,
  );
}

/**
 * Entity property getter callback: Returns the relevant nodequeue position for the queue.
 */
function custom_queue_position($entity, $options, $name, $entity_type, $info) {
  $nq = nodequeue_load_queue_by_name('my_nodequeue');
  if ($pos = nodequeue_queue_position($nq->qid, $entity->nid)) {
    // nodequeue_load_subqueues_by_queue creates an array of subqueue objects
    // Assuming the nodequeue has one subqueue, pull out that object
    $subqueue = array_shift(array_values(nodequeue_load_subqueues_by_queue($nq->qid)));
    // Easier to reverse the queue ordering so that we can order in a way that NULL/0 comes last.
    return -1 * (1+ $subqueue->count - $pos);
  }
}

/**
 * Implements hook_nodequeue_sort_alter().
 */
function mymodule_core_nodequeue_sort_alter($nodes, $sqid) {
  $subqueue = subqueue_load($sqid);
  $queue = nodequeue_load($subqueue->qid);
  if ($queue->name != 'my_nodequeue') {
    return;
  }
  $ids = array();
  foreach ($nodes as $pos => $node) {
    if (is_numeric($node['nid']) && $node['nid'] > 1) {
      $ids[] = $node['nid'];
    }
  }
  search_api_track_item_change('node', $ids);
}
hmartens’s picture

Thanks guys, must I add this code to a "new" module or can I add it in the template.php?

Thanks.

charginghawk’s picture

I implemented it in a custom module.

thirstysix’s picture

But, I add "Queue Position" only in the field. Can't add a Nodequeue in the view relationship or view sort.

nadavoid’s picture

Thanks for all the code samples! I've made the following updates for my use case.

1. In the config of my nodequeue, I checked "Reverse in admin view". This means that the top item in the list in the admin view will have the largest number. If there are 4 items in the queue, the top item will have position 4. This removes the need to reverse the number in the entity property callback. You can simply store $pos as it truly is.

2. I used hook_nodequeue_update() because it's invoked after the nodequeue has been completely updated, instead of hook_nodequeue_sort_alter() which can be invoked even if the nodequeue is not successfully saved.

@satheeshkumar.six What you will need to do is in your search api configuration, add the new "queue_position" (according to the posted examples) field to the index. Then that field will be available to your view, without needing to add any relationships.

interdruper’s picture

If you use a queue with just one subqueue, it is easier just reference the subqueue:

/**
 * Implements hook_entity_property_info_alter().
 */
function MYMODULE_entity_property_info_alter(&$info) {
  $bundles = &$info['node']['bundles'];

  $bundles['MYBUNDLE']['properties']['queue_position'] = array(
    'type' => 'integer',
    'label' => 'Queue position',
    'getter callback' => '_MYMODULE_queue_position',
    'description' => t('Position in the nodequeue'),
    'entity views field' => TRUE,
  );
}

/**
 * Entity property getter callback: Returns the relevant nodequeue 0-indexed position for the queue.
 */
function _MYMODULE_queue_position($entity, $options, $name, $entity_type, $info) {
  $nq = nodequeue_load_subqueue_by_name('MYQUEUE');
  if ($pos = nodequeue_subqueue_position($nq->sqid, $entity->nid)) {
    $subqueue = array_shift(array_values(nodequeue_load_subqueues_by_queue($nq->sqid)));
    return -1 * (1+ $subqueue->count - $pos);
  }
}

/**
 * Implements hook_nodequeue_sort_alter().
 */
function MYMODULE_nodequeue_sort_alter($nodes, $sqid) {
  $subqueue = subqueue_load($sqid);
  $queue = nodequeue_load($subqueue->sqid);
  if ($queue->name != 'MYQUEUE') {
    return;
  }
  $ids = array();
  foreach ($nodes as $pos => $node) {
    if (is_numeric($node['nid']) && $node['nid'] > 1) {
      $ids[] = $node['nid'];
    }
  }
  search_api_track_item_change('node', $ids);
}

/**
 * Helper function to obtain the subqueue id from queue name
 */
function nodequeue_load_subqueue_by_name($name) {
  $query = db_select('nodequeue_subqueue', 'nsq')
    ->fields('nsq', array('sqid'))
    ->condition('nsq.name', $name);

  $result = $query->execute()->fetchObject();

  return subqueue_load($result->sqid);
}