I have applied several price cart rules, I would like to see those frontend rules that work as a filter for discounted products. Someone can help me?
1 Answer
For filter products by discount percentage follow below steps:
1.Create the registration.php file
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Vendor_DiscountFilter',
__DIR__
);
2.Create the Vendor/DiscountFilter/etc/module.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vendor_DiscountFilter">
<sequence>
<module name="Magento_Catalog"/>
<module name="Magento_CatalogSearch"/>
<module name="Magento_Swatches"/>
<module name="Magento_ConfigurableProduct"/>
<module name="Magento_Eav"/>
<module name="Magento_Customer"/>
<module name="Magento_Store"/>
<module name="Magento_Backend"/>
<module name="Magento_MediaStorage"/>
<module name="Magento_Config"/>
<module name="Magento_LayeredNavigation"/>
<module name="Magento_Theme"/>
</sequence>
</module>
</config>
3.create the Vendor/DiscountFilter/etc/adminhtml/system.xmlfile
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Magento/Config/etc/system_file.xsd">
<system>
<tab id="discountFilter" translate="label" sortOrder="500">
<label>Discount Filter</label>
</tab>
<section id="discountFiltered" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Settings</label>
<tab>discountFilter</tab>
<resource>Vendor_DiscountFilter::vendor_discountfilter</resource>
<group id="discountFilterGroup" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Discount Filter</label>
<field id="isEnableDisable" translate="label comment" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
</group>
</section>
</system>
</config>
4.create Vendor/DiscountFilter/etc/frontend/routes.xml file
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route frontName="discountfilter" id="discountfilter">
<module name="Vendor_DiscountFilter"/>
</route>
</router>
</config>
5.Create Vendor/DiscountFilter/etc/config.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<discountFiltered>
<discountFilterGroup>
<isEnableDisable>1</isEnableDisable>
</discountFilterGroup>
</discountFiltered>
</default>
</config>
6.create Vendor/DiscountFilter/etc/di.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Model\Layer\FilterList" type="Vendor\DiscountFilter\Model\Layer\FilterList" />
<type name="Magento\Catalog\Model\Layer\FilterList">
<plugin name="FilterDiscountList" type="Vendor\DiscountFilter\Model\Layer\FilterList" sortOrder="1" disabled="false" />
</type>
</config>
7.create Vendor/DiscountFilter/Model/Layer/Filter/Rating.php file
<?php
namespace Vendor\DiscountFilter\Model\Layer\Filter;
use Magento\Catalog\Model\Layer;
use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
use Magento\Catalog\Model\Layer\Filter\DataProvider\PriceFactory;
use Magento\Catalog\Model\Layer\Filter\Item\DataBuilder;
use Magento\Catalog\Model\Layer\Filter\ItemFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
use Magento\Store\Model\StoreManagerInterface;
/**
* Class Rating
* @package Vendor\DiscountFilter\Model\Layer\Filter
*/
class Rating extends AbstractFilter
{
/**
* @var CollectionFactory
*/
protected CollectionFactory $productCollectionFactory;
/**
* @var PriceFactory
*/
private $dataProvider;
/**
* Rating constructor.
* @param ItemFactory $filterItemFactory
* @param StoreManagerInterface $storeManager
* @param Layer $layer
* @param DataBuilder $itemDataBuilder
* @param CollectionFactory $productCollectionFactory
* @param PriceFactory $dataProviderFactory
* @param array $data
* @throws LocalizedException
*/
public function __construct(
ItemFactory $filterItemFactory,
StoreManagerInterface $storeManager,
Layer $layer,
DataBuilder $itemDataBuilder,
CollectionFactory $productCollectionFactory,
PriceFactory $dataProviderFactory,
array $data = []
)
{
parent::__construct($filterItemFactory, $storeManager, $layer, $itemDataBuilder, $data);
$this->productCollectionFactory = $productCollectionFactory;
$this->_requestVar = 'dis';
$this->dataProvider = $dataProviderFactory->create(['layer' => $this->getLayer()]);
}
/**
* @return mixed
*/
public function getResetValue(): mixed
{
return $this->dataProvider->getResetValue();
}
/**
* @param RequestInterface $request
* @return $this|AbstractFilter
*/
public function apply(RequestInterface $request)
{
$filter = $request->getParam($this->getRequestVar());
if (!$filter || is_array($filter)) {
return $this;
}
$filter = explode('-', $filter);
list($from, $to) = $filter;
$entity_id = [];
$collection = $this->productCollectionFactory->create()
->addAttributeToSelect(array('sku', 'price', 'special_price', 'special_to_date', 'special_from_date'))
->addAttributeToFilter('special_price', array('notnull' => true));
foreach ($collection as $product) {
$price = $product->getPrice();
if($product->getTypeId() == "bundle")
{
$price = $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue() ;
}
$sprice = $product->getSpecialPrice();
$sprice_from_date = $product->getSpecialFromDate();
$sprice_to_date = $product->getSpecialToDate();
if ($price > 0 && isset($sprice_from_date) && isset($sprice_to_date) && !empty($sprice_from_date) && !empty($sprice_to_date)) {
if (time() >= strtotime($sprice_from_date) && time() <= strtotime($sprice_to_date)) {
$dis = ($price - $sprice) * 100 / $price;
if ($dis >= $from && $dis <= $to) {
$entity_id[] = $product->getId();
}
}
}
}
$this->getLayer()
->getProductCollection()
->addAttributeToFilter('entity_id', array('in' => ($entity_id)));
return $this;
}
/**
* @return Phrase
*/
public function getName(): Phrase
{
return __('Discount');
}
/**
* @return array
*/
protected function _getItemsData(): array
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();;
$scopeConfig = $objectManager->create('\Magento\Framework\App\Config\ScopeConfigInterface');
if ($scopeConfig->getValue('discountFiltered/discountFilterGroup/isEnableDisable')) {
$facets = array(
'0-20' => '<div class="rating-result"><span>' . __('1% to 20%') . '</span></div>',
'21-40' => '<div class="rating-result"><span>' . __('21% to 40%') . '</span></div>',
'41-60' => '<div class="rating-result"><span>' . __('41% to 60%') . '</span></div>',
'61-80' => '<div class="rating-result"><span>' . __('61% to 80%') . '</span></div>',
'81-100' => '<div class="rating-result"><span>' . __('81% to 100%') . '</span></div>',
);
if (count($facets) > 1) {
foreach ($facets as $key => $label) {
$filter = explode('-', $key);
list($from, $to) = $filter;
$collection = $this->getLayer()->getCurrentCategory()
->getProductCollection()
->addAttributeToSelect(array('sku', 'price', 'special_price', 'special_to_date', 'special_from_date'))
->addFieldToFilter('special_price', array('gt' => '5'));
$count1 = 0;
foreach ($collection as $product) {
$price = $product->getPrice();
if($product->getTypeId() == "bundle")
{
$price = $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue() ;
}
$sprice = $product->getSpecialPrice();
$sprice_from_date = $product->getSpecialFromDate();
$sprice_to_date = $product->getSpecialToDate();
if ($price > 0 && isset($sprice_from_date) && isset($sprice_to_date) && !empty($sprice_from_date) && !empty($sprice_to_date)) {
if (time() >= strtotime($sprice_from_date) && time() <= strtotime($sprice_to_date)) {
$dis = ($price - $sprice) * 100 / $price;
if ($dis >= $from && $dis <= $to) {
$count1++;
array($product);
}
}
}
}
if ($count1 > 0) {
$this->itemDataBuilder->addItemData(
$label,
$key,
$count1
);
}
}
}
return $this->itemDataBuilder->build();
}
}
/**
* @param $from
* @param $to
* @return array
*/
public function getProduct($from, $to): array
{
$sku = [];
$collection = $this->getLayer()
->getProductCollection()
->addAttributeToSelect(array('sku', 'price', 'special_price'))
->addAttributeToFilter('special_price', array('notnull' => true));
foreach ($collection as $product) {
$price = $product->getPrice();
$sprice = $product->getSpecialPrice();
$dis = ($price - $sprice) * 100 / $price;
if ($dis >= $from && $dis <= $to) {
$sku[] = $product->getId();
}
}
return $sku;
}
}
8.create Vendor/DiscountFilter/Model/Layer/FilterList.php file
<?php
namespace Vendor\DiscountFilter\Model\Layer;
use Magento\Framework\View\Element\Template\Context;
use Magento\Catalog\Model\Layer;
use Magento\Framework\ObjectManagerInterface;
/**
* Class FilterList
* @package Vendor\DiscountFilter\Model\Layer
*/
class FilterList
{
/**
* @var ObjectManagerInterface
*/
private ObjectManagerInterface $objectManager;
/**
* FilterList constructor.
* @param Context $context
* @param ObjectManagerInterface $objectManager
*/
public function __construct(
Context $context,
ObjectManagerInterface $objectManager
)
{
$this->objectManager = $objectManager;
}
/**
* @param Layer\FilterList $subject
* @param \Closure $proceed
* @param Layer $layer
* @return array|mixed
*/
public function aroundGetFilters(
Layer\FilterList $subject,
\Closure $proceed,
Layer $layer
)
{
$result = $proceed($layer);
$result[] = $this->objectManager->create('Vendor\DiscountFilter\Model\Layer\Filter\Rating', ['layer' => $layer]);
return $result;
}
}
9.create Vendor/DiscountFilter/view/frontend/layout/default.xml file
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Vendor_DiscountFilter::css/discount-filter.css"/>
</head>
</page>
10.create Vendor/DiscountFilter/view/frontend/web/css/discount-filter.css
.rating-result{
display: inline-block;
margin-top: -5px;
}
- Then set the special price of the product from the "Advance Pricing" and check on frontend side.
NOTE: it's works with a special price only.