=== Tidy Broken Link Scan – Broken Link & Image Checker ===
Contributors: pierreferrolliet
Tags: broken links, link checker, 404, dead links, images
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.2
Stable tag: 2.5.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Scan your posts, pages and custom post types for broken links and images — href, src, srcset included. No external service required.

== Description ==

BLC scans every published post, page and public custom post type on your WordPress site for broken links and images. It checks `<a href>`, `<img src>`, `<img srcset>`, and `<source srcset>` — all natively, using the WordPress HTTP API. No SaaS, no API key, no external dependency.

**Features:**

* Detects broken links (4xx, 5xx, timeouts)
* Checks images including `srcset` and `<picture>` elements
* Automatic daily scan via WP-Cron
* Instant re-scan when you save a post
* Admin dashboard with filtering (all / broken / ok)
* Direct link to edit the source post
* Works on any WordPress hosting

**Need a full-site crawl?** This plugin checks the links and images inside your published posts, pages and custom post types. For a complete crawl of your whole site — every URL discovered through your sitemap, plus SSL and redirect-chain checks — you can run a free scan with our companion cloud scanner at [brokenlinkscan.com](https://brokenlinkscan.com). It runs in your browser, needs no installation, and is made by the same author.

= More from Tidy Plugins =

If you like this plugin, take a look at the rest of the Tidy suite:

* [Tidy Table of Contents](https://wordpress.org/plugins/tidy-table-of-contents/) — automatic, accessible table of contents
* [Tidy Draft Share](https://wordpress.org/plugins/tidy-draft-share/) — share drafts via secure, expiring preview links
* [Tidy Author Box](https://wordpress.org/plugins/tidy-author-box/) — author bio box with avatar and social links


== Installation ==

1. Upload the `tidy-broken-link-scan` folder to `/wp-content/plugins/`
2. Activate the plugin in **Plugins → Installed Plugins**
3. Go to **Liens cassés** in the admin menu
4. Click **Scanner tout le site** to run your first scan

== Frequently Asked Questions ==

= Will it slow down my site? =
No. Scans run in the background via WP-Cron and are never triggered by front-end visitors.

= Does it check images? =
Yes — `<img src>`, `<img srcset>`, and `<source srcset>` are all parsed and checked.

= How often does it scan? =
Once per day automatically (at 03:00 server time). You can also trigger a full scan manually or re-scan individual posts on save.

= Can I scan a single post? =
Posts are automatically re-scanned every time you publish or update them.

== External services ==

This plugin sends HTTP requests to third-party URLs as its core functionality (broken link checking). The list of contacted URLs is dynamic: it consists of the external links and image sources found in your own published posts, pages, and custom post types.

* What is sent: HTTP HEAD (with GET fallback) requests using the WordPress HTTP API. The plugin does not transmit any user-identifying data; only the URL itself is requested.
* When: requests are issued during a scan, which is triggered manually from the admin dashboard, automatically once per day via WP-Cron, or when you save a post (re-scan of that post only).
* Why: to determine whether each link returns a 2xx/3xx response (OK) or a 4xx/5xx/timeout response (broken).

Because the contacted URLs are entirely determined by the content of your own site, the plugin does not rely on any single fixed third-party service. A small allow-list of well-known domains (Gravatar, gstatic, wordpress.com, Cloudflare, etc.) is skipped from scanning to avoid noise; no data is sent to those domains by the plugin itself.

== Upgrade Notice ==

= 2.4.1 =
Code cleanup: all licence checks and premium-feature gating removed from the free plugin.

= 2.4.0 =
New features: broken anchor detection, redirect chain tracking, Slack notifications, scan diff, and health score dashboard.

== Screenshots ==

1. Scan dashboard with health score and link results

== Changelog ==

= 2.5.0 =
* Scans now cover every public post type (posts, pages and custom post types) instead of only posts and pages — full scans, the daily auto-scan, the on-save re-scan, the post editor meta box and WP-CLI all use the same scope. Added a `blsc_scannable_post_types` filter to customise the list.

= 2.4.9 =
* Scan history now shows every recorded entry (up to the 30 the plugin stores) instead of being capped.
* Domain and URL exclusions are now fully configurable from the Settings screen — enter the domains or URLs to skip during scans.

= 2.4.8 =
* Replaced all direct cURL calls with the WordPress HTTP API (`wp_remote_*`) for link and image checking, including the batch scanner. Redirects are now followed via the HTTP API while still reporting redirect chains and loops.
* WP-CLI `blc export` now writes CSV to STDOUT only (use shell redirection, e.g. `wp blc export > report.csv`); the arbitrary `--file` path option was removed.

= 2.4.7 =
* WordPress.org coding-standards hardening: explicit output escaping in the admin dashboard and post meta box, documented safe `$wpdb` queries, and translators comments for all i18n placeholders (Plugin Check compliance).

= 2.4.6 =
* Added a dismissible tip on the dashboard linking to the companion cloud scanner (brokenlinkscan.com) for a full-site crawl beyond posts and pages.

= 2.4.5 =
* Replaced PHP short echo tags (`<?=`) with full `<?php echo` in the post meta box (WordPress.org coding-standards compliance).
* Bumped "Tested up to" to WordPress 7.0 and aligned the readme plugin name with the plugin header.

= 2.4.4 =
* Hardened admin output escaping: replaced `phpcs:ignore` suppressions with explicit `wp_kses()`, `esc_attr()` and `(int)` casts in the dashboard view (WordPress.org coding-standards compliance).

= 2.4.3 =
* Document outbound HTTP scanning behavior under the new "External services" section of the readme (WordPress.org guideline 6 compliance).

= 2.4.2 =
* Removed the ACF field scanner from the free plugin (the code only ran when the Pro add-on enabled the related setting). ACF scanning is now provided entirely by the companion Pro plugin via the new `blsc_extra_links` filter.

= 2.4.1 =
* Removed all licence checks and premium-feature gating from the free plugin code (premium features — auto-scan cron, email/Slack notifications, ACF scanning, exclusions, CSV/XLSX export, extended history — are now distributed via a separate companion plugin).
* Removed the now-unnecessary `load_plugin_textdomain()` call (handled by WordPress.org translation system since WP 4.6).
* Added extension hooks for add-on plugins (settings defaults/sanitisation, scan-complete notification, scan/exclusion filters, admin UI).

= 2.4.0 =
* Added: Broken anchor detection (missing #id targets)
* Added: Redirect chain tracking and reporting
* Added: Slack notifications for scan results
* Added: Scan diff — compare results between consecutive scans
* Added: Health score dashboard with summary cards

= 2.2.0 =
* Fixed: Plugin header version now matches internal constant
* Fixed: SSL_VERIFYHOST set to 2 (was incorrectly disabled, MITM vulnerability)
* Fixed: Plugin action links basename corrected (Settings link now works on Plugins page)
* Fixed: Double scan race condition — pending state now blocks duplicate starts
* Fixed: Raw $_POST passed to settings save without wp_unslash()
* Fixed: save_scan_history() query now uses $wpdb->prepare()
* Improved: Nonce caching in list table rows (performance)
* Improved: Hardcoded French strings in admin.js replaced with i18n keys
* Removed: Dead code (page_by_post method, by-post.php template, unused CSS, blsc_manual_ok_urls option)
* Added: Missing admin notice keys (settings_saved, export_empty)

= 2.1.0 =
* Parallel HTTP checks via curl_multi
* Email alerts for new broken links
* Scan history and delta reporting
* XLSX export support
* Ignore list with persistent overrides
* By-post view integrated into dashboard

= 1.0.0 =
* Initial release
