1

I want to create a 'suggested content' display that, by default, displays 4 nodes that share terms on a term reference field belonging to the currently node. So, if the current node is tagged with "baking" and "family", it should display nodes that have those terms in common. I have this working — all is good here.

Also, on the reference node I've added an entity reference field that allows editors to curate their own suggested content. My intention is to put this curated content at the beginning of the suggested results, so that if an editor specifies 2 nodes, the other view will populate the other 2 nodes.

Basically, what I think I need to do (correct me if I'm wrong), is to combine the results from two views (one displaying the curated nodes, the other displaying the term-related nodes), and limit them to the top 4 entries, ensuring that the curated nodes are displayed first.

If this was confusing, this image should make it clearer; enter image description here

How can I combine the results from two views and limit the combined result set? Also, note that each view only uses a single field for each row (a rendered node).

  • The way I have done this in the past is to feed the result node IDs from the first view to the second, where they are used as a combined argument of nodes to be excluded. I don't think there's a module that provides this functionality, though (could be wrong), I think I wrote some custom glue code to do it. (Could you edit your question to include the version of Drupal as a tag, by the way, please?) – Alfred Armstrong Apr 24 '18 at 15:27
  • Thanks Alfred. I've also done something like this in the past, but I can't remember what project it was, which isn't helpful at all. Frustrating! I tried doing something within a hook_views_pre_execute function, but can't seem to get it to work. Figure this question would help others if answered. Also, tagged at 7. – Aaron Silber Apr 25 '18 at 14:23
  • @Aaron-Silber isn't this just a matter of combining OR Filters on the same View (taxonomy and entityref filters)? And sorting them by curated nodes (entityref)? – prkos Apr 25 '18 at 23:31
  • @prkos I don't believe so. View 2 utilizes Contextual Filters and a Relationship. To my knowledge you can't apply AND/OR logic to those. Also, View 2 renders nodes, while View 1 renders an entity reference field's nodes (subtle, but different). – Aaron Silber Apr 25 '18 at 23:47
  • @AaronSilber I did this on a Drupal 8 project recently, which I realise is little help but basically it was an argument handler which executed another view and extracted the IDs from the result. – Alfred Armstrong Apr 26 '18 at 9:55
0

Here's what I ended up doing (not using views). I'm using Panels on this site, and my default view for this content-type is controlled via Panelizer. Since I couldn't find a way to do this with Views, I created a custom panels pane (code below).

Basically, this pane accepts one setting: the number of related events to display. The render callback counts the editor-defined related nodes, and grabs more (if needed) based on shared terms.

<?php

$plugin = array(
'single' => TRUE,
'title' => t('Suggested Events'),
'description' => t('Combines curated suggested events with those related by category.'),
'category' => t('Custom Panes'),
'edit form' => 'MYMODULE_suggested_events_edit_form',
'render callback' => 'MYMODULE_suggested_events_render',
'admin info' => 'MYMODULE_suggested_events_info',
'defaults' => array(
  'events_to_show' => 4
),
'all contexts' => TRUE,
);


/**
 * Edit Form.
 */
function MYMODULE_suggested_events_edit_form($form, &$form_state) {
$conf = $form_state['conf'];

$form['events_to_show'] = array(
  '#title' => t('Number of events to show'),
  '#description' => t('Used to control the number of suggested events shown. Defaults to 4.'),
  '#type' => 'select',
  '#options' => drupal_map_assoc(range(3, 6)),
  '#default_value' => $conf['events_to_show'],
  '#required' => TRUE,
);

return $form;
}


/**
 * Submit callback for settings form.
 */
function MYMODULE_suggested_events_edit_form_submit($form, &$form_state) {

foreach (array_keys($form_state['plugin']['defaults']) as $key) {
  if (isset($form_state['values'][$key])) {
    $form_state['conf'][$key] = $form_state['values'][$key];
  }
}
}


/**
 * Run-time rendering of the content
 */
function MYMODULE_suggested_events_render($subtype, $conf, $args, $contexts) {

  if (isset($contexts['panelizer'])) {
    $nid = $contexts['panelizer']->data->nid;
  } else {
    return false;
  }

  // Grab the Category Term IDs from referenced node.
  $node = node_load($nid);
  $categoryField = field_get_items('node', $node, 'field_category');
  $categoryTIDs = array_column($categoryField, 'tid');

  // suggestedEvents are the events which are selected by the editor.
  $suggestedEventsField = field_get_items('node', $node, 'field_event_suggested');

  if (empty($suggestedEventsField)) {
    $suggestedEvents = array();
  } else {
    $suggestedEventsNIDs = array_column($suggestedEventsField, 'target_id');
    $suggestedEvents = entity_load('node', $suggestedEventsNIDs ); // @returns array of entities
  }


  // determine how many events we need to find 
  // based upon the total to display and how many are site-editor-defined
  $relatedEvents = array();
  $relatedEventsCount = 0;
  if (count($suggestedEvents) < $conf['events_to_show']) {
    $relatedEventsCount = $conf['events_to_show'] - count($suggestedEvents);
  }

  if ($relatedEventsCount > 0) {
    // Query for other events that share the referenced categories.
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'event')
      ->propertyCondition('status', NODE_PUBLISHED)
      ->propertyCondition('nid', $nid, '<>')
      ->fieldCondition('field_category', 'tid', $categoryTIDs, 'IN')
      ->fieldCondition('field_datetime', 'value', date('Y-m-d').'00:00:00', '>=', 0)
      ->range(0, $relatedEventsCount)
      // Run the query as user 1.
      ->addMetaData('account', user_load(1));

    $result = $query->execute();
    if (isset($result['node'])) {
      $relatedEventsNIDs = array_keys($result['node']);
      $relatedEvents = entity_load('node', $relatedEventsNIDs);
    } 
  }

  $events = array_merge($suggestedEvents, $relatedEvents);

  $block = new stdClass();
  $block->title = 'You may also enjoy...';
  $block->content = '';
  if (!empty($events)) {
    $block->content .= '<div class="block__content">';
    $eventsRenderArray = entity_view('node', $events, 'showcase_card');
    $block->content .= render( $eventsRenderArray );
    $block->content .= '</div>';

    return $block;
  } else {
    return false;
  }


}


/**
 * Admin info.
 */
function MYMODULE_suggested_events_info($subtype, $conf, $contexts) {
if (!empty($conf)) {
  $block = new stdClass;
  $block->title = $conf['override_title'] ? $conf['override_title_text'] : '';
  $block->content = t('Show @events_to_show suggested events.', array(
    '@events_to_show' => $conf['events_to_show']
  ));

  return $block;
}
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.