Just to confirm, I've tested your code on a fresh Magento 2.1.2 and it works absolutely fine in both cases (when accessing the product via its direct URL or when accessing the product via the category).
Regarding your second question: yes I'm 90% sure the Porto theme is the problem. All those themes are shipped with a huge number of widgets, modules, custom modifications which are very often the root cause of many issues.
I'm not saying those themes are bad, they're great when you're dealing with a small store which do not need a lot of custom development and modifications. However, when you're dealing with a bigger structure, problems arise.
I have found a method that works. It seems that the Category view, regardless of a filter being applied or not, will ALWAYS use the Catalog Search module. Knowing that, we can override the following class to add a custom filter.
Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection
But it's not that simple, first we have to create a custom filter in an xml document. Here are the steps:
Step 1
Create a search_request.xml file in Company/RegionManager/etc/search_request.xml. For my example I used the following code, you can replace any instance of deal_active with your custom attribute. Including the $deal_active$
<?xml version="1.0"?>
<requests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Search/etc/search_request.xsd">
<request query="catalog_view_container" index="catalogsearch_fulltext">
<queries>
<query xsi:type="boolQuery" name="catalog_view_container" boost="1">
<queryReference clause="should" ref="active_query"/>
</query>
<query name="active_query" xsi:type="filteredQuery">
<filterReference clause="must" ref="active_query_filter"/>
</query>
</queries>
<filters>
<filter xsi:type="termFilter" name="active_query_filter" field="deal_active" value="$deal_active$"/>
</filters>
<from>0</from>
<size>10000</size>
</request>
</requests>
Step 2
Override \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection in the di.xml in your /etc/
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection" type="Company\RegionManager\Model\ResourceModel\Fulltext\Collection" />
</config>
Step 3
In the Company\RegionManager\Model\ResourceModel\Fulltext\Collection.php file, replace the code between the two ADDING CUSTOM FILTER comments with your custom attribute.
<?php
namespace Company\RegionManager\Model\ResourceModel\Fulltext;
use Magento\CatalogSearch\Model\Search\RequestGenerator;
use Magento\Framework\DB\Select;
use Magento\Framework\Exception\StateException;
use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage;
use Magento\Framework\Search\Response\QueryResponse;
use Magento\Framework\Search\Request\EmptyRequestDataException;
use Magento\Framework\Search\Request\NonExistingRequestNameException;
use Magento\Framework\Api\Search\SearchResultFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\App\ObjectManager;
/**
* Fulltext Collection
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Collection extends \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection
{
/**
* @var QueryResponse
* @deprecated
*/
protected $queryResponse;
/**
* Catalog search data
*
* @var \Magento\Search\Model\QueryFactory
* @deprecated
*/
protected $queryFactory = null;
/**
* @var \Magento\Framework\Search\Request\Builder
* @deprecated
*/
private $requestBuilder;
/**
* @var \Magento\Search\Model\SearchEngine
* @deprecated
*/
private $searchEngine;
/**
* @var string
*/
private $queryText;
/**
* @var string|null
*/
private $order = null;
/**
* @var string
*/
private $searchRequestName;
/**
* @var \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory
*/
private $temporaryStorageFactory;
/**
* @var \Magento\Search\Api\SearchInterface
*/
private $search;
/**
* @var \Magento\Framework\Api\Search\SearchCriteriaBuilder
*/
private $searchCriteriaBuilder;
/**
* @var \Magento\Framework\Api\Search\SearchResultInterface
*/
private $searchResult;
/**
* @var SearchResultFactory
*/
private $searchResultFactory;
/**
* @var \Magento\Framework\Api\FilterBuilder
*/
private $filterBuilder;
/**
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
* @param \Psr\Log\LoggerInterface $logger
* @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param \Magento\Eav\Model\Config $eavConfig
* @param \Magento\Framework\App\ResourceConnection $resource
* @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
* @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
* @param \Magento\Framework\Validator\UniversalFactory $universalFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\Module\Manager $moduleManager
* @param \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
* @param \Magento\Catalog\Model\ResourceModel\Url $catalogUrl
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Magento\Customer\Model\Session $customerSession
* @param \Magento\Framework\Stdlib\DateTime $dateTime
* @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
* @param \Magento\Search\Model\QueryFactory $catalogSearchData
* @param \Magento\Framework\Search\Request\Builder $requestBuilder
* @param \Magento\Search\Model\SearchEngine $searchEngine
* @param \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
* @param string $searchRequestName
* @param SearchResultFactory $searchResultFactory
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\Data\Collection\EntityFactory $entityFactory,
\Psr\Log\LoggerInterface $logger,
\Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
\Magento\Framework\Event\ManagerInterface $eventManager,
\Magento\Eav\Model\Config $eavConfig,
\Magento\Framework\App\ResourceConnection $resource,
\Magento\Eav\Model\EntityFactory $eavEntityFactory,
\Magento\Catalog\Model\ResourceModel\Helper $resourceHelper,
\Magento\Framework\Validator\UniversalFactory $universalFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\Module\Manager $moduleManager,
\Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
\Magento\Catalog\Model\ResourceModel\Url $catalogUrl,
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Magento\Customer\Model\Session $customerSession,
\Magento\Framework\Stdlib\DateTime $dateTime,
\Magento\Customer\Api\GroupManagementInterface $groupManagement,
\Magento\Search\Model\QueryFactory $catalogSearchData,
\Magento\Framework\Search\Request\Builder $requestBuilder,
\Magento\Search\Model\SearchEngine $searchEngine,
\Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory,
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
$searchRequestName = 'catalog_view_container',
SearchResultFactory $searchResultFactory = null
) {
$this->queryFactory = $catalogSearchData;
if ($searchResultFactory === null) {
$this->searchResultFactory = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\Api\Search\SearchResultFactory');
}
parent::__construct(
$entityFactory,
$logger,
$fetchStrategy,
$eventManager,
$eavConfig,
$resource,
$eavEntityFactory,
$resourceHelper,
$universalFactory,
$storeManager,
$moduleManager,
$catalogProductFlatState,
$scopeConfig,
$productOptionFactory,
$catalogUrl,
$localeDate,
$customerSession,
$dateTime,
$groupManagement,
$catalogSearchData,
$requestBuilder,
$searchEngine,
$temporaryStorageFactory,
$connection,
$searchRequestName,
$searchResultFactory
);
$this->requestBuilder = $requestBuilder;
$this->searchEngine = $searchEngine;
$this->temporaryStorageFactory = $temporaryStorageFactory;
$this->searchRequestName = $searchRequestName;
}
/**
* @inheritdoc
*/
protected function _renderFiltersBefore()
{
$this->getSearchCriteriaBuilder();
$this->getFilterBuilder();
$this->getSearch();
if ($this->queryText) {
$this->filterBuilder->setField('search_term');
$this->filterBuilder->setValue($this->queryText);
$this->searchCriteriaBuilder->addFilter($this->filterBuilder->create());
}
$priceRangeCalculation = $this->_scopeConfig->getValue(
\Magento\Catalog\Model\Layer\Filter\Dynamic\AlgorithmFactory::XML_PATH_RANGE_CALCULATION,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
if ($priceRangeCalculation) {
$this->filterBuilder->setField('price_dynamic_algorithm');
$this->filterBuilder->setValue($priceRangeCalculation);
$this->searchCriteriaBuilder->addFilter($this->filterBuilder->create());
}
// ADDING CUSTOM FILTER START
$this->filterBuilder->setField('deal_active');
$this->filterBuilder->setValue('yes');
$this->filterBuilder->setConditionType('eq');
$this->searchCriteriaBuilder->addFilter($this->filterBuilder->create());
// ADDING CUSTOM FILTER END
$searchCriteria = $this->searchCriteriaBuilder->create();
$searchCriteria->setRequestName($this->searchRequestName);
try {
$this->searchResult = $this->getSearch()->search($searchCriteria);
} catch (EmptyRequestDataException $e) {
/** @var \Magento\Framework\Api\Search\SearchResultInterface $searchResult */
$this->searchResult = $this->searchResultFactory->create()->setItems([]);
} catch (NonExistingRequestNameException $e) {
$this->_logger->error($e->getMessage());
throw new LocalizedException(__('Sorry, something went wrong. You can find out more in the error log.'));
}
$temporaryStorage = $this->temporaryStorageFactory->create();
$table = $temporaryStorage->storeApiDocuments($this->searchResult->getItems());
$this->getSelect()->joinInner(
[
'search_result' => $table->getName(),
],
'e.entity_id = search_result.' . TemporaryStorage::FIELD_ENTITY_ID,
[]
);
$this->_totalRecords = $this->searchResult->getTotalCount();
if ($this->order && 'relevance' === $this->order['field']) {
$this->getSelect()->order('search_result.'. TemporaryStorage::FIELD_SCORE . ' ' . $this->order['dir']);
}
//return parent::_renderFiltersBefore();
return \Magento\Catalog\Model\ResourceModel\Product\Collection::_renderFiltersBefore();
}
/**
* @deprecated
* @return \Magento\Framework\Api\Search\SearchCriteriaBuilder
*/
private function getSearchCriteriaBuilder()
{
if ($this->searchCriteriaBuilder === null) {
$this->searchCriteriaBuilder = ObjectManager::getInstance()
->get('\Magento\Framework\Api\Search\SearchCriteriaBuilder');
}
return $this->searchCriteriaBuilder;
}
/**
* @deprecated
* @return \Magento\Framework\Api\FilterBuilder
*/
private function getFilterBuilder()
{
if ($this->filterBuilder === null) {
$this->filterBuilder = ObjectManager::getInstance()->get('\Magento\Framework\Api\FilterBuilder');
}
return $this->filterBuilder;
}
/**
* @deprecated
* @return \Magento\Search\Api\SearchInterface
*/
private function getSearch()
{
if ($this->search === null) {
$this->search = ObjectManager::getInstance()->get('\Magento\Search\Api\SearchInterface');
}
return $this->search;
}
/**
* Return field faceted data from faceted search result
*
* @param string $field
* @return array
* @throws StateException
*/
public function getFacetedData($field)
{
$this->_renderFilters();
$result = [];
$aggregations = $this->searchResult->getAggregations();
// This behavior is for case with empty object when we got EmptyRequestDataException
if (null !== $aggregations) {
$bucket = $aggregations->getBucket($field . RequestGenerator::BUCKET_SUFFIX);
if ($bucket) {
foreach ($bucket->getValues() as $value) {
$metrics = $value->getMetrics();
$result[$metrics['value']] = $metrics;
}
} else {
throw new StateException(__('Bucket does not exist'));
}
}
return $result;
}
}
Best Answer
you can follow these steps :
1.Create your own module ( example :Vendor/Mysample)
2.app/code/Vendor/Mysample/etc/module.xml
3.Create file under app/code/Vendor/Mysample/etc/frontend/di.xml and copy this code :
4.Create the registration file app/code/Vendor/Mysample/registration.php
5.Create the file app/code/Vendor/Mysample/Plugin/Result/Page.php and copy the below code :
Good luck and happy coding !!!