# AEOHelper - Markdown Publisher — installation and testing guide

## 0.5.1 changes

- Renames the plugin to **AEOHelper - Markdown Publisher**.
- Adds optional section ordering for `llms.txt` and an optional per-page order within each section.
- Warns when manifest metadata is saved before the page has published Markdown.
- Removes standalone decorative `#` symbols from generated Markdown.
- Keeps an admin-page-only ZireAI information card as an optional next step while AEOHelper remains fully independent.


Version 0.5.1 · WordPress 6.4+ · PHP 8.0+ with DOM/XML · GPL-2.0-or-later

## 0.4.1 changes

- Adds an optional per-page llms.txt link-title override.
- Uses manual llms.txt titles and descriptions first, then falls back to metadata from the rendered public page.
- Supports existing Rank Math and Yoast title/description metadata when an older approved Markdown record does not yet contain captured page metadata.
- Falls back to the WordPress title and explicit excerpt when no SEO metadata exists.
- Decodes HTML entities so public manifest text contains characters such as `’` instead of `&#8217;`.
- Adds filters for site-specific llms.txt title and description integrations.

## 0.4.0 changes

- Adds `data-aeohelper-context="..."` for a Markdown-only context note immediately before an HTML section.
- Keeps legacy `data-zire-ai-*` attributes working for backwards compatibility while documenting the new `data-aeohelper-*` names.
- Reorganises per-page help into a compact HTML attributes panel covering context, precise exclusion and visual-grid tables.
- Keeps headings on one Markdown line when their HTML contains `<br>` elements.
- Removes punctuation/icon-only headings and detects duplicate H1 headings after normalising case, punctuation and whitespace.
- Prevents malformed nested emphasis such as `****0**%**`.
- Adds three source-update modes: manual review, automatic draft preparation or automatic replacement of previously approved Markdown.
- Displays the latest background source-update status on the page-management screen.
- Clarifies that the plugin-managed `llms.txt` page list updates automatically from approved, currently eligible Markdown.

## 0.3.1 changes

- Adds opt-in conversion of div-based visual grids using `data-aeohelper-table`.
- Preserves table column relationships and converts standalone checkmarks and dashes into `Included` and `Not included`.
- Adds visual-grid table instructions to the per-page Extraction controls.
- Adds a one-time rewrite-rule upgrade check so clean Markdown routes work after plugin updates without manually resaving Permalinks.
- Documents repeatable visual-grid acceptance checks.

## 0.3.0 changes

- Adds clean Markdown URLs using the page permalink followed by `/index.md`.
- Redirects legacy `?zire_ai_md=123` URLs to their clean Markdown equivalents.
- Adds an HTTP `Link` canonical header from successful Markdown responses to the original HTML page.
- Successful Markdown responses remain indexable; error responses retain `X-Robots-Tag: noindex`.
- Adds `rel="alternate"` discovery for approved Markdown and `rel="describedby"` discovery for `/llms.txt`.
- Keeps Markdown publishing selective and subject to generation, review and approval.

## 0.2.0 changes

- Adds a redesigned Overview, clearer Pages and Settings screens, and responsive administration UI.
- Adds optional, local Request Activity for Markdown and llms.txt endpoints, with 7/30/90-day retention, repeat-request deduplication, a 10,000-record cap and manual clearing.
- Stores no IP addresses, cookies or referrers and sends no activity to any external service; crawler labels are unverified user-agent claims.
- Shows last-request information beside pages and a most-requested-pages summary.
- Removes exact duplicate H1 headings, safely rewrites whole-card links and omits empty formatting markers.
- Adds extraction diagnostics, WordPress privacy-policy text and a WordPress.org-format `readme.txt`.
- Keeps core conversion, publishing and optional request activity local to WordPress; no external AI service is required.

## 0.1.4 changes

- Converts native `<details><summary>` disclosure blocks into clean Markdown H3 questions followed by their answers.
- Removes common decoration-only plus, minus and chevron controls from disclosure headings while retaining meaningful inline text and formatting.
- Requires no FAQ-specific class, schema or manual exclusion marker; the published preview still remains the approval boundary.

