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

`composer require etechflow/module-seo-audit`

Canonical URL: https://packagento.com/etechflow/module-seo-audit

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: 1.6.1 — released 2026-06-22
- **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-seo-audit 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-seo-audit:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

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.

## README

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) via `FlagManager`.
- **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 `Host` header). 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

```bash
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_check` breakdown 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 from `url_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 an `og:url` whose 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 `@graph` containers 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) returning `noindex` via robots meta or `X-Robots-Tag` header, across sampled product + category pages.
- **`indexability_robots_blocked`** (critical) — live catalogue URLs blocked from crawling by robots.txt (parses the `User-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

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

## Recent Versions

| Version | Released |
|---|---|
| 1.6.1 | 2026-06-22 |
| 1.6.0 | 2026-06-19 |
| 1.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-cms | >=104.0 |
| magento/module-store | >=101.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0 |

## Quality

Latest release (1.6.1) 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 | 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 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 | 11 | 11 | – | – |
| 2.4.8 | – | 11 | 11 | – |
| 2.4.9 | – | – | 11 | 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-seo-audit"],
  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.

