=== AI SEO Tools – Alt Text, Meta Descriptions, Schema & AI Content ===
Contributors: kingaddons, alxrlov, olgadev
Tags: seo, ai, alt text, schema, meta description
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 2.0.4
License: GPL v3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html

Generate alt text, meta descriptions, tags, schema and whole posts with your own API key. No credits, no markup, no middleman.

== Description ==

Most SEO work is not hard, it is just unfinished. Images uploaded without alt text. Posts nobody tagged. Pages with no meta description. Articles that were accurate three years ago. AI SEO Tools works through that backlog, and drafts new posts when you need them.

It talks straight to the model provider with your own key. No proxy, no per-credit pricing, no account with us — you pay the provider directly, and the plugin shows you exactly what it has spent.

Nothing happens behind your back. Every change is logged with the value it replaced and can be undone in one click, and content rewrites show you a diff before anything is saved.

= Fill in what is missing =

* **Alt text** — describes images on upload and in bulk. Images are downscaled before they are sent, and the file name, caption, host page and focus keyword go with them, so you get "Two hikers crossing a footbridge" rather than "a person outdoors". It can also find alt text that already exists but reads like a file name, and rewrite that.
* **Search snippets** — SEO titles and meta descriptions written straight into Yoast, Rank Math, SEOPress or All in One SEO, with a live Google-style preview and character budgets as you type.
* **Tags** — topical tags for posts, pages, custom post types and WooCommerce products. Suggestions prefer tags the site already uses, so your archives do not fragment into near-duplicates.
* **Structured data** — Article, FAQ and HowTo JSON-LD read out of the page itself. Dates, author, permalink and featured image come from WordPress, never from the model, so the markup cannot drift from reality.

= Improve what you already have =

* **Content refresh** — rewrites dated posts at the depth you choose, from correcting stale facts to a full rewrite. You see a word-level diff and tick what to apply: the content, the title, the description, or nothing.
* **Internal links** — finds phrases already present in a post that could link to other pages on the site, and inserts only the ones you approve. Anchors are verified against the real text, so nothing is invented.

= Write something new =

* **Draft writer** — give it a topic, a headline or a list of briefs and get back posts with tags and a search snippet, written under your own name. Drafts by default, or tick **Publish immediately** to send them straight live.

= Built for real sites =

* **Four providers.** OpenAI, Anthropic, Google Gemini and OpenRouter, switchable without losing your settings. OpenRouter opens up hundreds of models behind one key, including free tiers, and its live per-model prices feed the spend counter directly.
* **Spending is visible and capped.** Every request records its tokens and estimated cost, broken down by module. Set a monthly cap and bulk runs stop themselves when they reach it.
* **Bulk work that finishes.** Jobs run through Action Scheduler when it is available, otherwise WP-Cron with a loopback nudge so a quiet site still makes progress. Rate limits are retried with backoff rather than dropped, and a run that is interrupted picks up where it stopped.
* **Your library is not the bottleneck.** Statistics use indexed counts rather than loading every attachment into memory, so the screens stay usable on sites with tens of thousands of images.
* **WP-CLI.** `wp ai-seo alt`, `tags`, `meta`, `schema`, `write`, `usage` and `queue`, for work too large for a browser tab.
* **Keys can live in wp-config.php.** Define `AI_SEO_TOOLS_OPENAI_KEY`, `AI_SEO_TOOLS_ANTHROPIC_KEY`, `AI_SEO_TOOLS_GEMINI_KEY` or `AI_SEO_TOOLS_OPENROUTER_KEY` and nothing is stored in the database.

= For developers =

Prompts, models, post types, taxonomies, pricing, image size and every generated result pass through filters. A few of the useful ones:

* `ai_seo_tools_prompt` — rewrite any prompt before it is sent.
* `ai_seo_tools_model` — override the model per request.
* `ai_seo_tools_alt_text`, `ai_seo_tools_tags`, `ai_seo_tools_meta` — post-process results.
* `ai_seo_tools_model_pricing` — supply your own rates for the cost estimate.
* `ai_seo_tools_image_max_dimension` — control how large images are sent.
* `ai_seo_tools_modules` — register your own module.

== Installation ==

1. Install and activate the plugin.
2. Go to **AI SEO Tools → Settings**, choose a provider and paste an API key. To try the plugin without spending anything, pick OpenRouter and one of the models marked free.
3. Press **Test connection**.
4. Open any module tab and start with a small limit before running the whole site.

== Frequently Asked Questions ==

= Does this cost anything beyond the API bill? =

No. The plugin is free and charges nothing on top. You pay your model provider directly.

= Can I try it without paying anything at all? =

Yes. Choose OpenRouter and one of the models labelled free in the model list. They are rate limited, and not every free model accepts images or JSON schemas — the plugin restates the schema in the prompt and retries without structured output when a model rejects it, so results still parse. For a large bulk run, a small paid model is faster and more reliable.

= How much will a bulk run cost? =

Alt text on a small model is fractions of a cent per image, because images are downscaled before sending and the response is one sentence. The Overview tab shows running totals, and the monthly cap stops a run before it surprises you. The figures are estimates from published list prices — your provider dashboard is authoritative.

= Will it overwrite work I have already done? =

Only if you ask it to. Every bulk run defaults to the items that are empty. Alt text has a separate "weak" mode for text that exists but reads like a file name, and content refresh never writes anything until you have seen the diff and pressed Apply.

= I already use Yoast. Will there be duplicate output? =

Snippets are written into Yoast's own fields, so there is nothing duplicated. Structured data is a different matter: if your SEO plugin already outputs Article schema, leave the structured data module off for those post types. It ships off by default for exactly this reason.

= Does it work with WooCommerce? =

