PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 1.5.3
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v1.5.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
darkify / src / Frontend / Frontend.php

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

379 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ThemeAtelier\Darkify\Frontend;
4
5 use ThemeAtelier\Darkify\Includes\DarkifyExternalSupport;
6 use ThemeAtelier\Darkify\Includes\DarkifyUtils;
7
8 if (!defined('ABSPATH')) {
9 die;
10 } // Cannot access directly.
11
12 /**
13 * The public-facing functionality of the plugin.
14 *
15 * @link https://themeatelier.net
16 * @since 1.0.0
17 *
18 * @package Darkify
19 * @subpackage Darkify/public
20 */
21
22 /**
23 * The public-facing functionality of the plugin.
24 *
25 * Defines the plugin name, version, and two examples hooks for how to
26 * enqueue the public-facing stylesheet and JavaScript.
27 *
28 * @package Darkify
29 * @subpackage Darkify/public
30 * @author ThemeAtelier <themeatelierbd@gmail.com>
31 */
32 class Frontend
33 {
34
35 /**
36 * The ID of this plugin.
37 *
38 * @since 1.0.0
39 * @access private
40 * @var string $plugin_name The ID of this plugin.
41 */
42 private $plugin_name;
43
44 /**
45 * The version of this plugin.
46 *
47 * @since 1.0.0
48 * @access private
49 * @var string $version The current version of this plugin.
50 */
51 private $version;
52
53 public $utils;
54 public $settings;
55 public $external_support;
56 public $unique_id;
57
58 /**
59 * Initialize the class and set its properties.
60 *
61 * @since 1.0.0
62 * @param string $plugin_name The name of the plugin.
63 * @param string $version The version of this plugin.
64 */
65 public function __construct($plugin_name, $version)
66 {
67 $this->plugin_name = $plugin_name;
68 $this->version = $version;
69
70 $this->utils = new DarkifyUtils($this);
71 $this->external_support = new DarkifyExternalSupport($this);
72
73 new DarkifyShortcode($this);
74
75 if (function_exists('wp_rand')) {
76 $this->unique_id = wp_rand();
77 }
78
79 $options = get_option('darkify');
80 $show_in_menu = isset($options['show_in_menu']) ? $options['show_in_menu'] : "";
81 $enable_switcher_in_menu = isset($show_in_menu["enable_switch_in_menu"]) ? $show_in_menu["enable_switch_in_menu"] : false;
82
83 if ($enable_switcher_in_menu) {
84 add_filter('wp_nav_menu_items', array($this, 'darkify_switch_in_menu'), 10, 2);
85 }
86
87 add_action('wp_enqueue_scripts', array($this, 'darkify_client_enqueue'), 100);
88 add_action('login_enqueue_scripts', array($this, 'darkify_client_enqueue'));
89 add_action('register_enqueue_scripts', array($this, 'darkify_client_enqueue'));
90 add_action('wp_head', array($this, 'darkify_client_header_script'), 1);
91 add_action('login_head', array($this, 'darkify_client_header_script'), 1);
92 add_action('register_head', array($this, 'darkify_client_header_script'), 1);
93 add_action('wp_footer', array($this, 'darkify_client_footer_script'));
94 add_action('login_footer', array($this, 'darkify_client_footer_script'));
95 add_action('register_footer', array($this, 'darkify_client_footer_script'));
96
97 add_action('init', array($this, 'darkify_register_switcher_styles'), 5);
98 add_filter('autoptimize_filter_js_exclude', array($this, 'darkify_exclude_js_from_cache_plugins'));
99 }
100
101 public function darkify_exclude_js_from_cache_plugins($excludes)
102 {
103 $excludes .= ',client_main.js,client_main.min.js';
104 return $excludes;
105 }
106
107 public function darkify_register_switcher_styles()
108 {
109 $min = (apply_filters('darkify_dev_mode', false) || WP_DEBUG) ? '' : '.min';
110 wp_register_style('darkify-client-main', DARKIFY_DIR_URL . 'src/assets/css/client_main' . $min . '.css', array(), DARKIFY_VERSION);
111 wp_register_style('theme-classic', DARKIFY_DIR_URL . 'src/assets/css/switcher/classic' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
112 wp_register_style('theme-expand', DARKIFY_DIR_URL . 'src/assets/css/switcher/expand' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
113 wp_register_style('theme-inner-moon', DARKIFY_DIR_URL . 'src/assets/css/switcher/inner-moon' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
114 wp_register_style('theme-within', DARKIFY_DIR_URL . 'src/assets/css/switcher/within' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
115 wp_register_style('theme-orbit', DARKIFY_DIR_URL . 'src/assets/css/switcher/orbit' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
116 }
117
118 function darkify_client_enqueue()
119 {
120 if ($this->darkify_is_dark_mode_allowed()) {
121 $options = get_option('darkify');
122 $min = (apply_filters('darkify_dev_mode', false) || WP_DEBUG) ? '' : '.min';
123
124 wp_enqueue_style('darkify-client-main', DARKIFY_DIR_URL . 'src/assets/css/client_main' . $min . '.css', array(), DARKIFY_VERSION);
125 wp_enqueue_script('darkify-client-main', DARKIFY_DIR_URL . 'src/assets/js/client_main' . $min . '.js', array('jquery'), DARKIFY_VERSION);
126
127 // Enqueue the global floating switcher style from settings
128 $enable_dark_mode_switch = isset($options['enable_dark_mode_switch']) ? $options['enable_dark_mode_switch'] : true;
129 if ($enable_dark_mode_switch) {
130 $global_variant = isset($options['enable_dark_switcher']) ? $options['enable_dark_switcher'] : 'classic';
131 wp_enqueue_style('theme-' . $global_variant);
132 }
133
134 // Detect [darkify] shortcode usage in current post and enqueue its variant
135 $post = get_post();
136 if ($post && !empty($post->post_content)) {
137 if (has_shortcode($post->post_content, 'darkify')) {
138 preg_match_all('/\[darkify\b[^\]]*\bswitch=["\']([^"\']+)["\'][^\]]*\]/i', $post->post_content, $matches);
139 $used_switches = !empty($matches[1]) ? $matches[1] : [];
140 foreach ($used_switches as $switch_val) {
141 wp_enqueue_style('theme-' . $this->darkify_switch_to_variant($switch_val));
142 }
143 // Shortcode without switch= attribute defaults to classic
144 preg_match_all('/\[darkify\b/i', $post->post_content, $all_sc);
145 if (count($all_sc[0]) > count($used_switches)) {
146 wp_enqueue_style('theme-classic');
147 }
148 }
149
150 // Detect darkify/switcher Gutenberg block usage and enqueue its variant
151 if (function_exists('has_block') && has_block('darkify/switcher', $post)) {
152 foreach ($this->darkify_get_block_variants($post->post_content) as $variant) {
153 wp_enqueue_style('theme-' . $variant);
154 }
155 }
156 }
157
158 // Detect switcher used in nav menus and enqueue its variant
159 $show_in_menu = isset($options['show_in_menu']) ? $options['show_in_menu'] : [];
160 $enable_in_menu = isset($show_in_menu['enable_switch_in_menu']) ? $show_in_menu['enable_switch_in_menu'] : false;
161 if ($enable_in_menu) {
162 $select_menus = isset($show_in_menu['select_menus']) ? $show_in_menu['select_menus'] : [];
163 foreach ($select_menus as $select_menu) {
164 $shortcode = $select_menu['darkify_menu_shortcode_helper'] ?? '';
165 if ($shortcode) {
166 preg_match('/\bswitch=["\']([^"\']+)["\']/', $shortcode, $m);
167 $switch_val = $m[1] ?? '1';
168 wp_enqueue_style('theme-' . $this->darkify_switch_to_variant($switch_val));
169 }
170 }
171 }
172 }
173 }
174
175 private function darkify_switch_to_variant($switch_value)
176 {
177 $map = [
178 '1' => 'classic', '2' => 'expand', '3' => 'inner-moon',
179 '4' => 'within', '5' => 'orbit',
180 ];
181 if (is_numeric($switch_value)) {
182 return $map[(string) $switch_value] ?? 'classic';
183 }
184 return $switch_value ?: 'classic';
185 }
186
187 private function darkify_get_block_variants($content)
188 {
189 $variants = [];
190 $this->darkify_collect_block_variants(parse_blocks($content), $variants);
191 return array_unique($variants);
192 }
193
194 private function darkify_collect_block_variants($blocks, &$variants)
195 {
196 foreach ($blocks as $block) {
197 if ('darkify/switcher' === $block['blockName']) {
198 $variants[] = $block['attrs']['style'] ?? 'classic';
199 }
200 if (!empty($block['innerBlocks'])) {
201 $this->darkify_collect_block_variants($block['innerBlocks'], $variants);
202 }
203 }
204
205 $options = get_option('darkify');
206 $min = (apply_filters('darkify_dev_mode', false) || WP_DEBUG) ? '' : '.min';
207
208 // Always register all variant styles so page builders (Elementor, etc.) can reference them.
209 wp_register_style('darkify-client-main', DARKIFY_DIR_URL . 'src/assets/css/client_main' . $min . '.css', array(), DARKIFY_VERSION);
210 wp_register_style('theme-classic', DARKIFY_DIR_URL . 'src/assets/css/switcher/classic' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
211 wp_register_style('theme-expand', DARKIFY_DIR_URL . 'src/assets/css/switcher/expand' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
212 wp_register_style('theme-inner-moon', DARKIFY_DIR_URL . 'src/assets/css/switcher/inner-moon' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
213 wp_register_style('theme-orbit', DARKIFY_DIR_URL . 'src/assets/css/switcher/orbit' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
214 wp_register_style('theme-within', DARKIFY_DIR_URL . 'src/assets/css/switcher/within' . $min . '.css', array('darkify-client-main'), DARKIFY_VERSION, 'all');
215
216 // Determine which variants are actually needed on this page.
217 $variants = $this->darkify_collect_page_variants($options);
218
219 if (empty($variants)) {
220 return;
221 }
222
223 // Enqueue main CSS + only the required variant CSS — all resolved before wp_head fires.
224 wp_enqueue_style('darkify-client-main');
225 foreach ($variants as $variant) {
226 wp_enqueue_style("theme-{$variant}");
227 }
228 wp_enqueue_script('darkify-client-main', DARKIFY_DIR_URL . 'src/assets/js/client_main' . $min . '.js', array('jquery'), DARKIFY_VERSION);
229 }
230
231 /**
232 * Collects all switcher variants needed on the current page so they can be
233 * enqueued during wp_enqueue_scripts (before wp_head), guaranteeing CSS loads
234 * in the <head> regardless of page builder or theme.
235 */
236 private function darkify_collect_page_variants($options)
237 {
238 $all_variants = array('classic', 'expand', 'inner-moon', 'orbit', 'within');
239 $num_map = array('1' => 'classic', '2' => 'expand', '3' => 'inner-moon', '4' => 'within', '5' => 'orbit');
240 $variants = array();
241
242 // 1. Global / floating switcher variant (always present when dark mode is active).
243 $global_variant = isset($options['enable_dark_switcher']) ? $options['enable_dark_switcher'] : 'classic';
244 if (in_array($global_variant, $all_variants, true)) {
245 $variants[] = $global_variant;
246 }
247
248 // 2. Menu switcher — parse variant from each saved shortcode helper string.
249 $show_in_menu = isset($options['show_in_menu']) ? $options['show_in_menu'] : array();
250 if (!empty($show_in_menu['enable_switch_in_menu']) && !empty($show_in_menu['select_menus'])) {
251 foreach ($show_in_menu['select_menus'] as $menu_item) {
252 $helper = isset($menu_item['darkify_menu_shortcode_helper']) ? $menu_item['darkify_menu_shortcode_helper'] : '';
253 if ($helper && preg_match('/switch=["\']?([^"\'>\s\]]+)["\']?/', $helper, $m)) {
254 $v = isset($num_map[$m[1]]) ? $num_map[$m[1]] : $m[1];
255 if (in_array($v, $all_variants, true)) {
256 $variants[] = $v;
257 }
258 }
259 }
260 }
261
262 // 3. Page-level detection — shortcodes, Gutenberg blocks, Elementor widget.
263 global $post;
264 if ($post) {
265 $content = $post->post_content;
266
267 // Shortcodes: parse switch attribute from every [darkify] tag.
268 if (has_shortcode($content, 'darkify')) {
269 preg_match_all('/\[darkify[^\]]*switch=["\']?([^"\'>\s\]]+)/', $content, $sc_matches);
270 foreach ($sc_matches[1] as $switch_val) {
271 $v = isset($num_map[$switch_val]) ? $num_map[$switch_val] : $switch_val;
272 if (in_array($v, $all_variants, true)) {
273 $variants[] = $v;
274 } else {
275 $variants[] = 'classic'; // default when no valid variant found
276 }
277 }
278 // If [darkify] exists but has no switch attribute, default to classic.
279 if (empty($sc_matches[1]) && has_shortcode($content, 'darkify')) {
280 $variants[] = 'classic';
281 }
282 }
283
284 // Gutenberg blocks: walk the block tree and collect style attributes.
285 if (function_exists('has_block') && has_block('darkify/switcher', $post)) {
286 $blocks = parse_blocks($content);
287 $variants = array_merge($variants, $this->darkify_extract_block_variants($blocks, $all_variants));
288 }
289
290 // Elementor widget: if Darkify widget appears in the page's Elementor data,
291 // load all variants — the specific style is stored as a control value that
292 // would require deep JSON parsing to extract reliably.
293 if (class_exists('\Elementor\Plugin')) {
294 $elementor_data = get_post_meta($post->ID, '_elementor_data', true);
295 if ($elementor_data && strpos($elementor_data, '"widgetType":"darkify"') !== false) {
296 return $all_variants;
297 }
298 }
299 }
300
301 return array_values(array_unique(array_filter($variants)));
302 }
303
304 /**
305 * Recursively walks a parsed block tree and collects darkify/darkify style values.
306 */
307 private function darkify_extract_block_variants($blocks, $all_variants)
308 {
309 $variants = array();
310 foreach ($blocks as $block) {
311 if ('darkify/switcher' === $block['blockName']) {
312 $style = isset($block['attrs']['style']) ? $block['attrs']['style'] : 'classic';
313 if (in_array($style, $all_variants, true)) {
314 $variants[] = $style;
315 }
316 }
317 if (!empty($block['innerBlocks'])) {
318 $variants = array_merge($variants, $this->darkify_extract_block_variants($block['innerBlocks'], $all_variants));
319 }
320 }
321 return $variants;
322 }
323 public function darkify_is_dark_mode_allowed()
324 {
325 $options = get_option('darkify');
326 /* Disable if Oxygen Builder is Opened */
327 if (isset($_GET['ct_builder'])) {
328 if ($_GET['ct_builder'] == "true") {
329 if (!isset($_GET['oxygen_iframe'])) {
330 return False;
331 }
332 }
333 }
334
335 return True;
336 }
337
338
339 public function darkify_client_header_script()
340 {
341 if ($this->darkify_is_dark_mode_allowed()) {
342 include_once DarkifyUtils::darkify_locate_template('header_script.php');
343 }
344 }
345
346 public function darkify_client_footer_script()
347 {
348 if ($this->darkify_is_dark_mode_allowed()) {
349 include_once DarkifyUtils::darkify_locate_template('footer_script.php');
350 }
351 }
352
353 function darkify_switch_in_menu($items, $args)
354 {
355 $options = get_option('darkify');
356 $show_in_menu = $options['show_in_menu'];
357 $select_menus = isset($show_in_menu['select_menus']) ? $show_in_menu['select_menus'] : [];
358
359 $last_shortcode = '';
360
361 if ($this->darkify_is_dark_mode_allowed() && isset($args->menu->term_id)) {
362 foreach ($select_menus as $select_menu) {
363
364 $switch_in_menu_location = $select_menu['switch_in_menu_location'] ?? '';
365 $darkify_menu_shortcode_helper = $select_menu['darkify_menu_shortcode_helper'] ?? '';
366 $menu_position = isset($select_menu['select_menu_position']) ? $select_menu['select_menu_position'] : 'after';
367 if ($args->menu->term_id == $switch_in_menu_location) {
368 $last_shortcode = $darkify_menu_shortcode_helper;
369 }
370 }
371 if ($last_shortcode) {
372 $items = ($menu_position == 'before') ? '<li class="menu-item">' . do_shortcode($last_shortcode) . '</li>' . $items : $items . '<li class="menu-item">' . do_shortcode($last_shortcode) . '</li>';
373 }
374 }
375
376 return $items;
377 }
378 }
379