Layered Navigation

Filters that shoppers actually use: several options per filter with correct counts, swatches, a price slider, Ajax updates and optional readable filter URLs, on Luma and Hyvä.

  • Magento 2.4.7 – 2.4.9
  • PHP 8.2 – 8.5
  • Hyvä and Luma
  • Version 1.1.3
$189

One-off payment, with 12 months of updates.

What is included

  • 12 months of new versions and fixes; the versions released in that time stay yours
  • Install with Composer, or download a zip from your account
  • Licence for one production domain, staging and development copies included
  • 30-day money-back guarantee, refund policy

No subscription or automatic renewal. Keep using the versions included in your update period. Update and licence details

Key features

  • Several options per filter (OR) and across filters (AND)
  • Correct counts for the options of a filter in use
  • Checkboxes, swatches, dropdown or price slider per attribute
See all features

Composer package softaware/module-layered-navigation

  • Shoppers find it faster

    Black or Blue, in size M: shoppers combine options the way they think, and every count shows what is left before they click.

  • Readable filter addresses

    /tops-women/color-black-blue/size-m.html instead of option IDs, with your own words per store view and 301 redirects from the old addresses.

  • Fast and cache-friendly

    Counts come from the search engine, not from per-product queries. Every filtered list is a normal address that the full page cache stores.

All features

What is included

Filtering

  • Several options of one attribute combined with OR
  • Different attributes combined with AND
  • Counts stay correct for a filter already in use
  • Filters on category pages and search results
  • Optional: hide filters that offer only one option

Display

  • Checkboxes, swatches, dropdown or slider per attribute
  • Price slider with from and to boxes, or Magento's price ranges
  • Option order: position, name or number of products
  • Expanded or collapsed on page load per attribute
  • "Show more" link and search box for long lists

SEO

  • Optional friendly filter URLs on category pages
  • One address per combination, other orders redirect (301)
  • Old query-string addresses redirect (301)
  • Slugs per store view, editable in the admin
  • rel="nofollow" on links that combine two or more values

Shopping experience and developers

  • Ajax updates of list, filters and address bar; Back and Forward work
  • Works without JavaScript as plain links
  • Keyboard accessible filters
  • JavaScript event after every Ajax update
  • FilterStateInterface for other modules, CLI to list slugs

Feature tour

Everything your shoppers and your team see

01 / 07

All filters on one sidebar

Selected options appear as chips with a remove link. Colour swatches allow several choices, sizes keep their text swatches and price gets a slider with from and to boxes.

02 / 07

Native on Hyvä

The same filters on Hyvä, styled through Tailwind and run by one small vanilla JavaScript file. No RequireJS, jQuery or Alpine needed for the filters.

03 / 07

Folds behind "Shop By" on phones

On small screens the whole filter block opens from one "Shop By" bar, with the number of active filters in a badge. Luma on the left, Hyvä on the right.

04 / 07

Your words in the address

With SEO-friendly filter URLs on, the German store view of the demo filters to /de/women/tops-women/color-blau-schwarz/size-m.html. Combinations of two or more values get rel="nofollow".

05 / 07

Edit the slug of every option

Pick an attribute and a store view and set your own slug for each option, or leave it empty to use the option label. Slugs are checked before anything is saved.

06 / 07

Display, order and state per filter

On the attribute page: Filter Display, Filter Option Order (position, name or number of products) and Filter Expanded on Page Load.

07 / 07

Short settings page, per store view

Ajax filtering, the "Show more" limit, the search box threshold, hiding single-option filters and SEO-friendly filter URLs.

Live demo

Try it before you install it

A full Magento store with the module installed, on Luma and on Hyvä. The admin demo signs you in with one click.

Compatibility

Requirements and compatibility

Compatibility of Layered Navigation
Magento2.4.7 – 2.4.9
Storefront themes Luma Blank Hyvä
PHP8.2 – 8.5
Latest version 1.1.3
composer.json requires php ~8.2.0||~8.3.0||~8.4.0||~8.5.0 magento/framework ~103.0.7 softaware/module-core ^1.0 magento/module-backend * magento/module-catalog * magento/module-catalog-search * magento/module-config * magento/module-eav * magento/module-layered-navigation * magento/module-page-cache * magento/module-store * magento/module-swatches * magento/module-theme * magento/module-url-rewrite *

Installation

Up and running in minutes

