4

At present, my project has default search pages for sections of the site. They are per-content type. When the user goes the "search page" for the content type, they see a views-generated search result page unfiltered by any keywords. In other words, it displays all the items for that content type. The view:

has expose form in a block enabled settings on the exposed form has 'input required' disabled

What I want to happen...

I'd like users to

  • see the unfiltered search result page sorted by newest first. At present, this page, if set to relevance, shows old content first.
  • automatically switch to relevance sorting when they enter keywords and execute a search. At present, I've set the first sort to date, to solve the 'old content first' problem, so users have to manually change the sort to relevance when doing a search.

Some options... I could separate the list pages from the search result pages. My question is, is there a way to make an unfiltered "search result" views page show the newest content first, while having the default sort actually set to relevance, so nobody has to manually change it? How does that sort really work when there aren't any keywords to supply "relevance"?

My config basics...

  • Drupal 9.3.7
  • search_api
  • facets
  • search_api_solr

2 Answers 2

1

I think I have one solution. I remain interested in knowing if there is a better way. Here's what seems to be working so far:

In the sort section of the view, I have these fields, in this order:

  • Relevance (descending): exposed
  • Date field (descending): exposed
  • Date field (same one, descending): not exposed

After clearing caches (important), the result seems to be that navigating to the search result page without doing a search, lists all the content (as filtered) by 'Date field' descending, but the search form and its exposed sort indicates Relevance. When I key in terms and launch the search, it comes back relevance sorted.

I'm not sure why this is working though. On the views config page the query without keywords looks like this:

Index: main_index
Keys: NULL
Conditions:
  [
    status = 1
  AND
    type IN array (
          'resource' => 'resource',
        )
  ]
Sorting: search_api_relevance DESC, field_display_date DESC
Options: array (
    'search_api_view' => 'object (Drupal\\views\\ViewExecutable)',
    'search_api_base_path' => 'search/resources',
  )

I may learn more from the mysql query log, but I admit: I'm never sure I understand what I'm seeing there.

3
  • I have one content type where the above configuration is not having the same result. No idea yet why.
    – aharown07
    Commented Mar 23, 2022 at 15:00
  • 1
    At least with Elasticsearch (may be true for other server types as well), it skips sorting in the case where the sort is search_api_relevance and there is no fulltext search, and falls back on the subsequent sort criteria. (See elasticsearch_connector/src/ElasticSearch/Parameters/Builder/SearchBuilder.php.)
    – jlstrecker
    Commented Feb 14 at 18:27
  • This works because when there is no full-text search, the relevance of all result items is '0', i.e. they all have the same value. Secondary sort fields only do anything when the value for previous sorts is the same.
    – Dalin
    Commented Aug 21 at 16:02
0

I have almost the same use case. I tried your approach but unfortunately it didn't work for me. After two days of research, I got a working version.

The key is SearchApiQuery::getSort() where you can get and manipulate the sort fields.

/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter($view, $query) {

  if ($view->id() === 'some_view_name_using_solr_index') {

    // Determine if there's a full text search term
    $exposedInput = !empty($view->exposed_data) ? $view->exposed_data : [];
    $hasSearchTerm = $exposedInput['some_field_name'] ? TRUE : FALSE;

    if (!$hasSearchTerm) {
      foreach ($query->getSort() as $key => &$order) {

        // Unset all sort fields except the date field. 
        // You may also want to set $order to 'DESC' if you 
        // haven't set it in config yet.

        if ($key !== 'some_date_field') {
          unset($query->getSort()[$key]);
        }

      }
    }

    // print_r($query->getSort());
  }
}

You can find more information about the SearchApiQuery class here.

1
  • Thanks for that. I look forward to testing. It may be that updates to Search API, or some other updates have made my earlier approach ineffective. (That project got mothballed, so I probably won't know how it goes in my environment until it or a similar project opens up.) (An alternative is create a block that lists latest items based on a view. Block only appears before a search query is launched, then disappears, showing the search results instead.)
    – aharown07
    Commented Apr 29 at 16:08

Your Answer

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

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