=== Lwakit Autoblog ===
Contributors: yedaye
Tags: ai, claude, anthropic, autoblog, content
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.3.6
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Automatically generates blog drafts in the sector of your choice, powered by AI, with real sources cited.

== Description ==

The plugin creates a WordPress post draft on a schedule, in whichever sector or sectors
you define yourself (technology, health, travel, food, finance… any field at all),
powered by artificial intelligence. The current engine is Anthropic's Claude; other AI
engines are planned for a future version. Sectors are cycled in rotation, one per run.

Features:

* Fact grounding: Claude web search (dated, cited sources) or per-sector RSS feeds
* Angle rotation: news, common problem, background information
* A "Sources" section added at the end of the article
* Scheduling via WP-Cron (hourly, twice daily, daily, every 3 days, weekly, 4 times a day)
* Persistent rotation across a list of sectors
* The last 15 generated titles are sent to the model to avoid duplicate topics
* API key read from the ANTHROPIC_API_KEY constant (wp-config.php) with priority
* Default status: draft
* Manual test button
* Log of the last 20 runs, plus a pending-review view
* Content filtered through wp_kses_post()
* Featured image: Openverse (free, no key), Pexels, or a locally generated cover
* Two display shortcodes: paginated archive and latest posts
* Automatic proofreading pass (grammar, missing or wrong articles, spelling, punctuation) before the draft is created
* Automatic SEO field autofill for Yoast SEO, Rank Math, SEOPress, or All in One SEO when active
* Internal linking suggestions to the plugin's own prior posts
* Duplicate-topic avoidance within a configurable lookback window
* Field-level regenerate (title or featured image only) from the post edit screen
* A per-post grounding report showing exactly which URLs were cited
* Optional WPML / Polylang bridge: one scheduled run can generate linked, independently-researched translations
* Adjustable run-time jitter, so a fleet of sites on the same schedule doesn't call the API in the same minute
* Self-healing scheduler: repairs itself if "scheduling enabled" and WP-Cron's actual state ever drift apart

== Shortcodes ==

[lwa_autoblog_archive] — every post on one page, with pagination.
[lwa_autoblog_latest count="3"] — the latest posts, for a home page.

Attributes: columns, source (autoblog|all), category, tag, show_image, show_excerpt,
show_date, excerpt_length, image_size, orderby, order, read_more,
posts_per_page (archive), count and title (latest).

== External services ==

This plugin relies on the following third-party services to generate and illustrate blog drafts. All three are only contacted when the plugin actually runs a scheduled or manual generation — never on ordinary page views.

