It's a fairly common use case to have A-Z lists filterable, e.g. on http://d8.thegalleryguide.co.uk/galleries/a-z/a

A natural user expectation would be for the filter to match the sort, by making the natural sort value available as a contextual filter.

That way, when setting up this kind of glossary view, items like "The Agency" would appear under "A" rather than "T"

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

malcomio created an issue. See original summary.

generalredneck’s picture

That's an intesting scenario. You try it with exposed filters? In the filter use the starting with operation and expose the value. Then you should be able to at the very least use the query string to achieve what you want. I'be never tried to accomplish your scenario in core with normal sorting before.

malcomio’s picture

On the D6 version of the site, I added an extra computed field for the "sort title", and used glossary mode on that as an argument: http://thegalleryguide.co.uk/galleries/a-z/a

I think for D8, it'll be necessary to create a filter and/or argument plugin in views_natural_sort to make it available as a filter, won't it?

generalredneck’s picture

Yeah. Would be a new filter plugin to do that. As for glossary... I do have a ticket for glossary support in d7. That will be something to port to d8 as well.

generalredneck’s picture

malcomio’s picture

I couldn't get my head around how to implement a new argument plugin, so I ended up achieving this with a views_query_alter implementation on a view where I was setting glossary mode on the title. It feels a little bit hacky, but it gets the job done.


/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter($view, $query) {
  // make sure we're altering the correct view
  if ($view->storage->get('id') === 'galleries_a_z' && $view->current_display === 'page_1') {
    $definition = [
      'table' => 'views_natural_sort',
      'field' => 'eid',
      'left_table' => 'node_field_data',
      'left_field' => 'nid',
    ];
    $join = Drupal::service('plugin.manager.views.join')->createInstance('standard', $definition);
    $query->addRelationship('views_natural_sort', $join, 'views_natural_sort');

    // foreach top level condition group
    foreach ($query->where as &$condition_group) {
      // call helper function to recursively alter conditions
      _recursively_alter_query_conditions($condition_group['conditions']);
    }
  }
}

/**
 * Helper function to loop through query conditions.
 */
function _recursively_alter_query_conditions(&$conditions) {
  // foreach condition in condition group
  foreach ($conditions as &$condition) {
    // if condition is itself a condition group
    if (isset($condition['field']) && is_a($condition['field'], 'Drupal\Core\Database\Query\Condition')) {
      // call the helper function on it
      _recursively_alter_query_conditions($condition['field']->conditions());
    }
    else {
      // check if we want to alter the condition and if so alter it
      _alter_query_condition($condition);
    }
  }
}

/**
 * Actually alter the condition if relevant.
 */ 
function _alter_query_condition(&$condition) {
  if (isset($condition['field']) && ($condition['field'] === 'SUBSTRING(node_field_data.title, 1, 1) = :node_field_data_title')) {
    $condition['field'] = "SUBSTRING(views_natural_sort.content, 1, 1) = :node_field_data_title";
  }
}

SurajHo’s picture

To refer to comment #4/#5 concerning the D7 ticket for glossary support, that is actually already possible. What I did in D7, was use the field Node: Title - Natural and exclude from display, and use that field as a contextual filter. Works perfectly.

Would it be possible to implement that same field in the D8 version? Because I would also like to do this in D8 :-)

leeksoup’s picture

I'm trying to get contextual filters to work with natural sort on my site as well. It used to work years ago, as reported by SurajHo in #7, but the "Node: Title - Natural" field is now gone.

Can you give me any pointers to get this feature working again? I have read the comments here and at the issue linked at #5 but have no idea how to proceed.

keiserjb’s picture

From what I can tell, Node: Title - Natural field existed in the 7.x-1.x version of the module. Not sure how to get that capability back.

leeksoup’s picture

I tried comparing the code for that version with the current one. There are major changes throughout and I couldn't figure out what was the relevant part for the Node: Title - Natural field.

leeksoup’s picture

I was able to work around this problem by defining a Computed Field to hold the "natural sort" version of the title. Obviously, this isn't a great solution since it involves calculating and storing the same info a second time. But it does work with contextual filters.

generalredneck’s picture

Ok yall,

I made some headway on this. Keep in mind that my solution requires the fix in #3356107: Natural sort does not work with text fields anymore.

You can see the difference between the 2 branches in the following diff.

I have committed a test view in there. I've enabled "Glossary mode" on my contextual filter and as you can see it uses the first character of the raw transformed data. Keep in mind that this doens't work well for "numbers" so that's something yall will want to contend with. You can see that "A" works well and exactly like yall expected.

screenshot

I've added full access to all the VNS information using Views. You can list all the records in that table if you want, but really needed to do that in order to allow relationships to work which allows contextual filters. Give it some tests, let me know how it works for yall.