=== Lumioh SEO ===
Contributors: johnoconnor0
Donate link: https://github.com/sponsors/web-lifter
Tags: seo, technical seo, site audit, redirects, internal links
Requires at least: 6.0
Requires PHP: 7.4
Tested up to: 7.1
Stable tag: 1.22.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Technical SEO operating system for WordPress: audits, redirects, migrations, internal links and evidence-backed history. Local-first, no telemetry.

== Description ==

Lumioh SEO is a local-first technical SEO plugin for WordPress. It audits
what a site emits, records evidence for each finding, and provides controlled
tools to fix redirects, metadata, links, migrations and search appearance.

It works against your own WordPress database and server. There is no account,
licence key, usage quota or telemetry. It does not score pages or promise
rankings.

= Features =

* **Site audit:** resumable checks for titles, descriptions, canonicals,
  robots directives, sitemaps, redirects, links and other technical signals.
  Findings include severity, the affected object and supporting evidence. An
  audit can be scheduled locally to run daily or weekly.
* **Redirects and migration:** exact or regular-expression rules, supported
  status codes, scheduling, priorities, cycle detection, chain flattening,
  CSV/JSON imports, dry-run migration, backups and rollback.
* **Internal-link intelligence:** link graph, orphan and weak-page reports,
  anchor analysis, link-equity opportunities and topic clusters.
* **Metadata and search appearance:** per-object and inherited title,
  description, canonical and robots templates with a resolved preview.
* **Social and structured data:** Open Graph, X/Twitter and validated JSON-LD.
  Lumioh stands down when WooCommerce already owns Product schema.
* **Sitemaps and robots:** source-aware XML sitemaps, optional HTML sitemap,
  guided robots.txt rules, effective previews and optional llms.txt.
* **Internationalisation:** page and term hreflang support for native entries
  and supported translation plugins, without emitting duplicate sets.
* **Import/export:** detection-first imports from supported SEO and redirect
  plugins, dry runs, change history, rollback, JSON/CSV export and WP-CLI.
* **Administration:** bulk editing, granular capabilities, Site Health
  integration, audit reports and a local change/event history.

== Installation ==

1. Upload or install **Lumioh SEO** from **Plugins → Add New**, then activate it.
2. Open **Lumioh SEO** in the admin menu and review the setup checklist.
3. Configure templates under **Search Appearance**, then review **Sitemap** and
   **robots.txt** before relying on them.
4. Export existing data before a migration or destructive uninstall.

Lumioh detects supported SEO plugins and stands down from output they own. It
never deactivates or modifies another plugin.

== External services ==

Lumioh SEO has no telemetry, licence checks, tracking pixels, remote scripts,
styles or fonts. Analysis and output checks run on your server. Administrators
can enable these network features:

* Rendered-page analysis requests one published permalink on the same site.
* Output checks request the site's own home page, robots.txt, sitemap, llms.txt
  or IndexNow key file.
* A manually started redirect check sends one HEAD request to the destination
  entered for that rule; redirects off the site's host are not followed.
