1

I have a view where I want to output a list of content node teasers. At the moment all content nodes are used, but I want to filter the output to only contain nodes that have a certain value in a taxonomy field property they have, check if the current user has a certain role that is similar to the property and only then show them in the output.

So far I've tried to programmatically filter the output in the hook mytheme_preprocess_views_view_unformatted of my theme with the following code

function mytheme_preprocess_views_view_unformatted(&$variables) {
    $result = $variables['view']->result;
    $entity = $result->entity;
}

but that crashes the site and doesn't give me the results to filter.

Is there a way to filter the content nodes programmatically or view the view settings and if so how?

  • What does the error log message say? – hiew1 Jan 11 at 13:30
  • Notice: Trying to get property of non-object in mytheme_preprocess_views_view_unformatted() and some long stacktrace – plocks Jan 11 at 13:34
  • I'm not even sure if my approach is feasable here. – plocks Jan 11 at 13:34
  • 1
    As for the view setting, go to 'Structure', then go to 'Views', and you should be able to see next to the 'List' tab, there's a 'Settings' tab, click on that and since you are writing a filter to query the property, it will help to check the box "Show the SQL query". Then you should be able to see the SQL query as a reference to write your query programmatically. – hiew1 Jan 11 at 13:54
  • 1
    Then refer to the answer by Duncanmoo here: drupal.stackexchange.com/questions/26431/… it should point you in some direction, not a complete solution. – hiew1 Jan 11 at 13:55
2

I think I understand what you're describing, and it is theoretically possible to handle in the hook as you've started, with something like this:

/**
 * Implements hook_preprocess_views_view_unformatted().
 */
function mymodule_preprocess_views_view_unformatted(&$variables) {
  if (isset($variables['view'])) {
    $view = $variables['view'];
    // You'll want to check the ID && possibly the current_display so as not to fire on every View!
    // In this example, my View is called "test", and I have a page display called "page_1".
    if ($view->id() == "test" && $view->current_display == "page_1") {
      $result = $view->result;
      // You mentioned doing something regarding the user, so you could grab that here.
      $current_user = $variables['user']->account;
      // The $result will be an array of ResultRow entities.
      foreach ($result as $key => $resultRowEntity) {
        // Do some customized logic on each row.
        // You can access the entire entity here if needed like this:
        $row_entity = $resultRowEntity->_entity;
        // In my case this is a Node, so can do something to get a term field from it.
        // In this example, getting the "some_field" and the first delta of it as a string value.
        $some_field_on_the_node = $row_entity->get('field_some_field')->getValue();
        // You could do some sort of logic here to determine whether or not to unset this row.
        // In this example, I'll say if the field doesn't equal 2, OR the user ID is not equal to 1, unset the row.
        // This would remove it from the result.
        if ($some_field_on_the_node != "2" || $current_user->uid != 1) {
          // You'll want to unset it from 'rows' to not display it.
          unset($variables['rows'][$key]);
        }
      }
    }
  }
}

I think the takeaway is to use "isset" to avoid those nasty PHP errors, and I highly recommend using XDebug, or at the least the devel && kint modules, so that in your code, you can put things like ksm($variables['view']) to get some insight into what variables you have available to use. PHP can be very finicky when you try and reference things that don't exist!

Even though this might technically work, it's worth noting that a better approach would be to implement a relationship in Views to bring in the taxonomy term entity being referenced on your node, and that would allow you to add View filters in the UI to massage out the data that way. You could also add a role that could be associated with viewing your particular content type, and this would automatically exclude it from Views results regarding the user if they didn't have this role.

Of course, I may me misunderstanding the complexity of your use case. Another "better practice" approach would be to implement a custom Views filter, which could then be added via the Views UI and maintained separately in a custom module, and would possibly allow for a cleaner implementation - It's somewhat of a broad topic, but I think this is a great intro to the topic: https://www.webomelette.com/creating-custom-views-filter-drupal-8.

I hope this helps point you in the right direction!

  • Wow, thanks for the in depth answer, I'll look into it right away! – plocks Jan 11 at 14:38
  • With a few changes here and there the programmatical solutions works like a charm! Thanks again. – plocks Jan 11 at 15:23

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.