=== Rotbane – Broken Link Checker ===
Contributors: codinglabe
Tags: broken links, link checker, seo, redirects, 404
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Find and fix broken links, 404s, soft 404s and redirects in WordPress. No account, no link limits, and every check runs on your own site.

== Description ==

Rotbane is a free broken link checker for WordPress. It scans the links and images in your posts, pages, menus, widgets, and comments, reports broken links, 404 errors, soft 404s, redirects, and missing anchors with a plain-language reason, and lets you fix them without opening every post.

**No account, no credit card, no link limits, checks run on your own site.** Every check runs from your WordPress server, so there is nothing to sign up for and no cap on how many links it checks.

The scan runs in small, paced batches through WP-Cron, resumes if it is interrupted, and keeps the results in Rotbane's own database tables. Nothing is added to your public pages: no front-end scripts or styles.

It tells broken links apart from links a host merely refused to check. Amazon, LinkedIn, X, Medium, SSRN, and doi.org have built-in rules so a robot check or an expected DOI redirect is not reported as a dead link. A page that returns HTTP 200 but says “page not found” is reported as a soft 404, with a plain-language reason on every result.

By default Rotbane does not change the front end. Redirects, slug watching, and URL edits happen only when you ask for them. URL edits replace the quoted address, so surrounding attributes stay intact.

Nothing in the free plugin phones home. The only outbound requests are the link checks you start, including an oEmbed lookup when a YouTube or Vimeo URL needs to be confirmed, and the optional webhook alert you configure yourself.

= What it checks =

* Posts, pages, custom post types, comments, menus, widgets, excerpts, and block templates
* Optional allow-listed custom fields
* Internal and external links, images, and video embeds
* Mixed content (HTTP on an HTTPS site)
* Soft 404s and redirect chains: “not found” text in more than 30 languages, pages that use the site’s 404 template, deep links that land on a home page, and your own phrases
* SSL certificate problems (expired, self-signed, wrong name, untrusted), reported as their own status
* Links to your own posts that visitors cannot open yet: drafts, pending, scheduled, private, or trashed posts. These are rechecked automatically when the post is published or restored
* Missing anchors: a link such as `/pricing/#plans` whose page loads but no longer has a `plans` section

= What you can do with a result =

* Read why Rotbane chose that status
* Ignore a domain in one click
* Update a URL everywhere it appears, or point it at the final redirect
* Unlink, mark as not broken, or recheck
* Create a same-site 301 for a broken internal path
* Export a CSV

Email, when you turn it on, reports links that break after the first completed scan. It does not mail the whole backlog.

An optional webhook alert works the same way: when it is on, Rotbane posts a short JSON message to the https:// address you enter, only for problems that are new since the last alert. It works with Slack and Discord incoming webhooks, Zapier, Make, and n8n. Private, local, and cloud metadata addresses are refused.

= Redirects for 404 pages =

* Create a same-site 301 redirect for a broken internal path from the link's page, in bulk, or on the Redirects screen.
* A redirect runs only when WordPress would otherwise show a 404, so real pages are never overridden. Loops, off-site targets, and core paths such as /wp-admin are refused.
* Optional slug watcher: when you change the slug of a published post or page, Rotbane saves a 301 from the old address.
* Each redirect counts its hits.

= Light on your server =

* Three links at a time by default, a delay between requests to the same domain, and a timeout you can set.
* Links to your own posts are resolved from the database where possible, without an HTTP request.
* A failure is rechecked before it is reported, so a slow answer is not called broken.
* Slow host mode for small shared hosting plans. Settings are stored without autoload.

= WP-CLI and the Abilities API =

* `wp rotbane scan`, `wp rotbane status`, `wp rotbane list --status=broken`, `wp rotbane show <id>`, `wp rotbane recheck --status=broken`, and `wp rotbane export`.
* On WordPress versions with the Abilities API, Rotbane registers read-only abilities (summary, list links, get one link) and a recheck ability for AI assistants and automation tools. Each checks the same Rotbane permissions as the admin screens. Nothing is registered on older WordPress versions.