**Anthropic (Claude API)** — used to write and, if enabled, proofread every generated article. Every time a post is generated, the plugin sends the site's configured sector name, editorial angle, target word count, target language, and (if RSS grounding is used instead of live web search) the fetched RSS article text and titles, to Anthropic's API. When the built-in web search grounding option is enabled instead, Anthropic's own service performs the web searches on the plugin's behalf as part of generating the article. No visitor or personal site-user data is ever sent — only the sector/topic configuration and, optionally, publicly syndicated RSS content.
[Anthropic Commercial Terms of Service](https://www.anthropic.com/legal/commercial-terms), [Anthropic Privacy Policy](https://anthropic.com/privacy)

**Pexels** — an optional featured-image source, only contacted when the site owner selects Pexels (rather than Openverse or a locally generated cover) as the image provider. When a post is generated, the plugin sends the model's suggested image search keywords (2-4 English words describing a photographable scene, e.g. "developer workstation screens") to Pexels' search API and downloads the chosen photo to the site's own media library.
[Pexels Terms of Service](https://www.pexels.com/terms-of-service/), [Pexels Privacy Policy](https://www.pexels.com/privacy-policy/)

**Openverse** — the default featured-image source (no account or API key required). Same as Pexels above: only the model's suggested image search keywords are sent, only when a post is generated and Openverse is the active (or default) image provider, to search for a openly-licensed photo to download into the site's media library.
[Openverse Terms of Service](https://docs.openverse.org/terms_of_service.html), [Openverse Privacy Policy](https://openverse.org/privacy)

== Installation ==

1. Plugins > Add New > Upload Plugin > choose the .zip file
2. Activate the plugin
3. Add the API key to wp-config.php:
   define( 'ANTHROPIC_API_KEY', 'sk-ant-api03-...' );
4. "Lwakit Autoblog" menu: configure your sectors and frequency, then check "Enable scheduling"

== Screenshots ==

1. Settings tab — model, frequency, and fact-grounding controls.
2. Shortcodes tab — the full attribute reference for the two display shortcodes.
3. Log tab — the pending-review list, separate from the run log.
4. A generated post in the block editor, with the "Sources cited" grounding report visible in the sidebar.
5. The [lwa_autoblog_archive] shortcode on the front end.

== Changelog ==

= 1.3.6 =
* Addressed every item from the wordpress.org submission's Plugin Check review:
* Documented all three third-party services this plugin calls (Anthropic, Pexels, Openverse) in a new "External services" section below — what each is used for, what data is sent, and links to their Terms of Service and Privacy Policy.
* Removed the `load_plugin_textdomain()` call and the bundled French `.po`/`.mo` translation files — no longer needed or recommended for a wordpress.org-hosted plugin; translations will be delivered through translate.wordpress.org once the plugin's translation project exists there.
* Removed a leftover deprecated `libxml_disable_entity_loader()` call in the sentence-completion trimmer; it only ever ran on PHP versions where it changed nothing (libxml has disabled external entities by default since 2.9, before any PHP version this plugin supports), so removing it costs nothing.
* Re-verified, against WordPress 7.1's actual shipped AI Client source, that migrating off the direct Anthropic integration still isn't a fit today: no AI provider is bundled by core, and the library has no equivalent of the `allowed_callers` scoping, `pause_turn` multi-turn continuation, or native citation objects this plugin's mandatory grounding (FR-8) depends on.

= 1.3.5 =
* Translated every remaining French code comment and docblock to English across all plugin files, for consistency with the plugin's English source strings — no functional changes. The Anthropic prompt bodies (`system_prompt()`, `user_prompt()`, `angle_instruction()`, `regenerate_title()`, `proofread()` in `class-lwa-autoblog-generator.php`) are deliberately still written in French regardless of the article's output language and were left untouched, now with explicit "do not translate" notes in their docblocks to prevent this from happening by accident in the future.
* Found and fixed two categories of leftover French text while doing this pass: a French example string and shortcode-attribute example values in the Sectors/Shortcodes admin screens, and about twenty French log/error messages (API errors, "no source found", proofreading failures, the post-created summary line, Openverse/Pexels error messages) that were never wrapped in `__()` and rendered directly in the Journal tab's Message column regardless of the admin's interface language. All are now translatable, added to the French `.po`/`.mo` files, and verified by loading the `.mo` through WordPress's own `MO` class.

= 1.3.4 =
* Ran the official wordpress.org Plugin Check tool and fixed every warning: added `no_found_rows`/`fields => 'ids'` to postmeta-based queries where pagination counts weren't needed, removed a dead `post__not_in` exclusion that never excluded anything, wrapped `uninstall.php`'s working variables in a function instead of leaving them as unprefixed globals, and documented (rather than silently changing) two deliberate architectural choices: calling the Anthropic API directly instead of WordPress 7.0's AI Client, and keeping an explicit `load_plugin_textdomain()` call until the plugin is actually hosted on wordpress.org.
* Independent security audit (nothing critical or high found): tightened the per-post "regenerate title/image" buttons from `edit_post` to the same `manage_options` capability every other API-triggering action already requires, since they trigger billed API calls; added a public/private-address check before every outbound fetch to a URL this plugin didn't choose itself (RSS feed content, and image URLs returned by the Openverse/Pexels APIs) to close a server-side request forgery gap; validated the "Translate into" language setting against an explicit allow-list instead of only format-checking it; added defense-in-depth entity-loader hardening around the sentence-completion trimmer's HTML parsing.

= 1.3.3 =
* Display name simplified from "LWA Kit Autoblog" to "Lwakit Autoblog," matching the slug exactly. This also matters for the pending wordpress.org submission: the plugin's URL slug is auto-generated from this header and becomes permanent once review begins, and "LWA Kit Autoblog" (three words) would have auto-generated as "lwa-kit-autoblog," not the intended "lwakit-autoblog."

= 1.3.2 =
* Fixed: changing the frequency on an already-running schedule now updates "Next run" to reflect the new interval right away, instead of always restarting at "in 1 minute" (that fast restart is now reserved for first activating scheduling).
* Fixed: the execution log's timestamps are now stored in GMT and converted to the site's timezone at display time, so a later timezone change correctly updates past log entries too, not just new ones — previously, an entry logged before a timezone change stayed frozen at its original offset.
* Fixed: "Next run", the pending-review list, and the execution log now all use the same date/time format, the one configured under Settings > General, instead of each showing a different hardcoded pattern.

= 1.3.1 =
* The pending-review list now shows the date and time each draft was created, not just the date.
* readme.txt rewritten in English (a wordpress.org requirement since mid-2025) and trimmed to 5 tags.
* "Tested up to" updated to the current WordPress version.
* Hardened against the official Plugin Check tool's findings ahead of submission: nonce verification now runs before any of our own code reads the submitted post ID on the regenerate actions, and internal uninstall.php variables are prefixed.

= 1.3.0 =
* Renamed to Lwakit Autoblog (slug lwakit-autoblog) ahead of the wordpress.org submission.
* Settings screen reorganized into three tabs: Settings, Shortcodes, Log.
* New "4 times a day" frequency, and a usage example for every shortcode attribute.
* Admin interface translated (English by default, French based on the WordPress user's own profile language).
* New setting: keep settings and the log on uninstall (on by default).
* New setting: guaranteed complete final sentence — the output token ceiling now scales automatically with the requested length, and any response that's still cut off is trimmed back to a clean ending instead of publishing the fragment.
* New setting: automatic proofreading pass (grammar, missing or wrong articles, spelling, punctuation) before the draft is created.
* Automatic SEO field autofill (Yoast SEO, Rank Math, SEOPress, All in One SEO) when one of those plugins is active.
* Internal linking suggestions to posts the plugin has already published.
* Duplicate-topic avoidance: a sector and angle used too recently advances the rotation to the next angle instead of repeating.
* Pending-review list, in the Log tab.
* Targeted regenerate for just the title or the featured image, from a generated post's edit screen.
* WPML / Polylang multilingual bridge: one scheduled run can generate linked, independently-researched translations in French and English.
* Adjustable jitter on the scheduled run time, to spread the API call out across multiple sites.
* Per-post grounding report (the URLs actually cited), viewable on the post edit screen.
* Self-healing scheduler: a drift between "scheduling enabled" and no run actually scheduled now corrects itself.

= 1.2.1 =
* Replaced the JSON output format with a labeled format, far more robust alongside web search.
* Salvage path: an article returned as raw HTML is now used instead of rejected.
* Added a viewer for the model's last raw response, for diagnostics.

= 1.2.0 =
* Fact grounding via Claude's web search tool (pause_turn and citation handling).
* Alternative grounding via per-sector RSS feeds, with a feed-test button.
* Editorial angle rotation: news, common problem, background information.
* A "Sources" section added at the end of the article.
* New sector format: "Name | url1, url2".
* Default settings reoriented toward an international tech / AI / web dev readership.

= 1.1.0 =
* Added the [lwa_autoblog_archive] and [lwa_autoblog_latest] shortcodes.
* Added the featured image: Openverse, Pexels, or a GD-generated cover.
* The model now suggests illustration keywords in English.
* Optional display of photo credit and license at the end of the article.

= 1.0.0 =
* Initial version.
