# angeo/module-rich-data

> Magento 2 JSON-LD Rich Data for AI Engine Optimization. Injects spec-compliant Product, Organization, BreadcrumbList, FAQPage, and WebSite schema. Fixes the 'Product schema — JSON-LD structured data' signal in angeo/module-aeo-audit.

`composer require angeo/module-rich-data`

Canonical URL: https://packagento.com/angeo/module-rich-data

## At a glance

- **Vendor**: angeo (https://packagento.com/angeo.md)
- **Latest version**: 1.2.0 — released 2026-06-14
- **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/angeo/module-rich-data 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 angeo/module-rich-data:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Magento 2 JSON-LD Rich Data for AI Engine Optimization. Injects spec-compliant Product, Organization, BreadcrumbList, FAQPage, and WebSite schema. Fixes the 'Product schema — JSON-LD structured data' signal in angeo/module-aeo-audit.

## README

[![Packagist](https://img.shields.io/packagist/v/angeo/module-rich-data.svg)](https://packagist.org/packages/angeo/module-rich-data)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![PHP](https://img.shields.io/badge/php-%3E%3D8.2-8892BF.svg)](https://php.net)

**Fixes the "Product schema — JSON-LD structured data" signal in `angeo/module-aeo-audit`. Injects spec-compliant JSON-LD on product pages, CMS pages, and homepage.**

---

### What this module fixes

| AEO Audit signal | Before | After |
|-----------------|--------|-------|
| Product schema — JSON-LD structured data | FAIL / WARN | PASS |
| FAQPage schema — AI answer eligibility | WARN | PASS (on FAQ CMS pages) |
| Merchant policies — return & shipping schema | FAIL | PASS (when enabled & configured) |
| Product schema — AggregateRating | WARN | PASS (when reviews exist) |
| JSON-LD quality — BreadcrumbList | WARN | PASS (now rendered on product pages) |

---

### Schema types injected

| Schema | Pages | Key fields |
|--------|-------|------------|
| `Product` | All product pages | name, description, image, sku, gtin/mpn, offers.price, offers.priceCurrency, offers.availability, offers.hasMerchantReturnPolicy, offers.shippingDetails, aggregateRating |
| `Organization` | All pages | name, url, logo, sameAs, contactPoint |
| `WebSite` | Homepage only | name, url, potentialAction/SearchAction |
| `BreadcrumbList` | Product pages | category path |
| `FAQPage` | CMS pages with FAQ content | auto-detected Q&A pairs |

---

### Installation

```bash
composer require angeo/module-rich-data
bin/magento setup:upgrade
bin/magento cache:flush
```

---

### Configuration

**Stores → Configuration → Angeo → Rich Data (JSON-LD)**

#### Product schema
- Enable/disable
- Include AggregateRating (from Magento reviews)
- Include BreadcrumbList
- Include SKU
- Include Brand (configurable attribute)
- Include GTIN / MPN (configurable attributes)
- Item condition (New/Used/Refurbished)
- In-stock / out-of-stock availability URLs

#### Merchant policies (return & shipping)
Injects `offers.hasMerchantReturnPolicy` and `offers.shippingDetails` — required by Google & ChatGPT Shopping since Jan 2026. **Disabled by default**; enable and fill in your real values.
- Return policy: enable, return window (days), applicable country, return fee
- Shipping details: enable, flat shipping rate, destination country, handling time (min/max days), transit time (min/max days)

#### Organization schema
- Organization name (default: store name)
- Logo URL
- sameAs social URLs (comma-separated)
- Contact telephone + type

#### WebSite schema
- Enable/disable
- Include SearchAction (Sitelinks Searchbox)

#### FAQPage schema
- Enable/disable — auto-detected from CMS page content

---

### FAQ page markup (recommended)

Add `data-faq-question` / `data-faq-answer` attributes to your CMS FAQ page for explicit Q&A detection:

```html
<div data-faq-question="What is your return policy?"
     data-faq-answer="We offer 30-day returns on all items in original condition.">
</div>
```

Without these attributes the module uses heuristic detection: `<h2>/<h3>` followed by `<p>` are treated as question/answer pairs.

---

### Extending with custom schemas

Implement `Angeo\RichData\Api\Data\SchemaInterface` and register via `di.xml`:

```xml
<type name="Angeo\RichData\Model\JsonLd\Renderer\SchemaRenderer">
    <arguments>
        <argument name="builders" xsi:type="array">
            <item name="my_schema" xsi:type="object">Vendor\Module\Model\JsonLd\Builder\MySchemaBuilder</item>
        </argument>
    </arguments>
</type>
```

---

### CLI validation

```bash
## Validate on random product
bin/magento angeo:rich-data:validate --store=en_us

## Validate specific product on specific store
bin/magento angeo:rich-data:validate --store=en_us --product-id=42
```

Output example:
```
Validating JSON-LD for: [42] Alpine Hiking Jacket
  Store:   default
  URL:     https://mystore.com/alpine-jacket

Found 3 JSON-LD block(s):
  Block 1: @type:Organization — valid JSON ✓
  Block 2: @type:Product — valid JSON ✓
    PASS aggregateRating present
  Block 3: @type:BreadcrumbList — valid JSON ✓

All JSON-LD blocks are valid.
```

---

### The Angeo AI Suite

| Module | Purpose |
|--------|---------|
| `angeo/module-aeo-audit` | AEO audit — detects missing schema |
| `angeo/module-rich-data` | **This module** — fixes missing schema |
| `angeo/module-llms-txt` | Generates `/llms.txt` |
| `angeo/module-openai-product-feed-api` | ACP REST API for ChatGPT Shopping |

---

### License

MIT — see [LICENSE](LICENSE)

## Changelog

All notable changes to `angeo/module-rich-data` are documented here.
This project adheres to [Semantic Versioning](https://semver.org/).

### [1.2.0] - 2026-06-13

#### Added
- **CollectionPage + ItemList on category pages** (`CollectionPageBuilder`).
  Emits a `CollectionPage` whose `mainEntity` is an `ItemList` of the category's
  enabled, catalog-visible products (capped at 50). Read by the Gemini Shopping
  Graph, which previously had no machine-readable product listing on category
  pages. Toggle under Angeo Rich Data → CollectionPage schema (on by default).
- **Organization `description`.** The Organization schema now includes a
  `description` field (configurable under Angeo Rich Data → Organization →
  Organization description). AI engines read it as the brand entity summary;
  its absence was previously flagged by the AEO audit.

#### Changed
- `ViewModel\JsonLd` now builds context for `catalog_category_view` (current
  category + a lightweight product list) so the new CollectionPage builder has
  data to render.

### [1.1.0] - 2026-06-08

#### Added
- **Merchant return policy** (`offers.hasMerchantReturnPolicy`). Emits a
  spec-compliant `MerchantReturnPolicy` (applicableCountry, merchantReturnDays,
  returnPolicyCategory, returnMethod, returnFees). Required by Google &
  ChatGPT Shopping since January 2026. Configurable under
  **Stores → Configuration → Angeo → Rich Data → Merchant policies**.
- **Shipping details** (`offers.shippingDetails`). Emits `OfferShippingDetails`
  with `shippingRate` (MonetaryAmount), `shippingDestination` (DefinedRegion)
  and optional `deliveryTime` (handling + transit `QuantitativeValue`).
- **GTIN / MPN identifiers** on Product schema, read from configurable product
  attributes. Improves AI/Google product matching. Off by default.
- New admin config group **Merchant policies (return & shipping)** and new
  Product fields: Include GTIN/MPN, GTIN attribute, MPN attribute, In-stock
  availability URL, Out-of-stock availability URL.
- `Model/Config/Source/ReturnFee` source model for the return-fee dropdown.
- Unit coverage for the merchant return policy and shipping details output.

#### Fixed
- **BreadcrumbList now actually renders on product pages.** The
  `BreadcrumbBuilder` expected a `breadcrumbs` context key that the ViewModel
  never supplied, so the breadcrumb schema silently never appeared even with
  the toggle enabled. The ViewModel now builds the full trail
  (Home → category path → product) from the product's deepest active category
  and passes it into the render context. This resolves the persistent
  "BreadcrumbList missing" finding in `angeo/module-aeo-audit`.
- `availability_in_stock` / `availability_out_of_stock` are now exposed in the
  admin (previously only present as config.xml defaults and not editable). The
  builder also falls back to sane schema.org defaults if either value is blank.

#### Changed
- ViewModel now logs render failures via `LoggerInterface` instead of silently
  swallowing them, matching the error handling already used in `SchemaRenderer`.

#### Migration notes
- No schema or data migration required. After upgrading, run:
  ```
  bin/magento setup:upgrade
  bin/magento cache:flush
  ```
- Merchant return policy and shipping details are **disabled by default** to
  avoid publishing inaccurate policy data. Enable and fill them in under
  **Stores → Configuration → Angeo → Rich Data → Merchant policies** once your
  real return window, shipping rate and delivery times are known. Publishing
  incorrect policy values can hurt eligibility, so opt in deliberately.

### [1.0.2] - 2026-04-18

#### Added
- Initial public release: Product, Organization, WebSite, BreadcrumbList and
  FAQPage JSON-LD builders, admin configuration, `angeo:rich-data:validate`
  CLI command, and unit tests.

## Recent Versions

| Version | Released |
|---|---|
| 1.2.0 | 2026-06-14 |
| 1.0.2 | 2026-04-24 |
| 1.0.1 | 2026-04-18 |
| 1.0.0 | 2026-04-18 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | * |
| magento/module-backend | * |
| magento/module-catalog | * |
| magento/module-cms | * |
| magento/module-config | * |
| magento/module-review | * |
| magento/module-store | * |
| php | >=8.2 |

### Suggest

| Package | Constraint |
|---|---|
| angeo/module-aeo-audit | Verify JSON-LD injection with the AEO audit tool. |

## Quality

Latest release (1.2.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 | Pass |


### 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 | Warning | 57 | 57 warnings (ruleset: Magento2) — 33 auto-fixable with phpcbf |
| PHPMD | Warning | 12 | 12 rule violations (NPathComplexity:3, CyclomaticComplexity:3, UnusedFormalParameter:2, EmptyCatchBlock:1, ExcessiveClassComplexity:1) |
| Cpd | Pass | 0 |  |
| Composer validate | Info | 8 | valid; 8 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 | 6 | 6 | – | – |
| 2.4.8 | – | 6 | 6 | – |
| 2.4.9 | – | – | 6 | 6 |


### 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 | 13 | 13 | – | – |
| 2.4.8 | – | 13 | not tested | – |
| 2.4.9 | – | – | 13 | not tested |

#### 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=["angeo/module-rich-data"],
  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

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

