PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.3.2
Adminify – White Label, Admin Menu Editor, Login Customizer v4.3.2
4.3.2 4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 All 165 releases
← All changes | Inc/Classes/Assets.php +278 -50 4.2.224.3.2 View file →
@@ -29,15 +29,41 @@
29 29 add_action('admin_enqueue_scripts', array($this, 'pxlbsadminify_admin_scripts'), 100);
30 30 add_action('wp_ajax_pxlbsadminify_addons_install_active', array( $this, 'pxlbsadminify_addons_install_active' ) );
31 31 add_action('wp_ajax_pxlbsadminify_ssl_check', array( $this, 'pxlbsadminify_ssl_check' ) );
32 32
33 - if ($this->is_dark_mode() || $this->classic_editor || $this->block_editor) {
34 - add_action('admin_head', array($this, 'header_scripts'));
35 - }
33 + // Always hooked: header_scripts() prints the dark-mode loader, which the
34 + // topbar toggle needs even on pages that booted in light mode.
35 + add_action('admin_head', array($this, 'header_scripts'));
36 36 }
37 37
38 38
39 39 /**
40 + * Resolved light/dark mode for the current user, normalised to
41 + * 'light' | 'dark' | 'system'. The settings UI has used 'auto' as a
42 + * synonym for 'system', so fold that in here.
43 + *
44 + * @return string
45 + */
46 + public function color_mode()
47 + {
48 + $mode = !empty($this->dark_mode) ? $this->dark_mode : 'light';
49 +
50 + return ('auto' === $mode) ? 'system' : $mode;
51 + }
52 +
53 +
54 + /**
55 + * URL of the dark mode (Darkreader) bundle.
56 + *
57 + * @return string
58 + */
59 + private function dark_mode_url()
60 + {
61 + return PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify-dark-mode' . Utils::assets_ext('.js');
62 + }
63 +
64 +
65 + /**
40 66 * Function: Ajax Call for Install and Activate WP Adminify Plugin
41 67 */
42 68 function pxlbsadminify_addons_install_active()
43 69 {
@@ -149,8 +175,25 @@
149 175 }
150 176 return $adminify_dark_mode;
151 177 }
152 178
179 + /**
180 + * Print the dark-mode loader and boot it for the resolved mode.
181 + *
182 + * The Darkreader bundle is ~110 KB, so it is no longer enqueued on every admin
183 + * page. What ships on every page instead is `window.PXLBSADMINIFYDarkMode`, a few hundred
184 + * bytes that know how to pull the bundle into a window on demand:
185 + *
186 + * - 'dark' the bundle is already enqueued in the head by
187 + * pxlbsadminify_admin_scripts(), so this only calls enable().
188 + * - 'system' nothing is enqueued; the browser decides. When the OS prefers dark
189 + * the loader fetches the bundle, with a pre-paint guard so the page
190 + * does not flash white while it streams in.
191 + * - 'light' nothing is fetched at all.
192 + *
193 + * The topbar toggle (classic admin bar and the React frame alike) calls
194 + * PXLBSADMINIFYDarkMode.load() so switching to dark works without a page reload.
195 + */
153 196 public function header_scripts()
154 197 {
155 198 // Skip on excluded pages
156 199 if ( $this->should_skip_adminify_scripts() ) {
@@ -156,46 +199,120 @@
156 199 if ( $this->should_skip_adminify_scripts() ) {
157 200 return;
158 201 }
159 202
160 - if (!empty($this->dark_mode) && $this->dark_mode == 'dark') { ?>
203 + $mode = $this->color_mode();
204 + ?>
205 + <script id="adminify-dark-mode-loader">
206 + window.PXLBSADMINIFYDarkMode = window.PXLBSADMINIFYDarkMode || (function () {
207 + var url = <?php echo wp_json_encode( $this->dark_mode_url() ); ?>;
161 208
209 + // Pulls the bundle into `win` (defaults to this window) and hands
210 + // AdminifyDarkMode to `cb`. Repeat calls while a fetch is in flight
211 + // queue up behind it instead of requesting the file again.
212 + function load(win, cb) {
213 + win = win || window;
214 + cb = cb || function () {};
215 +
216 + var doc;
217 + try {
218 + doc = win.document;
219 + } catch (e) {
220 + return;
221 + }
222 + if (!doc) {
223 + return;
224 + }
225 +
226 + if (win.AdminifyDarkMode) {
227 + cb(win.AdminifyDarkMode);
228 + return;
229 + }
230 +
231 + if (win.__pxlbsadminifyDarkModeQueue) {
232 + win.__pxlbsadminifyDarkModeQueue.push(cb);
233 + return;
234 + }
235 + win.__pxlbsadminifyDarkModeQueue = [cb];
236 +
237 + var script = doc.createElement('script');
238 + script.src = url;
239 + script.async = false;
240 + script.onload = function () {
241 + var queue = win.__pxlbsadminifyDarkModeQueue || [];
242 + win.__pxlbsadminifyDarkModeQueue = null;
243 + for (var i = 0; i < queue.length; i++) {
244 + try {
245 + queue[i](win.AdminifyDarkMode);
246 + } catch (e) {}
247 + }
248 + };
249 + script.onerror = function () {
250 + win.__pxlbsadminifyDarkModeQueue = null;
251 + };
252 + (doc.head || doc.documentElement).appendChild(script);
253 + }
254 +
255 + function enable(win) {
256 + load(win, function (dm) {
257 + if (dm) {
258 + dm.enable({ brightness: 120 });
259 + }
260 + });
261 + }
262 +
263 + function disable(win) {
264 + win = win || window;
265 + // Nothing to undo when the bundle was never fetched.
266 + if (win.AdminifyDarkMode) {
267 + win.AdminifyDarkMode.disable();
268 + }
269 + }
270 +
271 + return { url: url, load: load, enable: enable, disable: disable };
272 + }());
273 + </script>
274 + <?php if ( 'dark' === $mode ) { ?>
162 275 <script>
163 - window.AdminifyDarkMode.enable({
164 - brightness: 120
165 - })
166 -
167 - addEventListener("load", (event) => {
168 - window.AdminifyDarkMode.enable({
169 - brightness: 120
170 - })
276 + window.PXLBSADMINIFYDarkMode.enable();
277 + addEventListener("load", function () {
278 + window.PXLBSADMINIFYDarkMode.enable();
171 279 });
172 280 </script>
173 - <?php }
281 + <?php } elseif ( 'system' === $mode ) { ?>
282 + <script>
283 + (function () {
284 + if (!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
285 + return;
286 + }
174 287
175 - if (!empty($this->dark_mode) && $this->dark_mode == 'system') { ?>
176 - <script>
177 - const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
178 - if(!!isDark) {
179 - window.AdminifyDarkMode.enable({
180 - brightness: 120
181 - })
288 + // The bundle is fetched rather than blocking in the head, so paint
289 + // the page dark up front and drop the guard once Darkreader owns it.
290 + var guard = document.createElement('style');
291 + guard.textContent = 'html,body{background-color:#181a1b!important;color:#e8e6e3!important}';
292 + (document.head || document.documentElement).appendChild(guard);
182 293
183 - addEventListener("load", (event) => {
184 - window.AdminifyDarkMode.enable({
185 - brightness: 120
186 - })
294 + var dropGuard = function () {
295 + if (guard && guard.parentNode) {
296 + guard.parentNode.removeChild(guard);
297 + }
298 + };
299 +
300 + window.PXLBSADMINIFYDarkMode.load(window, function (dm) {
301 + if (dm) {
302 + dm.enable({ brightness: 120 });
303 + }
304 + dropGuard();
187 305 });
188 - } else {
189 - window.AdminifyDarkMode.disable()
190 306
191 - addEventListener("load", (event) => {
192 - window.AdminifyDarkMode.disable()
307 + // Failsafe: never leave the guard behind if the fetch never lands.
308 + setTimeout(dropGuard, 5000);
309 +
310 + addEventListener("load", function () {
311 + window.PXLBSADMINIFYDarkMode.enable();
193 312 });
194 - }
195 -
313 + }());
196 314 </script>
197 -
198 315 <?php }
199 316
200 317 }
201 318
@@ -242,8 +359,120 @@
242 359 return false;
243 360 }
244 361
245 362
363 + /**
364 + * Matches a Font Awesome class in any of the shapes Adminify stores:
365 + * "fa fa-gear", "fas fa-rocket", and the URL-encoded "fas%20fa-rocket" that
366 + * WordPress produces when an icon class is handed to add_menu_page().
367 + */
368 + const FONTAWESOME_CLASS_PATTERN = '/(?:^|[^a-z0-9-])fa[bsrl]?(?:\s|%20|-)fa-/i';
369 +
370 +
371 + /**
372 + * Whether Font Awesome has anything to paint on the current screen.
373 + *
374 + * The stylesheet plus its webfonts weigh well over a megabyte, so it is only
375 + * worth loading where Adminify actually renders an icon with it:
376 + *
377 + * - Adminify's own screens, whose section headers and field UI use hardcoded
378 + * `fas fa-*` classes.
379 + * - The dashboard, but only when a widget is actually configured with a Font
380 + * Awesome class.
381 + * - Any screen at all when an admin menu item carries a Font Awesome icon,
382 + * because the sidebar renders on every screen.
383 + *
384 + * Framework option, metabox, taxonomy, widget, customizer, nav-menu, profile
385 + * and comment screens are deliberately not listed: the framework scopes and
386 + * enqueues Font Awesome itself in ADMINIFY::add_admin_enqueue_scripts().
387 + *
388 + * @param \WP_Screen|null $screen Current screen.
389 + * @return bool
390 + */
391 + private function needs_fontawesome( $screen ) {
392 +
393 + if ( isset( $screen->id ) && false !== strpos( $screen->id, 'wp-adminify' ) ) {
394 + return true;
395 + }
396 +
397 + if ( isset( $screen->id ) && 'dashboard' === $screen->id && $this->has_fontawesome_dashboard_widget() ) {
398 + return true;
399 + }
400 +
401 + // Falls through on the dashboard too: the admin menu renders there as well.
402 + return $this->has_fontawesome_menu_icon();
403 + }
404 +
405 +
406 + /**
407 + * Whether any dashboard widget is configured with a Font Awesome class.
408 + *
409 + * Widget icons come from the framework icon field, whose list is still Font
410 + * Awesome (Libs/adminify-framework/functions/actions.php), and the editor and
411 + * script widget types can hold arbitrary markup — so scan the whole saved
412 + * option rather than just the icon keys, or a widget whose body contains
413 + * `<i class="fas fa-star">` would render a blank square.
414 + *
415 + * The option is the one read by DashboardWidgetModel::$prefix, which the
416 + * Dashboard Widget module already loads on every admin page, so this is an
417 + * options-cache hit rather than a query. Only ever called on the dashboard.
418 + *
419 + * @return bool
420 + */
421 + private function has_fontawesome_dashboard_widget() {
422 +
423 + $settings = get_option( 'pxlbsadminify_dasboard_widgets' );
424 +
425 + if ( empty( $settings ) ) {
426 + return false;
427 + }
428 +
429 + // Arrays and objects come back as a serialized string; scalars pass through.
430 + $settings = maybe_serialize( $settings );
431 +
432 + if ( ! is_string( $settings ) || '' === $settings ) {
433 + return false;
434 + }
435 +
436 + return (bool) preg_match( self::FONTAWESOME_CLASS_PATTERN, $settings );
437 + }
438 +
439 +
440 + /**
441 + * Look for a Font Awesome class stored as an admin menu icon.
442 + *
443 + * Pro admin pages pass the picked icon class straight to add_menu_page()
444 + * (Pro/Modules/AdminPages/AdminPages_Output.php), where WordPress treats it as
445 + * an image URL and prints `http://fas%20fa-rocket`; wp-adminify.js turns that
446 + * back into a class. Either shape counts as a hit.
447 + *
448 + * $menu is built during admin_menu, which runs before admin_enqueue_scripts,
449 + * so it is fully populated by the time this is called.
450 + *
451 + * @return bool
452 + */
453 + private function has_fontawesome_menu_icon() {
454 + global $menu;
455 +
456 + if ( empty( $menu ) || ! is_array( $menu ) ) {
457 + return false;
458 + }
459 +
460 + foreach ( $menu as $item ) {
461 +
462 + if ( empty( $item[6] ) || ! is_string( $item[6] ) ) {
463 + continue;
464 + }
465 +
466 + if ( preg_match( self::FONTAWESOME_CLASS_PATTERN, $item[6] ) ) {
467 + return true;
468 + }
469 + }
470 +
471 + return false;
472 + }
473 +
474 +
246 475 public function pxlbsadminify_admin_scripts()
247 476 {
248 477 // Skip loading scripts on excluded pages (customize.php, login, etc.)
249 478 if ( $this->should_skip_adminify_scripts() ) {
@@ -255,25 +484,13 @@
255 484
256 485 // Register Styles
257 486 wp_register_style('adminify-admin', PXLBSADMINIFY_ASSETS . 'css/wp-adminify' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
258 487 wp_register_style('adminify-default-ui', PXLBSADMINIFY_ASSETS . 'css/wp-adminify-default-ui' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
259 - // wp_register_style('wp-adminify-admin-bar', PXLBSADMINIFY_ASSETS . 'css/admin-bar' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
260 - wp_register_style('adminify-menu-editor', PXLBSADMINIFY_ASSETS . 'css/adminify-menu-editor' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
261 - // wp_register_style('wp-adminify-dark-mode', PXLBSADMINIFY_ASSETS . 'css/dark-mode' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
262 - // wp_register_style('wp-adminify-rtl', PXLBSADMINIFY_ASSETS . 'css/adminify-rtl' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
263 - // wp_register_style('wp-adminify-responsive', PXLBSADMINIFY_ASSETS . 'css/adminify-responsive' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
264 - // wp_register_style('wp-adminify-animate', PXLBSADMINIFY_ASSETS . 'vendors/animatecss/animate' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
265 - wp_register_style('adminify-tokenize2', PXLBSADMINIFY_ASSETS . 'vendors/tokenize/tokenize2' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
266 - wp_register_style('adminify-select2', PXLBSADMINIFY_ASSETS . 'vendors/select2/select2' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
267 488
268 489
269 490 // Register Scripts
270 - wp_register_script('adminify-tokenize2', PXLBSADMINIFY_ASSETS . 'vendors/tokenize/tokenize2.min.js', array('jquery'), PXLBSADMINIFY_VER, false);
271 - wp_register_script('adminify-select2', PXLBSADMINIFY_ASSETS . 'vendors/select2/select2.min.js', array('jquery'), PXLBSADMINIFY_VER, true);
272 491 wp_register_script('adminify-admin', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify' . Utils::assets_ext('.js'), array('jquery'), PXLBSADMINIFY_VER, true);
273 492
274 - // wp_register_script('wp-adminify-realtime-server', PXLBSADMINIFY_ASSETS . 'js/adminify-realtime-server.js', array('jquery'), PXLBSADMINIFY_VER, true);
275 -
276 493 // Adminify Icon Picker
277 494 wp_register_style('adminify-simple-line-icons', PXLBSADMINIFY_ASSETS . 'vendors/font-icons/simple-line-icons/css/simple-line-icons' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
278 495 wp_register_style('adminify-icon-picker', PXLBSADMINIFY_ASSETS . 'vendors/adminify-icon-picker/css/style' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
279 496 wp_register_script('adminify-icon-picker', PXLBSADMINIFY_ASSETS . 'vendors/adminify-icon-picker/js/adminify-icon-picker' . Utils::assets_ext('.js'), array('jquery'), PXLBSADMINIFY_VER, true);
@@ -278,13 +495,10 @@
278 495 wp_register_style('adminify-icon-picker', PXLBSADMINIFY_ASSETS . 'vendors/adminify-icon-picker/css/style' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
279 496 wp_register_script('adminify-icon-picker', PXLBSADMINIFY_ASSETS . 'vendors/adminify-icon-picker/js/adminify-icon-picker' . Utils::assets_ext('.js'), array('jquery'), PXLBSADMINIFY_VER, true);
280 497
281 498 // Dark Mode
282 - wp_register_script('adminify--dark-mode', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify-dark-mode' . Utils::assets_ext('.js'), array(), PXLBSADMINIFY_VER, false);
499 + wp_register_script('adminify--dark-mode', $this->dark_mode_url(), array(), PXLBSADMINIFY_VER, false);
283 500
284 - // Menu Editor
285 - wp_register_script('adminify-menu-editor', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify-menu-editor' . Utils::assets_ext('.js'), array('jquery', 'jquery-ui-sortable', 'adminify-icon-picker'), PXLBSADMINIFY_VER, true);
286 -
287 501 // Styles Enqueue
288 502 if (!empty($this->options['admin_ui'])) {
289 503 // wp_enqueue_style('wp-adminify-animate');
290 504 wp_enqueue_style('adminify-admin');
@@ -289,9 +503,8 @@
289 503 // wp_enqueue_style('wp-adminify-animate');
290 504 wp_enqueue_style('adminify-admin');
291 505 // Commented on: 9-6-24
292 506 // wp_enqueue_style('wp-adminify-admin-bar');
293 - // wp_enqueue_style('wp-adminify-responsive');
294 507 } else {
295 508 wp_enqueue_style('adminify-default-ui');
296 509 }
297 510
@@ -303,11 +516,17 @@
303 516
304 517
305 518 // Dark Mode Style
306 519 // wp_enqueue_style('adminify-dark-mode');
307 - wp_enqueue_script('adminify--dark-mode');
308 520
521 + // Only a user who is actually in dark mode gets the ~110 KB bundle up front.
522 + // 'system' is resolved in the browser and 'light' never needs it at all; both
523 + // go through the loader printed by header_scripts().
524 + if ('dark' === $this->color_mode()) {
525 + wp_enqueue_script('adminify--dark-mode');
526 + }
309 527
528 +
310 529 // Get local fonts data for frontend - download if not exists
311 530 $local_fonts = GoogleFontsLocal::get_instance();
312 531 $local_fonts_urls = [];
313 532
@@ -364,9 +583,14 @@
364 583 // Scripts Enqueue
365 584 wp_enqueue_script('adminify-admin');
366 585 wp_localize_script( 'adminify-admin', 'PXLBSADMINIFY_ADMIN', $localize_array_data );
367 586
368 - if (!wp_script_is('adminify-fa', 'enqueued') || !wp_script_is('adminify-fa5', 'enqueued')) {
587 + // Font Awesome, only on screens that actually paint an icon with it. The
588 + // old guard called wp_script_is() on what are styles, so it always passed
589 + // and every admin page paid for the font. wp_enqueue_style() is a no-op on
590 + // an already-enqueued handle, so no guard is needed against the framework
591 + // having enqueued these first.
592 + if ($this->needs_fontawesome($screen)) {
369 593 if (apply_filters('adminify_fa4', false)) {
370 594 wp_enqueue_style('adminify-fa', PXLBSADMINIFY_ASSETS . 'vendors/fontawesome/fa4/css/font-awesome.min.css', array(), '4.7.0', 'all');
371 595 } else {
372 596 wp_enqueue_style('adminify-fa5', PXLBSADMINIFY_ASSETS . 'vendors/fontawesome/fa5/css/all.min.css', array(), '5.15.4', 'all');
@@ -390,8 +614,12 @@
390 614 'generic_error' => esc_html__('Could not verify HTTPS right now. Please try again.', 'adminify'),
391 615 ),
392 616 )
393 617 );
618 +
619 + // Adminify UI live theme preset changer
620 + wp_enqueue_script('adminify-theme-presetter', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify-theme-presetter' . Utils::assets_ext('.js'), ['jquery'], PXLBSADMINIFY_VER, true);
621 + wp_localize_script('adminify-theme-presetter', 'PXLBSADMINIFY_PRESET_THEMES', Utils::get_theme_presets());
394 622 }
395 623
396 624 if ($screen->id === 'adminify_page_wp-adminify-addons-plugins' || $screen->id === 'adminify-pro_page_wp-adminify-addons-plugins') {
397 625 // JS Files .