0

I have a view of all content, of all types, listed by date order. Paginated of course (with load more).

I want to find the latest piece of content of type X, and promote it/make it stick to the first result.

I was initially just going to use an attachment, but this comes with 2 problems.

  • The item ideally won't repeat
  • If it is already the first item, or in the first few results, there will be 2 right next to each other.

The item should not persist as the first item on each page, it should just be moved/re-ordered.

I feel like this should be very straight forward, but I am drawing a blank.

Any help most appreciated!

4 Answers 4

2

One thing you can do is set up a "sticky" view which pulls out the node you're looking for and then store the nid of the node. You could do this using hook_views_post_execute() in a custom module like so:

function MYMODULE_views_post_execute(&$view) {
  $nid = &drupal_static('MYMODULE_sticky_node_id');
  if(!empty($view->result)) {
    $nid = $view->result[0]->nid; // (or similar)
  }
}

(Replace all instances of "MYMODULE" with your module name)

Now if there is a result then it's nid should be stored in a static variable called 'MYMODULE_sticky_node_id'.

Next add a contextual filter of NID to the main view, leave "When the filter value is NOT in the URL" as "Display all results for the specified field", and under the "More" fieldset, tick "Exclude".

Next implement something like hook_views_pre_view():

function MYMODULE_views_pre_view(&$view, &$display_id, &$args) {
  if ($view->name == 'your_main_view_name') { // If need be add "&& $display_id == 'your_main_view_display_name'
    if ($nid = drupal_static('MYMODULE_sticky_node_id')) {
      $view->set_arguments(array($nid));
    }
  }
}

This will pull out the nid you saved while processing the sticky view and set it as the argument of the main view, therefore excluding it from that view.

You'll need to make sure that the sticky view is rendered before the main view for this to work.

Bear in mind that I haven't tested this exact code so it might need some tweaking to get it to work in context.

1
  • An interesting idea... I am actually looking at using hook_views_post_execute and reordering the results using a custom function to get the "promoted/sticky" nid. Aug 12, 2015 at 15:21
0

There are 3 option where you can those options can be seen:

  • admin/structure/types/manage/article

admin/structure/types/manage/article

  • on node/123/edit

 on node/123/edit

  • on admin/content

on admin/content

in Views - add sort type: "Node: Sticky" - descending order.

2
  • I think TO don't want to manually set the contect sticky and also if you sort the view by sticky, the sticky element still is not shown on every page as TO wants. Aug 12, 2015 at 12:31
  • Unfortunately, whilst this would make items "sticky", I don't want every item to be sticky, just the latest one. By this approach, the editor would have to manually set/update the content every time they added a new item. That said, you could use rules to set the latest one. Still, I left out that this content is also filtered by tag, so it is the latest of content X with the appropriate tag, so rules can't help either. Aug 12, 2015 at 13:26
0

If you use an attachment with the newest item, then you can skip the first item in the view by setting "Offset" to 1 in the Pager settings.

And your view should be sorted to show the newest item as first item, so this will be skipped from the views results.

Pager Settings

3
  • Definitely useful when pulling the first item into an attachment, but I am looking to pull an item that might be first, but might be 301... so by doing this you will 90% of the time lose one item from the list. Aug 12, 2015 at 13:28
  • You said you want to make the latest one sticky. So you can sort your view to have the latest one in first place and then skip this one. Or do you need another sorting on the view? Aug 12, 2015 at 15:15
  • Need the latest of type X to be promoted/sticky. It may be anyone of the results from first to last. Aug 12, 2015 at 15:18
0

So some credit to @paul-querol for pointing to hook_views_post_execute(), however the idea of using 2 views and custom code seems a bit odd to me… Views don't write the most efficient of queries, so for finding the promoted item I am using a custom function (although I have a bunch of extra things happening in there that views can't do).

Additionally, I want the "promoted" item to be treated the same as the other results, so don't want to be injecting info just befor render.

In the end it was very straight forward to push an item in, however you are getting that item.

My code:

/**
 * Implements hook_views_post_execute().
 */
function my_module_views_post_execute(&$view) {
  if ($view->name == 'view_name') {
    $results = $view->result;
    $promoted = '';
    $key = NULL;

    // Get promoted item.
    $target = _my_promoted_item _finding_function();

    if (!empty($target)) {
      // Loop through results.
      foreach ($results as $key => $item) {
        // Find our item of interest.
        if ($item->nid == $target['nid']) {
          $promoted = $results[$key];
          break;
        }
      }
    }

    // If we found the promoted item, and it isn't already first in the list.
    if (!empty($promoted) && ($key != 0)) {
      // Unset from current position and prepend to beginning.
      unset($results[$key]);
      array_unshift($results, $promoted);
    }

    $view->result = $results;

  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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