To load a custom product collection in the frontend using Smile ElasticSuite, you need to adjust how you develop your custom modules to work with ElasticSuite. This error occurs because the Smile ElasticSuite modifies the standard product collection to use Elasticsearch.
The method addSortFilterParameters()
is not in the Magento Catalog\Model\ResourceModel\Product\Collection
, but is instead in the Smile ElasticSuite ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection
. When ElasticSuite is enabled, the latter should be used everywhere instead of the former.
In your custom module, don't create the product collection directly. Instead, you should use the Magento\Catalog\Model\Layer
model to get the product collection to make sure it will return the product collection with ElasticSuite modification.
To do this in your block, you need to override the _getProductCollection
method from Magento\Catalog\Block\Product\ListProduct
:
class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
{
protected function _getProductCollection()
{
/** @var \Magento\Catalog\Model\Layer $layer */
$layer = $this->getLayer();
if ($this->_productCollection === null) {
$this->_productCollection = $layer->getProductCollection();
}
$this->_eventManager->dispatch(
'catalog_block_product_list_collection',
['collection' => $this->_productCollection]
);
return $this->_productCollection;
}
}
Then in your layout XML file, reference the "product_list" block, and replace the class to your custom class.
This should load the product collection with ElasticSuite modification. If you want to add more filters or sorts to the collection, use the AddFieldToFilter()
method on the product collection returned by $layer->getProductCollection()
instead of creating your own collection.
Edited to provide additional info:
From the error you shared, the method addSortFilterParameters()
is not defined in the class Magento\Catalog\Model\ResourceModel\Product\Collection\Interceptor
. If the method is defined in Smile's Full Text collection, I recommend using Dependency Injection to inject an instance of Smile's collection into your Model's constructor.
Here's an example of how you can do this:
namespace Sa\CustomCollection\Model;
class CustomModel {
protected $_smileCollection;
public function __construct(
\Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection $smileCollection,
) {
$this->_smileCollection = $smileCollection;
}
public function getSmileCollection() {
$this->_smileCollection->addSortFilterParameters();
}
}
Now, you can call the method getSmileCollection()
in your controller to get Smile's FullText collection.
Regarding your filters not adjusting to the pre-filtered collection on the first load of the page, the page load is not aware of the pre-filters applied on the collection. It seems that Smile was designed to work by applying filters via the URL, thus it's always expecting filter parameters in the URL.