## 0.1.3 changes

- Adds per-page exclusion selectors beside the Markdown preview.
- Accepts up to 30 simple `.class` or `#id` selectors, one per line; all matching elements are omitted.
- Keeps `data-aeohelper-exclude` as the precise option for excluding one element without removing every use of its class.
- Changing exclusion controls withdraws stale output and requires a fresh preview and approval.

## 0.1.2 changes

- Fixes a false shortcode warning on Custom HTML/CSS containing attribute selectors such as `[data-zire-section]`.
- Only shortcodes actually registered with WordPress now trigger the shortcode safeguard.

## 0.1.1 changes

- Shows the exact reason a page is blocked from generation.
- Adds a deliberate per-page override for shortcode-rendered public content.
- Shortcode pages remain blocked by default and still require preview approval.

## Install and test ONE page

1. Back up WordPress. Go to Plugins → Add New → Upload Plugin and upload the ZIP. Activate **AEOHelper - Markdown Publisher**.
2. Open **AEOHelper** in the admin menu. Leave **Specific pages** selected. No content is exported on activation.
3. Search for one ordinary public Page/Post, click **Manage page**, select **Enable this page**, and save.
4. Click **Generate / refresh preview**. This performs an unauthenticated, same-site HTML request with a 20-second timeout, no redirects and a 2 MB size limit.
5. Read the preview. Compare headings, prices, links, lists, FAQs and tables with the public page. A full marketing animation should not become factual article content. Use the exclusion-selector field beside the preview, add `data-aeohelper-exclude` to one wrapper you control, or use a narrower content selector.
6. Tick the review confirmation and click **Approve & publish Markdown**.
7. Open **Open public Markdown** in a private browser window. The URL follows the original permalink with `/index.md`, for example `https://example.com/about/index.md`. It serves Markdown directly, not HTML. You can append `?zire_ai_download=1` to download the response as a `.md` file.
8. Clear your page cache and inspect the original HTML source for `rel="alternate" type="text/markdown"`. Normal page design and content should be unchanged.
9. Edit the original page and save. In the default manual mode, the old Markdown endpoint should now return HTTP 404. Generate and approve a new preview. Optional background modes can prepare a draft or replace previously approved Markdown; WP-Cron timing and page caching depend on hosting.
10. Test **Withdraw Markdown**, disable the page, and enable **Exclude** in All eligible mode. Each must prevent access to the published output.

Test your theme, SEO plugin, cache and permissions before broad rollout. No claim is made that this plugin increases citations.

## Scope modes

- **Specific pages**: default; enable pages individually.
- **All eligible pages and posts**: makes supported public content eligible without selecting it individually. Exclusions still win. It deliberately does NOT silently generate or publish the entire site; each export needs review.
- Only WordPress `post` and `page` types are supported. Custom post types, attachments, job listings and products are not exported.
- Explicit exclusion, password protection, drafts/private statuses, known Rank Math/Yoast noindex settings, WordPress search visibility disabled, common account paths and known WooCommerce account/cart/checkout pages are blocked.
- Shortcode pages are blocked by default because shortcodes can expose account-specific content. A page-level override is available after confirming that the shortcode renders only public content. The final logged-out preview must still be reviewed.
- Membership/access plugins can implement different protection. Do not deploy to restricted-content sites without auditing those integrations. A public HTTP request is not a substitute for understanding site access rules.

## llms.txt

This manager starts OFF. Leave it off to keep a physical file, Rank Math or another provider. Do not enable two managers.

When enabling for the first time, the plugin requires the existing `/llms.txt` URL to return 404 and refuses physical-file or known Rank Math module conflicts. It never overwrites a file on disk. Other plugins enabled later can still compete: check the live endpoint after any plugin changes.

Configure the website name, summary and optional context. On each selected page configure its section. The optional llms.txt link title and description fields override automatic metadata; when left blank, the plugin uses the rendered page SEO title and meta description, then supported Rank Math/Yoast metadata, and finally the WordPress title or explicit excerpt. Only **approved, currently eligible** Markdown documents appear in the manifest. You can exclude a page from the manifest without withdrawing its Markdown.

