etechflow / module-seo-audit
etechflow/module-seo-audit
On-demand SEO health audit + score for Magento 2: scans products, categories and CMS for meta/content/link/schema issues and links each to the fix. Part of the Etechflow SEO Suite.
Etechflow_SeoAudit
On-demand SEO health audit + score for Magento 2. Scans your products, categories and CMS pages for SEO problems, gives the store a 0-100 health score, and lists every issue in an admin grid — each one tagged with the suite module that fixes it. Part of the Etechflow SEO Suite.
What it checks
| Area | Checks |
|---|---|
| Meta | products/categories/CMS missing meta title or description, duplicate meta titles or descriptions, meta titles/descriptions too short/long |
| Content | thin or missing product descriptions, products with no base image, and (rendered) pages whose main image has no alt text or with a missing/duplicate H1 |
| Links | logged 404s and redirect chains (via Etechflow_RedirectManager — soft dependency) |
| Canonical | rendered-HTML check on a sample of product pages: missing canonical, duplicate canonical tags, or a canonical that points to a URL which redirects (301/302) or 404s — the kind of render-time fault data-only checks can't see |
| Indexability | rendered-HTML checks for pages quietly lost from Google: live (200) pages returning noindex (robots meta or X-Robots-Tag), live catalogue URLs blocked by robots.txt, and dead/redirecting URLs listed in the XML sitemap (plus a sitemap not referenced in robots.txt) |
| Social | rendered-HTML check: product pages missing Open Graph / Twitter Card tags (how links look when shared), or an og:url on a different domain than the store (catches dev/staging-domain leakage after a domain swap) |
| Schema | rendered-HTML check: product pages with no Product JSON-LD structured data (Google's preferred format for rich results — price, availability, ratings). Handles @graph and arrays |
Each check is a small class implementing Api\CheckInterface, registered into the scanner pool in etc/di.xml — so you can add your own checks without touching core.
How it works
- Scanner runs every registered check (most are fast, SQL-backed; the canonical and indexability checks fetch a sample of rendered pages over HTTP via the shared
Service\HtmlFetcher), replaces the issue table with fresh findings, and stores a summary (score + counts) viaFlagManager. - Rendered-HTML checks read live pages, so for origins behind Varnish / basic-auth / an edge gate they can fetch an internal endpoint instead of the public URL. Configure once under Stores → Config → Etechflow → SEO Audit → Page Fetch (sample size, optional fetch base URL + basic auth; the store domain is sent as the
Hostheader). Each rendered group (Canonical, Indexability) has its own enable toggle. - ScoreCalculator turns issue counts into a transparent 0-100 score:
penalty = critical×3 + warning×1 + notice×0.3, normalised against the number of products + categories + CMS pages. - Admin dashboard (Content → SEO Audit) shows the score, a severity/area breakdown, a Run SEO Scan Now button, and the full issue grid. Each row links to the entity and names the Fix with module.
- CLI:
bin/magento etechflow:seoaudit:scan.
The suite hook
The audit is the finder; the rest of the Etechflow SEO Suite is the fixer. Findings point at the tool that resolves them:
- Missing / duplicate / poor meta → Etechflow_MetaTemplates or Etechflow_AiSeo
- 404s & redirect chains → Etechflow_RedirectManager
- Canonical pointing at a redirect / duplicate / missing → Etechflow_CanonicalHreflang
- Pages hidden from Google (noindex / robots.txt) → review robots directives; sitemap hygiene → core sitemap config
- (Structured-data gaps → Etechflow_RichSnippets)
Install
composer require etechflow/module-seo-audit
bin/magento module:enable Etechflow_SeoAudit
bin/magento setup:upgrade
bin/magento setup:di:compile # production
Configure
Stores → Configuration → Etechflow → SEO Audit — tune the meta-title/description length thresholds and the thin-description cutoff. Then Content → SEO Audit → Run SEO Scan Now.
License
Proprietary — © eTechFlow.
Changelog
All notable changes to this module are documented here.
v1.5.0 — 2026-06-08
Two dashboard improvements so findings are actionable:
- Score impact per check — the scan summary now carries a
by_checkbreakdown with the exact score points each check would recover if fixed (ScoreCalculator::pointsFor()), and the admin dashboard renders a "Fix priority" table sorted by recoverable points. You can see at a glance that, e.g., fixing meta-title lengths is worth +20 and social tags +1. - Open each issue on the live site — every finding now stores a resolved
frontend_url(new column), and the issue grid adds a "View on site" action next to "Edit". Product/category URLs are batch-resolved fromurl_rewrite; rendered-check findings use their path. So a merchant can jump from any finding straight to the live page and see the problem.
v1.4.1 — 2026-06-08
Fixed a false-positive: the image-alt check now reads rendered HTML instead of the image_label DB attribute. The old check (product_missing_image_alt) flagged every product with an empty image_label, but most themes (Hyvä, Luma) fall back to the product name for the <img alt>, so an empty label rarely means a truly missing alt — it over-reported badly (e.g. ~2,900 false notices on a Hyvä store). Replaced with content_image_alt: it samples product pages and flags a page only when a product image is present but neither a gallery caption/label nor an <img alt> supplies alt text (gated by the same on-page/page-fetch settings as the H1 check).
v1.4.0 — 2026-06-08
Added duplication & on-page checks:
product_duplicate_meta_description(warning) — products sharing an identical meta description.product_meta_description_length(notice) — meta descriptions outside the configured length range.product_missing_image_alt(notice) — visible products with a base image but no alt text (image label).onpage_h1(warning, rendered) — product pages with a missing or duplicate H1.
v1.3.0 — 2026-06-08
Added visibility rendered-HTML checks:
social_open_graph(warning) — product pages missing Open Graph / Twitter Card tags, or anog:urlwhose domain differs from the store domain (catches dev/staging-domain leakage after a base-URL/domain swap).schema_product_jsonld(warning) — product pages with no Product JSON-LD structured data. Walks@graphcontainers and arrays to find a Product@type.
v1.2.0 — 2026-06-08
Added indexability checks (the "hidden from Google" catchers) and refactored the HTTP fetching into a shared Service\HtmlFetcher:
indexability_noindex(critical) — live pages (HTTP 200) returningnoindexvia robots meta orX-Robots-Tagheader, across sampled product + category pages.indexability_robots_blocked(critical) — live catalogue URLs blocked from crawling by robots.txt (parses theUser-agent: *Disallow/Allow rules and tests real product/category/home paths).indexability_sitemap_health(warning) — XML sitemap missing, not referenced in robots.txt, or listing URLs that 404 / redirect (follows one level of sitemap-index, samples URLs evenly).
Config reorganised: the shared Page Fetch group (etechflow_seoaudit/fetch/* — sample size, base URL, basic auth) now drives all rendered-HTML checks, each with its own enable toggle (Canonical, Indexability).
v1.1.0 — 2026-06-08
Added a canonical health check (product_canonical_health) — the first check that reads rendered HTML over HTTP rather than catalog data at rest. On a configurable sample of product pages it flags a missing canonical, more than one canonical tag, or a canonical whose target redirects (301/302/…) or 404s (a canonical must resolve to a live 200 URL). New config group etechflow_seoaudit/canonical/* (enable, sample size, optional fetch base URL + basic auth) so the check works against origins behind Varnish / basic-auth / an edge gate.
v1.0.0 — 2026-06-05
Initial public release.
On-demand SEO health audit + 0-100 score. Scans products/categories/CMS for meta/content/link issues, links each finding to the fixing module. CLI scan, admin grid, pluggable checks.
Requires 6
| Package | Constraint |
|---|---|
| magento/framework | >=103.0 |
| magento/module-backend | >=102.0 |
| magento/module-catalog | >=104.0 |
| magento/module-cms | >=104.0 |
| magento/module-store | >=101.0 |
| php | ~8.1.0||~8.2.0||~8.3.0||~8.4.0 |
Compatibility
Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.
Code Quality
Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge — 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 | 487 | 5 errors, 482 warnings (ruleset: Magento2) — 349 auto-fixable with phpcbf |
| PHPMD | Warning | 27 | 27 rule violations (CyclomaticComplexity:6, NPathComplexity:6, MissingImport:5, UnusedFormalParameter:2, CountInLoopExpression:2) |
| Cpd | Warning | 2 | 2 duplicated chunks spanning 49 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 6 | valid; 6 advisory notes (composer validate --strict) |
PHPStan
Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases. Cell → details modal.
Tests
Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.
Unit tests
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
Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.
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.