diff --git a/assets/src/css/admin/settings.css b/assets/src/css/admin/settings.css
index fdc8ff3..fb42d91 100644
--- a/assets/src/css/admin/settings.css
+++ b/assets/src/css/admin/settings.css
@@ -1,15 +1,20 @@
.perform-settings-page {
--perform-color-brand: #0046d1;
+ --perform-color-primary: #0046d1;
--perform-color-brand-hover: #0037a8;
--perform-color-focus: #2271b1;
--perform-color-text: #1d2327;
--perform-color-text-muted: #50575e;
--perform-color-border: #dcdcde;
--perform-color-surface: #fff;
+ --perform-color-surface-subtle: #f7f8fa;
+ --perform-color-surface-accent: #f3f7ff;
--perform-color-canvas: #f0f0f1;
--perform-color-success: #008a20;
--perform-color-warning: #996800;
--perform-color-danger: #b32d2e;
+ --perform-radius-card: 10px;
+ --perform-shadow-card: 0 1px 2px rgba(16, 24, 40, 0.05), 0 1px 3px rgba(16, 24, 40, 0.08);
display: flex;
flex-direction: column;
min-height: calc(100vh - 32px);
@@ -18,6 +23,13 @@
background: var(--perform-color-surface);
}
+.perform-settings-page .perform-ui-icon {
+ flex: 0 0 auto;
+ width: 20px;
+ height: 20px;
+ stroke-width: 1.75;
+}
+
.perform-settings-page *,
.perform-settings-page *::before,
.perform-settings-page *::after {
@@ -87,8 +99,8 @@
min-height: 48px;
padding: 0 16px;
color: var(--perform-color-text-muted);
- font-size: 14px;
- font-weight: 600;
+ font-size: 13px;
+ font-weight: 500;
line-height: 1.4;
}
@@ -98,6 +110,7 @@
.perform-settings-tab-panel .components-tab-panel__tabs-item[aria-selected='true'] {
color: var(--perform-color-brand);
+ font-weight: 600;
}
.perform-settings-tab-panel .components-tab-panel__tabs-item[aria-selected='true']::after {
@@ -111,6 +124,85 @@
content: '';
}
+.perform-diagnostic-switcher {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 24px;
+ padding: 16px clamp(20px, 3vw, 44px);
+ border-bottom: 1px solid var(--perform-color-border);
+ background: var(--perform-color-surface-subtle);
+}
+
+.perform-diagnostic-switcher__context {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-width: 0;
+}
+
+.perform-diagnostic-switcher__icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex: 0 0 auto;
+ width: 40px;
+ height: 40px;
+ border: 1px solid #d7e3fb;
+ border-radius: 9px;
+ color: var(--perform-color-brand);
+ background: var(--perform-color-surface-accent);
+}
+
+.perform-diagnostic-switcher__context > span:last-child {
+ display: grid;
+ gap: 2px;
+}
+
+.perform-diagnostic-switcher__context strong {
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 1.35;
+}
+
+.perform-diagnostic-switcher__context small {
+ color: var(--perform-color-text-muted);
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+.perform-diagnostic-switcher__control {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex: 0 0 auto;
+}
+
+.perform-diagnostic-switcher__control > span {
+ color: var(--perform-color-text-muted);
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.perform-diagnostic-switcher__control select {
+ min-width: 220px;
+ height: 40px;
+ margin: 0;
+ border-color: var(--perform-color-border);
+ border-radius: 7px;
+ color: var(--perform-color-text);
+ background-color: var(--perform-color-surface);
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.perform-diagnostic-switcher__control select:focus {
+ border-color: var(--perform-color-focus);
+ outline: 2px solid var(--perform-color-focus);
+ outline-offset: 2px;
+ box-shadow: none;
+}
+
.perform-settings-tab-panel .components-tab-panel__tabs-item:focus-visible,
.perform-settings-page .components-button:focus-visible,
.perform-settings-page a:focus-visible {
@@ -278,6 +370,8 @@
.perform-savebar .components-button {
min-height: 40px;
+ font-size: 13px;
+ font-weight: 600;
}
.perform-cache-stats-container {
@@ -445,6 +539,19 @@
min-width: 0;
}
+.perform-dashboard .components-card,
+.perform-database-audit .components-card,
+.perform-site-inventory .components-card,
+.perform-admin-monitor .components-card,
+.perform-cron-pressure .components-card,
+.perform-admin-assets .components-card,
+.perform-plugin-impact .components-card,
+.perform-action-scheduler .components-card {
+ border: 1px solid var(--perform-color-border);
+ border-radius: var(--perform-radius-card);
+ box-shadow: var(--perform-shadow-card);
+}
+
.perform-dashboard-overview {
display: flex;
align-items: flex-start;
@@ -512,26 +619,68 @@
background: #f6f7f7;
}
+.perform-dashboard-stats .perform-dashboard-stat {
+ display: grid;
+ grid-template-columns: 42px minmax(0, 1fr);
+ align-items: center;
+ gap: 14px;
+ min-height: 104px;
+ padding: 16px;
+ border: 1px solid var(--perform-color-border);
+ border-left: 1px solid var(--perform-color-border);
+ border-radius: var(--perform-radius-card);
+ background: var(--perform-color-surface);
+ box-shadow: var(--perform-shadow-card);
+}
+
+.perform-dashboard-stat__icon {
+ display: inline-flex !important;
+ align-items: center;
+ justify-content: center;
+ width: 42px;
+ height: 42px;
+ border-radius: 10px;
+ color: var(--perform-color-brand) !important;
+ background: var(--perform-color-surface-accent);
+}
+
+.perform-dashboard-stat__icon[data-status='ready'] {
+ color: var(--perform-color-success) !important;
+ background: #edf8ef;
+}
+
+.perform-dashboard-stat__icon[data-status='review'] {
+ color: var(--perform-color-warning) !important;
+ background: #fff8e5;
+}
+
+.perform-dashboard-stat__content {
+ min-width: 0;
+}
+
.perform-health-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.perform-health-card {
- border-radius: 0;
- border-left: 4px solid var(--perform-color-border);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
+ --perform-health-status: var(--perform-color-text-muted);
+ --perform-health-status-bg: #f1f2f3;
+ border-left: 1px solid var(--perform-color-border) !important;
}
.perform-health-card[data-status='ready'] {
- border-left-color: var(--perform-color-success);
+ --perform-health-status: #006b1b;
+ --perform-health-status-bg: #edf8ef;
}
.perform-health-card[data-status='review'] {
- border-left-color: var(--perform-color-warning);
+ --perform-health-status: var(--perform-color-warning);
+ --perform-health-status-bg: #fff8e5;
}
.perform-health-card[data-status='observe'] {
- border-left-color: var(--perform-color-brand);
+ --perform-health-status: var(--perform-color-brand);
+ --perform-health-status-bg: var(--perform-color-surface-accent);
}
.perform-health-card__heading {
@@ -547,20 +696,49 @@
line-height: 1.35;
}
-.perform-health-card__heading span {
+.perform-health-card__title {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-width: 0;
+}
+
+.perform-health-card__icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 34px;
+ height: 34px;
+ border-radius: 8px;
+ color: var(--perform-health-status);
+ background: var(--perform-health-status-bg);
+}
+
+.perform-health-card__icon .perform-ui-icon {
+ width: 19px;
+ height: 19px;
+}
+
+.perform-health-card__status {
display: inline-flex;
flex-shrink: 0;
align-items: center;
+ gap: 5px;
min-height: 24px;
padding: 2px 8px;
border: 1px solid var(--perform-color-border);
border-radius: 12px;
- background: #f6f7f7;
- color: var(--perform-color-text-muted);
+ background: var(--perform-health-status-bg);
+ color: var(--perform-health-status);
font-size: 11px;
font-weight: 600;
}
+.perform-health-card__status .perform-ui-icon {
+ width: 14px;
+ height: 14px;
+}
+
.perform-health-card p {
min-height: 44px;
margin: 12px 0;
@@ -569,9 +747,18 @@
}
.perform-dashboard-measurement-note {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
padding: 16px 20px;
- border-left: 4px solid var(--perform-color-brand);
- background: #f6f7f7;
+ border: 1px solid #c9d9ff;
+ border-radius: var(--perform-radius-card);
+ background: var(--perform-color-surface-accent);
+}
+
+.perform-dashboard-measurement-note > .perform-ui-icon {
+ margin-top: 1px;
+ color: var(--perform-color-brand);
}
.perform-dashboard-measurement-note p {
@@ -609,6 +796,17 @@
margin-bottom: 8px;
}
+.perform-card-heading {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+}
+
+.perform-card-heading > .perform-ui-icon {
+ margin-top: 1px;
+ color: var(--perform-color-brand);
+}
+
.perform-database-audit {
display: grid;
gap: 24px;
@@ -1688,6 +1886,7 @@
}
.perform-settings-tab-panel .components-tab-panel__tabs,
+ .perform-diagnostic-switcher,
.perform-settings-content,
.perform-savebar {
padding-right: 16px;
@@ -1699,6 +1898,23 @@
padding-bottom: 40px;
}
+ .perform-diagnostic-switcher {
+ align-items: stretch;
+ flex-direction: column;
+ gap: 14px;
+ }
+
+ .perform-diagnostic-switcher__control {
+ align-items: stretch;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .perform-diagnostic-switcher__control select {
+ width: 100%;
+ max-width: none;
+ }
+
.perform-settings-field {
grid-template-columns: minmax(0, 1fr);
gap: 16px;
diff --git a/assets/src/js/admin/ActionSchedulerPanel.jsx b/assets/src/js/admin/ActionSchedulerPanel.jsx
index d337354..ff4bc7a 100644
--- a/assets/src/js/admin/ActionSchedulerPanel.jsx
+++ b/assets/src/js/admin/ActionSchedulerPanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
+import { ArrowPathIcon, TrashIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -133,11 +134,25 @@ const ActionSchedulerPanel = ( { initialAudit = SETTINGS.actionScheduler || {} }
onClick={ () => request( 'perform_refresh_action_scheduler_audit' ) }
disabled={ Boolean( working ) }
isBusy={ 'refresh' === working }
+ icon={
+ 'refresh' === working ? undefined : (
+
+ )
+ }
>
{ refreshLabel }
{ hasAudit && (
-
) }
diff --git a/assets/src/js/admin/AdminAssetAuditPanel.jsx b/assets/src/js/admin/AdminAssetAuditPanel.jsx
index d4f41e7..9191d73 100644
--- a/assets/src/js/admin/AdminAssetAuditPanel.jsx
+++ b/assets/src/js/admin/AdminAssetAuditPanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
+import { AdjustmentsHorizontalIcon, TrashIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -69,11 +70,16 @@ const AdminAssetAuditPanel = ( { initialSnapshot = SETTINGS.adminAssetAudit || {
onClick={ clearAudit }
disabled={ clearing || ! screens.length }
isBusy={ clearing }
+ icon={ clearing ? undefined : }
>
{ clearing ? __( 'Clearing…', 'perform' ) : __( 'Clear audit', 'perform' ) }
) : (
- onNavigate?.( 'advanced' ) }>
+ onNavigate?.( 'advanced' ) }
+ icon={ }
+ >
{ __( 'Enable in Advanced', 'perform' ) }
) }
diff --git a/assets/src/js/admin/AdminPerformanceMonitorPanel.jsx b/assets/src/js/admin/AdminPerformanceMonitorPanel.jsx
index 3fd48fd..4d687cb 100644
--- a/assets/src/js/admin/AdminPerformanceMonitorPanel.jsx
+++ b/assets/src/js/admin/AdminPerformanceMonitorPanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
+import { AdjustmentsHorizontalIcon, TrashIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -97,11 +98,16 @@ const AdminPerformanceMonitorPanel = ( { initialSnapshot = SETTINGS.adminPerform
onClick={ clearData }
disabled={ clearing || 0 === contexts.length }
isBusy={ clearing }
+ icon={ clearing ? undefined : }
>
{ clearing ? __( 'Clearing…', 'perform' ) : __( 'Clear collected data', 'perform' ) }
) : (
- onNavigate?.( 'advanced' ) }>
+ onNavigate?.( 'advanced' ) }
+ icon={ }
+ >
{ __( 'Enable in Advanced', 'perform' ) }
) }
diff --git a/assets/src/js/admin/CacheStatsPanel.jsx b/assets/src/js/admin/CacheStatsPanel.jsx
index 9f9dd91..1a90186 100644
--- a/assets/src/js/admin/CacheStatsPanel.jsx
+++ b/assets/src/js/admin/CacheStatsPanel.jsx
@@ -138,7 +138,13 @@ const CacheStatsPanel = ( { onClearSuccess = ( redirect ) => window.location.ass
: }
+ icon={
+ 'export' === activeAction ? (
+
+ ) : (
+
+ )
+ }
disabled={ isBusy }
onClick={ exportActivity }
>
@@ -149,7 +155,13 @@ const CacheStatsPanel = ( { onClearSuccess = ( redirect ) => window.location.ass
: }
+ icon={
+ 'clear' === activeAction ? (
+
+ ) : (
+
+ )
+ }
disabled={ isBusy }
onClick={ clearActivity }
>
diff --git a/assets/src/js/admin/CronPressurePanel.jsx b/assets/src/js/admin/CronPressurePanel.jsx
index df3c0cf..3f71f3a 100644
--- a/assets/src/js/admin/CronPressurePanel.jsx
+++ b/assets/src/js/admin/CronPressurePanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
+import { ArrowPathIcon, TrashIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -87,11 +88,25 @@ const CronPressurePanel = ( { initialAudit = SETTINGS.cronPressure || {} } ) =>
onClick={ () => request( 'perform_refresh_cron_pressure_audit' ) }
disabled={ Boolean( working ) }
isBusy={ 'refresh' === working }
+ icon={
+ 'refresh' === working ? undefined : (
+
+ )
+ }
>
{ refreshLabel }
{ hasAudit && (
-
+
+ )
+ }
+ >
{ 'clear' === working ? __( 'Clearing…', 'perform' ) : __( 'Clear snapshot', 'perform' ) }
) }
diff --git a/assets/src/js/admin/DashboardPanel.jsx b/assets/src/js/admin/DashboardPanel.jsx
index 9c2c4e8..ee7e789 100644
--- a/assets/src/js/admin/DashboardPanel.jsx
+++ b/assets/src/js/admin/DashboardPanel.jsx
@@ -1,5 +1,21 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { __, _n, sprintf } from '@wordpress/i18n';
+import {
+ ArrowTopRightOnSquareIcon,
+ BoltIcon,
+ CheckCircleIcon,
+ CircleStackIcon,
+ CodeBracketSquareIcon,
+ CpuChipIcon,
+ DocumentTextIcon,
+ EyeIcon,
+ ExclamationTriangleIcon,
+ InformationCircleIcon,
+ MinusCircleIcon,
+ ServerStackIcon,
+ ShoppingCartIcon,
+ Squares2X2Icon,
+} from '@heroicons/react/24/outline';
const STATUS_LABELS = {
ready: __( 'Ready', 'perform' ),
@@ -8,6 +24,22 @@ const STATUS_LABELS = {
'not-measured': __( 'Not measured', 'perform' ),
};
+const STATUS_ICONS = {
+ ready: CheckCircleIcon,
+ review: ExclamationTriangleIcon,
+ observe: EyeIcon,
+ 'not-measured': MinusCircleIcon,
+};
+
+const HEALTH_CARD_ICONS = {
+ inventory: Squares2X2Icon,
+ database: CircleStackIcon,
+ runtime: CpuChipIcon,
+ cache: BoltIcon,
+ server: ServerStackIcon,
+ store: ShoppingCartIcon,
+};
+
const formatBytes = ( bytes ) => {
const value = Number( bytes );
if ( ! Number.isFinite( value ) || value <= 0 ) {
@@ -187,28 +219,48 @@ const buildHealthCards = ( { dashboard, diagnostics, databaseAudit, siteInventor
return cards;
};
-const HealthCard = ( { card, onAction } ) => (
-
-
-
-
{ card.title }
- { STATUS_LABELS[ card.status ] || STATUS_LABELS[ 'not-measured' ] }
-
- { card.description }
- { card.action && (
- onAction( card.action ) }>
- { card.action.label }
-
- ) }
-
-
-);
+const HealthCard = ( { card, onAction } ) => {
+ const CardIcon = HEALTH_CARD_ICONS[ card.id ] || CpuChipIcon;
+ const StatusIcon = STATUS_ICONS[ card.status ] || STATUS_ICONS[ 'not-measured' ];
-const StatCard = ( { label, value, description } ) => (
+ return (
+
+
+
+
+
+
+
+
{ card.title }
+
+
+
+ { STATUS_LABELS[ card.status ] || STATUS_LABELS[ 'not-measured' ] }
+
+
+ { card.description }
+ { card.action && (
+ onAction( card.action ) }>
+ { card.action.label }
+
+ ) }
+
+
+ );
+};
+
+const StatCard = ( { label, value, description, icon: Icon, status } ) => (
-
{ label }
-
{ value }
- { description &&
{ description }
}
+ { Icon && (
+
+
+
+ ) }
+
+
{ label }
+
{ value }
+ { description &&
{ description }
}
+
);
@@ -258,10 +310,24 @@ const DashboardPanel = ( { dashboard, diagnostics, databaseAudit, siteInventory,
-
+ }
+ iconPosition="right"
+ >
{ __( 'View documentation', 'perform' ) }
-
+ }
+ iconPosition="right"
+ >
{ __( 'Get support', 'perform' ) }
@@ -272,16 +338,22 @@ const DashboardPanel = ( { dashboard, diagnostics, databaseAudit, siteInventory,
label={ __( 'Ready', 'perform' ) }
value={ readyCount }
description={ __( 'Measured local areas', 'perform' ) }
+ icon={ CheckCircleIcon }
+ status="ready"
/>
@@ -292,23 +364,32 @@ const DashboardPanel = ( { dashboard, diagnostics, databaseAudit, siteInventory,
-
{ __( 'Core Web Vitals need a separate test', 'perform' ) }
-
- { __(
- 'Local WordPress diagnostics cannot prove real-user LCP, INP, or CLS. Field data and lab testing remain separate evidence sources.',
- 'perform'
- ) }
-
+
+
+
{ __( 'Core Web Vitals need a separate test', 'perform' ) }
+
+ { __(
+ 'Local WordPress diagnostics cannot prove real-user LCP, INP, or CLS. Field data and lab testing remain separate evidence sources.',
+ 'perform'
+ ) }
+
+
-
-
{ __( 'Cache value observed', 'perform' ) }
-
- { __( 'Measured requests from this site, without estimated time savings.', 'perform' ) }
-
+
+
+
+
{ __( 'Cache value observed', 'perform' ) }
+
+ { __(
+ 'Measured requests from this site, without estimated time savings.',
+ 'perform'
+ ) }
+
+
@@ -335,11 +416,17 @@ const DashboardPanel = ( { dashboard, diagnostics, databaseAudit, siteInventory,
-
-
{ __( 'Configured asset coverage', 'perform' ) }
-
- { __( 'Configured rules only; no historical byte savings are claimed.', 'perform' ) }
-
+
+
+
+
{ __( 'Configured asset coverage', 'perform' ) }
+
+ { __(
+ 'Configured rules only; no historical byte savings are claimed.',
+ 'perform'
+ ) }
+
+
@@ -370,11 +457,14 @@ const DashboardPanel = ( { dashboard, diagnostics, databaseAudit, siteInventory,
-
-
{ __( 'What this build includes', 'perform' ) }
-
- { __( 'Evidence-bound product updates included in the current code.', 'perform' ) }
-
+
+
+
+
{ __( 'What this build includes', 'perform' ) }
+
+ { __( 'Evidence-bound product updates included in the current code.', 'perform' ) }
+
+
diff --git a/assets/src/js/admin/DashboardPanel.test.jsx b/assets/src/js/admin/DashboardPanel.test.jsx
index d9284cc..e36b940 100644
--- a/assets/src/js/admin/DashboardPanel.test.jsx
+++ b/assets/src/js/admin/DashboardPanel.test.jsx
@@ -53,7 +53,7 @@ describe( 'DashboardPanel', () => {
} );
it( 'uses measured local evidence for status and avoids an invented score', () => {
- render(
+ const { container } = render(
{
expect( screen.getByText( 'Core Web Vitals need a separate test' ) ).toBeInTheDocument();
expect( screen.getByText( /never turns these checks into an unverified speed score/i ) ).toBeInTheDocument();
expect( screen.getByText( /Response compression: needs a separate response test/ ) ).toBeInTheDocument();
+ expect( container.querySelectorAll( 'svg.perform-ui-icon[aria-hidden="true"]' ).length ).toBeGreaterThan( 8 );
} );
it( 'shows store-safety guidance only when a store pattern is measured', () => {
diff --git a/assets/src/js/admin/DatabaseAuditPanel.jsx b/assets/src/js/admin/DatabaseAuditPanel.jsx
index fabf7e6..5a54891 100644
--- a/assets/src/js/admin/DatabaseAuditPanel.jsx
+++ b/assets/src/js/admin/DatabaseAuditPanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
+import { ArrowPathIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -81,7 +82,13 @@ const DatabaseAuditPanel = ( { initialAudit = SETTINGS.databaseAudit || {} } ) =
) }
-
+ }
+ >
{ refreshLabel }
diff --git a/assets/src/js/admin/PluginImpactPanel.jsx b/assets/src/js/admin/PluginImpactPanel.jsx
index f2b30de..333e15e 100644
--- a/assets/src/js/admin/PluginImpactPanel.jsx
+++ b/assets/src/js/admin/PluginImpactPanel.jsx
@@ -1,5 +1,6 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
+import { ArrowRightIcon } from '@heroicons/react/24/outline';
const SETTINGS = window.performwpSettings || {};
@@ -8,19 +9,34 @@ const PluginImpactPanel = ( { report = SETTINGS.pluginImpact || {}, onNavigate }
const audit = report.adminAssetAudit || {};
const inventoryReady = 'ready' === report.status;
let primaryAction = (
- onNavigate?.( 'admin-assets' ) }>
+ onNavigate?.( 'admin-assets' ) }
+ icon={ }
+ iconPosition="right"
+ >
{ __( 'View admin asset evidence', 'perform' ) }
);
if ( ! inventoryReady ) {
primaryAction = (
- onNavigate?.( 'inventory' ) }>
+ onNavigate?.( 'inventory' ) }
+ icon={ }
+ iconPosition="right"
+ >
{ __( 'Generate site inventory', 'perform' ) }
);
} else if ( ! audit.enabled ) {
primaryAction = (
- onNavigate?.( 'advanced' ) }>
+ onNavigate?.( 'advanced' ) }
+ icon={ }
+ iconPosition="right"
+ >
{ __( 'Enable admin asset audit', 'perform' ) }
);
diff --git a/assets/src/js/admin/SettingsHeader.jsx b/assets/src/js/admin/SettingsHeader.jsx
index a6f7d6b..a9f8113 100644
--- a/assets/src/js/admin/SettingsHeader.jsx
+++ b/assets/src/js/admin/SettingsHeader.jsx
@@ -14,7 +14,7 @@ const SettingsHeader = () => (
href={ DOCS_URL }
target="_blank"
rel="noopener noreferrer"
- icon={ }
+ icon={ }
iconPosition="right"
>
View Documentation
diff --git a/assets/src/js/admin/SettingsNav.jsx b/assets/src/js/admin/SettingsNav.jsx
index fa2ceb3..c9a0624 100644
--- a/assets/src/js/admin/SettingsNav.jsx
+++ b/assets/src/js/admin/SettingsNav.jsx
@@ -1,5 +1,7 @@
import { TabPanel } from '@wordpress/components';
+import { WrenchScrewdriverIcon } from '@heroicons/react/24/outline';
import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
import CacheStatsPanel from './CacheStatsPanel';
import AdminPerformanceMonitorPanel from './AdminPerformanceMonitorPanel';
import DashboardPanel from './DashboardPanel';
@@ -12,6 +14,16 @@ import ActionSchedulerPanel from './ActionSchedulerPanel';
import SettingsFieldRow from './settings/SettingsFieldRow';
const SETTINGS = window.performwpSettings || {};
+const DIAGNOSTIC_TAB_KEYS = [
+ 'inventory',
+ 'database',
+ 'admin-monitor',
+ 'admin-assets',
+ 'plugin-impact',
+ 'scheduled-tasks',
+ 'action-scheduler',
+ 'cache-stats',
+];
const SettingsNav = ( {
tabs: propTabs,
@@ -33,9 +45,23 @@ const SettingsNav = ( {
} ) => {
const tabs = useMemo( () => propTabs || SETTINGS.tabs || {}, [ propTabs ] );
const fields = useMemo( () => propFields || SETTINGS.fields || {}, [ propFields ] );
- const tabKeys = useMemo( () => [ 'dashboard', ...Object.keys( tabs ) ], [ tabs ] );
+ const diagnosticTabKeys = useMemo(
+ () => DIAGNOSTIC_TAB_KEYS.filter( ( slug ) => Object.prototype.hasOwnProperty.call( tabs, slug ) ),
+ [ tabs ]
+ );
+ const tabKeys = useMemo( () => {
+ const keys = [
+ 'dashboard',
+ ...Object.keys( tabs ).filter( ( slug ) => ! DIAGNOSTIC_TAB_KEYS.includes( slug ) ),
+ ];
+ if ( diagnosticTabKeys.length > 0 ) {
+ keys.push( 'diagnostics' );
+ }
+ return keys;
+ }, [ tabs, diagnosticTabKeys ] );
const [ internalActiveTab, setInternalActiveTab ] = useState( tabKeys[ 0 ] || '' );
const activeTab = propActiveTab ?? internalActiveTab;
+ const activePrimaryTab = diagnosticTabKeys.includes( activeTab ) ? 'diagnostics' : activeTab;
const onTabChange = propOnTabChange ?? setInternalActiveTab;
const [ internalFieldValues, setInternalFieldValues ] = useState( {} );
const fieldValues = propFieldValues ?? internalFieldValues;
@@ -47,18 +73,22 @@ const SettingsNav = ( {
[ id ]: value,
} ) ) );
const tabPanelRef = useRef( null );
-
useEffect( () => {
const selectedTab = tabPanelRef.current?.querySelector( '[role="tab"][aria-selected="true"]' );
- selectedTab?.scrollIntoView( { block: 'nearest', inline: 'nearest' } );
+ selectedTab?.scrollIntoView?.( { block: 'nearest', inline: 'nearest' } );
}, [ activeTab ] );
const tabPanelTabs = useMemo(
() =>
- tabKeys.map( ( slug ) => ( {
- name: slug,
- title: 'dashboard' === slug ? 'Dashboard' : tabs[ slug ],
- } ) ),
+ tabKeys.map( ( slug ) => {
+ let title = tabs[ slug ];
+ if ( 'dashboard' === slug ) {
+ title = 'Dashboard';
+ } else if ( 'diagnostics' === slug ) {
+ title = __( 'Diagnostics', 'perform' );
+ }
+ return { name: slug, title };
+ } ),
[ tabKeys, tabs ]
);
@@ -69,18 +99,25 @@ const SettingsNav = ( {
return (
{
- if ( tabName !== activeTab ) {
- onTabChange( tabName );
+ let nextTab = tabName;
+ if ( 'diagnostics' === tabName ) {
+ nextTab = diagnosticTabKeys.includes( activeTab ) ? activeTab : diagnosticTabKeys[ 0 ];
+ }
+ if ( nextTab && nextTab !== activeTab ) {
+ onTabChange( nextTab );
}
} }
>
{ ( selectedTab ) => {
- const selectedTabName = selectedTab?.name || activeTab;
+ let selectedTabName = selectedTab?.name || activeTab;
+ if ( 'diagnostics' === selectedTab?.name ) {
+ selectedTabName = diagnosticTabKeys.includes( activeTab ) ? activeTab : diagnosticTabKeys[ 0 ];
+ }
const sections = fields[ selectedTabName ] || [];
let content = (
@@ -148,7 +185,46 @@ const SettingsNav = ( {
content =
;
}
- return
{ content }
;
+ return (
+ <>
+ { diagnosticTabKeys.includes( selectedTabName ) && (
+
+
+
+
+
+
+ { __( 'Diagnostics workspace', 'perform' ) }
+
+ { __( 'Private, local reports for this WordPress site', 'perform' ) }
+
+
+
+
+
+ ) }
+
{ content }
+ >
+ );
} }
diff --git a/assets/src/js/admin/SettingsNav.test.jsx b/assets/src/js/admin/SettingsNav.test.jsx
new file mode 100644
index 0000000..66f63fd
--- /dev/null
+++ b/assets/src/js/admin/SettingsNav.test.jsx
@@ -0,0 +1,38 @@
+/* eslint-env jest */
+
+import '@testing-library/jest-dom';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import SettingsNav from './SettingsNav';
+
+describe( 'SettingsNav', () => {
+ it( 'groups advanced diagnostics behind one primary tab and a report selector', async () => {
+ render(
+
+ );
+
+ expect( screen.getByRole( 'tab', { name: 'Diagnostics' } ) ).toBeInTheDocument();
+ expect( screen.queryByRole( 'tab', { name: 'Site Inventory' } ) ).not.toBeInTheDocument();
+
+ await act( async () => {
+ fireEvent.click( screen.getByRole( 'tab', { name: 'Diagnostics' } ) );
+ } );
+ const reportSelector = screen.getByRole( 'combobox', { name: 'Current report' } );
+ expect( reportSelector ).toHaveValue( 'inventory' );
+ expect( screen.getByText( 'Private, local reports for this WordPress site' ) ).toBeInTheDocument();
+ expect( screen.queryByRole( 'tablist', { name: 'Diagnostic tools' } ) ).not.toBeInTheDocument();
+
+ await act( async () => {
+ fireEvent.change( reportSelector, { target: { value: 'database' } } );
+ } );
+ expect( reportSelector ).toHaveValue( 'database' );
+ } );
+} );
diff --git a/assets/src/js/admin/SiteInventoryPanel.jsx b/assets/src/js/admin/SiteInventoryPanel.jsx
index f479c05..600eb9e 100644
--- a/assets/src/js/admin/SiteInventoryPanel.jsx
+++ b/assets/src/js/admin/SiteInventoryPanel.jsx
@@ -1,6 +1,7 @@
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
+import { ArrowPathIcon } from '@heroicons/react/24/outline';
import SystemHealthPanel from './SystemHealthPanel';
const SETTINGS = window.performwpSettings || {};
@@ -105,7 +106,13 @@ const SiteInventoryPanel = ( {
) }
-
+ }
+ >
{ refreshLabel }
diff --git a/assets/src/js/admin/settings/SettingsFieldRow.jsx b/assets/src/js/admin/settings/SettingsFieldRow.jsx
index c6bc634..0853d50 100644
--- a/assets/src/js/admin/settings/SettingsFieldRow.jsx
+++ b/assets/src/js/admin/settings/SettingsFieldRow.jsx
@@ -128,7 +128,7 @@ const SettingsFieldRow = ( { field, value, onChange } ) => {
className="perform-settings-field__learn-more"
>
Learn more
-
+
) }
diff --git a/config/constants.php b/config/constants.php
index 7f6cca2..1159cd7 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -6,7 +6,7 @@
// Define plugin version in SemVer format.
if ( ! defined( 'PERFORM_VERSION' ) ) {
- define( 'PERFORM_VERSION', '1.7.0' );
+ define( 'PERFORM_VERSION', '1.8.0' );
}
// Define plugin root File.
diff --git a/languages/perform.pot b/languages/perform.pot
index 5538ee0..21da56c 100644
--- a/languages/perform.pot
+++ b/languages/perform.pot
@@ -165,7 +165,7 @@ msgid "Remove unnecessary frontend scripts and tags that add extra requests or b
msgstr ""
#: src/Includes/Helpers.php:347
-msgid "Disable Emoji's"
+msgid "Disable Emojis"
msgstr ""
#: src/Includes/Helpers.php:348
diff --git a/package-lock.json b/package-lock.json
index 62a4cef..8365ffa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "perform",
- "version": "1.7.0",
+ "version": "1.8.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "perform",
- "version": "1.7.0",
+ "version": "1.8.0",
"license": "GPL-3.0-or-later",
"devDependencies": {
"@heroicons/react": "^2.2.0",
diff --git a/package.json b/package.json
index 032e8e9..d672fa6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "perform",
- "version": "1.7.0",
+ "version": "1.8.0",
"description": "Web Performance Optimization Plugin for WordPress",
"homepage": "https://github.com/performwp/perform#readme",
"license": "GPL-3.0-or-later",
diff --git a/perform.php b/perform.php
index 1a84e32..1094c45 100644
--- a/perform.php
+++ b/perform.php
@@ -17,7 +17,7 @@
* Plugin Name: Perform - Optimize Performance
* Plugin URI: https://performwp.com/
* Description: This plugin adds toolset for performance and speed improvements to your WordPress sites.
- * Version: 1.7.0
+ * Version: 1.8.0
* Author: Mehul Gohil
* Author URI: https://mehulgohil.com/
* License: GPLv3 or later
diff --git a/phpstan-bootstrap.php b/phpstan-bootstrap.php
index 4414c61..3bca6b3 100644
--- a/phpstan-bootstrap.php
+++ b/phpstan-bootstrap.php
@@ -17,7 +17,7 @@
}
if ( ! defined( 'PERFORM_VERSION' ) ) {
- define( 'PERFORM_VERSION', '1.7.0' );
+ define( 'PERFORM_VERSION', '1.8.0' );
}
if ( ! defined( 'PERFORM_PLUGIN_FILE' ) ) {
diff --git a/readme.txt b/readme.txt
index bddc4c3..11ccd28 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,9 +3,9 @@ Contributors: performwp, mehul0810, ankur0812
Tags: performance, caching, cdn, assets, optimize
Donate link: https://www.buymeacoffee.com/mehulgohil
Requires at least: 4.8
-Tested up to: 7.0
+Tested up to: 7.1
Requires PHP: 7.4
-Stable tag: 1.7.0
+Stable tag: 1.8.0
License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.html
@@ -15,7 +15,7 @@ Optimize WordPress performance with asset controls, page caching, CDN rewriting,
Perform helps site owners reduce unnecessary frontend work in WordPress. It combines asset controls, cache features, CDN rewriting, and small cleanup modules in one settings area.
-Version 1.7.0 focuses on safer, easier-to-understand controls for real sites: a dashboard overview, dashboard-only runtime diagnostics, page cache exclusion and lifecycle controls, an Assets Manager reset action, consistent settings layouts, and Cache Stats integrated into the main settings tabs.
+Version 1.8.0 adds privacy-conscious diagnostics for overloaded WordPress admin environments, clearer performance guidance, and a calmer settings navigation hierarchy.
Key capabilities:
@@ -56,8 +56,8 @@ Menu Cache is designed for classic themes that render menus through `wp_nav_menu
= Does Assets Manager scan the whole site? =
Assets Manager scans the current frontend page while you are logged in as an administrator. Use it page by page for safer asset decisions, then test important templates before applying broad changes.
-= Are settings preserved when updating to 1.7.0? =
-Yes. Perform 1.7.0 preserves existing public option keys and migrates legacy settings into the current settings shape where needed.
+= Are settings preserved when updating to 1.8.0? =
+Yes. Perform 1.8.0 preserves existing public option keys and migrates legacy settings into the current settings shape where needed.
== Support ==
@@ -67,6 +67,15 @@ Contributions and bug reports welcome on GitHub: https://github.com/performwp/pe
== Changelog ==
+= 1.8.0 =
+- Added privacy-conscious site inventory and system-health guidance for performance troubleshooting.
+- Added bounded diagnostics for autoloaded options, object cache status, slow admin screens, scheduled tasks, admin assets, plugin impact, and Action Scheduler queues.
+- Added a performance health dashboard that reports observed evidence without claiming unmeasured savings.
+- Reduced classic Menu Cache key cardinality and hardened purge tracking.
+- Simplified settings navigation by grouping advanced reports under Diagnostics while preserving existing report URLs.
+- Refined dashboard hierarchy, status visuals, responsive layouts, and keyboard navigation.
+- Confirmed compatibility with WordPress 7.1.
+
= 1.7.0 - 2026-07-26 =
- Added a dashboard overview for faster at-a-glance site status.
- Added a dashboard-only runtime diagnostics panel for environment and plugin inspection.
@@ -126,8 +135,8 @@ Contributions and bug reports welcome on GitHub: https://github.com/performwp/pe
== Upgrade Notice ==
-= 1.7.0 =
-Review Assets Manager, cache exclusions, Cache Stats, and runtime diagnostics after updating. Cache Stats now appears under Settings > Perform, and its export and clear actions report progress and results.
+= 1.8.0 =
+Review the new diagnostics and dashboard guidance after updating. Perform 1.8.0 keeps existing settings and report URLs while adding read-only evidence for troubleshooting overloaded WordPress admin environments.
== Screenshots ==
diff --git a/src/Includes/Helpers.php b/src/Includes/Helpers.php
index 0ead8d9..819dba6 100644
--- a/src/Includes/Helpers.php
+++ b/src/Includes/Helpers.php
@@ -344,7 +344,7 @@ public static function get_settings_fields() {
[
'id' => 'disable_emojis',
'type' => 'toggle',
- 'name' => __( 'Disable Emoji\'s', 'perform' ),
+ 'name' => __( 'Disable Emojis', 'perform' ),
'desc' => __( 'Prevents WordPress from loading the emoji detection script and related styles, reducing one extra HTTP request.', 'perform' ),
'help_link' => esc_url(
add_query_arg(
diff --git a/tests/e2e/perform-smoke.spec.js b/tests/e2e/perform-smoke.spec.js
index 57e64a0..69595e1 100644
--- a/tests/e2e/perform-smoke.spec.js
+++ b/tests/e2e/perform-smoke.spec.js
@@ -120,7 +120,7 @@ test( 'Site Inventory refresh is private, bounded, and responsive', async ( { pa
await login( page );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=inventory' );
- await expect( page.getByRole( 'tab', { name: 'Site Inventory' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'inventory' );
await expect( page.getByText( 'Private and local' ) ).toBeVisible();
await expect( page.getByText( /no post content, option values, private URLs/i ) ).toBeVisible();
await expect( page.getByRole( 'heading', { name: 'System health' } ) ).toBeVisible();
@@ -153,7 +153,7 @@ test( 'Scheduled-task pressure is bounded, private, resettable, and responsive',
await login( page );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=scheduled-tasks' );
- await expect( page.getByRole( 'tab', { name: 'Scheduled Tasks' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'scheduled-tasks' );
await expect( page.getByText( 'Read-only and bounded' ) ).toBeVisible();
await expect( page.getByText( /excludes hook arguments, payloads, URLs, and user data/ ) ).toBeVisible();
await page.getByRole( 'button', { name: /Run check|Refresh check/ } ).click();
@@ -181,7 +181,7 @@ test( 'Action Scheduler diagnostic handles an absent queue without mutation', as
await login( page );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=action-scheduler' );
- await expect( page.getByRole( 'tab', { name: 'Action Scheduler' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'action-scheduler' );
await expect( page.getByText( 'Read-only and private' ) ).toBeVisible();
await expect( page.getByText( /never runs, cancels, or deletes queued work/ ) ).toBeVisible();
await page.getByRole( 'button', { name: /Run check|Refresh check/ } ).click();
@@ -216,7 +216,7 @@ test( 'Admin Performance Monitor is opt-in, bounded, private, clearable, and res
await page.goto( '/wp-admin/edit.php' );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=admin-monitor' );
- await expect( page.getByRole( 'tab', { name: 'Admin Monitor' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'admin-monitor' );
await expect( page.getByText( 'Aggregate-only and per site' ) ).toBeVisible();
await expect( page.getByText( /does not store full URLs, query arguments, request payloads/ ) ).toBeVisible();
await expect( page.getByText( 'edit-post' ) ).toBeVisible();
@@ -249,16 +249,16 @@ test( 'Admin asset audit is opt-in, bounded, private, clearable, and responsive'
const auditToggle = page.getByRole( 'checkbox', { name: 'Admin Asset Audit' } );
if ( ! ( await auditToggle.isChecked() ) ) {
await auditToggle.check();
+ await page.getByRole( 'button', { name: 'Save Settings' } ).click();
+ await expect( page.getByText( /Settings saved/ ) ).toBeVisible();
}
- await page.getByRole( 'button', { name: 'Save Settings' } ).click();
- await expect( page.getByText( /Settings saved/ ) ).toBeVisible();
await page.goto( '/wp-admin/index.php' );
await page.goto( '/wp-admin/edit.php' );
await page.goto( '/wp-admin/plugins.php' );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=admin-assets' );
- await expect( page.getByRole( 'tab', { name: 'Admin Assets' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'admin-assets' );
await expect( page.getByText( 'Inventory only — nothing is disabled' ) ).toBeVisible();
await expect( page.getByText( /URLs, query strings, nonces, and user data are not stored/ ) ).toBeVisible();
await expect( page.getByText( 'Repeated across admin screens' ) ).toBeVisible();
@@ -291,13 +291,13 @@ test( 'Plugin impact report separates measured local evidence from unavailable a
const auditToggle = page.getByRole( 'checkbox', { name: 'Admin Asset Audit' } );
if ( ! ( await auditToggle.isChecked() ) ) {
await auditToggle.check();
+ await page.getByRole( 'button', { name: 'Save Settings' } ).click();
+ await expect( page.getByText( /Settings saved/ ) ).toBeVisible();
}
- await page.getByRole( 'button', { name: 'Save Settings' } ).click();
- await expect( page.getByText( /Settings saved/ ) ).toBeVisible();
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=general' );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings&tab=plugin-impact' );
- await expect( page.getByRole( 'tab', { name: 'Plugin Impact' } ) ).toHaveAttribute( 'aria-selected', 'true' );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveValue( 'plugin-impact' );
await expect( page.getByText( 'Evidence, not a plugin ranking' ) ).toBeVisible();
await expect( page.getByText( /does not attribute query, callback, or memory cost/ ) ).toBeVisible();
await expect( page.getByText( /Zero means not observed in this sample/ ) ).toBeVisible();
@@ -339,17 +339,18 @@ test( 'Classic menu cache stays functional across unrelated query variables', as
expect( await page.locator( '#perform-test-navigation' ).innerHTML() ).toBe( firstMarkup );
} );
-test( 'Cache Stats tab preserves legacy routing, actions, and keyboard access', async ( { page } ) => {
+test( 'Cache Stats report preserves legacy routing, actions, and keyboard access', async ( { page } ) => {
await login( page );
await openAdminPage( page, '/wp-admin/options-general.php?page=perform_settings' );
- const cacheStatsTab = page.getByRole( 'tab', { name: 'Cache Stats' } );
- await cacheStatsTab.focus();
- await expect( cacheStatsTab ).toBeFocused();
- await expect( cacheStatsTab ).toHaveCSS( 'outline-style', 'solid' );
- await page.keyboard.press( 'Enter' );
-
- await expect( cacheStatsTab ).toHaveAttribute( 'aria-selected', 'true' );
+ await page.getByRole( 'tab', { name: 'Diagnostics' } ).click();
+ const reportSelector = page.getByLabel( 'Current report' );
+ await reportSelector.focus();
+ await expect( reportSelector ).toBeFocused();
+ await expect( reportSelector ).toHaveCSS( 'outline-style', 'solid' );
+ await reportSelector.selectOption( 'cache-stats' );
+
+ await expect( reportSelector ).toHaveValue( 'cache-stats' );
await expect( page ).toHaveURL( /[?&]tab=cache-stats(?:&|$)/ );
await expect( page.getByRole( 'heading', { name: 'Perform Cache Observability' } ) ).toBeVisible();
await expect( page.getByRole( 'button', { name: 'Purge Site Page Cache' } ) ).toBeVisible();
@@ -426,7 +427,7 @@ test( 'lower-privilege users cannot access the legacy or canonical Cache Stats r
expect( canonicalResponse.status() ).not.toBe( 302 );
await expect( page ).toHaveURL( /page=perform_settings&tab=cache-stats$/ );
await expect( page.getByText( 'Sorry, you are not allowed to access this page.' ) ).toBeVisible();
- await expect( page.getByRole( 'tab', { name: 'Cache Stats' } ) ).toHaveCount( 0 );
+ await expect( page.getByLabel( 'Current report' ) ).toHaveCount( 0 );
const protectedActions = [
[ 'perform_purge_page_cache', 'You are not allowed to purge the page cache.' ],
diff --git a/tests/unit-tests/tests-dashboard-payload.php b/tests/unit-tests/tests-dashboard-payload.php
index b242f74..43842fb 100644
--- a/tests/unit-tests/tests-dashboard-payload.php
+++ b/tests/unit-tests/tests-dashboard-payload.php
@@ -87,7 +87,7 @@ public function test_assets_manager_summary_counts_rule_coverage_not_bytes_saved
public function test_empty_dashboard_payload_has_safe_defaults() {
$payload = DashboardPayload::get_data();
- $this->assertSame( '1.7.0', $payload['version'] );
+ $this->assertSame( '1.8.0', $payload['version'] );
$this->assertFalse( $payload['cache']['hasStats'] );
$this->assertSame( 0.0, $payload['cache']['hitRatio'] );
$this->assertSame( 0, $payload['assetsManager']['disabledJsHandles'] );