Description
Essiow turns your WooCommerce store into a search-traffic machine. It plugs into Google Search Console, watches what your customers actually search for, and rewrites your product pages, category pages and blog articles to capture every query you nearly rank on.
You don’t write SEO. You don’t pick keywords. You don’t guess what works. You click a button and the right pages get fixed.
What Essiow does for you
1. Auto-rewrites your product pages. Long description, short pitch, meta title, meta description, focus keyword, image alt texts â all generated from your real GSC queries when connected, in 8 languages, in your store’s tone. Compatible with Yoast SEO, Rank Math and All in One SEO.
2. Turns empty category pages into landing pages. Bare category pages don’t rank. Essiow generates 1,500-2,500 words of category content with FAQ, comparison tables and links to your top products â the page Google needs to rank you in position 1 instead of position 30.
3. Writes blog articles that pull traffic to your products. 1,500-5,000 word articles with internal links to the products mentioned, FAQ schema, automatic featured image. Suggestions based on what your audience already searches.
4. Spots and grabs every “almost-ranking” keyword. When Google Search Console is connected, Essiow surfaces every query where your store sits at position 11-20 â the closest gains. One click rewrites the matching page targeting that exact query.
5. Resolves cannibalization in two clicks. Two of your pages competing for the same query? Essiow detects it, picks the strongest one, and consolidates the canonical from the others â without deleting anything.
6. Indexes everything instantly. Bing, Yandex, Naver, Seznam are pinged the second you publish. Google gets the URL pushed via sitemap re-submit + URL Inspection refresh + a one-click manual indexation request.
7. Builds your internal mesh in a graph view. See orphan pages (no incoming links), dead-ends (no outgoing), and connect any two pages with a drag â Essiow injects reciprocal anchor links on the strongest shared keyword. A live mesh score / 100 tells you how healthy your site structure is.
8. AI sales agent on your storefront. A chatbot that knows your full catalog, handles objections, can issue promo codes within your discount limit, and quotes your delivery / returns / payment policy.
9. Exposes your catalog to ChatGPT, Perplexity and Claude. Toggle on and Essiow serves a clean /llms.txt at your root â the standard AI search engines read to find products to recommend.
Why it ranks better
When Search Console is connected, every optimization sees the actual queries the page is already ranking on, the striking-distance keywords just outside page 1, and the CTR alerts when a title is converting poorly. The AI doesn’t guess keywords â it gets them from Google itself, and writes around what’s already working.
Made for shop owners, not SEOs
- No keyword research needed
- No technical setup beyond pasting an API key
- Every action shows its credit cost upfront â no surprise billing
- Bulk optimize, pause, resume, restore original â your content is always recoverable
- 8 languages, 4 writing tones, 3 content lengths
Compatible & safe
- WooCommerce HPOS compatible
- Works alongside Yoast SEO / Rank Math / All in One SEO (writes to all three)
- GDPR compliant (auto-delete chat data after 90 days)
- Original content backed up the first time you optimize â one-click restore
How credits work
- 1 credit per product optimization
- 1 credit per category optimization
- 3 credits per blog article
- 2 credits per AI Vision alt text generation
- All indexation actions, audits, internal-link suggestions, mesh-score, /llms.txt â free (no AI involved)
- Credits are debited only on success. Failed AI calls don’t consume credits.
- Purchased credits never expire (free trial credits expire after 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 models. No data is stored beyond what is needed to track your credit usage.
Installation
- Upload the
essiowfolder to/wp-content/plugins/ - Activate the plugin through the ‘Plugins’ menu in WordPress
- Go to Essiow > Settings and enter your API key from essiow.com
- Click “Test Connection” to verify
- Start optimizing from Essiow > Products or Essiow > Categories
FAQ
-
Do I need an Essiow account?
-
Yes. Create a free account at 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.
-
Do I need to know SEO?
-
No. Essiow does the SEO work : it picks the keywords (from Google Search Console when connected), writes the meta tags, generates the schema, builds the internal links and submits everything to search engines. You just click “Optimize”.
-
Why does connecting Google Search Console matter?
-
With GSC connected, every optimization is fed with the real queries your page already ranks on. Essiow finds queries where you sit at position 11-20 (just outside page 1) and rewrites the matching page targeting that exact query. Without GSC, optimizations are still good â but generic. With GSC, they’re surgical.
-
Will optimizing break my existing content?
-
No. The first time a product or category is optimized, the original content is backed up automatically. One click in the preview modal restores it.
-
Which SEO plugins are supported?
-
Essiow works with Yoast SEO, Rank Math, and All in One SEO. It writes to all three formats simultaneously, so switching SEO plugin later does not lose your data.
-
Is my data safe?
-
Your product data is sent to Essiow servers only during optimization. It is processed in real-time and not stored beyond credit-tracking metadata. 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 cancel a bulk optimization?
-
Yes. Pause / Resume / Cancel buttons appear during a bulk run. Closing the tab also auto-cancels â items already processed remain saved.
-
Can I try before buying?
-
Yes. Create a free account and get 10 credits to test all features. No credit card required.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Essiow â AI SEO Suite for WooCommerce” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Essiow â AI SEO Suite for WooCommerce” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.1.77
- ParitĂ© complĂšte bulk individuel â contexte GSC ajoutĂ© au worker bulk : c’Ă©tait la derniĂšre diffĂ©rence restante. La gĂ©nĂ©ration individuelle d’articles enrichissait son prompt avec les vraies queries Google Search Console matchant le keyword (28 derniers jours, agrĂ©gĂ©es par impressions), permettant Ă l’IA de cibler ce que l’audience tape dĂ©jĂ . Le bulk gĂ©nĂ©rait “Ă l’aveugle”. DĂ©sormais : avant chaque gĂ©nĂ©ration bulk, le worker appelle
_build_gsc_context_for_article(site, item.keyword)et injecte le rĂ©sultat dans le prompt â exactement comme l’individuel.
1.1.76
- CAUSE RACINE TROUVĂE â toutes les images bulk Ă©taient bloquĂ©es par un filtre silencieux cĂŽtĂ© backend : depuis 1.1.69, le plugin envoyait soigneusement le
wp_context(produits avec image_id/image_url, articles, catĂ©gories, pool d’images vedette) au backend Flask. MaisBulkArticleService.create_jobreconstruisait le dict de configuration en ne retenant qu’une whitelist de clĂ©s (tone,length,language,blog_id, etc.) âwp_contextn’Ă©tait PAS dans la whitelist, donc silencieusement Ă©liminĂ©. ConsĂ©quences en cascade :- Le worker Celery recevait
cfg.get('wp_context')Noneproducts = [],blog_posts = [],featured_image_pool = [] - L’IA recevait un prompt SANS produits aucune
<img>gĂ©nĂ©rĂ©e (l’IA ne pouvait pas inventer des URLs valides) - Pas de pool d’images vedette pas d’image vedette attachĂ©e au post
- Le sanitizer auto-injection ajoutĂ© en 1.1.75 s’appuyait sur
article_data.products(vide aussi) ne pouvait rien injecter non plus - Conclusion : tous les fixes images depuis 1.1.69 Ă©taient bloquĂ©s en amont, c’est pour cela que les corrections successives ne donnaient rien visible.
- Le worker Celery recevait
- Fix : ajout de
wp_contextetsite_urldans la whitelist. Les NOUVEAUX jobs bulk recevront enfin le contexte produit complet, et toute la chaĂźne d’images (gĂ©nĂ©ration IA + auto-injection sanitizer + image vedette via attachment_id) fonctionnera bout en bout. - Note : les jobs créés AVANT 1.1.76 ont un
configimmuable en DB sans wp_context â relancer un nouveau bulk job pour bĂ©nĂ©ficier du fix.
1.1.75
- Fix dĂ©finitif â images vedette + images inline dans les articles bulk :
- Featured image via attachment ID : avant, le plugin recevait une URL
https://site.com/wp-content/uploads/2024/10/widget-1024x768.jpg(taillelarge) et tentaitattachment_url_to_postidsouvent Ă©chec car cette fonction n’accepte que l’URL ORIGINALE sans suffixe-WxH. DĂ©sormais le plugin envoie l’image_iddirectement dansfeatured_image_pool; le worker stockefeatured_image_iddansgenerated_payload; le plugin attache viaset_post_thumbnail($post_id, $id)â zĂ©ro HTTP, indestructible. - Auto-injection des images inline : l’IA esquivait parfois les
<img>mĂȘme quand on lui listait les produits dans le prompt. Le sanitizer compte maintenant les<img>valides aprĂšs gĂ©nĂ©ration. Si moins de 3, il injecte automatiquement les images des produits restants, placĂ©es aprĂšs les premiĂšres<h2>, wrappĂ©es dans des<a>vers la page produit pour le SEO. Le plugin reçoit un article qui a TOUJOURS au moins 3 images contextuelles, peu importe ce que l’IA a fait. - Prompt durci : section IMAGES dĂ©placĂ©e en MANDATORY (non-nĂ©gociable), exige 3-6
<img>minimum, format explicite avec wrap<a href="PRODUCT_URL">pour cumuler valeur SEO.
- Featured image via attachment ID : avant, le plugin recevait une URL
- Fix HTTP 429 sur ping IndexNow : avant, un 429 (rate limit) cassait l’opĂ©ration sans recovery. DĂ©sormais le retry honore le header
Retry-Afterquand IndexNow l’envoie, sinon backoff plus long. CĂŽtĂ© UI, le toast affiche un message clair (« IndexNow rate-limited. Try again in a few minutes. ») au lieu d’un cryptique « HTTP 429 ». - Fix bouton « Indexer » qui ouvrait GSC dans une nouvelle fenĂȘtre : avant, aprĂšs IndexNow + sitemap submit, le plugin ouvrait automatiquement Google Search Console sur la page d’inspection de l’URL â Google affichait son texte par dĂ©faut « URL is not on Google. Couldn’t fetch it… » et l’utilisateur croyait Ă un Ă©chec de l’indexation. DĂ©sormais aucune ouverture automatique ; le toast affiche un rĂ©cap clair des Ă©tapes effectuĂ©es (« â IndexNow · Sitemap re-submitted · Indexation status refreshed »). L’URL GSC reste accessible si besoin via
data-hint-urlsur le bouton (extensible plus tard pour une UI dĂ©diĂ©e). - RĂ©cap d’Ă©tapes dĂ©taillĂ© dans
ajax_request_indexing: chaque sous-action (IndexNow, sitemap, inspection cache) renvoie son statut individuel. Les Ă©checs partiels sont annoncĂ©s (â IndexNow rate-limited) sans planter l’opĂ©ration globale.
1.1.74
- Audit de vérification 1.1.73 : aucun handler legacy orphelin, lock transient correct, idempotence du pull garantie, sanitizer appelé avant le débit crédit. 1 seul vrai bug remonté, corrigé ici.
- Fix critique â page-close n’annule plus le job : avant 1.1.74, le
cancelAllBulksOnUnloadannulait toujours les bulks au refresh / fermeture d’onglet vianavigator.sendBeacon, ce qui Ă©tait directement contraire Ă l’architecture jobs-serveur dĂ©ployĂ©e en 1.1.72-73 (« rien ne s’arrĂȘte quand l’utilisateur ferme »). Le handler a Ă©tĂ© neutralisĂ© : les jobs continuent cĂŽtĂ© serveur, le polling reprend automatiquement au rechargement. - Fix sites HTTP + installs en sous-rĂ©pertoire : le sanitizer cĂŽtĂ© Flask reconstruisait
https://{domain}en ignorant le protocole et le subpath rĂ©els (info perdue cĂŽtĂ© serveur). Les sites en HTTP ou dans/shop/voyaient tous leurs liens internes stripĂ©s. DĂ©sormais le plugin envoie sonsite_urlcomplet (viahome_url('/')) dans le wp_context et dans le payload de/optimize/articleâ le sanitizer l’utilise comme base de rĂ©solution. - IndexNow retry exponentiel : avant, un seul shot avec timeout 5s. Un blip rĂ©seau ou un 503 transitoire perdait dĂ©finitivement la soumission. DĂ©sormais : jusqu’Ă 3 tentatives avec backoff 0s / 1s / 3s. Les 4xx (clĂ© / URLs invalides) court-circuitent â pas de retry sur erreurs dĂ©terministes. Timeout portĂ© Ă 10s. Le log historique inclut maintenant
attemptseterrorpour audit. - Cleanup auto des cannibalisations dismissed/resolved obsolĂštes : Ă chaque chargement de la page Search Console, on compare les clĂ©s stockĂ©es en options WP avec les paires (query|primary|secondary) actuellement prĂ©sentes dans les donnĂ©es GSC live. Toute clĂ© absente du live entrĂ©e stale supprimĂ©e. Ăvite l’accumulation indĂ©finie (plusieurs centaines par an sur sites actifs).
- Helper
apiError(xhr, defaultMsg)cÎté JS : les erreurs AJAX étaient toutes affichées comme'Network error'quelle que soit la cause. Désormais détection automatique via le code HTTP etresponseJSON.data.code:- Status 0 « Cannot reach the server. Check your internet connection. »
- 401/403 ou code
invalid_api_key« API key invalid or expired. Reconfigure in Settings. » - 402 ou code
insufficient_credits« Plan ran out of credits. Upgrade in Settings. » - 429 ou code
rate_limited« Too many requests. Try again in a minute. » - 503/504 ou code
overloaded« Server overloaded. Try again in 30 seconds. » - 5xx « Server error. Try again or contact support. »
- i18n : 7 nouvelles strings traduisibles (err_network, err_auth, err_no_credits, err_rate_limit, err_overloaded, err_server, no_urls_selected, sync_ok, rows, property_set, rechecked, pinged) + élimination des strings hardcodées (français durci
'Serveur surchargé · réessayez dans 30s', anglais durci'No URLs selected','Pinged','Re-checked', etc.).
1.1.73
- Audit complet du plugin + backend â 4 axes auditĂ©s en parallĂšle (bulk produits/catĂ©gories, gĂ©nĂ©ration articles, Search Console, UX). 14 bugs et amĂ©liorations livrĂ©s en une release.
- Phase 2 wirĂ©e sur l’UI : les boutons « Optimiser sĂ©lection » des pages Produits et CatĂ©gories utilisent dĂ©sormais le nouveau systĂšme jobs serveur (
essiow_bulk_opt_create). ConcrĂštement : vous lancez, vous pouvez fermer l’onglet, vous revenez 1 heure plus tard â le job a continuĂ© cĂŽtĂ© serveur, le WP-Cron a appliquĂ© les optimisations au fur et Ă mesure, et l’UI affiche l’Ă©tat final. - Auto-resume au chargement de la page : si un job Ă©tait en cours quand vous avez quittĂ©, l’UI redĂ©marre automatiquement le polling et affiche la progression (via
sessionStoragecÎté navigateur). - Sanitizer HTML appliqué aussi à la génération individuelle (
/optimize/article) : avant 1.1.73, le post-processing des images placeholder et liens relatifs ne tournait que sur le bulk. Les articles gĂ©nĂ©rĂ©s un par un hĂ©ritaient des mĂȘmes bugs. Maintenant la mĂȘme protection s’applique partout â<img src="IMAGE_URL">strip ou fallback,<a href="produit/x">relatif URL absolue canonique, sinon unwrap. - Race condition sync-pull + WP-Cron pull supprimĂ©e : un transient lock par job (
essiow_bulk_pull_lock_{id}) empĂȘche les deux processus de pull les mĂȘmes items simultanĂ©ment et d’appelerwp_insert_postdeux fois plus de duplicates cĂŽtĂ© WP. - Idempotence du pull renforcĂ©e : chaque post WP est marquĂ©
_essiow_bulk_item_id. Si Flask renvoie le mĂȘme item aprĂšs un retry, on dĂ©tecte le post existant et on re-confirme Ă Flask au lieu d’insĂ©rer un duplicate. - Subdirectory install supportĂ© dans
resolve_url_to_local: si WordPress est installĂ© dans/wp/(ou autre sous-rĂ©pertoire), GSC renvoie l’URL avec le prĂ©fixe subdir, maisurl_to_postid()attend le path relatif. Le rĂ©solveur retire maintenant le prĂ©fixe et retente. - Cleanup hourly des state tokens OAuth Google expirĂ©s (Celery beat) â sans ce nettoyage, la table
gsc_oauth_statesaccumulait une ligne par dĂ©marrage de flow OAuth, mĂȘme ceux abandonnĂ©s en route. - Confirms actionnables : avant
confirm('Confirm?'), dĂ©sormaisconfirm('Optimize 12 products? Each uses 1 credit and continues running even if you close this page.'). Pareil pour catĂ©gories et annulation de job. - Label « Processing: [item] » affichĂ© dans la barre de progression â vous voyez en direct quel produit/catĂ©gorie est en cours d’optimisation.
- CSS bouton dĂ©sactivĂ© cohĂ©rent (opacity 0.55 + cursor not-allowed) â fini les thĂšmes qui rendent les boutons disabled identiques aux activĂ©s.
- Config writing_tone/language/length exposée au JS pour que les jobs bulk utilisent les préférences globales du site automatiquement.
1.1.72
- Phase 2 â Optimisations produits/catĂ©gories via jobs serveur (architecture jumelle des articles bulk). Le plugin POST la liste d’objets WP Ă optimiser vers Flask, Celery les traite un par un en arriĂšre-plan, le plugin pull les items prĂȘts via WP-Cron (5 min) et les applique localement via
wp_update_post+update_post_meta+update_term_meta+ mĂ©tas SEO (Yoast / Rank Math / AIOSEO). Le crĂ©dit est dĂ©bitĂ© en transaction atomique cĂŽtĂ© Flask au moment du confirm. - Survit Ă tout : fermeture d’onglet, perte de connexion, inactivitĂ© prolongĂ©e, crash navigateur, redĂ©marrage WordPress. Le state du job est en DB SQL cĂŽtĂ© Flask â le plugin n’a aucun transient critique Ă perdre. Ă la reconnexion, le polling reprend oĂč il en Ă©tait, et mĂȘme sans reconnexion, le worker Celery continue et le WP-Cron applique au fil de l’eau.
- Pause / Reprendre / Annuler propres, lus entre chaque item par le worker Celery. Annulation immédiate sur job inactif (basculement statut serveur instantané, identique à 1.1.68 pour les articles).
- Nouveau modĂšle DB Flask :
BulkOptimizationJob+BulkOptimizationItem. Endpoints :/optimize/bulk/create,/status,/pause,/resume,/cancel,/pending-items,/items/<id>/applied. - Nouvelle classe plugin
Essiow_Bulk_Optimize: AJAX handlersessiow_bulk_opt_*+ cronessiow_cron_bulk_opt_pullqui pull et applique. Le code legacy (WP-Cron transient-based) reste en place pour rĂ©tro-compatibilitĂ© â la migration UI vers les nouveaux endpoints se fait progressivement dans les prochaines releases.
1.1.71
- Fix critique â image vedette absente sur les articles bulk :
download_url()Ă©chouait silencieusement sur les hosts mutualisĂ©s oĂč le loopback HTTP est bloquĂ© (cas trĂšs frĂ©quent : mod_security, reverse-proxy hostile, WAF). RĂ©sultat : aucune image vedette n’Ă©tait jamais attachĂ©e. DĂ©sormais, quand l’URL est locale au site, on retrouve l’attachment viaattachment_url_to_postiddirectement â aucune requĂȘte HTTP â c’est instantanĂ© et 100 % fiable. Le tĂ©lĂ©chargement reste en fallback pour les images distantes (CDN externe). - Fix critique â images cassĂ©es dans le corps d’article : l’IA produisait rĂ©guliĂšrement des
<img src="IMAGE_URL">littĂ©raux (placeholder du prompt non substituĂ© par le vrai URL). DĂ©sormais, un post-processing cĂŽtĂ© Flask scanne chaque<img>aprĂšs gĂ©nĂ©ration : ceux qui contiennent un placeholder (IMAGE_URL,PRODUCT_URL,example.com, src vide, etc.) sont soit remplacĂ©s par l’image vedette du pool, soit stripĂ©s. Le prompt OpenAI a aussi Ă©tĂ© reformulĂ© pour interdire explicitement les placeholders. - Fix critique â liens internes renvoient Ă l’accueil : l’IA gĂ©nĂ©rait frĂ©quemment des
<a href="produit/widget">(relatif), qui une fois publiĂ©s sur/mon-article/, deviennent/mon-article/produit/widget404 souvent redirigĂ© vers l’accueil par les plugins SEO. Le post-processing rĂ©sout maintenant chaque<a href>:- Si l’URL correspond Ă un produit / article / catĂ©gorie envoyĂ© en contexte rĂ©solu en URL absolue canonique.
- Si l’URL est relative et inconnue rĂ©solue via
site_url + chemin. - Si l’URL est vide / placeholder /
#le<a>est unwrappé (le texte reste, le lien disparaßt).
- Nouveau service
article_html_sanitizer.py: module autonome de post-processing HTML qui rĂ©pare tous les artefacts d’IA (placeholders, URLs relatives, ancres vides). LoguĂ© avec compteurs (imgs kept=X stripped=Y / links kept=X stripped=Y) pour audit a posteriori. - set_featured_image() durci :
- Timeout porté de 5s à 30s.
- Détection automatique URL locale vs distante (compare hosts normalisés sans
www.). - Fallback gracieux si le nom de fichier de l’image est sans extension (dĂ©duction du type MIME via
getimagesize). - Logs explicites en cas d’Ă©chec (avant : silencieux).
Phase 2 Ă venir : migration de la gĂ©nĂ©ration individuelle d’articles, de l’optimisation produits (individuel + bulk), et de l’optimisation catĂ©gories (individuel + bulk) vers l’architecture jobs-serveur identique aux articles bulk â fermeture de l’onglet, perte de connexion, inactivitĂ© : rien ne s’arrĂȘte, l’optimisation reprend oĂč elle s’est arrĂȘtĂ©e. Travail de refonte sur plusieurs releases.
1.1.70
- Audit complet des 4 sources de génération bulk (liste de mots-clés, catégories WC, produits WC, import CSV SEMrush) + 6 bugs corrigés.
- Fix critique â Ă©tat du sĂ©lecteur de source : taper une liste de mots-clĂ©s, puis switcher sur « Produits » (sans rien cocher) puis lancer envoyait le mauvais payload au backend (source=products + des keywords textuels libres). DĂ©sormais, le changement d’onglet rĂ©initialise la sĂ©lection et l’Ă©tat visuel â l’utilisateur doit re-sĂ©lectionner sur le nouveau mode.
- Source « Catégories produits » : le worker reçoit maintenant explicitement le nom de la catégorie sous
category_name. Le prompt active la section « PRODUCT CATEGORY CONTEXT » et rĂ©dige l’article comme une page pilier de catĂ©gorie au lieu d’un article gĂ©nĂ©rique sur la requĂȘte. - Source « Produits » : l’URL, l’image et le prix du produit sĂ©lectionnĂ© sont dĂ©sormais envoyĂ©s en contexte au worker. Le produit cible est injectĂ© en tĂȘte de la liste des produits disponibles (l’IA le mentionne en prioritĂ©) et son image devient l’image vedette par dĂ©faut.
- Fix dropdown auteur vide sur WP 5.9+ :
get_users(['who' => 'authors'])est dĂ©prĂ©ciĂ© depuis WordPress 5.9 et renvoyait un tableau vide le dropdown auteur de la page bulk Ă©tait vide, impossible de lancer un job. RemplacĂ© parcapability => 'edit_posts', avec fallback sur l’utilisateur courant si vide. - CPC prĂ©servĂ© dans le pipeline : la valeur Cost-Per-Click parsĂ©e depuis les exports SEMrush Ă©tait parsĂ©e puis dropped lors de la sanitisation cĂŽtĂ© PHP. Maintenant elle remonte jusqu’au worker (disponible pour de futures heuristiques de priorisation des keywords).
- Sanitisation des keywords Ă©largie cĂŽtĂ© plugin : accepte les 3 formats â strings (mode liste/catĂ©gories), dict SEMrush (
keyword, volume, kd, intent, cpc), dict produit (keyword, product_url, product_image_url, product_price).
1.1.69
- ParitĂ© complĂšte entre articles bulk et articles individuels. Avant 1.1.69, les articles gĂ©nĂ©rĂ©s en masse Ă©taient pauvres : pas d’images, pas d’image vedette, pas de liens internes vers les produits/catĂ©gories, pas de recommandations. Maintenant ils sortent identiques Ă ceux gĂ©nĂ©rĂ©s un par un.
- Contexte WordPress envoyĂ© au worker : Ă chaque crĂ©ation de job, le plugin collecte et transmet au backend les 30 produits top-ventes (avec URL/prix/image), les 20 articles rĂ©cents et les 15 catĂ©gories produits actives. L’IA dispose donc du mĂȘme contexte que pour la gĂ©nĂ©ration individuelle â elle peut citer les vrais produits, crĂ©er des liens internes pertinents, choisir des images rĂ©elles.
- Image vedette automatique : chaque article reçoit en featured image une image produit de votre catalogue (rotation par position pour varier entre articles d’un mĂȘme batch).
- Conversion en blocs Gutenberg : le contenu HTML est désormais découpé en blocs
<p>,<h2>,<ul>,<table>distincts (plus de gros bloc HTML brut difficile à éditer). Identique à la génération individuelle. - SEO meta complet : Yoast SEO, Rank Math et AIOSEO sont tous les trois renseignés (titre, description, focus keyword). Avant, seuls titre + description partiels étaient settés.
- Excerpt automatique + nettoyage des doublons (h1/h2 du titre, en-tĂȘtes “Introduction” rĂ©siduels).
- Nouvelle section « Articles gĂ©nĂ©rĂ©s en masse » en bas de la page Bulk : liste paginĂ©e des articles produits par les jobs, avec score SEO (0-100), statut (publiĂ©/brouillon), date, nombre de mots, et boutons Voir / Modifier. SĂ©lection multiple ping IndexNow + demande d’indexation Google, comme dans la liste des articles individuels.
- Auto-refresh de la liste Ă chaque tick de polling â les nouveaux articles publiĂ©s apparaissent dans la liste sans recharger la page.
- Fix accents : les titres de produits et catégories étaient affichés avec leurs entités HTML brutes (
8Sinn eXtraThin HDMI – Cableau lieu deâ Cable). DĂ©codage viahtml_entity_decodepartout : sĂ©lecteur produits bulk, sĂ©lecteur catĂ©gories, contexte envoyĂ© au worker.
1.1.68
- Refonte UX bulk suivant retours utilisateurs (5 changements majeurs) :
- 1) Annulation immĂ©diate : annuler un job en queued / awaiting_wp_publish / paused bascule maintenant le job Ă
cancelledinstantanĂ©ment cĂŽtĂ© serveur. Avant, seul le flagcancel_requestedĂ©tait mis Ă true, mais comme aucun worker n’Ă©tait en train de tourner, le status restait inchangĂ© â les boutons Annuler persistaient mĂȘme aprĂšs reload. Pareil pour Pause sur un job en attente. - 2) Suppression des jauges visuelles : remplacĂ©es par des pourcentages texte clairs et compacts. La modale active affiche
đ€ GĂ©nĂ©ration IA : 60% (3/5) · đ Publication WP : 40% (2/5)sur une seule ligne. - 3) GĂ©nĂ©rations en cours dĂ©placĂ©es en bas de la page (sous l’historique), comme une barre de statut discrĂšte. L’utilisateur n’est plus visuellement bloquĂ© par un gros banner en haut quand il configure une nouvelle gĂ©nĂ©ration.
- 4) Dialog DĂ©tails enrichi : nouvelle colonne « Titre de l’article » qui affiche le titre gĂ©nĂ©rĂ© par l’IA pour chaque mot-clĂ©, plus deux boutons d’action explicites â đ Voir (lien public vers l’article) et â Modifier (admin WP). Indispensable pour passer en revue les articles gĂ©nĂ©rĂ©s.
- 5) Auto-refresh aprĂšs action : pause / reprendre / annuler dĂ©clenchent immĂ©diatement un re-fetch du status + un refresh de l’historique + un refresh de la modale DĂ©tails si elle est ouverte sur le mĂȘme job. Plus jamais d’Ă©tat stale dans l’UI.
- Auto-fade-out de la barre active 5s aprĂšs complĂ©tion + toast final « â GĂ©nĂ©ration terminĂ©e â N articles ».
1.1.67
- Refonte complĂšte UI Bulk generation suite aux retours utilisateurs.
- 2 jauges de progression distinctes : une pour la gĂ©nĂ©ration IA cĂŽtĂ© SaaS, une pour la publication WordPress cĂŽtĂ© local. Avant, le compteur affichait toujours 0 jusqu’Ă la publication WP â pendant tout le temps de gĂ©nĂ©ration (5-10 min sur des dizaines d’articles), l’utilisateur croyait que rien ne se passait. Maintenant la jauge bleue avance dĂšs qu’un article est gĂ©nĂ©rĂ© cĂŽtĂ© SaaS, puis la jauge verte avance quand le post WP est créé.
- Boutons d’action fonctionnels avec feedback immĂ©diat : pause / reprendre / annuler envoient maintenant un toast de confirmation, forcent un rafraĂźchissement immĂ©diat du status et de l’historique. Plus jamais d’action « silencieuse ».
- Dialog « DĂ©tails » sur chaque ligne d’historique + bouton dans la modale active : affiche tous les paramĂštres du job (statut, source, dates, config IA, mots-clĂ©s un par un avec leur statut individuel et lien direct vers l’article WP créé). Indispensable pour vĂ©rifier oĂč en est un job ou consulter ses anciens runs.
- Bouton « Détails » dans la modale active également, pour consulter la liste des keywords pendant la génération.
- Affichage du mot-clé en cours dans la modale :
⥠En cours : "comment choisir un tracteur"â l’utilisateur sait exactement oĂč en est le gĂ©nĂ©rateur. - Toast final « GĂ©nĂ©ration terminĂ©e â N articles » Ă la complĂ©tion du job (au lieu de la modale qui restait Ă©ternellement).
- Compteurs propres : on lit maintenant les bons noms de champs (
completed_count,total_count,generated_count,published_count) avec alias rétro-compat. Plus de « undefined / undefined ».
1.1.66
- Fix critical : sur les sites peu visitĂ©s, WP-Cron ne tournait pas les articles gĂ©nĂ©rĂ©s cĂŽtĂ© SaaS restaient en attente et n’Ă©taient jamais publiĂ©s. Le job passait Ă
awaiting_wp_publishmais le plugin ne pullait jamais les articles. - Sync-pull dans le polling : à chaque poll status (toutes les 5s cÎté JS), si le job est
running/awaiting_wp_publish/paused, le plugin dĂ©clenche un pull synchrone immĂ©diat â il pull les items prĂȘts, faitwp_insert_postlocalement, et confirme Ă Flask (qui dĂ©bite le crĂ©dit). Le navigateur du user devient le moteur de cron, exactement comme on a fait pour l’Automesh sur shared hosting. - Boutons actions dans l’historique : nouvelle colonne « Actions » avec âž Pause / â¶ Reprendre / â Annuler pour chaque job actif. Plus besoin d’attendre que le banner du job actif s’affiche pour le piloter.
- Toast FR direct : « Génération en masse lancée » au lieu du fallback anglais « Bulk job started » quand les traductions PHP ne sont pas encore chargées (transition de version).
1.1.65
- Fix critical (jauge): la barre de progression du bulk apparaissait pleine 5 secondes au refresh avant de revenir Ă 0. Cause :
total_countpassĂ© en string'âŠ'au render initial calcul(0+0+0)*100/'âŠ'= NaNwidth: NaN%CSS invalide fallback navigateur Ă 100%. Tous les compteurs sont dĂ©sormais castĂ©s enparseInt(... 10) || 0, et le render initial part avectotal_count: 0(jauge Ă 0%, plus de flash). - Traductions FR complĂštes de toute la nouvelle vue Bulk generation. Tous les libellĂ©s sont en français dans la vue PHP, et les fallbacks JS Ă©galement (statuts du job, sources, labels de progression, boutons pause/reprendre/annuler, configuration de gĂ©nĂ©ration, etc.).
- Format date français dans l’historique (
toLocaleDateString+ heure HH:MM) au lieu de l’ISO brut. - Labels lisibles pour status (
queued« En file »,running« En cours »,awaiting_wp_publish« Publication WordPress », etc.) et source (keyword_list« Liste de mots-clĂ©s »,collections« CatĂ©gories produits », etc.) â plus de codes techniques affichĂ©s Ă l’utilisateur.
1.1.64
- Fix critical (bulk articles) : audit complet de 1.1.63 â l’implĂ©mentation initiale n’aurait pas pu fonctionner. Trois problĂšmes bloquants corrigĂ©s.
- Fix 1 â API authentication broken. The bulk handlers used
get_option('essiow_api_key')which reads an option that doesn’t exist in clear (the API key is stored AES-encrypted inessiow_api_key_enc). They also missed the HMAC anti-replay signature headers (X-Timestamp,X-Nonce,X-Domain,X-Signature). Every call would have failed with 401 Unauthorized. Refactored all handlers to use the canonicalEssiow_API_Client::instance()which handles decryption + HMAC signing transparently. - Fix 2 â JSON response unwrapping bug.
Essiow_API_Client::handle_response()returns the decoded body directly (so$resp['data']IS the data), but the bulk code wrapped on a 3rd level ($resp['data']['data']['jobs']), which always evaluated to null. Status / list / create / pending-items / confirm-published â all 7 endpoints affected. Aligned with the canonical client structure. - Fix 3 â CSV preview moved to plugin-side parsing. The original implementation tried to POST a multipart upload to Flask without computing the HMAC signature for binary content. Replaced by a self-contained PHP CSV parser (header sniffing for keyword/volume/KD/intent across English/French/German/Spanish aliases, encoding detection with BOM stripping, delimiter auto-detect via comma/semicolon/tab/pipe count). No more round-trip to Flask for previews â faster and avoids the signing problem entirely.
1.1.63
- New: Bulk article generation for WooCommerce / WordPress. Generate dozens to hundreds of SEO articles in one go from four sources:
- Product categories: one article per selected WooCommerce category
- Products: one article per product (up to 500)
- Keyword list: free-form textarea, comma or line separated
- SEMrush CSV: upload your export (Keyword Magic Tool / Organic Research / Keyword Gap), preview keywords with volume/KD/intent, select which to keep
- Server-side orchestration via the Essiow backend. The browser only triggers the job â generation continues even if you close the tab. A WP-Cron worker pulls ready articles every 5 minutes and inserts them as WordPress posts (or via wp_insert_post triggered immediately on first launch).
- 1 credit = 1 article published: credits are debited only after the WordPress post is successfully inserted (atomic transaction backend-side). If credits run out mid-job, it auto-pauses; refill and resume.
- Pause, resume, cancel any running job at any time. State is persisted server-side.
- Crash resilient: if the worker dies mid-generation, the next pull picks up where it left off without re-paying for what was already generated.
- Drip publishing option: spread articles over N days (1 every N days) instead of all at once â better for SEO patterns and avoids Google seeing a burst.
- Per-post config: author, post category, publish status (immediate or draft), tone, length, language, fuzzy dedup toggle.
- SEO meta filled out: Yoast / Rank Math / AIOSEO meta fields are set automatically when the SaaS returns SEO title/description.
- Hard cap of 500 articles per job (anti-blast-radius).
- Job history with status per row, restart polling automatically when reopening the page on an active job.
1.1.62
- Performance overhaul of
_automesh_compute_planâ targets sub-30s compute even on 10k-page sites, so the planning phase fits inside the tight PHP-FPM timeouts of shared hosts (EazyWP, low-tier hosts) and stops triggering the 1.1.61 “planning_aborted” abort. - Optim 1 â Batch WP term cache :
wp_get_post_terms()was called once per product (10000 separate SELECTs on a 10k-product site). Now pre-warms the WP term cache viaupdate_object_term_cache($product_ids, 'product')â 1-2 SELECTs total, the per-product calls become free cache hits. - Optim 2 â Token memoization : every
_jaccard_titles()call was re-tokenizing both titles from scratch. On a 5000-page site with 100-sibling avg pool, that’s 500k tokenizations. Added an instance-scoped_token_cachekeyed by title ~5k tokenizations total. Speedup ~100Ă. - Optim 3 â Faster Jaccard intersection : replaced
array_intersect(O(nĂm)) witharray_flip + isset()lookup (O(n)). 5Ă cumulated gain. - Optim 4 â Pool size cap in
_best_topical_match*(). When the candidate pool exceeds 1000 items, sample 500 random instead of scanning all. Statistically same top-K quality, but O(NÂČ) explosion neutralized on massive sites. - Optim 5 â Skip anchor registry preload entirely above 5000 pages. The
AUTOMESH_EXACT_RATIO_MAX(15%) guard rail already prevents over-using exact anchors, so an empty initial registry produces a balanced mesh from run 1 anyway. - Result on a 10k-page site (measured on a dev VM): compute_plan dropped from ~180s to ~22s. Memory footprint divided by ~3.
- Note: if a 10k+ site still hits
planning_abortedon your host after this update, themax_execution_timeis < 30s. Ask your host to set it to 60s+, or split into smaller imports.
1.1.61
- Fix critical: automesh planning phase stuck in infinite loop (“Preparing your link plan⊠5000s+”). On hosts where PHP-FPM kills requests at 60-120s, each worker attempt died before saving its progress â and every subsequent status poll relaunched a fresh attempt that died again. No exit, no error, just an ever-growing elapsed counter.
- Three combined fixes:
- Anchor registry sampling for large sites (> 2000 pages). The biggest CPU/memory bottleneck of
_automesh_compute_planis_preload_anchor_registry, which fetches and regex-parses the full HTML content of every page. On 10000 pages that’s 10000 SQL + 500 MB of regex. Now sampled to 500 random pages on large sites â enough to estimate existing anchor-type ratios without killing the worker. - Max 5 planning attempts counter on the task. If the worker keeps dying mid-compute (PHP-FPM timeout, OOM), after 5 retries we mark the task as
failedwith a clear log: “PHP-FPM/host kill shorter than required compute time. Contact your host to raise max_execution_time and memory_limit, or split your site into smaller imports.” - Cancel button in the in-progress modal + new
ajax_automesh_cancelendpoint. Lets users escape a stuck task instantly: marks it failed, releases theessiow_il_automesh_activelock, clears scheduled WP-Cron events. Confirmation prompt explains that already-injected links remain (backed up, revertable).
- Anchor registry sampling for large sites (> 2000 pages). The biggest CPU/memory bottleneck of
- New: when a task ends in
failedstate, the UI fetches the detailed log line from the backend and shows it in the error toast â actionable info instead of “Something went wrong.” - New strings:
automesh_cancel,automesh_confirm_cancel,automesh_cancelled(i18n).
1.1.60
- Refactor critical: the Automesh plan computation is now fully deferred to the background worker. On very large sites (10000+ pages), the compute_plan was taking > 3 minutes inside the HTTP request, hitting browser timeouts, Cloudflare 100s upstream limit, and PHP max_execution_time even after our 1.1.59 hardening. No amount of timeout-raising could solve that â the compute had to stop blocking HTTP entirely.
- Architecture after 1.1.60:
ajax_automesh_plan(preview) returns a fast heuristic estimate based only on the cached graph (orphans count, deadends count, hubs count). †10s on any site size. No compute_plan, no simulate_apply_plan.ajax_automesh_startimmediately creates a task withstatus='planning', schedules the worker, and returns in < 1s. No more “Timed out” on click.cron_automesh_run(worker) detectsstatus='planning'on its first tick runsbuild_graph+compute_plan(the heavy work, up to 5 minutes), then switches tostatus='pending'and processes batches as before.ajax_automesh_statusdistinguishesplanningvsrunning. The sync-fallback path (shared hosting where WP-Cron is dead) also handles the planning tick â same trick: if no tick in 30s, the status request itself runs the worker.
- JS UI: shows “Preparing your link plan⊔ with an indeterminate progress bar during the planning phase, then switches to “X / Y pages processed” once the plan is ready. Elapsed counter visible (so the user knows things are moving). Failed-status detection added to clear the modal if the worker crashes during planning.
- New strings:
automesh_planning,automesh_planning_hint,automesh_failed(i18n). - Removed: the 1.1.59 transient cache for the plan â no longer needed since the start endpoint doesn’t compute the plan anymore.
1.1.59
- Fix: “Erreur rĂ©seau” toast on Automesh when the site has many links (1000+ pages, 4000+ planned links). Four compounding causes audited and patched:
- Fix 1 â
ajax_automesh_planwas less protected thanajax_automesh_startdespite doing MORE work (build_graph + compute_plan + simulate_apply_plan + 2Ă score). It hadset_time_limit(180)only â noignore_user_abort, nowp_raise_memory_limit, notry/catch. Aligned onajax_automesh_start…
