{"id":295356,"date":"2026-06-29T21:20:49","date_gmt":"2026-06-29T21:20:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/vizproof-timeline\/"},"modified":"2026-06-29T21:23:12","modified_gmt":"2026-06-29T21:23:12","slug":"vizproof-timeline","status":"publish","type":"plugin","link":"https:\/\/pap-cw.wordpress.org\/plugins\/vizproof-timeline\/","author":16611973,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.2","stable_tag":"1.0.2","tested":"7.0","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"VizProof Timeline","header_author":"Tommy Bordas","header_description":"Run VizProof scans from WordPress, including post-update visual regression checks with timeline and diff preview.","assets_banners_color":"","last_updated":"2026-06-29 21:23:12","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/vizproof.com","header_author_uri":"https:\/\/tommy-bordas.fr\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":59,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.2":{"tag":"1.0.2","author":"tommybordas","date":"2026-06-29 21:23:12"}},"upgrade_notice":{"1.0.1":"<p>Fixed incorrect menu path in readme, added API token setup instructions, fixed admin notices leaking into plugin pages.<\/p>","1.0.0":"<p>First stable WordPress.org release. Full review-compliance pass: replaced <code>WP_PLUGIN_DIR<\/code>\/<code>WP_CONTENT_DIR<\/code> with <code>plugin_dir_path()<\/code> helpers, REST checks now call <code>current_user_can( &amp;#039;manage_options&amp;#039; )<\/code> explicitly, hardened inline CSS\/JS escaping, unified transient prefix.<\/p>","0.4.45":"<p>WP.org compliance hardening: enqueued inline assets (no raw <code>\/<\/code> output) and nonce-protected update request flags.<\/p>","0.4.44":"<p>Critical fix: post-update scans now resolve existing VizProof pages correctly (409 existingPageId extraction). Pre-update baseline waits for run completion before promotion.<\/p>","0.4.43":"<p>Update panel now visible on Themes and Plugins pages, not just update-core.php.<\/p>","0.4.42":"<p>Full audit: security hardening, WCAG AA accessibility, WP.org compliance, i18n fixes, dead code cleanup.<\/p>","0.4.41":"<p>Security and reliability: atomic scan lock, self-decrypting API proxy, dead code cleanup.<\/p>","0.4.40":"<p>Critical fix: PHP parse error from smart quotes, dead navigation links, tighter update panel layout.<\/p>","0.4.39":"<p>UX overhaul: compact update panel, simplified onboarding, grouped settings, accessibility improvements, and several logic bug fixes.<\/p>","0.4.38":"<p>Maintenance release recommended for update workflow reliability, multisite routing, and pre-update baseline consistency.<\/p>"},"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.2"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Settings page with API\/project linking and page scope.","2":"WordPress Updates panel with controls and post-update scan status.","3":"Timeline view with run summaries and diff cards."}},"plugin_section":[],"plugin_tags":[441,7615,8201,1591,215916],"plugin_category":[51],"plugin_contributors":[250689],"plugin_business_model":[],"class_list":["post-295356","plugin","type-plugin","status-publish","hentry","plugin_tags-multisite","plugin_tags-qa","plugin_tags-screenshots","plugin_tags-testing","plugin_tags-visual-regression","plugin_category-multisite","plugin_contributors-tommybordas","plugin_committers-tommybordas"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/vizproof-timeline.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>VizProof Timeline connects WordPress to VizProof so post-update quality checks are simple and actionable.<\/p>\n\n<p>Key features:<\/p>\n\n<ul>\n<li>Launch post-update scans after plugin, theme, or core updates<\/li>\n<li>Optionally launch a baseline scan before running updates<\/li>\n<li>Show scan status directly on the WordPress Updates screen<\/li>\n<li>Open run history and visual diff summaries from wp-admin<\/li>\n<li>Run scheduled checks with WP-Cron (Action Scheduler fallback)<\/li>\n<li>Support multisite in per-site and network-wide modes<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to VizProof APIs hosted at <code>https:\/\/vizproof.com<\/code> (or a custom VizProof API URL configured by the site administrator).<\/p>\n\n<p>It sends requests only when plugin features are used (project\/page loading, scan launches, run history refresh, post-update workflows, scheduled scans).<\/p>\n\n<p>Data that may be sent includes:<\/p>\n\n<ul>\n<li>API token entered by an administrator<\/li>\n<li>Linked VizProof site\/project ID<\/li>\n<li>Page IDs or URLs used for scans<\/li>\n<li>Run trigger metadata required by update workflows<\/li>\n<\/ul>\n\n<p>Service documentation and policies:<\/p>\n\n<ul>\n<li>Privacy Policy: https:\/\/vizproof.com\/privacy<\/li>\n<li>Terms of Service: https:\/\/vizproof.com\/terms<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>vizproof-timeline<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate <strong>VizProof Timeline<\/strong>.<\/li>\n<li>Click <strong>VizProof<\/strong> in the top admin bar, then <strong>Configuration<\/strong>.<\/li>\n<li>Enter your VizProof API URL (default: <code>https:\/\/vizproof.com<\/code>) and API token.<\/li>\n<li>Select the VizProof project to link with this WordPress site.<\/li>\n<li>Save your settings.<\/li>\n<\/ol>\n\n<p>To obtain an API token:<\/p>\n\n<ol>\n<li>Create a free account at <a href=\"https:\/\/vizproof.com\/register\">vizproof.com<\/a>.<\/li>\n<li>Create a project and add at least one page (use your WordPress site URL).<\/li>\n<li>Go to <strong>Account \u2192 API Tokens<\/strong> and generate a token (starts with <code>vrt_<\/code>).<\/li>\n<li>Paste the token in the plugin Configuration page.<\/li>\n<\/ol>\n\n<p>Multisite:<\/p>\n\n<ol>\n<li>Open <code>Network Admin -&gt; Settings -&gt; VizProof Timeline<\/code>.<\/li>\n<li>Choose <code>Per-site<\/code> or <code>Network-wide<\/code> mode.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20require%20a%20vizproof%20account%3F\"><h3>Does this plugin require a VizProof account?<\/h3><\/dt>\n<dd><p>Yes. Sign up at <a href=\"https:\/\/vizproof.com\/register\">vizproof.com<\/a>, create a project, then generate an API token from Account \u2192 API Tokens. See the Installation section for step-by-step instructions.<\/p><\/dd>\n<dt id=\"what%20happens%20after%20a%20plugin%2Ftheme%2Fcore%20update%3F\"><h3>What happens after a plugin\/theme\/core update?<\/h3><\/dt>\n<dd><p>If post-update scan is enabled, VizProof Timeline queues a scan after the update completes and exposes status\/results in wp-admin.<\/p><\/dd>\n<dt id=\"does%20wp-cli%20trigger%20the%20same%20scan%20logic%3F\"><h3>Does WP-CLI trigger the same scan logic?<\/h3><\/dt>\n<dd><p>Yes. WP-CLI update commands run through the same updater hooks used by this plugin.<\/p><\/dd>\n<dt id=\"is%20multisite%20supported%3F\"><h3>Is multisite supported?<\/h3><\/dt>\n<dd><p>Yes.<\/p>\n\n<ul>\n<li><code>Per-site<\/code>: each subsite keeps its own configuration.<\/li>\n<li><code>Network-wide<\/code>: one shared network-level configuration.<\/li>\n<\/ul><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Fixed readme: corrected menu location from \"Settings &gt; VizProof Timeline\" to the actual top-level \"VizProof\" admin bar menu.<\/li>\n<li>Added step-by-step instructions for obtaining a VizProof API token in the Installation section.<\/li>\n<li>Fixed admin notices from other plugins appearing inside VizProof pages (added screen-reader-text h1 anchor for WordPress notice injection).<\/li>\n<li>Redesigned timeline baseline status bar into a unified single-row component.<\/li>\n<li>Removed unused baseline-assist and baseline-summary CSS classes.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<p>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.<\/p>\n\n<p>WordPress.org review compliance:\n* Removed direct loading of <code>wp-admin\/includes\/misc.php<\/code> (no function from that file was used) and gated remaining <code>require_once ABSPATH . 'wp-admin\/includes\/...'<\/code> calls with <code>function_exists()<\/code> \/ <code>class_exists()<\/code> guards. Each guarded include is followed immediately by a call to a function\/class from that file, per WP.org guidelines.\n* Replaced hardcoded <code>WP_PLUGIN_DIR<\/code> and <code>WP_CONTENT_DIR<\/code> constants in the rollback service with paths derived from <code>plugin_dir_path( __FILE__ )<\/code> via new <code>VIZPROOF_TIMELINE_PLUGIN_FILE<\/code> \/ <code>VIZPROOF_TIMELINE_PLUGIN_DIR<\/code> \/ <code>VIZPROOF_TIMELINE_PLUGIN_URL<\/code> constants. Local backup path validation now reuses the existing <code>wp_upload_dir()<\/code>-based <code>get_local_backup_root()<\/code> helper for consistency.\n* Made REST permission callbacks (<code>can_access_timeline<\/code>, <code>can_launch_runs<\/code>) perform an explicit <code>current_user_can( 'manage_options' )<\/code> capability check (previously delegated only via <code>can_manage_plugin()<\/code>), so static analysis can confirm protection on all 23 endpoints.\n* Hardened <code>enqueue_inline_admin_style()<\/code> \/ <code>enqueue_inline_admin_script()<\/code>: CSS now goes through <code>wp_strip_all_tags()<\/code> before <code>wp_add_inline_style()<\/code>, and inline JS is rejected if it contains a <code>&lt;\/script&gt;<\/code> sequence that could break out of the inline <code>&lt;script&gt;<\/code> block.\n* Renamed admin bar regression transients from <code>vizproof_adminbar_regressions_*<\/code> to <code>vizproof_timeline_adminbar_regressions_*<\/code> for prefix consistency with the rest of the plugin.<\/p>\n\n<h4>0.4.45<\/h4>\n\n<p>WordPress.org compliance:\n* Replaced admin inline <code>&lt;style&gt;<\/code>\/<code>&lt;script&gt;<\/code> blocks with <code>wp_add_inline_style()<\/code> \/ <code>wp_add_inline_script()<\/code> attached to enqueued handles.\n* Moved admin bar badge CSS injection to <code>admin_enqueue_scripts<\/code>.\n* Update panel assets now load consistently on <code>update-core.php<\/code>, <code>themes.php<\/code>, and <code>plugins.php<\/code>.\n* Added dedicated nonce handling for post-update request flags (<code>vizproof_after_update_scan<\/code>, <code>vizproof_before_update_baseline<\/code>) and enforced nonce+capability checks before honoring explicit request overrides.<\/p>\n\n<h4>0.4.44<\/h4>\n\n<p>Bug fixes:\n* 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).\n* 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.<\/p>\n\n<p>Improvements:\n* API logs now display in chronological order by default (oldest\u2192newest) with a toggle button to switch to reverse order.\n* Log rotation: entries older than 7 days are automatically pruned. Retention increased from 120 to 500 entries.\n* Log rows with 4xx errors are highlighted in yellow, 5xx in red.<\/p>\n\n<h4>0.4.43<\/h4>\n\n<ul>\n<li>VizProof update panel now displays on Themes and Plugins admin pages (was limited to update-core.php).<\/li>\n<li>Assets (CSS\/JS) are now loaded on themes.php and plugins.php for update panel rendering.<\/li>\n<\/ul>\n\n<h4>0.4.42<\/h4>\n\n<p>Security:\n* Fixed path traversal in restore_local_plugin_backup: added trailing slash to realpath containment check.\n* Added bearer token redaction in proxy error log bodies.\n* REST rest_save_option now runs options through sanitize_options before update_option.<\/p>\n\n<p>WordPress compliance:\n* Added load_plugin_textdomain() on init for translation loading outside WP.org directory.\n* Capped get_sites() calls to 500 (was unbounded number=0, caused timeout on large Multisite).\n* Plugin header Description translated to English (WP.org requirement).\n* Merged duplicate REST route registrations for runs\/{id} (GET+DELETE in single call).\n* Complete uninstall cleanup: removes <em>vizproof_lock<\/em>* options, all vizproof_* transients and site transients.<\/p>\n\n<p>Accessibility (WCAG 2.1 AA):\n* Page tree checkboxes now include page title in aria-label (\"Suivre \u2014 Page title\").\n* Added label\/for association on network settings cache delay input.\n* Removed role=\"presentation\" from per-site targets data table.\n* Fixed color contrast: warn badge (#6b5100), pending pill (#7a5300).\n* Added :focus-visible styles on all custom buttons and clickable elements.\n* Replaced invalid<\/p>\n\n<p>&lt;<\/p>\n\n<p>h3&gt; inside<\/p>\n\n<p>&lt;<\/p>\n\n<p>legend&gt; with styled<\/p>\n\n<p>&lt;<\/p>\n\n<p>legend&gt; in automation fieldsets.<\/p>\n\n<p>i18n:\n* Translated network config mode radio labels to French (was mixed EN\/FR).\n* Wired ~10 hardcoded strings in inline JS bridge to t() translation helper.\n* Translated 8 untranslated msgstr entries in fr_FR.po (update summary labels, Status, etc.).<\/p>\n\n<p>Cleanup:\n* Removed dead SETTINGS_MENU_SLUG constant and render_settings_page() method.\n* Removed ~6 unused CSS selectors (activity-item, summary-list, health-check).\n* Capped scan history to 100 entries (was unbounded).\n* Added TODO comments on duplicated inline  blocks for future consolidation.<\/p>\n\n<h4>0.4.41<\/h4>\n\n<ul>\n<li>Fixed proxy_vizproof_request silently failing when receiving pre-normalization options with empty api_token (self-decrypt from api_token_encrypted).<\/li>\n<li>Fixed scan lock race condition on standard WP installs (no Redis): replaced non-atomic transient fallback with INSERT IGNORE for cross-process atomicity.<\/li>\n<li>Removed orphan SETTINGS_MENU_SLUG from is_vizproof_admin_request allowlists (page never registered in admin_menu).<\/li>\n<li>Removed dead code: register_admin_menu, register_network_admin_menu, register_settings from service-base (duplicated in main plugin file, never hooked).<\/li>\n<\/ul>\n\n<h4>0.4.40<\/h4>\n\n<ul>\n<li>Fixed PHP parse error caused by Unicode smart quotes in French translation strings.<\/li>\n<li>Fixed dead links: \"R\u00e9glages avanc\u00e9s\" and \"Choisir le projet\" pointed to unregistered SETTINGS_MENU_SLUG page.<\/li>\n<li>Simplified redundant boolean comparisons (=== true \/ === false) in update panel JS.<\/li>\n<li>Further compacted update panel CSS: tighter padding, margins, and gaps across all panel sections.<\/li>\n<\/ul>\n\n<h4>0.4.39<\/h4>\n\n<ul>\n<li>Fixed redundant boolean logic in token storage validation.<\/li>\n<li>Fixed race condition in scan lock using atomic wp_cache_add.<\/li>\n<li>Fixed REST route methods for favorite endpoints (PATCH only instead of PUT+PATCH).<\/li>\n<li>Fixed function_exists guard in uninstall.php referencing wrong function name.<\/li>\n<li>Simplified site picker: merged auto-detect into project loading, \"Create from WordPress\" is now a secondary link.<\/li>\n<li>Added AJAX save for project selection (no full page reload between onboarding steps).<\/li>\n<li>Grouped automation settings into sub-sections: Planification, Comportement post-update, Notifications.<\/li>\n<li>Moved API logs behind a collapsible \"Outils d\u00e9veloppeur\" toggle on the dashboard.<\/li>\n<li>Added empty state on the timeline when no runs exist.<\/li>\n<li>Translated raw API status strings (partial_failed, queued, etc.) to human-readable French in the update panel.<\/li>\n<li>Replaced setInterval polling with MutationObserver only in the timeline bridge script.<\/li>\n<li>Added aria-live attributes on all dynamically updated zones (state, runs, diffs, update panel).<\/li>\n<li>Fixed timeline filter labels: proper label-for associations instead of span wrappers.<\/li>\n<li>Restructured network settings form with fieldset groups (Connexion API, Comportement des scans, Notifications).<\/li>\n<li>Compacted update panel on update-core.php: single-row header, inline checkboxes, collapsible pipeline steps.<\/li>\n<li>Stale scan results from previous updates are no longer shown on the update listing page.<\/li>\n<\/ul>\n\n<h4>0.4.38<\/h4>\n\n<ul>\n<li>Improved update-flow reliability for async and sync scan events.<\/li>\n<li>Improved multisite admin URL routing between site and network contexts.<\/li>\n<li>Improved pre-update baseline behavior by promoting successful pre-update runs.<\/li>\n<li>Improved update panel consistency for partial-failure handling.<\/li>\n<li>Improved layout width handling on update-core screens.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Added asynchronous queue support with retry\/backoff.<\/li>\n<li>Added update workflows and visual regression notifications in wp-admin.<\/li>\n<li>Added multisite support for per-site and network-wide modes.<\/li>\n<\/ul>","raw_excerpt":"Run VizProof scans from WordPress updates, review visual diffs in wp-admin, and automate recurring checks.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/295356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=295356"}],"author":[{"embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/tommybordas"}],"wp:attachment":[{"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=295356"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=295356"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=295356"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=295356"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=295356"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/pap-cw.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=295356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}