How set a default value for search results?

Created on 3 February 2021, almost 4 years ago
Updated 8 March 2023, over 1 year ago

Is possible to set up a default value for the facet results? Even with custom code?

I'm on Drupal 9 and I have an ajax view with a page display and an exposed filter block and a single filter exposed, "Search: Fulltext search".
The search api is configured to search inside 3 different content type: products, articles and authors.
I've also configured a facet to filter on the content type, using a widget type "links", that let filter one content type at time
So, initially, the search page shows the results of all 3 content type. After a user filters a content type - e.g. articles - he can switch only to another and never return to the "no content type chosen" situation.

What I need to do is that the results are listed by default with one specific content type - e.g. product.
If that content type yield no results, the following content type should be used as filter. If there are no result, just "no result" should be shown.
In other words, the "no content type chosen" situation should be never available.

I've already tried to see if I can alter the query\options inside a hook_views_pre_view or SearchApiEvents::QUERY_PRE_EXECUTE, but with no success.

๐Ÿ’ฌ Support request
Status

Active

Version

2.0

Component

Documentation

Created by

๐Ÿ‡ฎ๐Ÿ‡นItaly Giuseppe87

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • ๐Ÿ‡จ๐Ÿ‡ฆCanada Shiraz Dindar Sooke, BC

    For me,

    #7 sets the default facet value in the facet field, but the results are not actually filtered accordingly.

    #2 works for me. However, since then a new argument ($urlGenerator) was added to the url_processor constructor (the one we are extending), so I had to add it here as well, as follows:

    <?php
    
    namespace Drupal\my_module\Plugin\facets\url_processor;
    
    use Drupal\Core\Entity\EntityTypeManagerInterface;
    use Drupal\facets\Plugin\facets\url_processor\QueryString;
    use Drupal\facets\Utility\FacetsUrlGenerator;
    use Symfony\Component\EventDispatcher\EventDispatcherInterface;
    use Symfony\Component\HttpFoundation\Request;
    
    /**
     * Query string URL processor.
     *
     * @FacetsUrlProcessor(
     *   id = "my_query_string",
     *   label = @Translation("My Query string"),
     *   description = @Translation("Add description")
     * )
     */
    class MyQueryString extends QueryString {
    
      /**
       * A string of how to represent the facet in the url.
       *
       * @var string
       */
      protected $urlAlias;
    
      /**
       * The event dispatcher.
       *
       * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
       */
      protected $eventDispatcher;
    
      /**
       * {@inheritdoc}
       */
      public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher, FacetsUrlGenerator $urlGenerator) {
        $this->alterRequest($request);
        parent::__construct($configuration, $plugin_id, $plugin_definition, $request, $entity_type_manager, $eventDispatcher, $urlGenerator);
      }
    
      /**
       * @param \Symfony\Component\HttpFoundation\Request $request
       */
      private function alterRequest(Request $request): void {
        $query = $request->query;
        $facet_new_parameters = [];
    
        if ($facet_parameters = $query->get('f')) {
          $article_type_filter_exists = FALSE;
    
          foreach ($facet_parameters as $parameter) {
            $sepator = ':';
            $explosion = explode($sepator, $parameter);
            $facet_type = array_shift($explosion);
            if ($facet_type === 'article_type') {
              $article_type_filter_exists = TRUE;
            }
          }
    
          if (!$article_type_filter_exists) {
            $facet_new_parameters = array_merge($facet_parameters, ['article_type:10372']);
          }
        }
        else {
          $facet_new_parameters = ['article_type:10372'];
        }
    
        if (!empty($facet_new_parameters)) {
          $query->set('f', $facet_new_parameters);
        }
      }
    }

    That said, I agree with #9 -- this should be something that we can set in the facet config.

    Thanks all!

  • ๐Ÿ‡ท๐Ÿ‡ดRomania reszli Tรขrgu Mureศ™

    $query->get('f') will not work anymore since it's not a scalar value but an array
    I used $query->all()['f'] ?? [] instead

    problem with this approach is that you can't even intentionally reset the filter to "any" since then the value is not in the URL and it will force the default

  • ๐Ÿ‡ฌ๐Ÿ‡ทGreece vensires

    Based on the previous comments of this thread, I was able to build the following URL processor.

    In my case, I wanted that the values from user fields became the default values for facets when entering the page. In some other views though, the default query_string plugin is what I needed. Read the inline comments if you intend to use it. Might require some refactoring for your case.

    
    namespace Drupal\mymodule\Plugin\facets\url_processor;
    
    use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
    use Drupal\Core\Entity\EntityTypeManagerInterface;
    use Drupal\facets\Plugin\facets\url_processor\QueryString;
    use Drupal\facets\Utility\FacetsUrlGenerator;
    use Symfony\Component\EventDispatcher\EventDispatcherInterface;
    use Symfony\Component\HttpFoundation\Request;
    
    /**
     * Query string URL processor.
     *
     * @FacetsUrlProcessor(
     *   id = "mymodule_query_string",
     *   label = @Translation("My module query string"),
     *   description = @Translation("Extends the original query string with predefined values")
     * )
     */
    class MymoduleQueryString extends QueryString {
    
      use UnchangingCacheableDependencyTrait;
    
      /**
       * {@inheritdoc}
       *
       * Since we are operating on the construct function and this gets called for
       * every facet on every page, we have to tamper the query object and then
       * restore it; otherwise facets without default values don't seem to work.
       */
      public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher, FacetsUrlGenerator $urlGenerator) {
        // Keep a clone of the original query to restore it later.
        $query = clone $request->query;
        /** @var \Drupal\facets\Entity\Facet $facet */
        $facet = $configuration['facet'];
        if ($facet->getFacetSourceConfig()->getUrlProcessorName() === $plugin_id) {
          $this->alterRequest($request);
        }
        parent::__construct($configuration, $plugin_id, $plugin_definition, $request, $entity_type_manager, $eventDispatcher, $urlGenerator);
        if ($facet->getFacetSourceConfig()->getUrlProcessorName() === $plugin_id) {
          // Restore the original query.
          $request->query = $query;
        }
      }
    
      /**
       * Alter the request object used by facets.
       *
       * When this function gets called, the default constructor has not yet been
       * called; thus we have to take all the variables we need as arguments instead
       * of relying on $this.
       *
       * @param \Symfony\Component\HttpFoundation\Request $request
       *   The current request object.
       */
      protected function alterRequest(Request $request) {
        // For this static variable to have any performance improvements, you must
        // have big_pipe module turned off. Otherwise, you would require another way
        // of caching due to different requests; maybe using a computed field on the
        // user entity is a possible solution.
        static $facet_parameters = [];
        /** @var \Drupal\user\UserInterface $account */
        $account = \Drupal::entityTypeManager()->getStorage('user')->load(\Drupal::currentUser()->id());
        $query = &$request->query;
        // Allow "?disable_defaults=1" for a "Clear defaults" button to be able to
        // work at this point.
        if ($query->getInt('disable_defaults', 0)) {
          return;
        }
    
        if (empty($facet_parameters)) {
          $original_query_parameters = $query->all()['f'] ?? [];
          if (empty($original_query_parameters)) {
            $facet_parameters = [];
    
            // Get user fields...
            if ($account->hasField('field_name_1') && !$account->get('field_name_1')->isEmpty()) {
              foreach ($account->get('field_name_1')->getValue() as $values) {
                $facet_parameters[] = 'facet_alias1:' . $values['target_id'];
              }
            }
            if ($account->hasField('field_name_2') && !$account->get('field_name_2')->isEmpty()) {
              foreach ($account->get('field_name_2')->getValue() as $values) {
                $facet_parameters[] = 'facet_alias2:' . $values['target_id'];
              }
            }
          }
        }
    
        if (!empty($facet_parameters)) {
          $query->set('f', $facet_parameters);
        }
      }
    
    }
    
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium ludo.r Brussels

    It seems, my custom URL processor is being called event when the facet source is set to use the default one.

    Anyone encountered this issue?

Production build 0.71.5 2024