mage2kishan / module-sale-filter
Panth Sale Filter — "On Sale" layered navigation filter for Magento 2, backed by a custom indexer that respects catalog rules, special prices, customer groups, websites, and all product types (simple, configurable, grouped, bundle, virtual, downloadable). Hyva and Luma compatible.
Package info
github.com/mage2sk/module-sale-filter
Type:magento2-module
pkg:composer/mage2kishan/module-sale-filter
Requires
- php: ~8.1.0||~8.2.0||~8.3.0||~8.4.0
- mage2kishan/module-core: ^1.0
- magento/framework: ^103.0
- magento/module-backend: ^102.0
- magento/module-bundle: ^101.0
- magento/module-catalog: ^104.0
- magento/module-catalog-inventory: ^100.4
- magento/module-catalog-rule: ^101.2
- magento/module-catalog-search: ^102.0
- magento/module-config: ^101.2
- magento/module-configurable-product: ^100.4
- magento/module-cron: ^100.4
- magento/module-customer: ^103.0
- magento/module-eav: ^102.1
- magento/module-grouped-product: ^100.4
- magento/module-layered-navigation: ^100.4
- magento/module-store: ^101.1
- magento/module-ui: ^101.2
Requires (Dev)
None
Suggests
- hyva-themes/magento2-default-theme: For Hyvä frontend compatibility (no jQuery, TailwindCSS, AlpineJS).
- mage2kishan/module-sale-filter-hyva: For Hyvä-branded Alpine template and Appearance admin group.
Provides
None
Conflicts
None
Replaces
None
README
Panth Sale Filter adds an "On Sale" filter to Magento 2 layered navigation on category pages and catalog search result pages. Whether a product is on sale is read from a dedicated indexer that evaluates special prices and catalog price rules per website and customer group. It is meant for stores that want shoppers to narrow a listing to discounted products (and, optionally, to regular-price products). The filter sits in the theme's layered navigation block and its options are drawn by the module template Panth_SaleFilter::layer/filter/sale.phtml on Luma-based themes; Hyva storefronts use the companion package mage2kishan/module-sale-filter-hyva, which supplies its own template.
Product page: Magento 2 Sale Filter
Features
- "On Sale" option in layered navigation on category pages and search result pages.
- Optional second option for regular-price products ("Not On Sale"), off by default.
- Configurable filter title and option labels, per store view.
- Optional product count next to each option.
- On-sale detection from active special prices (with
special_from_date/special_to_date) and from catalog price rules; each source can be switched off. - Per website and per customer group results, including NOT LOGGED IN and custom groups.
- Configurable, grouped and bundle parents are marked on sale when an enabled child is on sale.
- Counts are limited to the current category (or the current search results), enabled and visible products, the stock filter, and other active layered navigation filters (price, category and filterable attributes).
- Filtered result paging and toolbar totals reflect the filtered list, not the unfiltered search result.
- Dedicated indexer
panth_salefilter_productwith MView subscriptions, supporting "Update on Save" and "Update by Schedule". - Admin index grid with filters and a keyword search (SKU, product name, or the product ID when the keyword is a number), a "Refresh Index" button, and an admin "How It Works" page.
- CLI commands to rebuild the index and to show on-sale counts per website and customer group.
- Scoped cache cleaning: only the products whose on-sale state changed, and the categories that list them, are cleaned from the cache.
- Hourly cron that reindexes products whose special price window or catalog rule dates start or end today.
- Works with the
row_idlink field of Adobe Commerce as well asentity_idof Magento Open Source.
Screenshots
Luma sidebar:
Filter applied, "On Sale" and "Regular Price":
Hyva sidebar (with the Hyva companion module):
Admin configuration:
Admin index grid and Index Management:
Cache behaviour:
Compatibility
| Component | Supported |
|---|---|
| Magento Open Source | 2.4.4 to 2.4.8 |
| Adobe Commerce | 2.4.4 to 2.4.8 |
| PHP | 8.1, 8.2, 8.3, 8.4 |
| Themes | Luma-based themes (standard layered navigation rendering); Hyva with mage2kishan/module-sale-filter-hyva |
Magento constraints in composer.json: magento/framework ^103.0, magento/module-catalog ^104.0, magento/module-catalog-inventory ^100.4, magento/module-catalog-rule ^101.2, magento/module-catalog-search ^102.0, magento/module-layered-navigation ^100.4, magento/module-configurable-product ^100.4, magento/module-grouped-product ^100.4, magento/module-bundle ^101.0, magento/module-config ^101.2, magento/module-customer ^103.0, magento/module-store ^101.1, magento/module-eav ^102.1, magento/module-backend ^102.0, magento/module-ui ^101.2.
Requirements
- Magento 2.4.4 to 2.4.8 and PHP 8.1 to 8.4.
mage2kishan/module-core(modulePanth_Core), installed automatically by Composer.- Magento cron running, if the indexer is set to "Update by Schedule".
- For Hyva themes:
mage2kishan/module-sale-filter-hyva. The base package lists it undersuggestonly; the Hyva package itself requiresmage2kishan/module-sale-filter(^1.0.9) andhyva-themes/magento2-default-theme(^1.3).
Installation
composer require mage2kishan/module-sale-filter bin/magento module:enable Panth_Core Panth_SaleFilter bin/magento setup:upgrade bin/magento setup:di:compile bin/magento indexer:reindex panth_salefilter_product bin/magento cache:flush
setup:di:compile is only needed in production mode. In production mode, also deploy static content (the module ships frontend styles):
bin/magento setup:static-content:deploy -f
Check that the module is enabled:
bin/magento module:status Panth_SaleFilter
For Hyva storefronts, also install the companion package:
composer require mage2kishan/module-sale-filter-hyva
Then enable its module and run setup:upgrade and cache:flush again.
Configuration
Admin path: Stores > Configuration > Panth Extensions > Sale Filter. The same section opens from the admin menu entry Sale Filter > Configuration. All fields can be set at default, website and store view scope.
General
| Setting | Default | What it does |
|---|---|---|
| Enabled | Yes | Adds the filter to layered navigation. When set to No, the filter is not shown and the sale_filter URL parameter is ignored. |
| Filter Title | Sale Status | Heading shown above the filter options. |
| Option Label - On Sale | On Sale | Label of the option that lists discounted products. |
| Show "Not On Sale" Option | No | Adds a second option that lists regular-price products. |
| Option Label - Not On Sale | Regular Price | Label of the regular-price option. Shown only when Show "Not On Sale" Option is Yes. |
| Show Product Count | Yes | Shows the matching product count next to each option. |
| Include Special Prices | Yes | Treats products with an active special price as on sale. Used by the indexer. |
| Include Catalog Rules | Yes | Treats products discounted by a catalog price rule as on sale. Used by the indexer. |
| Filter Position | 100 | Sort position of the filter. The filter is placed before the first layered navigation filter whose attribute position is higher than this value. |
Config paths: panth_salefilter/general/enabled, panth_salefilter/general/filter_label, panth_salefilter/general/option_label_on_sale, panth_salefilter/general/show_not_on_sale_option, panth_salefilter/general/option_label_not_on_sale, panth_salefilter/general/show_count, panth_salefilter/general/include_special_prices, panth_salefilter/general/include_catalog_rules, panth_salefilter/general/position.
Notes:
- Include Special Prices and Include Catalog Rules are applied when the index is built. Reindex
panth_salefilter_productafter changing them. If both are No, the index is emptied and no product is on sale. - Filter Position is compared with the position of the attributes used by the other filters. The category filter has no attribute and always stays in front. With the default of 100 the filter is usually shown last.
Usage
How "on sale" is determined
The indexer checks every website and every customer group and stores the on-sale products in panth_salefilter_product_index:
- Catalog rules: a product is on sale for a website and customer group when
catalogrule_product_pricehas a row for it with today's rule date, where today is taken in the timezone of the website's default store view. - Special prices: a product is on sale when its
special_priceis greater than 0 and lower thanprice(for bundle products, where the special price is a percentage, when it is greater than 0 and lower than 100), and the current date in the store timezone is insidespecial_from_date/special_to_date(an empty date is treated as open, and the wholespecial_to_dateday counts as on sale). Values are read for the website's default store view: a store view value takes precedence over the global value. - Only products enabled for the website's default store view are kept. Configurable (super link), grouped (grouped link) and bundle (bundle selection) parents of an on-sale child are also marked on sale.
Tier prices are not taken into account.
On the storefront
- The filter uses the title from Filter Title and one or two options. An option is only shown when it has at least one matching product.
- The URL parameter is
sale_filter:sale_filter=1lists on-sale products,sale_filter=0lists regular-price products (only when Show "Not On Sale" Option is Yes). Any other value is ignored. - The customer group comes from the HTTP context and the website from the current store, so shoppers in different groups can see different results.
- On category pages the filtered list is built from the category's enabled, visible, in-stock products, combined with active price, category and filterable attribute filters, and sorted by position, price or name according to the toolbar.
- On search result pages the options, counts and results are limited to the products returned by the search engine for the query (up to 10000 hits), in relevance order.
sale_filter=1keeps the on-sale products andsale_filter=0the regular-price products. - The active filter appears in the "Now Shopping by" state like other layered navigation filters.
- Paging and the toolbar total use the filtered product list.
- The options are rendered by
Panth_SaleFilter::layer/filter/sale.phtml(blockPanth\SaleFilter\Block\LayeredNavigation\FilterRenderer, list classpanth-salefilter) inside the theme's layered navigation filter item. Show Product Count controls the counts in this template; the core setting Catalog > Layered Navigation > Display Product Count still applies to the other filters. - A theme or module can use another template or block for the sale filter by setting the
panth_salefilter_templateandpanth_salefilter_blockarguments on the layered navigation renderer block (catalog.navigation.rendererorcatalogsearch.navigation.renderer). The block must extendPanth\SaleFilter\Block\LayeredNavigation\FilterRenderer. All other filters keep the theme renderer.
Hyva
Install mage2kishan/module-sale-filter-hyva on Hyva storefronts. It sets the renderer arguments above in the Hyva layout handles, so its Tailwind template draws the sale filter options inside the Hyva layered navigation, and it adds the Expanded By Default setting.
Keeping the index current
- The indexer
panth_salefilter_product("Sale Filter Product Index") depends oncatalogrule_productandcatalog_product_price. - In "Update by Schedule" mode, MView tracks
catalogrule_product_price,catalog_product_entity_decimal,catalog_product_entity_datetime,catalog_product_relation,catalog_product_super_linkandcatalog_product_bundle_selection, and Magento cron processes the changes. - In "Update on Save" mode, saving or deleting a product reindexes that product (and related parents and children). Saving or deleting a catalog rule runs a full
catalogrule_rulereindex followed by a full sale filter reindex. - After each reindex, only the products whose on-sale state changed are cleaned from the cache: the product tags
cat_p_<id>and the category listing tagscat_c_p_<id>of every category (and parent category) the products are assigned to. The clean is sent through theclean_cache_by_tagsevent, so the built-in full page cache and Varnish are both purged. - The cron job
panth_salefilter_date_boundariesruns every hour at minute 7. It reindexes products whosespecial_from_dateorspecial_to_datefalls on today or yesterday in any website timezone, and products whose catalog rule prices differ between yesterday and today. Running hourly lets every store timezone cross midnight before the next run. Magento cron must be running.
Admin
- Sale Filter > Index Grid: listing of index rows with product ID, SKU, type, website, customer group, regular price, special price, rule price, discount %, active catalog rules, source (Special Price, Catalog Rule, Both, Parent Aggregation), on-sale flag and update time. The Refresh Index button asks for confirmation and runs a full reindex (POST request).
- Sale Filter > How It Works: help page inside the admin.
CLI
bin/magento panth:salefilter:reindex bin/magento panth:salefilter:reindex --force bin/magento panth:salefilter:status
panth:salefilter:reindex runs a full rebuild; --force (-f) invalidates the indexer view first. panth:salefilter:status shows the on-sale count per website and customer group. The standard bin/magento indexer:reindex panth_salefilter_product and bin/magento indexer:set-mode commands also work.
Developer Notes
- Module:
Panth_SaleFilter - Package:
mage2kishan/module-sale-filter - Namespace:
Panth\SaleFilter - Depends on:
Panth_Core(module sequence also lists Magento_Catalog, Magento_CatalogRule, Magento_CatalogSearch, Magento_LayeredNavigation, Magento_ConfigurableProduct, Magento_GroupedProduct, Magento_Bundle) - Filter model:
Panth\SaleFilter\Model\Layer\Filter\SaleFilter(request variablesale_filter) - Plugins:
Plugin\Catalog\Model\Layer\FilterListPluginonMagento\Catalog\Model\Layer\FilterListandMagento\Catalog\Model\Layer\Search\FilterList(adds the filter)Plugin\Catalog\Model\Layer\ApplySaleFilterPluginonMagento\Catalog\Model\Layer\CategoryandMagento\Catalog\Model\Layer\Search(appliessale_filterto the product collection)Plugin\Catalog\Model\ResourceModel\Product\GetSizePluginon the fulltext and catalog product collections (filtered total)Plugin\LayeredNavigation\FilterRendererPluginonMagento\LayeredNavigation\Block\Navigation\FilterRenderer(renders the sale filter with the module template)
- Preferences:
Model\ResourceModel\Fulltext\Collection\SearchResultApplierreplaces the CatalogSearchSearchResultApplierInterface, the CatalogSearchSearchResultApplierand the ElasticsearchSearchResultApplier. - Full page cache: the module no longer changes the page cache identifier. Magento already varies the cache key by the
X-Magento-Varycookie, which carries the customer group, and keeps its own store and query parts. - Cron:
panth_salefilter_date_boundaries(Cron\ReindexDateBoundaries, groupdefault). - Observer:
Observer\CatalogRuleSaveAfteroncatalogrule_rule_save_commit_after,catalogrule_rule_delete_commit_after,catalog_product_save_after,catalog_product_delete_after. - Indexer:
panth_salefilter_product(Model\Indexer\ProductIndexer, resourceModel\ResourceModel\Indexer\ProductIndexer), MView viewpanth_salefilter_product. - Table:
panth_salefilter_product_index(primary keyentity_id,customer_group_id,website_id; foreign keys tocatalog_product_entityandstore_website). - Cache tags:
panth_salefilteron the filter block; changed products are cleaned withcat_p_<id>andcat_c_p_<category id>. - Product links (EAV values, configurable, grouped and bundle relations) are joined on the link field from the product metadata pool (
row_idon Adobe Commerce,entity_idon Magento Open Source). - Admin route:
panth_salefilter; UI listingpanth_salefilter_index_listing. - ACL:
Panth_SaleFilter::group(underPanth_Core::panth_extensions) withPanth_SaleFilter::index_grid,Panth_SaleFilter::index_reindex,Panth_SaleFilter::config,Panth_SaleFilter::help. - Patches:
Setup\Patch\Schema\DropLegacyIndexTabledrops the oldmage2sk_salefilter_product_indextable if present;Setup\Patch\Data\ResetIndexGridBookmarkresets saved admin grid bookmarks.
Uninstallation
If the Hyva companion is installed, remove it first, since it requires this package.
bin/magento module:disable Panth_SaleFilter composer remove mage2kishan/module-sale-filter bin/magento setup:upgrade bin/magento cache:flush
The module has no uninstall script. Check that panth_salefilter_product_index and the indexer changelog table were removed, and drop them manually if they remain.
Support
- Product page: Magento 2 Sale Filter
- Contact: kishansavaliya.com/contact
- Email: kishansavaliyakb@gmail.com
- Issues: GitHub issues
License
Proprietary, as declared in composer.json. The package is published on Packagist and can be installed with Composer; see the product page for the terms of use.
Changelog
See CHANGELOG.md.
Links
- Website: kishansavaliya.com
- All extensions catalogue: kishansavaliya.com/magento-extensions.html
- GitHub: mage2sk/module-sale-filter
- Packagist: mage2kishan/module-sale-filter
- Hyva companion: GitHub, Packagist