After you buy, create a Composer key in your account. Then, in the root of your Magento project:

  1. 01Add the repository and your key (once per project)

    composer config repositories.softaware composer https://repo.softawarecommerce.com
    composer config --auth http-basic.repo.softawarecommerce.com PUBLIC_KEY PRIVATE_KEY
  2. 02Install the module

    composer require softaware/module-layered-navigation
  3. 03Enable it

    bin/magento setup:upgrade
    bin/magento setup:di:compile
    bin/magento setup:static-content:deploy
    bin/magento cache:flush

    The last three are only needed in production mode.

Prefer a zip? Every version you are entitled to can be downloaded from My modules. More about Composer access

User guide

How to set up and use Layered Navigation

For version 1.1.3. The same guide comes with the module, in docs/user-guide.md.

Better filters for category pages and search results on Luma and Hyvä: several options per filter with correct counts, swatches, a price slider, Ajax filtering and optional SEO-friendly filter URLs. This guide covers installation, configuration and day-to-day use.

Filters on a Luma category page
Filters on a Luma category page

1. Requirements

MagentoOpen Source or Adobe Commerce 2.4.7 to 2.4.9
PHP8.2 to 8.5
Search engineOpenSearch or Elasticsearch (Magento's standard catalogue search)
ThemesLuma, Blank and themes based on them; Hyvä (tested with Hyvä 1.5 and the default theme)
Othersoftaware/module-core (installed automatically)

The module replaces the template of the blocks catalog.leftnav and catalogsearch.leftnav. Themes that move these blocks keep working; a theme that replaces them with its own block needs the template set again.

2. Installation

With Composer. Use the Composer keys from your account on softawarecommerce.com; how to get access is described at https://softawarecommerce.com/shop/composer-access/.

composer config repositories.softaware composer https://repo.softawarecommerce.com
composer config --auth http-basic.repo.softawarecommerce.com PUBLIC_KEY PRIVATE_KEY
composer require softaware/module-layered-navigation
bin/magento setup:upgrade
bin/magento setup:di:compile            # production mode only
bin/magento setup:static-content:deploy # production mode only
bin/magento cache:flush

Hyvä: the module registers itself for Hyvä's Tailwind build. After installing, rebuild your theme CSS (npm run build in the theme's web/tailwind folder) so the filter styles are included. Luma loads the same styles as css/layered-navigation.css without a build step.

To update later: composer update softaware/module-layered-navigation, then the same bin/magento commands.

3. Quick start

  1. Install the module. It is enabled by default, so your category pages show the new filters straight away.
  2. Open Stores > Attributes > Product, pick an attribute that is used in layered navigation (for example color), tab Storefront Properties, and choose Filter Display, Filter Option Order and Filter Expanded on Page Load.
  3. Optional: switch on SEO-Friendly Filter URLs under Softaware > Layered Navigation > Settings for the store views where you want readable addresses.
  4. Refresh the page cache (System > Cache Management) after changing settings.

4. Settings

Softaware > Layered Navigation > Settings, the same page as Stores > Configuration > Softaware > Layered Navigation. Every setting can be set per website and store view. Changing a setting marks the page cache as invalid; refresh it under System > Cache Management.

Layered Navigation settings
Layered Navigation settings

General

SettingDefaultWhat it does
EnabledYesWhen set to No, the standard Magento layered navigation is shown.
Ajax FilteringYesFilters, chips and page links update the product list without a full page reload. Each filtered list keeps its own address, so the Back button, bookmarks and the page cache still work.
Show More Link After8Number of options shown in a filter before a "Show more" link. 0 shows all options.
Search Box for Filters With More Than15A filter with more options than this gets a search box. 0 turns the search box off.
Hide Filters With Only One OptionNoA filter that offers a single option cannot narrow the list, so it can be hidden. Selected filters are always shown.

Filter URLs

SettingDefaultWhat it does
SEO-Friendly Filter URLsNoCategory pages only: readable addresses such as /women/tops-women/color-black-blue/size-m.html instead of ?color=49,50&size=168. Old addresses are redirected (301). Price ranges, sorting and paging stay in the query string.

5. Settings per attribute

Open Stores > Attributes > Product, edit an attribute and go to the tab Storefront Properties. Below "Position" you find three fields:

