A minimum-area filter that offered one exact lot
The land-size dropdown offered 350, 383, 416 and 449 square metres. Every one of those was a real lot in the estate, which is precisely what made the filter useless.
Client anonymised — a residential land developer, delivered under another company. Estate names, page identifiers and staff names are withheld or changed.
- Steps after the fix
- At most 5 round jumps across the range
- Files changed
- Module template only
- Module instances affected
- None lost their saved settings
- Second defect found
- Identical bug in the price filter
A filter that read as an exact match
A marketing lead reported that the land-size filter on a live estate page was behaving oddly. The dropdown was offering 350, 383, 416, 449 — sequences that no buyer thinks in.
The values were not random. Each was the exact area of one specific lot currently for sale. So a control labelled "Minimum Area" was effectively asking the visitor to pick a particular block, which is the opposite of what a filter is for. Anyone using it either selects a value that matches one lot, or gives up.
Half the logic was right
The module was doing something sensible and something wrong in the same six lines.
The sensible half: it derived the ends of the range from the active listing type's real stock, so the filter never offers a bracket with nothing in it. That is genuinely the right behaviour and worth preserving.
The wrong half: having found the true low and high, it then divided the gap into even steps. Even steps between two arbitrary real numbers produce arbitrary real numbers. The bounds were correct and the intervals between them were meaningless.
The price filter had the identical six lines and the identical defect. Finding the second one was a matter of reading the neighbouring function rather than waiting for it to be reported separately.
Rounding as the actual requirement
The fix replaced both copies with one shared loop that picks the smallest round step — one, two or five times a power of ten — that covers the range in no more than five jumps, then floors the low end onto that step and ceils the high end onto it.
That produces the brackets a person would have written by hand, and it keeps working when the stock changes. A new lot at an unusual size shifts the bounds; it no longer contaminates every option in the list.
The change was confined to the module template. No JavaScript, no CSS, and critically no change to the module's field definitions — which is what meant every existing instance of the module across the site kept its saved settings. A fields change here would have been a much larger and riskier deployment for no additional benefit.
The related bug that was found by measuring rather than looking
A second issue on the same page was reported as a hover state that looked wrong. Diagnosing it by eye would have been guesswork, so the computed styles were read directly under a real hover in a live browser.
That showed a global theme override targeting every button on hover, with a specificity that outranked the module's own resting style. On hover, the control was swapping typeface entirely and acquiring an unwanted pill background.
The correction was to match the site's established navigation behaviour — an underline and a slight text-stroke — rather than invent a third hover style. Two details mattered: the border was pinned so the label does not shift by a pixel on hover, and the focus state was reset so the underline does not stick after a mouse click. The geometry was expressed in relative units so it stays in proportion with the navigation it is imitating.
The fix went into its own stylesheet rather than the shared one, because it reaches into a module that is not to be edited directly, and that boundary is worth keeping visible in the file layout.
Status
Both filters shipped and deployed to the client portal. The hover regression is fixed and regression-checked against the other styled sections on the page. Awaiting client review before go-live on the affected estate page.
CMS modules, template logic and the front-end details that decide whether a filter gets used or abandoned.
HubSpot Engineering