PluginProbe
Customify / trunk
Customify vtrunk
2.10.9 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.7.1 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.0.1 1.6.5 1.7.0 1.7.1 All 77 releases
customify / includes / class-customify-settings.php

class-customify-settings.php in Customify trunk, at includes/class-customify-settings.php

499 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This is the class that handles the plugin settings page.
4 *
5 * @see https://pixelgrade.com
6 * @author Pixelgrade
7 * @since 2.4.0
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly
12 }
13
14 class Customify_Settings {
15
16 /**
17 * Instance of this class.
18 * @var object
19 */
20 protected static $_instance = null;
21
22 /**
23 * Slug of the plugin screen.
24 * @var string
25 */
26 protected $plugin_screen_hook_suffix = null;
27
28 public $plugin_settings;
29
30 /**
31 * The main plugin file.
32 * @var string
33 * @access public
34 */
35 public $file;
36
37 public $slug;
38 public $version;
39
40 private $plugin_config = null;
41
42 protected function __construct( $file, $slug, $version = '1.0.0' ) {
43 $this->file = $file;
44 $this->slug = $slug;
45 $this->version = $version;
46
47 require plugin_dir_path( $this->file ) . 'includes/admin-settings/core/bootstrap.php';
48
49 // Load the plugin's settings from the DB.
50 // We use the settings key directly to avoid loading the full config (which has translation calls) too early.
51 $this->plugin_settings = get_option( 'pixcustomify_settings' );
52
53 // Register all the needed hooks
54 $this->register_hooks();
55 }
56
57 /**
58 * Get the plugin config, loading it on first access.
59 *
60 * This lazy-loads the config to avoid calling translation functions before the textdomain is loaded.
61 *
62 * @return array
63 */
64 private function get_lazy_plugin_config() {
65 if ( null === $this->plugin_config ) {
66 $this->plugin_config = self::get_plugin_config();
67 }
68
69 return $this->plugin_config;
70 }
71
72 /**
73 * Register our actions and filters
74 */
75 function register_hooks() {
76
77 // Starting with the menu item for this plugin
78 add_action( 'admin_menu', array( $this, 'add_plugin_admin_menu' ) );
79
80 // Add an action link pointing to the options page.
81 add_filter( 'plugin_action_links_' . plugin_basename( $this->file ), array( $this, 'add_action_links' ) );
82
83 // Load admin stylesheet and JavaScript.
84 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
85 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
86
87
88 add_action( 'rest_api_init', array( $this, 'add_rest_routes_api' ) );
89 }
90
91 /**
92 * Register the administration menu for this plugin into the WordPress Dashboard menu.
93 */
94 function add_plugin_admin_menu() {
95 $this->plugin_screen_hook_suffix = add_options_page(
96 esc_html__( 'Customify', 'customify' ),
97 esc_html__( 'Customify', 'customify' ),
98 'manage_options',
99 $this->slug,
100 array( $this, 'display_plugin_admin_page' )
101 );
102 }
103
104 /**
105 * Render the settings page for this plugin.
106 */
107 function display_plugin_admin_page() {
108 // Check the nonce, in case the form was submitted.
109 if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) {
110 check_admin_referer( 'customify_settings_save', '_wpnonce-customify-settings' );
111 }
112
113 $config = Customify_Settings::get_plugin_config();
114
115 // Invoke the processor.
116 /**
117 * @var PixCustomifyProcessorImpl $processor
118 */
119 $processor = pixcustomify::processor( $config );
120 $status = $processor->status();
121 $errors = $processor->errors();
122
123 // Do the saving and display the form.
124 include_once plugin_dir_path( $this->file ) . 'includes/admin-settings/views/admin.php';
125 }
126
127 /**
128 * Settings page styles
129 */
130 function enqueue_admin_styles() {
131
132 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
133 return;
134 }
135
136 $screen = get_current_screen();
137 if ( $screen->id === $this->plugin_screen_hook_suffix ) {
138 $rtl_suffix = is_rtl() ? '-rtl' : '';
139 wp_enqueue_style( $this->slug . '-admin-styles', plugins_url( 'css/admin' . $rtl_suffix . '.css', $this->file ), array(), $this->version );
140 }
141 }
142
143 /**
144 * Settings page scripts
145 */
146 function enqueue_admin_scripts() {
147
148 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
149 return;
150 }
151
152 $screen = get_current_screen();
153 if ( $screen->id == $this->plugin_screen_hook_suffix ) {
154 $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
155
156 wp_enqueue_script( $this->slug . '-settings-page-script',
157 plugins_url( 'js/settings-page' . $suffix . '.js', $this->file ),
158 array( 'jquery' ),
159 $this->version,
160 false );
161
162 wp_add_inline_script( $this->slug . '-settings-page-script',
163 PixCustomify_Customizer::getlocalizeToWindowScript( 'customify',
164 array(
165 'config' => array(
166 'ajax_url' => admin_url( 'admin-ajax.php' ),
167 'wp_rest' => array(
168 'root' => esc_url_raw( rest_url() ),
169 'nonce' => wp_create_nonce( 'wp_rest' ),
170 'customify_settings_nonce' => wp_create_nonce( 'customify_settings_nonce' )
171 ),
172 )
173 )
174 ) );
175 }
176
177 wp_localize_script( $this->slug . '-customizer-scripts', 'WP_API_Settings', array(
178 'root' => esc_url_raw( rest_url() ),
179 'nonce' => wp_create_nonce( 'wp_rest' )
180 ) );
181 }
182
183 /**
184 * Add settings action link to the plugins page.
185 */
186 public function add_action_links( $links ) {
187 return array_merge( array( 'settings' => '<a href="' . esc_url( menu_page_url( $this->slug, false ) ) . '">' . esc_html__( 'Settings', 'customify' ) . '</a>' ), $links );
188 }
189
190 public function add_rest_routes_api() {
191 register_rest_route( 'customify/v1', '/delete_theme_mod', array(
192 'methods' => 'POST',
193 'callback' => array( $this, 'delete_theme_mod' ),
194 'permission_callback' => array( $this, 'permission_nonce_callback' ),
195 ) );
196 }
197
198 public function delete_theme_mod() {
199 if ( ! current_user_can( 'manage_options' ) ) {
200 wp_send_json_error( esc_html__('You don\'t have admin privileges.', 'customify' ) );
201 }
202
203 $key = PixCustomifyPlugin()->get_options_key();
204
205 if ( empty( $key ) ) {
206 wp_send_json_error('no option key');
207 }
208
209 remove_theme_mod( $key );
210
211 PixCustomifyPlugin()->invalidate_all_caches();
212
213 wp_send_json_success('Deleted ' . $key . ' theme mod!');
214 }
215
216 public function permission_nonce_callback() {
217 return wp_verify_nonce( $this->get_nonce(), 'customify_settings_nonce' );
218 }
219
220 private function get_nonce() {
221 $nonce = null;
222
223 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This helper reads the nonce value that permission_nonce_callback() verifies.
224 if ( isset( $_REQUEST['customify_settings_nonce'] ) ) {
225 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This helper reads the nonce value that permission_nonce_callback() verifies.
226 $nonce = sanitize_text_field( wp_unslash( $_REQUEST['customify_settings_nonce'] ) );
227 }
228
229 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This helper reads the nonce value that permission_nonce_callback() verifies.
230 if ( null === $nonce && isset( $_POST['customify_settings_nonce'] ) ) {
231 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This helper reads the nonce value that permission_nonce_callback() verifies.
232 $nonce = sanitize_text_field( wp_unslash( $_POST['customify_settings_nonce'] ) );
233 }
234
235 return $nonce;
236 }
237
238 static public function get_plugin_config() {
239
240 $debug = false;
241 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only debug flag for rendering the settings config.
242 if ( isset( $_GET['debug'] ) && 'true' === sanitize_text_field( wp_unslash( $_GET['debug'] ) ) ) {
243 $debug = true;
244 }
245
246 return array(
247 'plugin-name' => 'pixcustomify',
248 'settings-key' => 'pixcustomify_settings',
249 'textdomain' => 'customify',
250 'template-paths' => array(
251 plugin_dir_path( __FILE__ ) . 'admin-settings/core/views/form-partials/',
252 plugin_dir_path( __FILE__ ) . 'admin-settings/views/form-partials/',
253 ),
254 'fields' => array(
255 'hiddens' => array(
256 'type' => 'group',
257 'options' => array(
258 'settings_saved_once' => array(
259 'default' => '0',
260 'value' => '1',
261 'type' => 'hidden',
262 ),
263 ),
264 ),
265 'general' => array(
266 'type' => 'postbox',
267 'label' => esc_html__( 'General Settings', 'customify' ),
268 'options' => array(
269 'values_store_mod' => array(
270 'name' => 'values_store_mod',
271 'label' => esc_html__( 'Store values as:', 'customify' ),
272 'desc' => esc_html__( 'You can store the values globally so you can use them with other themes or store them as a "theme_mod" which will make an individual set of options only for the current theme', 'customify' ),
273 'default' => 'theme_mod',
274 'type' => 'select',
275 'options' => array(
276 'option' => esc_html__( 'Option (global options)', 'customify' ),
277 'theme_mod' => esc_html__( 'Theme Mod (per theme options)', 'customify' ),
278 ),
279 ),
280
281 'disable_default_sections' => array(
282 'name' => 'disable_default_sections',
283 'label' => esc_html__( 'Disable default sections', 'customify' ),
284 'desc' => esc_html__( 'You can disable default sections', 'customify' ),
285 'type' => 'multicheckbox',
286 'options' => array(
287 'nav' => esc_html__( 'Navigation', 'customify' ),
288 'static_front_page' => esc_html__( 'Front Page', 'customify' ),
289 'title_tagline' => esc_html__( 'Title', 'customify' ),
290 'colors' => esc_html__( 'Colors', 'customify' ),
291 'background_image' => esc_html__( 'Background', 'customify' ),
292 'header_image' => esc_html__( 'Header', 'customify' ),
293 'widgets' => esc_html__( 'Widgets', 'customify' ),
294 ),
295 ),
296
297 'enable_reset_buttons' => array(
298 'name' => 'enable_reset_buttons',
299 'label' => esc_html__( 'Enable Reset Buttons', 'customify' ),
300 'desc' => esc_html__( 'You can enable "Reset to defaults" buttons for panels / sections or all settings. We have disabled this feature by default to avoid accidental resets. If you are sure that you need it please enable this.', 'customify' ),
301 'default' => false,
302 'type' => 'switch',
303 ),
304
305 'enable_editor_style' => array(
306 'name' => 'enable_editor_style',
307 'label' => esc_html__( 'Enable Editor Style', 'customify' ),
308 'desc' => esc_html__( 'The styling added by Customify in front-end can be added in the WordPress editor too by enabling this option', 'customify' ),
309 'default' => true,
310 'type' => 'switch',
311 ),
312 ),
313 ),
314 'output' => array(
315 'type' => 'postbox',
316 'label' => esc_html__( 'Output Settings', 'customify' ),
317 'options' => array(
318 'style_resources_location' => array(
319 'name' => 'style_resources_location',
320 'label' => esc_html__( 'Styles location:', 'customify' ),
321 'desc' => esc_html__( 'Here you can decide where to put your style output, in header or footer', 'customify' ),
322 'default' => 'wp_footer',
323 'type' => 'select',
324 'options' => array(
325 'wp_head' => esc_html__( 'In header (just before the head tag)', 'customify' ),
326 'wp_footer' => esc_html__( 'Footer (just before the end of the body tag)', 'customify' ),
327 ),
328 ),
329 ),
330 ),
331 'typography' => array(
332 'type' => 'postbox',
333 'label' => esc_html__( 'Typography Settings', 'customify' ),
334 'options' => array(
335 'typography' => array(
336 'label' => esc_html__( 'Enable Typography Options', 'customify' ),
337 'default' => true,
338 'type' => 'switch',
339 'show_group' => 'typography_group',
340 'display_option' => true,
341 ),
342
343 'typography_group' => array(
344 'type' => 'group',
345 'options' => array(
346 'typography_system_fonts' => array(
347 'name' => 'typography_system_fonts',
348 'label' => esc_html__( 'Use system fonts', 'customify' ),
349 'desc' => esc_html__( 'Would you like to have system fonts available in the font controls?', 'customify' ),
350 'default' => true,
351 'type' => 'switch',
352 ),
353 'typography_google_fonts' => array(
354 'name' => 'typography_google_fonts',
355 'label' => esc_html__( 'Use Google fonts:', 'customify' ),
356 'desc' => esc_html__( 'Would you like to have Google fonts available in the font controls?', 'customify' ),
357 'default' => true,
358 'type' => 'switch',
359 'show_group' => 'typography_google_fonts_group',
360 'display_option' => true,
361 ),
362 'typography_google_fonts_group' => array(
363 'type' => 'group',
364 'options' => array(
365 'typography_group_google_fonts' => array(
366 'name' => 'typography_group_google_fonts',
367 'label' => esc_html__( 'Group Google fonts:', 'customify' ),
368 'desc' => esc_html__( 'You can chose to see the Google fonts in groups', 'customify' ),
369 'default' => true,
370 'type' => 'switch',
371 ),
372 ),
373 ),
374 'typography_cloud_fonts' => array(
375 'name' => 'typography_cloud_fonts',
376 'label' => esc_html__( 'Use cloud fonts', 'customify' ),
377 'desc' => esc_html__( 'Would you to have Cloud fonts available in the font controls?', 'customify' ),
378 'default' => true,
379 'type' => 'switch',
380 'display_option' => true,
381 ),
382 ),
383 ),
384 ),
385 ),
386 'tools' => array(
387 'type' => 'postbox',
388 'label' => esc_html__( 'Tools', 'customify' ),
389 'options' => array(
390 'reset_theme_mod' => array(
391 'name' => 'reset_theme_mod',
392 'label' => esc_html__( 'Reset', 'customify' ),
393 'type' => 'reset_theme_mod',
394 ),
395 ),
396 ),
397 ),
398 'callbacks' => array(
399 'invalidate_caches' => 'pixcustomify_cache_invalidate_cache',
400 ),
401 'processor' => array(
402 // callback signature: (array $input, customifyProcessor $processor)
403 'preupdate' => array(
404 // callbacks to run before update process
405 // cleanup and validation has been performed on data
406 ),
407 'postupdate' => array(
408 'invalidate_caches'
409 ),
410 ),
411 'cleanup' => array(
412 'switch' => array( 'switch_not_available' ),
413 ),
414 'checks' => array(
415 'counter' => array( 'is_numeric', 'not_empty' ),
416 ),
417 'errors' => array(
418 'not_empty' => __( 'Invalid Value.', 'customify' ),
419 ),
420 // shows exception traces on error
421 'debug' => $debug,
422
423 ); # config
424 }
425
426 /**
427 * Get an option's value from the config file
428 *
429 * @param $option
430 * @param null $default
431 *
432 * @return bool|null
433 */
434 public function get_config_option( $option, $default = null ) {
435 $config = $this->get_lazy_plugin_config();
436
437 if ( isset( $config[ $option ] ) ) {
438 return $config[ $option ];
439 } elseif ( $default !== null ) {
440 return $default;
441 }
442
443 return false;
444 }
445
446 public function get_plugin_setting( $option, $default = null ) {
447
448 if ( isset( $this->plugin_settings[ $option ] ) ) {
449 return $this->plugin_settings[ $option ];
450 } elseif ( $default !== null ) {
451 return $default;
452 }
453
454 return false;
455 }
456
457 /**
458 * Main Customify_Settings Instance
459 *
460 * Ensures only one instance of Customify_Settings is loaded or can be loaded.
461 *
462 * @static
463 *
464 * @param string $file File.
465 * @param string $slug Plugin slug.
466 * @param string $version Optional.
467 *
468 * @return Customify_Settings Main Customify_Settings instance
469 */
470 public static function instance( $file, $slug, $version = '1.0.0' ) {
471 // If the single instance hasn't been set, set it now.
472 if ( is_null( self::$_instance ) ) {
473 self::$_instance = new self( $file, $slug, $version );
474 }
475
476 return self::$_instance;
477 }
478
479 /**
480 * Cloning is forbidden.
481 *
482 * @since 1.5.0
483 */
484 public function __clone() {
485
486 _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
487 }
488
489 /**
490 * Unserializing instances of this class is forbidden.
491 *
492 * @since 1.5.0
493 */
494 public function __wakeup() {
495
496 _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
497 }
498 }
499