Filter fields on the attribute page
Filter fields on the attribute page
FieldOptions
Filter DisplayAutomatic (default): swatches for swatch attributes, a slider for price and decimal attributes, checkboxes for everything else. Checkboxes: several options can be selected. Dropdown: one option. Swatches: swatch attributes only. Slider: price and decimal attributes only. Price ranges as links: Magento's price ranges, price and decimal attributes only. A choice that does not fit the attribute falls back to Automatic.
Filter Option OrderOption position (default, as sorted under Manage Options), Name (A to Z), Number of products (most first).
Filter Expanded on Page LoadNo (default) or Yes. A filter with a selected option is always expanded.

"Use in Layered Navigation" and "Position" are Magento's own fields and work as usual: they decide whether the attribute is a filter and where it appears in the list.

6. What your customers see

Filters on Hyvä
Filters on Hyvä

Several options per filter. Options of one attribute are combined with OR, different attributes with AND. A shopper can pick Black and Blue and then size M and sees products that are black or blue and available in M. The counts next to the options of a filter that is already in use are calculated without that filter's own selection, so they show what the shopper would get by adding that option. This costs one extra search request per filtered attribute (at most six per page).

Chips. Every selected option appears under "Now shopping by" with a remove link. "Clear All" removes every filter, and each filter has its own "Clear <filter>" link.

Swatches. Colour, image and text swatch attributes keep their swatches and allow several choices. Colour swatches only accept hex colour values.

Price slider. Price (and decimal attributes set to Slider) get a range slider plus from and to boxes and a Go button. Numbers typed into the boxes are used as typed. The slider needs JavaScript; without it the other filters still work as links.

Long lists. After the number of options set in Show More Link After a "Show more" link appears. Filters with more options than Search Box for Filters With More Than get a search box that narrows the visible options.

Mobile. On small screens the whole filter block folds behind a "Shop By" bar with a badge for the number of active filters.

Mobile filters on Luma (left) and Hyvä (right)
Mobile filters on Luma (left) and Hyvä (right)

Ajax filtering. With Ajax on, clicking a filter, a chip or a page link replaces the product column and the filter block with the same HTML a normal page load returns and updates the address bar. Back and Forward work. Every filtered list is a normal GET address, so it also works without JavaScript and the full page cache stores it like any other page.

Search results. The same filters appear on the search results page, with query-string addresses.

Accessibility. Filters are <details> elements, checkbox options are links with role="checkbox" (Space or Enter), and the slider uses native range inputs plus number inputs.

7. SEO-friendly filter URLs

Switch on SEO-Friendly Filter URLs for the store views you want. Filtered category pages then use this scheme:

<category path without suffix>/<attribute code>-<slug>[-<slug>...][/<attribute code>-<slug>...]<category suffix>

Example: /women/tops-women/color-black-blue/size-m.html.

  • One path segment per attribute, sorted by attribute code; slugs within a segment are sorted alphabetically, so each combination has exactly one address. Other orders redirect (301) to it, and so do the old query-string addresses.
  • Only dropdown, multiple select and yes/no attributes go into the path. Price and decimal ranges, the category filter, sorting and paging stay in the query string (?price=20-50&p=2).
  • The filter router answers only when the path ends with the category URL suffix, the trailing segments are valid filters, the full path is not an existing URL rewrite (products, CMS pages and real subcategories always win) and the rest of the path is a category of the store view.
  • Links that combine two or more filter values get rel="nofollow", so crawlers are not sent through every combination. Single-filter pages stay crawlable.
Friendly filter URLs in the German store view
Friendly filter URLs in the German store view

Filter URL Slugs

Softaware > Layered Navigation > Filter URL Slugs

Filter URL Slugs page
Filter URL Slugs page
  1. Choose an Attribute and a Store View ("All Store Views" or a single view) and click Show Options.
  2. The table lists each option with its admin label, the store view label, the Slug in Use and a Custom Slug field.
  3. Enter custom slugs using a-z, 0-9 and single hyphens. Invalid entries are flagged next to the field and checked again on save; if any entry is invalid, nothing is saved.
  4. Click Save URL Slugs in the page actions bar. Saving cleans the full page cache.

Empty fields use the automatic slug: the transliterated store view label, for example "Light Blue" becomes light-blue. When two options would get the same slug, the option ID is appended. A slug for a single store view takes priority over the one for "All Store Views". Yes/No attributes use yes and no.

Settings in the actions bar opens the module settings, and Edit Attribute opens the attribute.

8. Command line

bin/magento softaware:layered-navigation:slugs <attribute_code> [--store=<code or ID>]

