=== VizProof Timeline ===
Contributors: tommybordas
Tags: visual-regression, screenshots, qa, testing, multisite
Requires at least: 6.2
Tested up to: 7.1
Stable tag: 1.2.0
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Run VizProof scans from WordPress updates, review visual diffs in wp-admin, and automate recurring checks.

== Description ==

VizProof Timeline connects WordPress to [VizProof](https://vizproof.com), a visual regression testing service, so every WordPress update can be followed by an automated visual check of your key pages.

= Why =

Plugin, theme, and core updates rarely throw PHP errors when they break something visual: a shifted button, a collapsed layout, a missing hero image. Your monitoring stays green while your pages degrade. VizProof Timeline catches those regressions right from wp-admin, before your visitors do.

= How it works =

1. Click "Connecter à VizProof": authorize the site from your VizProof account and the API token and project are configured automatically (a manual API token also works).
2. Select the pages to monitor: each one is auto-classified as Single, Listing, or Static.
3. Run updates as usual: a modal captures the "before" reference with live progress, the update then applies on its own, and a visual scan runs right after.
4. Read the verdict first (OK / anomalies to review); pipeline and per-site details stay folded unless something is wrong.

= Key features =

* One-click connect to VizProof, without any API token copy/paste (manual token still supported)
* Settings profiles: "Simple (recommandé)" and "Prudent" presets configure the whole automation in one click; fine-grained settings live under "Réglages avancés"
* Guaranteed before/after ordering: the "before" reference is captured and promoted before the update starts, from a progress modal, including for WordPress core updates
* Optional strict mode: cancel the WordPress update if the baseline could not be captured in time
* Post-update scans after plugin, theme, or core updates, including background automatic updates
* Content-aware reference: publishing or editing content refreshes the baseline of the affected pages (partial re-capture on supporting servers), so editorial changes never show up as regressions
* Verdict-first update panel and quiet, dismissible admin notices
* Run history and visual diff summaries in wp-admin
* Scheduled checks with WP-Cron (Action Scheduler fallback)
* Plugin rollback with local backups when an update causes regressions
* Multisite support in per-site and network-wide modes
* WP-CLI compatible: scans also hook into CLI-triggered updates

= Requirements =

A VizProof account and API token are required. The free plan is enough to get started: sign up at [vizproof.com/register](https://vizproof.com/register). See the Installation section for the step-by-step setup.

== External services ==

This plugin connects to VizProof APIs hosted at `https://vizproof.com` (or a custom VizProof API URL configured by the site administrator).

It sends requests only when plugin features are used (project/page loading, scan launches, run history refresh, post-update workflows, scheduled scans).

Data that may be sent includes:

* API token entered by an administrator
* Linked VizProof site/project ID
* Page IDs or URLs used for scans
* Run trigger metadata required by update workflows

Service documentation and policies:

* Privacy Policy: https://vizproof.com/privacy
* Terms of Service: https://vizproof.com/terms

== Installation ==

1. Upload the `vizproof-timeline` folder to `/wp-content/plugins/`.
2. Activate **VizProof Timeline**.
3. Click **VizProof** in the top admin bar, then **Configuration**.
4. Click **Connecter à VizProof**: sign in (or create a free account), authorize the site, and you are redirected back with the API token and project configured automatically.
5. Select the pages to monitor and save.

Manual alternative (self-hosted servers or if you prefer explicit tokens):

1. Create a free account at [vizproof.com](https://vizproof.com/register).
2. Create a project and add at least one page (use your WordPress site URL).
3. Go to **Account → API Tokens** and generate a token (starts with `vrt_`).
4. Paste the token in the plugin Configuration page and select the project.

Multisite:

1. Open `Network Admin -> Settings -> VizProof Timeline`.
2. Choose `Per-site` or `Network-wide` mode.

== Frequently Asked Questions ==

= Does this plugin require a VizProof account? =

Yes. The free plan is enough to get started. The easiest path is the "Connecter à VizProof" button on the plugin Configuration page: it signs you in on vizproof.com and configures the token and project automatically. A manual API token (Account → API Tokens) also works; see the Installation section.

= Do I have to copy an API token? =

Not anymore: one-click connect creates and configures a dedicated, revocable token for the site. Manual tokens remain supported (useful for self-hosted VizProof servers).

= What happens after a plugin/theme/core update? =

If post-update scan is enabled, VizProof Timeline queues a scan after the update completes and exposes status/results in wp-admin.

= Does WP-CLI trigger the same scan logic? =

Yes. WP-CLI update commands run through the same updater hooks used by this plugin.

= Is multisite supported? =

Yes.

* `Per-site`: each subsite keeps its own configuration.
* `Network-wide`: one shared network-level configuration.

== Changelog ==

= 1.2.0 =

Reliable before/after ordering, including WordPress core updates:

* The "before" baseline is now captured from a dedicated modal, before you reach the update screen. WordPress core updates never fired `upgrader_pre_install`, so the baseline used to start at the same time as the update and was unusable; the browser-side guard fixes this for core, plugins and themes alike.
* The modal shows real progress (captured / expected screenshots) and lets you cancel, or update without a reference, at any time. No more frozen-looking update screen.
* Once the reference is promoted, the update resumes automatically and the post-update scan still runs.
* New REST endpoints `POST|GET /vizproof/v1/pre-update-baseline` to start and follow the capture without blocking any PHP request.
* Settings redesign: the recommended profiles are now real selectable cards (they were rendered as plain full-width buttons, since WordPress admin button styles overrode the layout), section headers are readable, "Réglages avancés" is a proper disclosure, and setting rows get separators and legible descriptions.
* Admin bar: the VizProof entry is now clickable (it opens the scan results), carries an eye icon so it stands out, and its submenu labels are explicit ("Résultats des scans", "Réglages du réseau").

= 1.1.1 =

* Copy editing pass across the plugin UI, notices, and readme: clearer phrasing and punctuation cleanup, no functional change.

= 1.1.0 =

Simplicity release: one-click setup, guided settings, live progress.

* One-click connect: a "Connecter à VizProof" button opens vizproof.com where you authorize the site; the API token and project are created and configured automatically (single-use code exchange, no copy/paste). Requires a VizProof server advertising the `wordpressConnect` capability; the manual token path remains available.
* Settings profiles: "Simple (recommandé)" and "Prudent" presets fill the whole automation form in one click; all fine-grained settings now live in a folded "Réglages avancés" section.
* Live progress during the pre-update pause: the update screen streams "capture en cours… x/y captures" lines while WordPress waits for the "before" baseline, instead of appearing frozen.
* Verdict-first update panel: after a scan the big binary verdict (OK / anomalies) is the hero; pipeline and per-site details are folded into "Détails techniques", auto-opened only when something is wrong.
* Fixed a PHP 8.2+ dynamic-property deprecation on the plugin bootstrap class.
* Updated "Tested up to" to WordPress 7.1.

= 1.0.4 =

Pre-update baseline ordering and quieter notices:

* The WordPress update now waits for the "before" baseline capture to finish (and be promoted) before any file is replaced, instead of giving up after ~60 seconds. The wait budget is configurable (30–600 s, default 240 s) and the PHP execution limit is refreshed during the wait.
* New strict mode "Require pre-update baseline": if the baseline cannot be captured and promoted within the budget, the WordPress update is cancelled before touching any file (opt-in, off by default).
* The update panel announces the pause ("Baseline « avant » en cours de capture…") and a new "Baseline avant mise à jour" step appears in the scan pipeline with its outcome (done / failed / skipped).
* When strict mode cancels an update, the panel explains why instead of pretending a post-update scan ran.
* Admin notices are quieter: compact styling, softer tone (regressions are now a warning, red is reserved for hard scan failures), 24-hour window instead of 48, and a persistent "Ne plus afficher" dismissal per notice.
* The activation welcome notice only appears on the Dashboard, Plugins and Updates screens, and can be permanently dismissed.
* Page classification: each tracked page is auto-classified as Single / Listing / Static (blog index detected as Listing), with a manual override select in the page selector for custom listing pages.
* New "Re-baseline after content change" automation (opt-in): publishing, editing or unpublishing content re-captures the tracked pages and promotes the run as the new reference, so editorial changes stop showing up as visual regressions. Debounced (configurable quiet delay, default 10 min) so a burst of edits triggers a single scan; it only fires when a tracked page is affected (the content's own tracked page, or a tracked Listing page).
* Content-rebase runs never raise "visual regression" admin notices (their diffs are the expected content change); hard failures are still notified.
* New option to also capture the pre-update baseline during background automatic updates (WP-Cron), enabling safe unattended auto-updates.
* Partial rebase: on VizProof servers advertising the `pageBaseline` capability, a content change only re-captures the affected pages (edited single + tracked listings) and pins them as their own baseline via `POST /api/sites/{id}/baseline-pages`; the site baseline and every other page stay untouched. Falls back to the full rebase on older servers.
* Server capability discovery now probes `/api/capabilities` (with `/capabilities` fallback), so feature detection works behind reverse proxies that only forward `/api/*`.

= 1.0.3 =

UX and reliability improvements based on real-world testing:

* Update panel now shows live scan progress: pipeline steps stay expanded while a scan is active, with an elapsed-time counter refreshed every second.
* Clearer status copy during post-update scans (queued vs running phases are now distinct and accurate).
* Stuck-scan detection: the UI warns when a queued scan has not started after 4 minutes or a running scan exceeds 20 minutes, with actionable hints (WP-Cron / Action Scheduler, API logs).
* Server-side stale-scan sweep: scans stuck in "queued" for 30+ minutes (or "running" for 2+ hours) are automatically finalized as failed instead of polling forever.
* Fixed error messages showing raw JSON instead of the human-readable message returned by the plugin.
* Dedicated messages for invalid/expired tokens (401/403) and plan quota reached (429); upstream 429 is no longer retried 4 times.
* Token validity is now verified against the VizProof API (cached 5 min) and surfaced on the dashboard Token card with an inline error, instead of showing "OK" for any non-empty string.
* Results page: the "Launch scan" button is disabled until the plugin is configured, and the notice now links to the Configuration page.
* Welcome notice after activation linking to the Configuration page (dismissed automatically once configured, expires after 14 days).
* Fixed a JavaScript syntax error (unescaped apostrophe) that silently disabled the onboarding health-check module.

= 1.0.2 =

* Updated "Tested up to" to WordPress 7.0.
* Removed the duplicate README.md from the distributed package.

= 1.0.1 =

* Fixed readme: corrected menu location from "Settings > VizProof Timeline" to the actual top-level "VizProof" admin bar menu.
* Added step-by-step instructions for obtaining a VizProof API token in the Installation section.
* Fixed admin notices from other plugins appearing inside VizProof pages (added screen-reader-text h1 anchor for WordPress notice injection).
* Redesigned timeline baseline status bar into a unified single-row component.
* Removed unused baseline-assist and baseline-summary CSS classes.

= 1.0.0 =

First stable WordPress.org release. The plugin has reached production maturity for the VizProof Timeline integration: multisite-aware updates workflow, asynchronous scan queue with retry/backoff, admin bar regression badge, REST API surface, and rollback service with local backups in the uploads directory.

WordPress.org review compliance:
* Removed direct loading of `wp-admin/includes/misc.php` (no function from that file was used) and gated remaining `require_once ABSPATH . 'wp-admin/includes/...'` calls with `function_exists()` / `class_exists()` guards. Each guarded include is followed immediately by a call to a function/class from that file, per WP.org guidelines.
* Replaced hardcoded `WP_PLUGIN_DIR` and `WP_CONTENT_DIR` constants in the rollback service with paths derived from `plugin_dir_path( __FILE__ )` via new `VIZPROOF_TIMELINE_PLUGIN_FILE` / `VIZPROOF_TIMELINE_PLUGIN_DIR` / `VIZPROOF_TIMELINE_PLUGIN_URL` constants. Local backup path validation now reuses the existing `wp_upload_dir()`-based `get_local_backup_root()` helper for consistency.
* Made REST permission callbacks (`can_access_timeline`, `can_launch_runs`) perform an explicit `current_user_can( 'manage_options' )` capability check (previously delegated only via `can_manage_plugin()`), so static analysis can confirm protection on all 23 endpoints.
* Hardened `enqueue_inline_admin_style()` / `enqueue_inline_admin_script()`: CSS now goes through `wp_strip_all_tags()` before `wp_add_inline_style()`, and inline JS is rejected if it contains a `</script>` sequence that could break out of the inline `<script>` block.
* Renamed admin bar regression transients from `vizproof_adminbar_regressions_*` to `vizproof_timeline_adminbar_regressions_*` for prefix consistency with the rest of the plugin.

= 0.4.45 =

WordPress.org compliance:
* Replaced admin inline `<style>`/`<script>` blocks with `wp_add_inline_style()` / `wp_add_inline_script()` attached to enqueued handles.
* Moved admin bar badge CSS injection to `admin_enqueue_scripts`.
* Update panel assets now load consistently on `update-core.php`, `themes.php`, and `plugins.php`.
* Added dedicated nonce handling for post-update request flags (`vizproof_after_update_scan`, `vizproof_before_update_baseline`) and enforced nonce+capability checks before honoring explicit request overrides.

= 0.4.44 =

Bug fixes:
* Fixed post-update scan failing silently when pages already exist on VizProof: the existing page ID from 409 responses was not extracted (nested in proxy body, not at details root).
* Pre-update baseline promotion now polls until the VizProof run completes (up to ~60s) before promoting, instead of promoting an incomplete run which was always rejected by the API.

Improvements:
* API logs now display in chronological order by default (oldest→newest) with a toggle button to switch to reverse order.
* Log rotation: entries older than 7 days are automatically pruned. Retention increased from 120 to 500 entries.
* Log rows with 4xx errors are highlighted in yellow, 5xx in red.

= 0.4.43 =

* VizProof update panel now displays on Themes and Plugins admin pages (was limited to update-core.php).
* Assets (CSS/JS) are now loaded on themes.php and plugins.php for update panel rendering.

= 0.4.42 =

Security:
* Fixed path traversal in restore_local_plugin_backup: added trailing slash to realpath containment check.
* Added bearer token redaction in proxy error log bodies.
* REST rest_save_option now runs options through sanitize_options before update_option.

WordPress compliance:
* Added load_plugin_textdomain() on init for translation loading outside WP.org directory.
* Capped get_sites() calls to 500 (was unbounded number=0, caused timeout on large Multisite).
* Plugin header Description translated to English (WP.org requirement).
* Merged duplicate REST route registrations for runs/{id} (GET+DELETE in single call).
* Complete uninstall cleanup: removes _vizproof_lock_* options, all vizproof_* transients and site transients.

Accessibility (WCAG 2.1 AA):
* Page tree checkboxes now include page title in aria-label ("Suivre — Page title").
* Added label/for association on network settings cache delay input.
* Removed role="presentation" from per-site targets data table.
* Fixed color contrast: warn badge (#6b5100), pending pill (#7a5300).
* Added :focus-visible styles on all custom buttons and clickable elements.
* Replaced invalid <h3> inside <legend> with styled <legend> in automation fieldsets.

i18n:
* Translated network config mode radio labels to French (was mixed EN/FR).
* Wired ~10 hardcoded strings in inline JS bridge to t() translation helper.
* Translated 8 untranslated msgstr entries in fr_FR.po (update summary labels, Status, etc.).

Cleanup:
* Removed dead SETTINGS_MENU_SLUG constant and render_settings_page() method.
* Removed ~6 unused CSS selectors (activity-item, summary-list, health-check).
* Capped scan history to 100 entries (was unbounded).
* Added TODO comments on duplicated inline <style> blocks for future consolidation.

= 0.4.41 =

* Fixed proxy_vizproof_request silently failing when receiving pre-normalization options with empty api_token (self-decrypt from api_token_encrypted).
* Fixed scan lock race condition on standard WP installs (no Redis): replaced non-atomic transient fallback with INSERT IGNORE for cross-process atomicity.
* Removed orphan SETTINGS_MENU_SLUG from is_vizproof_admin_request allowlists (page never registered in admin_menu).
* Removed dead code: register_admin_menu, register_network_admin_menu, register_settings from service-base (duplicated in main plugin file, never hooked).

= 0.4.40 =

* Fixed PHP parse error caused by Unicode smart quotes in French translation strings.
* Fixed dead links: "Réglages avancés" and "Choisir le projet" pointed to unregistered SETTINGS_MENU_SLUG page.
* Simplified redundant boolean comparisons (=== true / === false) in update panel JS.
* Further compacted update panel CSS: tighter padding, margins, and gaps across all panel sections.

= 0.4.39 =

* Fixed redundant boolean logic in token storage validation.
* Fixed race condition in scan lock using atomic wp_cache_add.
* Fixed REST route methods for favorite endpoints (PATCH only instead of PUT+PATCH).
* Fixed function_exists guard in uninstall.php referencing wrong function name.
* Simplified site picker: merged auto-detect into project loading, "Create from WordPress" is now a secondary link.
* Added AJAX save for project selection (no full page reload between onboarding steps).
* Grouped automation settings into sub-sections: Planification, Comportement post-update, Notifications.
* Moved API logs behind a collapsible "Outils développeur" toggle on the dashboard.
* Added empty state on the timeline when no runs exist.
* Translated raw API status strings (partial_failed, queued, etc.) to human-readable French in the update panel.
* Replaced setInterval polling with MutationObserver only in the timeline bridge script.
* Added aria-live attributes on all dynamically updated zones (state, runs, diffs, update panel).
* Fixed timeline filter labels: proper label-for associations instead of span wrappers.
* Restructured network settings form with fieldset groups (Connexion API, Comportement des scans, Notifications).
* Compacted update panel on update-core.php: single-row header, inline checkboxes, collapsible pipeline steps.
* Stale scan results from previous updates are no longer shown on the update listing page.

= 0.4.38 =

* Improved update-flow reliability for async and sync scan events.
* Improved multisite admin URL routing between site and network contexts.
* Improved pre-update baseline behavior by promoting successful pre-update runs.
* Improved update panel consistency for partial-failure handling.
* Improved layout width handling on update-core screens.

= 0.4.0 =

* Added asynchronous queue support with retry/backoff.
* Added update workflows and visual regression notifications in wp-admin.
* Added multisite support for per-site and network-wide modes.

== Upgrade Notice ==

= 1.0.3 =

Live scan progress with elapsed time, stuck-scan detection and auto-expiry, human-readable error messages, real token validation, and a post-activation setup notice.

= 1.0.1 =

Fixed incorrect menu path in readme, added API token setup instructions, fixed admin notices leaking into plugin pages.

= 1.0.0 =

First stable WordPress.org release. Full review-compliance pass: replaced `WP_PLUGIN_DIR`/`WP_CONTENT_DIR` with `plugin_dir_path()` helpers, REST checks now call `current_user_can( 'manage_options' )` explicitly, hardened inline CSS/JS escaping, unified transient prefix.

= 0.4.45 =

WP.org compliance hardening: enqueued inline assets (no raw `<style>/<script>` output) and nonce-protected update request flags.

= 0.4.44 =

Critical fix: post-update scans now resolve existing VizProof pages correctly (409 existingPageId extraction). Pre-update baseline waits for run completion before promotion.

= 0.4.43 =

Update panel now visible on Themes and Plugins pages, not just update-core.php.

= 0.4.42 =

Full audit: security hardening, WCAG AA accessibility, WP.org compliance, i18n fixes, dead code cleanup.

= 0.4.41 =

Security and reliability: atomic scan lock, self-decrypting API proxy, dead code cleanup.

= 0.4.40 =

Critical fix: PHP parse error from smart quotes, dead navigation links, tighter update panel layout.

= 0.4.39 =

UX overhaul: compact update panel, simplified onboarding, grouped settings, accessibility improvements, and several logic bug fixes.

= 0.4.38 =

Maintenance release recommended for update workflow reliability, multisite routing, and pre-update baseline consistency.
