== Changelog == = 1.5.0 = _Release date: 2026-05-05_ **Added** * PicDefense as a third external scan provider: POST-based copyright risk analysis via `POST /checkImageRisk`, authenticated with `X-API-TOKEN: {userId}:{apiKey}` header. * PicDefense results include risk classification (`picrisk`: high/medium/low), backlinks with similarity score and image URL, risk flags (face, logo, landmark, stock, EXIF copyright), and label detection. * Full Report attachment detail page: PicDefense section with picRisk badge, risk flags list, backlinks table sorted by similarity score (highest first), and detected labels. * Audit list quick-view modal: picRisk badge shown inline next to PicDefense match count. * Settings page: PicDefense User ID and API Key fields with credential status indicator. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4 = 1.4.0 = _Release date: 2026-05-05_ **Added** * Full attachment detail page accessible via "Full Report" row action in the audit list and "View full report →" link in the quick-view modal. Shows file metadata, internal usage, and complete raw external scan results per provider: * Google Vision: pages with matching images (URL + page title), full image matches, and partial image matches — all as clickable links. * TinEye: backlinks table with webpage URL, direct image URL, and crawl date — sorted by crawl date, newest first. **Fixed** * `rate_limit_per_minute` setting (Settings page) was stored but never read by providers — both Google Vision and TinEye used a hardcoded limit of 10 req/min regardless of configuration. * `external_batch_size` setting was ignored by Action Scheduler batch processing and by the browser AJAX runner — both always processed 10 attachments per batch. * TinEye domain extraction used the wrong API field: `backlink.url` is the direct image URL (CDN), while `backlink.backlink` is the webpage URL. The `top_domains` summary and the detail page now show the correct page domains and URLs. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4 = 1.3.0 = _Release date: 2026-05-05_ **Added** * Per-provider scan tracking table (`mra_provider_status`) with composite primary key `(attachment_id, provider)`. Each API provider now has an independent row tracking its scan status, so adding a new provider only queues the missing scans rather than resetting everything. * "Sync providers" operation in the Tools page: inserts rows for any provider that has no existing entry for a given attachment, then schedules a background scan batch for the new work only. **Changed** * `mra_external_results.provider` column changed from `ENUM('google_vision','tineye')` to `varchar(100)` to allow third-party providers registered via the `mra/external/providers` filter to store results. * External scan batch processing now reads from `mra_provider_status` and processes each provider independently. Aggregate `external_status` on `mra_media_index` is recomputed after each scan and used only for display. * `ExternalScanner::get_pending_count()` counts queued rows from `mra_provider_status`. * DB schema version bumped to `1.1.0`. Migration runs automatically on admin_init when updating from an older version; existing data is backfilled into `mra_provider_status`. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4 = 1.2.0 = _Release date: 2026-05-02_ **Added** * Browser-based AJAX scan runner in the Tools page: run index, usage, and external scan batches directly from the browser with a live progress bar. Useful when WP-Cron is disabled or Action Scheduler is not running. * "Requeue scan errors" operation: re-queues only attachments that failed the last external scan run (status `error`), without touching already-scanned items. * "Last Scanned" column in the audit list, showing a human-readable relative time with a precise date tooltip. Sortable with NULLs always listed last. * Bulk action "Export External Results CSV": downloads a CSV with attachment metadata and all external scan results, including top matching domains per provider. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4 = 1.1.0 = _Release date: 2026-05-02_ **Changed** * Plugin URI updated to `https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit`. * Author changed to `ROBOTSTXT` with URI `https://www.robotstxt.es/`. * Contributors updated to `javiercasares, robotstxt`. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4 = 1.0.0 = _Release date: 2026-05-01_ **Highlights** * First stable release. **Added** * Internal media usage scanner: tracks featured images, inline content, and post meta references across all post types. * External reverse image search via Google Cloud Vision (Web Detection) and TinEye Commercial API. * Cross-provider consensus detection: surfaces domains confirmed by multiple providers. * WP-CLI commands: `wp mra install`, `wp mra status`, `wp mra scan-internal`, `wp mra scan-external`. * Admin audit list page with filtering by external scan status and pagination. * Settings page for API credentials, batch size, and rate limiting. * GDPR compliance: personal data export and erasure via WordPress privacy tools. * Spanish (Spain) and Catalan translations. * Action Scheduler integration for async batch processing with configurable batch size and per-minute rate limit. * `mra/internal/scanner/post_types`, `mra/internal/scanner/meta_keys`, and `mra/external/providers` extension filters. **Compatibility** * WordPress: 6.8 - 7.0 * PHP: 8.2 - 8.4 * WP-CLI: 2.x **Tests** * PHP Coding Standards: WPCS 3.x / PHPCS 3.x * PHPStan: level 9 * PHPCompatibility: PHP 8.2 - 8.4