Elasticsuite: Dev Question: Filter for new Products

Created on 29 Jan 2019  路  5Comments  路  Source: Smile-SA/elasticsuite

We want a filter in layered navigation that filters for new products. Our idea is to base it on the magento default attributes news_from_date and news_to_date. I found an example in the wiki under Query Filters. But what is a good way to implement it?

question

All 5 comments

Hello @DanieliMi,

There are several steps if you want to take inspiration on the wiki page you mentioned.

A "by the book" approach is a bit complex...

A filter in the layered navigation is represented by two components : a layer filter model and its layer filter renderer (in M1, it was a block)
The layer filter renderers are children block of the layer Navigation block and displays what the layer filters pulls from the DB/ElasticSearch.
Usually (native ES or Solr implementation), the layer filter model has three tasks :

  • asking for a "facet" to the search engine : it will populate the filter with items in the layered navigation
  • apply a "filter" to the search engine/production collection : to restrict the products to those satisfying the conditions expressed by the items being selected in the layered navigation filter
  • report the filter items being applied to the layer state block

In ElasticSuite, it's slightly different, but not by much :

  • the "facets" related to the filterable product attributes (those with is_filterable = 1 or is_filterable_in_search = 1) are aggregations that are automatically added to the ES request by providers, so it's not longer the job of the filter models to do it
    => look in vendor/smile/elasticsuite/src/module-elasticsuite-catalog/etc/elasticsuite_search_request.xmlfor aggregations/provider nodes
    Also note the presence of a term aggregation on attribute_set_id being added to search (quick_search_container request) and catalog navigation (catalog_view_container).
    So, in all likelyhood, it's there you should add your is_new custom aggregation there.
    You could probably use the \Smile\ElasticsuiteCore\Search\Request\Aggregation\Bucket\QueryGroup bucket aggregation type (but I'm not 100% sure).
  • You will need to plugin on \Smile\ElasticsuiteCatalog\Block\Navigation::getFilters (\Magento\LayeredNavigation\Block\Navigation::getFilters) to inject your layer filter model because it will not be returned by the filter list models
  • You might also need to declare your own filter renderer and inject it in the layout

The trickiest part will be the filter model in itself :

  • you can take inspiration from \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Attribute / \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Boolean but might not be able to extend those classes because you will not have an attribute per se.
    So \Magento\Catalog\Model\Layer\Filter\AbstractFilter::getAttributeModel will throw an exception, but on the other hand, you're not supposed to need the behavior of \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Attribute::getFilterField :

    • the name of the aggregation containing the items to show is fixed : it's the one you declared in etc/elasticsuite_search_request.xml, so \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Attribute::_getItemsData could be made to work

  • you will have to take inspiration from both \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Boolean and \Smile\ElasticsuiteCatalog\Model\Layer\Filter\Category to write the apply and _getItemsData methods (having toyed with layered navigation filters in M1 is a plus)

    • as you will not be handling a mapped product attribute, a simple $productCollection->addFieldToFilter($this->getFilterField(), $attributeValue); is out of question

  • - - it's at this point that you will have to use the example of Query Filters to add the correct query filter (through $this->getLayer()->getProductCollection()->addQueryFilter)

We do not provide (yet) the functionnality of "Virtual Attributes" that were written for the M1 version of the module, if we did, you would have had a lot less code to write.
I'll try to think about an alternative way of doing things (adding a filterable + frontendInput=hidden "is_new" real product attribute + tweaking the models to select the specific filter model/renderer).

Regards

Closed as being answered

So, we added our filter via a custom plugin with elasticsuite_search_request.xml. The filter works pretty good, however, we're having trouble to add it to the layered navigation. We tried plugging Smile\ElasticsuiteCatalog\Block\Navigation::getFilters, but it looks like getFilters returns an array of filter items which are strictly tied to attributes, which we don't have.

We tried something like this:

    private function createAttribute()
    {
        $filter = $this->filterItemFactory->create()
        //->setFilter($this)
        ->setLabel('New Product')
        ->setValue(1)
        ->setCount(0);
        $layer = $this->getLayer()->getState()->addFilter($filter);

        return $this->objectManager->create(
            Attribute::class,
            ['data' => ['attribute_model' => null], 'layer' => $layer]
        );
    }

Do you have an idea how to add a filter without an eav attribute?

@rbayet Do you maybe have an idea for a solution?

For our Filter we used so \Smile\ElasticsuiteCore\Api\Search\Request\Container\FilterInterface so far I think that's a point we need to change to add it to \Smile\ElasticsuiteCatalog\Block\Navigation::getFilters

Was this page helpful?
0 / 5 - 0 ratings