The file list is generated on each request. Publishing approved Markdown adds its entry automatically; withdrawing it, changing the source or making the page ineligible removes the entry automatically. The format follows the llms.txt proposal: one site H1, an optional summary blockquote and context, followed by H2 groups containing Markdown links.

The plugin dynamically serves `/llms.txt`; no filesystem writes or Nginx changes are required on ordinary WordPress routing. If your server intercepts `.txt` requests before WordPress, leave this manager off and use your existing manager or ask your host to route that one URL to WordPress. Do not broadly change server static-file handling.

## Extraction

The converter uses the logged-out HTML response, not raw WordPress post_content, and does not execute JavaScript, CSS, shortcodes or model calls. Automatic container preference: `main`, `[role="main"]`, `article`, `.entry-content`. If none matches, it stops rather than falling back to the entire body.

Supported custom selector: one tag, `#id`, or `.class`. Complex selectors are intentionally unsupported. Only the first matching container is extracted; inspect pages with several articles/main elements.

Per-page exclusions accept one simple `.class` or `#id` per line and remove every matching descendant of the selected content container. Use the manual `data-aeohelper-exclude` attribute when only one particular element should be removed. Exclusion changes invalidate any existing preview and published copy.

### HTML extraction attributes

These attributes can be added to an existing HTML element without changing its front-end appearance:

- `data-aeohelper-exclude` removes that element and all of its descendants from Markdown.
- `data-aeohelper-table` treats a div-based visual grid as a structured Markdown table.
- `data-aeohelper-context="Illustrative example; figures are fictional."` inserts the supplied text as a bold Markdown-only note immediately before that element's converted content.

Context is plain text taken from the attribute value. Use it for concise factual qualifications, not hidden promotional copy or unrelated keywords. Context inside an excluded element is also excluded.

Headings, paragraphs, native disclosure/FAQ blocks, simple tables, nested lists, code, links and meaningful image alt text are converted. Heading line breaks are collapsed so each Markdown heading stays on one line. Duplicate H1 headings are compared without case, punctuation or whitespace, and punctuation/icon-only headings are omitted. Disclosure summaries become H3 headings and common decoration-only toggle symbols are removed. Navigation, scripts, styles, forms, SVGs, footers, explicitly hidden elements and `data-aeohelper-exclude` blocks are removed. Article headers are kept because they may contain the title and author.

Known limitations: external CSS visibility cannot be evaluated; complex merged/nested tables may need a different source layout; dynamic/JS-only content cannot be extracted; output must be reviewed. No JSON-LD preservation or AI-written summary is included. Theme-only or external-data changes do not trigger post-save invalidation: withdraw/regenerate affected pages manually.

### Visual grids as Markdown tables

Native HTML `<table>` elements are converted automatically. Existing comparison tables built from styled div elements can opt into structured conversion by adding `data-aeohelper-table` to the outer wrapper.

The first direct child is treated as the header row. Each remaining direct child becomes a row, and its direct child elements become cells:

```html
<div class="comparison-grid" data-aeohelper-table>
    <div>
        <div>Feature</div>
        <div>Basic</div>
        <div>Pro</div>
    </div>

    <div>
        <div>Projects</div>
        <div>1</div>
        <div>3</div>
    </div>
</div>
```

A direct child containing text but no child elements becomes a group-label row. Standalone checkmarks are converted to `Included`, while standalone dashes are converted to `Not included`.

Use `data-aeohelper-exclude` on duplicated action or button rows that should not appear in the Markdown table. This conversion is explicitly opt-in because arbitrary div layouts cannot safely be assumed to represent tabular data.

Always review the generated table to ensure every value remains associated with the correct column before publishing.

## Source-update modes

Every first Markdown publication requires a generated preview and explicit approval. After that, **Settings → After an approved source page changes** provides three choices:

- **Require manual review** (default): withdraw stale Markdown and wait for a new preview and approval.
- **Prepare a fresh draft**: withdraw stale Markdown and use WP-Cron to create an unapproved replacement preview.
- **Update Markdown automatically**: withdraw stale Markdown, regenerate it and publish the replacement because that page was approved previously.

