{"id":378251,"date":"2026-10-06T20:36:49","date_gmt":"2026-10-06T20:36:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/magic-linking\/"},"modified":"2026-10-06T20:36:39","modified_gmt":"2026-10-06T20:36:39","slug":"magic-linking","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/magic-linking\/","author":49251,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.9.2","stable_tag":"0.9.2","tested":"7.1.3","requires":"6.9","requires_php":"8.1","requires_plugins":null,"header_name":"Magic Linking","header_author":"Color Vivo","header_description":"Find orphan pages, under-linked and over-linked entries and broken internal links. It never changes your content.","assets_banners_color":"cbcdd3","last_updated":"2026-10-06 20:36:39","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/magiclinking.com","header_author_uri":"https:\/\/colorvivo.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":93,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.9.2":{"tag":"0.9.2","author":"dcarrero","date":"2026-10-06 20:36:39","revision":3731540}},"upgrade_notice":{"0.9.2":"<p>Table schema rewritten without callable interpolation, package without development folders and clearer requirement checks on activation. No changes to your data.<\/p>","0.9.1":"<p>Documentation fix only. No functional changes.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3731540,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3731540,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3731540,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3731540,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3731540,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner.svg":{"filename":"banner.svg","revision":3731540,"resolution":false,"location":"assets","locale":false}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.9.2"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3731540,"resolution":"1","location":"assets","locale":"","width":1280,"height":960},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3731540,"resolution":"2","location":"assets","locale":"","width":1280,"height":960},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3731540,"resolution":"3","location":"assets","locale":"","width":1280,"height":960},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3731540,"resolution":"4","location":"assets","locale":"","width":1280,"height":960}},"screenshots":{"1":"The report: totals for analyzed entries, orphans, internal links and broken links, with filters, search and sorting.","2":"The Orphans filter: entries that no other entry links to, with quick Edit and View actions on each row.","3":"Broken internal links: the anchor text, the reason it is broken and the entry to edit, with CSV export.","4":"Settings and maintenance: choose the content types, adjust the thresholds and analyze everything again from scratch."}},"plugin_section":[],"plugin_tags":[14279,6681,252136,915,186],"plugin_category":[55],"plugin_contributors":[254979],"plugin_business_model":[],"class_list":["post-378251","plugin","type-plugin","status-publish","hentry","plugin_tags-broken-links","plugin_tags-internal-links","plugin_tags-orphan-pages","plugin_tags-report","plugin_tags-seo","plugin_category-seo-and-marketing","plugin_contributors-dcarrero","plugin_committers-dcarrero"],"banners":{"banner":"https:\/\/ps.w.org\/magic-linking\/assets\/banner-772x250.png?rev=3731540","banner_2x":"https:\/\/ps.w.org\/magic-linking\/assets\/banner-1544x500.png?rev=3731540","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/magic-linking\/assets\/icon.svg?rev=3731540","icon":"https:\/\/ps.w.org\/magic-linking\/assets\/icon.svg?rev=3731540","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/magic-linking\/assets\/screenshot-1.png?rev=3731540","caption":"The report: totals for analyzed entries, orphans, internal links and broken links, with filters, search and sorting."},{"src":"https:\/\/ps.w.org\/magic-linking\/assets\/screenshot-2.png?rev=3731540","caption":"The Orphans filter: entries that no other entry links to, with quick Edit and View actions on each row."},{"src":"https:\/\/ps.w.org\/magic-linking\/assets\/screenshot-3.png?rev=3731540","caption":"Broken internal links: the anchor text, the reason it is broken and the entry to edit, with CSV export."},{"src":"https:\/\/ps.w.org\/magic-linking\/assets\/screenshot-4.png?rev=3731540","caption":"Settings and maintenance: choose the content types, adjust the thresholds and analyze everything again from scratch."}],"raw_content":"<!--section=description-->\n<p>Magic Linking reads the internal links that are already written in your posts and pages and gives you a clear report:<\/p>\n\n<ul>\n<li><strong>Orphan pages<\/strong>: entries that no other entry links to.<\/li>\n<li><strong>Under-linked pages<\/strong>: entries with some inbound links, but fewer than you consider enough (2 by default, you can change it).<\/li>\n<li><strong>Over-linked pages<\/strong>: entries with more internal links than one for every 100 words (you can change that too). A short text may always have one link.<\/li>\n<li><strong>Broken internal links<\/strong>: links to an entry that is in the trash, is a draft or private, or does not exist. The complete list, with the anchor text, the reason and a link to edit the entry.<\/li>\n<li>Numbers for every entry: inbound, internal outbound, external and broken links.<\/li>\n<li>Filters, search by title, sorting, pagination and <strong>CSV export<\/strong> of the view you are looking at.<\/li>\n<li>The same report from the terminal with WP-CLI.<\/li>\n<\/ul>\n\n<p><strong>What it does not do (in this version)<\/strong><\/p>\n\n<ul>\n<li>It does not modify any content. Not a single link is added, changed or removed.<\/li>\n<li>It does not use artificial intelligence and does not call any external service.<\/li>\n<li>It does not check links over the network: a link is \"broken\" when it points to an address on your own site that leads nowhere, according to WordPress. Links to other sites are counted, not checked.<\/li>\n<li>It does not show notices anywhere except on its own screen, does not ask for your email, does not send any data out of your site and does not track you.<\/li>\n<\/ul>\n\n<p><strong>How links are counted<\/strong><\/p>\n\n<ul>\n<li>Only the links written inside the content of each entry are counted. Links in menus, widgets, theme templates or blocks that are pulled from somewhere else are not, so your home page or a page that is only linked from the menu can appear as an orphan.<\/li>\n<li>Content that a page builder keeps outside the normal post content is not read. If your builder saves rendered HTML in the post content, it is read.<\/li>\n<li>Inbound = how many different entries link to this one, counting only links that work. Outbound = internal links to other pages of your site; every appearance counts. A link to the same entry, to a file (uploads, PDF, images) or to <code>mailto:<\/code> and <code>tel:<\/code> addresses is not counted.<\/li>\n<li>Category, tag, author, date and search pages, the home page and feeds are valid destinations and are never reported as broken.<\/li>\n<li>Tracking parameters (<code>utm_*<\/code>, <code>gclid<\/code>, <code>fbclid<\/code>\u2026) and anchors (<code>#\u2026<\/code>) are ignored when matching a link to an entry.<\/li>\n<li>The language of each entry comes from WPML, Polylang or, if you use neither, from the language of the site. The language column, the language filter and the language column of the CSV only appear if WPML or Polylang is active, or if your entries are in more than one language.<\/li>\n<\/ul>\n\n<p><strong>Made for big sites<\/strong><\/p>\n\n<p>The analysis runs in the background in small batches with Action Scheduler (bundled), can be paused, resumed and cancelled, and every entry is analysed again when you save it. The front end of your site is never touched: no scripts, no styles and no database queries from this plugin on your public pages.<\/p>\n\n<p><strong>Roadmap<\/strong><\/p>\n\n<p>Later versions will add link suggestions in the editor, safe insertion of links with undo, automatic rules and, if you want it, help from the AI connectors that WordPress already provides. Nothing of that is in this version, and nothing in the plugin is locked or \"coming soon\".<\/p>\n\n<h3>Support and documentation<\/h3>\n\n<p>Documentation and news: https:\/\/magiclinking.com<\/p>\n\n<p>Questions and bug reports: use the support forum of this plugin on WordPress.org.<\/p>\n\n<h3>External services<\/h3>\n\n<p>Magic Linking does not connect to any external service.<\/p>\n\n<h3>Privacy<\/h3>\n\n<p>Magic Linking does not collect, store or send personal data. It stores, in your database, the addresses and anchor texts of the internal links found in your own content, and counts per entry. It does not set cookies.<\/p>\n\n<h3>Third-party libraries<\/h3>\n\n<ul>\n<li>Action Scheduler (WooCommerce) 4.2.x, GPL-3.0-or-later, bundled in <code>vendor\/woocommerce\/action-scheduler\/<\/code>. Used to run the analysis in the background.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin and activate it.<\/li>\n<li>Go to <strong>Magic Linking<\/strong> in the admin sidebar and press <strong>Analyze my site<\/strong>. Nothing is analysed until you do it.<\/li>\n<li>Read the report. Use the filters <em>Orphans<\/em>, <em>Under-linked<\/em>, <em>Over-linked<\/em> and <em>With broken links<\/em>, or open <em>Broken links<\/em> to fix them one by one.<\/li>\n<\/ol>\n\n<p>From the terminal: <code>wp magic-linking index<\/code> analyses the site and <code>wp magic-linking report --filter=orphans --format=csv<\/code> prints the orphan pages as CSV.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20change%20my%20posts%20or%20pages%3F\"><h3>Does it change my posts or pages?<\/h3><\/dt>\n<dd><p>No. It only reads them. The only things it writes are its own tables in your database.<\/p><\/dd>\n<dt id=\"does%20it%20need%20ai%2C%20an%20api%20key%20or%20an%20account%3F\"><h3>Does it need AI, an API key or an account?<\/h3><\/dt>\n<dd><p>No. It works entirely on your server, with no key, no account and no credit.<\/p><\/dd>\n<dt id=\"why%20does%20my%20home%20page%20%28or%20another%20page%29%20appear%20as%20an%20orphan%3F\"><h3>Why does my home page (or another page) appear as an orphan?<\/h3><\/dt>\n<dd><p>Because it is not linked from the content of any other entry. If it is linked from your menu, the menu is not counted. See \"How links are counted\".<\/p><\/dd>\n<dt id=\"why%20is%20a%20link%20not%20listed%20as%20broken%20if%20the%20page%20is%20really%20gone%3F\"><h3>Why is a link not listed as broken if the page is really gone?<\/h3><\/dt>\n<dd><p>A link is reported when it points to an entry in the trash, unpublished or private, or to an address of your site that WordPress does not recognise. If a redirect plugin sends the old address elsewhere, the link may still work for your visitors. Developers can tell Magic Linking about redirects with the <code>magiclinking_resolve_link<\/code> filter.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20wpml%20or%20polylang%3F\"><h3>Does it work with WPML or Polylang?<\/h3><\/dt>\n<dd><p>Yes. It records the language of every entry and, when WPML or Polylang is active (or the analysis finds more than one language), shows it in the report, lets you filter by it and adds it to the CSV. On a single-language site those columns are hidden.<\/p><\/dd>\n<dt id=\"how%20long%20does%20the%20first%20analysis%20take%3F\"><h3>How long does the first analysis take?<\/h3><\/dt>\n<dd><p>A few seconds for a small site; thousands of entries per minute on ordinary hosting. It runs in the background; you can keep working and watch the progress on the screen.<\/p><\/dd>\n<dt id=\"the%20analysis%20does%20not%20move.\"><h3>The analysis does not move.<\/h3><\/dt>\n<dd><p>It needs Action Scheduler to run, which WordPress triggers with WP-Cron. On sites with very little traffic, use a system cron, or run <code>wp action-scheduler run --group=magic-linking<\/code>, or analyse directly from the terminal with <code>wp magic-linking index<\/code>.<\/p><\/dd>\n<dt id=\"how%20do%20i%20analyze%20only%20what%20changed%3F\"><h3>How do I analyze only what changed?<\/h3><\/dt>\n<dd><p>Press \"Analyze changes\" in the report (or run <code>wp magic-linking index<\/code>). It goes through every entry but skips the ones whose content has not changed since the last analysis, and tells you how many were new or modified. Entries are also analysed again automatically when you save them.<\/p><\/dd>\n<dt id=\"how%20do%20i%20analyze%20the%20whole%20site%20again%20from%20scratch%3F\"><h3>How do I analyze the whole site again from scratch?<\/h3><\/dt>\n<dd><p>Go to Magic Linking &gt; Settings, open the \"Maintenance\" section and press \"Analyze everything again from scratch\" (or run <code>wp magic-linking index --force<\/code>). It asks you to confirm and then runs in the background, even for entries that have not changed. It never changes your content.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20delete%20the%20plugin%3F\"><h3>What happens when I delete the plugin?<\/h3><\/dt>\n<dd><p>By default your data is kept. If you tick \"Delete all Magic Linking data when the plugin is deleted\" in the settings, its tables and settings are removed. Your content is never touched.<\/p><\/dd>\n<dt id=\"is%20it%20multisite%20compatible%3F\"><h3>Is it multisite compatible?<\/h3><\/dt>\n<dd><p>Each site of a network has its own report and settings.<\/p><\/dd>\n<dt id=\"which%20hooks%20can%20developers%20use%3F\"><h3>Which hooks can developers use?<\/h3><\/dt>\n<dd><p>magiclinking_post_language (set the language of an entry), <code>magiclinking_internal_hosts<\/code> (extra hosts that count as your site), <code>magiclinking_resolve_link<\/code> (say where an internal address leads) and <code>magiclinking_post_html<\/code> (add HTML that a builder keeps outside the content).<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.9.2<\/h4>\n\n<ul>\n<li>Table schema rewritten without callable interpolation inside SQL strings (the generated SQL is identical).<\/li>\n<li>The package no longer contains development folders (such as <code>.claude<\/code>); the build now fails if any hidden or development file gets into the ZIP.<\/li>\n<li>Requirements (PHP 8.1, WordPress 6.9, mbstring) are checked before anything else loads. On activation without them the plugin deactivates itself with an explanatory message instead of failing.<\/li>\n<li>Added unit tests for the schema statements.<\/li>\n<\/ul>\n\n<h4>0.9.1<\/h4>\n\n<ul>\n<li>Readme: the bundled Action Scheduler is 4.2.x (the third-party libraries section still said 3.9.x).<\/li>\n<li>No functional changes.<\/li>\n<\/ul>\n\n<h4>0.9.0<\/h4>\n\n<ul>\n<li>First public version: \"Analyze changes\" (skips unchanged entries) and \"Analyze everything again from scratch\", report of orphan, under-linked and over-linked entries, complete list of broken internal links, CSV export, WP-CLI commands and settings. It never modifies content.<\/li>\n<li>Requires WordPress 6.9 or later and bundles Action Scheduler 4.2.0.<\/li>\n<\/ul>","raw_excerpt":"Find orphan pages, under-linked and over-linked entries and broken internal links. It never changes your content.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/378251","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=378251"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/dcarrero"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=378251"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=378251"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=378251"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=378251"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=378251"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=378251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}