The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →You can automate internal link suggestions for a WordPress post in n8n by reading the site’s XML sitemaps, asking Gemini 2.5 Flash to choose relevant pages from that list, and inserting only links that pass a validation step before the post is updated. The design comes from Ruesch Manny’s DEV Community article, which the workflow below follows. It is custom workflow logic built from n8n’s HTTP Request, Code and WordPress nodes, not a built-in n8n feature. The DEV post is displayed with a September 27, 2026 publication date, so check the author’s code against your own n8n version before you copy it.
How the pipeline is organized
The workflow separates two jobs that are easy to blur together. Sitemap parsing decides which pages exist and may be linked to. The language model only ranks and picks from that list and writes anchor text. Keeping those jobs apart is what makes the output checkable.
As an Amazon Associate I earn from qualifying purchases.
- Fetch the sitemap index and each child sitemap that holds the content you want to link to.
- Extract every
<loc>URL into a candidate inventory. - Group the candidates, for example by language, and give each one a readable label.
- Send the post’s text and the closed candidate list to Gemini 2.5 Flash, and request JSON containing chosen URLs and anchor text.
- Validate the returned URLs against the candidate list and the site’s host before anything is written.
- Assemble the approved links into HTML and update the WordPress post.
What you need before building it
- A self-hosted or hosted WordPress site with its sitemap enabled. Many SEO-plugin setups publish a sitemap index that points to separate post and page sitemaps, but the exact path varies, so confirm yours in a browser first.
- WordPress REST API access and a user with permission to edit posts. For self-hosted sites, n8n’s WordPress credential guide describes Basic authentication with a username, an application password and the site URL. The same guide describes OAuth2 for WordPress.com-hosted sites and says self-hosted WordPress should use Basic authentication.
- A Gemini API key with access to the Gemini 2.5 Flash model in your account. Confirm the model name and availability in Google’s current documentation before you start, since model names and access rules change.
- A staging copy of the site or a draft-only test post. Do not run the first test against live published content.
Build the workflow step by step
Step 1: Fetch the sitemap index and child sitemaps
Add an HTTP Request node that requests your sitemap index URL and returns the response body as text. The index does not list articles directly; it lists child sitemaps, such as one for posts and one for pages. Add a second request for each child sitemap you want to draw from. Limit this to content types you actually want linked. Including tag archives, author pages or utility pages usually adds noise.
Free tools Windows power users keep installed
One-click scans. No signup required.
Step 2: Extract candidate URLs
The source article uses regular expressions in a Code node rather than a full XML parser. That is a lightweight choice that works for simple, well-formed sitemaps, and it is the first thing to test on your own files. A minimal version looks like this:
#1 Best Overall
const xml = $input.first().json.data; // field name depends on your HTTP Request output
const locs = [...xml.matchAll(/<loc>s*([^<]+?)s*</loc>/g)]
.map(m => m[1].replace(/&/g, '&').trim());
return [...new Set(locs)].map(url => ({ json: { url } }));
The decoding line matters. A URL containing a query string can appear in XML with &, and without decoding it will not match the same URL elsewhere in your workflow. Remove the Set call only if you want duplicates to flow through, which you normally do not. If your sitemaps contain namespaces, CDATA sections or unusual escaping, switch to a proper XML parser node or library rather than extending the regex.
Step 3: Organize the candidate inventory
The source groups candidates by language and builds display labels from URL slugs. Treat slug-derived labels as a convenience only. A slug such as /guide-2 tells the model nothing, and translated sites can have slugs that do not match the page title. If you can, store each post’s real title alongside its URL, which you can retrieve through the WordPress node, and pass that title to the model instead of the slug.
Rank #2
Step 4: Ask Gemini 2.5 Flash to choose from the list
The prompt in the source article instructs the model to use only the URLs provided, to exclude the article being edited, and to return natural anchor text inside valid JSON. Keep those constraints and add two more: a maximum number of links, and a rule that anchors must be phrases a reader would plausibly click. Give the model the current post’s text, not only its title, so it can judge topical fit.
Whatever the prompt says, treat the response as untrusted input. Parse it inside a try/catch block, and if parsing fails, stop the run for that post rather than retrying blindly and inserting partial output.
Step 5: Validate before writing
The source’s gate intersects the model’s returned URLs with the candidate list and checks the allowed host. That blocks invented and off-site links. It does not confirm that a destination is live, relevant, canonical or in the right language, so add checks of your own. The following sketch covers the points that are cheap to verify inside n8n:
const allowedHost = 'www.example.com'; // set to your site's host
const candidates = new Set(candidateUrls.map(u => new URL(u).href));
const currentHref = new URL(currentPostUrl).href;
const approved = [];
for (const raw of returnedUrls) {
let u;
try { u = new URL(raw); } catch { continue; }
if (u.protocol !== 'https:' || u.hostname !== allowedHost) continue;
const href = u.href;
if (!candidates.has(href) || href === currentHref) continue;
if (approved.some(a => a.url === href)) continue;
approved.push({ url: href, anchor: String(raw.anchor || '').slice(0, 80) });
}
Normalize candidates and returned URLs the same way, or valid matches will fail for reasons such as a trailing slash. The https-only check assumes your site is served entirely over HTTPS. Add a status check for each approved URL, looking for a 200 response and no redirect chain, if you want to catch dead or moved pages before publication. The source does not describe this step, so it is a recommendation rather than a documented feature of the pattern.
Rank #4
Step 6: Assemble the HTML and update the post
The source assembles approved links into a related-articles block in Markdown or HTML and passes it to WordPress. The WordPress node documents Create, Get and Update operations for posts and pages, which is the part of this step that n8n supports directly. Append the block to the existing content rather than replacing the post body, and set the post to draft on the first runs. Only move to publishing once you have reviewed several outputs by hand.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteInserting anchors inside body paragraphs is a different and riskier task than appending a related block. It requires locating the phrase in the HTML, avoiding existing links and headings, and handling repeated phrases. The source describes the block approach, so start there.
Best Value
Design trade-offs
Each of these choices has a cost. The table lists the alternatives the source implicitly raises, with the trade-off for each.
| Choice | What it gains | What it risks |
|---|---|---|
| Regex extraction from sitemaps | Quick to build inside a Code node | Breaks on namespaces, CDATA, unusual escaping or unexpected sitemap shapes |
| Dedicated XML parsing | Handles standard XML structure reliably | Needs an extra node or library and more setup |
| Sitemap-based candidate discovery | Limits destinations to pages the site already publishes in its sitemap | Sitemaps can be stale or include pages you do not want linked |
| WordPress REST API content enumeration | Gives access to titles, status and metadata directly | Requires credentials and paging logic for large sites |
| AI-selected anchor text | Fast, and fits the surrounding topic | Can produce awkward or over-optimized phrasing that needs editing |
| Editor-written anchor text | Full control over wording | Slower, and does not scale to many posts |
| Draft-first updates | Gives a review step before anything goes live | Adds manual work to each run |
| Direct publish updates | Fully automated | A bad run reaches readers before anyone checks it |
Failure modes and what to check
- Empty or partial candidate list. Log the count of URLs per sitemap. A sudden drop usually means the request returned an error page or a cached file.
- Model returns URLs outside the list. The validation gate removes them. Log how many were rejected, since a rising count signals a prompt or model problem.
- Anchors that do not match the content. Review a sample of drafts each week. Automated checks cannot judge whether a link genuinely helps a reader.
- Language mismatch. On multilingual sites, restrict candidates to the post’s language before calling the model.
- Duplicate links. Check the existing post for links to the same destinations and skip them.
- Credential or permission errors. A 401 or 403 from the WordPress node usually means the application password, user role or REST API access is wrong.
What the evidence does and does not establish
The DEV Community article is the source for the specific design, and its code and cost claims are the author’s own. The source calls the approach production-ready and links it to SEO benefits. No independent testing, crawl measurements or ranking results were available for this workflow, so treat both statements as the author’s framing. n8n’s documentation supports the WordPress node operations and the credential types described above. A separate n8n workflow template uses sitemap data for internal linking, which shows the broader pattern is used in templates, but it does not show that this exact design produces better results.
Pricing for Gemini 2.5 Flash is not stated here. The source’s per-run cost estimate depends on token prices and assumptions that change, so compare it against Google’s current Gemini API pricing page for your own volume.
Recommended Free Tools
The Bottom Line
The pattern is sound for a controlled rollout: sitemaps supply the candidate destinations, Gemini chooses among them and writes anchors, and your own validation decides what reaches WordPress. Start with drafts, log every rejection, and expand to live posts only after a manual review of the output.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