Automatic replacement is deliberately opt-in. Use it for routine edits and review the result after structural, pricing or policy changes. A failed refresh does not publish an incomplete replacement. WP-Cron may be delayed on low-traffic sites, and a page cache may delay the HTML seen by the background fetch.


## Indexing and cache policy

- Successful Markdown copies return `Content-Type: text/markdown; charset=UTF-8`, `X-Content-Type-Options: nosniff` and `Cache-Control: no-store, private, max-age=0`.
- Successful Markdown responses include an HTTP `Link` header with `rel="canonical"` pointing to the original HTML page.
- Successful Markdown responses are not given an `X-Robots-Tag: noindex` header. HTTP 404 and other error responses remain marked `noindex`.
- HTML pages are not marked `noindex` by this plugin. The plugin does not alter their canonical tags, robots.txt or XML sitemaps.
- Approved HTML pages advertise their Markdown version using `rel="alternate" type="text/markdown"`.
- When `/llms.txt` exists, eligible HTML pages can advertise it using `rel="describedby"`.
- Clean Markdown URLs use the original permalink followed by `/index.md`. Legacy `?zire_ai_md=123` requests redirect permanently to the clean URL.
- The plugin does not use same-URL Accept negotiation or bot-user-agent switching.
- Keep Markdown URLs out of the XML sitemap. The HTML page remains the primary search result and canonical source.
- Cache/CDN configuration must allow `/index.md` requests to reach WordPress and honour `no-store`. If the plugin manages `/llms.txt`, exclude that endpoint from persistent caching while testing.
- Purge caches after enabling, disabling, publishing, withdrawing or deleting exports. Stale discovery links might otherwise persist in cached HTML.

## Audit tools

Each page has an access/extraction probe. Choose a user-agent and inspect HTTP result, content type, size, words, canonical and heading outline. This is a simulated request from your server: a successful probe is NOT verified bot access or proof of indexability. No robots.txt parser, bot identity verification, genuine crawler traffic logging or upstream firewall visibility is provided.

Check the live robots.txt separately, inspect server/CDN logs, and use Search Console. An HTTP 200 can still contain an unexpected page: inspect the preview. Never interpret byte reduction as measured provider token savings.

## Data, privacy and uninstall

No external AI service, API keys, telemetry, IP storage or paid dependencies. The plugin requests only the selected same-host permalink using WordPress's safe HTTP client, with no cookies and no redirects. Private/local network targets are not bypassed if the safe client rejects them. Identical request activity is collapsed into 15-minute observations and storage is capped at the latest 10,000 records, so this is a directional access log rather than exact traffic analytics.

Settings and previews live in WordPress options/post metadata. No physical Markdown files are written. Deactivation stops handling requests but keeps settings. Deleting the plugin removes its own metadata/settings on the current site. Network activation and network-wide management are not supported; test per-site installations. Clear external caches after removal.

## Troubleshooting

- **DOM missing**: enable PHP DOM/XML in hosting PHP extensions.
- **Source HTTP 301/302**: correct the saved permalink/canonical/HTTPS host. The fetcher intentionally does not follow redirects.
- **Source HTTP 403/429**: inspect the firewall. Do not disable security site-wide.
- **No main container**: choose the exact content selector and regenerate.
- **Page blocked**: the Manage page screen now lists the exact detected reason. Check visibility, passwords, exclusions, noindex, shortcodes and account paths.
- **llms.txt not enabled**: existing endpoint must return 404. Disable its existing manager first if you want AEOHelper to serve it. Soft-404/redirect behaviour requires host investigation.
- **Stale preview**: generate a fresh copy after saving the original or changing the selector.
- **Headers/HTML wrong**: inspect CDN and page-cache bypasses before enabling more pages.

## Licence

Copyright 2026 AEOHelper contributors. This program is free software: you may redistribute and/or modify it under the GNU General Public License as published by the Free Software Foundation, version 2 or any later version. Distributed without any warranty, including merchantability or fitness for a particular purpose. Full licence: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