* IndexNow is disabled by default. When enabled, it sends changed public URLs,
  the site's hostname and its IndexNow key to the configured endpoint
  (default: https://api.indexnow.org/indexnow). It sends no post content,
  personal data or visitor information. See https://www.indexnow.org/ and the
  Microsoft Privacy Statement at https://privacy.microsoft.com/privacystatement.

== Frequently Asked Questions ==

= Does it work with WooCommerce? =

Yes. Lumioh does not emit duplicate Product schema when WooCommerce already
provides it. Shop archives and product taxonomies can be configured.

= Can I use it with another SEO plugin? =

Lumioh can coexist with supported SEO plugins. It stops emitting metadata,
canonical, social and schema output owned by the other plugin, while its
redirect, sitemap, robots, IndexNow and reporting tools remain available.
Importers help you migrate before switching.

= Can non-administrators use it? =

Yes. Lumioh defines separate capabilities for settings, metadata, redirects,
schema, analysis and reports. Administrators can assign only the parts a user
needs.

= What happens when I delete the plugin? =

Deactivation keeps settings and metadata. Deleting the plugin removes Lumioh
options, metadata and tables for redirects, links, audits, history, activity
and the IndexNow queue. On multisite this runs for each site. The **Keep Lumioh
SEO data on this site** setting preserves that data during uninstall; it is off
by default. Export anything required before deleting.

= Will it make my site rank higher? =

No plugin can promise rankings. Lumioh reports verifiable technical signals
and advisory editorial guidance; search engines decide how to use them.

= Where do I get support? =

Use the WordPress.org support forum. Report security issues privately to
john@weblifter.com.au.

== Screenshots ==

1. Dashboard evidence states, findings and setup progress.
2. Post editor meta box with search, social, JSON-LD and analysis tabs.
3. Search Appearance templates and variable picker.
4. Redirect Manager rules, 404 log, activity and import/export.
5. Sitemap settings and public URL status.
6. Site audit findings with evidence, ownership and resolution state.

== Changelog ==

= 1.22.1 =

* Maintenance release: no change to features, settings or stored data, with one exception for a restore started before 1.22 (below).
* CSV imports (bulk edit, redirects, metadata) are read by one shared reader and the audit CSV is written by one shared formatter. The bytes written and the rows read are the same as in 1.22.0. The reader holds the file in memory only; it no longer uses a temporary stream that can spill to disk.
* The sitemap stylesheet, the inclusive-language word list, the audit report style and import files are read through WordPress's own filesystem class, with a size limit checked before and after the read.
* A bundle restore that a release before 1.22 left half finished can no longer be resumed: it stops and asks you to read the bundle again. Its old scratch file is still deleted and is never read.
* The bulk CSV export reads 100 posts at a time instead of 200 and still stops at the same number of posts.
* Database statements name their tables as `{$wpdb->prefix}useo_...`, so WordPress coding-standard checks can read them. The SQL itself is unchanged.
* Coding-standard clean-up: fewer inline suppression comments, translators comments on strings that take placeholders, and renamed parameters that shadowed reserved words.

= 1.22.0 =

* Fixed stored cross-site scripting in the page title: custom-field values used by the `%%cf_<key>%%` token are treated as plain text and the title handed to WordPress is escaped.
* Fixed the audit CSV export so a value can no longer start a spreadsheet formula.
* Tightened permissions: running audits, changing finding status and refreshing the dashboard need the manager capability; redirect data over REST, abilities and activity export needs the redirect capability; configuration cards on the dashboard are shown to site managers only.
* Every admin form and Ajax action now has its own nonce and all request data is read through one verified gateway. A form left open while updating must be reloaded once.
* Redirects: destinations WordPress would refuse are rejected when you save them, a source typed the way browsers send it (for example `/caf%C3%A9/`) now matches because the encoded characters are no longer deleted from the request, and the host is checked again when a visitor is redirected.
* Screens no longer write data, create folders or make loopback requests while they render; checks run when you press the button.
* Redirect imports and audit snapshots scale with the data instead of the square of it, wildcard rules in robots and content sources no longer use regular expressions, and a bulk CSV import stops at 50,000 rows (filter `useo_bulk_import_max_rows`).
* Disabled features have no public, REST, IndexNow or scheduled effect.
* llms.txt is cached for five minutes for anonymous visitors. A `$` inside a robots.txt tester rule is matched literally, as RFC 9309 defines; only a trailing `$` anchors the end.
* A large redirect import holds the redirect write lock while it runs; another redirect save waits up to three seconds and then asks you to try again.
* Editor and admin scripts build DOM nodes instead of HTML strings.

= 1.21.1 =

* Hardened request handling with field-specific sanitization, validation,
  contextual output escaping and capability/nonces on state-changing actions.
* Kept bundle-restore payloads in the database instead of writing protection
  directives into uploads, and retained safe cleanup for legacy restore files.
* Fixed WordPress upload MIME validation for JSON imports and strengthened the
  exact-ZIP security and release audit gates.

= 1.21.0 =

* Activity report imports now recognize custom WordPress admin, content, core,
  REST and uploads paths when filtering asset requests.

= 1.20.0 =

* Moved Lumioh field access from core `wp/v2` routes to `lumioh/v1`; see the
  upgrade notice for sites using REST Writes.
* Added REST access for post, term and user fields, content analysis and
  template previews against unsaved edits.
* Fixed template-variable display, keyword-field controls and admin list layout.

Earlier release history is included in `CHANGELOG.md` in the plugin files.

== Upgrade Notice ==

= 1.22.1 =

Maintenance release: shared CSV and file-reading helpers, and SQL written so coding-standard checks can read it. No change to features, settings or stored data. A bundle restore started before 1.22 must be read again.

= 1.22.0 =

Security release. Running audits, changing findings and viewing configuration now need manager capabilities, and every form has its own nonce, so reload any admin page you left open before updating. Disabled features no longer act in the background.

= 1.20.0 =

Lumioh SEO fields have moved off the core REST routes to
/wp-json/lumioh/v1/seo/<post|term|user>/<id>, where each is named after its
meta key without the _useo_ prefix. This affects you only if you turned on
REST Writes and built against /wp/v2. The admin is unaffected.