Documentation and guides: [rotbane.forgestacks.net/docs](https://rotbane.forgestacks.net/docs/)

Rotbane Pro is a separate plugin for agencies: scheduled white-label reports, an agency hub, Search Console, per-client alert channels, repurposed-domain detection, site migration checks, and an affiliate link audit. The free plugin does not require it, and nothing in the free plugin is locked.

= Missing anchors =

A link with a #fragment should land on the element with that id (or an `<a name>`). When the page loads but that element is not there, Rotbane shows **Missing anchor**: a warning, not a broken link, with the reason on the result.

* Your own pages are checked from the stored content first, then from the published page itself, which is requested once through the same safe HTTP path as every other check and remembered for ten minutes.
* Anchors on other websites are not checked unless you turn that on in Settings → Anchors. Then the check for such a link is one GET request instead of HEAD, and Rotbane reads up to 1 MB of the page.
* `#top`, empty `#`, `#!` and `#/` app routes, text fragments (`#:~:text=`), and `#name=value` fragments are skipped. Ids are matched exactly, so `#Plans` and `#plans` are different, as in browsers.

== External services ==

Rotbane does not send data to any service of its own. A link check requests the checked URL from the host in that URL. The request carries a User-Agent header, by default `Rotbane/<version> (+<your site address>)`, which you can change in Settings. The host also sees your server's IP address.

Two links are checked through a third-party oEmbed endpoint instead of the page itself. A removed or private video still returns a normal-looking page, and the oEmbed endpoint tells Rotbane whether the video is really there.

**YouTube oEmbed (Google)**

* What it is used for: confirming that a linked or embedded YouTube video still exists.
* What is sent: the video URL, rebuilt from its id as `https://www.youtube.com/watch?v=<id>`, to `https://www.youtube.com/oembed`, along with the User-Agent described above.
* When: only while a scan or recheck is checking a YouTube link (youtube.com, youtu.be, youtube-nocookie.com, m.youtube.com, or music.youtube.com) found in your content. Nothing is sent if your content has no YouTube links.
* Terms of Service: [https://www.youtube.com/t/terms](https://www.youtube.com/t/terms)
* Privacy Policy: [https://policies.google.com/privacy](https://policies.google.com/privacy)

**Vimeo oEmbed**

* What it is used for: confirming that a linked or embedded Vimeo video still exists.
* What is sent: the video URL, rebuilt from its id as `https://vimeo.com/<id>`, to `https://vimeo.com/api/oembed.json`, along with the User-Agent described above.
* When: only while a scan or recheck is checking a Vimeo link found in your content. Nothing is sent if your content has no Vimeo links.
* Terms of Service: [https://vimeo.com/terms](https://vimeo.com/terms)
* Privacy Policy: [https://vimeo.com/privacy](https://vimeo.com/privacy)

**Your webhook (optional)**

* What it is used for: telling you about new broken links in a chat or automation tool you choose.
* What is sent: a JSON message with your site name and address, the new problem URLs, their status, HTTP code, reason, and a link to the Rotbane screen.
* Where: only to the https:// address you enter in Settings → Webhook alert. Rotbane has no webhook service of its own; the terms and privacy policy are those of the service you choose (for example Slack, Discord, Zapier, Make, or n8n).
* When: only when the setting is on, after a scan confirms problems that are new since the last alert, or when you press “Send a test message”. It is off by default.

Apart from these two oEmbed lookups and your own webhook, Rotbane only requests the URLs it is checking (plus any redirects they lead to). To confirm a #anchor on one of your own pages, it may also request that page from your own site. It has no analytics, telemetry, or license calls, and it loads no remote scripts, fonts, or images in the admin.

== Installation ==

1. Upload the `rotbane` folder to `/wp-content/plugins/`, or install the zip from Plugins → Add New.
2. Activate Rotbane.
3. Open Rotbane and start a scan.
4. Review Settings before you enable email or front-end redirects.

== Frequently Asked Questions ==

= Does Rotbane send my links to its own server? =

No. Checks run from your site with the WordPress HTTP API. There is no account, no quota, and no telemetry in the free plugin.

= Will it change my public site? =

Not by default. Automatic homepage redirects and the slug-change watcher are off until you enable them. A redirect you save only runs when a visitor hits a 404 on that path.

= What is a soft 404? =

Some sites answer “page not found” with HTTP 200. Rotbane reads a short title or body and reports that as broken, with the reason “soft 404”, instead of calling the link OK.

= Why does a link to my own post say Not public? =

The post is a draft, pending review, scheduled, private, or in the Trash, so visitors get a “not found” page. Rotbane names the post and rechecks the link by itself as soon as the post is published or restored.

= How do webhook alerts avoid spam? =

Each problem is sent once. The first completed scan sets a baseline, so turning alerts on does not send the backlog, and scans with nothing new send nothing.

= Why is a link Blocked instead of Broken? =

A 401, 403, 429, or a challenge page means the host refused the checker. LinkedIn, X, Medium, SSRN, and Amazon robot checks stay in Blocked so you do not “fix” a link that still works in a browser.

= What does Missing anchor mean? =

The page works, but the section the link points at (the part after #) is not on it, so visitors land at the top of the page. It usually means a heading was renamed. Edit the link to the new #id, or remove the fragment. Missing anchors are warnings and are not included in the broken-link email.

= Why was an anchor on another site not checked? =

Checking anchors on other websites is off by default, because sites that build their pages with JavaScript can add sections after the page loads and would show false warnings. Turn it on in Settings → Anchors.

= Does a DOI link count as broken when it redirects? =

No. doi.org is supposed to redirect to the publisher. When the identifier resolves, Rotbane marks it OK and explains that.

= Does the scan block page views? =

No. Work is queued in WP-Cron and on the dashboard progress bar, a batch at a time. You can pause it and it resumes.

= What happens to my data if I delete the plugin? =

Deactivation clears Rotbane’s scheduled jobs. Deletion removes its tables and settings unless you uncheck that option first. Options are stored without autoload.

== Screenshots ==

1. The dashboard: every checked link counted by status, the scan progress, and the links table.
2. The links list filtered to broken links, with a plain-language reason on every row, including soft 404s.
3. A link's detail page: the reason, the final address of a redirect, and the fixes (Update to final URL, Recheck, Unlink everywhere).
4. Settings: choose which content, post statuses and parts of the site are scanned.
5. Links to private or trashed posts shown as Not public, next to timeouts and SSL certificate errors.

== Changelog ==

= 1.1.1 =
* Links list: the Recheck and Ignore domain row buttons are now spaced apart instead of running together.

= 1.1.0 =
* Soft 404 detection v2: the site’s 404 template, deep links that redirect to a home page (can be turned off), “not found” phrases in more than 30 languages, and your own phrases.
* New SSL error status, with a plain reason for expired, self-signed, wrong-name, and untrusted certificates.
* New Not public status for links to drafts, pending, scheduled, private, and trashed posts, with automatic recheck when the post is published or restored.
* Optional webhook alert for new problems only (off by default, public https:// addresses only, SSRF-guarded).
* WP-CLI: new `list`, `show`, and `recheck` commands.
* Abilities API support on WordPress versions that include it.
* Bengali (bn_BD) translation updated.

= 1.0.0 =
* First release.
* Broken links, redirects, blocked hosts, soft 404s, mixed content, and video embeds, each with a plain-language reason.
* Missing anchor status for links whose #section is not on the target page. Same-page (#id) and same-site (/page/#id) links are checked; other sites optionally (Settings → Anchors).
* Missing anchors have their own card, filter, badge, and "Why?" explanation, an Anchor column in the CSV export, and a summary line in the email digest. The block editor panel lists them too.
* Bengali (bn_BD) translation.

== Upgrade Notice ==

= 1.1.1 =
Small admin fix: the Recheck and Ignore domain buttons in the links list are spaced apart again.

= 1.1.0 =
Better soft 404 detection, SSL error and Not public statuses, optional webhook alerts, and new WP-CLI commands. Existing problems are not re-sent as alerts.

= 1.0.0 =
First release.
