PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.1.3
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.1.3
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
← All changes | src/Admin/Admin.php +103 -1 2.1.12.1.3 View file →
@@ -42,8 +42,17 @@
42 42 private $version;
43 43 public $unique_id;
44 44
45 45 /**
46 + * Whether enqueue_scripts() actually put the admin engine in the queue on
47 + * this request. Read by darkify_restore_no_conflict_scripts(), which must
48 + * only re-add handles Darkify itself asked for.
49 + *
50 + * @var bool
51 + */
52 + private $engine_enqueued = false;
53 +
54 + /**
46 55 * The class constructor.
47 56 *
48 57 * @param string $plugin_name The slug of the plugin.
49 58 * @param string $version Current version of the plugin.
@@ -98,8 +107,30 @@
98 107 // src/Admin/Views/*.php, so the text domain has to be registered first —
99 108 // Darkify::load_textdomain() runs on this same hook at priority 1.
100 109 add_action('after_setup_theme', array($this, 'init_components'));
101 110 add_filter('autoptimize_filter_js_exclude', array($this, 'darkify_exclude_js_from_cache_plugins'));
111 +
112 + /*
113 + * "No-conflict mode" compatibility.
114 + *
115 + * Fluent Forms, FluentCRM, Fluent Booking, FluentSMTP, WP Social Ninja
116 + * and friends dequeue *every* script served from wp-content/plugins on
117 + * their own admin screens (Fluent Forms: app/Hooks/actions.php, on
118 + * `wp_print_scripts` priority 1). That runs after `admin_enqueue_scripts`,
119 + * so it strips Darkify's engine while the admin-bar node — printed by
120 + * `admin_bar_menu` and untouched by the dequeue — keeps its inline
121 + * onclick, producing "darkify_switch_trigger is not defined" and a dead
122 + * toggle on e.g. admin.php?page=fluent_forms.
123 + *
124 + * Two layers: the published allow-list filters where a plugin offers one,
125 + * and a generic re-enqueue after their sweep for the ones that don't.
126 + */
127 + add_filter('fluentform/exclude_js_slugs_from_dequeue', array($this, 'darkify_no_conflict_allow_slugs'));
128 + add_filter('fluent_crm_asset_listed_slugs', array($this, 'darkify_no_conflict_allow_slugs'));
129 + add_filter('fluent_booking/asset_listed_slugs', array($this, 'darkify_no_conflict_allow_slugs'));
130 + add_action('wp_print_scripts', array($this, 'darkify_restore_no_conflict_scripts'), 100);
131 + add_action('wp_print_styles', array($this, 'darkify_restore_no_conflict_styles'), 100);
132 +
102 133 add_action('admin_init', [$this, 'load_classic_editor_scripts']);
103 134 add_filter('admin_footer_text', array($this, 'darkify_admin_footer'), 1, 2);
104 135 $active_plugins = get_option('active_plugins');
105 136 foreach ($active_plugins as $active_plugin) {
@@ -280,11 +311,71 @@
280 311 array('darkify-darkreader'),
281 312 $this->darkify_asset_version($darkify_engine_rel),
282 313 false
283 314 );
315 +
316 + $this->engine_enqueued = true;
284 317 }
285 318
286 319 /**
320 + * Add Darkify to a no-conflict allow-list.
321 + *
322 + * Both filter shapes this is attached to pass an array of substrings matched
323 + * against the script `src`, so the plugin folder name is the right token.
324 + *
325 + * @param array $slugs Allowed slugs.
326 + *
327 + * @return array
328 + */
329 + public function darkify_no_conflict_allow_slugs($slugs)
330 + {
331 + if (! is_array($slugs)) {
332 + return $slugs;
333 + }
334 +
335 + $slugs[] = 'darkify';
336 +
337 + return array_unique($slugs);
338 + }
339 +
340 + /**
341 + * Put the admin engine back after a no-conflict sweep dropped it.
342 + *
343 + * Runs on `wp_print_scripts` at 100 — after the sweeps, which all hook it at
344 + * 1 — and before `do_items()`, so a re-enqueue here still prints. Gated on
345 + * `$engine_enqueued`, so it never resurrects a script Darkify itself chose
346 + * not to load (or dequeued in admin_dequeue_for_specefic_pages).
347 + */
348 + public function darkify_restore_no_conflict_scripts()
349 + {
350 + if (! $this->engine_enqueued || ! is_admin()) {
351 + return;
352 + }
353 +
354 + foreach (array('darkify-darkreader', 'darkify-admin-engine') as $handle) {
355 + if (wp_script_is($handle, 'registered') && ! wp_script_is($handle, 'enqueued')) {
356 + wp_enqueue_script($handle);
357 + }
358 + }
359 + }
360 +
361 + /**
362 + * Same sweep, styles side: the engine adds `.darkify_dark_mode_enabled` and
363 + * the switch classes, and client_main.css is what they mean. Losing only the
364 + * stylesheet leaves a half-styled admin bar icon.
365 + */
366 + public function darkify_restore_no_conflict_styles()
367 + {
368 + if (! $this->engine_enqueued || ! is_admin()) {
369 + return;
370 + }
371 +
372 + if (wp_style_is('darkify-admin-switch', 'registered') && ! wp_style_is('darkify-admin-switch', 'enqueued')) {
373 + wp_enqueue_style('darkify-admin-switch');
374 + }
375 + }
376 +
377 + /**
287 378 * Cache-busting version for a bundled asset: the plugin version plus the
288 379 * file's mtime, so rebuilding client_main.js/.css (which does NOT bump the
289 380 * plugin version) still changes the URL and browsers fetch the new file
290 381 * instead of serving a stale one. Mirrors Admin\Assets::asset_version().
@@ -350,8 +441,12 @@
350 441
351 442 if (in_array($page, $dequeue_pages, true)) {
352 443 wp_deregister_style('darkify-admin-switch');
353 444 wp_dequeue_script('darkify-admin-client-main');
445 + wp_dequeue_script('darkify-admin-engine');
446 + wp_dequeue_script('darkify-darkreader');
447 + // Keep darkify_restore_no_conflict_scripts() from undoing this.
448 + $this->engine_enqueued = false;
354 449 }
355 450 }
356 451
357 452 /**
@@ -459,9 +554,16 @@
459 554 'parent' => 'top-secondary',
460 555 'id' => 'darkify_admin_bar_switch_container',
461 556 'meta' => array(
462 557 'class' => $classes,
463 - 'onclick' => 'darkify_switch_trigger()',
558 + // Guarded call: a plugin's "no-conflict mode" can still strip the
559 + // engine on its own screens (see the compatibility hooks in the
560 + // constructor). A missing function should be an inert click, not
561 + // an uncaught ReferenceError in every visitor's console.
562 + // No quotes in the expression: the admin bar escapes `meta`
563 + // attributes, and the escaped quotes come back as literal
564 + // entities inside the handler ("Invalid or unexpected token").
565 + 'onclick' => 'window.darkify_switch_trigger&&window.darkify_switch_trigger()',
464 566 ),
465 567 ));
466 568 }
467 569