{"id":379997,"date":"2026-10-06T12:21:48","date_gmt":"2026-10-06T12:21:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/hrefhub\/"},"modified":"2026-10-06T12:21:24","modified_gmt":"2026-10-06T12:21:24","slug":"hrefhub","status":"publish","type":"plugin","link":"https:\/\/am.wordpress.org\/plugins\/hrefhub\/","author":16133903,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.7.1","stable_tag":"1.7.1","tested":"7.1.3","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"HrefHub","header_author":"Keshab Adhikari","header_description":"Every link on your site in one table \u2014 grouped by destination URL, status-checked, and changeable everywhere at once.","assets_banners_color":"f8faf8","last_updated":"2026-10-06 12:21:24","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/topnewthings.com\/?utm_source=hrefhub&utm_medium=plugin&utm_campaign=plugin-uri","header_author_uri":"https:\/\/topnewthings.com\/?utm_source=hrefhub&utm_medium=plugin&utm_campaign=author","rating":0,"author_block_rating":0,"active_installs":0,"downloads":92,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.7.1":{"tag":"1.7.1","author":"kesadh","date":"2026-10-06 12:21:24","revision":3730767}},"upgrade_notice":{"1.0.0":"<p>First release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3730767,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3730767,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3730767,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3730767,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.7.1"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"The link inventory, grouped by destination URL.","2":"The confirmation preview before a change is written.","3":"Filtering to redirecting links before a bulk fix."}},"plugin_section":[],"plugin_tags":[14279,14280,175,726,12126],"plugin_category":[],"plugin_contributors":[282896],"plugin_business_model":[],"class_list":["post-379997","plugin","type-plugin","status-publish","hentry","plugin_tags-broken-links","plugin_tags-link-checker","plugin_tags-links","plugin_tags-redirects","plugin_tags-search-replace","plugin_contributors-kesadh","plugin_committers-kesadh"],"banners":{"banner":"https:\/\/ps.w.org\/hrefhub\/assets\/banner-772x250.png?rev=3730767","banner_2x":"https:\/\/ps.w.org\/hrefhub\/assets\/banner-1544x500.png?rev=3730767","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/hrefhub\/assets\/icon-128x128.png?rev=3730767","icon_2x":"https:\/\/ps.w.org\/hrefhub\/assets\/icon-256x256.png?rev=3730767","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>You changed a URL. Now it is wrong in forty-seven posts and you have no list of\nwhich ones.<\/p>\n\n<p>Broken link plugins tell you what is broken. Search-and-replace plugins swap a\nstring across your database and hope. Neither of them shows you what you actually\nhave. HrefHub is the link <strong>inventory<\/strong>: every link on the site, grouped by\nwhere it points, with the number of places it appears and what happens when you\nfollow it.<\/p>\n\n<p>Then it lets you change one of them everywhere, in one action.<\/p>\n\n<h4>What it does<\/h4>\n\n<ul>\n<li>Lists every link found in post content and Gutenberg blocks, grouped by destination URL<\/li>\n<li>Shows how many places each URL appears, and which posts they are<\/li>\n<li>Checks HTTP status and counts the redirect chain, so \"three redirects\" reads differently from \"404\"<\/li>\n<li>Filters by status, internal or external, host, post type, and anchor text<\/li>\n<li>Changes a URL everywhere it appears, with a confirmation preview first<\/li>\n<li>One-step undo of the last change<\/li>\n<li>Bulk action: replace every redirecting URL with its final destination<\/li>\n<li>CSV export of whatever you are currently looking at<\/li>\n<\/ul>\n\n<h4>The one that saves an afternoon<\/h4>\n\n<p>Sites accumulate redirects. A link you added three years ago now goes through two\nor three hops before it lands. Filter to <strong>Redirecting<\/strong>, select all, and choose\n<em>Replace redirects with their final destination<\/em>. Every one of them is rewritten\nto point straight at where it already ends up.<\/p>\n\n<h4>What gets scanned<\/h4>\n\n<p>This version reads:<\/p>\n\n<ul>\n<li>All public post types, plus reusable blocks \u2014 untick any you do not want under <em>HrefHub \u2192 Settings<\/em><\/li>\n<li><code>post_content<\/code> HTML anchors<\/li>\n<li>Gutenberg block attributes \u2014 button URLs, image links, cover backgrounds and so on<\/li>\n<\/ul>\n\n<p>This version does <strong>not<\/strong> read links stored by page builders (Elementor), custom\nfield plugins (ACF), navigation menus, widgets, theme options or FSE templates.\nThey are not listed and they are not changed. The admin screen states this too,\nso you always know what the numbers cover.<\/p>\n\n<p>Pages built with Elementor, Beaver Builder or Bricks are skipped as a whole. The\nbuilder displays them from its own data, and the copy it leaves in post content\nis not what visitors see, so changing links there would change nothing. The admin\nscreen shows how many were skipped.<\/p>\n\n<h4>Careful by default<\/h4>\n\n<p>This plugin edits your content, so it is built to be boring about it:<\/p>\n\n<ul>\n<li>A preview before every write, showing exactly how many occurrences in how many posts<\/li>\n<li>A snapshot of every post before it is touched, and a one-click undo<\/li>\n<li>Post revisions are left switched on, as a second safety net<\/li>\n<li>No link is called broken until it has failed twice \u2014 403, 429 and 503 get a \"needs review\" state instead, because a bot filter is not a dead link<\/li>\n<li>Your own site's links are resolved internally rather than fetched over HTTP, which is faster and avoids loopback stalls<\/li>\n<li>Scanning runs in small batches, so it finishes on managed hosts that kill long requests<\/li>\n<\/ul>\n\n<h4>Privacy<\/h4>\n\n<p>HrefHub makes HTTP requests to the URLs found on your site in order to check\ntheir status. It sends no data anywhere else, has no external API, and does not\nphone home.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>hrefhub<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install through Plugins \u2192 Add New.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Open <strong>HrefHub<\/strong> in the admin menu and click <strong>Scan site<\/strong>. It collects every link, then checks each one's status.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"will%20it%20find%20links%20inside%20elementor%20or%20acf%3F\"><h3>Will it find links inside Elementor or ACF?<\/h3><\/dt>\n<dd><p>Not in this version. Those live in serialized meta and JSON rather than post\ncontent, and reading \u2014 and more importantly, safely writing \u2014 them is a separate\npiece of work. The plugin never claims to have scanned them: pages built with\nElementor are skipped entirely, and the admin screen tells you how many.<\/p><\/dd>\n<dt id=\"is%20a%20bulk%20change%20reversible%3F\"><h3>Is a bulk change reversible?<\/h3><\/dt>\n<dd><p>The last change is, in one click. Every post is snapshotted before it is written,\nand undo restores it \u2014 unless you have edited that post since, in which case it is\nskipped rather than overwriting your work. Post revisions give you a second route\nback.<\/p><\/dd>\n<dt id=\"why%20is%20a%20link%20marked%20%22needs%20review%22%20instead%20of%20broken%3F\"><h3>Why is a link marked \"needs review\" instead of broken?<\/h3><\/dt>\n<dd><p>Because the server answered in a way that does not prove the link is dead. Cloudflare\nchallenges, rate limits and bot filters all look like failures and are not. Nothing\nis flagged broken until it has failed twice.<\/p><\/dd>\n<dt id=\"does%20it%20slow%20my%20site%20down%3F\"><h3>Does it slow my site down?<\/h3><\/dt>\n<dd><p>No. Scans run in the admin screen on demand, and the only other work is a quick local re-read of a post's links when it is saved, trashed or deleted. Nothing hooks the front end.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20uninstall%3F\"><h3>What happens when I uninstall?<\/h3><\/dt>\n<dd><p>Its three database tables and all its options are removed.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.7.1<\/h4>\n\n<ul>\n<li>Re-checking selected links from the bulk actions no longer keeps the page loading until every link is done: they are checked a few at a time with a progress bar, the last link checked, a Stop button and a summary.<\/li>\n<li>Stopping \"Check links\" part-way no longer leaves links with a status but \"Last checked: never\". Each link keeps its real check date.<\/li>\n<\/ul>\n\n<h4>1.7.0<\/h4>\n\n<ul>\n<li>Everything HrefHub shows now sits in one panel, with its own header and its own message style, so its messages no longer mix with other plugins' notices at the top of the page.<\/li>\n<\/ul>\n\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>The Issues view is split into two sections \u2014 Broken, then Needs review \u2014 each with a short note on what to do.<\/li>\n<li>The Status column now explains each link in plain words (\"Page not found\", \"Timed out\", \"Blocked by Cloudflare \u2014 not a dead link\") instead of raw server messages, which stay available on hover.<\/li>\n<li>A link that has failed once now says it will be confirmed on the next check, so a 404 is never silently waiting.<\/li>\n<li>A \"Review N issues\" button at the top goes straight to everything that needs fixing.<\/li>\n<li>All \/ Internal \/ External is now a one-click switch above the table.<\/li>\n<li>The summary cards show how many problem links are on this site and how many point elsewhere.<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Cleaner top of the screen: one status line (last scan, posts, links and the places they appear), and three buttons \u2014 Scan site, Check links, Export CSV \u2014 that give way to a single Stop button while a scan runs.<\/li>\n<li>Summary cards ordered by severity \u2014 Broken, Needs review, Redirects, Links found \u2014 with a plain explanation of what \"Needs review\" means.<\/li>\n<li>New Issues filter: broken, needs-review and unreachable links together.<\/li>\n<li>Each row has a visible \"Change URL\" button; Re-check, Ignore and Unlink are in a small menu beside it.<\/li>\n<li>Status labels carry an icon as well as a colour, and blue is now used only for buttons and links.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Changing a URL now opens a proper dialog: type the new URL, preview every post that will change, then confirm. Errors show in the dialog instead of browser pop-ups.<\/li>\n<li>Unlink asks for confirmation in a dialog that says how many places the link will be removed from.<\/li>\n<li>New \"Check all links now\" button re-checks every link without waiting for the weekly re-check.<\/li>\n<li>A status line shows when the site was last scanned and when links are next due for a check.<\/li>\n<li>Scan and check progress now has a progress bar, and a run with nothing to check says so instead of reloading straight away.<\/li>\n<li>The summary counts are cards that filter the table to broken, redirecting or needs-review links.<\/li>\n<li>A clearer first screen before the first scan, and a message after Undo saying what was restored.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Scanning now reports progress in two labelled steps: reading posts (with the number of links found so far), then checking link status.<\/li>\n<li>Link checking shows how many are due before it starts, how many are done, the last link checked and its result, and why the remaining links are not being checked.<\/li>\n<li>Links are checked in smaller batches, so the progress count moves steadily.<\/li>\n<li>A summary is shown when a scan finishes or is stopped: posts read, links found, links checked, and the current number of broken, redirecting and needs-review links.<\/li>\n<\/ul>\n\n<h4>1.2.9<\/h4>\n\n<ul>\n<li>After changing or unlinking a URL, a message now says how many posts were changed and, when a run stops at its 50-post limit, how many still use the link.<\/li>\n<li>Unlink now follows the same 50-posts-per-run limit as changing a URL.<\/li>\n<li>The change preview counts every post that uses the link, not just the first few hundred.<\/li>\n<li>CSV export now includes every link in the current view instead of stopping at 5,000.<\/li>\n<li>Scan and check progress now say what is being counted, and how many links were skipped from checking and why.<\/li>\n<\/ul>\n\n<h4>1.2.8<\/h4>\n\n<ul>\n<li>Pages built with Elementor, Beaver Builder or Bricks are no longer scanned or changed. Those builders display a page from their own data, so a change to its post content was reported as done but never reached visitors. The admin screen now says how many were skipped.<\/li>\n<li>Unlink no longer removes the link from a button block, which left the block invalid, and now also finds relative links.<\/li>\n<li>Link checks refuse private and local network addresses, and never download more than a few kilobytes of a page.<\/li>\n<li>The change-URL preview can now be translated.<\/li>\n<li>Uninstalling also removes the saved \"links per page\" screen option.<\/li>\n<\/ul>\n\n<h4>1.2.7<\/h4>\n\n<ul>\n<li>Updated author details.<\/li>\n<\/ul>\n\n<h4>1.2.6<\/h4>\n\n<ul>\n<li>Admin notices after saving settings or running a bulk action are now stored on the server instead of being passed in the page address.<\/li>\n<\/ul>\n\n<h4>1.2.5<\/h4>\n\n<ul>\n<li>Code hardening for the WordPress.org Plugin Check: every database query now passes table names through <code>$wpdb-&gt;prepare()<\/code>, and every AJAX request verifies its security token before reading any input.<\/li>\n<li>Tested up to WordPress 7.1.<\/li>\n<\/ul>\n\n<h4>1.2.4<\/h4>\n\n<ul>\n<li>Links to your own archives \u2014 custom post type archives, category, tag and author pages \u2014 are now resolved properly instead of reported as \"could not be resolved\". Links to files such as PDFs and images are recognised too.<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>A link refused by Cloudflare, Akamai, Imperva, Sucuri, DataDome or AWS WAF now says which service blocked it, instead of a generic \"blocked by the host\". These are bot filters, not dead links \u2014 the page usually loads fine in a browser.<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Scan site now checks link status too, straight after collecting links, with a progress count and a Stop button. The separate <em>Check link status<\/em> button is gone. A scan only re-checks links that are new or were last checked more than 7 days ago.<\/li>\n<li>Saving a post updates its links in the inventory straight away. New links are checked on the next scan.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Fix: links in trashed or deleted posts stayed in the inventory, and replace-everywhere could still rewrite them. Trashing or deleting a post now removes its links straight away, and restoring it from the trash scans it again.<\/li>\n<li>Fix: a full scan now drops links recorded for posts it no longer reaches, so rows left behind by earlier versions are cleaned up.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>New Settings screen: choose which post types are scanned, with a count of each. Unticking a type removes its links from the inventory straight away; post types added later by other plugins are scanned by default.<\/li>\n<li>Fix: links were re-checked early or late by the site's UTC offset, because the last-checked time was stored in site time but compared in UTC. Old undo snapshots were pruned on the same shifted schedule.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release: link inventory from post content and Gutenberg blocks, status and redirect checking, replace-everywhere with preview and one-step undo, bulk redirect flattening, CSV export.<\/li>\n<\/ul>","raw_excerpt":"Every link on your site in one table. Change a URL once and it changes in all 47 places it appears \u2014 with a preview before and an undo after.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/379997","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=379997"}],"author":[{"embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/kesadh"}],"wp:attachment":[{"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=379997"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=379997"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=379997"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=379997"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=379997"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/am.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=379997"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}