PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.0.1
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.0.1
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
darkify / src / Admin / Admin.php

Admin.php in Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) 2.0.1, at src/Admin/Admin.php

419 lines 16.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The admin-facing functionality of the plugin.
5 *
6 * @link https://themeatelier.net
7 * @since 1.0.0
8 *
9 * @package darkify
10 * @subpackage darkify/Admin
11 * @author ThemeAtelier<themeatelierbd@gmail.com>
12 */
13
14 namespace ThemeAtelier\Darkify\Admin;
15
16 use ThemeAtelier\Darkify\Admin\ReviewNotice\ReviewNotice;
17 use ThemeAtelier\Darkify\Admin\ReviewNotice\ThemeAtelier_Offer_Banner;
18 use ThemeAtelier\Darkify\Admin\Views\DarkifyOptions;
19 use ThemeAtelier\Darkify\Includes\DarkifyExternalSupport;
20 use ThemeAtelier\Darkify\Includes\DarkifyUtils;
21 use ThemeAtelier\Darkify\Admin\DBUpdates;
22
23 /**
24 * The admin class
25 */
26 class Admin
27 {
28
29 /**
30 * The min of this plugin.
31 *
32 * @since 1.0.0
33 * @access private
34 * @var string $min The slug of this plugin.
35 */
36 private $min;
37 public $utils;
38 public $settings;
39 public $external_support;
40 private $plugin_name;
41 private $version;
42 public $unique_id;
43
44 /**
45 * The class constructor.
46 *
47 * @param string $plugin_name The slug of the plugin.
48 * @param string $version Current version of the plugin.
49 */
50 public function __construct($plugin_name, $version)
51 {
52 $this->plugin_name = $plugin_name;
53 $this->version = $version;
54 $this->utils = new DarkifyUtils($this);
55 $this->external_support = new DarkifyExternalSupport($this);
56 $this->min = (apply_filters('darkify_dev_mode', false) || WP_DEBUG) ? '' : '.min';
57 if (function_exists('wp_rand')) {
58 $this->unique_id = wp_rand();
59 }
60
61 add_action('current_screen', function ($screen) {
62 $options = get_option('darkify');
63 $block_editor_dark_mode = isset($options['block_editor_dark_mode']) ? $options['block_editor_dark_mode'] : false;
64 $enable_admin_panel_dark_mode = isset($options['enable_admin_panel_dark_mode']) ? $options['enable_admin_panel_dark_mode'] : false;
65 $is_block_editor = method_exists($screen, 'is_block_editor') && $screen->is_block_editor();
66
67 // Block Editor Dark Mode is INDEPENDENT of Admin Panel Dark Mode:
68 // the block editor darkens whenever Block Editor Dark Mode is on,
69 // even if the rest of wp-admin stays light. Every other admin screen
70 // still keys on Admin Panel Dark Mode.
71 $needs_engine = $is_block_editor
72 ? (bool) $block_editor_dark_mode
73 : (bool) $enable_admin_panel_dark_mode;
74
75 // Darkify's own settings/help screens additionally load it even while
76 // the option is OFF, so flipping "Admin Panel Dark Mode" in the React
77 // admin can show the admin-bar icon (and have it actually work)
78 // immediately instead of only after a reload. Loading it here cannot
79 // darken anything on its own: both the FOUC snippet in
80 // header_script.php and darkify_check_preloading() in client_main.js
81 // are gated on `darkify_admin_panel_dark_enabled`.
82 if ($needs_engine || $this->is_darkify_spa_page()) {
83 add_action('admin_bar_menu', array($this, 'darkify_admin_bar_switch'), 9999);
84 add_action('admin_print_scripts', array($this, 'darkify_admin_header_script'), 1);
85 add_action('admin_footer', array($this, 'darkify_admin_footer_script'));
86 }
87 });
88
89 new ReviewNotice();
90 new DBUpdates();
91 if (! defined('THEMEATELIER_OFFER_BANNER_LOADED')) {
92 define('THEMEATELIER_OFFER_BANNER_LOADED', true);
93 ThemeAtelier_Offer_Banner::instance();
94 }
95
96 add_action('after_setup_theme', array($this, 'init_components'));
97 add_filter('autoptimize_filter_js_exclude', array($this, 'darkify_exclude_js_from_cache_plugins'));
98 add_action('admin_init', [$this, 'load_classic_editor_scripts']);
99 add_filter('admin_footer_text', array($this, 'darkify_admin_footer'), 1, 2);
100 $active_plugins = get_option('active_plugins');
101 foreach ($active_plugins as $active_plugin) {
102 $_temp = strpos($active_plugin, 'darkify.php');
103 if (false != $_temp) {
104 add_filter('plugin_action_links_' . DARKIFY_BASENAME, array($this, 'add_plugin_action_links'), 10, 2);
105 add_filter('plugin_row_meta', array($this, 'after_darkify_row_meta'), 10, 4);
106 }
107 }
108 }
109
110 public function init_components()
111 {
112 DarkifyOptions::options('darkify');
113 }
114
115 /**
116 * Whether the current screen is one of Darkify's own React SPA screens
117 * (Settings / Get Help) — the only place the Admin Panel Dark Mode option can
118 * be toggled, and therefore the only place that needs the engine loaded up
119 * front so the admin-bar icon can react instantly.
120 */
121 public function is_darkify_spa_page(): bool
122 {
123 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen check.
124 $page = isset($_GET['page']) ? \sanitize_key(\wp_unslash($_GET['page'])) : '';
125 return \in_array($page, Assets::SPA_SLUGS, true);
126 }
127
128 public function darkify_exclude_js_from_cache_plugins($excludes)
129 {
130 $excludes .= ',client_main.js,client_main.min.js';
131 return $excludes;
132 }
133
134 public function enqueue_styles()
135 {
136 $options = get_option('darkify');
137 $enable_admin_panel_dark_mode = isset($options["enable_admin_panel_dark_mode"]) ? $options["enable_admin_panel_dark_mode"] : false;
138 // Block Editor Dark Mode darkens the editor independently of Admin Panel
139 // Dark Mode, so the stylesheet must load there too.
140 $block_editor_dark_mode = isset($options['block_editor_dark_mode']) ? $options['block_editor_dark_mode'] : false;
141 $screen = \function_exists('get_current_screen') ? \get_current_screen() : null;
142 $is_block_editor = $screen && \method_exists($screen, 'is_block_editor') && $screen->is_block_editor();
143 $allow_admin_dark = $enable_admin_panel_dark_mode || ($is_block_editor && $block_editor_dark_mode);
144 // Darkify's own screens always get the stylesheet so the admin-bar icon
145 // can be revealed the moment the option is switched on. It only styles
146 // `.darkify_*` classes, so it is inert until the engine adds them.
147 if (($allow_admin_dark || $this->is_darkify_spa_page()) && $this->darkify_is_dark_mode_allowed()) {
148 if (!wp_style_is('darkify-admin-switch', 'enqueued')) {
149 wp_enqueue_style('darkify-admin-switch', DARKIFY_DIR_URL . 'src/assets/css/client_main' . $this->min . '.css', array(), $this->darkify_asset_version('src/assets/css/client_main' . $this->min . '.css'), 'all');
150 }
151 }
152 // Review notice CSS
153 wp_enqueue_style('darkify-review-notice', DARKIFY_DIR_URL . 'src/Admin/ReviewNotice/assets/css/review-notice' . $this->min . '.css', array(), DARKIFY_VERSION, 'all');
154 }
155
156 public function enqueue_scripts($hook)
157 {
158 $options = get_option('darkify');
159 $enable_admin_panel_dark_mode = isset($options["enable_admin_panel_dark_mode"]) ? $options["enable_admin_panel_dark_mode"] : false;
160 $is_spa = $this->is_darkify_spa_page();
161 if (! $this->darkify_is_dark_mode_allowed()) {
162 return;
163 }
164
165 // Mirror the `current_screen` engine-load rule exactly, so the engine is
166 // only enqueued where its inline config (header_script.php) is ALSO
167 // printed. Block Editor Dark Mode is independent of Admin Panel Dark
168 // Mode: the block editor loads the engine when Block Editor Dark Mode is
169 // on (regardless of Admin Panel Dark Mode); every other admin screen
170 // keys on Admin Panel Dark Mode. (A SPA screen always gets the config.)
171 if (! $is_spa) {
172 $screen = \function_exists('get_current_screen') ? \get_current_screen() : null;
173 $is_block_editor = $screen && \method_exists($screen, 'is_block_editor') && $screen->is_block_editor();
174 $block_editor_dark_mode = isset($options['block_editor_dark_mode']) ? $options['block_editor_dark_mode'] : false;
175 $allow = $is_block_editor ? (bool) $block_editor_dark_mode : (bool) $enable_admin_panel_dark_mode;
176 if (! $allow) {
177 return;
178 }
179 }
180
181 wp_enqueue_script(
182 'darkify-admin-client-main',
183 DARKIFY_DIR_URL . 'src/assets/js/client_main' . $this->min . '.js',
184 array(),
185 $this->darkify_asset_version('src/assets/js/client_main' . $this->min . '.js')
186 );
187 }
188
189 /**
190 * Cache-busting version for a bundled asset: the plugin version plus the
191 * file's mtime, so rebuilding client_main.js/.css (which does NOT bump the
192 * plugin version) still changes the URL and browsers fetch the new file
193 * instead of serving a stale one. Mirrors Admin\Assets::asset_version().
194 */
195 public function darkify_asset_version(string $relative_path): string
196 {
197 $abs = DARKIFY_PATH . $relative_path;
198 $mtime = \is_readable($abs) ? \filemtime($abs) : false;
199 return $mtime ? DARKIFY_VERSION . '.' . $mtime : DARKIFY_VERSION;
200 }
201
202 /*
203 Dequeue Darkify scripts and styles on specific admin pages (e.g., MainWP pages)
204 */
205
206 public function admin_dequeue_for_specefic_pages()
207 {
208 $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
209 $dequeue_pages = array(
210 'mainwp_tab',
211 'managesites',
212 'ManageClients',
213 'CostSummary',
214 'InsightsOverview',
215 'Extensions',
216 'RESTAPI',
217 'mainwp-setup',
218 'ThemesManage',
219 'PluginsManage',
220 'InsightsManage',
221 'ManageGroups',
222 'UpdatesManage',
223 'PluginsInstall',
224 'PluginsAutoUpdate',
225 'PluginsIgnore',
226 'PluginsAbandoned',
227 'PluginsIgnoredAbandoned',
228 'ThemesInstall',
229 'ThemesAutoUpdate',
230 'ThemesIgnore',
231 'ThemesAbandoned',
232 'ThemesIgnoredAbandoned',
233 'UserBulkManage',
234 'UserBulkAdd',
235 'BulkImportUsers',
236 'UpdateAdminPasswords',
237 'PostBulkManage',
238 'Extensions-Mainwp-Backups',
239 'Extensions-Mainwp-Security',
240 'Extensions-Mainwp-Analytics',
241 'Mainwp-Monitoring',
242 'Extensions-Mainwp-Agency',
243 'Extensions-Mainwp-Administrative',
244 'Extensions-Mainwp-Development',
245 'Extensions-Mainwp-Performance',
246 'ClientAddNew',
247 'ClientImport',
248 'ManageCostTracker',
249 'CostTrackerAdd',
250 'AddApiKeys',
251 );
252
253
254 if (in_array($page, $dequeue_pages, true)) {
255 wp_deregister_style('darkify-admin-switch');
256 wp_dequeue_script('darkify-admin-client-main');
257 }
258 }
259
260 /**
261 * Replace wp-admin's footer credit with Darkify's review request, on
262 * Darkify's own screens only.
263 *
264 * Screens are matched by page slug (`is_darkify_spa_page()`) rather than by
265 * a hardcoded screen id, so both the Settings and Get Help SPA screens match
266 * and the check keeps working if the menu is ever retitled. The slug list is
267 * the same source of truth the assets already load from.
268 *
269 * @param string $text Existing footer text.
270 *
271 * @return string
272 */
273 public function darkify_admin_footer($text)
274 {
275 if (! $this->is_darkify_spa_page()) {
276 return $text;
277 }
278
279 return sprintf(
280 /* translators: 1: start strong tag, 2: close strong tag. 3: start link 4: close link */
281 __('<i>Enjoying %1$sDarkify?%2$s Please rate us %3$sWordPress.org%4$s. Your positive feedback will help us grow more. Thank you! 😊</i>', 'darkify'),
282 '<strong>',
283 '</strong>',
284 '<span class="greet-footer-text-star">�
285
286
287
288
289 </span> <a href="https://wordpress.org/support/plugin/darkify/reviews/#new-post" target="_blank" rel="noopener noreferrer">',
290 '</a>'
291 );
292 }
293
294 // Plugin settings in plugin list
295 public function add_plugin_action_links(array $links)
296 {
297 $new_links = array(
298 sprintf('<a href="' . esc_url(admin_url('admin.php?page=darkify')) . '">' . esc_html__('Settings', 'darkify') . '</a>'),
299 sprintf('<a target="_blank" href="https://wordpress.org/support/plugin/darkify/">' . esc_html__('Support', 'darkify') . '</a>'),
300 );
301
302 $links[] = sprintf('<a style="font-weight: bold;color:#35b747" target="_blank" href="https://darkifywp.com/pricing/?utm_source=darkify_plugin&utm_medium=action_link&utm_campaign=regular">%s</a>', esc_html__('Go Pro!', 'darkify'));
303
304 return array_merge($new_links, $links);
305 }
306
307 /**
308 * Add plugin row meta link.
309 *
310 * @since 2.0
311 *
312 * @param array $plugin_meta .
313 * @param string $file .
314 *
315 * @return array
316 */
317 public function after_darkify_row_meta($plugin_meta, $file)
318 {
319
320 if (DARKIFY_BASENAME === $file) {
321 $plugin_meta[] = '<a href="' . DARKIFY_DEMO_URL . '" target="_blank">' . __('Live Demo', 'darkify') . '</a>';
322 }
323
324 return $plugin_meta;
325 }
326
327 public function darkify_admin_bar_switch($wp_admin_bar)
328 {
329 if (! $this->darkify_is_dark_mode_allowed()) {
330 return;
331 }
332
333 $options = get_option('darkify');
334 $enable_admin_panel_dark_mode = isset($options['enable_admin_panel_dark_mode']) ? $options['enable_admin_panel_dark_mode'] : false;
335
336 // Everywhere but Darkify's own screens the node is only registered when
337 // the option is on, so it is always visible. On the SPA screens it is
338 // registered regardless and starts hidden while the option is off — the
339 // React admin then just flips this class (see WpAdminBarBridge), which is
340 // what makes the icon appear/disappear without a reload.
341 $classes = 'darkify_admin_bar_switch_container';
342 if (! $enable_admin_panel_dark_mode) {
343 $classes .= ' darkify_admin_bar_hidden';
344 }
345
346 $wp_admin_bar->add_node(array(
347 'parent' => 'top-secondary',
348 'id' => 'darkify_admin_bar_switch_container',
349 'meta' => array(
350 'class' => $classes,
351 'onclick' => 'darkify_switch_trigger()',
352 ),
353 ));
354 }
355
356 public function darkify_is_dark_mode_allowed()
357 {
358
359 $options = get_option('darkify');
360 $options = is_array($options) ? $options : array();
361 // Guarded read: `disallowed_admin_pages` has no schema default, so the
362 // React settings save doesn't persist it until the field is used. Reading
363 // it unguarded would emit an "Undefined array key" warning on every
364 // dark-mode hook (see the Pro plugin's Admin.php for the full story).
365 $disallowed_admin_pages = isset($options['disallowed_admin_pages']) ? $options['disallowed_admin_pages'] : '';
366 /* Disable on Disallowed Admin Plugins */
367 if ($this->utils->isRestrictedByDisallowedAdminPages($disallowed_admin_pages)) {
368 return False;
369 }
370 return True;
371 }
372
373 public function darkify_admin_header_script()
374 {
375 if ($this->darkify_is_dark_mode_allowed()) {
376 include_once DarkifyUtils::darkify_locate_template('header_script.php');
377 }
378 }
379
380 public function darkify_admin_footer_script()
381 {
382 if ($this->darkify_is_dark_mode_allowed()) {
383 include_once DarkifyUtils::darkify_locate_template('footer_script.php');
384 }
385 }
386
387 /**
388 * Load classic editor scripts.
389 *
390 * @since 5.0.0
391 */
392 public function load_classic_editor_scripts()
393 {
394 $options = get_option('darkify');
395 $classic_editor_dark_mode = isset($options['classic_editor_dark_mode']) ? $options['classic_editor_dark_mode'] : '';
396 if (! current_user_can('edit_posts') && ! current_user_can('edit_pages')) {
397 return;
398 }
399 if (get_user_option('rich_editing') !== 'true') {
400 return;
401 }
402
403 // Bail if admin_classic_editor is not enabled.
404 if (! wp_validate_boolean($classic_editor_dark_mode)) {
405 return;
406 }
407
408 add_filter('mce_external_plugins', function ($plugins) {
409 $plugins['darkify_button'] = plugins_url('src/assets/js/admin-classic-editor.js', DARKIFY_FILE);
410 return $plugins;
411 });
412
413 add_filter('mce_buttons', function ($buttons) {
414 $buttons[] = 'darkify_button';
415 return $buttons;
416 });
417 }
418 }
419