href Scanner
Scan selected content types, classify internal domains, filter internal and external link records, and export CSV reports from your WordPress dashboard.
by Nadeem Khan · github.com/nadeem-khan/href-scanner · website
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/nadeem-khan/href-scanner/archive/refs/heads/main.zipSource repository: nadeem-khan/href-scanner.
Scan saved WordPress content to audit internal and external link occurrences, review their anchor text and follow attributes, and export filtered CSV reports.
Features
- Complete scans rebuild the link profile; quick scans refresh content created or updated since the last complete scan.
- Select Posts, Pages and registered custom content types with editor support.
- Resume interrupted scans and view progress and time estimates.
- Group external links by domain and internal links by target page.
- Filter individual records by anchor text, follow type, source title and content type; click report counts to see their records.
- Configure three additional internal domains and export every matching occurrence across listing pages.
This scans HTML <a href> links in saved post content. It does not fetch destinations or check their HTTP status. Excerpts, custom fields, shortcode output, dynamically rendered blocks and links generated by themes, widgets or navigation are not scanned.
Requirements
WordPress 6.2+, PHP 7.4+, and the PHP DOM/libxml extension. No other plugin, account, API key, Composer package or npm dependency is required. Consult the release checklist for validation required before each release. Minimum versions describe compatibility; use maintained WordPress and PHP releases in production.
Installation and usage
Build or obtain the reviewed href-scanner-1.0.0.zip. In a test site, open Plugins → Add New Plugin → Upload Plugin, install the ZIP and activate href Scanner. Alternatively, extract its href-scanner folder into wp-content/plugins. GitHub's Download ZIP is a development source archive; build the installable plugin ZIP before uploading it to WordPress. Keep the installed folder named href-scanner.
Before upgrading a private development build, note any additional internal domains. After upgrading, reload Settings, save those domains again and run a complete scan. This release uses a new internal-domain option name; existing link records and selected content types are retained.
Open href Scanner → Settings, select the source content types, optionally enter additional internal domains, and save. Run Start Complete Scan and keep Settings open until completion. For example, add example.com as an internal domain to classify its HTTP(S) links as aliases of your site's pages. Use Start Quick Scan after changing content; use another complete scan after changing domains or source types. Open either report, click a link count, apply filters and choose Export All to download matching records.
If a scan stops, return to Settings and click Resume Complete Scan or Resume Quick Scan. Resumption uses the settings saved when that scan started. Scanning runs through requests from the open Settings page; there is no scheduled or background scan. On multisite, configure and scan each site separately; network activation does not produce a network-wide report.
No screenshots are included yet. The interface uses the existing WordPress admin pages and native tables.
Known limitations
- Content created or edited during a complete scan can be missed by later quick scans, because their cutoff is the complete scan's completion time. Avoid editing during a complete scan, or run another complete scan after edits finish.
- A CSV can be incomplete without an error message if a database read fails. Export after scanning finishes, compare its record count with the filtered listing, and retry after resolving database errors.
Privacy and retained data
Scans include selected private, draft, pending, scheduled and inherited content. Reports store URLs, anchor text, source titles/types, grouping and scan state in core WordPress posts, metadata and options. Only users with manage_options can view reports, scan or export. No telemetry, remote requests or visitor cookies are added.
URLs and titles can contain personal information or credentials from source content. Protect administrative access and CSV files. After removing sensitive source content, run a complete scan to remove outdated copies. Deactivation and plugin deletion retain records and settings. Backups and downloaded exports have separate retention obligations. There is no built-in purge control or integration with WordPress's personal-data exporter/eraser. Full removal requires reviewed database maintenance by a site administrator after a backup. There is no user-profile database or reliable email-based ownership mapping for individual occurrences; site administrators must review derived content when handling privacy requests.
Development and checks
Keep the repository separate from a production site. Install WordPress and this plugin in a disposable test site with a fresh database. Add define('HREF_SCANNER_TEST_SITE', true); to that test site's wp-config.php; it is required before any database regression script can run. Set HREF_SCANNER_WP_ROOT to its absolute WordPress directory. Tests intentionally alter fixtures, settings and generated link records. Development checks need command-line PHP, Node.js, Python 3.9+ and Git; WordPress checks also need WP-CLI and Plugin Check. Run the commands below from the repository root. See the CI workflow for the automated version matrix; multisite and browser checks are separate.
export HREF_SCANNER_WP_ROOT=/absolute/path/to/disposable/wordpress
php tests/check.php
node tests/check_admin.js
php tests/check-scan.php
php tests/check-local-urls.php
php tests/check-content-types.php
php tests/check-quick-scan.php
php tests/check-security.php
php tests/check-lifecycle.php
python scripts/check_secrets.py --self-test
python scripts/check_secrets.py
python tests/check_release.py
In PowerShell, set $env:HREF_SCANNER_WP_ROOT = 'C:\path\to\disposable\wordpress'. The lightweight check.php only loads WordPress libraries and uses mocked options; the other PHP scripts load and modify the marked test site. Activate the plugin first. The quick-scan test resets the selected test content; run it only against disposable data.
Run syntax validation for every PHP file, and node --check admin.js. In the disposable site, install the official Plugin Check and run:
wp plugin install plugin-check --activate --path="$HREF_SCANNER_WP_ROOT"
wp plugin check href-scanner --format=strict-json --severity=1 --include-experimental --path="$HREF_SCANNER_WP_ROOT"
wp plugin check href-scanner --format=strict-json --severity=1 --include-experimental --path="$HREF_SCANNER_WP_ROOT" --require="$HREF_SCANNER_WP_ROOT/wp-content/plugins/plugin-check/cli.php"
The last command enables runtime checks. These examples use a POSIX shell and a wp executable on PATH. In PowerShell, use $env:HREF_SCANNER_WP_ROOT in place of $HREF_SCANNER_WP_ROOT. Run PHP_CodeSniffer from the installed Plugin Check package with --standard=.phpcs.xml.dist from the repository root; it is not bundled with href Scanner. Save and review errors and warnings; neither a clean result nor CI replaces directory review. See CONTRIBUTING.md for exact commands and the complete workflow.
For multisite isolation coverage, create a separate marked disposable network with blogs 1 and 2, network-activate the plugin, set HREF_SCANNER_WP_ROOT to that installation and run php tests/check-multisite.php.
Build from source
python scripts/build.py
Python 3.9+ and its standard library are sufficient. There is no compilation or minification step. The build uses an explicit runtime-file allowlist, sorted paths, fixed ZIP timestamps and file permissions, then verifies archive contents, CRC integrity and source bytes. It creates dist/href-scanner-1.0.0.zip and a SHA-256 file. Store reviewed submission ZIPs and checksum files in the Git-ignored release/ folder. Repeated builds from identical source bytes and toolchain are identical. .distignore describes the exclusion policy; the allowlist in the build script enforces it and must be updated when adding runtime files. All deployed PHP, JS and CSS are readable source. From dist, verify the ZIP checksum with sha256sum --check href-scanner-1.0.0.zip.sha256; in PowerShell, compare (Get-FileHash dist/href-scanner-1.0.0.zip -Algorithm SHA256).Hash with the sidecar file.
Contributing, security and license
Read CONTRIBUTING.md before proposing a change and SECURITY.md before reporting a vulnerability through private reporting. Code and styles are GPL-2.0-or-later; see LICENSE and dependency notices.
Releases
GitHub hosts the source project. WordPress.org will host reviewed plugin releases after approval. Version 1.0.0 is the first public release candidate, and href-scanner is the intended slug, subject to directory assignment. GitHub installations have no plugin-provided automatic updater; install reviewed updates manually until a WordPress.org release is available. Publication, initial submission and every SVN release require explicit maintainer approval; no workflow deploys automatically. Follow the release checklist and the release procedure.