=== Essiow — AI SEO Suite for WooCommerce ===
Contributors: boni58
Tags: woocommerce, seo, ai, product-descriptions, chatbot
Requires at least: 5.8
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.1.17
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Optimize your WooCommerce store SEO with AI. Auto-generate product descriptions, category pages, blog articles, and add an AI sales chatbot.

== Description ==

**Essiow** is the all-in-one AI-powered SEO suite for WooCommerce stores. It connects to the [Essiow platform](https://essiow.com) to automatically generate and optimize your store content using artificial intelligence.

= 5 Modules Included =

**1. Product SEO Optimization**
Automatically generate SEO-optimized product descriptions, meta titles, meta descriptions, focus keywords, and image alt text. Supports Yoast SEO, Rank Math, and All in One SEO. Includes JSON-LD schema generation for rich snippets.

**2. Category SEO Optimization**
Transform your bare category pages into rich content pages with short descriptions, long-form SEO content (1,500-2,500 words), FAQ sections, comparison tables, and internal linking. Automatically fixes corrupted category names.

**3. Blog Article Generator**
Generate long-form SEO blog articles (1,500-5,000 words) that naturally integrate your WooCommerce products. Includes internal linking, external authority links, FAQ sections, and automatic featured images.

**4. AI Sales Agent**
Add an intelligent chatbot to your store that searches your products in real-time, answers customer questions, handles price objections, creates promotional codes, and guides visitors to purchase.

**5. WooCommerce Scraper** (via Essiow dashboard)
Analyze competitor WooCommerce stores. Extract products, categories, prices, and descriptions with CSV export.

= Key Features =

* 8 languages supported: English, French, Spanish, German, Italian, Portuguese, Dutch, Arabic
* 4 writing tones: Professional, Casual, Luxury, Technical
* 3 content lengths: Short, Medium, Long
* Bulk optimization with progress tracking
* Backup and restore original content
* Compatible with Yoast SEO, Rank Math, and All in One SEO
* JSON-LD Product schema for rich snippets
* GDPR compliant (auto-delete chat data after 90 days)
* WooCommerce HPOS compatible

= How It Works =

1. Create a free account on [essiow.com](https://essiow.com) and get 10 free credits
2. Install this plugin and enter your API key
3. Start optimizing your products, categories, and blog content
4. Watch your search rankings improve

= Credit System =

* 1 credit per product optimization
* 1 credit per category optimization
* 3 credits per blog article
* Credits never expire (except free credits: 30 days)

= External Service =

This plugin connects to the Essiow API at `https://essiow.com/api/v1` to process AI content generation. Your product data (names, descriptions, prices, categories) is sent to the Essiow servers where it is processed using OpenAI's GPT models. No data is stored on Essiow servers beyond what is needed to track your credit usage.

* [Essiow Terms of Service](https://essiow.com/terms)
* [Essiow Privacy Policy](https://essiow.com/privacy)

== Installation ==

1. Upload the `essiow` folder to `/wp-content/plugins/`
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Go to **Essiow > Settings** and enter your API key from [essiow.com](https://essiow.com)
4. Click "Test Connection" to verify
5. Start optimizing from **Essiow > Products** or **Essiow > Categories**

== Frequently Asked Questions ==

= Do I need an Essiow account? =
Yes. Create a free account at [essiow.com](https://essiow.com) to get your API key and 10 free credits.

= Do I need technical skills? =
No. If you can install a WordPress plugin, you can use Essiow. Everything is done in a few clicks.

= Which SEO plugins are supported? =
Essiow works with Yoast SEO, Rank Math, and All in One SEO. It automatically detects your plugin and updates the correct fields.

= Is my data safe? =
Your product data is sent to Essiow servers only during optimization. It is processed in real-time and not stored. Chat conversations are auto-deleted after 90 days per GDPR requirements.

= Do credits expire? =
Purchased credits never expire. The 10 free credits expire after 30 days.

= Can I try before buying? =
Yes. Create a free account and get 10 credits to test all features. No credit card required.

== Screenshots ==

1. Dashboard with connection status and credit balance
2. Product optimization with SEO score and bulk actions
3. Category optimization with rich content preview
4. Blog article generator with async processing
5. AI Sales Agent configuration
6. Settings page with API connection

== Changelog ==

= 1.1.17 =
* Fix: bulk no longer stops after 3-5 items on shared hosts. The previous worker iterated all items inside a single PHP process, which got killed by `max_execution_time` (typically 30-60 s on shared hosts) mid-loop — leaving the current item stuck in `processing` and the queue frozen. Each call now processes EXACTLY ONE item then re-spawns itself via WP-Cron + `spawn_cron()` for the next. Workers stay well under any `max_execution_time` value.
* Fix: running multiple individual optimizations in parallel no longer saturates PHP-FPM. The status endpoint is now the worker for single-item flows too — instead of one long-running FPM process per task, every poll handles at most one ~25 s slice. With 4 FPM workers the host can handle 4 simultaneous optimizations cleanly instead of choking after 3-5.
* Fix: try/catch around every Flask call. If the AI client throws (network, timeout, OpenAI 5xx), the item is recorded as `failed` with the exception message and the queue continues. Previously, an exception would kill the worker mid-state-update, leaving items stuck in `processing` until the 90 s recovery kicked in.
* Improve: explicit memory hygiene between bulk items (`unset` of the AI response payload + `gc_collect_cycles()`). On hosts with low `memory_limit`, this keeps long bulks well below the cap.
* Improve: single-item status fallback now triggers after 3 s of `pending` (instead of 30 s) so a non-FPM host where neither cron nor `fastcgi_finish_request` fires sees processing start within the first poll cycle.
* Improve: 90 s stuck-item recovery now also applies to single-item tasks, not just bulk.

= 1.1.16 =
* Fix: stuck-item recovery in bulk worker. If a worker crashes mid-item (FPM killed, OOM, container restart), the item is no longer abandoned in `processing`. After 90 s without a heartbeat, the next worker pass picks it up.
* Fix: orphan UI rows on bulk cancel/error. Rows still showing the spinner ("In progress…") at the moment the user cancels or the network drops are now reset cleanly.
* Fix: distinct "Cancelled" summary in the bulk progress bar instead of the misleading "Bulk complete!" toast.
* Fix: bulk no longer flashes "Queued" on already-optimized rows when the user includes them in a re-run.
* Fix: defensive `removeClass` on row badges so visual state can't accumulate stale classes when cycling done → re-run → failed.
* Fix: missing localized strings (`generate`, `cancelled_summary`) — buttons now stay in the user's language after a generation completes.

= 1.1.15 =
* New: bulk product and bulk category optimization are now fully asynchronous (start → poll → complete) with per-item state tracking. The previous design held the browser open for one HTTP request per item, which timed out on Cloudflare and overwrote any concurrent run. Now a single background worker processes the queue while the browser polls a status endpoint every 3 s.
* New: per-row UI updates during bulk. Each product/category row shows its real-time state — `Queued` → `In progress…` (with a spinner) → `Optimized` (with new SEO score) — exactly like single-item optimization. The "Optimize" button on each row is automatically disabled while processing.
* New: progress percentage everywhere. Article generation, single product/category optimize, and bulk all show a percentage bar with elapsed time and estimated phase ("AI is writing your content…", "Finalizing…"). Single-item progress uses an asymptotic estimator based on a per-task ETA that never reaches 100% before the worker actually returns.
* New: `Cancel` button on bulk operations. The worker checks the cancellation flag between items so cancelling a 50-item bulk halts after the current item finishes (within ~30 s) instead of running to completion in the background.
* New: bulk resumes automatically. Closing the admin tab during a bulk no longer abandons the job — when the page reloads, the JS detects the active task and reattaches its UI to the still-running worker.
* New: bulk singleton lock. Starting a bulk while one is already active no longer overwrites the queue; it reattaches to the running task instead.
* Improve: per-item error capture. Failures during bulk are stored on each item's status so the UI can show which products/categories failed and why (tooltip on the `Failed` badge).

= 1.1.14 =
* Fix: admin assets (admin.js, admin.css) now use a `filemtime()`-based cache buster on top of the plugin version. Hard-refreshes the browser/CDN cache the moment the JS file changes, even when an update was pushed without bumping the user-visible version. Fixes "user is on the new plugin but the browser still calls the old AJAX endpoints".
* Improve: legacy synchronous endpoints (`essiow_optimize_product`, `essiow_optimize_category`, bulk processors) now also call `session_write_close()` and raise the PHP time limit before doing any work. Mitigates 504 timeouts on shared hosts where Wordfence WAF or similar serializes admin-ajax requests through a session lock.

= 1.1.13 =
* Fix: product and category optimization are now also async (same `start → poll → result` pattern as blog articles), so single-product and single-category optimizations no longer fail with a 504 Gateway Timeout on hosts behind Cloudflare. The legacy synchronous `essiow_optimize_product` / `essiow_optimize_category` endpoints are kept for backward compatibility (used by the bulk optimizer that already handles its own retries).
* Improve: shared `runEssiowAsyncTask()` helper in admin.js — same network resilience for products/categories as for articles (30 s XHR timeout, 5 consecutive 504s tolerated, 8 s polling interval).
* Improve: prompts now ban colons in titles outright (no exceptions). The previous "avoid colons unless splitting two clearly different ideas" wording was misinterpreted by the AI as permission to keep generic " : guide / efficace / pas cher" suffixes. Article, product and category SEO titles now use dashes, commas, "vs" or rephrasing instead.

= 1.1.12 =
* Fix: definitive fix for "Erreur réseau / 504" on sites behind Cloudflare with Wordfence WAF or any plugin that opens a PHP session. Every AJAX handler now calls `session_write_close()` at the very top, so concurrent polls are never blocked behind a worker that holds the session lock.
* Fix: removed the HTTP loopback dispatch — on Cloudflare-fronted sites the loopback request to admin-ajax.php went through Cloudflare too and counted as another concurrent admin-ajax hit, which triggered WAF serialization and saturated FPM workers. The plugin now relies on (1) `fastcgi_finish_request()` when available + (2) WP-Cron with `spawn_cron()` triggered immediately + (3) a poll-driven fallback in `check_status` that runs the task itself if it has been pending more than 30 seconds.
* Improve: client-side polling is now resilient to transient 504/timeout errors. A single failed poll no longer kills the generation: up to 5 consecutive network errors are tolerated, the polling interval is 8 s instead of 3 s, the first poll fires after 10 s, and each XHR has an explicit 30 s timeout (well below Cloudflare's 100 s origin timeout).

= 1.1.11 =
* Fix: blog article generation no longer triggers a 504 Gateway Timeout on hosts behind a strict reverse proxy (Cloudflare, Caddy, hardened NGINX). The previous 1.1.8 dispatch ran `run_task_inline` inside a `shutdown` action, which keeps the FPM connection open until the AI call completes (10–30 s) — proxies that buffer the entire response would time out at 60 s. The new flow sends the JSON response, calls `fastcgi_finish_request()`, THEN processes the task in background. The browser sees a sub-second response.
* Improve: loopback fallback (for hosts without `fastcgi_finish_request`) now uses a 0.5 s timeout instead of 1 s — fewer cases of the parent request hanging while it waits for the loopback to dispatch.

= 1.1.10 =
* Fix: blog article generation now passes the real WooCommerce category permalinks to the AI (the previous payload key `cat_links` was ignored by the server, which expects `category_links`). Articles now contain real internal links to your store categories instead of invented or missing ones.
* Fix: category optimization now passes blog post permalinks under the correct `blog_posts` key — the AI can finally weave links to your real articles into the long category description.
* Add: JSON-LD `BlogPosting` schema is now emitted on the front-end of every Essiow-generated article (gated by the existing schema option). Includes headline, description, datePublished, dateModified, author, publisher, image, keywords. Helps rich snippet eligibility for users not running Yoast/Rank Math.

= 1.1.9 =
* Improve: blog articles, products and categories are now generated with intent-driven titles. The AI must analyze the search intent (informational, commercial, transactional, navigational) and produce a question-style or affirmative title that directly answers it — replaces generic clichés like "X : guide complet et conseils efficaces".
* Improve: AI no longer paraphrases the prompt. Forbidden patterns explicitly listed in prompts: "Introduction" / "Présentation" / "Pour commencer" headings, "voici les liens", "Dans cet article", "Saviez-vous que…", "De nos jours…". Articles must open with the actual answer in the first sentence.
* Fix: published articles now appear as proper Gutenberg blocks (paragraph, heading, list, table, image, quote, separator) instead of a single HTML block. The plugin parses the AI HTML with DOMDocument and wraps each top-level element in the correct `<!-- wp:... -->` annotation before `wp_insert_post`.
* Fix: residual "Introduction" / "Présentation" H2 headings the AI may still slip in are now stripped before publishing.

= 1.1.8 =
* Fix: blog article generation no longer hangs with `admin-ajax.php` ERR_TIMED_OUT on shared / mod_security hosts. Background dispatch now uses a 3-tier strategy: fastcgi_finish_request() (instant, PHP-FPM hosts), HTTP loopback (existing), and WP-Cron fallback (always works). The first available wins; redundant workers are idempotent (transient state guards against double-processing).
* Improve: client-side polling extended from 5 min to 10 min so 5000-word articles have time to complete on slower OpenAI responses.
* Improve: HTTP loopback now forwards cookies for hosts that require an authenticated session even on nopriv handlers.

= 1.1.7 =
* Fix: API key now persists correctly across saves (no longer "disappears" after Test Connection)
* Fix: rare "Invalid API key" error caused by encryption format collision (random IV containing the legacy "::" separator) — new "v2:" format is collision-proof, legacy "v1" payloads remain readable
* Add: static cache on get_api_key() prevents redundant decryptions and migration race conditions within a single request
* Add: 5-minute transient cache on license verification, 60-second transient on credit balance — fewer redundant API calls per admin page load
* Add: automatic retry with backoff (1s, 3s) on network errors and 5xx responses (4xx auth/validation are not retried)
* Add: auto-purge of essiow_last_errors entries older than 7 days
* Settings UI: API key field now shows the masked saved key as placeholder, leave empty to keep the saved key
* Improve: uninstall.php now lists encrypted-key options explicitly

= 1.1.6 =
* Fix: blog article generation now uses asynchronous task processing to avoid "Network error" on hosts with short proxy or PHP-FPM timeouts
* Improve: background generation worker keeps running on long AI calls (ignore_user_abort, extended time limit, session lock released)

= 1.0.0 =
* Initial release
* Product SEO optimization with descriptions, meta, alt text, schema
* Category SEO optimization with rich content and FAQ
* Blog article generator with product integration
* AI Sales Agent with chatbot widget
* 8 languages, 4 tones, 3 content lengths
* Bulk optimization with progress tracking
* Yoast SEO, Rank Math, All in One SEO support
* GDPR compliant

== Upgrade Notice ==

= 1.1.17 =
Critical fix for bulk and parallel optimizations stopping after 3-5 items. Each Flask call is now isolated to its own short-lived PHP process so `max_execution_time` and FPM worker saturation can't interrupt the queue. Recommended.

= 1.1.16 =
Polish on 1.1.15 bulk: stuck-item recovery, clean cancel/error UX, missing strings. Recommended.

= 1.1.15 =
Major bulk overhaul: full async dispatch (no more 504 on category bulk), per-row progress states like single optimize, percentage bar everywhere, cancel button, auto-resume on page reload. Recommended for anyone using bulk optimization.

= 1.1.14 =
Adds a filemtime-based cache buster so the new admin JS is loaded immediately after update, plus session/timeout hardening on legacy sync endpoints. Recommended for anyone still seeing 504 on category optimize after 1.1.13.

= 1.1.13 =
Fixes 504 Gateway Timeout on single-product and single-category optimization (same async dispatch as blog), and bans colons in AI-generated titles. Recommended update.

= 1.1.12 =
Definitive fix for "Erreur réseau / 504" on sites behind Cloudflare + Wordfence (or similar). Concurrent polls no longer block on PHP sessions, the loopback dispatch is removed, and the JS tolerates transient network errors. Recommended update for everyone on 1.1.8 → 1.1.11.

= 1.1.11 =
Critical fix for "Erreur réseau / 504" when generating blog articles on hosts behind Cloudflare/Caddy/strict NGINX. The browser response now closes before the AI call runs. Recommended update.

= 1.1.10 =
Fixes a payload mismatch that prevented categories and blog links from reaching the AI for articles and category pages, and adds JSON-LD Article schema. Recommended update for anyone on 1.1.8 or 1.1.9.

= 1.1.9 =
Major content quality fix: AI now writes intent-driven titles (no more "guide complet" clichés), stops paraphrasing the brief ("Introduction", "voici les liens"), and articles publish as real Gutenberg blocks instead of a single HTML block. Recommended update.

= 1.1.6 =
Fixes a "Network error" that could appear when generating blog articles on hosts with short HTTP proxy timeouts. Recommended update.

= 1.0.0 =
Initial release of Essiow AI SEO Suite for WooCommerce.
