PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / includes / dashboard / class-wp-optimize-dashboard.php

class-wp-optimize-dashboard.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at includes/dashboard/class-wp-optimize-dashboard.php

326 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('Access denied.');
4
5 if (!class_exists('WP_Optimize_Dashboard')) :
6
7 /**
8 * WP-Optimize Dashboard orchestrator.
9 *
10 * Assembles the full data payload the dashboard template needs.
11 * Heavy lifting is delegated to per-module data classes.
12 */
13 class WP_Optimize_Dashboard {
14
15 /** @var WP_Optimize_Dashboard */
16 private static $instance = null;
17
18 /** @return self */
19 public static function instance(): self {
20 if (null === self::$instance) {
21 self::$instance = new self();
22 }
23 return self::$instance;
24 }
25
26 private function __construct() {
27 }
28
29 /**
30 * Full payload for the dashboard template.
31 *
32 * @return array<string, mixed>
33 */
34 public function get_dashboard_data(): array {
35 $module_data = $this->get_modules_data();
36 $modules = $this->get_module_statuses($module_data);
37 $setup = $this->get_setup_progress($modules);
38
39 return array(
40 'modules' => $modules,
41 'savings' => $this->get_savings_summary($module_data['cache'], $module_data['images'], $module_data['minify']),
42 'cache' => $module_data['cache'],
43 'images' => $module_data['images'],
44 'minify' => $module_data['minify'],
45 'database' => $module_data['database'],
46 'setup' => $setup,
47 'banner' => $this->get_banner_view_data($modules, $setup),
48 'is_premium' => WP_Optimize::is_premium(),
49 );
50 }
51
52 /**
53 * Builds all pre-computed strings the setup-banner template needs for display.
54 * Keeps the template free of logic.
55 *
56 * @param array<string, array{active: bool, label: string, scheduled: bool}> $modules Output of get_module_statuses().
57 * @param array{active_modules: int, total_modules: int, pending_modules: string[], running_days: int} $setup Output of get_setup_progress().
58 * @return array<string, mixed>
59 */
60 private function get_banner_view_data(array $modules, array $setup): array {
61 $active_count = (int) $setup['active_modules'];
62 $total_count = (int) $setup['total_modules'];
63 $running_days = (int) $setup['running_days'];
64 $is_complete = $total_count === $active_count;
65 $is_start = 0 === $active_count;
66
67 $module_labels = array(
68 'cache' => __('caching', 'wp-optimize'),
69 'images' => __('image compression', 'wp-optimize'),
70 'minify' => __('minification', 'wp-optimize'),
71 'database' => __('database cleanup', 'wp-optimize'),
72 );
73
74 $cta_page_map = array(
75 'cache' => 'wpo_cache',
76 'images' => 'wpo_images',
77 'minify' => 'wpo_minify',
78 'database' => 'wpo_database',
79 );
80
81 $cta_label_map = array(
82 'cache' => __('Set up cache', 'wp-optimize'),
83 'images' => __('Set up images', 'wp-optimize'),
84 'minify' => __('Setup minification', 'wp-optimize'),
85 'database' => __('Set up database', 'wp-optimize'),
86 );
87
88 $eyebrow = sprintf(
89 /* translators: %1$d active, %2$d total */
90 __('%1$d OF %2$d MODULES ACTIVE', 'wp-optimize'),
91 $active_count,
92 $total_count
93 );
94
95 if ($is_start) {
96 $eyebrow = __('Get started', 'wp-optimize');
97 $title = __('Make your site faster in a few clicks', 'wp-optimize');
98 $subtitle = __('WP-Optimize can cache pages, compress images, clean your database, and minify code.', 'wp-optimize')
99 . ' ' . __('Pick a module below or let us set up the basics for you.', 'wp-optimize');
100
101 global $wp_version;
102 $onboarding_supported = version_compare(PHP_VERSION, '7.4', '>=') && version_compare($wp_version, '6.2', '>=');
103 $cta_href = $onboarding_supported ? WP_Optimize()->get_onboarding()->get_reopen_onboarding_url() : '';
104 $cta_label = $onboarding_supported ? __('Quick setup', 'wp-optimize') : '';
105 } elseif ($is_complete) {
106 $title = __('Your site is optimised', 'wp-optimize');
107 $active_labels = $this->collect_module_labels($modules, $module_labels, true);
108 $subtitle = ucfirst(sprintf(
109 /* translators: %s = comma-separated module names */
110 _n('%s is active.', '%s are active.', count($active_labels), 'wp-optimize'),
111 self::join_with_and($active_labels)
112 ));
113 $subtitle = $active_labels ? $subtitle : '';
114 $cta_href = '';
115 $cta_label = '';
116 } else {
117 $title = __('You\'re almost set up', 'wp-optimize');
118 $active_labels = $this->collect_module_labels($modules, $module_labels, true);
119 $pending_labels = $this->collect_module_labels($modules, $module_labels, false);
120 $subtitle = '';
121 if ($active_labels) {
122 $subtitle .= ucfirst(sprintf(
123 /* translators: %s = comma-separated module names */
124 _n('%s is active.', '%s are active.', count($active_labels), 'wp-optimize'),
125 self::join_with_and($active_labels)
126 )) . ' ';
127 }
128 if ($pending_labels) {
129 $subtitle .= ucfirst(sprintf(
130 /* translators: %s = comma-separated module names */
131 _n('%s is available when you\'re ready.', '%s are available when you\'re ready.', count($pending_labels), 'wp-optimize'),
132 self::join_with_and($pending_labels)
133 ));
134 }
135
136 $pending_key = $setup['pending_modules'][0] ?? null;
137 if (null !== $pending_key && isset($cta_page_map[$pending_key])) {
138 $cta_href = WP_Optimize()->get_options()->admin_page_url($cta_page_map[$pending_key]);
139 $cta_label = $cta_label_map[$pending_key];
140 } else {
141 $cta_href = '';
142 $cta_label = '';
143 }
144 }
145 $running_label = sprintf(
146 /* translators: %d = days */
147 _n('Running for %d day', 'Running for %d days', $running_days, 'wp-optimize'),
148 $running_days
149 );
150 $running_label = $running_days > 0 ? $running_label : __('Installed today', 'wp-optimize');
151
152 return array(
153 'is_start' => $is_start,
154 'is_complete' => $is_complete,
155 'eyebrow' => $eyebrow,
156 'title' => $title,
157 'subtitle' => $subtitle,
158 'running_label' => $running_label,
159 'cta_href' => $cta_href,
160 'cta_label' => $cta_label,
161 );
162 }
163
164 /**
165 * Collects human-readable module labels for either active or pending modules.
166 *
167 * @param array<string, array{active: bool, label: string, scheduled: bool}> $modules Module statuses.
168 * @param array<string, string> $label_map Human-readable label per module key.
169 * @param bool $active_only True = collect active, false = collect pending.
170 * @return string[]
171 */
172 private function collect_module_labels(array $modules, array $label_map, bool $active_only): array {
173 $result = array();
174 foreach ($modules as $key => $module) {
175 $is_active = $module['active'] || $module['scheduled'];
176 if ($active_only === $is_active) {
177 $result[] = $label_map[$key] ?? strtolower($module['label']);
178 }
179 }
180 return $result;
181 }
182
183 /**
184 * Joins items with ", " and "and" before the last entry.
185 * ["A"] → "A"; ["A","B"] → "A and B"; ["A","B","C"] → "A, B, and C".
186 *
187 * @param string[] $items
188 * @return string
189 */
190 private static function join_with_and(array $items): string {
191 $count = count($items);
192 if (0 === $count) return '';
193 if (1 === $count) return $items[0];
194 if (2 === $count) return $items[0] . ' ' . __('and', 'wp-optimize') . ' ' . $items[1];
195 $last = array_pop($items);
196 return implode(', ', $items) . ', ' . __('and', 'wp-optimize') . ' ' . $last;
197 }
198
199 /**
200 * Instantiates each module class and calls collect() once.
201 *
202 * @return array{cache: WpoDashboardCacheData, images: WpoDashboardImagesData, minify: WpoDashboardMinifyData, database: WpoDashboardDatabaseData}
203 */
204 private function get_modules_data(): array {
205 return array(
206 'cache' => (new WP_Optimize_Dashboard_Cache())->collect(),
207 'images' => (new WP_Optimize_Dashboard_Images())->collect(),
208 'minify' => (new WP_Optimize_Dashboard_Minify())->collect(),
209 'database' => (new WP_Optimize_Dashboard_Database())->collect(),
210 );
211 }
212
213 /**
214 * Returns active/label/features status for each module.
215 *
216 * @param array<string, array<string, mixed>> $module_data Already-fetched module data arrays.
217 * @return array<string, array{active: bool, label: string, scheduled: bool}>
218 */
219 private function get_module_statuses(array $module_data): array {
220 $statuses = array();
221 foreach ($module_data as $key => $data) {
222 $statuses[$key] = array(
223 'active' => !empty($data['active']),
224 'label' => is_string($data['label']) ? $data['label'] : $key,
225 'scheduled' => !empty($data['scheduled']),
226 );
227 }
228 return $statuses;
229 }
230
231 /**
232 * Aggregates byte savings from all modules.
233 * Segment colors: Media=#1A80BB, Database=#EAC11C, Cache=#B8B8B8, Files=#605F69.
234 *
235 * @param WpoDashboardCacheData $cache
236 * @param WpoDashboardImagesData $images
237 * @param WpoDashboardMinifyData $minify
238 *
239 * @return array<string, mixed>
240 */
241 private function get_savings_summary($cache, $images, $minify): array {
242 $image_bytes = $images['saved_bytes'];
243 $db_bytes = (int) WP_Optimize()->get_options()->get_option('db_bytes_saved', 0);
244 $cache_bytes = $cache['cache_size_bytes'];
245 $files_bytes = $minify['saved_bytes'];
246 $total = $image_bytes + $db_bytes + $cache_bytes + $files_bytes;
247
248 $total_human_formatted = size_format(max(0, $total), 1);
249 $parts = is_string($total_human_formatted) ? explode(' ', $total_human_formatted, 2) : array('0', 'B');
250 $number = $parts[0];
251 $unit = $parts[1] ?? 'B';
252
253 $total_human = sprintf('%s <span class="size-unit">%s</span>', esc_html($number), esc_html($unit));
254
255 return array(
256 'total_bytes' => $total,
257 'total_human' => $total_human,
258 'image_bytes' => $image_bytes,
259 'image_human' => (string) size_format($image_bytes, 1),
260 'database_bytes' => $db_bytes,
261 'database_human' => (string) size_format($db_bytes, 1),
262 'cache_bytes' => $cache_bytes,
263 'cache_human' => (string) size_format($cache_bytes, 1),
264 'files_bytes' => $files_bytes,
265 'files_human' => (string) size_format($files_bytes, 1),
266 'image_pct' => self::savings_pct($image_bytes, $total),
267 'database_pct' => self::savings_pct($db_bytes, $total),
268 'cache_pct' => self::savings_pct($cache_bytes, $total),
269 'files_pct' => self::savings_pct($files_bytes, $total),
270 );
271 }
272
273 /**
274 * Returns how many modules are active and which are still pending setup.
275 *
276 * @param array<string, array{active: bool, label: string, scheduled: bool}> $modules Output of get_module_statuses().
277 * @return array{active_modules: int, total_modules: int, pending_modules: string[], running_days: int}
278 */
279 private function get_setup_progress(array $modules): array {
280 $total = count($modules);
281 $active = 0;
282 $pending = array();
283
284 foreach ($modules as $key => $data) {
285 if (!empty($data['active']) || !empty($data['scheduled'])) {
286 $active++;
287 } else {
288 $pending[] = $key;
289 }
290 }
291
292 return array(
293 'total_modules' => $total,
294 'active_modules' => $active,
295 'pending_modules' => $pending,
296 'running_days' => $this->days_since_activation(),
297 );
298 }
299
300 /**
301 * Returns the percentage share of $part in $total, clamped to [1, 100].
302 * Returns 0 if either value is non-positive.
303 *
304 * @param int $part
305 * @param int $total
306 * @return int
307 */
308 private static function savings_pct(int $part, int $total): int {
309 if ($total <= 0 || $part <= 0) return 0;
310 return min(100, max(1, (int) round(($part / $total) * 100)));
311 }
312
313 /**
314 * Returns the number of days since the plugin was first activated.
315 *
316 * @return int Days elapsed, or 0 if the activation timestamp is not recorded.
317 */
318 private function days_since_activation(): int {
319 $activated = WP_Optimize()->get_options()->get_option('newly-activated', null);
320 // Legacy installs stored `true` instead of a timestamp — treat as unknown.
321 if (!is_numeric($activated) || (int) $activated <= 0) return 0;
322 return (int) floor((time() - (int) $activated) / DAY_IN_SECONDS);
323 }
324 }
325 endif;
326