Lists the option IDs, labels and the URL segment of each option for a store view (read-only). Example: bin/magento softaware:layered-navigation:slugs color --store=de.

9. For developers

JavaScript event. After every Ajax update this event fires:

document.addEventListener('softaware:layered-navigation:updated', function (event) {
    // event.detail.url      - the new address
    // event.detail.document - the parsed HTML document of the new page
});

Use it to re-run code that reads the product list on page load, such as analytics list views, sliders or lazy loaders. window.SoftawareLayeredNavigation.load(url) loads a filtered address the same way.

PHP API. Softaware\LayeredNavigation\Api\FilterStateInterface tells other modules what is filtered on the current category or search page: isFiltered(), getAppliedFilters() and isFriendlyUrl(). It is filled while the layered navigation is built, so read it when the page head or body is rendered. The filters are also added to Magento's layer state as usual, so code that reads the layer state keeps working in both URL modes.

10. Permissions (ACL)

Under System > Permissions > User Roles > Role Resources, Softaware > Layered Navigation:

ResourceGives access to
Softaware_LayeredNavigation::layered_navigationThe menu entry
Softaware_LayeredNavigation::slugsFilter URL Slugs
Softaware_LayeredNavigation::configSettings

A role can be given either page on its own. The fields on the attribute page use Magento's own attribute permissions.

11. Troubleshooting

ProblemSolution
The old filters are still shownCheck Enabled for the store view and refresh the page cache. If your theme replaces the catalog.leftnav block with its own block, set the module's template on it again.
Filters look unstyled on HyväRebuild the theme CSS (npm run build in web/tailwind) so the module's styles are compiled in.
A setting has no effect on the storefrontSettings mark the page cache as invalid; refresh it under System > Cache Management.
Ajax filtering does a full page loadThe theme has no .column.main element, so the module falls back to normal page loads. Filtering still works.
A filter is not in the friendly URLOnly dropdown, multiple select and yes/no attributes go into the path; price, decimal and category filters stay in the query string. Search results always use the query string.
An old friendly address returns 404The option label (and with it the automatic slug) was changed. Set a custom slug under Filter URL Slugs to keep the address.
An option stays in the query string with friendly URLs onIf a combination of slugs could be read in two ways, that filter stays in the query string. Give one of the options a different custom slug.

12. Uninstall

bin/magento module:disable Softaware_LayeredNavigation
composer remove softaware/module-layered-navigation
bin/magento setup:upgrade
bin/magento cache:flush

With friendly URLs switched off (or the module removed), category pages use Magento's own filter addresses again.

Changelog

Release notes

1.1.3

Latest
  • docs/listing.json, docs/faq.md, docs/user-guide.md and screenshots in docs/images/ (Luma, Hyvä, mobile, friendly filter URLs, admin).

1.1.2

  • Price/decimal slider: numbers typed into the from/to boxes are used as typed. They used to be clamped to the range of the products left, so 30–60 on a list priced 75–77 applied price=-75 (up to 75) and showed a product outside the requested range. A selected range outside the products' range now widens the slider instead of being changed, so the boxes show what was asked for (Luma and Hyvä).
  • ACL: the module has its own resource *Softaware > Layered Navigation* (Softaware_LayeredNavigation::layered_navigation) with *Filter URL Slugs* and *Settings* below it. The menu entry used to require the Settings permission, so a role with only Filter URL Slugs did not see it. Settings moved there from *Stores > Configuration*; existing roles that had either permission get the new parent (data patch), with their Settings and Filter URL Slugs rights unchanged.

1.1.1

  • Filter URL Slugs: *Save URL Slugs* and *Settings* sit in the page actions bar (Save only when there is something to save); the attribute and store view selection is a tidy filter bar whose attribute list is no longer cut off; column headings in title case ("Slug in Use", "Custom Slug"); invalid slugs are flagged next to the field before anything is posted; an *Edit Attribute* link next to the table.
  • Filter URL Slugs: empty states with the next step when there are no filterable attributes (*Manage Product Attributes*) or the attribute has no options, and the "filter URLs are switched off" notice links to the settings.
  • Settings: every field has "Use system value", comments name the defaults, General opens first, the number fields accept whole numbers from 0 only, and the long Filter URLs comment is shorter and links to Filter URL Slugs. The menu item is called "Settings" like in the other modules.
  • Attribute edit page (Storefront Properties): the layered navigation fields name their defaults; Filter Option Order explains what it sorts.
  • Admin styles moved from inline attributes to view/adminhtml/web/css/admin.css; no horizontal overflow at 1024 px.

