# etechflow/module-product-fitment-finder

> 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.

`composer require etechflow/module-product-fitment-finder`

Canonical URL: https://packagento.com/etechflow/module-product-fitment-finder

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: 2.0.0 — released 2026-06-05
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/etechflow/module-product-fitment-finder and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require etechflow/module-product-fitment-finder:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

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.

## README

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-product-fitment-finder`
- **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_data`** product attribute (JSON) storing every (Make, Model, Year) combination a product fits.
- **`parts_required`** product 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 sends `field=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_ProductFitmentFinder::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

```bash
## 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_ProductFitmentFinder
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: support@etechflow.com
- Include: Magento version, PHP version, active theme, sample product with vehicle data, screenshot.

---

### License

proprietary — see `LICENSE.txt`.

## Changelog

### [1.2.1] — 2026-06-03 — Storefront copy polish + customer-facing tooltips + theme accent colour

Final polish release. v1.1.1 / v1.2.0 made the big strings
configurable; v1.2.1 sweeps up the remaining ~12 minor strings,
adds 3 optional customer-facing tooltips, and replaces the hardcoded
inline accent colour with a CSS custom property so themes can override.

#### Added — 12 new copy fields under new admin group "Storefront Copy Polish + Tooltips"

Every remaining customer-visible string now configurable:

1. **"No Results" Title** — when filters return zero products (default `No products match all your filters.`)
2. **"No Results" Hint** — secondary line (`Try removing one or two filters…`)
3. **"Use the Form" Prompt** — secondary line in empty-state (`Use the form above to start.`)
4. **Dropdown "No Matches"** — when a typed search yields no items (`No matches`)
5. **Dropdown Search Placeholder** — each dropdown's search input (`Search…`)
6. **PDP Fitment Badge Overflow** — template with `{count}` placeholder (`and {count} more`)
7. **Garage Widget Title** — default `My Garage`. Watch shop: `My Watches`. Phone shop: `My Phones`.
8. **Garage Clear-All Button** — `Clear Garage`
9. **Garage Remove Label** — `Remove` (aria-label + title for × button)
10. **"Saved!" Confirmation Text** — the 1.5s post-save microinteraction
11. **Sidebar "No Filters" Message** — `No filters active.`
12. **OEM Search Submit Button** — `Search`

#### Added — 3 customer-facing tooltips (all optional)

Rendered as standard HTML `title=""` attributes. Blank value → no tooltip.

13. **PDP Fitment Badge Tooltip** — suggested:
    > "This list shows the vehicles this part fits. Match your car's Make, Model and Year to confirm."
14. **My Garage Tooltip** — suggested:
    > "Vehicles you've saved for quick reload. Click any vehicle to filter the catalog by that fit."
15. **OEM Search Tooltip** — suggested:
    > "Paste a part number (OEM, MPN, or your store's SKU) to find the matching product directly."

Each tooltip default is **empty** — opt in by typing a message in admin.
The PDP fitment badge gains `tabindex="0"` when a tooltip is set so
keyboard users get the hover help.

#### Added — Theme accent colour

16. **Accent Colour (hex)** — six-digit hex, default `#0535F5`
    (eTechFlow blue). Validated against `/^#?[0-9a-f]{6}$/i`; anything
    malformed falls back silently. Drives:
    - OEM Search submit button (via `var(--etechflow-vc-accent, #0535F5)`)
    - Find page CSS custom property `--etechflow-vc-accent` scoped to the
      `.vc-find-page` wrapper. Your theme CSS can also override it
      globally for full design-system integration.

Common values: `#16A34A` green / `#DC2626` red / `#7C3AED` purple.

#### Added — supporting infrastructure

- `Setup/Patch/Data/V121ReleaseMarker.php` — always-a-patch discipline.
  Depends on `V120ReleaseMarker`.
- **16 new Config getters** covering all of the above. Accent colour
  getter validates input shape to defend against malformed values.

#### Changed

- `Block/FindResults`: 7 new getters.
- `Block/PartFinderData`: 4 new getters for the form template.
- `Block/Garage`: 5 new getters.
- `Block/Product/FitmentBadge::getRenderData()`: now includes
  `more_text` (configurable overflow) and `tooltip` (optional title).

#### Templates updated

- `product/fitment-badge.phtml`: tooltip + configurable overflow
- `garage/widget.phtml`: tooltip + title/clear/remove all configurable
- `find/results.phtml`: no-results / use-form copy + OEM tooltip +
  OEM button text + CSS variable for accent
- `find/chips.phtml`: use-form prompt configurable
- `find/sidebar.phtml`: no-filters message configurable

#### Not changed

- No schema changes — drop-in from 1.2.0.
- All 16 new fields opt-in; defaults preserve v1.2.0 behaviour exactly.
- No URL or API breakage.

#### Migration

_(Changelog truncated for .md surface. Full history on https://packagento.com/etechflow/module-product-fitment-finder.)_

## Recent Versions

| Version | Released |
|---|---|
| 2.0.0 | 2026-06-05 |

## Dependencies

### Require

| 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 |

## Quality

Latest release (2.0.0) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | not tested |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 554 | 1 error, 553 warnings (ruleset: Magento2) — 291 auto-fixable with phpcbf |
| PHPMD | Warning | 47 | 47 rule violations (CyclomaticComplexity:14, NPathComplexity:13, MissingImport:8, ExcessiveMethodLength:5, ExcessiveClassComplexity:3) |
| Cpd | Warning | 3 | 3 duplicated chunks spanning 81 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 6 | valid; 6 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 66 | 66 | – | – |
| 2.4.8 | – | 64 | 64 | – |
| 2.4.9 | – | – | 64 | N/A |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["etechflow/module-product-fitment-finder"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

etechflow is a Magento 2 vendor on Packagento. See https://packagento.com/etechflow.md for their full catalogue.

