<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[LumoWP — WordPress Field Notes]]></title><description><![CDATA[LumoWP — WordPress Field Notes]]></description><link>https://lumowp.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 28 Oct 2026 21:59:13 GMT</lastBuildDate><atom:link href="https://lumowp.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Best AI Translation Plugins for WordPress: Natural Results, Real Control]]></title><description><![CDATA[Compare WordPress translation workflows and configure Lumo for WPML with your own AI provider, terminology rules and a practical review process.]]></description><link>https://lumowp.hashnode.dev/best-ai-translation-plugins-for-wordpress-natural-results-real-control</link><guid isPermaLink="true">https://lumowp.hashnode.dev/best-ai-translation-plugins-for-wordpress-natural-results-real-control</guid><category><![CDATA[WordPress]]></category><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Tue, 27 Oct 2026 21:28:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/7698caf5-9ca6-4020-86b4-f5ae44fe9840.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A translated website can be grammatically correct and still feel wrong. A button sounds like a paragraph. A product name changes halfway through the page. A return policy reads smoothly but promises something the original never promised.</p>
<p>That is why I would not choose a WordPress translation plugin by asking which one sounds the most human in a short demo. I would ask a more useful question: <strong>which workflow lets us preserve meaning, control terminology, review important pages and maintain translations when the site changes?</strong></p>
<p>This guide compares four practical options, then walks through Lumo AI Translation Addon for WPML. The goal is natural, accurate content that works inside a real website—not a score from an AI detector.</p>
<blockquote>
<p><strong>How this guide was prepared</strong></p>
<p>We develop Lumo, so this is not an independent ranking of our own product. The Lumo walkthrough is based on a review of local version 3.20.28 and existing product-interface captures. Competitor capabilities are checked against their official documentation. We did not run a paid, native-speaker benchmark across these services; illustrative examples below are not claimed as model outputs.</p>
</blockquote>
<h2>The best option depends on the website you already have</h2>
<p>There are three different decisions hiding inside the phrase “AI translation plugin.” The multilingual plugin manages language versions and their relationship. The translation engine generates text. The editorial workflow decides whether that text is suitable to publish.</p>
<p>Changing the engine does not automatically fix a missing translated template. Adding a glossary does not fix a broken language switcher. A model that writes attractive prose may still alter a technical instruction.</p>
<table>
<thead>
<tr>
<th>Option</th>
<th>A good fit when</th>
<th>What to evaluate before choosing</th>
</tr>
</thead>
<tbody><tr>
<td>WPML with its built-in automatic translation workflow</td>
<td>You want translation management and review within an established WPML setup</td>
<td>Supported content, editor workflow, engine availability and translation charges</td>
</tr>
<tr>
<td>WPML plus Lumo AI Translation Addon</td>
<td>You already use WPML and want your own provider API key, model choice and content-specific instructions</td>
<td>Provider billing, queue operation and review of your actual content types</td>
</tr>
<tr>
<td>TranslatePress AI</td>
<td>You prefer a front-end-oriented translation workflow and an integrated AI service</td>
<td>Included AI allocation, SEO requirements and how newly visited content is translated</td>
</tr>
<tr>
<td>Weglot</td>
<td>You prefer managing translation corrections in a hosted dashboard</td>
<td>Plan limits, glossary workflow and your dependency on the hosted service</td>
</tr>
</tbody></table>
<p>These are alternatives to evaluate, not four plugins to activate together. On an existing multilingual site, test a change on staging and check the migration implications before replacing the system that owns your translated URLs.</p>
<h2>1. WPML: an integrated translation and review workflow</h2>
<p>WPML is a sensible shortlist option when you want translation tasks, editable translations and terminology management in the same multilingual environment. Its documentation describes editing automatic translations, maintaining glossary entries and reviewing pages in its translation tools. Those controls matter more than a promise that every sentence will be perfect on the first attempt. <a href="https://wpml.org/documentation/translating-your-contents/edit-automatic-translations/">WPML: editing automatic translations</a>.</p>
<p>Check the workflow in the version you actually run: WPML screens and engine options evolve. Before buying or migrating, confirm how your theme, custom fields and page builder content enter translation jobs. A multilingual system needs to handle the website's structure as well as its paragraphs.</p>
<p>For a new installation, follow our <a href="https://lumowp.com/how-to-install-and-set-up-wpml-full-step-by-step-guide-2026/">WPML setup guide</a> first. Configuring an AI engine is much easier after source language, target languages and the language switcher are working.</p>
<h2>2. Lumo AI Translation Addon: bring your own engine to WPML</h2>
<p>Lumo is an <strong>add-on for WPML</strong>, not a standalone replacement. The reviewed build offers provider selection, an API key field, model selection, background processing, chunking and bulk tools. Its supported provider families include OpenAI, Anthropic, Google Gemini, xAI, DeepSeek and Mistral; the model you can use also depends on your provider account and the plugin build.</p>
<p>The practical reason to choose this approach is control. You can keep WPML as the multilingual foundation while setting translation instructions and choosing the engine used by Lumo's jobs. Costs for those provider calls are billed through your own provider account. WPML licensing and the Lumo license are separate considerations; using a personal key does not make translation free.</p>
<p>One detail in the source is especially useful: instructions are not limited to a single generic box. There are separate settings for titles, body content, Elementor templates and terms, alongside global instructions. That lets a short navigation label follow different writing constraints from a long tutorial.</p>
<p>The <a href="https://lumowp.com/product/lumo-wpml-ai-translation-addon-automate-your-multilingual-site-with-openai-claude-mistral-grok/">Lumo AI Translation Addon product page</a> contains the current package and product details. The walkthrough below focuses on what you should configure and verify before running a large batch.</p>
<p><a href="https://lumowp.com/product/lumo-wpml-ai-translation-addon-automate-your-multilingual-site-with-openai-claude-mistral-grok/"><img src="https://cdn.lumowp.com/2026/10/lumo-ai-guide-v2-overview.webp" alt="Explore Lumo AI Translation Addon for WPML: translate posts, products, strings and Elementor templates with your own AI provider" /></a></p>
<p><em>Lumo supplies the translation engine while WPML manages the languages. Select the image to see the product and requirements.</em></p>
<h2>3. TranslatePress AI: a visual editing approach</h2>
<p>TranslatePress is worth evaluating if your team prefers finding text on the front end. Its integrated AI option does not require you to supply a separate provider API key. Its documentation explains that generated translations are stored in the WordPress database and reused, while AI usage is counted across translated words and languages. Check the allocation associated with your active license. <a href="https://translatepress.com/docs/automatic-translation/translatepress-ai/">TranslatePress AI documentation</a>.</p>
<p>This workflow is attractive when an editor needs to see where a phrase appears. Still, include SEO fields, slugs and dynamic content in your trial rather than judging only the homepage. TranslatePress documents separate automatic-translation settings and SEO-related requirements, including its SEO Pack for automatic slug translation. <a href="https://translatepress.com/docs/automatic-translation/">Automatic translation settings</a>.</p>
<h2>4. Weglot: centralized editing and terminology rules</h2>
<p>Weglot provides a hosted translation dashboard with a translation list, visual editing and glossary rules. Its editing documentation also describes AI-assisted improvement and ways to involve other reviewers. This can suit a team that wants to manage corrections in a central workspace rather than only in WordPress. Confirm the availability of the features you need in your chosen plan. <a href="https://support.weglot.com/article/128-how-to-edit-my-translations">Weglot translation editing</a>.</p>
<p>Do not confuse an attractive preview with a completed functional test. Weglot notes that cookie-dependent and dynamic behavior, including login or add-to-cart actions, may behave differently in its Visual Editor. Test those journeys on the actual translated site too. <a href="https://support.weglot.com/article/409-how-to-use-the-visual-editor">Weglot Visual Editor</a>.</p>
<h2>What “human-sounding” translation should mean</h2>
<p>Natural writing is only one part of quality. A translation can sound excellent while changing an exclusion in a refund policy. It can preserve every fact but leave a button so long that nobody can use it on mobile.</p>
<p>Use five acceptance checks: <strong>meaning, terminology, tone, interface fit and technical integrity</strong>. They reveal problems that a vague “make this human” prompt cannot reliably prevent.</p>
<table>
<thead>
<tr>
<th>Check</th>
<th>A concrete question</th>
<th>A failure worth fixing</th>
</tr>
</thead>
<tbody><tr>
<td>Meaning</td>
<td>Are obligations, quantities and exceptions unchanged?</td>
<td>“Usually dispatched” becomes a guaranteed delivery promise</td>
</tr>
<tr>
<td>Terminology</td>
<td>Is the same feature named consistently?</td>
<td>“Workspace” becomes three different concepts</td>
</tr>
<tr>
<td>Tone</td>
<td>Is the level of formality appropriate for this audience?</td>
<td>A support article suddenly sounds like a sales pitch</td>
</tr>
<tr>
<td>Interface fit</td>
<td>Does the translated label work where it appears?</td>
<td>A mobile button wraps into three lines</td>
</tr>
<tr>
<td>Technical integrity</td>
<td>Do links, placeholders and markup still work?</td>
<td>A variable or URL is translated as ordinary prose</td>
</tr>
</tbody></table>
<h3>A small example with a large consequence</h3>
<p>Consider the English source: <strong>“You can cancel at any time. Your access continues until the end of the billing period.”</strong> An acceptable French rendering might be: “Vous pouvez résilier à tout moment. Votre accès reste actif jusqu’à la fin de la période de facturation.”</p>
<p>A shorter version that says access ends immediately would be wrong, however fluent it sounds. The two sentences contain two separate commitments: cancellation is allowed at any time, and access lasts until a specified endpoint. A reviewer should check both.</p>
<p>This is an illustrative editorial example, not a measured comparison of Claude, Gemini or GPT. To compare engines fairly, use the same source, locale, instructions and review criteria, and hide the engine names from the reviewer until scoring is complete.</p>
<h2>Configure Lumo step by step</h2>
<h3>Step 1: prepare a small, representative pilot</h3>
<p>Back up the site and use staging for your first configuration. Install and configure WPML, then upload the Lumo ZIP through <strong>Plugins → Add New Plugin → Upload Plugin</strong>, install it and activate it. The add-on requires the WPML translation-management environment described in its requirements.</p>
<p>Choose one target language and three pieces of content: a short product or service page, a tutorial with formatting, and a shared template if you use Elementor. Include one difficult phrase or brand term on purpose. A pilot that contains only an easy welcome sentence will tell you very little.</p>
<p>Record the source URL, target language and current publication state. Preserve any existing reviewed translation before trying a retranslation operation. Do not make the whole site your first batch.</p>
<h3>Step 2: select the provider and save before testing</h3>
<p>Open <strong>Lumo WP → AI Translator → Settings</strong>. In <strong>AI Provider Configuration</strong>, select the provider, enter its API key and choose an available model. Save the configuration before pressing <strong>Test connection</strong>.</p>
<p>That order is not cosmetic: the reviewed settings interface explicitly states that the connection test uses saved database values. Testing immediately after typing an unsaved key can test the previous configuration instead.</p>
<p>A successful connection test establishes that a request can reach the selected provider with that saved configuration. It does not prove that a translated page is complete, correctly linked in WPML or linguistically ready to publish. Keep the provider key private and set a spending limit or alert in the provider account where available.</p>
<p>For the complete bring-your-own-key workflow, see our <a href="https://lumowp.com/wpml-own-api-key-translation-guide/">personal API key tutorial for WPML</a>.</p>
<h3>Step 3: describe the audience and the rules</h3>
<p>In the Settings screen, find <strong>Custom Instructions</strong>. Start with global rules that apply to all translated material. Specify the audience and terminology, and make clear which elements must survive unchanged. Avoid asking the model to “improve everything”—that can encourage it to rewrite facts or invent supporting claims.</p>
<p>Here is a starting brief to adapt to your own site:</p>
<pre><code>Translate from [SOURCE_LANGUAGE] into [TARGET_LANGUAGE].
Write for the intended audience of the website.
Use clear, natural wording without adding claims or examples.
Preserve the meaning of conditions, exclusions and commitments.
Keep LumoWP and product names unchanged.
Preserve URLs, placeholders, HTML structure and code identifiers.
Keep terminology consistent across the content.
Do not add an introduction, conclusion or translator commentary.
</code></pre>
<p>The placeholders above are supported by the reviewed implementation: <code>replace_instruction_placeholders()</code> substitutes the source and target language names at runtime. This lets one global brief follow the job's language pair instead of accidentally forcing every job into one language. If you require a specific regional variety, make that explicit in your language-specific workflow. Do not put a global instruction such as “always use German” on a site that also translates into Spanish and French.</p>
<p><img src="https://cdn.lumowp.com/2026/10/lumo-ai-guide-v2-voice.webp" alt="Lumo Custom Instructions for preserving brand terms and adapting heading style" /></p>
<p><em>Graphically adapted product-interface excerpts show where global and heading instructions belong. Annotations are editorial guidance.</em></p>
<h3>Step 4: use different instructions for different content</h3>
<p>Use <strong>Title &amp; Heading Instructions</strong> for concise, accurate headings. Use <strong>Body Content Instructions</strong> for prose style. Use <strong>Elementor Template Instructions</strong> for short interface text, and <strong>Categories &amp; Terms Instructions</strong> for consistent taxonomy labels.</p>
<p>For example, a template instruction might say: “Keep button labels concise and action-oriented; preserve the original action and do not add urgency.” A body instruction can ask for straightforward explanations without imposing button-length limits on a tutorial.</p>
<p>The source explains why conflicting instructions are a problem. In <code>includes/class-ai-processor.php</code>, <code>get_custom_instructions()</code> reads the global setting and the applicable content-type setting before returning the combined instructions. Treat them as cooperating rules, not independent prompts that can safely contradict each other.</p>
<blockquote>
<p><strong>Prompt control is not a guarantee</strong></p>
<p>An instruction to preserve a placeholder is useful, but it is not proof that the placeholder survived. Review the resulting content and test the page. The inspected implementation provides a mechanism for guidance; it does not certify linguistic accuracy.</p>
</blockquote>
<h3>Step 5: send a small job and inspect the queue</h3>
<p>Use your WPML translation-management workflow to send the selected content, with Lumo configured as the translation service. The plugin's installation guidance points to <strong>WPML → Translation Management → Translators</strong> to confirm the translator integration; labels can differ across WPML versions.</p>
<p>Open Lumo's <strong>Queue Status</strong> to inspect progress. If jobs do not advance, inspect the job information and <strong>Cron Setup</strong> rather than repeatedly submitting the same page. Check the saved provider configuration, provider limits and background-processing setup before increasing batch size.</p>
<p><img src="https://cdn.lumowp.com/2026/10/lumo-ai-guide-v2-queue.webp" alt="Lumo Queue Status interface and the steps from processing to reviewing a translated page" /></p>
<p><em>Product screenshot with illustrative job counts, adapted into an instructional graphic. These counts are not results of a new benchmark; completed processing still needs review.</em></p>
<p>Chunking and background processing help manage large jobs, but they are not a quality setting. Do not increase concurrency simply because a server has spare memory: provider rate limits and request timeouts may be the actual constraint.</p>
<h3>Step 6: include the Elementor content that owns the text</h3>
<p>The reviewed <strong>Bulk Tools</strong> interface includes <strong>Elementor Templates</strong>. Its template query looks for Elementor data on templates, pages and posts. A header or footer may therefore need attention separately from the page body.</p>
<p><img src="https://cdn.lumowp.com/2026/10/lumo-ai-guide-v2-bulk.webp" alt="Lumo Bulk Tools and the Elementor Templates tab for translating shared website content" /></p>
<p><em>The product's Bulk Tools tab strip identifies distinct content sources. Existing translations may be overwritten: back up first and select the correct source.</em></p>
<p>Before retranslating a page with an untranslated navigation item, identify where that item is stored. A page translation cannot fix the wrong template assignment or a label owned by a different content object. Our <a href="https://lumowp.com/wpml-elementor-translations-not-updating/">WPML and Elementor update diagnosis</a> explains that distinction in more detail.</p>
<h3>Step 7: review the delivered page, not only the job status</h3>
<p>Open the target-language URL as a logged-out visitor. Check the heading, body, navigation, buttons, links and mobile layout. Compare numbers, policies and technical instructions against the source. Then make a small source edit on staging and confirm how your chosen translation workflow handles the update.</p>
<p>Keep a simple review record: source version, target URL, reviewer, issues found and approval date. If you cannot read the target language well enough to detect changed meaning, use a qualified reviewer for important customer-facing content. Back-translation can help flag questions, but it cannot replace that review.</p>
<h2>Compare cost per approved page, not just the cheapest request</h2>
<p>A low API bill can be misleading if the result takes an hour to repair. For a useful pilot, track provider or service usage, review time, corrections and technical failures separately.</p>
<p>Imagine two workflows translating the same ten pages. One has a lower generation cost but repeatedly changes product terminology. The other costs more to generate but needs fewer corrections. Without measuring review time, you cannot say which is cheaper to operate. These are hypothetical outcomes, not results from a Lumo benchmark.</p>
<p>Use this worksheet for your own trial:</p>
<table>
<thead>
<tr>
<th>Record</th>
<th>Why it matters</th>
</tr>
</thead>
<tbody><tr>
<td>Exact content and target locale</td>
<td>Makes the comparison repeatable</td>
</tr>
<tr>
<td>Provider/model or service configuration</td>
<td>Explains which setup produced the output</td>
</tr>
<tr>
<td>Translation charges</td>
<td>Shows direct generation cost</td>
</tr>
<tr>
<td>Review minutes and corrections</td>
<td>Captures the cost hidden behind fluent prose</td>
</tr>
<tr>
<td>Broken links, placeholders or layouts</td>
<td>Separates website failures from language quality</td>
</tr>
<tr>
<td>Result after a source update</td>
<td>Tests maintenance, not just the first translation</td>
</tr>
</tbody></table>
<p>Do not convert the result into “80% human.” A useful conclusion is more specific: which content needed corrections, how long review took and whether the page worked after publication.</p>
<h2>Translate for readers, then verify multilingual SEO</h2>
<p>Google's guidance warns against generating many pages without adding value and emphasizes accuracy, relevance and review. Choosing an AI translation plugin does not provide immunity from those requirements. <a href="https://developers.google.com/search/docs/fundamentals/using-gen-ai-content">Google Search guidance on generative AI content</a>.</p>
<p>Start with languages you can support and content that helps those readers. A translated product page is incomplete if its instructions, availability or support journey do not match what a customer can actually receive.</p>
<p>Technically, use accessible language-specific URLs, make language switching possible and verify the relationship between translated pages. Google recommends distinct URLs and appropriate <code>hreflang</code> annotations; it also warns that automatic language redirection can make versions harder to discover. <a href="https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites">Google's multilingual-site guidance</a>.</p>
<p>Review translated titles and descriptions alongside the visible page. Do not add repetitive keywords in the name of localization. Our <a href="https://lumowp.com/multilingual-seo-crawl-budget-hreflang/">multilingual SEO and crawl-budget guide</a> covers the wider indexing decisions without turning this plugin comparison into another full SEO tutorial.</p>
<h2>Frequently asked questions</h2>
<h3>Which plugin gives the most human translation?</h3>
<p>There is no defensible universal winner without testing the actual language pair, content and workflow. Shortlist by integration needs, then evaluate meaning, terminology and review effort on representative pages. Naturalness is a review criterion, not a guaranteed plugin feature.</p>
<h3>Can I use Lumo without WPML?</h3>
<p>No. The reviewed product is a WPML add-on. It supplies an AI translation workflow on top of the required multilingual foundation rather than replacing it.</p>
<h3>Do I need a separate humanizer after translating?</h3>
<p>Not as a default step. Another rewrite can change terminology, conditions or formatting that the translation already got right. Correct specific problems against the source instead of sending every page through an additional paraphrasing pass.</p>
<h3>Should I translate every page into every language?</h3>
<p>Only when there is a reader need and a practical plan to maintain those versions. Begin with the pages that support a real customer journey. Translation volume alone is not an SEO strategy.</p>
<h3>What would you do first on an existing WPML site?</h3>
<p>Keep the current multilingual structure, back it up and run a one-language pilot. Configure a provider, write a short terminology brief, translate representative content and review the resulting pages. Expand only when both the wording and the website behavior are acceptable. That is a more useful buying test than a polished paragraph on a plugin's sales page.</p>
<p>Originally published on <a href="https://lumowp.com/best-ai-translation-plugins-wordpress/">LumoWP</a>.</p>
]]></content:encoded></item><item><title><![CDATA[WPML Translations Not Updating in Elementor: Find the Cause Before Retranslating]]></title><description><![CDATA[Trace stale Elementor translations through source data, widget fields, templates and caches, with code checks and a careful Lumo Bulk workflow.]]></description><link>https://lumowp.hashnode.dev/wpml-translations-not-updating-in-elementor-find-the-cause-before-retranslating</link><guid isPermaLink="true">https://lumowp.hashnode.dev/wpml-translations-not-updating-in-elementor-find-the-cause-before-retranslating</guid><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Sun, 25 Oct 2026 06:28:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/f2d0db69-83c6-4672-a39b-88ffb77a46bc.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Originally published on <a href="https://lumowp.com/wpml-elementor-translations-not-updating/">LumoWP</a>.</p>
<p>You change a heading in Elementor, finish the translation, and open the French page. The old heading is still there. So you send the page for translation again. Sometimes that helps. Sometimes it changes nothing—and sometimes it replaces a layout someone carefully customized.</p>
<p>Before paying for another translation or clearing every cache on the site, find out <strong>which document and which layer still contain the old text</strong>. A page body, a reusable Elementor template, a dynamic field and a cached HTML response can all produce the same symptom. They need different fixes.</p>
<blockquote>
<p><strong>The short answer</strong></p>
<p>Confirm the source and target page IDs, locate the widget that owns the text, check whether that field reached the translation workflow, and inspect the saved target. Only then decide between updating a translation, correcting a template relationship or clearing cached output.</p>
</blockquote>
<p>This investigation combines official WPML and Elementor documentation with a review of <strong>WPML 4.7.4, Elementor 4.2.0 and Lumo AI Translator 3.20.28</strong> source code. We also ran eight isolated tests against the Lumo extractor and path-writing methods. These are version-specific source findings and controlled data tests, not a claim that we reproduced every production failure or ran a paid AI translation end to end.</p>
<p><img src="https://cdn.lumowp.com/2026/10/wpml-elementor-diagnosis.webp" alt="Five checkpoints for Elementor translations that do not update: source, extraction, target, template and cache" /></p>
<p><em>Follow the update through five layers before repeating the translation.</em></p>
<h2>1. Identify the symptom before changing anything</h2>
<p>Start with one affected URL and one sentence you can recognize. Record the source page ID, target page ID, language, widget type and expected text. If the problem affects a header, record its template ID too. This small record stops a surprisingly common mistake: updating a page while looking at a reusable component supplied by a different document.</p>
<table>
<thead>
<tr>
<th>What you observe</th>
<th>What to inspect first</th>
<th>What to avoid initially</th>
</tr>
</thead>
<tbody><tr>
<td>Target editor and public page both contain old text</td>
<td>Extraction, translation status and the saved target document</td>
<td>Repeated cache purges</td>
</tr>
<tr>
<td>Target editor is correct; public URL is old</td>
<td>Exact URL, template selection and cached output</td>
<td>Deleting the translation</td>
</tr>
<tr>
<td>Body changes, but header or footer does not</td>
<td>The separate Elementor template and its language relationship</td>
<td>Retranslating the page body</td>
</tr>
<tr>
<td>One custom widget never appears in the translation job</td>
<td>Widget registration and supported fields</td>
<td>Replacing the AI provider</td>
</tr>
<tr>
<td>A manually redesigned language page changes back</td>
<td>Which editor or process owns the target layout</td>
<td>Running another source-based job</td>
</tr>
<tr>
<td>Only logged-out visitors see the old content</td>
<td>Page cache, CDN and language-specific cache behavior</td>
<td>Assuming a correct admin preview proves public delivery</td>
</tr>
</tbody></table>
<p><strong>Back up the affected content before a write operation.</strong> For an Elementor page, a plain copy of its visible text is not a complete backup: layout data and related metadata matter. Use your normal staging and backup workflow, and keep the first test limited to one language.</p>
<h2>2. Understand where Elementor actually stores the page</h2>
<p>The important discovery in the source is that checking WordPress <code>post_content</code> alone is insufficient. Elementor's document class defines <code>_elementor_data</code> as its document-data meta key. That JSON contains the element tree, widget settings and nested elements used by the builder.</p>
<p>WPML's Elementor integration also identifies <code>_elementor_data</code> as the relevant field. In <code>class-wpml-elementor-data-settings.php</code>, <code>get_node_id_field()</code> returns <code>id</code>. The integration additionally handles Elementor-specific metadata and invalidates copied CSS state in its own workflow.</p>
<p><img src="https://cdn.lumowp.com/2026/10/wpml-elementor-data-source.webp" alt="WPML Elementor source identifies _elementor_data and the element id field" /></p>
<p><em>Condensed source excerpt from WPML 4.7.4; the surrounding explanation distinguishes page data from template selection.</em></p>
<p>That gives us a useful investigation order: <strong>source document → extracted fields → target document → selected template → rendered response</strong>. A translated paragraph appearing in a database field does not prove that the visible widget is reading it. Likewise, correct body data does not prove that the correct translated header has been selected.</p>
<h3>Optional developer check: confirm the target without modifying it</h3>
<p>The following diagnostic is intended for an administrator with WP-CLI access. Save it as a temporary local PHP file and run it with <code>wp eval-file audit-elementor.php</code> from the intended WordPress installation. Replace <code>123</code> and <code>fr</code>. Do not paste it into a public template or make a public diagnostic endpoint.</p>
<pre><code class="language-php">&lt;?php
if (!defined('WP_CLI') || !WP_CLI) {
    exit;
}
if (!defined('ICL_SITEPRESS_VERSION')) {
    WP_CLI::error('WPML is not active.');
}
$source_id = 123;
$language  = 'fr';
$post_type = get_post_type($source_id);
if (!$post_type) {
    WP_CLI::error('Source post does not exist.');
}
$target_id = apply_filters(
    'wpml_object_id', $source_id, $post_type, false, $language
);
if (!$target_id) {
    WP_CLI::error('No linked translation found.');
}
foreach ([$source_id, (int) $target_id] as $id) {
    $raw = get_post_meta($id, '_elementor_data', true);
    $tree = is_string($raw) ? json_decode($raw, true) : null;
    WP_CLI::log(wp_json_encode([
        'id' =&gt; $id,
        'status' =&gt; get_post_status($id),
        'elementor_data_is_array' =&gt; is_array($tree),
        'top_level_elements' =&gt; is_array($tree) ? count($tree) : null,
        'duplicate_of' =&gt; (int) get_post_meta(
            $id, '_icl_lang_duplicate_of', true
        ),
    ]));
}
</code></pre>
<p>The <code>return_original_if_missing</code> parameter is deliberately <code>false</code>: a missing translation should not silently fall back to the original. See the <a href="https://wpml.org/wpml-hook/wpml_object_id/">official wpml_object_id reference</a> for the argument order. The output checks identity and data presence; it does <strong>not</strong> prove translation quality, nested-field completeness or correct frontend rendering. A duplicate marker is a reason to investigate synchronization, not an invitation to delete metadata manually.</p>
<h2>3. Check whether the missing text reached the translation job</h2>
<p>Open the source page and locate the affected widget. Confirm the change was saved, then inspect the appropriate WPML translation job. Is the changed sentence present there? If it is absent, translating the available strings more accurately will not solve the missing-field problem.</p>
<p>For third-party or custom widgets, field registration matters. WPML documents registration through <code>wpml-config.xml</code> and, where appropriate, the <code>wpml_elementor_widgets_to_translate</code> filter. Repeater fields need their actual structure handled; a widget being visible in Elementor does not mean every setting is automatically translatable. See <a href="https://wpml.org/documentation/plugins-compatibility/elementor/how-to-add-wpml-support-to-custom-elementor-widgets/">WPML's custom Elementor widget integration guide</a>.</p>
<p>Dynamic content needs a separate question: <strong>where does this value originate?</strong> A product field, an ACF field or a linked reusable template may supply the visible text. Translate or configure that source through its supported workflow. Editing the surrounding heading cannot repair an unrelated dynamic value.</p>
<p>If the changed text is present in the job, review and complete that specific translation, then reopen the target page. If delivery remains pending or errors appear, collect the job status, affected IDs and relevant error details. Do not reset all translation jobs merely because one page is stale. Also check the affected version before applying a workaround from an old support thread.</p>
<h2>4. Decide who is allowed to change the translated layout</h2>
<p>Two legitimate workflows are easy to mix up. In one, the translation follows the original page's structure. In the other, someone deliberately maintains a different design for each language.</p>
<p>WPML's <a href="https://wpml.org/documentation/translating-your-contents/using-different-translation-editors-for-different-pages/">different-designs documentation</a> warns that using the Translation Editor or automatic translation can replace a custom target design with the source layout. Choose the workflow deliberately instead of alternating editors whenever the page looks wrong.</p>
<p>For a manually maintained language version, check the per-page editor selection and whether it remains a synchronized duplicate. Our <a href="https://lumowp.com/wpml-different-elementor-designs-per-language/">guide to different Elementor designs per language</a> walks through that setup. An independent translation also needs independent maintenance: an English copy change will not necessarily become a French edit automatically.</p>
<blockquote>
<p><strong>Do not confuse “not updating” with “intentionally independent”</strong></p>
<p>If your team chose a separate French layout, the correct action may be to update that French document manually. Rebuilding it from the English structure is a different operation, with different consequences.</p>
</blockquote>
<h2>5. Treat headers, footers and reusable templates separately</h2>
<p>If the main content translates but a navigation label remains English, stop resubmitting the page. Identify whether the label belongs to a menu, a header template, a saved section or a dynamic source. Then open that actual component.</p>
<p>For Elementor Pro Theme Builder, WPML has a <a href="https://wpml.org/documentation/plugins-compatibility/elementor/creating-different-elementor-templates-per-language-with-wpml/">documented language-template relationship procedure</a>. It sets the display conditions on the original template and connects a secondary-language template without an additional set of conditions. Follow that procedure for the relevant template type; do not assume another theme builder uses the same rules.</p>
<p>After connecting or updating a template, test a real page where it should appear. A correct template preview only proves that the template can render. It does not establish that the public page selected it.</p>
<h2>6. Clear caches only after the stored translation is correct</h2>
<p>Suppose the correct target document contains the new French heading, but visitors still receive the old heading. Now caching is a useful line of investigation. Confirm the exact public URL and language first. Then clear the affected page-cache and CDN entries using the tools provided by your stack, and compare a fresh logged-out request.</p>
<p>For generated Elementor files and data, use Elementor's supported <strong>Clear Files &amp; Data</strong> tool. The menu location varies between releases; the <a href="https://elementor.com/help/regenerate-css-data/">official instructions</a> show the current interface. This does not translate missing strings or repair a wrong language relationship.</p>
<p>There is a useful source detail here: Elementor 4.2.0's <code>core/files/manager.php::clear_cache()</code> removes generated files and metadata including document element-cache data, then fires its clear-cache hook. Its scope is broader than a single CSS file. Whether your page-cache or CDN integration also purges content depends on that integration; do not assume every cache layer was cleared.</p>
<p>If the target's stored JSON still contains the old wording, a cache purge cannot create the missing translation. Return to extraction, job completion or the process writing the target.</p>
<h2>7. What our source tests found in Lumo's Elementor Bulk workflow</h2>
<p>Lumo AI Translator has a dedicated <strong>Bulk Tools → Elementor Templates</strong> section. That is relevant when the stale content belongs to an Elementor document rather than a generic WordPress title. But the implementation deserves a closer look before pressing Translate &amp; Save.</p>
<p>We extracted two method bodies from version 3.20.28 into an isolated PHP fixture, changing only their visibility so the test could call them. No WordPress records were modified and no AI API was called. All eight checks passed their stated expectations—including checks that deliberately demonstrate limitations.</p>
<table>
<thead>
<tr>
<th>Controlled input</th>
<th>Observed behavior</th>
<th>Practical meaning</th>
</tr>
</thead>
<tbody><tr>
<td>A normal settings.title value</td>
<td>Extracted with its indexed path</td>
<td>Standard supported fields can enter the workflow</td>
</tr>
<tr>
<td>A custom settings.promo_copy value</td>
<td>Not extracted</td>
<td>Arbitrary custom settings are not automatically covered</td>
</tr>
<tr>
<td>Common editor field with 499 ASCII bytes</td>
<td>Extracted</td>
<td>Below this branch's length gate</td>
</tr>
<tr>
<td>Same field with 500 ASCII bytes</td>
<td>Not extracted</td>
<td>Retrying the same scan does not remove the gate</td>
</tr>
<tr>
<td>250 two-byte accented letters</td>
<td>Not extracted</td>
<td>strlen measures bytes, not visible characters</td>
</tr>
<tr>
<td>Existing matching target path</td>
<td>Updated</td>
<td>The basic setter works for that fixture</td>
</tr>
<tr>
<td>Missing target path</td>
<td>Setter returns false</td>
<td>Some fields can fail to apply</td>
</tr>
<tr>
<td>Existing path pointing to a different element ID</td>
<td>Updated anyway</td>
<td>A successful write is not an identity check</td>
</tr>
</tbody></table>
<p>These findings apply to the <strong>Bulk Elementor extractor</strong>, not every translation route in the plugin and not WPML's own editor. The source also contains separate handling for certain menu and icon-list structures. The common-field length gate should not be generalized to every branch.</p>
<h3>Why the last test matters</h3>
<p>The extractor records paths such as <code>0.settings.title</code>. The setter follows those array keys using <code>isset</code>; it does not verify the Elementor node's <code>id</code>. If the target layout has been reordered, index zero can now belong to another widget. The path still exists, so the write can succeed while reaching the wrong element.</p>
<p><img src="https://cdn.lumowp.com/2026/10/wpml-elementor-path-source.webp" alt="Source-code diagram showing an indexed translation path reaching a different Elementor widget after reordering" /></p>
<p><em>Two source lines plus an explanatory comment. Our isolated fixture confirms that this setter does not compare element IDs.</em></p>
<p>That is why <strong>translations_applied is a write count, not a translation-quality score</strong>. Compare element identity, position and meaning when source and target layouts differ. For independently redesigned pages, manual editing or an explicitly compatible workflow is safer than assuming indexed paths still match.</p>
<p>The two modes also differ in the reviewed handler. <strong>Re-translate existing template</strong> begins with target Elementor data, but falls back to source data if the target data is empty or invalid. <strong>Create new translation</strong> begins with source data and may reuse an already linked target. Its label does not guarantee a separate new draft. When it creates a target, the reviewed code sets its post status to published.</p>
<p>The creation branch also writes duplicate-related metadata. We did not run a full later-source-save synchronization test for that branch, so we do not claim how every WPML configuration will behave afterward. Check the resulting translation relationship and duplicate state, and perform a controlled later source-save test on staging before adopting it for independently maintained layouts.</p>
<h2>8. Use Bulk Tools for the right job, with a one-language check</h2>
<p>Once you have established that an Elementor template actually needs translation, <a href="https://lumowp.com/product/lumo-wpml-ai-translation-addon-automate-your-multilingual-site-with-openai-claude-mistral-grok/">Lumo AI Translation Addon for WPML</a> provides a dedicated workflow. This is our product, and its Bulk tools are distinct from WPML's own Translation Editor.</p>
<h3>Step 1: verify the source and preserve the target</h3>
<p>Keep a recoverable copy of the affected template and its language version. Confirm which one is the original and whether the target has a custom structure. Do not use a production-wide operation as the first diagnostic test.</p>
<h3>Step 2: open Bulk Tools → Elementor Templates</h3>
<p>Choose the correct <strong>Source Template</strong>. In the reviewed source, the picker considers Elementor library items, pages and posts with <code>_elementor_data</code>, then applies source-language filtering. If a document is missing, investigate its type, language relationship and picker filtering rather than duplicating it to force it into the list.</p>
<h3>Step 3: choose the mode deliberately</h3>
<p>Use <strong>Re-translate existing template</strong> only after identifying the intended linked target and assessing its structure. For <strong>Create new translation</strong>, remember the existing-target and published-status behavior described above. Start on staging and select one target language instead of <strong>All Languages (Auto)</strong>.</p>
<h3>Step 4: scan before translating</h3>
<p>Click <strong>Scan Source Template</strong> and inspect <strong>Found Texts</strong>. Look for the exact stale heading, label or sentence. If it is absent, stop and investigate extraction. Another model or another paid request cannot translate a field that was never included.</p>
<h3>Step 5: translate, save and verify the actual result</h3>
<p>After <strong>Translate &amp; Save</strong>, check the returned target, applied counts and public language URL. Review links as well as labels, especially menu items. Test mobile layout and the relevant header/footer assignment. Then make one controlled source change on staging and check what the next update does to the target.</p>
<p>Provider configuration is a separate prerequisite; our <a href="https://lumowp.com/wpml-own-api-key-translation-guide/">own API key setup guide</a> covers that part. It should not distract from diagnosing an incorrect document, missing field or stale cache.</p>
<p><a href="https://lumowp.com/product/lumo-wpml-ai-translation-addon-automate-your-multilingual-site-with-openai-claude-mistral-grok/"><img src="https://cdn.lumowp.com/2026/10/wpml-elementor-bulk.webp" alt="Lumo AI Translator Bulk Tools interface with callouts identifying the Elementor Templates tab" /></a></p>
<p><em>Annotated product screenshot showing where to open Elementor Templates. The screenshot itself has Selected Posts active; it is navigation guidance, not a completed translation test.</em></p>
<h2>9. A useful handover is evidence, not “we cleared the cache”</h2>
<p>Before closing the issue, keep a short record that another editor can follow:</p>
<ul>
<li>The source and target IDs, language and affected template, if any.</li>
<li>The exact field that was missing or stale and where it is stored.</li>
<li>The workflow allowed to maintain the target layout.</li>
<li>The operation that corrected the problem, with a recoverable before-state.</li>
<li>The verified public language URL, including a logged-out check.</li>
<li>A result for one later source update, if synchronization is part of the workflow.</li>
</ul>
<p>The next time a translated heading stays old, you should be able to say where the update stopped. That is a much better maintenance strategy than translating the whole page again and hoping the right layer changes.</p>
<h2>Source notes and scope</h2>
<p>The local code review covered WPML's <code>class-wpml-elementor-data-settings.php</code>, Elementor's <code>core/base/document.php</code> and <code>core/files/manager.php</code>, and Lumo's <code>includes/admin-tab-bulk-tools.php</code>, <code>extract_elementor_texts()</code>, <code>ajax_translate_elementor_template()</code> and <code>set_nested_value()</code>. The test fixture exercised extraction and nested-array writes only. The product image is an annotated version of the published product screenshot, not evidence of a fresh successful translation job.</p>
<p>Menu labels, limits and implementation details can change between versions. Compare your installed release with the versions stated above. The official documentation linked beside each procedure is the reference for its supported workflow; the source observations explain the behavior of the specific copies we examined.</p>
]]></content:encoded></item><item><title><![CDATA[How to Send WordPress Emails with Gmail: Lumo Mail SMTP Setup]]></title><description><![CDATA[Configure Gmail OAuth or App Passwords in Lumo Mail SMTP, with real plugin screenshots, sender checks and troubleshooting.]]></description><link>https://lumowp.hashnode.dev/how-to-send-wordpress-emails-with-gmail-lumo-mail-smtp-setup</link><guid isPermaLink="true">https://lumowp.hashnode.dev/how-to-send-wordpress-emails-with-gmail-lumo-mail-smtp-setup</guid><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Sat, 24 Oct 2026 19:24:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/ca6d8537-955d-4fbc-bd86-315552074540.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You want WordPress to send a password reset, a contact-form notification or an order email through a Gmail account. The confusing part is that “connect Gmail” can describe two different setups: an App Password used over SMTP, or a Google OAuth connection used with the Gmail API.</p>
<p>Lumo Mail SMTP supports both. This guide takes you from choosing the right provider card to checking a real message in the recipient mailbox. It also explains two easily missed details: a connection test is not always an authentication test, and a Google app left in Testing can lose its refresh token after seven days.</p>
<p><strong>Scope of this walkthrough</strong></p>
<p>The field names and sending behavior below were checked against Lumo Mail SMTP 2.17.3 source code and Google’s official documentation. The numbered panels below are graphically annotated captures of the real plugin interface in our permanent tutorial lab, with demonstration values. The cover and workflow overview are conceptual illustrations. We did not connect a live mailbox or claim an inbox-delivery test. Lumo Mail SMTP is our product.</p>
<h2>Start here: choose one Gmail connection method</h2>
<table>
<thead>
<tr>
<th>Method in Lumo</th>
<th>What you need</th>
<th>How mail is sent</th>
</tr>
</thead>
<tbody><tr>
<td>Gmail / Google (OAuth)</td>
<td>Google Cloud OAuth client, exact redirect URI and account permission</td>
<td>Gmail API over HTTPS</td>
</tr>
<tr>
<td>Gmail / Google Workspace</td>
<td>Eligible Google account, 2-Step Verification and an App Password</td>
<td>Authenticated SMTP: smtp.gmail.com, port 465, encrypted transport</td>
</tr>
</tbody></table>
<p>Google generally recommends a Google sign-in connection instead of App Passwords. However, OAuth is not automatically a least-privilege setup: the reviewed Lumo release requests a broad Gmail scope. Read the permission note below before choosing that route. If an organization manages the mailbox, ask its administrator which connection method is permitted.</p>
<p>Do not configure both routes at once just to make the test turn green. Start with one primary provider and keep the initial test easy to interpret. A later backup or queue is a separate configuration decision.</p>
<h2>Before you start</h2>
<ul>
<li><p>Use a WordPress administrator account and an HTTPS website for a production connection.</p>
</li>
<li><p>Choose a dedicated sending mailbox you control. Do not start with an employee’s personal inbox if the website must keep working after that person leaves.</p>
</li>
<li><p>Have access to your Lumo installation ZIP and the license required by your edition.</p>
</li>
<li><p>Keep one mail-routing plugin active. Back up the old configuration before changing an existing SMTP setup.</p>
</li>
<li><p>Prepare a recipient mailbox you control for testing. Never put real passwords or tokens in screenshots or support messages.</p>
</li>
</ul>
<p>Gmail is a reasonable option to evaluate for modest transactional traffic, but it is not an unlimited newsletter service. Google’s <a href="https://support.google.com/mail/answer/22839?hl=en">personal Gmail limits</a> describe restrictions around daily messages and recipients; work and school accounts have different limits. Plan around your actual order volume, resets and notifications rather than treating a published maximum as guaranteed capacity.</p>
<h2>1. Install Lumo Mail SMTP and open Providers</h2>
<p>Download the plugin ZIP from your Lumo account. In WordPress, go to <strong>Plugins → Add Plugin → Upload Plugin</strong>, choose the ZIP, install it and activate it. Complete the license step if your edition requires one. Then open <strong>Lumo WP → Mail SMTP → Providers</strong>.</p>
<p>If you have not chosen a mail plugin yet, the <a href="https://lumowp.com/product/lumo-mail-smtp-wordpress-smtp-email-log-plugin/">Lumo Mail SMTP product page</a> lists current editions and included features. The important choice for this tutorial is the provider card: <strong>Gmail / Google (OAuth)</strong> and <strong>Gmail / Google Workspace</strong> are different paths.</p>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-real-01-providers.webp?v=20261024" alt="Lumo Mail SMTP provider screen with Gmail App Password and Google OAuth cards highlighted" /></p>
<p>Real plugin panel, annotated for clarity. Choose the card matching your connection method.</p>
<h2>2. Connect Gmail with OAuth</h2>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-oauth-lumo-steps.webp" alt="Google Cloud, Lumo Mail SMTP and email testing form the three stages of Gmail OAuth setup" /></p>
<p>Workflow illustration. Use the current Google Console and the values displayed by your own WordPress installation.</p>
<h3>Step 2.1 — Create or select the Google Cloud project</h3>
<p>Open <a href="https://console.cloud.google.com/">Google Cloud Console</a> while signed in to the account that will manage the integration. Create a project for the website, or select an appropriate existing project. Give it a recognizable name so you can distinguish it from unrelated integrations later.</p>
<p>In <strong>APIs &amp; Services → Library</strong>, find <strong>Gmail API</strong> and enable it for that project. Enabling an API makes it available to the project; it does not yet grant access to your mailbox. Google’s <a href="https://developers.google.com/workspace/guides/get-started">Workspace development overview</a> separates project creation, API enablement, consent and credentials.</p>
<h3>Step 2.2 — Configure the consent information</h3>
<p>Open <strong>Google Auth platform</strong>. If this is a new project, complete the initial setup. Use <strong>Branding</strong> for the app name and support/contact details, <strong>Audience</strong> for who may use it, and <strong>Data Access</strong> to review the scopes. Older Console layouts may group these controls under <strong>OAuth consent screen</strong>.</p>
<p>Use a name that you will recognize on the Google consent screen, such as your website’s mail integration. Choose Internal only when your Workspace organization and intended users qualify. For an External app in Testing, add the intended sending account as a test user. Being the website administrator does not automatically put your Google account on that list.</p>
<p><strong>Read the requested access</strong></p>
<p>In Lumo 2.17.3, the Google scope is <code>https://mail.google.com/</code>. Google classifies this as restricted and describes access beyond sending, including reading and deleting mail. It is not a send-only permission. Review the consent screen and use an account appropriate for that access. Google recommends narrower scopes where possible; changing the plugin to use them needs a compatibility review, not just editing the Console form.</p>
<p>Consult Google’s <a href="https://developers.google.com/workspace/gmail/api/auth/scopes">Gmail scope reference</a> for the permission categories. If the access is unsuitable for your organization, stop before authorizing it and use an approved integration. Publishing the Google app does not automatically satisfy Google verification requirements or remove an administrator’s restrictions.</p>
<h3>Step 2.3 — Copy the redirect URI from Lumo</h3>
<p>Back in <strong>Lumo WP → Mail SMTP → Providers</strong>, select <strong>Gmail / Google (OAuth)</strong>. Locate the read-only <strong>Authorized Redirect URI</strong> field and copy it exactly. Do not substitute your home page or the URL of this tutorial.</p>
<p>The reviewed plugin builds this address with WordPress’s admin URL. A typical installation produces a URL with this shape:</p>
<p><code>https://your-site.example/wp-admin/admin.php?page=lumo-mail-smtp&amp;action=oauth_callback</code></p>
<p>This is an illustration, not a value to paste unchanged. Your site might use a different domain, a subdirectory or another admin URL. HTTPS, hostname, path and query string must match the value Lumo uses. Copying the displayed field is safer than typing it.</p>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-real-02-oauth.webp?v=20261024" alt="Actual Gmail OAuth fields in Lumo Mail SMTP: Client ID, Client Secret and Authorized Redirect URI" /></p>
<p>Real local-lab interface with dummy credentials. Copy the redirect URI from YOUR website; do not copy the localhost example shown here.</p>
<h3>Step 2.4 — Create a web OAuth client</h3>
<p>In Google Cloud, open <strong>Google Auth platform → Clients → Create client</strong>. Choose <strong>Web application</strong>. Add the copied Lumo URL under <strong>Authorized redirect URIs</strong> and create the client. Do not use a Desktop app client or paste the callback into Authorized JavaScript origins; this plugin uses a server-side callback.</p>
<p>Copy the resulting <strong>Client ID</strong> and <strong>Client Secret</strong> into the matching Lumo fields. Store the secret securely. A Google API key is not a substitute for either field. Google’s <a href="https://developers.google.com/workspace/guides/create-credentials">credential setup guide</a> explains the client types, while the <a href="https://developers.google.com/workspace/gmail/api/auth/web-server">Gmail server-side authorization guide</a> explains the token exchange.</p>
<h3>Step 2.5 — Save, connect and confirm the account</h3>
<p>Save the provider settings, then use the Google connection button in the OAuth section. The reviewed interface saves those credentials before opening Google’s authorization page. Sign in to the mailbox you actually want WordPress to use, inspect the app name and permissions, and authorize only if they are expected.</p>
<p>If Google blocks the application or your administrator denies access, resolve that configuration or policy issue. Do not disable account protection to complete a tutorial. After returning to WordPress, check the connected-account identity and make sure <strong>Gmail / Google (OAuth)</strong> is the selected primary provider.</p>
<h3>Step 2.6 — Avoid the seven-day Testing trap</h3>
<p>Google documents that refresh tokens for External apps in Testing generally expire after seven days, with an exception for a small set of basic identity scopes. The broad Gmail scope requested here is outside that exception. That can explain a connection that works initially and then needs authorization again.</p>
<p>Before relying on the connection for production, review the app’s publishing status and applicable verification requirements. Reconnect after the appropriate configuration change if required. Do not promise permanent access: token revocation and account or organization policies can still invalidate it. See Google’s <a href="https://developers.google.com/identity/protocols/oauth2">OAuth token-expiration documentation</a>.</p>
<h2>3. Alternative: connect Gmail with an App Password</h2>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-real-03-app-password.webp?v=20261024" alt="Gmail Address and masked App Password fields in the actual Lumo Mail SMTP interface" /></p>
<p>Real plugin interface with demonstration values. Use your own eligible Gmail or Workspace account and its generated App Password.</p>
<p>Use this route only when your account offers App Passwords and the organization permits them. Google prefers Google sign-in where supported. An App Password is a separate credential for the application; it is not your normal Google password.</p>
<h3>Step 3.1 — Create the App Password in your own account</h3>
<p>Enable <strong>2-Step Verification</strong> in your Google Account if it is not already enabled. Then open <a href="https://myaccount.google.com/apppasswords">App passwords</a>, sign in when asked, give the credential a descriptive name and create it. Copy the generated value into your password manager and the plugin’s password field, not into a public document.</p>
<p>If the option is missing, account policies, Advanced Protection or a security-key-only setup can be relevant. Ask your Workspace administrator rather than switching off protections. Google also revokes App Passwords when the account password changes. Its <a href="https://support.google.com/accounts/answer/185833?hl=en">App Password help page</a> covers availability and revocation.</p>
<h3>Step 3.2 — Enter the two Gmail fields in Lumo</h3>
<p>Open <strong>Lumo WP → Mail SMTP → Providers</strong> and choose <strong>Gmail / Google Workspace</strong>. Fill <strong>Gmail Address</strong> with the full address that owns the App Password. Put the generated credential in <strong>App Password</strong>, then save.</p>
<p>This specific provider supplies the SMTP host and transport settings itself. In the reviewed source they are <strong>smtp.gmail.com</strong>, <strong>port 465</strong>, encrypted SSL/TLS transport and SMTP authentication. You do not need to invent a host or port for this card. The generic SMTP provider is a different configuration screen.</p>
<p><strong>The connection check has a limit</strong></p>
<p>The reviewed Gmail App Password connection test opens a socket to Gmail’s SMTP endpoint after checking that required fields are present. It does not authenticate by sending a message. Even an incorrect App Password can coexist with a successful reachability test. Always continue to Send Test.</p>
<h2>4. Set the sender and Reply-To correctly</h2>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-real-04-sender.webp?v=20261024" alt="Lumo Mail SMTP General settings showing From Name, From Email and sender override switches" /></p>
<p>Real General settings panel; Northstar Studio and <a href="mailto:sender@example.com">sender@example.com</a> are examples. The switches shown are the captured lab state, not a universal preset.</p>
<p>Open <strong>General</strong> and use the connected mailbox as your initial <strong>From Email</strong>. Set a recognizable <strong>From Name</strong>, such as the site name. If you force the sender across WordPress, check that it does not conflict with another intentional sending identity.</p>
<p>The App Password provider aligns the From address to the configured Gmail mailbox. The OAuth sender checks the account’s send-as addresses and can retain an allowed alias; otherwise it falls back to the connected mailbox. Typing an arbitrary company address into WordPress does not authorize Gmail to send as that address.</p>
<p>For a contact form, put the visitor’s address in <strong>Reply-To</strong> and keep your authorized mailbox in From. You can then reply to the visitor without pretending that their address is the sender. Test this explicitly by receiving the form notification and checking where Reply would go.</p>
<h2>5. Send a real test and inspect the evidence</h2>
<p><img src="https://cdn.lumowp.com/2026/10/gmail-real-05-test.webp?v=20261024" alt="Actual Test Email screen in Lumo Mail SMTP with Send To field and Send Test Email button" /></p>
<p>Real test-email form with an example recipient. No message was sent from the lab; follow the checks below on your configured site.</p>
<ul>
<li><p>Open <strong>Lumo WP → Mail SMTP → Send Test</strong> using the header button or Test Email section.</p>
</li>
<li><p>Enter a recipient mailbox you control in Send To, then click Send Test Email. The plugin supplies the test-message content.</p>
</li>
<li><p>Check the plugin result and the corresponding entry in <strong>Email Logs</strong>.</p>
</li>
<li><p>Open the recipient mailbox, including spam. Confirm the message, sender and Reply-To.</p>
</li>
<li><p>Trigger the actual site workflow: a test form, a password reset for your test account, or an email from a test order.</p>
</li>
</ul>
<p>For OAuth, the provider’s connection test retrieves a Gmail profile using a valid access token. That is a stronger account check than opening an SMTP socket, but it still does not prove delivery of a WordPress notification. Both routes need the final message test.</p>
<p>Keep queuing off while establishing your baseline unless the site already depends on it. If an email is queued, inspect the worker and cron behavior before concluding that Gmail rejected it. Our <a href="https://lumowp.com/wordpress-email-smtp-setup-guide/">WordPress SMTP setup and troubleshooting guide</a> explains the difference between queued, accepted, delivered and inbox placement.</p>
<h2>6. Fix common Gmail connection problems</h2>
<p><strong>redirect_uri_mismatch</strong></p>
<p>Copy Authorized Redirect URI from this installation again. Compare protocol, domain, path and the complete query string with the Google client.</p>
<p><strong>Access denied during Google authorization</strong></p>
<p>Check the selected Google account, test-user list, audience and Workspace policy.</p>
<p><strong>App is unverified or blocked</strong></p>
<p>Review the project, requested scopes and verification requirements. Do not assume every warning is safe to bypass.</p>
<p><strong>Connection stops after about seven days</strong></p>
<p>Check External + Testing status and token expiry before reinstalling the plugin.</p>
<p><strong>App Password authentication fails</strong></p>
<p>Use the generated App Password for the same Gmail Address, not the normal account password. Check whether it was revoked.</p>
<p><strong>SMTP connection timeout</strong></p>
<p>Ask the host whether outbound smtp.gmail.com:465 is reachable. A correct password cannot fix a blocked network route.</p>
<p><strong>TLS certificate error</strong></p>
<p>Resolve certificate trust or hostname problems with the host. Do not disable certificate verification.</p>
<p><strong>Test reaches the mailbox but forms do not</strong></p>
<p>Inspect the form’s recipient and notification trigger. Confirm it uses the WordPress mail path.</p>
<p><strong>Email is sent from an unexpected address</strong></p>
<p>Check the connected mailbox, forced From setting and whether the OAuth send-as alias is actually allowed.</p>
<p><strong>Rate-limit or quota error</strong></p>
<p>Inspect the account’s current limits and reduce or pause the workload. A queue or API connection does not remove Gmail’s sending limits.</p>
<h2>7. Know when Gmail is no longer the right fit</h2>
<p>A small site sending occasional contact notifications has a different requirement from a busy store sending orders, refunds, resets and reminders throughout the day. Count those events before committing your entire mail workflow to a mailbox account.</p>
<p>Consider a dedicated transactional email service when you need higher sustained volume, clearer bounce and suppression handling, operational monitoring or separation from a person’s mailbox. Changing from App Password to OAuth solves an authentication choice; it does not turn Gmail into unlimited delivery infrastructure.</p>
<h2>A final checklist before you leave the settings page</h2>
<ul>
<li><p>The selected provider matches the method you configured.</p>
</li>
<li><p>The authorized mailbox is the intended sender, and Reply-To behaves correctly.</p>
</li>
<li><p>A real test email arrived; a connection badge was not the only evidence.</p>
</li>
<li><p>The site’s actual notification workflow was tested with controlled data.</p>
</li>
<li><p>OAuth audience, publishing status and requested permissions were reviewed, or App Password availability and ownership were confirmed.</p>
</li>
<li><p>Someone knows how to reconnect the account or replace a revoked credential.</p>
</li>
<li><p>No secret or reset link appears in public screenshots, and log retention is intentional.</p>
</li>
</ul>
<h2>Sources and version notes</h2>
<p>Reviewed October 24, 2026. Lumo source files inspected: <code>GmailProvider.php</code>, <code>GmailOAuthProvider.php</code>, <code>GmailApiClient.php</code>, <code>OAuth.php</code>, <code>PhpMailerSender.php</code> and the Providers admin view. Google documentation is linked beside the relevant instructions. Console labels and account policies can change; use the exact redirect URI and permission screen shown for your installation.</p>
<p>Originally published on <a href="https://lumowp.com/send-wordpress-emails-gmail-lumo-smtp/">LumoWP</a>.</p>
]]></content:encoded></item><item><title><![CDATA[WordPress Emails Not Sending? WP Mail SMTP Pro vs Lumo Mail SMTP]]></title><description><![CDATA[Configure WordPress email, diagnose missing messages, and understand logs, queues and backup connections with WP Mail SMTP Pro and Lumo Mail SMTP.]]></description><link>https://lumowp.hashnode.dev/wordpress-emails-not-sending-wp-mail-smtp-pro-vs-lumo-mail-smtp</link><guid isPermaLink="true">https://lumowp.hashnode.dev/wordpress-emails-not-sending-wp-mail-smtp-pro-vs-lumo-mail-smtp</guid><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Sat, 24 Oct 2026 18:28:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/93f4b124-d371-4162-bb16-ac8cc5826e85.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A customer places an order. WooCommerce records it, the payment succeeds, and the confirmation email never appears. Installing an SMTP plugin can help—but only if the failure is in the part of the journey that the plugin controls.</p>
<p>This guide walks through that journey, then shows how to configure <strong>WP Mail SMTP Pro</strong> and <strong>Lumo Mail SMTP</strong>. The useful comparison is not which plugin has the longest feature list. It is whether you can identify what happened to a message, configure the right sender, and recover from a failure without creating another one.</p>
<p><strong>What this guide is based on</strong></p>
<p>We reviewed Lumo Mail SMTP 2.17.3 source code, relevant WP Mail SMTP Pro 4.9.0 logging code, and official WordPress, WP Mail SMTP and Google documentation. This is a configuration and code-review guide, not an inbox-placement benchmark. Lumo Mail SMTP is our product; this is not an independent review. Features and plan entitlements can change.</p>
<h2>1. Find the broken step before changing the plugin</h2>
<p>There are four different questions hiding inside “WordPress email is not working”: Did the application create the message? Did the sending service accept it? Did the recipient server accept it? Did it reach the inbox rather than spam? A green status at one step cannot answer all four.</p>
<p><img src="https://cdn.lumowp.com/2026/10/email-delivery-stages.webp" alt="Four stages of WordPress email delivery, from message creation to inbox or spam placement" />Conceptual diagram: transport acceptance, recipient delivery and inbox placement are separate events.</p>
<p>WordPress explicitly warns that a successful <a href="https://developer.wordpress.org/reference/functions/wp_mail/">wp_mail() return value</a> does not prove that the recipient received the email. In Lumo’s queued send path, a successful return can mean the message was added to the queue. It has not necessarily contacted an SMTP server yet.</p>
<table>
<thead>
<tr>
<th>Status or observation</th>
<th>What it tells you</th>
<th>What to check next</th>
</tr>
</thead>
<tbody><tr>
<td>No expected message in the log</td>
<td>The event may not have generated mail, logging may be disabled, or another route may bypass this plugin.</td>
<td>Check the form, order status, notification setting and actual sending method.</td>
</tr>
<tr>
<td>Queued / pending</td>
<td>Work has been scheduled, not completed.</td>
<td>Inspect queue processing and WordPress cron.</td>
</tr>
<tr>
<td>Sent / accepted</td>
<td>The configured transport reported success.</td>
<td>Inspect the provider’s delivery events and recipient mailbox.</td>
</tr>
<tr>
<td>Delivered, when supported</td>
<td>The provider has reported delivery to a recipient server.</td>
<td>Check inbox versus spam; delivery is not a placement guarantee.</td>
</tr>
<tr>
<td>Opened</td>
<td>A tracking mechanism recorded activity.</td>
<td>Do not treat it as proof that a person read the message.</td>
</tr>
</tbody></table>
<p>For a missing WooCommerce confirmation, first check that the relevant email is enabled and that the order reached the status that triggers it. An SMTP connection cannot repair a notification that was never generated. Also check whether the affected extension uses wp_mail(), its own API, or a separate service.</p>
<h2>2. Choose the sender and service first</h2>
<p>The plugin connects WordPress to a mail service. The service supplies the SMTP endpoint or API, sending limits and delivery infrastructure. Decide which service will handle transactional mail before choosing connection settings. A plugin purchase does not automatically include an unlimited email-sending account.</p>
<ul>
<li><p>Use an address on a domain you control, such as <a href="mailto:notifications@your-domain.example">notifications@your-domain.example</a>. Verify that identity with your provider.</p>
</li>
<li><p>For a contact form, keep the verified site address in <strong>From</strong> and put the visitor’s address in <strong>Reply-To</strong>. Pretending to send from the visitor’s Gmail address creates an authentication problem.</p>
</li>
<li><p>Choose a supported API or OAuth connection when appropriate. For conventional SMTP, obtain the exact host, port, encryption mode and credentials from the provider.</p>
</li>
<li><p>Activate only one plugin responsible for routing normal WordPress mail. Two SMTP plugins can compete over the same hooks and make the result harder to explain.</p>
</li>
</ul>
<h3>Authenticate the domain, not just the mailbox</h3>
<p>SPF authorizes sending infrastructure, DKIM provides a signature, and DMARC connects authentication to the visible From domain through alignment. Follow your provider’s exact DNS instructions; do not paste a generic SPF record over existing records used by other services.</p>
<p>Google’s <a href="https://support.google.com/mail/answer/81126?hl=en">email sender guidelines</a> distinguish requirements for all senders from stricter bulk-sender requirements. For a production domain, configure SPF, DKIM and DMARC correctly even when your volume is small. Introduce an enforcement policy only after checking legitimate sending sources and alignment. Authentication helps establish identity; it does not guarantee inbox placement.</p>
<h2>3. WP Mail SMTP Pro vs Lumo Mail SMTP: what to compare</h2>
<table>
<thead>
<tr>
<th>Requirement</th>
<th>WP Mail SMTP Pro</th>
<th>Lumo Mail SMTP</th>
</tr>
</thead>
<tbody><tr>
<td>Basic connection</td>
<td>Provider-specific mailers and an Other SMTP setup documented by the vendor.</td>
<td>SMTP plus provider integrations; the reviewed registry includes Gmail, Outlook, Brevo, SendGrid, Mailgun, Postmark and Amazon SES.</td>
</tr>
<tr>
<td>Mail visibility</td>
<td>Pro email logs; delivery verification depends on the mailer and supported provider integration.</td>
<td>Email logs, test interface and reporting; do not interpret a basic sent status as confirmed inbox delivery.</td>
</tr>
<tr>
<td>Recovery</td>
<td>Additional connections can supply a configured backup connection, subject to license availability.</td>
<td>The reviewed send path tries a configured backup after a primary send failure.</td>
</tr>
<tr>
<td>Routing and volume</td>
<td>Smart Routing and other advanced features depend on the current offering.</td>
<td>Connections, conditional routing and queue tools are available in the product; check your plan.</td>
</tr>
<tr>
<td>Migration</td>
<td>Confirm the vendor’s supported migration options for your starting plugin.</td>
<td>A WP Mail SMTP importer maps supported saved settings, with limits discussed below.</td>
</tr>
</tbody></table>
<p>WP Mail SMTP Pro is a sensible candidate when its supported mailer, documentation and licensing fit your existing stack. <a href="https://lumowp.com/product/lumo-mail-smtp-wordpress-smtp-email-log-plugin/">Lumo Mail SMTP</a> is worth evaluating when you want mail administration alongside the other Lumo tools, particularly logs and connection workflows. Compare the features included in the plan you would actually use—not every feature mentioned somewhere on a product page.</p>
<h2>4. Configure WP Mail SMTP Pro step by step</h2>
<h3>Install and select a connection</h3>
<p>Download the plugin from your WP Mail SMTP account. In WordPress, open <strong>Plugins → Add Plugin → Upload Plugin</strong>, select the ZIP, install and activate it. Follow the vendor’s upgrade instructions if Lite is already installed. Take a settings backup first and avoid leaving a competing SMTP plugin active.</p>
<p>Run the setup wizard, or open <strong>WP Mail SMTP → Settings → General</strong>. Under the primary connection, set the From Email and From Name, then select the mailer. With a provider integration, follow that mailer’s authorization steps. Use <strong>Other SMTP</strong> when your provider has supplied SMTP credentials.</p>
<h3>Enter SMTP settings deliberately</h3>
<p>Use the provider’s SMTP host, not automatically your website hostname. Port 587 with TLS and port 465 with implicit TLS/SSL are common combinations, but the provider’s instructions decide which is correct. Enable authentication when required and enter the supplied SMTP username and password. Some services issue a dedicated SMTP credential rather than accepting your normal account password.</p>
<p>Force From Email can make the sender consistent across plugins. Before enabling it, check whether any existing workflow intentionally uses a different verified identity. For contact forms, preserve a useful Reply-To address so that replying still reaches the visitor. Save the settings. See the vendor’s <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-other-smtp-mailer-in-wp-mail-smtp/">Other SMTP instructions</a> for the current field layout.</p>
<h3>Test both the connection and a real workflow</h3>
<p>Open <strong>WP Mail SMTP → Tools → Email Test</strong>. Send a test to a mailbox you control. Read the result, then check the actual inbox and spam folder. If you use additional connections, select and test each intended connection separately.</p>
<p>Next, trigger the workflow that originally failed: submit a test form, request a password reset for a dedicated test user, or send an email from a test order. Use test data and avoid charging a real customer. A successful diagnostic message does not prove that a form’s recipient setting or a WooCommerce notification is correct.</p>
<p>If your license includes email logging, enable the appropriate log settings and choose a retention period. Keep full message content only when you need it. Logs can contain personal information, reset links or other content that should not remain in the database indefinitely.</p>
<h3>Add a backup after the primary route works</h3>
<p>Configure an additional connection first, then select it as the backup in General settings. The official <a href="https://wpmailsmtp.com/docs/configuring-backup-connection/">backup connection guide</a> explains this sequence. Test the backup independently before relying on it. A second connection to the same failing infrastructure may provide little resilience.</p>
<h2>5. Configure Lumo Mail SMTP step by step</h2>
<p>Download your installation ZIP from your Lumo account, then use <strong>Plugins → Add Plugin → Upload Plugin</strong>. After installation and activation, open <strong>Lumo WP → Mail SMTP</strong>. Complete any license activation required by your edition. The following labels come from the reviewed 2.17.3 admin view.</p>
<h3>General: establish the sender identity</h3>
<p>In <strong>General</strong>, enter the From Name and From Email that belong to your verified sending domain. Decide whether to force them across wp_mail() messages. In the source, these overrides are conditional: merely filling in a sender does not mean every plugin’s identity will be replaced unless the corresponding force option is enabled.</p>
<h3>Providers: configure one primary route</h3>
<p>Open <strong>Providers</strong> and configure your chosen provider. For SMTP, enter the host, port, encryption, authentication setting, username and password. Match the provider’s requirements rather than experimenting with random ports. Save the connection and select the intended primary provider in the relevant general settings.</p>
<p>If you choose a Google or Microsoft OAuth integration, complete that connection’s authorization flow rather than assuming a normal mailbox password will work. Do not copy OAuth instructions from an unrelated provider or reuse production credentials in screenshots.</p>
<p><strong>A configured badge is not a delivery test</strong></p>
<p>In the reviewed admin code, the configured indicator is based on the selected provider rather than proof of inbox receipt. Treat it as a configuration status. Continue to the test and recipient checks before calling the setup complete.</p>
<h3>Send Test, then inspect Email Logs</h3>
<p>Use <strong>Send Test</strong> in the plugin header, or open the <strong>Test Email</strong> section. Send to a mailbox you control. Then open <strong>Email Logs</strong> and inspect the matching entry. Record the recipient, time, selected connection, status and any error. Compare that evidence with the provider’s dashboard and the actual mailbox.</p>
<p>The SMTP provider also has a connection-probe path in the code. A connection check can establish that the server is reachable and authentication works, but it is not equivalent to sending the application’s full message to a recipient. Use both kinds of evidence where available.</p>
<h3>Logging and Email Control: keep them intentional</h3>
<p>In <strong>Logging</strong>, choose retention and decide whether message content and tracking are necessary. Open and click tracking adds a separate measurement layer; privacy software, proxies and automated scanners can affect those signals. For diagnosing basic delivery, status, error and provider-event information are more useful than an open-rate percentage.</p>
<p>Review <strong>Email Control</strong> before disabling any WordPress notifications. Reducing unwanted administrative messages can be useful, but do not accidentally suppress password resets or the very notification you are troubleshooting. Change one category at a time and test its expected behavior.</p>
<h2>6. Three source-code details that affect production behavior</h2>
<h3>A fallback cannot recover every missing email</h3>
<p>Lumo’s reviewed Mailer send path invokes the backup when the primary send operation fails. It cannot infer that a successfully accepted message will later bounce or land in spam. “Primary accepted, recipient never saw it” therefore requires provider-event investigation, not an assumption that the fallback should have run.</p>
<p>The global fallback branch also excludes a backup whose provider identifier is the same as the primary provider identifier. Do not assume that adding a second account of the same provider automatically creates that global failover route. Confirm the exact connection behavior in the installed version.</p>
<h3>Routing rules can be narrower than they look</h3>
<p>In the reviewed routed-send path, populated sender, recipient and subject conditions are combined: all specified conditions must match. Sender and recipient rules support wildcard matching; subject matching uses a case-insensitive substring. The first matching enabled connection is selected. A rule without a concrete condition is not treated as a match by that path.</p>
<p>For example, a recipient pattern for *@example.test plus the subject condition “invoice” should not match every invoice sent anywhere. It should match an invoice addressed to that domain. Test one message that should match, one with the wrong recipient and one with the wrong subject. This catches a routing mistake that an ordinary SMTP test cannot reveal.</p>
<h3>A queue changes when mail is sent</h3>
<p>Lumo schedules its queue worker through WordPress cron. In the reviewed send path, a queued message can return success while it is still pending. That matters for password resets and time-sensitive codes: the application may say the message was sent while the worker has not processed it yet.</p>
<p>Start with a working immediate-send configuration. If you need queuing, verify how cron is triggered on your hosting, inspect pending messages and measure the delay with controlled tests. A one-minute scheduled interval is not a promise that every message will leave within one minute. Traffic, cron triggering, server load and retries all affect processing.</p>
<p><strong>Successful sending is not a security audit</strong></p>
<p>Do not disable TLS certificate verification as a production fix. Resolve the hostname, certificate chain or hosting configuration with your provider. Review the security behavior of your installed release before deployment; this source review is not a complete security audit of either product.</p>
<h2>7. Troubleshoot by symptom</h2>
<table>
<thead>
<tr>
<th>Symptom</th>
<th>Useful next check</th>
<th>Avoid</th>
</tr>
</thead>
<tbody><tr>
<td>Authentication failed</td>
<td>Verify the SMTP credential type, username and provider permissions.</td>
<td>Repeatedly changing unrelated WordPress settings.</td>
</tr>
<tr>
<td>Connection timed out</td>
<td>Check the provider endpoint and whether the host permits outbound traffic on that port.</td>
<td>Assuming a different SMTP plugin can bypass a network block.</td>
</tr>
<tr>
<td>TLS or certificate error</td>
<td>Check the hostname, certificate chain and server trust store with the host/provider.</td>
<td>Disabling certificate validation to make the error disappear.</td>
</tr>
<tr>
<td>Test works; form does not</td>
<td>Check the form recipient, trigger, From and Reply-To settings.</td>
<td>Treating one test message as a complete application test.</td>
</tr>
<tr>
<td>Accepted but not in inbox</td>
<td>Inspect bounce/suppression events, authentication results and spam.</td>
<td>Calling a sent log entry proof of inbox delivery.</td>
</tr>
<tr>
<td>Messages remain queued</td>
<td>Check cron execution, worker errors and provider limits.</td>
<td>Increasing retries without understanding the failure.</td>
</tr>
<tr>
<td>Duplicate messages</td>
<td>Check duplicate triggers, competing mail plugins and manual resends.</td>
<td>Resending an uncertain transaction repeatedly.</td>
</tr>
</tbody></table>
<h2>8. Migrating from WP Mail SMTP to Lumo</h2>
<p>Back up the current settings and record a working test result. Deactivate the old mail-routing plugin without deleting its saved settings, then configure the replacement. Lumo’s importer reads the saved wp_mail_smtp option and maps supported settings; it is not evidence that every possible mailer, log or routing rule will migrate.</p>
<p>The reviewed mapping includes SMTP, Google/Outlook OAuth, SendGrid, Mailgun, Postmark, Brevo and Amazon SES. If your starting provider is unsupported, configure it manually through a supported route. Review any OAuth reconnection requirement. Do not assume credentials defined only in configuration constants will be present in the saved option being imported.</p>
<p>After import, verify the sender, primary connection, any backup and every conditional route. Repeat your application-level tests. Keep a rollback plan until the replacement has passed them, and remove unused credentials only after you know which connection is actually sending.</p>
<h2>9. A small acceptance test beats a large feature list</h2>
<p>Use a test sheet with five columns: trigger, expected recipient, expected connection, observed log status and actual mailbox result. Start with a diagnostic message, then a form submission, a password reset and an order notification if the site has a store. Record results rather than relying on memory.</p>
<ul>
<li><p>Confirm the expected message is created exactly once.</p>
</li>
<li><p>Confirm the selected connection matches your routing plan.</p>
</li>
<li><p>Check receipt in a mailbox you control and inspect spam as well.</p>
</li>
<li><p>Check provider events and message authentication results when available.</p>
</li>
<li><p>If using a backup or queue, test that behavior separately in a controlled environment.</p>
</li>
<li><p>Confirm logs retain only the data and duration you need.</p>
</li>
</ul>
<p>Choose the plugin that makes those checks clear for the person maintaining the site. A reliable email setup is a chain of correct application settings, authenticated identity, working transport and observable outcomes. The SMTP plugin is an important link in that chain; it is not the entire chain.</p>
<h2>Sources and review scope</h2>
<ul>
<li><p><a href="https://developer.wordpress.org/reference/functions/wp_mail/">WordPress: wp_mail() behavior and return value</a>.</p>
</li>
<li><p><a href="https://wpmailsmtp.com/docs/how-to-use-the-wp-mail-smtp-setup-wizard/">WP Mail SMTP: setup wizard</a>; <a href="https://wpmailsmtp.com/docs/configuring-additional-connections/">additional connections</a>; setup and backup guides linked above.</p>
</li>
<li><p><a href="https://support.google.com/mail/answer/81126?hl=en">Google: email sender guidelines</a>.</p>
</li>
<li><p>Lumo Mail SMTP 2.17.3 source review: includes/Core/Mailer.php, PluginManager.php, PhpMailerSender.php and WpMailSmtpImport.php; includes/Queue/QueueManager.php; SMTP provider and admin views.</p>
</li>
<li><p>WP Mail SMTP Pro 4.9.0 source review: src/Pro/Emails/Logs/Email.php distinguishes sent, waiting and delivered statuses. Official documentation supplies the setup instructions.</p>
</li>
</ul>
<p><em>Reviewed October 24, 2026. Illustrations explain the workflow; they are not screenshots or measured delivery results. No live inbox-placement comparison or provider outage simulation is claimed.</em></p>
<p>Originally published on <a href="https://lumowp.com/wordpress-email-smtp-setup-guide/">LumoWP</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Build a Trello-Style Task Manager in WordPress: An Agency Workflow]]></title><description><![CDATA[A tested WordPress agency workflow: boards, ownership, review, reminders and recurring tasks, with real screenshots and clear test limitations.]]></description><link>https://lumowp.hashnode.dev/build-a-trello-style-task-manager-in-wordpress-an-agency-workflow</link><guid isPermaLink="true">https://lumowp.hashnode.dev/build-a-trello-style-task-manager-in-wordpress-an-agency-workflow</guid><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Fri, 23 Oct 2026 20:54:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/bcf067f8-1210-470f-9348-b62776681077.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A client sends a homepage revision in chat. The designer reads it, the developer assumes someone else owns it, and the project manager asks for an update two days later. Everyone has communicated. Nobody has made the next action unambiguous.</p>
<p>For a small digital agency, that is often the real task-management problem. Another messaging channel will not fix it. A useful workflow needs a named owner, a concrete deliverable, a deadline and a place where the team can see what is waiting for review.</p>
<p>This guide builds a Trello-style kanban workflow inside WordPress using <strong>Lumo Team Messenger</strong>. We will use a fictional website-launch project to connect those ideas to the actual controls: boards, members, task cards, checklists, comments and follow-up settings. “Trello-style” describes the board-and-card workflow; it does not mean feature parity, a Trello integration or an import tool.</p>
<blockquote>
<p><strong>What was actually checked</strong></p>
<p>I inspected Team Messenger 2.214.0, installed it in our permanent local WordPress lab, created a fictional agency board and five tasks, and checked the real interface. Fifteen integration and timing checks passed. I also saved a task status and checklist item through the browser, then reopened the task; a weekly recurring rule displayed its next run and was disabled after the demonstration. Email delivery, Telegram delivery and large-team load were not tested. This is our own product, so the limitations below matter as much as the setup.</p>
</blockquote>
<h2>Is a WordPress task manager right for your agency?</h2>
<p>It is worth evaluating when your team already works in WordPress and wants its internal conversations and project cards together. Designers, developers, content editors and the person checking the final site can share a project board without making the public website itself into a customer-facing project portal.</p>
<p>The trade-off is operational responsibility. Your hosting, backups, updates, access rules and scheduled jobs become part of the workspace. Self-hosted does not automatically mean encrypted end to end, maintenance-free or faster than a hosted project-management service.</p>
<p>Before switching an entire company, pilot one real project with a small team. If you need advanced resource planning, billing, enterprise reporting or strict read-only client seats, verify those requirements independently. This tutorial does not establish those capabilities.</p>
<p>The <a href="https://lumowp.com/product/lumo-team-messenger-wordpress-internal-chat-task-manager-and-telegram-integration-plugin/">Team Messenger product page</a> contains the current package, licensing information and additional interface demonstrations. Check the plan you intend to buy includes the task features you need; do not infer commercial entitlements from this local installation.</p>
<h2>Design the workflow before adding tasks</h2>
<p>Our example is <strong>Northstar Agency · Website Launch</strong>. Maya handles design, Alex handles development and Sam checks quality. These are fictional accounts, not customers or staff whose private work appears in screenshots.</p>
<p>Start with four columns. A column should answer “what happens next?”, not simply make the board look busy.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>What belongs here</th>
<th>Condition for leaving</th>
</tr>
</thead>
<tbody><tr>
<td>To Do</td>
<td>A defined deliverable that has not started</td>
<td>Someone accepts responsibility and has what they need</td>
</tr>
<tr>
<td>In Progress</td>
<td>Work actively being done</td>
<td>The output is ready for another person to inspect</td>
</tr>
<tr>
<td>Review</td>
<td>A deliverable waiting for a decision</td>
<td>The reviewer accepts it or explains the required revision</td>
</tr>
<tr>
<td>Done</td>
<td>Accepted work with evidence attached or linked</td>
<td>Reopen only if a new defect or revision needs action</td>
</tr>
</tbody></table>
<p>“Design website” is too broad for one useful card. “Approve homepage wireframe” has a visible outcome. “QA mobile navigation and contact form” tells the reviewer what to inspect. That difference is more valuable than adding ten custom columns.</p>
<blockquote>
<p><strong>A practical starting rule</strong></p>
<p>Agree that each person normally has one active deliverable before starting another. This is a team policy, not an automatic limit demonstrated in the plugin. If Review keeps growing, help the reviewer clear the queue instead of starting more work. Atlassian’s explanation of work-in-progress limits is a useful background reference for this practice.</p>
</blockquote>
<h2>Step 1. Install the plugin and initialize its storage</h2>
<p>Download the plugin ZIP from your account. In WordPress, open <strong>Plugins → Add Plugin → Upload Plugin</strong>, choose the ZIP, click <strong>Install Now</strong>, then <strong>Activate</strong>. Complete the license activation required by your package.</p>
<p>Open <strong>Messenger</strong>. A fresh installation may ask you to configure the database first. Choose <strong>Go to Setup</strong>. The settings page opens <strong>Connections → Database</strong>.</p>
<p>For this tutorial, select <strong>WordPress Database</strong> and click <strong>Install Tables</strong>. The actual setup created the plugin’s separate, prefixed tables inside the lab’s existing WordPress database. That avoids introducing another database connection just to learn the workflow.</p>
<p><img src="https://cdn.lumowp.com/2026/10/agency-task-database.webp" alt="Team Messenger Connections settings with WordPress Database selected and Install Tables button" /></p>
<p><em>Actual local setup: Messenger → Settings → Connections → Database. No external database credentials are required for internal mode.</em></p>
<p>The <strong>External Database</strong> option is a different deployment choice, not a performance switch you should enable blindly. A remote database adds credentials, connection reliability and backup coordination to the setup. File storage is configured separately, so choosing a database does not automatically move attachments to FTP.</p>
<p>After installation, confirm Messenger opens without a database warning. Keep a backup that includes both the plugin’s tables and the attachment storage you selected. A database-only backup is not a complete recovery plan for uploaded files.</p>
<p>For a fuller walkthrough of groups, messages and storage, use our <a href="https://lumowp.com/wordpress-team-messenger-setup/">WordPress team messenger setup guide</a>. The remaining steps here focus on delivery and task management rather than repeating that article.</p>
<h2>Step 2. Give colleagues access without making everyone an administrator</h2>
<p>Create individual WordPress accounts for the people taking part. Use <strong>Users → Add User</strong>, then review <strong>Messenger → Settings → General</strong>, where messenger access is controlled by allowed roles.</p>
<p>Use the least-privileged role that meets the person’s actual work requirements. A developer who needs WordPress administration is different from a colleague who only needs to discuss work. Do not grant Administrator merely to make the task interface appear.</p>
<p>There are two separate questions: can this WordPress account enter the messenger, and does it belong to this project board? Test both. In our lab we used fictional subscriber accounts for project collaborators and a separate nonmember account to check board access.</p>
<blockquote>
<p><strong>Board membership is collaboration access</strong></p>
<p>In the reviewed version, BoardService::can_manage_content() delegates to can_view(). An ordinary board member can therefore manage board content; membership is not a read-only viewing seat. Our test confirmed a member could manage content and a nonmember could not view the board or move its card. Test a real client-access requirement separately before inviting customers into internal boards. This was a focused service check, not a complete security audit.</p>
</blockquote>
<h2>Step 3. Create one board for one delivery stream</h2>
<p>Open <strong>Messenger → Tasks → New Board</strong>. Give it a recognizable name, such as the client and deliverable, rather than “General tasks.” Add a short description stating the scope and what completion means. Select only the colleagues who need to collaborate, then save.</p>
<p>Our board contains five example cards: wireframe approval, a responsive service page, mobile navigation and form QA, content inventory, and launch redirects. The default board columns are <strong>To Do</strong>, <strong>In Progress</strong> and <strong>Done</strong>. Use <strong>Add another column</strong> to add <strong>Review</strong>. The column edit controls let you adjust the title and appearance.</p>
<p><img src="https://cdn.lumowp.com/2026/10/agency-task-board.webp" alt="Real Northstar Agency demonstration board with five tasks across To Do, In Progress, Review and Done" /></p>
<p><em>Actual lab board with fictional tasks and colleagues. The cropped interface is unchanged.</em></p>
<p>Do not create a new board for every small task. A useful boundary might be one website launch, one ongoing maintenance stream, or a content-production pipeline. Separate boards when membership, confidentiality or the review process really differs.</p>
<p>If you rename the final column, check its completion setting too. In the inspected code, moving a card to a column marked as done sets its completion timestamp; moving it out clears that timestamp. A decorative column name and the completion flag are not the same thing.</p>
<h2>Step 4. Write a task another person can finish without guessing</h2>
<p>Inside the intended column, click <strong>Add a card</strong>, or use <strong>New Task</strong> while working in the project board. Give the task an outcome-based title. Select an <strong>Assignee</strong>, choose an appropriate <strong>Priority</strong>, and set a <strong>Due Date</strong> if the work has a real delivery deadline.</p>
<p>Use <strong>Notes</strong> for the brief and decisions. Use <strong>Checklist</strong> for acceptance conditions, and <strong>Comments</strong> for the conversation about the work. The task also provides an attachment area for the relevant files. Avoid putting passwords, API keys or unrelated customer information into the brief.</p>
<p>Here is a practical brief for the wireframe card:</p>
<pre><code>Deliverable: homepage wireframe ready for internal approval
Owner: Maya
Reviewer: Sam
Scope: desktop and mobile layout, navigation and primary CTA
Evidence: attach or link the two wireframes
Done when: reviewer feedback is resolved and approval is recorded
If blocked: explain what is missing and who can supply it
</code></pre>
<p>“Reviewer” here is a convention in the note, not a separate approval engine demonstrated in the plugin. The visible Assignee field identifies one responsible person. A checklist makes review repeatable, but ticking it does not prove the work is correct.</p>
<p><img src="https://cdn.lumowp.com/2026/10/agency-task-task.webp" alt="Real Team Messenger task editor showing notes, checklist, comments, assignee, priority and due date" /></p>
<p><em>Actual task editor. The checklist and status were saved and reopened during the browser check.</em></p>
<p>In the browser test, I checked <strong>Primary CTA and navigation are clear</strong>, changed the task status to <strong>In Progress</strong>, saved and reopened it. Both changes persisted. That is a useful minimum test before asking the team to rely on the workspace.</p>
<h3>Keep board position and personal status straight</h3>
<p>The source distinguishes board-column placement from per-user task status. A delegated task can show <strong>Delegated</strong> to its creator and <strong>Referred</strong> to its assignee. Do not assume that the personal status dropdown and the shared kanban column are the same field.</p>
<p>For the agency’s daily meeting, use the shared board as the agreed workflow view. When someone says a task is finished, check the actual card, its review evidence and its column. In our integration check, moving a card changed its stored board-column ID; that is different from merely changing a personal status.</p>
<h2>Step 5. Move the work through review, not just across a screen</h2>
<p>Drag the card to the next appropriate column. When work enters Review, add a concise comment explaining what changed and where the reviewer can inspect it. If it fails review, return it to In Progress with a specific reason.</p>
<p>For example, “Mobile menu does not close after following an anchor link; tested at the small-screen layout” is actionable. “Mobile broken” is not. Record the relevant page URL and reproduction steps so the developer can work without another meeting.</p>
<p>Use <strong>History</strong> on the board and <strong>Activity</strong> inside the task when you need to understand changes. Do not treat an activity log as proof that a deliverable was approved; record the approval explicitly.</p>
<p>For a team that already discusses revisions in Messenger, the product also offers message-to-task conversion from the message context menu. After converting, still review the title, assignee, deadline and checklist. A copied chat message is a starting brief, not automatically a complete task specification.</p>
<h2>Step 6. Configure follow-up without turning it into noise</h2>
<p>Open the card and find <strong>Deadline &amp; Follow-up</strong>. Enable <strong>Give this task a time limit and send follow-up reminders</strong>. Choose the time allowance and begin with <strong>Normal — once per stage</strong> intensity.</p>
<p>The reviewed defaults use elapsed-time thresholds such as 25%, 50%, 75% and 100%. <strong>Strong</strong> and <strong>Aggressive</strong> add repeat reminders. They do not make the assignee work faster; they change how frequently the system asks for an update.</p>
<p><img src="https://cdn.lumowp.com/2026/10/agency-task-followup.webp" alt="Actual task follow-up controls with two days allowed, Normal reminder intensity and time elapsed indicator" /></p>
<p><em>Actual interface: the elapsed-time percentage is a timer, not a completion score. Click the image to inspect the full-size controls.</em></p>
<p>Three controls are easy to confuse:</p>
<table>
<thead>
<tr>
<th>Control</th>
<th>What it represents</th>
<th>What it does not prove</th>
</tr>
</thead>
<tbody><tr>
<td>Due Date</td>
<td>A date/time used for deadline and overdue behavior</td>
<td>That someone has accepted the brief</td>
</tr>
<tr>
<td>Time allowed to complete</td>
<td>A duration for the follow-up cycle</td>
<td>Working days or billable hours</td>
</tr>
<tr>
<td>Time elapsed percentage</td>
<td>How much of that duration has passed</td>
<td>Percentage of the deliverable completed</td>
</tr>
</tbody></table>
<p>The source converts one day to 24 hours. A two-day allowance is 48 elapsed hours, not two agency working days with weekends excluded. Our timing check used a four-hour allowance with a start two hours earlier and returned 50% elapsed. It did not inspect any completed checklist items to calculate that number.</p>
<p><strong>Report status</strong> and the optional second follow-up cycle can separate an initial response from later follow-through. Only enable <strong>Treat a status change as a status report</strong> if that matches how your team works. Otherwise, a casual status change may be interpreted as the update you were waiting for.</p>
<p>Begin with one test task and verify the intended notification channel. We did not send real email or Telegram notifications in this lab, so the screenshots are not evidence of mail deliverability.</p>
<h2>Step 7. Use recurring tasks for maintenance with a clear schedule</h2>
<p>Recurring work makes sense for repeated deliverables: review backup results, check a client’s contact form, or prepare the weekly project update. It is a poor fit for an unfinished one-off task that simply needs someone to finish it.</p>
<p>Inside a task, find <strong>Recurring</strong> and enable it. The reviewed interface offers <strong>Daily</strong> and <strong>Weekly</strong>, an interval, a time, a start date and an optional end date. Weekly also exposes day selection. Set the schedule, click <strong>Save Rule</strong>, and inspect <strong>Next run</strong>.</p>
<p>In the browser demonstration, selecting Monday with a 09:00 time showed the next Monday run. The rule was then disabled so the tutorial would not keep producing cards. This verifies configuration and the displayed next-run value, not an unattended multi-week execution history.</p>
<p>Check WordPress’s time zone before relying on that schedule. An agency serving overseas clients should agree on one operational time zone and write the client’s deadline clearly in the brief when necessary.</p>
<p>WordPress scheduled work also depends on execution, not just a saved date. <a href="https://developer.wordpress.org/plugins/cron/">The WordPress cron documentation</a> explains that normal WP-Cron is triggered by page loads. A quiet private workspace may need a properly configured server scheduler. Follow the <a href="https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/">official system-scheduler integration guide</a> with your host, and verify execution before disabling the normal trigger.</p>
<h2>A short acceptance test before your first real project</h2>
<p>Do not judge the installation only while logged in as Administrator. Run this checklist with the accounts and hosting configuration your team will actually use.</p>
<ul>
<li>Open the workspace as an intended colleague and confirm the right board is visible.</li>
<li>Open it as a nonmember and confirm the internal project is not exposed.</li>
<li>Save a task with an owner, deadline and a short checklist; reload it and inspect the saved values.</li>
<li>Move one card between columns and confirm another team member sees the result.</li>
<li>Check a permitted attachment download and an unauthorized access attempt separately.</li>
<li>Send one agreed test reminder and confirm delivery and time zone, rather than only looking for a success message.</li>
<li>Restore a backup in a safe environment and confirm both task data and files are recoverable.</li>
</ul>
<p>These are deployment acceptance checks. They are not all claimed as completed in this article’s lab. The focused checks we did complete are summarized below.</p>
<table>
<thead>
<tr>
<th>Check performed here</th>
<th>Observed result</th>
</tr>
</thead>
<tbody><tr>
<td>Board member vs. nonmember service checks</td>
<td>Member allowed; nonmember board read and card move denied</td>
</tr>
<tr>
<td>Card move and subsequent read</td>
<td>Destination board-column ID persisted</td>
</tr>
<tr>
<td>Browser task save</td>
<td>Status and checklist change remained after reopening</td>
</tr>
<tr>
<td>Follow-up normalization and elapsed time</td>
<td>Zero duration rejected; invalid intensity fell back to Normal; half the allowance returned 50%</td>
</tr>
<tr>
<td>Weekly rule configuration</td>
<td>Next-run value displayed; rule disabled after the test</td>
</tr>
</tbody></table>
<h2>Keep the workspace reliable after launch</h2>
<p>A task board is a logged-in, changing application. Do not place its authenticated HTML or AJAX responses behind a shared full-page cache. Ordinary public marketing pages and the private workspace have different caching needs. If your site becomes slow specifically after login, investigate the actual request path instead of assuming a cache switch will solve it.</p>
<p>Keep attachments purposeful. A final PDF and the source link are often more useful than ten near-identical exports with unclear names. Decide who archives completed projects, who removes former employees’ access, and how long the agency retains project material.</p>
<p>For a new team, I would review the pilot after one completed delivery. Ask where work stalled: unclear brief, too much active work, missing review, or unreliable notifications. Change the process that caused the delay. Adding more alerts or columns is not always the answer.</p>
<h2>What this setup gives you—and where to draw the line</h2>
<p>The useful result is a shared delivery process inside WordPress: one project board, visible ownership, explicit review, task context and controlled follow-up. Team Messenger supplies the interface; your agency still needs to define responsibility and acceptance.</p>
<p>Start with a single project and the four-column workflow above. Keep the brief small enough to understand, keep the next action visible, and close the card only when the deliverable is accepted. That is a much stronger foundation than buying a tool and hoping the team will become organized around it.</p>
<h3>References and verification notes</h3>
<ul>
<li>Lumo Team Messenger 2.214.0 source reviewed: BoardService, BoardRepository, TaskService, TaskFollowupService, TaskRecurringService and TaskAjax. Local screenshots use fictional data. The product page may describe a different release; check your installed version.</li>
<li><a href="https://www.atlassian.com/agile/kanban/wip-limits">Atlassian: Working with WIP limits for kanban</a> — background for the suggested team policy; automatic WIP enforcement was not demonstrated here.</li>
<li><a href="https://wordpress.org/documentation/article/roles-and-capabilities/">WordPress: Roles and capabilities</a> — distinguish WordPress privileges from plugin-specific board membership.</li>
<li><a href="https://developer.wordpress.org/plugins/cron/">WordPress: WP-Cron</a> — scheduled execution and traffic-triggered behavior.</li>
</ul>
<hr />
<p>Originally published on <a href="https://lumowp.com/wordpress-task-manager-digital-agency/">LumoWP</a>. The original tutorial is credited to Mansour Jabinpour. I work on LumoWP, which makes the plugin used in this walkthrough. The test scope and limitations above are retained from the original.</p>
]]></content:encoded></item><item><title><![CDATA[Build a WordPress Member Resource Library: A Tested One-Page Workflow]]></title><description><![CDATA[Set up a member resource page with Content Restrictor. Test roles, redirects, caches and file access with a practical, source-reviewed workflow.]]></description><link>https://lumowp.hashnode.dev/build-a-wordpress-member-resource-library-a-tested-one-page-workflow</link><guid isPermaLink="true">https://lumowp.hashnode.dev/build-a-wordpress-member-resource-library-a-tested-one-page-workflow</guid><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Fri, 23 Oct 2026 20:11:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/b4437663-e147-42fa-b6b0-c97719f7789b.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For a small WordPress resource library, I want an access rule I can explain in one sentence: these accounts may open this page. Before extending it to an entire post type, I want a repeatable test that proves the rule behaves as intended. Here is the one-page workflow we used, including a redirect edge case we found along the way.</p>
<p>For this narrowly defined reader-access requirement, a small plugin can be enough. In this tutorial, we will build a Member Resource Library, allow the right WordPress accounts to read it, and test what happens when someone else opens the same URL. We will use <strong>Content Restrictor</strong>, our free plugin, with the normal WordPress block editor.</p>
<p>This is a tutorial for version <strong>2.10.6</strong>, checked against its source and a local WordPress 7.1.3 installation. The screenshots below are real settings screens, enlarged and annotated for readability. We also document a redirect issue found during testing, because a useful setup guide should explain the edges as well as the happy path.</p>
<blockquote>
<p><strong>What you will build</strong></p>
<p>One published resource page with a reader-access rule. Public pages remain public. You will not need Elementor, a payment gateway, or an elevated user role just to let someone read it.</p>
</blockquote>
<h2>First, choose the access rule you actually need</h2>
<p>“Members only” sounds specific, but it can mean several different things. A registered reader, a paying customer, and a particular client are different audiences. Start by writing down which one you mean.</p>
<table>
<thead>
<tr>
<th>Your requirement</th>
<th>Use this visibility option</th>
<th>What it really checks</th>
</tr>
</thead>
<tbody><tr>
<td>Any signed-in account may read the page</td>
<td>Members Only</td>
<td>Whether the visitor is logged in</td>
</tr>
<tr>
<td>Only accounts with a particular role may read it</td>
<td>Selected User Roles</td>
<td>Whether the account has a selected role</td>
</tr>
<tr>
<td>Only two named clients may read it</td>
<td>Selected Users</td>
<td>Whether the account is in your selected list</td>
</tr>
<tr>
<td>Only visitors who are signed out may read it</td>
<td>Guests Only</td>
<td>Whether the visitor is logged out</td>
</tr>
<tr>
<td>This page must stay public despite a broader rule</td>
<td>Everyone</td>
<td>An explicit public rule for this page</td>
</tr>
</tbody></table>
<p>The important distinction: <strong>Members Only does not check whether somebody paid you</strong>. Likewise, selecting the WooCommerce Customer role does not establish that a customer bought a particular product or still has an active subscription. Those requirements need an entitlement check connected to the relevant commerce or membership system.</p>
<p>For our example, we will first allow any logged-in member, then narrow access to the Subscriber role. WordPress describes roles as collections of capabilities; they are not a simple ladder of reader access. See the official <a href="https://wordpress.org/documentation/article/roles-and-capabilities/">WordPress roles and capabilities reference</a> if you are deciding which account role to assign.</p>
<h2>Download and install the free plugin</h2>
<p>The linked ZIP is the prepared <strong>Content Restrictor 2.10.6</strong> package. At the time this tutorial was prepared, it was not yet available in the WordPress.org plugin directory, so these instructions use a ZIP upload rather than a repository search.</p>
<p><a href="https://lumowp.com/restrict-wordpress-pages-user-roles-free-plugin/#download-and-install-the-free-plugin">Download the free ZIP from the original tutorial</a>. Version 2.10.6, GPLv2 or later. Guests verify an email to download; signed-in readers use the direct-download flow.</p>
<p>The package requires WordPress 6.0 or later and PHP 7.4 or later and is distributed under GPLv2 or later. Those are package minimums, not a recommendation to run an old PHP version. Keep a backup and try the setup on staging before applying access rules to a working site.</p>
<ul>
<li>Open <strong>Plugins → Add New Plugin → Upload Plugin</strong> in WordPress.</li>
<li>Choose the downloaded ZIP as it is; do not upload an extracted folder.</li>
<li>Click <strong>Install Now</strong>, then <strong>Activate Plugin</strong>.</li>
<li>Open <strong>Lumo WP → Content Restrictor</strong> in the dashboard menu.</li>
</ul>
<p>If WordPress says the destination folder already exists, check whether Content Restrictor is already installed before replacing anything. The package in this tutorial is the free Content Restrictor release; do not assume that a differently named legacy plugin has identical settings or an automatic migration path.</p>
<p>For the product overview, requirements, and future release information, see <a href="https://lumowp.com/product/lumo-content-restriction-plugin-control-your-wordpress-page-access-with-user-role-permissions-protected-content/">Lumo Content Restrictor</a>. You can complete this tutorial with the ZIP above.</p>
<h2>Step 1: Leave global restrictions off</h2>
<p>Open <strong>Lumo WP → Content Restrictor → General</strong>. Keep <strong>Enable Global Restrictions</strong> off for this walkthrough. We want to control one page first, not unexpectedly change access to other content.</p>
<p>Leave <strong>Exclude Administrators</strong> enabled while you configure the plugin, then click <strong>Save Changes</strong> if you changed anything. This helps preserve your working access, but it also means your administrator session is a poor test of the visitor experience.</p>
<p><img src="https://cdn.lumowp.com/2026/10/content-restrictor-general.webp" alt="Content Restrictor General settings with global restrictions disabled" /></p>
<p><em>Real lab screen, cropped and annotated: global restrictions stay off for this one-page tutorial.</em></p>
<blockquote>
<p><strong>The administrator preview trap</strong></p>
<p>“I can still see the page” does not prove the rule failed. You may be looking at it with an administrator account that bypasses the front-end restriction. Test with a separate ordinary account and a signed-out browser window.</p>
</blockquote>
<h2>Step 2: Create a page and make it members-only</h2>
<p>Go to <strong>Pages → Add New Page</strong>. Call it “Member Resource Library” and add a short introduction plus some harmless sample content. Use a fictional resource while testing; do not put confidential client information on the page to see whether the restriction works.</p>
<p>Publish the page using normal WordPress publishing controls. In the editor, open the <strong>Page</strong> settings sidebar and find <strong>Content Restriction Settings</strong>. Depending on your editor layout, the meta box may be lower down in the sidebar or in the meta-box area below the editor.</p>
<ul>
<li>Open the plugin's <strong>Visibility</strong> selector.</li>
<li>Choose <strong>Members Only</strong>.</li>
<li>Save or update the page.</li>
<li>Copy the public page URL and open it in a signed-out window.</li>
</ul>
<p>The plugin's Visibility field is separate from WordPress's own public, private, and password-protected publishing options. For this example, the page is published normally and Content Restrictor supplies the reader rule. Setting a page to WordPress Private instead is not a way to give ordinary Subscribers access; native private content uses WordPress permissions. The official <a href="https://make.wordpress.org/support/user-manual/posts/post-visibility/">post visibility guide</a> explains that distinction.</p>
<p>If you need a refresher on arranging headings, images, and reusable sections, our <a href="https://lumowp.com/gutenberg-tips-professional-wordpress-articles/">Gutenberg article-publishing tutorial</a> covers the editor workflow. No page-builder layout is required for the restriction.</p>
<h2>Step 3: Restrict the page to a role or named users</h2>
<p>Now suppose you want the resource library to be available to Subscribers rather than every logged-in account. In the same page's <strong>Content Restriction Settings</strong>, change Visibility to <strong>Selected User Roles</strong>, check <strong>Subscriber</strong>, and save the page.</p>
<p><img src="https://cdn.lumowp.com/2026/10/content-restrictor-roles.webp" alt="WordPress page settings with Selected User Roles and Subscriber checked" /></p>
<p><em>Real Gutenberg settings, enlarged and annotated. Select Subscriber, then save the page.</em></p>
<p>An account with the Author role is not automatically allowed by a Subscriber-only rule. The code checks role membership, not which role sounds more powerful. If you want Subscribers and Customers, select both. An account matching either selected role can satisfy this rule.</p>
<p>For a client-specific page, choose <strong>Selected Users</strong> instead and select the intended existing accounts. Save, then test with both a selected and an unselected account. This is often a clearer fit for a small client handover page than creating a new role for every client.</p>
<p>Do not give a reader the Editor or Administrator role to solve a viewing problem. Editing permissions and reading permissions are separate decisions. Also, the <strong>Plugin Access Control</strong> section in the plugin's Advanced tab controls who may manage the plugin settings and meta box. It is not where you grant readers access to your resource page.</p>
<h2>Step 4: Give denied visitors a useful destination</h2>
<p>A restriction needs a sensible next step. A guest can be sent to your login page; a logged-in user with the wrong role may need an explanation instead of another login form.</p>
<p>Open <strong>Lumo WP → Content Restrictor → Redirect</strong> and review the default redirect destination. Use a public page on the same site that explains how to sign in or request access. The page editor also provides a <strong>Custom Redirect URL</strong> when one resource needs its own destination.</p>
<p>Keep that destination outside the restriction it is explaining. For example, if every Page has a members-only rule, make your access-information page explicitly <strong>Everyone</strong>. Otherwise, the destination can itself be denied and create a confusing redirect loop. Use the Redirect tab for the default destination; do not rely on the similarly named General-tab field in this release.</p>
<blockquote>
<p><strong>Version 2.10.6 finding: test the return URL</strong></p>
<p>Our anonymous request correctly received a 302 redirect, but the generated redirect_to value was URL-encoded twice. We therefore do not recommend assuming that “return after login” works in every login flow. If the return destination is malformed, disable that option, use a public login/access page, and open the resource URL again after signing in. Verify the full journey on your own login setup before launch.</p>
</blockquote>
<p>This is a version-specific observation, not a reason to quietly modify your login system. The download here remains the original prepared package, so the tutorial and the file refer to the same behavior.</p>
<h2>Step 5: Understand which rule wins</h2>
<p>Once one page works, you can consider <strong>Post Types</strong> rules for a larger collection. For example, a custom resource post type could have a default members-only rule, with one introductory resource left public.</p>
<p>Reading the front-end restriction code revealed this decision order:</p>
<pre><code class="language-text">Explicit rule on this individual post or page
    otherwise → enabled rule for its post type
    otherwise → enabled global rule
    otherwise → public access