1.1.0

  • Requires softaware/module-core instead of softaware/module-base. The admin menu and ACL now sit under Softaware_Core::core ("Softaware"); roles that had access keep it (migrated by module-core). After updating all SoftAware modules, softaware/module-base can be removed.

1.0.0

  • First release: multi-select filters with disjunctive counts from the search engine, "Now shopping by" chips, checkbox, swatch, dropdown and price/decimal slider display per attribute, option order and expanded state per attribute, "Show more" and search inside long filters, Ajax filtering with address bar and back button support, optional SEO-friendly filter URLs for category pages with editable option slugs and 301 redirects from query-string addresses, filters on search results, FilterStateInterface for other modules, Luma and Hyvä.

FAQ

Questions, answered

Something else on your mind? The developers who wrote the module answer before and after you buy.

Ask a question →

Already installed it? Open a support ticket

What does it change compared with Magento's own layered navigation?

Shoppers can pick several options in one filter (for example Black or Blue) and combine filters (Black or Blue, in size M). Selected options are shown as "Now shopping by" chips with a remove link, "Clear All" and "Clear <filter>". Each attribute can be shown as checkboxes, swatches, a dropdown or a price slider, long lists get "Show more" and a search box, the list updates without a full page reload, and filtered category pages can have readable addresses.

Are the product counts correct when several options are selected?

Yes. Options of one attribute are combined with OR, so the counts of a filter you are already using are calculated without that filter's own selection ("disjunctive" counts). This costs one extra search request per filtered attribute, at most six per page. All counts come from the search engine (OpenSearch or Elasticsearch); nothing is queried per product.

Does it work with Hyvä?

Yes. The module ships Hyvä layout handles and registers itself for Hyvä's Tailwind build, so the styles are merged into your theme CSS when you rebuild it. The behaviour is one small vanilla JavaScript file shared by Luma and Hyvä, with no RequireJS, jQuery or Alpine needed. It was tested with Hyvä 1.5 and the default theme.

What do the SEO-friendly filter URLs look like?

/women/tops-women.html?color=49,50&size=168 becomes /women/tops-women/color-black-blue/size-m.html. Each attribute gets one path segment, sorted by attribute code, and the options within a segment are sorted alphabetically, so every combination has exactly one address. Other orders and the old query-string addresses answer with a 301 redirect. The setting is off by default and can be switched on per store view.

Can I use my own words in the filter URLs, for example in German?

Yes. Under Softaware > Layered Navigation > Filter URL Slugs you pick an attribute and a store view and enter a slug for each option (letters a to z, digits and single hyphens). Empty fields use the store view's option label. The demo's German store view uses German colour slugs such as color-blau-schwarz.

Which filters go into the friendly URL?

Dropdown, multiple select and yes/no attributes on category pages. Price and decimal ranges, the category filter, sorting and paging stay in the query string (for example ?price=20-50&p=2). Search results keep query-string filters.

Can friendly filter URLs clash with products, CMS pages or subcategories?

No. The filter router only answers when the full address is not an existing URL rewrite, so products, CMS pages and real subcategories always win. It also checks that the rest of the path is a category of the store view and that every segment is a valid filter.

Will search engines crawl every filter combination?

Links that combine two or more filter values get rel="nofollow", so crawlers are not sent through every combination; pages with a single filter value stay crawlable. If you use an SEO module for robots and canonical tags, it can read the current filters through the module's FilterStateInterface.

Does Ajax filtering break the full page cache or the Back button?

No. Every filtered list is a normal GET address, so the full page cache stores it like any other page and the list works without JavaScript. With Ajax filtering on, the product list, the filters and the address bar update without a reload, and Back and Forward work.

My theme or another extension runs code on the product list. Does it still work after an Ajax update?

The product column is replaced with the same HTML a normal page load returns, Luma widgets are started again and on Hyvä inline scripts run and Alpine components are initialised. After that the event softaware:layered-navigation:updated fires on document, so analytics, sliders or lazy loaders can run again.

Is there a stock status or rating filter?

Not in this version. Stock status and ratings are not offered as filters.

What happens to old friendly addresses when I rename an option?

The automatic slug follows the option label, so an address with the old name returns 404. Set a custom slug under Filter URL Slugs to keep an address when you rename an option.

Support

Help from the developers who wrote it