Dynamic sorting in Views for Drupal

Fri, 09/01/2017 - 11:41 -- admin

A common problem that I see when working with non-table views is dynamic sorting. It seems as if there's no easy way to make use of the sort functionality that views provides without using the table style. This is the method that I use to get around the problem. I'm not the first to do it this way, and I'm also not convinced it's the easiest way to do it. But it does work and we've used it without trouble.

I create a module to contain a function to handle the sorting. That makes it easier to make changes on the fly and keeps code out of the database where possible. You'll still have to do some work in the view, but it's minimal and hopefully self explanatory. Below, I've outlined the parts of the view that need to be edited or added. In this case I want to be able to sort on title or price, but your case will likely be different. Change the sort features as appropriate.

Create an argument of type "Global:Null". It can come at any point in you're list, but there must be an argument present in that url location or the code will not execute. I usually add a title or search type. Set the argument to display all values if not present and add a validator. Choose a PHP validator and add the following.

return _mymodule_handle_sortables($view);

That will allow you to edit the contents of the function quickly/easily without having to edit view / save view / preview view at each iteration. Note that I pass the $_GET variable. That's not strictly necessary, since it should be available in the function anyway. I just do it for easier readability.

First step, get the names of the sortable fields with the devel module

function _mymodule_handle_sortables(&$view) { dpm($view->sort); }

Preview the view and note the names of the fields. Once you've got them, you can do the following to alter the output of the view.

function _mymodule_handle_sortables(&$view) { switch ($_GET['sort']) { case 'sell_price_asc': unset($view->sort['title']); $view->sort['sell_price']->options['order'] = 'ASC'; break; case 'sell_price_desc': unset($view->sort['title']); $view->sort['sell_price']->options['order'] = 'DESC'; break; case 'alpha_asc': unset($view->sort['sell_price']); $view->sort['title']->options['order'] = 'ASC'; break; case 'alpha_desc': unset($view->sort['sell_price']); $view->sort['title']->options['order'] = 'DESC'; break; } return true; }

Add a PHP header to your view and add the following to it

Now you can dynamically display a sort header. Here's an admittedly overdone function to do that.

function _mymodule_sortables($g) { // Collect all the relevant GET parameters $gopts = array(); foreach ($g as $k=>$v) { if ($k == 'q') continue; $gopts[$k] = $v; } $opts = http_build_query($gopts); // Preserve the sort choice for selection $s1 = $s2 = $s3 = $s4 = ''; switch ($gopts['sort']) { case 'alpha_asc' : $s1 = 'selected="selected"';break; case 'alpha_desc' : $s2 = 'selected="selected"';break; case 'sell_price_asc' : $s3 = 'selected="selected"';break; case 'sell_price_desc' : $s4 = 'selected="selected"';break; } // Unset the sort option so that it can be set in the url manually below unset($gopts['sort']); $opts_sort = http_build_query($gopts); $output = "

Sorta-zz-a$ - $$$$ - $

"; return $output; }


Note also that I provide a means of choosing a different "display" within this view by preserving the url options and adding direct links. I've got a grid view and list view, the header provides links to the pages for each and preserves url options.

I ripped out some code for readability and to focus more on the point of this article, so let me know if you have any questions.