#702·unopim

[Feature]: Make the attribute codes the product grid's quick search looks in configurable

Author: astek100Created Sep 12, 2026Updated Sep 12, 2026

Pre-submission checklist

  • I have searched the existing issues and this feature has not already been requested.

Is your feature request related to a problem? Please describe.

On a 30,659-product catalogue, typing a product's full 13-digit EAN into the product grid's search box returns nothing. Typing its SKU returns it at once.

The value is not missing from the backend. Elasticsearch is enabled, the indexer maps the attribute, and querying the index for that EAN directly returns the product in well under a second. The grid never asks for it, because the field list is a literal — ProductDataGrid::processFilters(), the all branch:

php
$queryBuilder->applySkuOrUnfilteredFilter(['sku', 'name'], FilterOperators::WILDCARD, $value, $context);

That one line decides what the quick search looks in, on both the Elasticsearch and the database path, and has been unchanged since February 2025. Everything below it is already generic: both SkuOrUniversalFilter implementations take an array of codes and skip the ones that do not resolve. Only the caller is fixed.

Describe the solution you'd like

A configuration key holding those codes, defaulting to today's behaviour:

php
// config/products.php
'search_fields' => ['sku', 'name'],

so an administrator can write ['sku', 'name', 'ean', 'supplier_article_number'].

So a bad value degrades instead of breaking the grid:

  • Unchanged out of the box, including on installations upgraded from a release whose config/products.php predates the key.
  • Text attributes only — Elasticsearch maps price as float and date as date, and the option types store the option code rather than the typed label. textarea excluded too: a description matches most of the catalogue, and the grid orders by its sort column, not by relevance.
  • Unknown codes are skipped; if nothing is left, SKU and name are searched.
  • Capped at ten, with SKU and name pinned to the front. Every code adds a clause — on the database path a JSON extraction plus a leading-wildcard LIKE per product.

Describe alternatives you've considered

Per-column filters. An attribute with is_filterable can be added as a column and filtered with contains, which does cover part of this. Two gaps: it is per-session setup rather than one box, and the seeded identifier attribute product_number ships is_filterable => 0, so on a fresh install it is not reachable that way at all. That is also why the proposed list should not consult is_filterable.

Switching to Elasticsearch. Already the case here, and it changes nothing: the index holds the value, the query never asks for it.

Patching the grid downstream. getSearchFields() would be protected and processFilters() is the only seam, so every module wanting this has to copy the method. Two of them in one installation conflict.

Additional Context

While verifying this we found a related defect worth fixing first, separately: when none of the codes handed to SkuOrUniversalFilter resolves, both engines answer with the entire catalogue rather than with nothing. The database filter opens an empty where group, which the query builder drops; the Elasticsearch filter emits {"bool": {"should": [], "minimum_should_match": 1}}, which Lucene turns into a MatchAllDocsQuery before minimum_should_match is considered.

We have a patch against 3.x — the config key, the fallback and cap, that fix as its own commit, tests and a CHANGELOG entry — and will open a PR referencing this issue. Happy to drop it if you would rather build this in-house, or to rework it toward an is_searchable column if you prefer that direction.


Disclosure: this report was written by Claude Opus 5 (Anthropic) working on our installation. Every figure and code reference above was measured or read on a running 3.1.0 instance, not inferred.