SEO Internal Linker
Automatically link key phrases to target pages the first time they appear in WordPress posts — a lightweight, self-hosted alternative to manual internal linking for SEO.
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/eaybes/seo-internal-linker/archive/refs/heads/main.zipReadme
SEO Internal Linker
A WordPress plugin that automatically turns the first occurrence of a defined phrase in a post into a link to a target page, and generates a friendly, SEO/AEO-optimised TL;DR summary at the top of each post via the Gemini API — all without touching render time.
Created by Elad Aybes.
Table of Contents
- Features
- How It Works
- Installation
- Usage
- Matching Rules
- Security
- Database Schema
- Hooks Reference
- FAQ
- Changelog
- License
Features
Internal linking
- Automatic first-occurrence linking — define a phrase and a target URL once; the plugin links the first plain-text appearance of that phrase in each post.
- Runs on posts by default — enabled automatically for the
postpost type. - Opt-in for pages — disabled by default on
page, with a per-page checkbox to enable it. - Per-post opt-out — disable automatic linking on an individual post via a checkbox in the editor sidebar.
- Per-phrase override per post — uncheck any phrase in the post meta box to stop it being linked on that specific post, without affecting any other post.
- Manual-unlink detection — if an editor manually deletes an auto-inserted link, the plugin detects this on the next save and adds that phrase to the skip list so it won't snap back.
- Skips headings and existing links — a phrase already inside an
<h1>–<h6>or any existing<a>counts as "used" and won't receive a duplicate link. - Live usage statistics — each phrase tracks how many posts currently carry an auto-generated link to it, updated in real time as content is created, edited, or deleted.
- Configurable link behavior — optionally open auto-inserted links in a new tab (
target="_blank" rel="noopener noreferrer").
TL;DR Auto-Summary
- AI-generated summaries — on post save, the plugin calls the Gemini API to produce up to 5 friendly, keyword-rich bullet points summarising the article.
- SEO + AEO optimised — bullets are written as standalone, complete sentences designed to rank in search results and surface in voice search / AI answer engines.
- Schema.org markup — the TL;DR box renders as an
ItemListwithitemscope/itempropattributes giving structured-data signals to search engines. - Opt-in for pages — TL;DR is on by default for posts and can be enabled per-page via the editor sidebar.
- Stored in post meta — TL;DR content lives in
_sil_tldr_bullets, keeping it completely separate frompost_contentso it never interferes with the internal linker. - Fully editable — clear and regenerate via the editor sidebar's "Clear TL;DR" button; the next save will regenerate from the latest content.
- Graceful fallback — if no API key is configured, TL;DR generation is silently skipped with no errors.
General
- RTL / Hebrew-safe — all string matching and DOM manipulation uses multibyte-safe functions.
- Batched background rescanning — re-apply the phrase list to all existing content via WP-Cron in batches of 20, without timing out on large sites.
- Hardened against malicious input — URLs restricted to
http/httpsat multiple layers; all output escaped; every action nonce- and capability-protected.
How It Works
- You define phrase → target URL pairs in the plugin's admin screen.
- When a post (or enabled page) is saved:
- The plugin parses the content into a DOM tree and links the first plain-text occurrence of each phrase (longest-first to avoid partial matches).
- Occurrences inside headings or existing links are counted as "used" — no second link is added.
- The rewritten
post_contentis stored permanently in the database.
- If a Gemini API key is configured, the plugin also calls the Gemini API and stores up to 5 TL;DR bullet points in post meta.
- On the front end, the TL;DR box is injected at the top of the content via the
the_contentfilter (nopost_contentis modified), styled with a small inline CSS block.
Installation
- Upload or clone the plugin folder into
wp-content/plugins/seo-internal-linker/. - In WordPress Admin → Plugins, find SEO Internal Linker and click Activate.
- On activation, the plugin creates
wp_sil_phrasesin the database.
- On activation, the plugin creates
- A new Internal Linker menu item appears in the WordPress admin sidebar.
Installing on additional sites
Copy the plugin folder (or upload the ZIP via Plugins → Add New → Upload Plugin) to any WordPress install and activate normally. Phrases are stored per-site so you'll need to re-enter them on each new site (or migrate the wp_sil_phrases table directly).
Usage
Managing Phrases
Go to WordPress Admin → Internal Linker:
- Add new phrase — enter the exact phrase text and a target URL (
http://orhttps://only). - Existing phrases table — shows each phrase, its target, and the Active links count (how many posts currently contain an auto-generated link to it).
- Edit / Delete are available per row.
💡 Tip: Choose your anchor text strategically. Use clear, specific phrases instead of broad words or just brand names. Pick phrases that describe the linked page well and have a good chance of ranking in search results.
Settings
Under Settings on the same page:
| Setting | Description |
|---|---|
| Open links in new tab | Adds target="_blank" rel="noopener noreferrer" to all auto-inserted links. |
| TL;DR section heading | Label shown at the top of every TL;DR box (default: TL;DR 😎). |
| Gemini API key | Used to call the Gemini API for TL;DR generation. Leave blank to disable. The field is a password input that preserves the existing key if submitted empty. |
TL;DR Auto-Summary
Once a Gemini API key is entered:
- Every time a post is saved, the plugin sends the post title and content (up to ~700 words) to the Gemini API and stores up to 5 bullet points in post meta.
- Bullets appear in a styled, bordered box right at the start of the post content.
- The box includes
schema.org/ItemListstructured data for SEO/AEO. - You can preview the current bullets in the post editor's SEO Internal Linker sidebar meta box.
- Click Clear TL;DR in the sidebar to delete the stored bullets; the next save will regenerate them.
Per-Post / Per-Page Controls
The SEO Internal Linker meta box in the editor sidebar contains:
Internal linking
- Pages: checkbox to enable auto-linking (off by default).
- Posts: checkbox to disable auto-linking (on by default).
- Phrase checklist: uncheck any phrase to skip it on this specific post/page. Manually removed links are added here automatically.
TL;DR Summary
- Pages: checkbox to enable TL;DR (off by default).
- Posts: checkbox to disable TL;DR (on by default).
- Preview of current bullet points + Clear TL;DR button.
Rescanning Existing Content
After adding, editing, or deleting phrases, existing posts won't be updated until you rescan:
- Click Rescan all content now on the plugin's admin page.
- The plugin queues all eligible posts/pages and processes them in batches of 20 via WP-Cron (no timeout risk on large sites).
- Progress (
X of Y processed) is shown on the admin page — reload to refresh.
Note: the rescan re-runs internal linking only. TL;DR bullets are regenerated on each individual post save, not by the rescan.
Matching Rules
- Matching is exact and case-sensitive — the phrase must appear verbatim.
- Only the first occurrence per post is linked; subsequent occurrences are left untouched.
- A phrase inside an existing
<a>tag or inside a heading (<h1>–<h6>) counts as "first occurrence" and prevents a second link being added elsewhere. - Phrases are processed longest-first so a longer phrase containing a shorter one (e.g. "climate crisis" vs. "climate") is matched before the shorter substring can claim it.
- `