</code></pre>
<p>The individual option labelled <strong>Use Global Settings</strong> is therefore best understood as “inherit the applicable rule.” An enabled post-type rule can apply before the global default. Turning off global restrictions does not turn off an independently enabled post-type rule.</p>
<p>Likewise, <strong>Everyone</strong> on an individual page is an explicit override, not the same as inheriting the default. These details matter when a page unexpectedly stays restricted or unexpectedly becomes public.</p>
<p>Before using a broad rule, list your required public destinations: your home page, access-information page, contact page, and any account or checkout routes involved in your setup. Test those destinations individually. A global content setting is not a web-server access policy for every URL on the domain.</p>
<h2>Step 6: Review archives, search results, and excerpts</h2>
<p>Restricting a page's contents and removing its listing from discovery are different tasks. Open <strong>Lumo WP → Content Restrictor → Advanced</strong> and review <strong>Hide Restricted Posts from Archives</strong>.</p>
<p><img src="https://cdn.lumowp.com/2026/10/content-restrictor-advanced.webp" alt="Content Restrictor Advanced settings for archives and restricted excerpts" /></p>
<p><em>Real Advanced settings screen, annotated. Review archive and excerpt behavior separately from page access.</em></p>
<p>In the reviewed source, the listing filter targets the main home, archive, search, and feed queries. That is useful, but it is not a promise that every custom Elementor grid, secondary query, API response, or third-party search service will hide the same item. Test the places where your site actually displays it.</p>
<p>Also review <strong>Show Excerpts for Restricted Content</strong>. If you intentionally want a teaser, write a public-safe excerpt. Do not copy confidential details into it and then assume the full-page rule will hide them. Leave debug mode off on a production site unless you are investigating a specific issue.</p>
<h2>Step 7: Check caching and direct file access</h2>
<p>Two things sit outside the simple “who is this WordPress user?” decision: cached responses and direct media URLs.</p>
<p><strong>A shared cache may serve a response before WordPress runs.</strong> Exclude your protected pages from shared full-page caching until you have verified a safe configuration for each audience. Purge any previously public cached copy. Then repeat the guest and member tests through your real host, cache plugin, and CDN—not just while logged into the dashboard.</p>
<p><strong>A protected page does not make its linked PDF private.</strong> If a document lives at a publicly accessible uploads URL, a visitor who has that URL may be able to request it directly. This plugin does not turn the uploads directory into a private document store. Sensitive downloads need their own authenticated delivery mechanism or server-level protection.</p>
<blockquote>
<p><strong>Protect the resource, not only its introduction</strong></p>
<p>A members-only page can be a useful navigation and reader-access feature. For confidential files, check the file URL separately in a signed-out browser. Hiding the link is not the same as denying the download.</p>
</blockquote>
<h2>Step 8: Run an access test before sharing the page</h2>
<p>Keep one administrator window for making changes and use separate browser sessions for testing. Do not switch between accounts in the same cached tab and assume you are seeing a fresh response.</p>
<table>
<thead>
<tr>
<th>Test session</th>
<th>Members Only</th>
<th>Subscriber-only rule</th>
</tr>
</thead>
<tbody><tr>
<td>Signed-out visitor</td>
<td>Denied or redirected</td>
<td>Denied or redirected</td>
</tr>
<tr>
<td>Logged-in Subscriber</td>
<td>Allowed</td>
<td>Allowed</td>
</tr>
<tr>
<td>Logged-in Author with no Subscriber role</td>
<td>Allowed</td>
<td>Denied or redirected</td>
</tr>
<tr>
<td>Administrator with bypass enabled</td>
<td>Not a reliable visitor test</td>
<td>Not a reliable visitor test</td>
</tr>
</tbody></table>
<p>Then check the full journey: open the URL while logged out, sign in, reopen the resource, log out, and request it again. Test your access-information destination, site search, relevant archive pages, and any directly linked file. Repeat after purging caches and again after a permitted user has visited the resource.</p>
<p>In our lab, twelve focused checks passed for the access-decision logic, including role matching, named users, guests-only access, post-type inheritance, and an individual Everyone override. We also saved the role rule through the real editor and confirmed that an anonymous HTTP request was redirected without the sample page content in that response.</p>
<p>Those results support the workflow described here. They are not a full security audit or a guarantee about every theme, REST integration, cache layer, or membership extension. The source files most relevant to this review were <strong>includes/Frontend/Restrictor.php</strong>, <strong>includes/Core/Permissions.php</strong>, and <strong>includes/Admin/MetaBox.php</strong>.</p>
<h2>Troubleshooting the most common surprises</h2>
<table>
<thead>
<tr>
<th>What you see</th>
<th>What to check first</th>
</tr>
</thead>
<tbody><tr>
<td>The administrator still sees the page</td>
<td>Exclude Administrators and the account used for testing</td>
</tr>
<tr>
<td>An Author cannot open a Subscriber-only page</td>
<td>Exact selected roles; roles are not inherited reader tiers</td>
</tr>
<tr>
<td>The page is restricted with global settings off</td>
<td>An individual or enabled post-type rule</td>
</tr>
<tr>
<td>A protected resource is visible in a custom grid</td>
<td>Whether that grid uses a secondary query outside the archive filter</td>
</tr>
<tr>
<td>Login succeeds but the return address is wrong</td>
<td>The 2.10.6 redirect_to encoding issue and your login flow</td>
</tr>
<tr>
<td>A guest can download the PDF</td>
<td>Direct media delivery is separate from page restrictions</td>
</tr>
<tr>
<td>A guest sometimes sees an old public copy</td>
<td>Shared page cache, CDN rules, and previously cached responses</td>
</tr>
</tbody></table>
<h2>A sensible first setup</h2>
<p>Start with one resource page, one ordinary test account, and a public access-information page. Keep global rules off, choose the narrowest reader rule that matches your real requirement, and test the URL outside your administrator session.</p>
<p>Once that works, expand deliberately to more resources or a post-type default. The goal is not to put the largest number of pages behind a switch. It is to make the access rule understandable: the right person can open the resource, the wrong person gets a useful next step, and a cache or direct file URL does not undermine the arrangement.</p>
<hr />
<p>Disclosure: I work on LumoWP, which makes the plugin used here. This is an adapted version of our <a href="https://lumowp.com/restrict-wordpress-pages-user-roles-free-plugin/">original tutorial</a>, including the same tested version and known limitation.</p>
]]></content:encoded></item><item><title><![CDATA[Using Your Own AI API with WPML: A One-Page Test Before Bulk Translation]]></title><description><![CDATA[Connect an AI provider to WPML, validate one page, and troubleshoot queues before bulk translation. A practical guide with Lumo source-code notes.]]></description><link>https://lumowp.hashnode.dev/using-your-own-ai-api-with-wpml-a-one-page-test-before-bulk-translation</link><guid isPermaLink="true">https://lumowp.hashnode.dev/using-your-own-ai-api-with-wpml-a-one-page-test-before-bulk-translation</guid><category><![CDATA[WordPress]]></category><category><![CDATA[translation]]></category><dc:creator><![CDATA[Mahdi Jabinpour]]></dc:creator><pubDate>Fri, 23 Oct 2026 12:29:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb4ef2641e732adf52f28f/7912b586-4791-4c53-ad30-e9db2cedfd02.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>An AI model can return fluent French and still give you a page you should not publish. A product dimension may change. A paragraph may disappear. A button may become too long for its layout.</p>
<p>That is why I would start a WordPress translation project with one representative page, not the “translate everything” button.</p>
<p>This guide explains a small acceptance test for connecting a provider API to a WPML workflow. It also explains what to inspect when a translation job stalls.</p>
<p><strong>Disclosure:</strong> I build products at LumoWP, including the Lumo AI Translation Addon for WPML discussed below. It is an independent third-party add-on, not an official WPML product. The implementation notes here come from inspecting the add-on’s local 3.20.28 source. This article is a workflow and source review, not a measured comparison of AI models.</p>
<h2>1. Separate the language structure from the translation engine</h2>
<p>WPML manages the relationship between your original content and its translations. Your chosen AI provider generates translated text. The integration between them has to deliver that text back to the right job and field.</p>
<p>An API key alone does not establish that integration. WPML’s <a href="https://wpml.org/fr/faq/why-cant-i-use-my-own-deepl-google-or-microsoft-api-key-for-automatic-translation/">API-key FAQ</a> specifically says that its built-in automatic translation does not accept your own DeepL, Google or Microsoft keys. A third-party provider integration is a separate workflow; do not paste an OpenAI key into an unrelated WPML authentication field.</p>
<p>In the Lumo workflow, you configure the provider inside the add-on and send content through its WPML integration. Keep these three questions separate:</p>
<ul>
<li><strong>Routing:</strong> Did the correct page and target language enter the job?</li>
<li><strong>Execution:</strong> Did every required field finish translating?</li>
<li><strong>Acceptance:</strong> Is the resulting page accurate and usable?</li>
</ul>
<p>A successful API connection answers only a small part of the second question.</p>
<h2>2. Prepare a small, recoverable test</h2>
<p>Use a staging copy and take a backup before experimenting with existing translations. Start with one target locale you actually intend to support.</p>
<p>Choose a page containing a heading, several paragraphs, an internal link, an image, a button and at least one detail that must not change. For a shop, include a product model number and a measurement. For a service business, include a delivery condition or a limitation.</p>
<p>Write down the acceptance criteria before translating. Here is an illustrative source sentence, not a claimed model output:</p>
<blockquote>
<p>The Lumo Desk Mini supports monitors up to 8 kg. Delivery takes 3–5 business days. The mounting kit is sold separately.</p>
</blockquote>
<p>A fluent translation fails if it changes 8 kg, turns business days into calendar days, or implies that the mounting kit is included. Those are factual errors, even if a language detector calls the text natural.</p>
<p>Keep a copy of the source and record the exact provider, model identifier, target locale and instructions. You will need them to reproduce a problem later.</p>
<h2>3. Connect the provider and assign one job</h2>
<p>For the add-on version inspected here:</p>
<ol>
<li>Install and configure WPML Multilingual CMS with its translation-management functionality. Confirm that your source and target languages are correct. If this is your first WPML installation, our <a href="https://lumowp.com/how-to-install-and-set-up-wpml-full-step-by-step-guide-2026/">WPML setup guide</a> covers that groundwork.</li>
<li>Install the Lumo add-on ZIP through <strong>Plugins → Add New → Upload Plugin</strong>, then activate it.</li>
<li>Open <strong>Lumo WP → AI Translator → Settings</strong>. Choose a supported provider, enter its API key and select a model available to that account. Save the settings and use <strong>Test connection</strong>.</li>
<li>Configure your translation instructions before creating the test job.</li>
<li>In WPML’s translation-management or translator settings, confirm that the Lumo translator is available. Assign only your test page and target language to that integration.</li>
<li>Open the add-on’s <strong>Queue</strong> tab and inspect the job status and logs. When it completes, inspect the translated page itself.</li>
</ol>
<p>WPML labels and translator locations vary between releases. Its current <a href="https://wpml.org/documentation/customizing-wpml/translator-workflows/">translator-workflow documentation</a> describes the translator settings under WPML Settings. Follow the labels in your installed release rather than treating an old screenshot as an exact map.</p>
<p>Use a dedicated API key for the project where your provider supports it, and set a provider-side budget or usage alert. A consumer chat subscription does not necessarily include API usage. Content sent for translation goes to the configured provider, so review what you are sending before including private material.</p>
<h2>4. Give the model rules it can actually follow</h2>
<p>“Make it human” is too vague to be a useful acceptance criterion. Define audience, terminology and facts that must survive.</p>
<p>For example, adapt these instructions for a German product page:</p>
<blockquote>
<p>Translate into German for customers in Germany. Use formal Sie consistently. Preserve product names, SKUs, measurements and delivery conditions. Do not add claims or remove limitations. Preserve markup and shortcode syntax present in the input. Translate customer-facing text naturally. Keep button labels concise without changing their meaning.</p>
</blockquote>
<p>This is a starting instruction, not a guarantee. WordPress content may be split into fields or chunks before it reaches a model. A rule that depends on an earlier paragraph may not have that paragraph available in every request.</p>
<p>That is also why terminology belongs in reusable instructions, rather than being explained only once at the top of a long source article.</p>
<h2>5. Review the output in two passes</h2>
<p>First, check completeness and behavior:</p>
<ul>
<li>Are all expected sections present, including the final paragraph?</li>
<li>Do headings, links, images and shortcodes still behave correctly?</li>
<li>Does the language switcher lead to the matching page?</li>
<li>Do buttons and navigation work on mobile?</li>
<li>For a product, are attributes and purchasing choices still correct?</li>
</ul>
<p>Then ask a fluent reviewer to check meaning, tone and terminology. Review the rendered page, not just the text in an editor: a good sentence can still overflow a narrow button.</p>
<p>For the illustrative sentence above, the pass criteria are unchanged product identity, the same 8 kg limit, the same delivery range and the same separate-purchase condition. Record failures individually. A single “quality: 9/10” score hides the reason a page should be held back.</p>
<p>Only expand to a small batch after the representative page passes. Include different content types in that batch; a plain blog post does not prove that an Elementor page or a variable product will behave the same way.</p>
<h2>6. What the source reveals about long jobs</h2>
<p>Two implementation details are worth understanding before you translate hundreds of pages.</p>
<p><strong>Temporary API errors get bounded retries.</strong> In the inspected version, the request handler in class-ai-processor.php retries HTTP 429, 500, 502 and 503 up to three times, waiting 1, 2 and 4 seconds. That can help with a brief interruption. It does not fix an invalid key, exhausted quota or an unavailable model, and it is not a promise that every failed request will recover.</p>
<p><strong>Chunk completion needs a success check.</strong> The chunk manager stores completed pieces and retrieves them in chunk-number order for assembly. Its are_all_chunks_completed() method also treats exhausted retries as “done processing”; the source comment explicitly requires the caller to inspect permanently failed chunks before deciding that the operation succeeded.</p>
<p>That distinction is useful well beyond this plugin:</p>
<blockquote>
<p>“No work left to attempt” and “all content successfully translated” are different states.</p>
</blockquote>
<p>When reviewing a job, look for failed pieces and missing content, not merely a queue that stopped moving. Stored progress can reduce repeated work, but it should not be interpreted as an absolute guarantee of zero duplicate provider billing after every possible failure.</p>
<h2>7. Diagnose a stalled queue before submitting again</h2>
<p>A repeated click on Translate can make diagnosis harder. Start with the job you already have.</p>
<ul>
<li><strong>Pending without progress:</strong> check the add-on’s Cron Setup and dashboard status. WordPress background scheduling must actually run. If WP-Cron is disabled, use the server-cron instructions shown by the plugin; keep any secret-bearing cron URL private.</li>
<li><strong>Authentication or quota error:</strong> check the provider account, key and available API balance. Waiting longer will not correct credentials.</li>
<li><strong>Rate limiting or temporary server error:</strong> inspect the logs and retry state before launching additional jobs.</li>
<li><strong>Completed but incomplete-looking page:</strong> compare the source sections and translated fields, then inspect chunk failures and WPML delivery status.</li>
<li><strong>Good translation, broken layout:</strong> investigate the affected widget or field mapping instead of assuming a different language model will fix it.</li>
</ul>
<p>Logs can contain provider responses and content fragments. Redact keys and private text before sharing them in a support request.</p>
<h2>8. Decide whether bringing your own key is worth it</h2>
<p>Direct API access gives you provider and model choice, but it also leaves you responsible for provider billing, model availability and part of the operational troubleshooting.</p>
<p>Compare total effort and cost: add-on licensing, API usage, retries, re-translation and human review. Do not assume that a direct API is always cheaper than an existing WPML workflow with bundled credits or translation memory.</p>
<p>If you want to use the integration described here, the <a href="https://lumowp.com/product/lumo-wpml-ai-translation-addon-automate-your-multilingual-site-with-openai-claude-mistral-grok/">Lumo AI Translation Addon for WPML</a> provides the provider settings, queue and bulk tools. It supplies the translation engine; it does not replace WPML or the acceptance test.</p>
<p>My recommendation is deliberately small: connect one provider, translate one representative page, check every important detail, and expand only after that process is repeatable. The useful result is a page you can stand behind, not a large number in a completed-jobs counter.</p>
]]></content:encoded></item></channel></rss>