=== Linkmender – Broken Link Scanner ===
Contributors: prayasa
Tags: broken links, link checker, orphan pages, 404, redirects
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Find and fix broken links, redirects, missing images and orphan pages. 100% local: no cloud service, no external API, nothing leaves your site.

== Description ==

Linkmender scans the published content on your site, checks every link and image it finds, and shows you what is broken, what redirects, and what needs a second look. Then it lets you fix things without leaving the results screen.

Everything runs on your own server. There is no account to create, no API key, no usage quota and no data sent to a third party.

**What it checks**

* `<a href>` links (internal and external) and `<img src>` images in posts, pages and public custom post types
* Optionally, links stored in custom fields (post meta)
* In-page anchors (`#section`) are recorded but not fetched

**What you get**

* A dashboard with counts of broken links, redirects, warnings and orphan pages
* An **Orphan pages** tab listing published pages that nothing on your site links to
* A sortable, searchable results table with status and type filters
* Row and bulk actions: **Recheck**, **Edit URL** (replaces the URL inside the post), **Unlink** (removes the tag, keeps the text), **Ignore / Unignore**
* A WordPress Dashboard widget with the current link health
* A "Last full scan" indicator and a progress bar while a scan runs

**How it stays lightweight**

* Scans run in the background in small batches (20 URLs per run by default) using WP-Cron single events
* Keeping the Linkmender screen open acts as a keep-alive so scans progress even on sites where WP-Cron is slow
* Each URL is checked once per scan even if it appears in many posts
* `HEAD` requests first, with a small ranged `GET` fallback for servers that refuse `HEAD`
* Network errors are retried with exponential back-off before a link is marked broken
* Content is re-parsed automatically when a post is saved, so results stay current between scans

**Orphan pages**

An orphan is a published post or page that no other post on your site links to. Readers and search engines can usually only reach it through your sitemap, so it tends to be overlooked no matter how good it is. Linking to it from a relevant post is normally all it takes.

Linkmender builds this from the internal links it already found during a scan, so finding orphans costs no extra requests — it is a query, not a crawl.

Be aware of one limit: Linkmender reads links from post content and, when enabled, custom fields. Navigation menus, widgets and theme templates are **not** scanned, so a page linked only from your menu is still listed as an orphan. Add such pages to **Settings → Exclude post IDs** to silence them. Your front page and blog posts page are excluded automatically.

**Statuses**

* **OK** — 2xx response
* **Redirect** — 3xx response; the redirect target is recorded
* **Broken** — 4xx/5xx response, or unreachable after 3 attempts
* **Warning** — a network error that will be retried

**Privacy**

Linkmender only ever contacts the URLs that appear in your own content, from your own server, with a clear user agent. It does not phone home, does not collect analytics and does not display promotional notices.

**Extending**

Developers can hook into the plugin: `lmnd_parsed_links`, `lmnd_pre_check_url`, `lmnd_check_result`, `lmnd_http_args`, `lmnd_scan_complete`, `lmnd_link_checked`, `lmnd_bulk_action`, `lmnd_row_actions`, `lmnd_admin_tabs`, `lmnd_pro_features`, `lmnd_link_target_post_id`, `lmnd_orphan_excluded_posts`, `lmnd_orphan_row_actions` and more.

== Installation ==

1. Upload the `linkmender` folder to `/wp-content/plugins/`, or install it from the Plugins screen.
2. Activate the plugin.
3. Go to **Tools → Linkmender** and click **Scan now**.

== Frequently Asked Questions ==

= Does this send my links to an external service? =

No. Every request is made from your own server with the WordPress HTTP API. The plugin never contacts any server other than the URLs found in your content.

= Will scanning slow down my site? =

Scans run in small batches with a configurable pause between them, and never run longer than about 40 seconds in one go. You can lower the batch size on shared hosting.

= A working site is reported as broken. Why? =

Some sites block automated requests (LinkedIn, some CDNs, some bot-protection services). Add such domains to **Settings → Exclude domains**, or set a browser-like user agent under **Settings → User agent**.

= What does "Unlink" do? =

For a text link it removes the `<a>` tag and keeps the link text. For an image it removes the `<img>` tag. The change is saved to the post like a normal edit, so it appears in the post's revision history.

= Does it check links inside page builders or widgets? =

It checks the rendered HTML stored in `post_content`, which covers the block editor, the classic editor and most page builders that store HTML. Builders that store their layout only as shortcodes or JSON in post meta are covered by the "Also scan custom fields" option when the meta contains HTML or a bare URL.

= What is an orphan page, and why does it matter? =

An orphan page is a published post or page that nothing else on your site links to. Search engines discover pages largely by following links, so an orphan is crawled less and ranks worse than its content deserves. The fix is editorial: link to it from a post where it is genuinely relevant.

= Why is a page listed as an orphan when it is in my menu? =

Linkmender reads links from post content (and custom fields, when that option is on). It does not scan navigation menus, widgets or theme templates, so a page reachable only from your menu still counts as an orphan here. Add its ID to **Settings → Exclude post IDs** to hide it. The front page and the blog posts page are excluded for you.

= The Orphan pages tab says to run a scan first. =

Orphan detection is built from the internal links recorded during a scan. Before the first full scan finishes there is no link graph, so every page would look orphaned — the tab asks you to scan rather than show you a misleading list. This also applies right after upgrading from 1.0.x, which did not record the link graph.

= Is there a Pro version? =

Not yet. The **Pro** tab lists what is planned. The free version is complete and will stay free.

= What happens when I delete the plugin? =

Scheduled events are removed. The results table and settings are kept unless you enable **Settings → Delete the links table and all settings when the plugin is deleted**.

== Screenshots ==

1. Dashboard: link health cards, scan controls and the results table.
2. Row actions: Recheck, Edit URL, Unlink, Ignore.
3. Settings: batch size, pause, timeout, exclusions.
4. Orphan pages: published pages that nothing on your site links to.

== Changelog ==

= 1.1.0 =
* New: **Orphan pages** tab listing published pages that no other post links to, with a count on the dashboard. Built from the links already collected during a scan, so it costs no extra requests.
* New: internal links are now resolved to the post they point at, giving Linkmender an internal link graph.
* Fixed: internal images were classified only as images, so they were missing from internal-link reporting. They are now tracked as both.
* Fixed: editing a link's URL did not update whether it was internal or which post it pointed at, which could leave stale internal-link data behind.
* Developers: new `lmnd_link_target_post_id`, `lmnd_orphan_excluded_posts` and `lmnd_orphan_row_actions` filters.

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 1.1.0 =
Adds orphan page detection. Run one full scan after upgrading to build the internal link graph; the Orphan pages tab will prompt you until you do.

= 1.0.0 =
Initial release.
