PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / trunk
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) vtrunk
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 1.3.1 All 56 releases
darkify / src / Includes / Darkify.php

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

365 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The file of the Darkify class.
5 *
6 * @link https://themeatelier.net
7 * @since 1.0.0
8 *
9 * @package Darkify
10 */
11
12 namespace ThemeAtelier\Darkify\Includes;
13
14 use ThemeAtelier\Darkify\Admin\Admin;
15 use ThemeAtelier\Darkify\Admin\Assets;
16 use ThemeAtelier\Darkify\Admin\Menu;
17 use ThemeAtelier\Darkify\Admin\Rest\HelpRest;
18 use ThemeAtelier\Darkify\Admin\Rest\PreviewRest;
19 use ThemeAtelier\Darkify\Admin\Rest\SettingsRest;
20 use ThemeAtelier\Darkify\Frontend\Frontend;
21
22
23 // don't call the file directly.
24 if (!defined('ABSPATH')) {
25 exit;
26 }
27
28 /**
29 * The main class of the plugin.
30 *
31 * Handle all the class and methods of the plugin.
32 *
33 * @author ThemeAtelier <themeatelierbd@gmail.com>
34 */
35 class Darkify
36 {
37 /**
38 * Plugin version
39 *
40 * @since 1.0.0
41 * @access protected
42 * @var string
43 */
44 protected $version;
45
46 /**
47 * Plugin slug
48 *
49 * @since 1.0.0
50 * @access protected
51 * @var string
52 */
53 protected $plugin_slug;
54
55 /**
56 * Main Loader.
57 *
58 * The loader that's responsible for maintaining and registering all hooks that empowers
59 * the plugin.
60 *
61 * @since 1.0.0
62 * @access protected
63 * @var object
64 */
65 protected $loader;
66 /**
67 * Constructor for the Darkify class.
68 *
69 * Sets up all the appropriate hooks and actions within the plugin.
70 */
71 public function __construct()
72 {
73 $this->version = DARKIFY_VERSION;
74 $this->plugin_slug = 'darkify';
75 $this->load_dependencies();
76 $this->define_constants();
77 $this->define_admin_hooks();
78 $this->define_public_hooks();
79 $this->init_action();
80 add_action('plugin_loaded', array($this, 'init_plugin'));
81
82 // Translations load on `after_setup_theme`, not alongside the boot action
83 // above. `plugin_loaded` fires while plugin files are still being
84 // included, before the pluggable functions exist, so `determine_locale()`
85 // cannot yet see a per-user admin language. Priority 1 puts this ahead of
86 // Admin::init_components (same hook, priority 10), which is where the
87 // settings schema evaluates its `__()` calls.
88 add_action('after_setup_theme', array($this, 'load_textdomain'), 1);
89
90 add_action('elementor/controls/register', [$this, 'register_controls']);
91 add_action('elementor/widgets/register', array($this, 'register_darkify_widget'));
92
93 add_action('init', [$this, 'create_darkify_block_init']);
94 }
95
96 /**
97 * Run the loader to execute all of the hooks with WordPress.
98 *
99 * @since 1.0.0
100 */
101 public function run()
102 {
103 $this->loader->run();
104 }
105
106 public function darkify_redirect_to($plugin)
107 {
108 if (DARKIFY_BASENAME === $plugin) {
109 $redirect_url = esc_url(admin_url('admin.php?page=darkify'));
110 exit(wp_kses_post(wp_safe_redirect($redirect_url)));
111 }
112 }
113
114 /**
115 * The slug of the plugin used to uniquely identify it within the context of
116 * WordPress and to define internationalization functionality.
117 *
118 * @since 1.0.0
119 * @return string The name of the plugin.
120 */
121 public function get_plugin_name()
122 {
123 return $this->plugin_slug;
124 }
125
126 /**
127 * Retrieve the version number of the plugin.
128 *
129 * @since 1.0.0
130 * @return string The version number of the plugin.
131 */
132 public function get_version()
133 {
134 return $this->version;
135 }
136
137
138 public function register_controls($controls_manager)
139 {
140 require_once DARKIFY_PATH . 'src/Admin/elementor/controls/class-elementor-control-switch.php';
141
142 $controls_manager->register_control(
143 'darkify_switch',
144 new \Elementor_Darkify_Switcher()
145 );
146 }
147 public function register_darkify_widget($widgets_manager)
148 {
149 require_once DARKIFY_PATH . 'src/Admin/elementor/widgets/elementor-widget.php';
150 $widgets_manager->register(new \Elementor_Darkify());
151 }
152
153 /**
154 * Define the constants
155 *
156 * @return void
157 */
158 public function define_constants()
159 {
160 define('DARKIFY_URL', plugins_url('', DARKIFY_FILE));
161 define('DARKIFY_ASSETS', DARKIFY_URL . '/src/assets/');
162 define('DARKIFY_ADMIN', DARKIFY_URL . '/src/Admin');
163 }
164
165 /**
166 * Fire the plugin's own boot action.
167 *
168 * @return void
169 */
170 public function init_plugin()
171 {
172 do_action('darkify_loaded');
173 }
174
175 /**
176 * Load the plugin's translations.
177 *
178 * @return void
179 */
180 public function load_textdomain()
181 {
182 // `load_plugin_textdomain()` wants a path *relative to WP_PLUGIN_DIR* —
183 // it does `WP_PLUGIN_DIR . '/' . $path`. DARKIFY_DIR_NAME is an absolute
184 // path (`dirname(__FILE__)`), so the old call built a nonsense path like
185 // `/wp-content/plugins//Users/…/plugins/darkify/languages` and the .mo
186 // was never found. `wp_set_script_translations()` in Admin/Assets.php
187 // does take an absolute path and got it right, which is why the React
188 // strings translated and nothing from PHP ever did.
189 load_plugin_textdomain(
190 'darkify',
191 false,
192 dirname(plugin_basename(DARKIFY_FILE)) . '/languages'
193 );
194 }
195
196 /**
197 * Load the required dependencies for this plugin.
198 *
199 * Include the following files that make up the plugin:
200 *
201 * - Loader. Orchestrates the hooks of the plugin.
202 * - Teamproi18n. Defines internationalization functionality.
203 * - Admin. Defines all hooks for the admin area.
204 * - Frontend. Defines all hooks for the public side of the site.
205 *
206 * Create an instance of the loader which will be used to register the hooks
207 * with WordPress.
208 *
209 * @since 1.0.0
210 * @access private
211 */
212 private function load_dependencies()
213 {
214 /**
215 * The class responsible for orchestrating the actions and filters of the
216 * core plugin.
217 */
218 $this->loader = new Loader();
219 }
220
221 /**
222 * Register all of the hooks related to the admin dashboard functionality
223 * of the plugin.
224 *
225 * @since 1.0.0
226 * @access private
227 */
228 private function define_admin_hooks()
229 {
230 $plugin_admin = new Admin($this->get_plugin_name(), $this->get_version());
231 $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
232 $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
233 $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'admin_dequeue_for_specefic_pages', 999);
234
235 // The React admin: its menu page, its bundle, and the REST endpoints it
236 // talks to. The controllers hook themselves onto `rest_api_init`, so they
237 // must be constructed on every request, not only in wp-admin.
238 new Menu();
239 new Assets();
240 new SettingsRest();
241 // Backs the Get Help page's Recommended tab (ThemeAtelier plugin
242 // directory with one-click install/activate).
243 new HelpRest();
244 // Constructed unconditionally (not admin-only): its `init` hook also has
245 // to fire on the frontend iframe request to swap in the preview values.
246 new PreviewRest();
247 }
248
249 /**
250 * Register all of the hooks related to the public-facing functionality
251 * of the plugin.
252 *
253 * @since 1.0.0
254 * @access private
255 */
256 private function define_public_hooks()
257 {
258 $plugin_public = new Frontend($this->get_plugin_name(), $this->get_version());
259 }
260
261 public static function switcher($variant, $unique_id)
262 {
263 if ('classic' == $variant) {
264 return '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="0px" height="0px" fill="currentColor" stroke-linecap="round" class="theme-toggle__classic" viewBox="0 0 32 32"><clipPath id="theme-toggle__classic__cutout_' . esc_attr($unique_id) . '"><path d="M0-5h30a1 1 0 0 0 9 13v24H0Z" /></clipPath><g clip-path="url(#theme-toggle__classic__cutout_' . esc_attr($unique_id) . ')"><circle cx="16" cy="16" r="9.34" /><g stroke="currentColor" stroke-width="1.5"><path d="M16 5.5v-4" /><path d="M16 30.5v-4" /><path d="M1.5 16h4" /><path d="M26.5 16h4" /><path d="m23.4 8.6 2.8-2.8" /><path d="m5.7 26.3 2.9-2.9" /><path d="m5.8 5.8 2.8 2.8" /><path d="m23.4 23.4 2.9 2.9" /></g></g></svg>';
265 } else if ('expand' == $variant) {
266 return '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="0px" height="0px" fill="currentColor" class="theme-toggle__expand" viewBox="0 0 32 32"><clipPath id="theme-toggle__expand__cutout_' . esc_attr($unique_id) . '"><path d="M0-11h25a1 1 0 0017 13v30H0Z" /></clipPath><g clip-path="url(#theme-toggle__expand__cutout_' . esc_attr($unique_id) . ')"><circle cx="16" cy="16" r="8.4" /><path d="M18.3 3.2c0 1.3-1 2.3-2.3 2.3s-2.3-1-2.3-2.3S14.7.9 16 .9s2.3 1 2.3 2.3zm-4.6 25.6c0-1.3 1-2.3 2.3-2.3s2.3 1 2.3 2.3-1 2.3-2.3 2.3-2.3-1-2.3-2.3zm15.1-10.5c-1.3 0-2.3-1-2.3-2.3s1-2.3 2.3-2.3 2.3 1 2.3 2.3-1 2.3-2.3 2.3zM3.2 13.7c1.3 0 2.3 1 2.3 2.3s-1 2.3-2.3 2.3S.9 17.3.9 16s1-2.3 2.3-2.3zm5.8-7C9 7.9 7.9 9 6.7 9S4.4 8 4.4 6.7s1-2.3 2.3-2.3S9 5.4 9 6.7zm16.3 21c-1.3 0-2.3-1-2.3-2.3s1-2.3 2.3-2.3 2.3 1 2.3 2.3-1 2.3-2.3 2.3zm2.4-21c0 1.3-1 2.3-2.3 2.3S23 7.9 23 6.7s1-2.3 2.3-2.3 2.4 1 2.4 2.3zM6.7 23C8 23 9 24 9 25.3s-1 2.3-2.3 2.3-2.3-1-2.3-2.3 1-2.3 2.3-2.3z" /></g></svg>';
267 } else if ('inner-moon' === $variant) {
268 return '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="0px" height="0px" fill="currentColor" class="theme-toggle__inner-moon" viewBox="0 0 32 32"><path d="M27.5 11.5v-7h-7L16 0l-4.5 4.5h-7v7L0 16l4.5 4.5v7h7L16 32l4.5-4.5h7v-7L32 16l-4.5-4.5zM16 25.4a9.39 9.39 0 1 1 0-18.8 9.39 9.39 0 1 1 0 18.8z" /><circle cx="16" cy="16" r="8.1" /></svg>';
269 } else if ('within' === $variant) {
270 return '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="theme-toggle__within" height="1em" width="1em" viewBox="0 0 32 32" fill="currentColor"><clipPath id="theme-toggle__within__clip_' . esc_attr($unique_id) . '"><path d="M0 0h32v32h-32ZM6 16A1 1 0 0026 16 1 1 0 006 16" /></clipPath><g clip-path="url(#theme-toggle__within__clip_' . esc_attr($unique_id) . ')"><path d="M30.7 21.3 27.1 16l3.7-5.3c.4-.5.1-1.3-.6-1.4l-6.3-1.1-1.1-6.3c-.1-.6-.8-.9-1.4-.6L16 5l-5.4-3.7c-.5-.4-1.3-.1-1.4.6l-1 6.3-6.4 1.1c-.6.1-.9.9-.6 1.3L4.9 16l-3.7 5.3c-.4.5-.1 1.3.6 1.4l6.3 1.1 1.1 6.3c.1.6.8.9 1.4.6l5.3-3.7 5.3 3.7c.5.4 1.3.1 1.4-.6l1.1-6.3 6.3-1.1c.8-.1 1.1-.8.7-1.4zM16 25.1c-5.1 0-9.1-4.1-9.1-9.1 0-5.1 4.1-9.1 9.1-9.1s9.1 4.1 9.1 9.1c0 5.1-4 9.1-9.1 9.1z" /></g><path class="theme-toggle__within__circle" d="M16 7.7c-4.6 0-8.2 3.7-8.2 8.2s3.6 8.4 8.2 8.4 8.2-3.7 8.2-8.2-3.6-8.4-8.2-8.4zm0 14.4c-3.4 0-6.1-2.9-6.1-6.2s2.7-6.1 6.1-6.1c3.4 0 6.1 2.9 6.1 6.2s-2.7 6.1-6.1 6.1z" />
271 <path class="theme-toggle__within__inner" d="M16 9.5c-3.6 0-6.4 2.9-6.4 6.4s2.8 6.5 6.4 6.5 6.4-2.9 6.4-6.4-2.8-6.5-6.4-6.5z" /></svg>';
272 } elseif ('orbit' === $variant) {
273 return '<span class="toggle-track"><span class="toggle-sun"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M277.3 32h-42.7v64h42.7V32zm129.1 43.7L368 114.1l29.9 29.9 38.4-38.4-29.9-29.9zm-300.8 0l-29.9 29.9 38.4 38.4 29.9-29.9-38.4-38.4zM256 128c-70.4 0-128 57.6-128 128s57.6 128 128 128 128-57.6 128-128-57.6-128-128-128zm224 106.7h-64v42.7h64v-42.7zm-384 0H32v42.7h64v-42.7zM397.9 368L368 397.9l38.4 38.4 29.9-29.9-38.4-38.4zm-283.8 0l-38.4 38.4 29.9 29.9 38.4-38.4-29.9-29.9zm163.2 48h-42.7v64h42.7v-64z"></path></svg></span><span class="toggle-thumb"></span><span class="toggle-moon"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 384 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176c0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z"></path></svg></span></span>';
274 }
275 }
276
277 public static function switcher_wrapper($type, $unique_id, $variant, $switch_size, $position_class = '', $floating_switch_position = '', $tooltip_classes = '', $hide_dark_mode_on_mobile_screen = '', $floating_switch_width = '', $tooltip_on_floating_switch = '')
278 {
279
280 // A single `style` attribute: this used to be emitted TWICE (once with
281 // just the scale variable, then — for `shortcode` — a second `style="..."`
282 // appended after `class`). HTML only honors the FIRST of two duplicate
283 // attributes, so that second one (the only place `position: relative` was
284 // set) was silently dropped by every browser. Without it, an absolutely-
285 // positioned inner element (e.g. a pill variant's sliding thumb) has no
286 // guarantee of being positioned relative to THIS wrapper — it falls back
287 // to whatever positioned ancestor happens to exist (or none), which is
288 // exactly the kind of thing a page's content wrapper (often already
289 // `position: relative`) can accidentally paper over while a theme's nav
290 // `<li>` — the Menu Switch's actual context — usually doesn't.
291 $style = '--darkify-switch-scale: ' . esc_attr($switch_size) . ';' . ($type === 'shortcode' ? ' position: relative;' : '');
292 $classes = 'darkify_switch darkify_switch_style switch-' . esc_attr($variant)
293 . ($type !== 'shortcode' ? ' ' . esc_attr($position_class) . ' ' . esc_attr($floating_switch_position) . ' ' . esc_attr($tooltip_classes) . ' ' . esc_attr($hide_dark_mode_on_mobile_screen) : '');
294 return '<div style="' . $style . '" id="darkify_switch_' . esc_attr($unique_id) . '" onclick="darkify_switch_trigger()" class="' . $classes . '"><div class="theme-toggle">' . self::switcher($variant, $unique_id) . '</div>' . ($type !== 'shortcode' && $floating_switch_width ? '<span class="darkify_tooltiptext">' . esc_attr($tooltip_on_floating_switch) . '</span>' : '') . '</div>';
295 }
296
297 private function init_action()
298 {
299 add_action('activated_plugin', [$this, 'darkify_redirect_to']);
300 }
301
302
303 public function create_darkify_block_init()
304 {
305 register_block_type_from_metadata(
306 DARKIFY_PATH . 'src/Admin/blocks/',
307 array(
308 'render_callback' => [$this, 'render_darkify_block_callback'],
309 )
310 );
311
312 wp_localize_script(
313 'darkify-switcher-editor-script',
314 'darkify',
315 array(
316 'dir_url' => DARKIFY_DIR_URL,
317 )
318 );
319 }
320
321 /**
322 * Render callback for the Darkify Pro block.
323 */
324 public function render_darkify_block_callback($attributes)
325 {
326 $style = $attributes['style'] ?? 'classic';
327 $size = $attributes['size'] ?? '1.0';
328 $custom_size = $attributes['custom_size'] ?? 100;
329 $bg_light = $attributes['switch_bg_light'] ?? '#121116';
330 $bg_dark = $attributes['switch_bg_dark'] ?? '#ffffff';
331 $light_icon_color = $attributes['light_icon_color'] ?? '#ffffff';
332 $dark_icon_color = $attributes['dark_icon_color'] ?? '#121116';
333 $light_text_color = $attributes['light_text_color'] ?? '#121116';
334 $dark_text_color = $attributes['dark_text_color'] ?? '#ffffff';
335 $border_width = $attributes['border_width'] ?? 0;
336 $border_light_color = $attributes['border_light_color'] ?? '#121116';
337 $border_dark_color = $attributes['border_dark_color'] ?? '#ffffff';
338 $border_radius = $attributes['border_radius'] ?? 7;
339 $alignment = $attributes['alignment'] ?? 'left';
340
341 // Size logic
342 if ('custom' === $size) {
343 $switcher_size = $custom_size;
344 } else {
345 $switcher_size = (float) $size * 100;
346 }
347
348 return '<div style="display: flex; justify-content: ' . esc_attr($alignment) . '">' . do_shortcode(wp_sprintf(
349 '[darkify switch="%s" icon_size="40px" light_mode_bg="%s" dark_mode_bg="%s" light_mode_color="%s" dark_mode_color="%s" border="%spx" border_light_color="%s" border_dark_color="%s" border_radius="%spx" text_light_mode_color="%s" text_dark_mode_color="%s" switch_size="%s"]',
350 $style,
351 $bg_light,
352 $bg_dark,
353 $light_icon_color,
354 $dark_icon_color,
355 $border_width,
356 $border_light_color,
357 $border_dark_color,
358 $border_radius,
359 $light_text_color,
360 $dark_text_color,
361 $switcher_size
362 )) . '</div>';
363 }
364 }
365