etechflow / module-vehicle-compat
etechflow/module-vehicle-compat
Universal Product Fitment Finder for Magento 2. Make/Model/Year/Part filtering on any fitment domain — automotive, motorcycle, marine, RV, bicycle, phone accessories, watch straps, appliance parts, or any product where customers ask "will this fit my X?". Admin-configurable labels and field visibility. SEO-friendly URLs, PDP fitment badges, customer garage. Theme-agnostic — Hyvä, Luma, custom themes.
ETechFlow_VehicleCompat — Vehicle Compatibility + Part Finder for Magento 2
A complete vehicle compatibility (Make / Model / Year / Part) system for Magento 2 stores selling automotive products. Theme-agnostic by design — bundles its own Alpine.js loader so it works on Hyvä, Luma, and any custom theme without code changes.
- Version: 1.0.0
- Package:
etechflow/module-vehicle-compat - Magento: 2.4.4 – 2.4.8
- PHP: 8.1, 8.2, 8.3
- License: proprietary (see
LICENSE.txt) - Vendor: ETechFlow — https://etechflow.com
What's in the box
Two halves of one feature, intentionally bundled in one module:
Half 1 — Vehicle compatibility data
vehicle_compat_dataproduct attribute (JSON) storing every (Make, Model, Year) combination a product fits.parts_requiredproduct attribute (multi-select) tagging which part-types each product covers (key blade, transponder, immobilizer chip, etc.).- Admin CRUD for Makes and Models under Catalog → Vehicles → Makes / Models.
- CSV import for bulk-loading vehicle compatibility data (
bin/magento etechflow:vehiclecompat:import-parts). - Product edit form modifier — a visual Make/Model/Year picker tab on every product, so the admin doesn't hand-edit JSON.
Half 2 — Part Finder widget
/vehiclecompat/options/index— server-side filtered options endpoint. Each dropdown click sendsfield=make|model|year|part+ current selections, server applies bidirectional filter and returns only matching options./vehiclecompat/tree/index— full vehicle tree (cached, browser-cacheable for 1h)./vehiclecompat/find/index— find-parts results page that filters the catalog by the customer's vehicle.- Shareable form fragment (
ETechFlow_VehicleCompat::partfinder/form.phtml) that drops into any layout — header modal, hero section, PDP sidebar, all use the same template. - Self-contained Alpine.js bootstrap — on Hyvä stores Alpine is already loaded; on Luma / custom themes the bootstrap lazy-loads Alpine from a CDN (URL is overridable for stores that want to self-host).
- Shared Alpine store so multiple form instances on the same page (desktop hero + mobile hero + header modal) stay in sync.
Theme compatibility
| Theme | Status | What happens |
|---|---|---|
| Hyvä (Tailwind + Alpine) | ✅ Native | Alpine is global. The bootstrap shim becomes a no-op. Module just works. |
| Luma / Blank | ✅ With bootstrap | The bootstrap shim detects no Alpine and lazy-loads it from a CDN. Module works. |
| Custom themes (Luma parent) | ✅ With bootstrap | Same as Luma. |
| Custom themes (Hyvä parent) | ✅ Native | Same as Hyvä. |
| Air-gapped / no-CDN stores | ⚠️ Self-host Alpine | Replace the CDN URL in view/frontend/web/js/alpine-bootstrap.js with your self-hosted Alpine URL, or pre-install Alpine in your theme. |
| Headless / PWA Studio | ⚠️ Use API only | Use /vehiclecompat/options/index directly from your headless storefront. The PHP-rendered form fragment is skipped in headless. |
See COMPATIBILITY.md for the full audit.
Quick start
# 1. Extract into your Magento root
unzip etechflow-module-vehicle-compat-1.0.0.zip -d <magento-root>/
# 2. Enable + migrate (creates DB tables + product attributes)
cd <magento-root>
bin/magento module:enable ETechFlow_VehicleCompat
bin/magento setup:upgrade
bin/magento setup:di:compile # production-mode only
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
# 3. Visit the admin
open https://your-store.example.com/admin/etechflow_vehicle/make/index
# (Admin sidebar → Catalog → Vehicles → Makes / Models)
# 4. Embed the Part Finder on your homepage / header
# Reference: USAGE.md → "Embedding the Part Finder form"
Documentation index
| File | Purpose |
|---|---|
README.md |
Overview, features, theme matrix (this file) |
INSTALL.md |
Manual + Composer install + verification + troubleshooting |
USAGE.md |
Admin walk-through (Make/Model CRUD, product editor, CSV import) + how to embed the Part Finder widget |
CONFIGURATION.md |
Alpine bootstrap CDN URL, server-side filter behavior, caching |
COMPATIBILITY.md |
Theme + Magento + PHP matrix and the design choices that keep it portable |
CHANGELOG.md |
Version history |
UNINSTALL.md |
Clean removal |
LICENSE.txt |
proprietary license |
Support
- Email: [email protected]
- Include: Magento version, PHP version, active theme, sample product with vehicle data, screenshot.
License
proprietary — see LICENSE.txt.
Changelog — ETechFlow_VehicleCompat
[1.0.3] — 2026-06-03 — Restore docs accidentally pruned during v1.0.2 publish-repo sync
The v1.0.2 release shipped clean code but the publish-repo rsync
accidentally deleted the top-level documentation files
(INSTALL.md, USAGE.md, CONFIGURATION.md, COMPATIBILITY.md,
UNINSTALL.md) that ship at the repo root alongside README and
CHANGELOG. This release restores them.
No code change. No behaviour change. Pure documentation file
restoration plus V103ReleaseMarker for always-a-patch discipline.
If you installed 1.0.2 you're functionally fine — composer doesn't
care about INSTALL.md vs not. But the GitHub repo page was missing
those docs and 1.0.3 puts them back.
Migration
composer require etechflow/module-vehicle-compat:^1.0.3
bin/magento setup:upgrade
bin/magento cache:flush
[1.0.2] — 2026-06-03 — Universal fitment: admin-configurable labels, Year bounds, optional Year field
Same module, three new admin knobs that make it work for any
product-fitment domain — not just vehicles. Drop-in upgrade from
1.0.1, no schema change, no breaking change. Default behaviour
identical to 1.0.1 (Year field visible, "Make/Model/Year/Parts"
labels, year range 1990 – current).
Added
Three new admin fields under Stores → Configuration → eTechFlow →
Vehicle Compatibility → General Settings:
-
Earliest Year — text field, default
1990. The oldest year
that appears in the Year dropdown. Set to1950for vintage car
parts shops (classic Mustangs, Series Land Rovers). Set to2007
for smartphone-fitment shops where there's no point listing
pre-iPhone years. Anything below 1900 or above the current year
gets clamped to safe bounds. -
Show Year Field — Yes/No, default Yes. When No, the Year
dropdown disappears from the Part Finder form. The form becomes
Make → Model → Parts, which is what phone case shops, watch strap
shops, printer cartridge shops, and appliance parts shops actually
need. -
Field Labels — 4 separate text fields for the customer-facing
labels:- Make Field Label (default "Make") — set to "Brand" for
phone cases / watches / appliances - Model Field Label (default "Model") — set to "Phone" /
"Watch" / "Appliance Model" - Year Field Label (default "Year") — set to "Generation"
for phones, "Year of Manufacture" for older fitments - Parts Field Label (default "Parts Required") — set to
"Type" / "Style" / "Strap Size" / "Component"
When the labels are configured, the Part Finder dropdowns render
the merchant's wording instead of "Select Make / Select Model /
etc." A blank label falls back to the default. - Make Field Label (default "Make") — set to "Brand" for
Changed
-
Model/Source/Year.php—MIN_YEARconstant is now
@deprecated; the year source reads fromConfig::getEarliestYear()
instead. Constant kept on disk so any third-party code referencing
it doesn't immediately fatal. -
Block/PartFinderData.php— gains 5 public getters:
getMakeLabel(),getModelLabel(),getYearLabel(),
getPartLabel(),isYearFieldEnabled(). Templates and any
custom integration can read the configured values. -
view/frontend/templates/partfinder/form.phtml— uses the
configured labels for placeholder texts; wraps the Year field
block withif ($block->isYearFieldEnabled())so it can disappear
entirely when not relevant. -
Setup/Patch/Data/V102ReleaseMarker.php— no-op release
marker patch, depends on V101.
Why this matters
This release transforms the module from "Vehicle Compatibility" into
a "Universal Product Fitment Finder". The same code now sells to:
- Auto parts (as before —
Make/Model/Year/Partsworks perfectly) - Motorcycle / marine / RV / ATV / bicycle parts (same labels work)
- Vintage car parts (set Earliest Year to 1950)
- Phone cases (set labels to
Brand/Phone/Generation/Style, hide
Year, set Earliest Year to 2007) - Watch straps (
Brand/Watch/<hide year>/Strap Size) - Printer cartridges (
Brand/Printer/Year/Cartridge Type) - Appliance parts (
Brand/Appliance Model/Year/Part Type) - Any product fitment problem the merchant can map to 2-4 axes
Competing against Amasty Product Parts Finder (~$399) at a fraction
of the price.
Not changed
- No schema changes — drop-in upgrade from 1.0.1
- No URL changes — existing
/vehiclecompat/find/indexURLs keep working - No API changes — public block + service methods unchanged
- Default behaviour identical to 1.0.1 — merchants who don't touch
the new fields see no change at all
Migration
composer require etechflow/module-vehicle-compat:^1.0.2
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
Pre-flight check:
SELECT module, schema_version, data_version FROM setup_module
WHERE module='ETechFlow_VehicleCompat';
Both should read 1.0.2. If data_version is stale, re-run
setup:upgrade — do NOT flush cache yet.
To opt in to the universal-fitment positioning:
- Set your merchant's label preferences in
Stores → Configuration → eTechFlow → Vehicle Compatibility →
General Settings. - If your fitment domain doesn't use year, set Show Year Field to No.
- Save → flush cache → reload the Part Finder.
[1.0.1] — 2026-06-03 — Brand de-leak: rename Keystation-derived routes, files, and CSS classes
Cosmetic but important release. Renames every customer-visible and
admin-visible identifier that still carried the original developer's
"Keystation Vehicle Compatibility" (kvc) / "Keystation" branding, so the
module ships as a generic eTechFlow product any merchant can install
without seeing another shop's name in their URLs or DevTools.
Changed (customer-facing)
- URL prefix renamed:
frontName="kvc"→frontName="vehiclecompat".
Part Finder page is now at/vehiclecompat/find/indexinstead of
/kvc/find/index. The Options + Tree AJAX endpoints follow:
/vehiclecompat/options/index,/vehiclecompat/tree.json. - Frontend JS file renamed:
view/frontend/web/js/kvc-part-finder.js
→part-finder.js. The Alpine.js function inside is now
vehicleCompatPartFinder()(waskvcPartFinder()), and its store key
is'vehicleCompatSel'(was'kvcSel'). - CSS class prefix:
kvc-*→vc-*across all templates (vc-row,
vc-ico-left,vc-trigger,vc-side,vc-find-page,vc-pager,
vc-cat-chips, etc.). Keeps the prefix short while removing the
Keystation branding. - Frontend layout file:
view/frontend/layout/kvc_find_index.xml→
vehiclecompat_find_index.xml. - Block names in layout XML:
kvc.sidebar.summary/
kvc.category.filter.chips→vehiclecompat.sidebar.summary/
vehiclecompat.category.filter.chips.
Changed (admin-facing)
- 11 admin layout + UI component files renamed from
keystation_vehicle_*toetechflow_vehicle_*so they match the
module's existing admin route id (etechflow_vehicle). Previously
they were dead-code on disk (route id and file name didn't match;
Magento auto-loads layout by URL pattern). Renaming gets them back
on the auto-load path under the canonical eTechFlow naming.
Added
Setup/Patch/Data/V101ReleaseMarker.php— no-op release marker
patch. Continues the always-a-patch discipline. Depends on the three
v1.0.0 data patches so patches run in version order.
Breaking changes ⚠
Anyone who installed v1.0.0 in the ~1 hour between v1.0.0 and v1.0.1
publication will see the Part Finder URL change. No real customers
were installed at the time of this release. Bookmarks pointing at
/kvc/find/index will 404 — clients should update to
/vehiclecompat/find/index.
If you've embedded the Part Finder form in CMS blocks or themes via
JavaScript, the Alpine.js function call needs renaming:
kvcPartFinder() → vehicleCompatPartFinder(). Same for any
Alpine.store('kvcSel') references.
Why this exists
The original developer of this module built it first for the Keystation
brand and then handed the code to eTechFlow. The brand prefixes
(kvc/, keystation_vehicle_*) survived the rebadge. v1.0.0 shipped
with that leak. v1.0.1 cleans it up so the module sells generically.
Migration
composer require etechflow/module-vehicle-compat:^1.0.1
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
Pre-flight check after upgrade:
SELECT module, schema_version, data_version FROM setup_module
WHERE module='ETechFlow_VehicleCompat';
Both columns should read 1.0.1. If data_version is stale, re-run
setup:upgrade — do NOT flush cache yet.
After upgrade, the Part Finder page is at /vehiclecompat/find/index.
A merchant who wants to preserve the old /kvc/* URLs can ship a
custom URL rewrite from /kvc/* to /vehiclecompat/* in their web
server config — but a fresh install no longer publishes any /kvc/*
URLs at all.
1.0.0 — 2026-05-20
First public release as a standalone, theme-agnostic Magento 2 module.
Added
- Vehicle compatibility data
vehicle_compat_dataproduct attribute (JSON) — Make / Model / Year tuples per productparts_requiredmulti-select product attribute- Admin Makes CRUD under Catalog → Vehicles → Makes
- Admin Models CRUD under Catalog → Vehicles → Models
- Product editor tab with visual Make/Model/Year picker (no hand-edited JSON)
- CSV import command:
bin/magento etechflow:vehiclecompat:import-parts
- Part Finder widget
- Reusable form fragment (
ETechFlow_VehicleCompat::partfinder/form.phtml) — embed anywhere - Server-side filtered options endpoint
/vehiclecompat/options/index(bidirectional) - Full vehicle tree endpoint
/vehiclecompat/tree/index(cached, browser-cacheable) - Find-parts results page
/vehiclecompat/find/indexwith category chips - Shared Alpine store keeps multiple form instances in sync (header modal + hero + sidebar)
- Reusable form fragment (
- Theme-agnostic JS bootstrap
alpine-bootstrap.jsdetects Alpine, lazy-loads it from CDN if absentpart-finder.jsfactory function — loaded once via layout XML- Both loaded on every storefront page via
view/frontend/layout/default.xml
- Scoped namespaced CSS
.vc-*class prefix prevents theme collisions- Inline
<style>block inpartfinder/styles.phtml
- Catalog filter integration
Plugin\Catalog\Layer\FilterByVehiclenarrows product collections by?make_id=&model_id=&year=&part_id=URL paramsPlugin\Catalog\Block\HideLayeredNavhides the layered nav on/vehiclecompat/find/indexpages
- Documentation bundle
- README, INSTALL, USAGE, CONFIGURATION, COMPATIBILITY, CHANGELOG, UNINSTALL, LICENSE
Compatibility
- Magento 2.4.4 – 2.4.8
- PHP 8.1, 8.2, 8.3
- Hyvä Theme (native — Alpine global)
- Luma / Blank / custom themes (Alpine auto-loaded from CDN)
- Adobe Commerce + Magento Open Source + Mage-OS
| Version | Stability | QA Status | Compatibility | Released |
|---|---|---|---|---|
| 1.2.1 | stable | Fail | Magento 2.4.7-2.4.8 Details | 2026-06-03 16:12:56 |
| 1.2.0 | stable | Not tested | Not yet tested Details | 2026-06-03 13:22:54 |
| 1.1.1 | stable | Not tested | Not yet tested Details | 2026-06-03 13:03:05 |
| 1.1.0 | stable | Not tested | Not yet tested Details | 2026-06-03 10:56:25 |
| 1.0.3 | stable | Not tested | Not yet tested Details | 2026-06-03 10:47:01 |
| 1.0.2 | stable | Not tested | Not yet tested Details | 2026-06-03 10:45:39 |
| 1.0.1 | stable | Not tested | Not yet tested Details | 2026-06-03 10:29:19 |
| 1.0.0 | stable | Not tested | Not yet tested Details | 2026-06-03 10:22:30 |
Requires 6
| Package | Constraint |
|---|---|
| magento/framework | >=103.0 |
| magento/module-backend | >=102.0 |
| magento/module-catalog | >=104.0 |
| magento/module-store | >=101.0 |
| magento/module-ui | >=101.0 |
| php | ~8.1.0||~8.2.0||~8.3.0||~8.4.0 |
No QA results yet
QA pipelines haven't run for this version. Compatibility and quality results appear here once the vendor publishes a tagged release that gets ingested.
More from etechflow
View vendorDynamic 'View Other Options/Finishes/Sizes' PDP buttons driven by per-product link attributes; replaces hardcoded in-description buttons and strips the old ones at render time.
Theme-agnostic mega menu for Magento 2. Renders on Hyvä, Luma, Adobe Commerce default and custom themes via automatic runtime detection. Provides a JSON endpoint for lazy-loaded subcategory + featured-product data.
EtechFlow Store Locator — admin-managed store/branch finder for Magento 2 with a Leaflet + OpenStreetMap map and postcode proximity search (postcodes.io). Hyva and Luma compatible. No paid map API key required.
Universal Product Fitment Finder for Magento 2 — Make/Model/Year/Part filtering on any fitment domain (automotive, motorcycle, marine, RV, phone cases, watches, appliance parts, anywhere a customer asks "will this fit my X?"). Admin-configurable labels + URL prefix so the same module rebrands to any merchant domain. Includes PDP fitment badge, SEO URLs, customer garage with cross-device sync, OEM/part-number search, and admin tooltips throughout. Theme-agnostic — Hyvä, Luma, custom themes. Renamed from "module-vehicle-compat" in v2.0.0.
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.