Yes. Products appear in the post type list for tags and snippets, and tags are written to the product tag taxonomy.

= Can I run it from the command line? =

Yes: `wp ai-seo alt --scope=missing --limit=500`, and the same for `tags`, `meta` and `schema`. `wp ai-seo write --file=topics.txt` writes a post per line, with `--publish` to send them live. `wp ai-seo usage` reports spend.

= Can generated posts go live automatically? =

Yes. The writer saves drafts by default; tick **Publish immediately** on the Write tab, or pass `--publish` on the command line, and finished posts are published as they are written. If your role cannot publish, they are submitted for review instead. Undo moves a generated post to the trash, where it can still be recovered.

= What happens if I uninstall it? =

Settings, the activity log and the plugin's own post meta are removed. Alt text, tags and meta descriptions stay — that is your content now, not plugin data.

== Screenshots ==

1. Overview: coverage across every module and this month's spend.
2. Alt text: library statistics, bulk runner, and a review grid for editing suggestions.
3. Write: topics in, finished posts out.
4. Search snippets in the editor, with a live preview and character budgets.
5. Content refresh: a word-level diff before anything is written.
6. Activity: every change, with one-click undo.

== Changelog ==

= 2.0.4 =
A rebuild around a single AI client, a shared job queue and a new admin interface.

**New**
* Anthropic, Google Gemini and OpenRouter support alongside OpenAI, switchable without losing your settings.
* OpenRouter puts hundreds of models behind one key, including free tiers. Its live per-model prices are fetched with the model list and feed the spend counter directly, instead of a built-in price table.
* Draft writer: turn a topic, a headline or a list of briefs into posts, complete with tags and a search snippet, authored by you. Drafts by default, with a **Publish immediately** option and a `--publish` flag for WP-CLI. Roles that cannot publish submit for review instead.
* Search snippets module: SEO titles and meta descriptions written into Yoast, Rank Math, SEOPress or All in One SEO, with a live preview and character budgets.
* Structured data module: Article, FAQ and HowTo JSON-LD, built from what the page actually says. Dates, author, permalink and featured image come from WordPress, never from the model.
* Internal links module: anchor suggestions taken from phrases already in the post, inserted only where you approve them.
* Content refresh is now fully implemented, with a word-level diff, selective apply and undo. Previously it was a disabled placeholder.
* Spend tracking per module, plus a monthly cap that pauses bulk runs before they surprise you.
* Activity log with one-click undo for every change the plugin makes.
* WP-CLI commands: `alt`, `tags`, `meta`, `schema`, `write`, `usage` and `queue`.
* API keys can be defined in wp-config.php (`AI_SEO_TOOLS_OPENAI_KEY` and friends) instead of being stored in the database.
* Tags now work on pages, custom post types and WooCommerce products, not just posts.
* Alt text can find and rewrite weak alt text — file names, IMG_1234, one-word placeholders — not only fill in missing alt text.
* Tag language and alt text language can be set independently.
* New plugin icon, with a flat single-colour variant for the admin menu so it tints correctly with every admin colour scheme.
* Filters throughout for prompts, models, pricing, image size, post types, taxonomies and every generated result.

**Improved**
* Images are downscaled to a configurable dimension before being sent, cutting request size, cost and memory use dramatically compared with sending the original upload.
* Alt text prompts now include the file name, caption, the page the image appears on and that page's focus keyword.
* Structured responses use JSON schema output where the provider supports it. OpenRouter also restates the schema in the prompt and retries without `response_format`, because support varies per model there.
* Reasoning models are handled: when one spends its whole output budget thinking and returns nothing, the request is retried automatically with far more headroom rather than reported as a failure.
* Rate limits and outages are retried with backoff and honour `Retry-After`; bulk runs requeue the item instead of dropping it. OpenRouter rate-limit errors now explain that free tiers share tight limits.
* One shared queue replaces four per-module cron loops, with configurable batch size and a loopback nudge so runs progress on low-traffic sites.
* Library statistics use indexed `COUNT` queries instead of loading every attachment ID into memory.
* Alt text is trimmed on a word boundary, and a refusal is detected through the model's own confidence flag rather than matching an English phrase, which never survived translation.
* Redesigned admin interface on a dark surface of its own, which does not follow the system colour scheme. Metaboxes and list-table controls stay light, matching the WordPress screens they sit inside.
* Requires WordPress 6.5 or newer and PHP 8.1 or newer; tested up to WordPress 7.1.

**Fixed**
* All in One SEO metadata is read and written through its own table rather than an unused post meta key.
* With no SEO plugin installed, the fallback title and description were written but never read back, so coverage always reported them as missing.
* Deactivating or uninstalling left scheduled jobs behind: alt text jobs and queue ticks are scheduled with arguments, which `wp_clear_scheduled_hook()` does not match.
* A completed bulk run made its tab reload endlessly, because the runner treated the finished state on a fresh page load as a reason to refresh.
* Headings, links and table cells inherited WordPress core's dark text colour and became unreadable on the dark surface.
* Select controls turned their text black on hover, from a core rule that outranked the plugin's own.
* Editor metaboxes rendered dark inside the light block editor sidebar.
* The connection test asked for so few tokens that a working key looked broken on a reasoning model.
* Uninstall removes the plugin's options, transients, tables, post meta and scheduled events, while leaving alt text, tags and meta descriptions in place — that content belongs to the site, not the plugin.
* Modules are declared explicitly instead of being derived from file names, so a typo fails loudly rather than silently loading nothing.

= 2.0.3 =
* Maintenance release.

== Upgrade Notice ==

= 2.0.4 =
Major update. Existing settings carry over, and any bulk run in progress is cleared. The plugin's own screens are now dark. If another SEO plugin already outputs Article schema, leave the new structured data module switched off — it ships off for that reason.
