PluginProbe
QuadMenu – Mega Menu / 3.3.3
QuadMenu – Mega Menu v3.3.3
3.3.7 3.3.6 trunk 1.8.4 1.8.5 1.8.7 1.8.8 1.8.9 1.9.0 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 All 87 releases
quadmenu / redux / ReduxCore / framework.php

framework.php in QuadMenu – Mega Menu 3.3.3, at redux/ReduxCore/framework.php

4,361 lines 143.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Redux Framework is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
7 * Redux Framework is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with Redux Framework. If not, see <http://www.gnu.org/licenses/>.
13 *
14 * @package Redux_Framework
15 * @subpackage Core
16 * @author Redux Framework Team
17 */
18 // Exit if accessed directly
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 if ( ! class_exists( 'ReduxFrameworkInstancesLegacy' ) ) {
24 // Instance Container
25 require_once __DIR__ . '/inc/class.redux_instances.php';
26 require_once __DIR__ . '/inc/lib.redux_instances.php';
27 }
28
29 if ( class_exists( 'ReduxFrameworkInstancesLegacy' ) ) {
30 add_action( 'redux/init', 'ReduxFrameworkInstancesLegacy::get_instance' );
31 }
32
33 // Don't duplicate me!
34 if ( ! class_exists( 'ReduxFrameworkLegacy' ) ) {
35 // Redux CDN class
36 require_once __DIR__ . '/inc/class.redux_cdn.php';
37
38 // Redux API class :)
39 require_once __DIR__ . '/inc/class.redux_api.php';
40
41 // General helper functions
42 require_once __DIR__ . '/inc/class.redux_helpers.php';
43
44 // General functions
45 require_once __DIR__ . '/inc/class.redux_functions.php';
46 require_once __DIR__ . '/inc/class.p.php';
47
48 require_once __DIR__ . '/inc/class.thirdparty.fixes.php';
49
50 require_once __DIR__ . '/inc/class.redux_filesystem.php';
51
52 require_once __DIR__ . '/inc/class.redux_admin_notices.php';
53
54 // ThemeCheck checks
55 require_once __DIR__ . '/inc/themecheck/class.redux_themecheck.php';
56
57 // Welcome
58 require_once __DIR__ . '/inc/welcome/welcome.php';
59
60 /**
61 * Main ReduxFrameworkLegacy class
62 *
63 * @since 1.0.0
64 */
65 class ReduxFrameworkLegacy {
66 // ATTENTION DEVS
67 // Please update the build number with each push, no matter how small.
68 // This will make for easier support when we ask users what version they are using.
69
70 public static $_version = '3.6.18';
71 public static $_dir;
72 public static $_url;
73 public static $_upload_dir;
74 public static $_upload_url;
75 public static $wp_content_url;
76 public static $base_wp_content_url;
77 public static $_is_plugin = true;
78 public static $_as_plugin = false;
79 public $old_opt_name;
80 public $transients_check;
81 public $field_types;
82 public $field_head;
83 public $googleArray;
84 public $validation_ran;
85 public $no_output;
86 public $no_panel_section;
87
88 public static function init() {
89 $dir = ReduxLegacy_Helpers::cleanFilePath( __DIR__ );
90
91 // Windows-proof constants: replace backward by forward slashes. Thanks to: @peterbouwmeester
92 self::$_dir = trailingslashit( $dir );
93 self::$wp_content_url = trailingslashit( ReduxLegacy_Helpers::cleanFilePath( ( is_ssl() ? str_replace( 'http://', 'https://', WP_CONTENT_URL ) : WP_CONTENT_URL ) ) );
94
95 // See if Redux is a plugin or not
96 if ( strpos( ReduxLegacy_Helpers::cleanFilePath( __FILE__ ), ReduxLegacy_Helpers::cleanFilePath( get_stylesheet_directory() ) ) !== false || strpos( ReduxLegacy_Helpers::cleanFilePath( __FILE__ ), ReduxLegacy_Helpers::cleanFilePath( get_template_directory_uri() ) ) !== false || strpos( ReduxLegacy_Helpers::cleanFilePath( __FILE__ ), ReduxLegacy_Helpers::cleanFilePath( WP_CONTENT_DIR . '/themes/' ) ) !== false ) {
97 self::$_is_plugin = false;
98 } else {
99 // Check if plugin is a symbolic link, see if it's a plugin. If embedded, we can't do a thing.
100 if ( strpos( self::$_dir, ABSPATH ) === false ) {
101 if ( ! function_exists( 'get_plugins' ) ) {
102 require_once ABSPATH . 'wp-admin/includes/plugin.php';
103 }
104
105 $is_plugin = false;
106
107 // QUADLAYERS DEVS NOTE: this change the path if the plugin version is installed in WordPress, breaking the options tab in dashboard
108
109 // foreach ( get_plugins() as $key => $value ) {
110 // if ( is_plugin_active( $key ) && strpos( $key, 'redux-framework.php' ) !== false ) {
111 // self::$_dir = trailingslashit( ReduxLegacy_Helpers::cleanFilePath( WP_CONTENT_DIR . '/plugins/' . plugin_dir_path( $key ) . 'ReduxCore/' ) );
112 // $is_plugin = true;
113 // }
114 // }
115 if ( ! $is_plugin ) {
116 self::$_is_plugin = false;
117 }
118 }
119 }
120
121 if ( self::$_is_plugin == true || self::$_as_plugin == true ) {
122 self::$_url = plugin_dir_url( __FILE__ );
123 } elseif ( strpos( ReduxLegacy_Helpers::cleanFilePath( __FILE__ ), ReduxLegacy_Helpers::cleanFilePath( get_template_directory() ) ) !== false ) {
124 $relative_url = str_replace( ReduxLegacy_Helpers::cleanFilePath( get_template_directory() ), '', self::$_dir );
125 self::$_url = trailingslashit( get_template_directory_uri() . $relative_url );
126 } elseif ( strpos( ReduxLegacy_Helpers::cleanFilePath( __FILE__ ), ReduxLegacy_Helpers::cleanFilePath( get_stylesheet_directory() ) ) !== false ) {
127 $relative_url = str_replace( ReduxLegacy_Helpers::cleanFilePath( get_stylesheet_directory() ), '', self::$_dir );
128 self::$_url = trailingslashit( get_stylesheet_directory_uri() . $relative_url );
129 } else {
130 $wp_content_dir = trailingslashit( ReduxLegacy_Helpers::cleanFilePath( WP_CONTENT_DIR ) );
131 $wp_content_dir = trailingslashit( str_replace( '//', '/', $wp_content_dir ) );
132 $relative_url = str_replace( $wp_content_dir, '', self::$_dir );
133 self::$_url = trailingslashit( self::$wp_content_url . $relative_url );
134 }
135
136 /**
137 * TODO: Fix mkdir url
138 * */
139
140 if ( QUADMENU_DEV ) {
141 self::$_url = plugin_dir_url( __FILE__ );
142 }
143
144 self::$_url = apply_filters( 'redux/_url', self::$_url );
145 self::$_dir = apply_filters( 'redux/_dir', self::$_dir );
146 self::$_is_plugin = apply_filters( 'redux/_is_plugin', self::$_is_plugin );
147 }
148
149 // ::init()
150
151 public $framework_url = 'http://www.ReduxFrameworkLegacy.com/';
152 public static $instance = null;
153 public $admin_notices = array();
154 public $page = '';
155 public $saved = false;
156 public $fields = array(); // Fields by type used in the panel
157 public $field_sections = array(); // Section id's by field type, then field ID
158 public $current_tab = ''; // Current section to display, cookies
159 public $extensions = array(); // Extensions by type used in the panel
160 public $sections = array(); // Sections and fields
161 public $errors = array(); // Errors
162 public $warnings = array(); // Warnings
163 public $options = array(); // Option values
164 public $options_defaults = null; // Option defaults
165 public $notices = array(); // Option defaults
166 public $compiler_fields = array(); // Fields that trigger the compiler hook
167 public $required = array(); // Information that needs to be localized
168 public $required_child = array(); // Information that needs to be localized
169 public $localize_data = array(); // Information that needs to be localized
170 public $fonts = array(); // Information that needs to be localized
171 public $folds = array(); // The itms that need to fold.
172 public $path = '';
173 public $changed_values = array(); // Values that have been changed on save. Orig values.
174 public $output = array(); // Fields with CSS output selectors
175 public $outputCSS = null; // CSS that get auto-appended to the header
176 public $compilerCSS = null; // CSS that get sent to the compiler hook
177 public $customizerCSS = null; // CSS that goes to the customizer
178 public $fieldsValues = array(); // all fields values in an id=>value array so we can check dependencies
179 public $fieldsHidden = array(); // all fields that didn't pass the dependency test and are hidden
180 public $toHide = array(); // Values to hide on page load
181 public $typography = null; // values to generate google font CSS
182 public $import_export = null;
183 public $no_panel = array(); // Fields that are not visible in the panel
184 private $show_hints = false;
185 public $hidden_perm_fields = array(); // Hidden fields specified by 'permissions' arg.
186 public $hidden_perm_sections = array(); // Hidden sections specified by 'permissions' arg.
187 public $typography_preview = array();
188 public $args = array();
189 public $filesystem = null;
190 public $font_groups = array();
191 public $lang = '';
192 public $dev_mode_forced = false;
193 public $reload_fields = array();
194 public $omit_share_icons = false;
195 public $omit_admin_items = false;
196 public $apiHasRun = false;
197 public $transients;
198
199 /**
200 * Class Constructor. Defines the args for the theme options class
201 *
202 * @since 1.0.0
203 *
204 * @param array $sections Panel sections.
205 * @param array $args Class constructor arguments.
206 * @param array $extra_tabs Extra panel tabs. // REMOVE
207 *
208 * @return \ReduxFrameworkLegacy
209 */
210 public function __construct( $sections = array(), $args = array(), $extra_tabs = array() ) {
211 // Disregard WP AJAX 'heartbeat'call. Why waste resources?
212 if ( isset( $_POST ) && isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
213
214 // Hook, for purists.
215 if ( has_action( 'redux/ajax/heartbeat' ) ) {
216 do_action( 'redux/ajax/heartbeat', $this );
217 }
218
219 // Buh bye!
220 return;
221 }
222
223 // Pass parent pointer to function helper.
224 ReduxLegacy_Functions::$_parent = $this;
225 ReduxLegacy_CDN::$_parent = $this;
226
227 // Set values
228 $this->set_default_args();
229 $this->args = wp_parse_args( $args, $this->args );
230
231 if ( empty( $this->args['transient_time'] ) ) {
232 $this->args['transient_time'] = 60 * MINUTE_IN_SECONDS;
233 }
234
235 if ( empty( $this->args['footer_credit'] ) ) {
236 $this->args['footer_credit'] = '<span id="footer-thankyou">' . sprintf( __( 'Options panel created using %1$s', 'redux-framework' ), '<a href="' . esc_url( $this->framework_url ) . '" target="_blank">' . __( 'Redux Framework', 'redux-framework' ) . '</a> v' . self::$_version ) . '</span>';
237 }
238
239 if ( empty( $this->args['menu_title'] ) ) {
240 $this->args['menu_title'] = __( 'Options', 'redux-framework' );
241 }
242
243 if ( empty( $this->args['page_title'] ) ) {
244 $this->args['page_title'] = __( 'Options', 'redux-framework' );
245 }
246
247 $this->old_opt_name = $this->args['opt_name'];
248
249 /**
250 * filter 'redux/args/{opt_name}'
251 *
252 * @param array $args ReduxFrameworkLegacy configuration
253 */
254 $this->args = apply_filters( "redux/args/{$this->args['opt_name']}", $this->args );
255
256 /**
257 * filter 'redux/options/{opt_name}/args'
258 *
259 * @param array $args ReduxFrameworkLegacy configuration
260 */
261 $this->args = apply_filters( "redux/options/{$this->args['opt_name']}/args", $this->args );
262
263 if ( $this->args['opt_name'] == $this->old_opt_name ) {
264 unset( $this->old_opt_name );
265 }
266
267 // Do not save the defaults if we're on a live preview!
268 if ( $GLOBALS['pagenow'] == 'customize' && isset( $_GET['theme'] ) && ! empty( $_GET['theme'] ) ) {
269 $this->args['save_defaults'] = false;
270 }
271
272 if ( ! empty( $this->args['opt_name'] ) ) {
273 /**
274 * SHIM SECTION
275 * Old variables and ways of doing things that need correcting. ;)
276 * */
277 // Variable name change
278 if ( ! empty( $this->args['page_cap'] ) ) {
279 $this->args['page_permissions'] = $this->args['page_cap'];
280 unset( $this->args['page_cap'] );
281 }
282
283 if ( ! empty( $this->args['page_position'] ) ) {
284 $this->args['page_priority'] = $this->args['page_position'];
285 unset( $this->args['page_position'] );
286 }
287
288 if ( ! empty( $this->args['page_type'] ) ) {
289 $this->args['menu_type'] = $this->args['page_type'];
290 unset( $this->args['page_type'] );
291 }
292
293 // Auto create the page_slug appropriately
294 if ( empty( $this->args['page_slug'] ) ) {
295 if ( ! empty( $this->args['display_name'] ) ) {
296 $this->args['page_slug'] = sanitize_html_class( $this->args['display_name'] );
297 } elseif ( ! empty( $this->args['page_title'] ) ) {
298 $this->args['page_slug'] = sanitize_html_class( $this->args['page_title'] );
299 } elseif ( ! empty( $this->args['menu_title'] ) ) {
300 $this->args['page_slug'] = sanitize_html_class( $this->args['menu_title'] );
301 } else {
302 $this->args['page_slug'] = str_replace( '-', '_', $this->args['opt_name'] );
303 }
304 }
305
306 $this->change_demo_defaults();
307
308 // Get rid of extra_tabs! Not needed.
309 if ( is_array( $extra_tabs ) && ! empty( $extra_tabs ) ) {
310 foreach ( $extra_tabs as $tab ) {
311 array_push( $this->sections, $tab );
312 }
313 }
314
315 // Move to the first loop area!
316 /**
317 * filter 'redux-sections'
318 *
319 * @deprecated
320 *
321 * @param array $sections field option sections
322 */
323 $this->sections = apply_filters( 'redux-sections', $sections ); // REMOVE LATER
324 /**
325 * filter 'redux-sections-{opt_name}'
326 *
327 * @deprecated
328 *
329 * @param array $sections field option sections
330 */
331 $this->sections = apply_filters( "redux-sections-{$this->args['opt_name']}", $this->sections ); // REMOVE LATER
332 /**
333 * filter 'redux/options/{opt_name}/sections'
334 *
335 * @param array $sections field option sections
336 */
337 $this->sections = apply_filters( "redux/options/{$this->args['opt_name']}/sections", $this->sections );
338
339 /**
340 * Construct hook
341 * action 'redux/construct'
342 *
343 * @param object $this ReduxFrameworkLegacy
344 */
345 do_action( 'redux/construct', $this );
346
347 // Set the default values
348 $this->_default_cleanup();
349
350 // Internataionalization
351 $this->_internationalization();
352
353 $this->filesystem = ReduxLegacy_Filesystem::get_instance( $this );
354
355 // set redux upload folder
356 $this->set_redux_content();
357
358 // Register extra extensions
359 $this->_register_extensions();
360
361 // Grab database values
362 $this->get_options();
363
364 // Tracking
365 if ( isset( $this->args['allow_tracking'] ) && $this->args['allow_tracking'] && ReduxLegacy_Helpers::isTheme( __FILE__ ) ) {
366 $this->_tracking();
367 }
368
369 // Options page
370 add_action( 'admin_menu', array( $this, '_options_page' ) );
371
372 // Add a network menu
373 if ( $this->args['database'] == 'network' && $this->args['network_admin'] ) {
374 add_action( 'network_admin_menu', array( $this, '_options_page' ) );
375 }
376
377 // Admin Bar menu
378 add_action(
379 'admin_bar_menu',
380 array(
381 $this,
382 '_admin_bar_menu',
383 ),
384 $this->args['admin_bar_priority']
385 );
386
387 // Register setting
388 add_action( 'admin_init', array( $this, '_register_settings' ) );
389
390 // Display admin notices in dev_mode
391 if ( true == $this->args['dev_mode'] ) {
392 if ( true == $this->args['update_notice'] ) {
393 // add_action( 'admin_init', array( $this, '_update_check' ) );
394 }
395 }
396
397 // Display admin notices
398 add_action( 'admin_notices', array( $this, '_admin_notices' ), 99 );
399
400 // Check for dismissed admin notices.
401 add_action( 'admin_init', array( $this, '_dismiss_admin_notice' ), 9 );
402
403 // Enqueue the admin page CSS and JS
404 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
405 add_action( 'admin_enqueue_scripts', array( $this, '_enqueue' ), 1 );
406 }
407
408 // Output dynamic CSS
409 // Frontend: Maybe enqueue dynamic CSS and Google fonts
410 if ( empty( $this->args['output_location'] ) || in_array( 'frontend', $this->args['output_location'] ) ) {
411 add_action( 'wp_head', array( &$this, '_output_css' ), 150 );
412 add_action( 'wp_enqueue_scripts', array( &$this, '_enqueue_output' ), 150 );
413 }
414
415 // Login page: Maybe enqueue dynamic CSS and Google fonts
416 if ( in_array( 'login', $this->args['output_location'] ) ) {
417 add_action( 'login_head', array( &$this, '_output_css' ), 150 );
418 add_action( 'login_enqueue_scripts', array( &$this, '_enqueue_output' ), 150 );
419 }
420
421 // Admin area: Maybe enqueue dynamic CSS and Google fonts
422 if ( in_array( 'admin', $this->args['output_location'] ) ) {
423 add_action( 'admin_head', array( &$this, '_output_css' ), 150 );
424 add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_output' ), 150 );
425 }
426
427 add_action( 'wp_print_scripts', array( $this, 'vc_fixes' ), 100 );
428 add_action( 'admin_enqueue_scripts', array( $this, 'vc_fixes' ), 100 );
429
430 if ( $this->args['database'] == 'network' && $this->args['network_admin'] ) {
431 add_action(
432 'network_admin_edit_redux_' . $this->args['opt_name'],
433 array(
434 $this,
435 'save_network_page',
436 ),
437 10,
438 0
439 );
440 add_action( 'admin_bar_menu', array( $this, 'network_admin_bar' ), 999 );
441 }
442 // Ajax saving!!!
443 add_action( 'wp_ajax_' . $this->args['opt_name'] . '_ajax_save', array( $this, 'ajax_save' ) );
444
445 if ( $this->args['dev_mode'] == true || ReduxLegacy_Helpers::isLocalHost() == true ) {
446 require_once 'core/dashboard.php';
447 new reduxLegacyDashboardWidget( $this );
448
449 if ( ! isset( $GLOBALS['redux_notice_check'] ) || $GLOBALS['redux_notice_check'] == 0 ) {
450 require_once 'core/newsflash.php';
451
452 $params = array(
453 'dir_name' => 'notice',
454 'server_file' => 'http://ReduxFrameworkLegacy.com/wp-content/uploads/redux/redux_notice.json',
455 'interval' => 3,
456 'cookie_id' => 'redux_blast',
457 );
458
459 new reduxLegacyNewsflash( $this, $params );
460 $GLOBALS['redux_notice_check'] = 1;
461 }
462 }
463 }
464
465 /**
466 * Loaded hook
467 * action 'redux/loaded'
468 *
469 * @param object $this ReduxFrameworkLegacy
470 */
471 do_action( 'redux/loaded', $this );
472 }
473
474 // __construct()
475
476 private function set_redux_content() {
477 $upload_dir = wp_upload_dir();
478 self::$_upload_dir = $upload_dir['basedir'] . '/redux/';
479 self::$_upload_url = str_replace(
480 array(
481 'https://',
482 'http://',
483 ),
484 '//',
485 $upload_dir['baseurl'] . '/redux/'
486 );
487 }
488
489 private function set_default_args() {
490 $this->args = array(
491 'opt_name' => '',
492 // Must be defined by theme/plugin
493 'google_api_key' => '',
494 // Must be defined to update the google fonts cache for the typography module
495 'google_update_weekly' => false,
496 // Set to keep your google fonts updated weekly
497 'last_tab' => '',
498 // force a specific tab to always show on reload
499 'menu_icon' => '',
500 // menu icon
501 'menu_title' => '',
502 // menu title/text
503 'page_title' => '',
504 // option page title
505 'page_slug' => '',
506 'page_permissions' => 'manage_options',
507 'menu_type' => 'menu',
508 // ('menu'|'submenu')
509 'page_parent' => 'themes.php',
510 // requires menu_type = 'submenu
511 'page_priority' => null,
512 'allow_sub_menu' => true,
513 // allow submenus to be added if menu_type == menu
514 'save_defaults' => true,
515 // Save defaults to the DB on it if empty
516 'footer_credit' => '',
517 'async_typography' => false,
518 'disable_google_fonts_link' => false,
519 'class' => '',
520 // Class that gets appended to all redux-containers
521 'admin_bar' => true,
522 'admin_bar_priority' => 999,
523 // Show the panel pages on the admin bar
524 'admin_bar_icon' => '',
525 // admin bar icon
526 'help_tabs' => array(),
527 'help_sidebar' => '',
528 'database' => '',
529 // possible: options, theme_mods, theme_mods_expanded, transient, network
530 'customizer' => false,
531 // setting to true forces get_theme_mod_expanded
532 'global_variable' => '',
533 // Changes global variable from $GLOBALS['YOUR_OPT_NAME'] to whatever you set here. false disables the global variable
534 'output' => true,
535 // Dynamically generate CSS
536 'compiler' => true,
537 // Initiate the compiler hook
538 'output_tag' => true,
539 // Print Output Tag
540 'output_location' => array( 'frontend' ),
541 // Where the dynamic CSS will be added. Can be any combination from: 'frontend', 'login', 'admin'
542 'transient_time' => '',
543 'default_show' => false,
544 // If true, it shows the default value
545 'default_mark' => '',
546 // What to print by the field's title if the value shown is default
547 'update_notice' => true,
548 // Recieve an update notice of new commits when in dev mode
549 'disable_save_warn' => false,
550 // Disable the save warn
551 'open_expanded' => false,
552 'hide_expand' => false,
553 // Start the panel fully expanded to start with
554 'network_admin' => false,
555 // Enable network admin when using network database mode
556 'network_sites' => true,
557 // Enable sites as well as admin when using network database mode
558 'hide_reset' => false,
559 'hide_save' => false,
560 'hints' => array(
561 'icon' => 'el el-question-sign',
562 'icon_position' => 'right',
563 'icon_color' => 'lightgray',
564 'icon_size' => 'normal',
565 'tip_style' => array(
566 'color' => 'light',
567 'shadow' => true,
568 'rounded' => false,
569 'style' => '',
570 ),
571 'tip_position' => array(
572 'my' => 'top_left',
573 'at' => 'bottom_right',
574 ),
575 'tip_effect' => array(
576 'show' => array(
577 'effect' => 'slide',
578 'duration' => '500',
579 'event' => 'mouseover',
580 ),
581 'hide' => array(
582 'effect' => 'fade',
583 'duration' => '500',
584 'event' => 'click mouseleave',
585 ),
586 ),
587 ),
588 'show_import_export' => true,
589 'show_options_object' => true,
590 'dev_mode' => true,
591 'templates_path' => '',
592 // Path to the templates file for various Redux elements
593 'ajax_save' => true,
594 // Disable the use of ajax saving for the panel
595 'use_cdn' => true,
596 'cdn_check_time' => 1440,
597 'options_api' => true,
598 );
599 }
600
601 // Fix conflicts with Visual Composer.
602 public function vc_fixes() {
603 if ( reduxLegacy_helpers::isFieldInUse( $this, 'ace_editor' ) ) {
604 wp_dequeue_script( 'wpb_ace' );
605 wp_deregister_script( 'wpb_ace' );
606 }
607 }
608
609 public function network_admin_bar( $wp_admin_bar ) {
610
611 $args = array(
612 'id' => $this->args['opt_name'] . '_network_admin',
613 'title' => $this->args['menu_title'],
614 'parent' => 'network-admin',
615 'href' => network_admin_url( 'settings.php' ) . '?page=' . $this->args['page_slug'],
616 'meta' => array( 'class' => 'redux-network-admin' ),
617 );
618 $wp_admin_bar->add_node( $args );
619 }
620
621 public function save_network_page() {
622
623 $data = $this->_validate_options( $_POST[ $this->args['opt_name'] ] );
624
625 if ( ! empty( $data ) ) {
626 $this->set_options( $data );
627 }
628
629 wp_redirect(
630 add_query_arg(
631 array(
632 'page' => $this->args['page_slug'],
633 'updated' => 'true',
634 ),
635 network_admin_url( 'settings.php' )
636 )
637 );
638 exit();
639 }
640
641 public function _update_check() {
642 // Only one notice per instance please
643 if ( ! isset( $GLOBALS['redux_update_check'] ) ) {
644 ReduxLegacy_Functions::updateCheck( $this, self::$_version );
645 $GLOBALS['redux_update_check'] = 1;
646 }
647 }
648
649 public function _admin_notices() {
650 ReduxLegacy_Admin_Notices::adminNotices( $this, $this->admin_notices );
651 }
652
653 public function _dismiss_admin_notice() {
654 ReduxLegacy_Admin_Notices::dismissAdminNotice();
655 }
656
657 /**
658 * Load the plugin text domain for translation.
659 *
660 * @since 3.0.5
661 */
662 private function _internationalization() {
663
664 /**
665 * Locale for text domain
666 * filter 'redux/textdomain/{opt_name}'
667 *
668 * @param string The locale of the blog or from the 'locale' hook
669 * @param string 'redux-framework' text domain
670 */
671 // $locale = apply_filters( "redux/textdomain/{$this->args['opt_name']}", get_locale(), 'redux-framework' );
672 //
673 // if ( strpos( $locale, '_' ) === false ) {
674 // if ( file_exists( self::$_dir . 'languages/' . strtolower( $locale ) . '_' . strtoupper( $locale ) . '.mo' ) ) {
675 // $locale = strtolower( $locale ) . '_' . strtoupper( $locale );
676 // }
677 // }
678
679 $basename = basename( __FILE__ );
680 $basepath = plugin_basename( __FILE__ );
681 $basepath = str_replace( $basename, '', $basepath );
682
683 $basepath = apply_filters( "redux/textdomain/basepath/{$this->args['opt_name']}", $basepath );
684
685 $loaded = load_plugin_textdomain( 'redux-framework', false, $basepath . 'languages' );
686
687 if ( ! $loaded ) {
688 $loaded = load_muplugin_textdomain( 'redux-framework', $basepath . 'languages' );
689 }
690
691 if ( ! $loaded ) {
692 $loaded = load_theme_textdomain( 'redux-framework', $basepath . 'languages' );
693 }
694
695 if ( ! $loaded ) {
696 $locale = apply_filters( 'plugin_locale', get_locale(), 'redux-framework' );
697 $mofile = __DIR__ . '/languages/redux-framework-' . $locale . '.mo';
698 load_textdomain( 'redux-framework', $mofile );
699 }
700 }
701 // _internationalization()
702
703 /**
704 * @return ReduxFrameworkLegacy
705 */
706 public function get_instance() {
707 // self::$_instance = $this;
708 return self::$instance;
709 }
710
711 // get_instance()
712
713 private function _tracking() {
714 if ( file_exists( __DIR__ . '/inc/tracking.php' ) ) {
715 require_once __DIR__ . '/inc/tracking.php';
716 $tracking = ReduxLegacy_Tracking::get_instance();
717 $tracking->load( $this );
718 }
719 }
720 // _tracking()
721
722 /**
723 * ->_get_default(); This is used to return the default value if default_show is set
724 *
725 * @since 1.0.1
726 * @access public
727 *
728 * @param string $opt_name The option name to return
729 * @param mixed $default (null) The value to return if default not set
730 *
731 * @return mixed $default
732 */
733 public function _get_default( $opt_name, $default = null ) {
734 if ( $this->args['default_show'] == true ) {
735
736 if ( empty( $this->options_defaults ) ) {
737 $this->_default_values(); // fill cache
738 }
739
740 $default = array_key_exists( $opt_name, $this->options_defaults ) ? $this->options_defaults[ $opt_name ] : $default;
741 }
742
743 return $default;
744 }
745 // _get_default()
746
747 /**
748 * ->get(); This is used to return and option value from the options array
749 *
750 * @since 1.0.0
751 * @access public
752 *
753 * @param string $opt_name The option name to return
754 * @param mixed $default (null) The value to return if option not set
755 *
756 * @return mixed
757 */
758 public function get( $opt_name, $default = null ) {
759 return ( ! empty( $this->options[ $opt_name ] ) ) ? $this->options[ $opt_name ] : $this->_get_default( $opt_name, $default );
760 }
761 // get()
762
763 /**
764 * ->set(); This is used to set an arbitrary option in the options array
765 *
766 * @since 1.0.0
767 * @access public
768 *
769 * @param string $opt_name The name of the option being added
770 * @param mixed $value The value of the option being added
771 *
772 * @return void
773 */
774 public function set( $opt_name = '', $value = '' ) {
775 if ( $opt_name != '' ) {
776 $this->options[ $opt_name ] = $value;
777 $this->set_options( $this->options );
778 }
779 }
780 // set()
781
782 /**
783 * Set a global variable by the global_variable argument
784 *
785 * @since 3.1.5
786 * @return bool (global was set)
787 */
788 private function set_global_variable() {
789 if ( $this->args['global_variable'] ) {
790 $option_global = $this->args['global_variable'];
791 /**
792 * filter 'redux/options/{opt_name}/global_variable'
793 *
794 * @param array $value option value to set global_variable with
795 */
796 $GLOBALS[ $this->args['global_variable'] ] = apply_filters( "redux/options/{$this->args['opt_name']}/global_variable", $this->options );
797 if ( isset( $this->transients['last_save'] ) ) {
798 // Deprecated
799 $GLOBALS[ $this->args['global_variable'] ]['REDUX_last_saved'] = $this->transients['last_save'];
800 // Last save key
801 $GLOBALS[ $this->args['global_variable'] ]['REDUX_LAST_SAVE'] = $this->transients['last_save'];
802 }
803 if ( isset( $this->transients['last_compiler'] ) ) {
804 // Deprecated
805 $GLOBALS[ $this->args['global_variable'] ]['REDUX_COMPILER'] = $this->transients['last_compiler'];
806 // Last compiler hook key
807 $GLOBALS[ $this->args['global_variable'] ]['REDUX_LAST_COMPILER'] = $this->transients['last_compiler'];
808 }
809
810 return true;
811 }
812
813 return false;
814 }
815 // set_global_variable()
816
817 /**
818 * ->set_options(); This is used to set an arbitrary option in the options array
819 *
820 * @since ReduxFrameworkLegacy 3.0.0
821 *
822 * @param mixed $value the value of the option being added
823 */
824 public function set_options( $value = '' ) {
825
826 $this->transients['last_save'] = time();
827
828 if ( ! empty( $value ) ) {
829
830 $this->options = $value;
831
832 if ( $this->args['database'] === 'transient' ) {
833 set_transient( $this->args['opt_name'] . '-transient', $value, $this->args['transient_time'] );
834 } elseif ( $this->args['database'] === 'theme_mods' ) {
835 set_theme_mod( $this->args['opt_name'] . '-mods', $value );
836 } elseif ( $this->args['database'] === 'theme_mods_expanded' ) {
837 foreach ( $value as $k => $v ) {
838 set_theme_mod( $k, $v );
839 }
840 } elseif ( $this->args['database'] === 'network' ) {
841 // Strip those slashes!
842 // $value = json_decode( stripslashes( json_encode( $value ) ), true );
843 update_site_option( $this->args['opt_name'], $value );
844 } else {
845 update_option( $this->args['opt_name'], $value );
846 }
847
848 // Store the changed values in the transient
849 if ( $value != $this->options ) {
850 foreach ( $value as $k => $v ) {
851 if ( ! isset( $this->options[ $k ] ) ) {
852 $this->options[ $k ] = '';
853 } elseif ( $v == $this->options[ $k ] ) {
854 unset( $this->options[ $k ] );
855 }
856 }
857 $this->transients['changed_values'] = $this->options;
858 }
859
860 $this->options = $value;
861
862 // Set a global variable by the global_variable argument.
863 $this->set_global_variable();
864
865 // Saving the transient values
866 $this->set_transients();
867
868 // do_action( "redux-saved-{$this->args['opt_name']}", $value ); // REMOVE
869 // do_action( "redux/options/{$this->args['opt_name']}/saved", $value, $this->transients['changed_values'] );
870 }
871 }
872 // set_options()
873
874 /**
875 * ->get_options(); This is used to get options from the database
876 *
877 * @since ReduxFrameworkLegacy 3.0.0
878 */
879 public function get_options() {
880 $defaults = false;
881
882 if ( ! empty( $this->defaults ) ) {
883 $defaults = $this->defaults;
884 }
885
886 if ( $this->args['database'] === 'transient' ) {
887 $result = get_transient( $this->args['opt_name'] . '-transient' );
888 } elseif ( $this->args['database'] === 'theme_mods' ) {
889 $result = get_theme_mod( $this->args['opt_name'] . '-mods' );
890 } elseif ( $this->args['database'] === 'theme_mods_expanded' ) {
891 $result = get_theme_mods();
892 } elseif ( $this->args['database'] === 'network' ) {
893 $result = get_site_option( $this->args['opt_name'], array() );
894 // $result = json_decode( stripslashes( json_encode( $result ) ), true );
895 } else {
896 $result = get_option( $this->args['opt_name'], array() );
897 }
898
899 if ( empty( $result ) && ! empty( $defaults ) ) {
900 $results = $defaults;
901 $this->set_options( $results );
902 } else {
903 $this->options = $result;
904 }
905
906 /**
907 * action 'redux/options/{opt_name}/options'
908 *
909 * @param mixed $value option values
910 */
911 $this->options = apply_filters( "redux/options/{$this->args['opt_name']}/options", $this->options );
912
913 // Get transient values
914 $this->get_transients();
915
916 // Set a global variable by the global_variable argument.
917 $this->set_global_variable();
918 }
919 // get_options()
920
921 /**
922 * ->get_wordpress_date() - Get WordPress specific data from the DB and return in a usable array
923 *
924 * @since ReduxFrameworkLegacy 3.0.0
925 */
926 public function get_wordpress_data( $type = false, $args = array() ) {
927 $data = '';
928 // return $data;
929 /**
930 * filter 'redux/options/{opt_name}/wordpress_data/{type}/'
931 *
932 * @deprecated
933 *
934 * @param string $data
935 */
936 $data = apply_filters( "redux/options/{$this->args['opt_name']}/wordpress_data/$type/", $data ); // REMOVE LATER
937
938 /**
939 * filter 'redux/options/{opt_name}/data/{type}'
940 *
941 * @param string $data
942 */
943 $data = apply_filters( "redux/options/{$this->args['opt_name']}/data/$type", $data );
944
945 $argsKey = md5( serialize( $args ) );
946
947 if ( empty( $data ) && isset( $this->wp_data[ $type . $argsKey ] ) ) {
948 $data = $this->wp_data[ $type . $argsKey ];
949 }
950
951 if ( empty( $data ) && ! empty( $type ) ) {
952
953 /**
954 * Use data from WordPress to populate options array
955 * */
956 if ( ! empty( $type ) && empty( $data ) ) {
957 if ( empty( $args ) ) {
958 $args = array();
959 }
960
961 $data = array();
962 $args = wp_parse_args( $args, array() );
963
964 if ( $type == 'categories' || $type == 'category' ) {
965 $cats = get_categories( $args );
966 if ( ! empty( $cats ) ) {
967 foreach ( $cats as $cat ) {
968 $data[ $cat->term_id ] = $cat->name;
969 }
970 // foreach
971 } // If
972 } elseif ( $type == 'menus' || $type == 'menu' ) {
973 $menus = wp_get_nav_menus( $args );
974 if ( ! empty( $menus ) ) {
975 foreach ( $menus as $item ) {
976 $data[ $item->term_id ] = $item->name;
977 }
978 // foreach
979 }
980 // if
981 } elseif ( $type == 'pages' || $type == 'page' ) {
982 if ( ! isset( $args['posts_per_page'] ) ) {
983 $args['posts_per_page'] = 20;
984 }
985 $pages = get_pages( $args );
986 if ( ! empty( $pages ) ) {
987 foreach ( $pages as $page ) {
988 $data[ $page->ID ] = $page->post_title;
989 }
990 // foreach
991 }
992 // if
993 } elseif ( $type == 'terms' || $type == 'term' ) {
994 $taxonomies = $args['taxonomies'];
995 unset( $args['taxonomies'] );
996 $terms = get_terms( $taxonomies, $args ); // this will get nothing
997 if ( ! empty( $terms ) && ! is_a( $terms, 'WP_Error' ) ) {
998 foreach ( $terms as $term ) {
999 $data[ $term->term_id ] = $term->name;
1000 }
1001 // foreach
1002 } // If
1003 } elseif ( $type == 'taxonomy' || $type == 'taxonomies' ) {
1004 $taxonomies = get_taxonomies( $args );
1005 if ( ! empty( $taxonomies ) ) {
1006 foreach ( $taxonomies as $key => $taxonomy ) {
1007 $data[ $key ] = $taxonomy;
1008 }
1009 // foreach
1010 } // If
1011 } elseif ( $type == 'posts' || $type == 'post' ) {
1012 $posts = get_posts( $args );
1013 if ( ! empty( $posts ) ) {
1014 foreach ( $posts as $post ) {
1015 $data[ $post->ID ] = $post->post_title;
1016 }
1017 // foreach
1018 }
1019 // if
1020 } elseif ( $type == 'post_type' || $type == 'post_types' ) {
1021 global $wp_post_types;
1022
1023 $defaults = array(
1024 'public' => true,
1025 'exclude_from_search' => false,
1026 );
1027 $args = wp_parse_args( $args, $defaults );
1028 $output = 'names';
1029 $operator = 'and';
1030 $post_types = get_post_types( $args, $output, $operator );
1031
1032 ksort( $post_types );
1033
1034 foreach ( $post_types as $name => $title ) {
1035 if ( isset( $wp_post_types[ $name ]->labels->menu_name ) ) {
1036 $data[ $name ] = $wp_post_types[ $name ]->labels->menu_name;
1037 } else {
1038 $data[ $name ] = ucfirst( $name );
1039 }
1040 }
1041 } elseif ( $type == 'tags' || $type == 'tag' ) { // NOT WORKING!
1042 $tags = get_tags( $args );
1043 if ( ! empty( $tags ) ) {
1044 foreach ( $tags as $tag ) {
1045 $data[ $tag->term_id ] = $tag->name;
1046 }
1047 // foreach
1048 }
1049 // if
1050 } elseif ( $type == 'menu_location' || $type == 'menu_locations' ) {
1051 global $_wp_registered_nav_menus;
1052
1053 foreach ( $_wp_registered_nav_menus as $k => $v ) {
1054 $data[ $k ] = $v;
1055 }
1056 } elseif ( $type == 'image_size' || $type == 'image_sizes' ) {
1057 global $_wp_additional_image_sizes;
1058
1059 foreach ( $_wp_additional_image_sizes as $size_name => $size_attrs ) {
1060 $data[ $size_name ] = $size_name . ' - ' . $size_attrs['width'] . ' x ' . $size_attrs['height'];
1061 }
1062 } elseif ( $type == 'elusive-icons' || $type == 'elusive-icon' || $type == 'elusive' ||
1063 $type == 'font-icon' || $type == 'font-icons' || $type == 'icons'
1064 ) {
1065
1066 /**
1067 * filter 'redux-font-icons'
1068 *
1069 * @deprecated
1070 *
1071 * @param array $font_icons array of elusive icon classes
1072 */
1073 $font_icons = apply_filters( 'redux-font-icons', array() ); // REMOVE LATER
1074
1075 /**
1076 * filter 'redux/font-icons'
1077 *
1078 * @deprecated
1079 *
1080 * @param array $font_icons array of elusive icon classes
1081 */
1082 $font_icons = apply_filters( 'redux/font-icons', $font_icons );
1083
1084 /**
1085 * filter 'redux/{opt_name}/field/font/icons'
1086 *
1087 * @deprecated
1088 *
1089 * @param array $font_icons array of elusive icon classes
1090 */
1091 $font_icons = apply_filters( "redux/{$this->args['opt_name']}/field/font/icons", $font_icons );
1092
1093 foreach ( $font_icons as $k ) {
1094 $data[ $k ] = $k;
1095 }
1096 } elseif ( $type == 'roles' ) {
1097 /** @global WP_Roles $wp_roles */
1098 global $wp_roles;
1099
1100 $data = $wp_roles->get_names();
1101 } elseif ( $type == 'sidebars' || $type == 'sidebar' ) {
1102 /** @global array $wp_registered_sidebars */
1103 global $wp_registered_sidebars;
1104
1105 foreach ( $wp_registered_sidebars as $key => $value ) {
1106 $data[ $key ] = $value['name'];
1107 }
1108 } elseif ( $type == 'capabilities' ) {
1109 /** @global WP_Roles $wp_roles */
1110 global $wp_roles;
1111
1112 foreach ( $wp_roles->roles as $role ) {
1113 foreach ( $role['capabilities'] as $key => $cap ) {
1114 $data[ $key ] = ucwords( str_replace( '_', ' ', $key ) );
1115 }
1116 }
1117 } elseif ( $type == 'callback' ) {
1118 if ( ! is_array( $args ) ) {
1119 $args = array( $args );
1120 }
1121 $data = call_user_func( $args[0] );
1122 } elseif ( $type == 'users' || $type == 'users' ) {
1123 $users = get_users( $args );
1124 if ( ! empty( $users ) ) {
1125 foreach ( $users as $user ) {
1126 $data[ $user->ID ] = $user->display_name;
1127 }
1128 // foreach
1129 }
1130 // if
1131 }
1132 // if
1133 }
1134 // if
1135
1136 $this->wp_data[ $type . $argsKey ] = $data;
1137 }
1138
1139 // if
1140
1141 return $data;
1142 }
1143 // get_wordpress_data()
1144
1145 /**
1146 * ->show(); This is used to echo and option value from the options array
1147 *
1148 * @since 1.0.0
1149 * @access public
1150 *
1151 * @param string $opt_name The name of the option being shown
1152 * @param mixed $default The value to show if $opt_name isn't set
1153 *
1154 * @return void
1155 */
1156 public function show( $opt_name, $default = '' ) {
1157 $option = $this->get( $opt_name );
1158 if ( ! is_array( $option ) && $option != '' ) {
1159 echo $option;
1160 } elseif ( $default != '' ) {
1161 echo $this->_get_default( $opt_name, $default );
1162 }
1163 }
1164 // show()
1165
1166 /**
1167 * Get the default value for an option
1168 *
1169 * @since 3.3.6
1170 * @access public
1171 *
1172 * @param string $key The option's ID
1173 * @param string $array_key The key of the default's array
1174 *
1175 * @return mixed
1176 */
1177 public function get_default_value( $key, $array_key = false ) {
1178 if ( empty( $this->options_defaults ) ) {
1179 $this->options_defaults = $this->_default_values();
1180 }
1181
1182 $defaults = $this->options_defaults;
1183 $value = '';
1184
1185 if ( isset( $defaults[ $key ] ) ) {
1186 if ( $array_key !== false && isset( $defaults[ $key ][ $array_key ] ) ) {
1187 $value = $defaults[ $key ][ $array_key ];
1188 } else {
1189 $value = $defaults[ $key ];
1190 }
1191 }
1192
1193 return $value;
1194 }
1195
1196 public function field_default_values( $field ) {
1197 // Detect what field types are being used
1198 if ( ! isset( $this->fields[ $field['type'] ][ $field['id'] ] ) ) {
1199 $this->fields[ $field['type'] ][ $field['id'] ] = 1;
1200 } else {
1201 $this->fields[ $field['type'] ] = array( $field['id'] => 1 );
1202 }
1203 if ( isset( $field['default'] ) ) {
1204 $this->options_defaults[ $field['id'] ] = apply_filters( "redux/{$this->args['opt_name']}/field/{$field['type']}/defaults", $field['default'], $field );
1205 } elseif ( ( $field['type'] != 'ace_editor' ) ) {
1206 // Sorter data filter
1207
1208 if ( isset( $field['data'] ) && ! empty( $field['data'] ) ) {
1209 if ( ! isset( $field['args'] ) ) {
1210 $field['args'] = array();
1211 }
1212 if ( is_array( $field['data'] ) && ! empty( $field['data'] ) ) {
1213 foreach ( $field['data'] as $key => $data ) {
1214 if ( ! empty( $data ) ) {
1215 if ( ! isset( $field['args'][ $key ] ) ) {
1216 $field['args'][ $key ] = array();
1217 }
1218 $field['options'][ $key ] = $this->get_wordpress_data( $data, $field['args'][ $key ] );
1219 }
1220 }
1221 } else {
1222 $field['options'] = $this->get_wordpress_data( $field['data'], $field['args'] );
1223 }
1224 }
1225
1226 if ( $field['type'] == 'sorter' && isset( $field['data'] ) && ! empty( $field['data'] ) && is_array( $field['data'] ) ) {
1227 if ( ! isset( $field['args'] ) ) {
1228 $field['args'] = array();
1229 }
1230 foreach ( $field['data'] as $key => $data ) {
1231 if ( ! isset( $field['args'][ $key ] ) ) {
1232 $field['args'][ $key ] = array();
1233 }
1234 $field['options'][ $key ] = $this->get_wordpress_data( $data, $field['args'][ $key ] );
1235 }
1236 }
1237
1238 if ( isset( $field['options'] ) ) {
1239 if ( $field['type'] == 'sortable' ) {
1240 $this->options_defaults[ $field['id'] ] = array();
1241 } elseif ( $field['type'] == 'image_select' ) {
1242 $this->options_defaults[ $field['id'] ] = '';
1243 } elseif ( $field['type'] == 'select' ) {
1244 $this->options_defaults[ $field['id'] ] = '';
1245 } else {
1246 $this->options_defaults[ $field['id'] ] = $field['options'];
1247 }
1248 }
1249 }
1250 }
1251
1252 /**
1253 * Get default options into an array suitable for the settings API
1254 *
1255 * @since 1.0.0
1256 * @access public
1257 * @return array $this->options_defaults
1258 */
1259 public function _default_values() {
1260 if ( ! is_null( $this->sections ) && is_null( $this->options_defaults ) ) {
1261
1262 // fill the cache
1263 foreach ( $this->sections as $sk => $section ) {
1264 if ( ! isset( $section['id'] ) ) {
1265 if ( ! is_numeric( $sk ) || ! isset( $section['title'] ) ) {
1266 $section['id'] = $sk;
1267 } else {
1268 $section['id'] = sanitize_title( $section['title'], $sk );
1269 }
1270 $this->sections[ $sk ] = $section;
1271 }
1272 if ( isset( $section['fields'] ) ) {
1273 foreach ( $section['fields'] as $k => $field ) {
1274 if ( empty( $field['id'] ) && empty( $field['type'] ) ) {
1275 continue;
1276 }
1277
1278 if ( in_array( $field['type'], array( 'ace_editor' ) ) && isset( $field['options'] ) ) {
1279 $this->sections[ $sk ]['fields'][ $k ]['args'] = $field['options'];
1280 unset( $this->sections[ $sk ]['fields'][ $k ]['options'] );
1281 }
1282
1283 if ( $field['type'] == 'section' && isset( $field['indent'] ) && $field['indent'] == 'true' ) {
1284 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1285 $field['class'] .= ' redux-section-indent-start';
1286 $this->sections[ $sk ]['fields'][ $k ] = $field;
1287 }
1288 $this->field_default_values( $field );
1289 }
1290 }
1291 }
1292 }
1293
1294 /**
1295 * filter 'redux/options/{opt_name}/defaults'
1296 *
1297 * @param array $defaults option default values
1298 */
1299 $this->transients['changed_values'] = isset( $this->transients['changed_values'] ) ? $this->transients['changed_values'] : array();
1300 $this->options_defaults = apply_filters( "redux/options/{$this->args['opt_name']}/defaults", $this->options_defaults, $this->transients['changed_values'] );
1301
1302 return $this->options_defaults;
1303 }
1304
1305 /**
1306 * Set default options on admin_init if option doesn't exist
1307 *
1308 * @since 1.0.0
1309 * @access public
1310 * @return void
1311 */
1312 private function _default_cleanup() {
1313
1314 // Fix the global variable name
1315 if ( $this->args['global_variable'] == '' && $this->args['global_variable'] !== false ) {
1316 $this->args['global_variable'] = str_replace( '-', '_', $this->args['opt_name'] );
1317 }
1318
1319 // Force dev_mode on WP_DEBUG = true and if it's a local server
1320 if ( ReduxLegacy_Helpers::isLocalHost() || ( ReduxLegacy_Helpers::isWpDebug() ) ) {
1321 if ( $this->args['dev_mode'] != true ) {
1322 $this->args['update_notice'] = false;
1323 }
1324 $this->dev_mode_forced = true;
1325 $this->args['dev_mode'] = true;
1326 // if ( isset( $this->args['forced_dev_mode_off'] ) && $this->args['forced_dev_mode_off'] == true ) {
1327 // $this->dev_mode_forced = false;
1328 // $this->args['dev_mode'] = false;
1329 // }
1330 }
1331
1332 if ( isset( $this->args['customizer_only'] ) && $this->args['customizer_only'] == true ) {
1333 $this->args['menu_type'] = 'hidden';
1334 $this->args['customizer'] = true;
1335 $this->args['admin_bar'] = false;
1336 $this->args['allow_sub_menu'] = false;
1337 }
1338
1339 // Check if the Airplane Mode plugin is installed
1340 if ( class_exists( 'Airplane_Mode_Core' ) ) {
1341 $airplane = Airplane_Mode_Core::getInstance();
1342 if ( method_exists( $airplane, 'enabled' ) ) {
1343 if ( $airplane->enabled() ) {
1344 $this->args['use_cdn'] = false;
1345 }
1346 } elseif ( $airplane->check_status() == 'on' ) {
1347 $this->args['use_cdn'] = false;
1348 }
1349 }
1350 }
1351
1352 /**
1353 * Class Add Sub Menu Function, creates options submenu in WordPress admin area.
1354 *
1355 * @since 3.1.9
1356 * @access private
1357 * @return void
1358 */
1359 private function add_submenu( $page_parent, $page_title, $menu_title, $page_permissions, $page_slug ) {
1360 global $submenu;
1361
1362 // Just in case. One never knows.
1363 $page_parent = strtolower( $page_parent );
1364
1365 $test = array(
1366 'index.php' => 'dashboard',
1367 'edit.php' => 'posts',
1368 'upload.php' => 'media',
1369 'link-manager.php' => 'links',
1370 'edit.php?post_type=page' => 'pages',
1371 'edit-comments.php' => 'comments',
1372 'themes.php' => 'theme',
1373 'plugins.php' => 'plugins',
1374 'users.php' => 'users',
1375 'tools.php' => 'management',
1376 'options-general.php' => 'options',
1377 );
1378
1379 if ( isset( $test[ $page_parent ] ) ) {
1380 $function = 'add_' . $test[ $page_parent ] . '_page';
1381 $this->page = $function(
1382 $page_title,
1383 $menu_title,
1384 $page_permissions,
1385 $page_slug,
1386 array( $this, 'generate_panel' )
1387 );
1388 } else {
1389 // Network settings and Post type menus. These do not have
1390 // wrappers and need to be appened to using add_submenu_page.
1391 // Okay, since we've left the post type menu appending
1392 // as default, we need to validate it, so anything that
1393 // isn't post_type=<post_type> doesn't get through and mess
1394 // things up.
1395 $addMenu = false;
1396 if ( 'settings.php' != $page_parent ) {
1397 // Establish the needle
1398 $needle = '?post_type=';
1399
1400 // Check if it exists in the page_parent (how I miss instr)
1401 $needlePos = strrpos( $page_parent, $needle );
1402
1403 // It's there, so...
1404 if ( $needlePos > 0 ) {
1405
1406 // Get the post type.
1407 $postType = substr( $page_parent, $needlePos + strlen( $needle ) );
1408
1409 // Ensure it exists.
1410 if ( post_type_exists( $postType ) ) {
1411 // Set flag to add the menu page
1412 $addMenu = true;
1413 }
1414 // custom menu
1415 } elseif ( isset( $submenu[ $this->args['page_parent'] ] ) ) {
1416 $addMenu = true;
1417 } else {
1418 global $menu;
1419
1420 foreach ( $menu as $menupriority => $menuitem ) {
1421 $needle_menu_slug = isset( $menuitem ) ? $menuitem[2] : false;
1422 if ( $needle_menu_slug != false ) {
1423
1424 // check if the current needle menu equals page_parent
1425 if ( strcasecmp( $needle_menu_slug, $page_parent ) == 0 ) {
1426
1427 // found an empty parent menu
1428 $addMenu = true;
1429 }
1430 }
1431 }
1432 }
1433 } else {
1434 // The page_parent was settings.php, so set menu add
1435 // flag to true.
1436 $addMenu = true;
1437 }
1438 // Add the submenu if it's permitted.
1439 if ( true == $addMenu ) {
1440 // ONLY for non-wp.org themes OR plugins. Theme-Check alert shown if used and IS theme.
1441 $this->page = call_user_func(
1442 'add_submenu_page',
1443 $page_parent,
1444 $page_title,
1445 $menu_title,
1446 $page_permissions,
1447 $page_slug,
1448 array(
1449 &$this,
1450 'generate_panel',
1451 )
1452 );
1453 }
1454 }
1455 }
1456
1457 /**
1458 * Class Options Page Function, creates main options page.
1459 *
1460 * @since 1.0.0
1461 * @access public
1462 * @return void
1463 */
1464 public function _options_page() {
1465
1466 if ( $this->args['menu_type'] == 'hidden' ) {
1467
1468 // No menu to add!
1469 } elseif ( $this->args['menu_type'] == 'submenu' ) {
1470 $this->add_submenu(
1471 $this->args['page_parent'],
1472 $this->args['page_title'],
1473 $this->args['menu_title'],
1474 $this->args['page_permissions'],
1475 $this->args['page_slug']
1476 );
1477 } else {
1478 // Theme-Check notice is displayed for WP.org theme devs, informing them to NOT use this.
1479 $this->page = call_user_func(
1480 'add_menu_page',
1481 $this->args['page_title'],
1482 $this->args['menu_title'],
1483 $this->args['page_permissions'],
1484 $this->args['page_slug'],
1485 array(
1486 &$this,
1487 'generate_panel',
1488 ),
1489 $this->args['menu_icon'],
1490 $this->args['page_priority']
1491 );
1492
1493 if ( true === $this->args['allow_sub_menu'] ) {
1494 foreach ( $this->sections as $k => $section ) {
1495 $canBeSubSection = ( $k > 0 && ( ! isset( $this->sections[ ( $k ) ]['type'] ) || $this->sections[ ( $k ) ]['type'] != 'divide' ) ) ? true : false;
1496 if ( ! isset( $section['title'] ) || ( $canBeSubSection && ( isset( $section['subsection'] ) && $section['subsection'] == true ) ) ) {
1497 continue;
1498 }
1499 if ( isset( $section['submenu'] ) && $section['submenu'] == false ) {
1500 continue;
1501 }
1502 if ( isset( $section['customizer_only'] ) && $section['customizer_only'] == true ) {
1503 continue;
1504 }
1505 if ( isset( $section['hidden'] ) && $section['hidden'] == true ) {
1506 continue;
1507 }
1508 if ( isset( $section['permissions'] ) && ! self::current_user_can( $section['permissions'] ) ) {
1509 continue;
1510 }
1511 // ONLY for non-wp.org themes OR plugins. Theme-Check alert shown if used and IS theme.
1512 call_user_func(
1513 'add_submenu_page',
1514 $this->args['page_slug'],
1515 $section['title'],
1516 $section['title'],
1517 $this->args['page_permissions'],
1518 $this->args['page_slug'] . '&tab=' . $k,
1519 // create_function( '$a', "return null;" )
1520 '__return_null'
1521 );
1522 }
1523 // Remove parent submenu item instead of adding null item.
1524 remove_submenu_page( $this->args['page_slug'], $this->args['page_slug'] );
1525 }
1526 }
1527
1528 add_action( "load-{$this->page}", array( &$this, '_load_page' ) );
1529 }
1530 // _options_page()
1531
1532 /**
1533 * Add admin bar menu
1534 *
1535 * @since 3.1.5.16
1536 * @access public
1537 * @global $menu , $submenu, $wp_admin_bar
1538 * @return void
1539 */
1540 public function _admin_bar_menu() {
1541 global $menu, $submenu, $wp_admin_bar;
1542
1543 if ( ! is_super_admin() || ! is_admin_bar_showing() || ! $this->args['admin_bar'] || $this->args['menu_type'] == 'hidden' ) {
1544 return;
1545 }
1546
1547 if ( $menu ) {
1548 foreach ( $menu as $menu_item ) {
1549 if ( isset( $menu_item[2] ) && $menu_item[2] === $this->args['page_slug'] ) {
1550
1551 // Fetch the title
1552 $title = empty( $this->args['admin_bar_icon'] ) ? $menu_item[0] : '<span class="ab-icon ' . $this->args['admin_bar_icon'] . '"></span>' . $menu_item[0];
1553
1554 $nodeargs = array(
1555 'id' => $menu_item[2],
1556 'title' => $title,
1557 'href' => admin_url( 'admin.php?page=' . $menu_item[2] ),
1558 'meta' => array(),
1559 );
1560 $wp_admin_bar->add_node( $nodeargs );
1561
1562 break;
1563 }
1564 }
1565
1566 if ( isset( $submenu[ $this->args['page_slug'] ] ) && is_array( $submenu[ $this->args['page_slug'] ] ) ) {
1567 foreach ( $submenu[ $this->args['page_slug'] ] as $index => $redux_options_submenu ) {
1568 $subnodeargs = array(
1569 'id' => $this->args['page_slug'] . '_' . $index,
1570 'title' => $redux_options_submenu[0],
1571 'parent' => $this->args['page_slug'],
1572 'href' => admin_url( 'admin.php?page=' . $redux_options_submenu[2] ),
1573 );
1574
1575 $wp_admin_bar->add_node( $subnodeargs );
1576 }
1577 }
1578
1579 // Let's deal with external links
1580 if ( isset( $this->args['admin_bar_links'] ) ) {
1581
1582 if ( ! $this->args['dev_mode'] && $this->omit_admin_items ) {
1583 return;
1584 }
1585
1586 // Group for Main Root Menu (External Group)
1587 $wp_admin_bar->add_node(
1588 array(
1589 'id' => $this->args['page_slug'] . '-external',
1590 'parent' => $this->args['page_slug'],
1591 'group' => true,
1592 'meta' => array( 'class' => 'ab-sub-secondary' ),
1593 )
1594 );
1595
1596 // Add Child Menus to External Group Menu
1597 foreach ( $this->args['admin_bar_links'] as $link ) {
1598 if ( ! isset( $link['id'] ) ) {
1599 $link['id'] = $this->args['page_slug'] . '-sub-' . sanitize_html_class( $link['title'] );
1600 }
1601 $externalnodeargs = array(
1602 'id' => $link['id'],
1603 'title' => $link['title'],
1604 'parent' => $this->args['page_slug'] . '-external',
1605 'href' => $link['href'],
1606 'meta' => array( 'target' => '_blank' ),
1607 );
1608
1609 $wp_admin_bar->add_node( $externalnodeargs );
1610 }
1611 }
1612 } else {
1613 // Fetch the title
1614 $title = empty( $this->args['admin_bar_icon'] ) ? $this->args['menu_title'] : '<span class="ab-icon ' . $this->args['admin_bar_icon'] . '"></span>' . $this->args['menu_title'];
1615
1616 $nodeargs = array(
1617 'id' => $this->args['page_slug'],
1618 'title' => $title,
1619 'href' => admin_url( 'admin.php?page=' . $this->args['page_slug'] ),
1620 'meta' => array(),
1621 );
1622
1623 $wp_admin_bar->add_node( $nodeargs );
1624 }
1625 }
1626 // _admin_bar_menu()
1627
1628 /**
1629 * Output dynamic CSS at bottom of HEAD
1630 *
1631 * @since 3.2.8
1632 * @access public
1633 * @return void
1634 */
1635 public function _output_css() {
1636 if ( $this->args['output'] == false && $this->args['compiler'] == false ) {
1637 return;
1638 }
1639
1640 if ( isset( $this->no_output ) ) {
1641 return;
1642 }
1643
1644 if ( ! empty( $this->outputCSS ) && ( $this->args['output_tag'] == true || ( isset( $_POST['customized'] ) ) ) ) {
1645 echo '<style type="text/css" title="dynamic-css" class="options-output">' . $this->outputCSS . '</style>';
1646 }
1647 }
1648
1649 /**
1650 * Enqueue CSS and Google fonts for front end
1651 *
1652 * @since 1.0.0
1653 * @access public
1654 * @return void
1655 */
1656 public function _enqueue_output() {
1657 if ( $this->args['output'] == false && $this->args['compiler'] == false ) {
1658 return;
1659 }
1660
1661 /** @noinspection PhpUnusedLocalVariableInspection */
1662 foreach ( $this->sections as $k => $section ) {
1663 if ( isset( $section['type'] ) && ( $section['type'] == 'divide' ) ) {
1664 continue;
1665 }
1666
1667 if ( isset( $section['fields'] ) ) {
1668 /** @noinspection PhpUnusedLocalVariableInspection */
1669 foreach ( $section['fields'] as $fieldk => $field ) {
1670 if ( isset( $field['type'] ) && $field['type'] != 'callback' ) {
1671 $field_class = "ReduxFrameworkLegacy_{$field['type']}";
1672 if ( ! class_exists( $field_class ) ) {
1673
1674 if ( ! isset( $field['compiler'] ) ) {
1675 $field['compiler'] = '';
1676 }
1677
1678 /**
1679 * Field class file
1680 * filter 'redux/{opt_name}/field/class/{field.type}
1681 *
1682 * @param string field class file
1683 * @param array $field field config data
1684 */
1685 $class_file = apply_filters( "redux/{$this->args['opt_name']}/field/class/{$field['type']}", self::$_dir . "inc/fields/{$field['type']}/field_{$field['type']}.php", $field );
1686
1687 if ( $class_file && file_exists( $class_file ) && ! class_exists( $field_class ) ) {
1688 /** @noinspection PhpIncludeInspection */
1689 require_once $class_file;
1690 }
1691 }
1692
1693 if ( ! empty( $this->options[ $field['id'] ] ) && class_exists( $field_class ) && method_exists( $field_class, 'output' ) && $this->_can_output_css( $field ) ) {
1694 $field = apply_filters( "redux/field/{$this->args['opt_name']}/output_css", $field );
1695
1696 if ( ! empty( $field['output'] ) && ! is_array( $field['output'] ) ) {
1697 $field['output'] = array( $field['output'] );
1698 }
1699
1700 $value = isset( $this->options[ $field['id'] ] ) ? $this->options[ $field['id'] ] : '';
1701 $enqueue = new $field_class( $field, $value, $this );
1702
1703 if ( ( ( isset( $field['output'] ) && ! empty( $field['output'] ) ) || ( isset( $field['compiler'] ) && ! empty( $field['compiler'] ) ) || $field['type'] == 'typography' || $field['type'] == 'icon_select' ) ) {
1704 $enqueue->output();
1705 }
1706 }
1707 }
1708 }
1709 }
1710 }
1711
1712 // For use like in the customizer. Stops the output, but passes the CSS in the variable for the compiler
1713 if ( isset( $this->no_output ) ) {
1714 return;
1715 }
1716
1717 if ( ! empty( $this->typography ) && ! empty( $this->typography ) && filter_var( $this->args['output'], FILTER_VALIDATE_BOOLEAN ) ) {
1718 $version = ! empty( $this->transients['last_save'] ) ? $this->transients['last_save'] : '';
1719 $typography = new ReduxFrameworkLegacy_typography( null, null, $this );
1720
1721 if ( $this->args['async_typography'] && ! empty( $this->typography ) ) {
1722 $families = array();
1723 foreach ( $this->typography as $key => $value ) {
1724 $families[] = $key;
1725 }
1726 ?>
1727 <script>
1728 /* You can add more configuration options to webfontloader by previously defining the WebFontConfig with your options */
1729 if ( typeof WebFontConfig === "undefined" ) {
1730 WebFontConfig = new Object();
1731 }
1732 WebFontConfig['google'] = {families: [<?php echo $typography->makeGoogleWebfontString( $this->typography ); ?>]};
1733
1734 (function() {
1735 var wf = document.createElement( 'script' );
1736 wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1.5.3/webfont.js';
1737 wf.type = 'text/javascript';
1738 wf.async = 'true';
1739 var s = document.getElementsByTagName( 'script' )[0];
1740 s.parentNode.insertBefore( wf, s );
1741 })();
1742 </script>
1743 <?php
1744 } elseif ( ! $this->args['disable_google_fonts_link'] ) {
1745 $protocol = ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443 ) ? 'https:' : 'http:';
1746
1747 // echo '<link rel="stylesheet" id="options-google-fonts" title="" href="'.$protocol.$typography->makeGoogleWebfontLink( $this->typography ).'&amp;v='.$version.'" type="text/css" media="all" />';
1748 wp_register_style( 'redux-google-fonts-' . $this->args['opt_name'], $protocol . $typography->makeGoogleWebfontLink( $this->typography ), '', $version );
1749 wp_enqueue_style( 'redux-google-fonts-' . $this->args['opt_name'] );
1750 }
1751 }
1752 }
1753 // _enqueue_output()
1754
1755 /**
1756 * Enqueue CSS/JS for options page
1757 *
1758 * @since 1.0.0
1759 * @access public
1760 * @global $wp_styles
1761 * @return void
1762 */
1763 public function _enqueue() {
1764 require_once 'core/enqueue.php';
1765 $enqueue = new reduxLegacyCoreEnqueue( $this );
1766 $enqueue->init();
1767 }
1768 // _enqueue()
1769
1770 /**
1771 * Show page help
1772 *
1773 * @since 1.0.0
1774 * @access public
1775 * @return void
1776 */
1777 public function _load_page() {
1778
1779 // Do admin head action for this page
1780 add_action( 'admin_head', array( &$this, 'admin_head' ) );
1781
1782 // Do admin footer text hook
1783 add_filter( 'admin_footer_text', array( &$this, 'admin_footer_text' ) );
1784
1785 $screen = get_current_screen();
1786
1787 if ( is_array( $this->args['help_tabs'] ) ) {
1788 foreach ( $this->args['help_tabs'] as $tab ) {
1789 $screen->add_help_tab( $tab );
1790 }
1791 }
1792
1793 // If hint argument is set, display hint tab
1794 if ( true == $this->show_hints ) {
1795 global $current_user;
1796
1797 // Users enable/disable hint choice
1798 $hint_status = get_user_meta( $current_user->ID, 'ignore_hints' ) ? get_user_meta( $current_user->ID, 'ignore_hints', true ) : 'true';
1799
1800 // current page parameters
1801 $curPage = esc_attr( $_GET['page'] );
1802
1803 $curTab = '0';
1804 if ( isset( $_GET['tab'] ) ) {
1805 $curTab = esc_attr( $_GET['tab'] );
1806 }
1807
1808 // Default url values for enabling hints.
1809 $dismiss = 'true';
1810 $s = __( 'Enable', 'redux-framework' );
1811
1812 // Values for disabling hints.
1813 if ( 'true' == $hint_status ) {
1814 $dismiss = 'false';
1815 $s = __( 'Disable', 'redux-framework' );
1816 }
1817
1818 // Make URL
1819 $url = '<a class="redux_hint_status" href="?dismiss=' . $dismiss . '&amp;id=hints&amp;page=' . $curPage . '&amp;tab=' . $curTab . '">' . $s . ' hints</a>';
1820
1821 $event = __( 'moving the mouse over', 'redux-framework' );
1822 if ( 'click' == $this->args['hints']['tip_effect']['show']['event'] ) {
1823 $event = __( 'clicking', 'redux-framework' );
1824 }
1825
1826 // Construct message
1827 $msg = sprintf( __( 'Hints are tooltips that popup when %1$d the hint icon, offering addition information about the field in which they appear. They can be %2$d d by using the link below.', 'redux-framework' ), $event, strtolower( $s ) ) . '<br/><br/>' . $url;
1828
1829 // Construct hint tab
1830 $tab = array(
1831 'id' => 'redux-hint-tab',
1832 'title' => __( 'Hints', 'redux-framework' ),
1833 'content' => '<p>' . $msg . '</p>',
1834 );
1835
1836 $screen->add_help_tab( $tab );
1837 }
1838
1839 // Sidebar text
1840 if ( $this->args['help_sidebar'] != '' ) {
1841
1842 // Specify users text from arguments
1843 $screen->set_help_sidebar( $this->args['help_sidebar'] );
1844 } else {
1845
1846 // If sidebar text is empty and hints are active, display text
1847 // about hints.
1848 if ( true == $this->show_hints ) {
1849 $screen->set_help_sidebar( '<p><strong>Redux Framework</strong><br/><br/>Hint Tooltip Preferences</p>' );
1850 }
1851 }
1852
1853 /**
1854 * action 'redux-load-page-{opt_name}'
1855 *
1856 * @deprecated
1857 *
1858 * @param object $screen WP_Screen
1859 */
1860 do_action( "redux-load-page-{$this->args['opt_name']}", $screen ); // REMOVE
1861
1862 /**
1863 * action 'redux/page/{opt_name}/load'
1864 *
1865 * @param object $screen WP_Screen
1866 */
1867 do_action( "redux/page/{$this->args['opt_name']}/load", $screen );
1868 }
1869 // _load_page()
1870
1871 /**
1872 * Do action redux-admin-head for options page
1873 *
1874 * @since 1.0.0
1875 * @access public
1876 * @return void
1877 */
1878 public function admin_head() {
1879 /**
1880 * action 'redux-admin-head-{opt_name}'
1881 *
1882 * @deprecated
1883 *
1884 * @param object $this ReduxFrameworkLegacy
1885 */
1886 do_action( "redux-admin-head-{$this->args['opt_name']}", $this ); // REMOVE
1887
1888 /**
1889 * action 'redux/page/{opt_name}/header'
1890 *
1891 * @param object $this ReduxFrameworkLegacy
1892 */
1893 do_action( "redux/page/{$this->args['opt_name']}/header", $this );
1894 }
1895 // admin_head()
1896
1897 /**
1898 * Return footer text
1899 *
1900 * @since 2.0.0
1901 * @access public
1902 * @return string $this->args['footer_credit']
1903 */
1904 public function admin_footer_text() {
1905 return $this->args['footer_credit'];
1906 }
1907 // admin_footer_text()
1908
1909 /**
1910 * Return default output string for use in panel
1911 *
1912 * @since 3.1.5
1913 * @access public
1914 * @return string default_output
1915 */
1916 private function get_default_output_string( $field ) {
1917 $default_output = '';
1918
1919 if ( ! isset( $field['default'] ) ) {
1920 $field['default'] = '';
1921 }
1922
1923 if ( ! is_array( $field['default'] ) ) {
1924 if ( ! empty( $field['options'][ $field['default'] ] ) ) {
1925 if ( ! empty( $field['options'][ $field['default'] ]['alt'] ) ) {
1926 $default_output .= $field['options'][ $field['default'] ]['alt'] . ', ';
1927 } else {
1928 // TODO: This serialize fix may not be the best solution. Look into it. PHP 5.4 error without serialize
1929 if ( ! is_array( $field['options'][ $field['default'] ] ) ) {
1930 $default_output .= $field['options'][ $field['default'] ] . ', ';
1931 } else {
1932 $default_output .= serialize( $field['options'][ $field['default'] ] ) . ', ';
1933 }
1934 }
1935 } elseif ( ! empty( $field['options'][ $field['default'] ] ) ) {
1936 $default_output .= $field['options'][ $field['default'] ] . ', ';
1937 } elseif ( ! empty( $field['default'] ) ) {
1938 if ( $field['type'] == 'switch' && isset( $field['on'] ) && isset( $field['off'] ) ) {
1939 $default_output .= ( $field['default'] == 1 ? $field['on'] : $field['off'] ) . ', ';
1940 } else {
1941 $default_output .= $field['default'] . ', ';
1942 }
1943 }
1944 } else {
1945 foreach ( $field['default'] as $defaultk => $defaultv ) {
1946 if ( ! empty( $field['options'][ $defaultv ]['alt'] ) ) {
1947 $default_output .= $field['options'][ $defaultv ]['alt'] . ', ';
1948 } elseif ( ! empty( $field['options'][ $defaultv ] ) ) {
1949 $default_output .= $field['options'][ $defaultv ] . ', ';
1950 } elseif ( ! empty( $field['options'][ $defaultk ] ) ) {
1951 $default_output .= $field['options'][ $defaultk ] . ', ';
1952 } elseif ( ! empty( $defaultv ) ) {
1953 $default_output .= $defaultv . ', ';
1954 }
1955 }
1956 }
1957
1958 if ( ! empty( $default_output ) ) {
1959 $default_output = __( 'Default', 'redux-framework' ) . ': ' . substr( $default_output, 0, - 2 );
1960 }
1961
1962 if ( ! empty( $default_output ) ) {
1963 $default_output = '<span class="showDefaults">' . $default_output . '</span><br class="default_br" />';
1964 }
1965
1966 return $default_output;
1967 }
1968
1969 // get_default_output_string()
1970
1971 public function get_header_html( $field ) {
1972 global $current_user;
1973
1974 // Set to empty string to avoid wanrings.
1975 $hint = '';
1976 $th = '';
1977
1978 if ( isset( $field['title'] ) && isset( $field['type'] ) && $field['type'] !== 'info' && $field['type'] !== 'section' ) {
1979 $default_mark = ( ! empty( $field['default'] ) && isset( $this->options[ $field['id'] ] ) && $this->options[ $field['id'] ] == $field['default'] && ! empty( $this->args['default_mark'] ) && isset( $field['default'] ) ) ? $this->args['default_mark'] : '';
1980
1981 // If a hint is specified in the field, process it.
1982 if ( isset( $field['hint'] ) && ! '' == $field['hint'] ) {
1983
1984 // Set show_hints flag to true, so helptab will be displayed.
1985 $this->show_hints = true;
1986
1987 $hint = apply_filters( 'redux/hints/html', $hint, $field, $this->args );
1988
1989 // Get user pref for displaying hints.
1990 $metaVal = get_user_meta( $current_user->ID, 'ignore_hints', true );
1991 if ( 'true' == $metaVal || empty( $metaVal ) && empty( $hint ) ) {
1992
1993 // Set hand cursor for clickable hints
1994 $pointer = '';
1995 if ( isset( $this->args['hints']['tip_effect']['show']['event'] ) && 'click' == $this->args['hints']['tip_effect']['show']['event'] ) {
1996 $pointer = 'pointer';
1997 }
1998
1999 $size = '16px';
2000 if ( 'large' == $this->args['hints']['icon_size'] ) {
2001 $size = '18px';
2002 }
2003
2004 // In case docs are ignored.
2005 $titleParam = isset( $field['hint']['title'] ) ? $field['hint']['title'] : '';
2006 $contentParam = isset( $field['hint']['content'] ) ? $field['hint']['content'] : '';
2007
2008 $hint_color = isset( $this->args['hints']['icon_color'] ) ? $this->args['hints']['icon_color'] : '#d3d3d3';
2009
2010 // Set hint html with appropriate position css
2011 $hint = '<div class="redux-hint-qtip" style="float:' . $this->args['hints']['icon_position'] . '; font-size: ' . $size . '; color:' . $hint_color . '; cursor: ' . $pointer . ';" qtip-title="' . $titleParam . '" qtip-content="' . $contentParam . '">&nbsp;<i class="' . ( isset( $this->args['hints']['icon'] ) ? $this->args['hints']['icon'] : '' ) . '"></i></div>';
2012 }
2013 }
2014
2015 if ( ! empty( $field['title'] ) ) {
2016 if ( 'left' == $this->args['hints']['icon_position'] ) {
2017 $th = $hint . $field['title'] . $default_mark . '';
2018 } else {
2019 $th = $field['title'] . $default_mark . '' . $hint;
2020 }
2021 }
2022
2023 if ( isset( $field['subtitle'] ) ) {
2024 $th .= '<span class="description">' . $field['subtitle'] . '</span>';
2025 }
2026 }
2027
2028 if ( ! empty( $th ) ) {
2029 $th = '<div class="redux_field_th">' . $th . '</div>';
2030 }
2031
2032 $filter_arr = array(
2033 'editor',
2034 'ace_editor',
2035 'info',
2036 'section',
2037 'repeater',
2038 'color_scheme',
2039 'social_profiles',
2040 'css_layout',
2041 );
2042
2043 if ( $this->args['default_show'] == true && isset( $field['default'] ) && isset( $this->options[ $field['id'] ] ) && $this->options[ $field['id'] ] != $field['default'] && ! in_array( $field['type'], $filter_arr ) ) {
2044 $th .= $this->get_default_output_string( $field );
2045 }
2046
2047 return $th;
2048 }
2049
2050 /**
2051 * Register Option for use
2052 *
2053 * @since 1.0.0
2054 * @access public
2055 * @return void
2056 */
2057 public function _register_settings() {
2058
2059 // TODO - REMOVE
2060 // Not used by new sample-config, but in here for legacy builds
2061 // This is bad and can break things. Hehe.
2062 if ( ! function_exists( 'wp_get_current_user' ) ) {
2063 require_once ABSPATH . 'wp-includes/pluggable.php';
2064 }
2065
2066 if ( $this->args['options_api'] == true ) {
2067 register_setting(
2068 $this->args['opt_name'] . '_group',
2069 $this->args['opt_name'],
2070 array(
2071 $this,
2072 '_validate_options',
2073 )
2074 );
2075 }
2076
2077 if ( is_null( $this->sections ) ) {
2078 return;
2079 }
2080
2081 if ( empty( $this->options_defaults ) ) {
2082 $this->options_defaults = $this->_default_values();
2083 }
2084
2085 $runUpdate = false;
2086
2087 foreach ( $this->sections as $k => $section ) {
2088 if ( isset( $section['type'] ) && $section['type'] == 'divide' ) {
2089 continue;
2090 }
2091
2092 $display = true;
2093
2094 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
2095 if ( isset( $section['panel'] ) && $section['panel'] == false ) {
2096 $display = false;
2097 }
2098 }
2099
2100 // DOVY! Replace $k with $section['id'] when ready
2101 /**
2102 * filter 'redux-section-{index}-modifier-{opt_name}'
2103 *
2104 * @param array $section section configuration
2105 */
2106 $section = apply_filters( "redux-section-{$k}-modifier-{$this->args['opt_name']}", $section );
2107
2108 /**
2109 * filter 'redux/options/{opt_name}/section/{section.id}'
2110 *
2111 * @param array $section section configuration
2112 */
2113 if ( isset( $section['id'] ) ) {
2114 $section = apply_filters( "redux/options/{$this->args['opt_name']}/section/{$section['id']}", $section );
2115 }
2116
2117 if ( empty( $section ) ) {
2118 unset( $this->sections[ $k ] );
2119 continue;
2120 }
2121
2122 if ( ! isset( $section['title'] ) ) {
2123 $section['title'] = '';
2124 }
2125
2126 if ( isset( $section['customizer_only'] ) && $section['customizer_only'] == true ) {
2127 $section['panel'] = false;
2128 $this->sections[ $k ] = $section;
2129 }
2130
2131 $heading = isset( $section['heading'] ) ? $section['heading'] : $section['title'];
2132
2133 if ( isset( $section['permissions'] ) ) {
2134 if ( ! self::current_user_can( $section['permissions'] ) ) {
2135 $this->hidden_perm_sections[] = $section['title'];
2136
2137 foreach ( $section['fields'] as $num => $field_data ) {
2138 $field_type = $field_data['type'];
2139
2140 if ( $field_type != 'section' || $field_type != 'divide' || $field_type != 'info' || $field_type != 'raw' ) {
2141 $field_id = $field_data['id'];
2142 $default = isset( $this->options_defaults[ $field_id ] ) ? $this->options_defaults[ $field_id ] : '';
2143 $data = isset( $this->options[ $field_id ] ) ? $this->options[ $field_id ] : $default;
2144
2145 $this->hidden_perm_fields[ $field_id ] = $data;
2146 }
2147 }
2148
2149 continue;
2150 }
2151 }
2152
2153 if ( ! $display || ! function_exists( 'add_settings_section' ) ) {
2154 $this->no_panel_section[ $k ] = $section;
2155 } else {
2156 add_settings_section(
2157 $this->args['opt_name'] . $k . '_section',
2158 $heading,
2159 array(
2160 &$this,
2161 '_section_desc',
2162 ),
2163 $this->args['opt_name'] . $k . '_section_group'
2164 );
2165 }
2166
2167 $sectionIndent = false;
2168 if ( isset( $section['fields'] ) ) {
2169 foreach ( $section['fields'] as $fieldk => $field ) {
2170 if ( ! isset( $field['type'] ) ) {
2171 continue; // You need a type!
2172 }
2173
2174 if ( $field['type'] == 'info' && isset( $field['raw_html'] ) && $field['raw_html'] == true ) {
2175 $field['type'] = 'raw';
2176 $field['content'] = $field['desc'];
2177 $field['desc'] = '';
2178 $this->sections[ $k ]['fields'][ $fieldk ] = $field;
2179 } elseif ( $field['type'] == 'info' ) {
2180 if ( ! isset( $field['full_width'] ) ) {
2181 $field['full_width'] = true;
2182 $this->sections[ $k ]['fields'][ $fieldk ] = $field;
2183 }
2184 }
2185
2186 if ( $field['type'] == 'raw' ) {
2187 if ( isset( $field['align'] ) ) {
2188 $field['full_width'] = $field['align'] ? false : true;
2189 unset( $field['align'] );
2190 } elseif ( ! isset( $field['full_width'] ) ) {
2191 $field['full_width'] = true;
2192 }
2193 $this->sections[ $k ]['fields'][ $fieldk ] = $field;
2194 }
2195
2196 /**
2197 * filter 'redux/options/{opt_name}/field/{field.id}'
2198 *
2199 * @param array $field field config
2200 */
2201 $field = apply_filters( "redux/options/{$this->args['opt_name']}/field/{$field['id']}/register", $field );
2202
2203 $this->field_types[ $field['type'] ] = isset( $this->field_types[ $field['type'] ] ) ? $this->field_types[ $field['type'] ] : array();
2204
2205 $this->field_sections[ $field['type'] ][ $field['id'] ] = $k;
2206
2207 $display = true;
2208
2209 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
2210 if ( isset( $field['panel'] ) && $field['panel'] == false ) {
2211 $display = false;
2212 }
2213 }
2214 if ( isset( $field['customizer_only'] ) && $field['customizer_only'] == true ) {
2215 $display = false;
2216 }
2217
2218 if ( isset( $section['customizer'] ) ) {
2219 $field['customizer'] = $section['customizer'];
2220 $this->sections[ $k ]['fields'][ $fieldk ] = $field;
2221 }
2222
2223 if ( isset( $field['permissions'] ) ) {
2224
2225 if ( ! self::current_user_can( $field['permissions'] ) ) {
2226 $data = isset( $this->options[ $field['id'] ] ) ? $this->options[ $field['id'] ] : $this->options_defaults[ $field['id'] ];
2227
2228 $this->hidden_perm_fields[ $field['id'] ] = $data;
2229
2230 continue;
2231 }
2232 }
2233
2234 if ( ! isset( $field['id'] ) ) {
2235 echo '<br /><h3>No field ID is set.</h3><pre>';
2236 print_r( $field );
2237 echo '</pre><br />';
2238 continue;
2239 }
2240
2241 if ( isset( $field['type'] ) && $field['type'] == 'section' ) {
2242 if ( isset( $field['indent'] ) && $field['indent'] == true ) {
2243 $sectionIndent = true;
2244 } else {
2245 $sectionIndent = false;
2246 }
2247 }
2248
2249 if ( isset( $field['type'] ) && $field['type'] == 'info' && $sectionIndent ) {
2250 $field['indent'] = $sectionIndent;
2251 }
2252
2253 $th = $this->get_header_html( $field );
2254
2255 $field['name'] = $this->args['opt_name'] . '[' . $field['id'] . ']';
2256
2257 // Set the default value if present
2258 $this->options_defaults[ $field['id'] ] = isset( $this->options_defaults[ $field['id'] ] ) ? $this->options_defaults[ $field['id'] ] : '';
2259
2260 // Set the defaults to the value if not present
2261 $doUpdate = false;
2262
2263 // Check fields for values in the default parameter
2264 if ( ! isset( $this->options[ $field['id'] ] ) && isset( $field['default'] ) ) {
2265 $this->options_defaults[ $field['id'] ] = $this->options[ $field['id'] ] = $field['default'];
2266 $doUpdate = true;
2267
2268 // Check fields that hae no default value, but an options value with settings to
2269 // be saved by default
2270 } elseif ( ! isset( $this->options[ $field['id'] ] ) && isset( $field['options'] ) ) {
2271
2272 // If sorter field, check for options as save them as defaults
2273 if ( $field['type'] == 'sorter' || $field['type'] == 'sortable' ) {
2274 $this->options_defaults[ $field['id'] ] = $this->options[ $field['id'] ] = $field['options'];
2275 $doUpdate = true;
2276 }
2277 }
2278
2279 // CORRECT URLS if media URLs are wrong, but attachment IDs are present.
2280 if ( $field['type'] == 'media' ) {
2281 if ( isset( $this->options[ $field['id'] ]['id'] ) && isset( $this->options[ $field['id'] ]['url'] ) && ! empty( $this->options[ $field['id'] ]['url'] ) && strpos( $this->options[ $field['id'] ]['url'], str_replace( 'http://', '', WP_CONTENT_URL ) ) === false ) {
2282 $data = wp_get_attachment_url( $this->options[ $field['id'] ]['id'] );
2283
2284 if ( isset( $data ) && ! empty( $data ) ) {
2285 $this->options[ $field['id'] ]['url'] = $data;
2286 $data = wp_get_attachment_image_src(
2287 $this->options[ $field['id'] ]['id'],
2288 array(
2289 150,
2290 150,
2291 )
2292 );
2293 $this->options[ $field['id'] ]['thumbnail'] = $data[0];
2294 $doUpdate = true;
2295 }
2296 }
2297 }
2298
2299 if ( $field['type'] == 'background' ) {
2300 if ( isset( $this->options[ $field['id'] ]['media']['id'] ) && isset( $this->options[ $field['id'] ]['background-image'] ) && ! empty( $this->options[ $field['id'] ]['background-image'] ) && strpos( $this->options[ $field['id'] ]['background-image'], str_replace( 'http://', '', WP_CONTENT_URL ) ) === false ) {
2301 $data = wp_get_attachment_url( $this->options[ $field['id'] ]['media']['id'] );
2302
2303 if ( isset( $data ) && ! empty( $data ) ) {
2304 $this->options[ $field['id'] ]['background-image'] = $data;
2305 $data = wp_get_attachment_image_src(
2306 $this->options[ $field['id'] ]['media']['id'],
2307 array(
2308 150,
2309 150,
2310 )
2311 );
2312 $this->options[ $field['id'] ]['media']['thumbnail'] = $data[0];
2313 $doUpdate = true;
2314 }
2315 }
2316 }
2317
2318 if ( $field['type'] == 'slides' ) {
2319 if ( isset( $this->options[ $field['id'] ] ) && is_array( $this->options[ $field['id'] ] ) && isset( $this->options[ $field['id'] ][0]['attachment_id'] ) && isset( $this->options[ $field['id'] ][0]['image'] ) && ! empty( $this->options[ $field['id'] ][0]['image'] ) && strpos( $this->options[ $field['id'] ][0]['image'], str_replace( 'http://', '', WP_CONTENT_URL ) ) === false ) {
2320 foreach ( $this->options[ $field['id'] ] as $key => $val ) {
2321 $data = wp_get_attachment_url( $val['attachment_id'] );
2322
2323 if ( isset( $data ) && ! empty( $data ) ) {
2324 $this->options[ $field['id'] ][ $key ]['image'] = $data;
2325 $data = wp_get_attachment_image_src(
2326 $val['attachment_id'],
2327 array(
2328 150,
2329 150,
2330 )
2331 );
2332 $this->options[ $field['id'] ][ $key ]['thumb'] = $data[0];
2333 $doUpdate = true;
2334 }
2335 }
2336 }
2337 }
2338 // END -> CORRECT URLS if media URLs are wrong, but attachment IDs are present.
2339
2340 if ( true == $doUpdate && ! isset( $this->never_save_to_db ) ) {
2341 if ( $this->args['save_defaults'] ) { // Only save that to the DB if allowed to
2342 $runUpdate = true;
2343 }
2344 // elseif($this->saved != '' && $this->saved != false) {
2345 // $runUpdate = true;
2346 // }
2347 }
2348
2349 if ( ! isset( $field['class'] ) ) { // No errors please
2350 $field['class'] = '';
2351 }
2352 $id = $field['id'];
2353
2354 /**
2355 * filter 'redux-field-{field.id}modifier-{opt_name}'
2356 *
2357 * @deprecated
2358 *
2359 * @param array $field field config
2360 */
2361 $field = apply_filters( "redux-field-{$field['id']}modifier-{$this->args['opt_name']}", $field ); // REMOVE LATER
2362
2363 /**
2364 * filter 'redux/options/{opt_name}/field/{field.id}'
2365 *
2366 * @param array $field field config
2367 */
2368 $field = apply_filters( "redux/options/{$this->args['opt_name']}/field/{$field['id']}", $field );
2369
2370 if ( empty( $field ) || ! $field || $field == false ) {
2371 unset( $this->sections[ $k ]['fields'][ $fieldk ] );
2372 continue;
2373 }
2374
2375 if ( ! empty( $this->folds[ $field['id'] ]['parent'] ) ) { // This has some fold items, hide it by default
2376 $field['class'] .= ' fold';
2377 }
2378
2379 if ( ! empty( $this->folds[ $field['id'] ]['children'] ) ) { // Sets the values you shoe fold children on
2380 $field['class'] .= ' foldParent';
2381 }
2382
2383 if ( ! empty( $field['compiler'] ) ) {
2384 $field['class'] .= ' compiler';
2385 $this->compiler_fields[ $field['id'] ] = 1;
2386 }
2387
2388 if ( isset( $field['unit'] ) && ! isset( $field['units'] ) ) {
2389 $field['units'] = $field['unit'];
2390 unset( $field['unit'] );
2391 }
2392
2393 $this->sections[ $k ]['fields'][ $fieldk ] = $field;
2394
2395 if ( isset( $this->args['display_source'] ) ) {
2396 $th .= '<div id="' . $field['id'] . '-settings" style="display:none;"><pre>' . var_export( $this->sections[ $k ]['fields'][ $fieldk ], true ) . '</pre></div>';
2397 $th .= '<br /><a href="#TB_inline?width=600&height=800&inlineId=' . $field['id'] . '-settings" class="thickbox"><small>View Source</small></a>';
2398 }
2399
2400 /**
2401 * action 'redux/options/{opt_name}/field/field.type}/register'
2402 */
2403 do_action( "redux/options/{$this->args['opt_name']}/field/{$field['type']}/register", $field );
2404
2405 $this->check_dependencies( $field );
2406 $this->field_head[ $field['id'] ] = $th;
2407
2408 if ( ! $display || isset( $this->no_panel_section[ $k ] ) ) {
2409 $this->no_panel[] = $field['id'];
2410 } else {
2411 if ( isset( $field['hidden'] ) && $field['hidden'] ) {
2412 $field['label_for'] = 'redux_hide_field';
2413 }
2414 if ( $this->args['options_api'] == true ) {
2415 add_settings_field(
2416 "{$fieldk}_field",
2417 $th,
2418 array(
2419 &$this,
2420 '_field_input',
2421 ),
2422 "{$this->args['opt_name']}{$k}_section_group",
2423 "{$this->args['opt_name']}{$k}_section",
2424 $field
2425 );
2426 }
2427 }
2428 }
2429 }
2430 }
2431
2432 /**
2433 * action 'redux-register-settings-{opt_name}'
2434 *
2435 * @deprecated
2436 */
2437 do_action( "redux-register-settings-{$this->args['opt_name']}" ); // REMOVE
2438
2439 /**
2440 * action 'redux/options/{opt_name}/register'
2441 *
2442 * @param array option sections
2443 */
2444 do_action( "redux/options/{$this->args['opt_name']}/register", $this->sections );
2445
2446 if ( $runUpdate && ! isset( $this->never_save_to_db ) ) { // Always update the DB with new fields
2447 $this->set_options( $this->options );
2448 }
2449
2450 if ( isset( $this->transients['run_compiler'] ) && $this->transients['run_compiler'] ) {
2451
2452 $this->no_output = true;
2453 $this->_enqueue_output();
2454
2455 /**
2456 * action 'redux-compiler-{opt_name}'
2457 *
2458 * @deprecated
2459 *
2460 * @param array options
2461 * @param string CSS that get sent to the compiler hook
2462 */
2463 do_action( "redux-compiler-{$this->args['opt_name']}", $this->options, $this->compilerCSS, $this->transients['changed_values'] ); // REMOVE
2464
2465 /**
2466 * action 'redux/options/{opt_name}a'
2467 *
2468 * @param array options
2469 * @param string CSS that get sent to the compiler hook
2470 */
2471 do_action( "redux/options/{$this->args['opt_name']}/compiler", $this->options, $this->compilerCSS, $this->transients['changed_values'] );
2472
2473 /**
2474 * action 'redux/options/{opt_name}/compiler/advanced'
2475 *
2476 * @param array options
2477 * @param string CSS that get sent to the compiler hook, which sends the full Redux object
2478 */
2479 do_action( "redux/options/{$this->args['opt_name']}/compiler/advanced", $this );
2480
2481 unset( $this->transients['run_compiler'] );
2482 $this->set_transients();
2483 }
2484 }
2485 // _register_settings()
2486
2487 /**
2488 * Register Extensions for use
2489 *
2490 * @since 3.0.0
2491 * @access public
2492 * @return void
2493 */
2494 private function _register_extensions() {
2495 $path = __DIR__ . '/inc/extensions/';
2496 $folders = scandir( $path, 1 );
2497
2498 /**
2499 * action 'redux/extensions/before'
2500 *
2501 * @param object $this ReduxFrameworkLegacy
2502 */
2503 do_action( 'redux/extensions/before', $this );
2504
2505 /**
2506 * action 'redux/extensions/{opt_name}/before'
2507 *
2508 * @param object $this ReduxFrameworkLegacy
2509 */
2510 do_action( "redux/extensions/{$this->args['opt_name']}/before", $this );
2511
2512 if ( isset( $this->old_opt_name ) ) {
2513 do_action( "redux/extensions/{$this->old_opt_name}/before", $this );
2514 }
2515
2516 foreach ( $folders as $folder ) {
2517 if ( $folder === '.' || $folder === '..' || ! is_dir( $path . $folder ) || substr( $folder, 0, 1 ) === '.' || substr( $folder, 0, 1 ) === '@' || substr( $folder, 0, 4 ) === '_vti' ) {
2518 continue;
2519 }
2520
2521 $extension_class = 'ReduxFrameworkLegacy_Extension_' . $folder;
2522
2523 /**
2524 * filter 'redux-extensionclass-load'
2525 *
2526 * @deprecated
2527 *
2528 * @param string extension class file path
2529 * @param string $extension_class extension class name
2530 */
2531 $class_file = apply_filters( 'redux-extensionclass-load', "$path/$folder/extension_{$folder}.php", $extension_class ); // REMOVE LATER
2532
2533 /**
2534 * filter 'redux/extension/{opt_name}/{folder}'
2535 *
2536 * @param string extension class file path
2537 * @param string $extension_class extension class name
2538 */
2539 $class_file = apply_filters( "redux/extension/{$this->args['opt_name']}/$folder", "$path/$folder/extension_{$folder}.php", $class_file );
2540
2541 if ( $class_file ) {
2542
2543 if ( file_exists( $class_file ) ) {
2544 require_once $class_file;
2545
2546 $this->extensions[ $folder ] = new $extension_class( $this );
2547 }
2548 }
2549 }
2550
2551 /**
2552 * action 'redux-register-extensions-{opt_name}'
2553 *
2554 * @deprecated
2555 *
2556 * @param object $this ReduxFrameworkLegacy
2557 */
2558 do_action( "redux-register-extensions-{$this->args['opt_name']}", $this ); // REMOVE
2559
2560 /**
2561 * action 'redux/extensions/{opt_name}'
2562 *
2563 * @param object $this ReduxFrameworkLegacy
2564 */
2565 do_action( "redux/extensions/{$this->args['opt_name']}", $this );
2566
2567 if ( isset( $this->old_opt_name ) && ! empty( $this->old_opt_name ) ) {
2568 do_action( "redux/extensions/{$this->old_opt_name}", $this );
2569 }
2570 }
2571
2572 private function get_transients() {
2573 if ( ! isset( $this->transients ) ) {
2574 $this->transients = get_option( $this->args['opt_name'] . '-transients', array() );
2575 $this->transients_check = $this->transients;
2576 }
2577 }
2578
2579 public function set_transients() {
2580 if ( ! isset( $this->transients ) || ! isset( $this->transients_check ) || $this->transients != $this->transients_check ) {
2581 update_option( $this->args['opt_name'] . '-transients', $this->transients );
2582 $this->transients_check = $this->transients;
2583 }
2584 }
2585
2586 /**
2587 * Validate the Options options before insertion
2588 *
2589 * @since 3.0.0
2590 * @access public
2591 *
2592 * @param array $plugin_options The options array
2593 *
2594 * @return array|mixed|string|void
2595 */
2596 public function _validate_options( $plugin_options ) {
2597 // print_r($plugin_options);
2598 // exit();
2599 if ( isset( $this->validation_ran ) ) {
2600 return $plugin_options;
2601 }
2602 $this->validation_ran = 1;
2603
2604 // Save the values not in the panel
2605 if ( isset( $plugin_options['redux-no_panel'] ) ) {
2606 $keys = explode( '|', $plugin_options['redux-no_panel'] );
2607 foreach ( $keys as $key ) {
2608 $plugin_options[ $key ] = $this->options[ $key ];
2609 }
2610 if ( isset( $plugin_options['redux-no_panel'] ) ) {
2611 unset( $plugin_options['redux-no_panel'] );
2612 }
2613 }
2614
2615 if ( ! empty( $this->hidden_perm_fields ) && is_array( $this->hidden_perm_fields ) ) {
2616 foreach ( $this->hidden_perm_fields as $id => $data ) {
2617 $plugin_options[ $id ] = $data;
2618 }
2619 }
2620
2621 if ( $plugin_options == $this->options ) {
2622 return $plugin_options;
2623 }
2624
2625 $time = time();
2626
2627 // Sets last saved time
2628 $this->transients['last_save'] = $time;
2629
2630 // Import
2631 if ( ( isset( $plugin_options['import_code'] ) && ! empty( $plugin_options['import_code'] ) ) || ( isset( $plugin_options['import_link'] ) && ! empty( $plugin_options['import_link'] ) ) ) {
2632 $this->transients['last_save_mode'] = 'import'; // Last save mode
2633 $this->transients['last_compiler'] = $time;
2634 $this->transients['last_import'] = $time;
2635 $this->transients['run_compiler'] = 1;
2636
2637 if ( $plugin_options['import_code'] != '' ) {
2638 $import = $plugin_options['import_code'];
2639 } elseif ( $plugin_options['import_link'] != '' ) {
2640 $import = wp_remote_retrieve_body( wp_remote_get( $plugin_options['import_link'] ) );
2641 }
2642
2643 if ( ! empty( $import ) ) {
2644 $imported_options = json_decode( $import, true );
2645 }
2646
2647 if ( ! empty( $imported_options ) && is_array( $imported_options ) && isset( $imported_options['redux-backup'] ) && $imported_options['redux-backup'] == '1' ) {
2648
2649 $this->transients['changed_values'] = array();
2650 foreach ( $plugin_options as $key => $value ) {
2651 if ( isset( $imported_options[ $key ] ) && $imported_options[ $key ] != $value ) {
2652 $this->transients['changed_values'][ $key ] = $value;
2653 $plugin_options[ $key ] = $value;
2654 }
2655 }
2656
2657 /**
2658 * action 'redux/options/{opt_name}/import'
2659 *
2660 * @param &array [&$plugin_options, redux_options]
2661 */
2662 do_action_ref_array(
2663 "redux/options/{$this->args['opt_name']}/import",
2664 array(
2665 &$plugin_options,
2666 $imported_options,
2667 $this->transients['changed_values'],
2668 )
2669 );
2670
2671 setcookie( 'redux_current_tab', '', 1, '/', $time + 1000, '/' );
2672 $_COOKIE['redux_current_tab'] = 1;
2673
2674 unset( $plugin_options['defaults'], $plugin_options['compiler'], $plugin_options['import'], $plugin_options['import_code'] );
2675 if ( $this->args['database'] == 'transient' || $this->args['database'] == 'theme_mods' || $this->args['database'] == 'theme_mods_expanded' || $this->args['database'] == 'network' ) {
2676 $this->set_options( $plugin_options );
2677
2678 return;
2679 }
2680
2681 $plugin_options = wp_parse_args( $imported_options, $plugin_options );
2682
2683 $this->set_transients(); // Update the transients
2684
2685 return $plugin_options;
2686 }
2687 }
2688
2689 // Reset all to defaults
2690 if ( ! empty( $plugin_options['defaults'] ) ) {
2691 if ( empty( $this->options_defaults ) ) {
2692 $this->options_defaults = $this->_default_values();
2693 }
2694
2695 /**
2696 * apply_filters 'redux/validate/{opt_name}/defaults'
2697 *
2698 * @param &array [ $this->options_defaults, $plugin_options]
2699 */
2700 $plugin_options = apply_filters( "redux/validate/{$this->args['opt_name']}/defaults", $this->options_defaults );
2701
2702 $this->transients['changed_values'] = array();
2703
2704 if ( empty( $this->options ) ) {
2705 $this->options = $this->options_defaults;
2706 }
2707
2708 foreach ( $this->options as $key => $value ) {
2709 if ( isset( $plugin_options[ $key ] ) && $value != $plugin_options[ $key ] ) {
2710 $this->transients['changed_values'][ $key ] = $value;
2711 }
2712 }
2713
2714 $this->transients['run_compiler'] = 1;
2715 $this->transients['last_save_mode'] = 'defaults'; // Last save mode
2716 // setcookie('redux-compiler-' . $this->args['opt_name'], 1, time() + 1000, "/");
2717 // setcookie("redux-saved-{$this->args['opt_name']}", 'defaults', time() + 1000, "/");
2718
2719 $this->set_transients(); // Update the transients
2720
2721 return $plugin_options;
2722 }
2723
2724 // Section reset to defaults
2725 if ( ! empty( $plugin_options['defaults-section'] ) ) {
2726 if ( isset( $plugin_options['redux-section'] ) && isset( $this->sections[ $plugin_options['redux-section'] ]['fields'] ) ) {
2727 /**
2728 * apply_filters 'redux/validate/{opt_name}/defaults_section'
2729 *
2730 * @param &array [ $this->options_defaults, $plugin_options]
2731 */
2732 foreach ( $this->sections[ $plugin_options['redux-section'] ]['fields'] as $field ) {
2733 if ( isset( $this->options_defaults[ $field['id'] ] ) ) {
2734 $plugin_options[ $field['id'] ] = $this->options_defaults[ $field['id'] ];
2735 } else {
2736 $plugin_options[ $field['id'] ] = '';
2737 }
2738
2739 if ( isset( $field['compiler'] ) ) {
2740 $compiler = true;
2741 }
2742 }
2743
2744 $plugin_options = apply_filters( "redux/validate/{$this->args['opt_name']}/defaults_section", $plugin_options );
2745 }
2746
2747 $this->transients['changed_values'] = array();
2748 foreach ( $this->options as $key => $value ) {
2749 if ( isset( $plugin_options[ $key ] ) && $value != $plugin_options[ $key ] ) {
2750 $this->transients['changed_values'][ $key ] = $value;
2751 }
2752 }
2753
2754 if ( isset( $compiler ) ) {
2755 // $this->run_compiler = true;
2756 // setcookie('redux-compiler-' . $this->args['opt_name'], 1, time()+1000, '/');
2757 // $plugin_options['REDUX_COMPILER'] = time();
2758 $this->transients['last_compiler'] = $time;
2759 $this->transients['run_compiler'] = 1;
2760 }
2761
2762 $this->transients['last_save_mode'] = 'defaults_section'; // Last save mode
2763 // setcookie("redux-saved-{$this->args['opt_name']}", 'defaults_section', time() + 1000, "/");
2764 unset( $plugin_options['defaults'], $plugin_options['defaults_section'], $plugin_options['import'], $plugin_options['import_code'], $plugin_options['import_link'], $plugin_options['compiler'], $plugin_options['redux-section'] );
2765
2766 $this->set_transients();
2767
2768 return $plugin_options;
2769 }
2770
2771 // if ($this->transients['last_save_mode'] != 'remove') {
2772 $this->transients['last_save_mode'] = 'normal'; // Last save mode
2773 // } else {
2774 // $this->transients['last_save_mode'] = '';
2775 // }
2776
2777 /**
2778 * apply_filters 'redux/validate/{opt_name}/before_validation'
2779 *
2780 * @param &array [&$plugin_options, redux_options]
2781 */
2782 $plugin_options = apply_filters( "redux/validate/{$this->args['opt_name']}/before_validation", $plugin_options, $this->options );
2783
2784 // Validate fields (if needed)
2785 $plugin_options = $this->_validate_values( $plugin_options, $this->options, $this->sections );
2786
2787 if ( ! empty( $this->errors ) || ! empty( $this->warnings ) ) {
2788 $this->transients['notices'] = array(
2789 'errors' => $this->errors,
2790 'warnings' => $this->warnings,
2791 );
2792 }
2793
2794 /**
2795 * action 'redux-validate-{opt_name}'
2796 *
2797 * @deprecated
2798 *
2799 * @param &array [&$plugin_options, redux_options]
2800 */
2801 do_action_ref_array(
2802 "redux-validate-{$this->args['opt_name']}",
2803 array(
2804 &$plugin_options,
2805 $this->options,
2806 )
2807 ); // REMOVE
2808
2809 if ( ! isset( $this->transients['changed_values'] ) ) {
2810 $this->transients['changed_values'] = array();
2811 }
2812
2813 /**
2814 * action 'redux/options/{opt_name}/validate'
2815 *
2816 * @param &array [&$plugin_options, redux_options]
2817 */
2818 do_action_ref_array(
2819 "redux/options/{$this->args['opt_name']}/validate",
2820 array(
2821 &$plugin_options,
2822 $this->options,
2823 $this->transients['changed_values'],
2824 )
2825 );
2826
2827 if ( ! empty( $plugin_options['compiler'] ) ) {
2828 unset( $plugin_options['compiler'] );
2829
2830 $this->transients['last_compiler'] = $time;
2831 $this->transients['run_compiler'] = 1;
2832 }
2833
2834 $this->transients['changed_values'] = array(); // Changed values since last save
2835 if ( ! empty( $this->options ) ) {
2836 foreach ( $this->options as $key => $value ) {
2837 if ( isset( $plugin_options[ $key ] ) && $value != $plugin_options[ $key ] ) {
2838 $this->transients['changed_values'][ $key ] = $value;
2839 }
2840 }
2841 }
2842
2843 unset( $plugin_options['defaults'], $plugin_options['defaults_section'], $plugin_options['import'], $plugin_options['import_code'], $plugin_options['import_link'], $plugin_options['compiler'], $plugin_options['redux-section'] );
2844 if ( $this->args['database'] == 'transient' || $this->args['database'] == 'theme_mods' || $this->args['database'] == 'theme_mods_expanded' ) {
2845 $this->set_options( $plugin_options );
2846
2847 return;
2848 }
2849
2850 if ( defined( 'WP_CACHE' ) && WP_CACHE && class_exists( 'W3_ObjectCache' ) && function_exists( 'w3_instance' ) ) {
2851 // echo "here";
2852 $w3_inst = w3_instance( 'W3_ObjectCache' );
2853 $w3 = $w3_inst->instance();
2854 $key = $w3->_get_cache_key( $this->args['opt_name'] . '-transients', 'transient' );
2855 // echo $key;
2856 $w3->delete( $key, 'transient', true );
2857 // set_transient($this->args['opt_name'].'-transients', $this->transients);
2858 // exit();
2859 }
2860
2861 $this->set_transients();
2862
2863 return $plugin_options;
2864 }
2865
2866 public function ajax_save() {
2867 if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'redux_ajax_nonce' . $this->args['opt_name'] ) ) {
2868 echo json_encode(
2869 array(
2870 'status' => __( 'Invalid security credential. Please reload the page and try again.', 'redux-framework' ),
2871 'action' => '',
2872 )
2873 );
2874
2875 die();
2876 }
2877
2878 if ( ! self::current_user_can( $this->args['page_permissions'] ) ) {
2879 echo json_encode(
2880 array(
2881 'status' => __( 'Invalid user capability. Please reload the page and try again.', 'redux-framework' ),
2882 'action' => '',
2883 )
2884 );
2885
2886 die();
2887 }
2888
2889 $redux = ReduxFrameworkInstancesLegacy::get_instance( $_POST['opt_name'] );
2890
2891 if ( ! empty( $_POST['data'] ) && ! empty( $redux->args['opt_name'] ) ) {
2892
2893 $values = array();
2894 // if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
2895 // $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
2896 // while (list($key, $val) = each($process)) {
2897 // foreach ($val as $k => $v) {
2898 // unset($process[$key][$k]);
2899 // if (is_array($v)) {
2900 // $process[$key][stripslashes($k)] = $v;
2901 // $process[] = &$process[$key][stripslashes($k)];
2902 // } else {
2903 // $process[$key][stripslashes($k)] = stripslashes($v);
2904 // }
2905 // }
2906 // }
2907 // unset($process);
2908 // }
2909 $_POST['data'] = stripslashes( $_POST['data'] );
2910
2911 // Old method of saving, in case we need to go back! - kp
2912 // parse_str( $_POST['data'], $values );
2913
2914 // New method to avoid input_var nonesense. Thanks @harunbasic
2915 $values = $this->redux_parse_str( $_POST['data'] );
2916
2917 $values = $values[ $redux->args['opt_name'] ];
2918
2919 if ( function_exists( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc() ) {
2920 $values = array_map( 'stripslashes_deep', $values );
2921 }
2922
2923 if ( ! empty( $values ) ) {
2924
2925 try {
2926 if ( isset( $redux->validation_ran ) ) {
2927 unset( $redux->validation_ran );
2928 }
2929 $redux->set_options( $redux->_validate_options( $values ) );
2930
2931 $do_reload = false;
2932 if ( isset( $this->reload_fields ) && ! empty( $this->reload_fields ) ) {
2933 if ( ! empty( $this->transients['changed_values'] ) ) {
2934 foreach ( $this->reload_fields as $idx => $val ) {
2935 if ( array_key_exists( $val, $this->transients['changed_values'] ) ) {
2936 $do_reload = true;
2937 }
2938 }
2939 }
2940 }
2941
2942 if ( $do_reload || ( isset( $values['defaults'] ) && ! empty( $values['defaults'] ) ) || ( isset( $values['defaults-section'] ) && ! empty( $values['defaults-section'] ) ) || ( isset( $values['import_code'] ) && ! empty( $values['import_code'] ) ) || ( isset( $values['import_link'] ) && ! empty( $values['import_link'] ) ) ) {
2943 echo json_encode(
2944 array(
2945 'status' => 'success',
2946 'action' => 'reload',
2947 )
2948 );
2949 die();
2950 }
2951
2952 require_once 'core/enqueue.php';
2953 $enqueue = new reduxLegacyCoreEnqueue( $redux );
2954 $enqueue->get_warnings_and_errors_array();
2955
2956 $return_array = array(
2957 'status' => 'success',
2958 'options' => $redux->options,
2959 'errors' => isset( $redux->localize_data['errors'] ) ? $redux->localize_data['errors'] : null,
2960 'warnings' => isset( $redux->localize_data['warnings'] ) ? $redux->localize_data['warnings'] : null,
2961 );
2962
2963 } catch ( Exception $e ) {
2964 $return_array = array( 'status' => $e->getMessage() );
2965 }
2966 } else {
2967 echo json_encode( array( 'status' => __( 'Your panel has no fields. Nothing to save.', 'redux-framework' ) ) );
2968 }
2969 }
2970 if ( isset( $this->transients['run_compiler'] ) && $this->transients['run_compiler'] ) {
2971
2972 $this->no_output = true;
2973 $this->_enqueue_output();
2974
2975 try {
2976 /**
2977 * action 'redux-compiler-{opt_name}'
2978 *
2979 * @deprecated
2980 *
2981 * @param array options
2982 * @param string CSS that get sent to the compiler hook
2983 */
2984 do_action( "redux-compiler-{$this->args['opt_name']}", $this->options, $this->compilerCSS, $this->transients['changed_values'] ); // REMOVE
2985
2986 /**
2987 * action 'redux/options/{opt_name}/compiler'
2988 *
2989 * @param array options
2990 * @param string CSS that get sent to the compiler hook
2991 */
2992 do_action( "redux/options/{$this->args['opt_name']}/compiler", $this->options, $this->compilerCSS, $this->transients['changed_values'] );
2993
2994 /**
2995 * action 'redux/options/{opt_name}/compiler/advanced'
2996 *
2997 * @param array options
2998 * @param string CSS that get sent to the compiler hook, which sends the full Redux object
2999 */
3000 do_action( "redux/options/{$this->args['opt_name']}/compiler/advanced", $this );
3001 } catch ( Exception $e ) {
3002 $return_array = array( 'status' => $e->getMessage() );
3003 }
3004
3005 unset( $this->transients['run_compiler'] );
3006 $this->set_transients();
3007 }
3008 if ( isset( $return_array ) ) {
3009 if ( $return_array['status'] == 'success' ) {
3010 require_once 'core/panel.php';
3011 $panel = new reduxLegacyCorePanel( $redux );
3012 ob_start();
3013 $panel->notification_bar();
3014 $notification_bar = ob_get_contents();
3015 ob_end_clean();
3016 $return_array['notification_bar'] = $notification_bar;
3017 }
3018
3019 echo json_encode( apply_filters( "redux/options/{$this->args['opt_name']}/ajax_save/response", $return_array ) );
3020 }
3021
3022 die();
3023 }
3024
3025 /**
3026 * Validate values from options form (used in settings api validate function)
3027 * calls the custom validation class for the field so authors can override with custom classes
3028 *
3029 * @since 1.0.0
3030 * @access public
3031 *
3032 * @param array $plugin_options
3033 * @param array $options
3034 *
3035 * @return array $plugin_options
3036 */
3037 public function _validate_values( $plugin_options, $options, $sections ) {
3038 foreach ( $sections as $k => $section ) {
3039 if ( isset( $section['fields'] ) ) {
3040 foreach ( $section['fields'] as $fkey => $field ) {
3041
3042 if ( is_array( $field ) ) {
3043 $field['section_id'] = $k;
3044 }
3045
3046 if ( isset( $field['type'] ) && ( $field['type'] == 'checkbox' || $field['type'] == 'checkbox_hide_below' || $field['type'] == 'checkbox_hide_all' ) ) {
3047 if ( ! isset( $plugin_options[ $field['id'] ] ) ) {
3048 $plugin_options[ $field['id'] ] = 0;
3049 }
3050 }
3051
3052 // if ( isset ( $field['type'] ) && $field['type'] == 'typography' ) {
3053 // if ( ! is_array( $plugin_options[ $field['id'] ] ) && ! empty( $plugin_options[ $field['id'] ] ) ) {
3054 // $plugin_options[ $field['id'] ] = json_decode( $plugin_options[ $field['id'] ], true );
3055 // }
3056 // }
3057
3058 if ( isset( $this->extensions[ $field['type'] ] ) && method_exists( $this->extensions[ $field['type'] ], '_validate_values' ) ) {
3059 $plugin_options = $this->extensions[ $field['type'] ]->_validate_values( $plugin_options, $field, $sections );
3060
3061 }
3062
3063 // Default 'not_empty 'flag to false.
3064 $isNotEmpty = false;
3065
3066 // Make sure 'validate' field is set.
3067 if ( isset( $field['validate'] ) ) {
3068
3069 // Make sure 'validate field' is set to 'not_empty' or 'email_not_empty'
3070 // if ( $field['validate'] == 'not_empty' || $field['validate'] == 'email_not_empty' || $field['validate'] == 'numeric_not_empty' ) {
3071 if ( strtolower( substr( $field['validate'], - 9 ) ) == 'not_empty' ) {
3072
3073 // Set the flag.
3074 $isNotEmpty = true;
3075 }
3076 }
3077
3078 // Check for empty id value
3079
3080 if ( ! isset( $field['id'] ) || ! isset( $plugin_options[ $field['id'] ] ) || ( isset( $plugin_options[ $field['id'] ] ) && $plugin_options[ $field['id'] ] == '' ) ) {
3081
3082 // If we are looking for an empty value, in the case of 'not_empty'
3083 // then we need to keep processing.
3084 if ( ! $isNotEmpty ) {
3085
3086 // Empty id and not checking for 'not_empty. Bail out...
3087 if ( ! isset( $field['validate_callback'] ) ) {
3088 continue;
3089 }
3090 // continue;
3091 }
3092 }
3093
3094 // Force validate of custom field types
3095 if ( isset( $field['type'] ) && ! isset( $field['validate'] ) && ! isset( $field['validate_callback'] ) ) {
3096 if ( $field['type'] == 'color' || $field['type'] == 'color_gradient' ) {
3097 $field['validate'] = 'color';
3098 } elseif ( $field['type'] == 'date' ) {
3099 $field['validate'] = 'date';
3100 }
3101 }
3102
3103 if ( isset( $field['validate'] ) ) {
3104 $validate = 'Redux_Validation_' . $field['validate'];
3105
3106 if ( ! class_exists( $validate ) ) {
3107 /**
3108 * filter 'redux-validateclass-load'
3109 *
3110 * @deprecated
3111 *
3112 * @param string validation class file path
3113 * @param string $validate validation class name
3114 */
3115 $class_file = apply_filters( 'redux-validateclass-load', self::$_dir . "inc/validation/{$field['validate']}/validation_{$field['validate']}.php", $validate ); // REMOVE LATER
3116
3117 /**
3118 * filter 'redux/validate/{opt_name}/class/{field.validate}'
3119 *
3120 * @param string validation class file path
3121 * @param string $class_file validation class file path
3122 */
3123 $class_file = apply_filters( "redux/validate/{$this->args['opt_name']}/class/{$field['validate']}", self::$_dir . "inc/validation/{$field['validate']}/validation_{$field['validate']}.php", $class_file );
3124
3125 if ( $class_file ) {
3126 if ( file_exists( $class_file ) ) {
3127 require_once $class_file;
3128 }
3129 }
3130 }
3131
3132 if ( class_exists( $validate ) ) {
3133
3134 // !DOVY - DB saving stuff. Is this right?
3135 if ( empty( $options[ $field['id'] ] ) ) {
3136 $options[ $field['id'] ] = '';
3137 }
3138
3139 if ( isset( $plugin_options[ $field['id'] ] ) && is_array( $plugin_options[ $field['id'] ] ) && ! empty( $plugin_options[ $field['id'] ] ) ) {
3140 foreach ( $plugin_options[ $field['id'] ] as $key => $value ) {
3141 $before = $after = null;
3142 if ( isset( $plugin_options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || $plugin_options[ $field['id'] ][ $key ] == '0' ) ) {
3143 if ( is_array( $plugin_options[ $field['id'] ][ $key ] ) ) {
3144 $before = $plugin_options[ $field['id'] ][ $key ];
3145 } else {
3146 $before = trim( $plugin_options[ $field['id'] ][ $key ] );
3147 }
3148 }
3149
3150 if ( isset( $options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || $plugin_options[ $field['id'] ][ $key ] == '0' ) ) {
3151 $after = $options[ $field['id'] ][ $key ];
3152 }
3153
3154 $validation = new $validate( $this, $field, $before, $after );
3155 if ( ! empty( $validation->value ) || $validation->value == '0' ) {
3156 $plugin_options[ $field['id'] ][ $key ] = $validation->value;
3157 } else {
3158 unset( $plugin_options[ $field['id'] ][ $key ] );
3159 }
3160
3161 if ( isset( $validation->error ) ) {
3162 $this->errors[] = $validation->error;
3163 }
3164
3165 if ( isset( $validation->warning ) ) {
3166 $this->warnings[] = $validation->warning;
3167 }
3168 }
3169 } else {
3170 if ( isset( $plugin_options[ $field['id'] ] ) ) {
3171 if ( is_array( $plugin_options[ $field['id'] ] ) ) {
3172 $pofi = $plugin_options[ $field['id'] ];
3173 } else {
3174 $pofi = trim( $plugin_options[ $field['id'] ] );
3175 }
3176 } else {
3177 $pofi = null;
3178 }
3179
3180 $validation = new $validate( $this, $field, $pofi, $options[ $field['id'] ] );
3181 $plugin_options[ $field['id'] ] = $validation->value;
3182
3183 if ( isset( $validation->error ) ) {
3184 $this->errors[] = $validation->error;
3185 }
3186
3187 if ( isset( $validation->warning ) ) {
3188 $this->warnings[] = $validation->warning;
3189 }
3190 }
3191
3192 continue;
3193 }
3194 }
3195 if ( isset( $field['validate_callback'] ) && ( is_callable( $field['validate_callback'] ) || ( is_string( $field['validate_callback'] ) && function_exists( $field['validate_callback'] ) ) ) ) {
3196 $callback = $field['validate_callback'];
3197 unset( $field['validate_callback'] );
3198
3199 $plugin_option = isset( $plugin_options[ $field['id'] ] ) ? $plugin_options[ $field['id'] ] : null;
3200 $option = isset( $options[ $field['id'] ] ) ? $options[ $field['id'] ] : null;
3201 $callbackvalues = call_user_func( $callback, $field, $plugin_option, $option );
3202 $plugin_options[ $field['id'] ] = $callbackvalues['value'];
3203
3204 if ( isset( $callbackvalues['error'] ) ) {
3205 $this->errors[] = $callbackvalues['error'];
3206 }
3207 // TODO - This warning message is failing. Hmm.
3208 // No it isn't. Problem was in the sample-config - kp
3209 if ( isset( $callbackvalues['warning'] ) ) {
3210 $this->warnings[] = $callbackvalues['warning'];
3211 }
3212 }
3213 }
3214 }
3215 }
3216
3217 return $plugin_options;
3218 }
3219
3220 /**
3221 * Return Section Menu HTML
3222 *
3223 * @since 3.1.5
3224 * @access public
3225 * @return void
3226 */
3227 public function section_menu( $k, $section, $suffix = '', $sections = array() ) {
3228 $display = true;
3229
3230 $section['class'] = isset( $section['class'] ) ? ' ' . $section['class'] : '';
3231
3232 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
3233 if ( isset( $section['panel'] ) && $section['panel'] == false ) {
3234 $display = false;
3235 }
3236 }
3237
3238 if ( ! $display ) {
3239 return '';
3240 }
3241
3242 if ( empty( $sections ) ) {
3243 $sections = $this->sections;
3244 }
3245
3246 $string = '';
3247 if ( ( ( isset( $this->args['icon_type'] ) && $this->args['icon_type'] == 'image' ) || ( isset( $section['icon_type'] ) && $section['icon_type'] == 'image' ) ) || ( isset( $section['icon'] ) && strpos( $section['icon'], '/' ) !== false ) ) {
3248 // if( !empty( $this->args['icon_type'] ) && $this->args['icon_type'] == 'image' ) {
3249 $icon = ( ! isset( $section['icon'] ) ) ? '' : '<img class="image_icon_type" src="' . esc_url( $section['icon'] ) . '" /> ';
3250 } else {
3251 if ( ! empty( $section['icon_class'] ) ) {
3252 $icon_class = ' ' . $section['icon_class'];
3253 } elseif ( ! empty( $this->args['default_icon_class'] ) ) {
3254 $icon_class = ' ' . $this->args['default_icon_class'];
3255 } else {
3256 $icon_class = '';
3257 }
3258 $icon = ( ! isset( $section['icon'] ) ) ? '<i class="el el-cog' . esc_attr( $icon_class ) . '"></i> ' : '<i class="' . esc_attr( $section['icon'] ) . esc_attr( $icon_class ) . '"></i> ';
3259 }
3260 if ( strpos( $icon, 'el-icon-' ) !== false ) {
3261 $icon = str_replace( 'el-icon-', 'el el-', $icon );
3262 }
3263
3264 $hide_section = '';
3265 if ( isset( $section['hidden'] ) ) {
3266 $hide_section = ( $section['hidden'] == true ) ? ' hidden ' : '';
3267 }
3268
3269 $canBeSubSection = ( $k > 0 && ( ! isset( $sections[ ( $k ) ]['type'] ) || $sections[ ( $k ) ]['type'] != 'divide' ) ) ? true : false;
3270
3271 if ( ! $canBeSubSection && isset( $section['subsection'] ) && $section['subsection'] == true ) {
3272 unset( $section['subsection'] );
3273 }
3274
3275 if ( isset( $section['type'] ) && $section['type'] == 'divide' ) {
3276 $string .= '<li class="divide' . esc_attr( $section['class'] ) . '">&nbsp;</li>';
3277 } elseif ( ! isset( $section['subsection'] ) || $section['subsection'] != true ) {
3278
3279 // DOVY! REPLACE $k with $section['ID'] when used properly.
3280 // $active = ( ( is_numeric($this->current_tab) && $this->current_tab == $k ) || ( !is_numeric($this->current_tab) && $this->current_tab === $k ) ) ? ' active' : '';
3281 $subsections = ( isset( $sections[ ( $k + 1 ) ] ) && isset( $sections[ ( $k + 1 ) ]['subsection'] ) && $sections[ ( $k + 1 ) ]['subsection'] == true ) ? true : false;
3282 $subsectionsClass = $subsections ? ' hasSubSections' : '';
3283 $subsectionsClass .= ( ! isset( $section['fields'] ) || empty( $section['fields'] ) ) ? ' empty_section' : '';
3284 $extra_icon = $subsections ? '<span class="extraIconSubsections"><i class="el el-chevron-down">&nbsp;</i></span>' : '';
3285 // var_dump($section);
3286 $string .= '<li id="' . esc_attr( $k . $suffix ) . '_section_group_li" class="redux-group-tab-link-li' . esc_attr( $hide_section ) . esc_attr( $section['class'] ) . esc_attr( $subsectionsClass ) . '">';
3287 $string .= '<a href="javascript:void(0);" id="' . esc_attr( $k . $suffix ) . '_section_group_li_a" class="redux-group-tab-link-a" data-key="' . esc_attr( $k ) . '" data-rel="' . esc_attr( $k . $suffix ) . '">' . $extra_icon . $icon . '<span class="group_title">' . wp_kses_post( $section['title'] ) . '</span></a>';
3288
3289 $nextK = $k;
3290
3291 // Make sure you can make this a subsection
3292 if ( $subsections ) {
3293 $string .= '<ul id="' . esc_attr( $nextK . $suffix ) . '_section_group_li_subsections" class="subsection">';
3294 $doLoop = true;
3295
3296 while ( $doLoop ) {
3297 $nextK += 1;
3298 $display = true;
3299
3300 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
3301 if ( isset( $sections[ $nextK ]['panel'] ) && $sections[ $nextK ]['panel'] == false ) {
3302 $display = false;
3303 }
3304 }
3305
3306 if ( count( $sections ) < $nextK || ! isset( $sections[ $nextK ] ) || ! isset( $sections[ $nextK ]['subsection'] ) || $sections[ $nextK ]['subsection'] != true ) {
3307 $doLoop = false;
3308 } else {
3309 if ( ! $display ) {
3310 continue;
3311 }
3312
3313 $hide_sub = '';
3314 if ( isset( $sections[ $nextK ]['hidden'] ) ) {
3315 $hide_sub = ( $sections[ $nextK ]['hidden'] == true ) ? ' hidden ' : '';
3316 }
3317
3318 if ( ( isset( $this->args['icon_type'] ) && $this->args['icon_type'] == 'image' ) || ( isset( $sections[ $nextK ]['icon_type'] ) && $sections[ $nextK ]['icon_type'] == 'image' ) ) {
3319 // if( !empty( $this->args['icon_type'] ) && $this->args['icon_type'] == 'image' ) {
3320 $icon = ( ! isset( $sections[ $nextK ]['icon'] ) ) ? '' : '<img class="image_icon_type" src="' . esc_url( $sections[ $nextK ]['icon'] ) . '" /> ';
3321 } else {
3322 if ( ! empty( $sections[ $nextK ]['icon_class'] ) ) {
3323 $icon_class = ' ' . $sections[ $nextK ]['icon_class'];
3324 } elseif ( ! empty( $this->args['default_icon_class'] ) ) {
3325 $icon_class = ' ' . $this->args['default_icon_class'];
3326 } else {
3327 $icon_class = '';
3328 }
3329 $icon = ( ! isset( $sections[ $nextK ]['icon'] ) ) ? '' : '<i class="' . esc_attr( $sections[ $nextK ]['icon'] ) . esc_attr( $icon_class ) . '"></i> ';
3330 }
3331 if ( strpos( $icon, 'el-icon-' ) !== false ) {
3332 $icon = str_replace( 'el-icon-', 'el el-', $icon );
3333 }
3334
3335 $sections[ $nextK ]['class'] = isset( $sections[ $nextK ]['class'] ) ? $sections[ $nextK ]['class'] : '';
3336 $section[ $nextK ]['class'] = isset( $section[ $nextK ]['class'] ) ? $section[ $nextK ]['class'] : $sections[ $nextK ]['class'];
3337 $string .= '<li id="' . esc_attr( $nextK . $suffix ) . '_section_group_li" class="redux-group-tab-link-li ' . esc_attr( $hide_sub ) . esc_attr( $section[ $nextK ]['class'] ) . ( $icon ? ' hasIcon' : '' ) . '">';
3338 $string .= '<a href="javascript:void(0);" id="' . esc_attr( $nextK . $suffix ) . '_section_group_li_a" class="redux-group-tab-link-a" data-key="' . esc_attr( $nextK ) . '" data-rel="' . esc_attr( $nextK . $suffix ) . '">' . $icon . '<span class="group_title">' . wp_kses_post( $sections[ $nextK ]['title'] ) . '</span></a>';
3339 $string .= '</li>';
3340 }
3341 }
3342
3343 $string .= '</ul>';
3344 }
3345
3346 $string .= '</li>';
3347 }
3348
3349 return $string;
3350 }
3351 // section_menu()
3352
3353 /**
3354 * HTML OUTPUT.
3355 *
3356 * @since 1.0.0
3357 * @access public
3358 * @return void
3359 */
3360 public function generate_panel() {
3361 require_once 'core/panel.php';
3362 $panel = new reduxLegacyCorePanel( $this );
3363 $panel->init();
3364 $this->set_transients();
3365 }
3366
3367 /**
3368 * Section HTML OUTPUT.
3369 *
3370 * @since 1.0.0
3371 * @access public
3372 *
3373 * @param array $section
3374 *
3375 * @return void
3376 */
3377 public function _section_desc( $section ) {
3378 $id = rtrim( $section['id'], '_section' );
3379 $id = str_replace( $this->args['opt_name'], '', $id );
3380
3381 if ( isset( $this->sections[ $id ]['desc'] ) && ! empty( $this->sections[ $id ]['desc'] ) ) {
3382 echo '<div class="redux-section-desc">' . $this->sections[ $id ]['desc'] . '</div>';
3383 }
3384 }
3385
3386 /**
3387 * Field HTML OUTPUT.
3388 * Gets option from options array, then calls the specific field type class - allows extending by other devs
3389 *
3390 * @since 1.0.0
3391 *
3392 * @param array $field
3393 * @param string $v
3394 *
3395 * @return void
3396 */
3397 public function _field_input( $field, $v = null ) {
3398
3399 if ( isset( $field['callback'] ) && ( is_callable( $field['callback'] ) || ( is_string( $field['callback'] ) && function_exists( $field['callback'] ) ) ) ) {
3400
3401 $value = ( isset( $this->options[ $field['id'] ] ) ) ? $this->options[ $field['id'] ] : '';
3402
3403 /**
3404 * action 'redux-before-field-{opt_name}'
3405 *
3406 * @deprecated
3407 *
3408 * @param array $field field data
3409 * @param string $value field.id
3410 */
3411 do_action( "redux-before-field-{$this->args['opt_name']}", $field, $value ); // REMOVE
3412
3413 /**
3414 * action 'redux/field/{opt_name}/{field.type}/callback/before'
3415 *
3416 * @param array $field field data
3417 * @param string $value field.id
3418 */
3419 do_action_ref_array(
3420 "redux/field/{$this->args['opt_name']}/{$field['type']}/callback/before",
3421 array(
3422 &$field,
3423 &$value,
3424 )
3425 );
3426
3427 /**
3428 * action 'redux/field/{opt_name}/callback/before'
3429 *
3430 * @param array $field field data
3431 * @param string $value field.id
3432 */
3433 do_action_ref_array(
3434 "redux/field/{$this->args['opt_name']}/callback/before",
3435 array(
3436 &$field,
3437 &$value,
3438 )
3439 );
3440
3441 call_user_func( $field['callback'], $field, $value );
3442
3443 /**
3444 * action 'redux-after-field-{opt_name}'
3445 *
3446 * @deprecated
3447 *
3448 * @param array $field field data
3449 * @param string $value field.id
3450 */
3451 do_action( "redux-after-field-{$this->args['opt_name']}", $field, $value ); // REMOVE
3452
3453 /**
3454 * action 'redux/field/{opt_name}/{field.type}/callback/after'
3455 *
3456 * @param array $field field data
3457 * @param string $value field.id
3458 */
3459 do_action_ref_array(
3460 "redux/field/{$this->args['opt_name']}/{$field['type']}/callback/after",
3461 array(
3462 &$field,
3463 &$value,
3464 )
3465 );
3466
3467 /**
3468 * action 'redux/field/{opt_name}/callback/after'
3469 *
3470 * @param array $field field data
3471 * @param string $value field.id
3472 */
3473 do_action_ref_array(
3474 "redux/field/{$this->args['opt_name']}/callback/after",
3475 array(
3476 &$field,
3477 &$value,
3478 )
3479 );
3480
3481 return;
3482 }
3483
3484 if ( isset( $field['type'] ) ) {
3485
3486 // If the field is set not to display in the panel
3487 $display = true;
3488 if ( isset( $_GET['page'] ) && $_GET['page'] == $this->args['page_slug'] ) {
3489 if ( isset( $field['panel'] ) && $field['panel'] == false ) {
3490 $display = false;
3491 }
3492 }
3493
3494 if ( ! $display ) {
3495 return;
3496 }
3497
3498 $field_class = "ReduxFrameworkLegacy_{$field['type']}";
3499
3500 if ( ! class_exists( $field_class ) ) {
3501 // $class_file = apply_filters( 'redux/field/class/'.$field['type'], self::$_dir . 'inc/fields/' . $field['type'] . '/field_' . $field['type'] . '.php', $field ); // REMOVE
3502 /**
3503 * filter 'redux/{opt_name}/field/class/{field.type}'
3504 *
3505 * @param string field class file path
3506 * @param array $field field data
3507 */
3508 $class_file = apply_filters( "redux/{$this->args['opt_name']}/field/class/{$field['type']}", self::$_dir . "inc/fields/{$field['type']}/field_{$field['type']}.php", $field );
3509
3510 if ( $class_file ) {
3511 if ( file_exists( $class_file ) ) {
3512 require_once $class_file;
3513 }
3514 }
3515 }
3516
3517 if ( class_exists( $field_class ) ) {
3518 $value = isset( $this->options[ $field['id'] ] ) ? $this->options[ $field['id'] ] : '';
3519
3520 if ( $v != null ) {
3521 $value = $v;
3522 }
3523
3524 /**
3525 * action 'redux-before-field-{opt_name}'
3526 *
3527 * @deprecated
3528 *
3529 * @param array $field field data
3530 * @param string $value field id
3531 */
3532 do_action( "redux-before-field-{$this->args['opt_name']}", $field, $value ); // REMOVE
3533
3534 /**
3535 * action 'redux/field/{opt_name}/{field.type}/render/before'
3536 *
3537 * @param array $field field data
3538 * @param string $value field id
3539 */
3540 do_action_ref_array(
3541 "redux/field/{$this->args['opt_name']}/{$field['type']}/render/before",
3542 array(
3543 &$field,
3544 &$value,
3545 )
3546 );
3547
3548 /**
3549 * action 'redux/field/{$this->args['opt_name']}/render/before'
3550 *
3551 * @param array $field field data
3552 * @param string $value field id
3553 */
3554 do_action_ref_array(
3555 "redux/field/{$this->args['opt_name']}/render/before",
3556 array(
3557 &$field,
3558 &$value,
3559 )
3560 );
3561
3562 if ( ! isset( $field['name_suffix'] ) ) {
3563 $field['name_suffix'] = '';
3564 }
3565
3566 $render = new $field_class( $field, $value, $this );
3567 ob_start();
3568
3569 $render->render();
3570
3571 /*
3572 echo "<pre>";
3573 print_r($value);
3574 echo "</pre>";
3575 */
3576
3577 /**
3578 * filter 'redux-field-{opt_name}'
3579 *
3580 * @deprecated
3581 *
3582 * @param string rendered field markup
3583 * @param array $field field data
3584 */
3585 $_render = apply_filters( "redux-field-{$this->args['opt_name']}", ob_get_contents(), $field ); // REMOVE
3586
3587 /**
3588 * filter 'redux/field/{opt_name}/{field.type}/render/after'
3589 *
3590 * @param string rendered field markup
3591 * @param array $field field data
3592 */
3593 $_render = apply_filters( "redux/field/{$this->args['opt_name']}/{$field['type']}/render/after", $_render, $field );
3594
3595 /**
3596 * filter 'redux/field/{opt_name}/render/after'
3597 *
3598 * @param string rendered field markup
3599 * @param array $field field data
3600 */
3601 $_render = apply_filters( "redux/field/{$this->args['opt_name']}/render/after", $_render, $field );
3602
3603 ob_end_clean();
3604
3605 // save the values into a unique array in case we need it for dependencies
3606 $this->fieldsValues[ $field['id'] ] = ( isset( $value['url'] ) && is_array( $value ) ) ? $value['url'] : $value;
3607
3608 // create default data und class string and checks the dependencies of an object
3609 $class_string = '';
3610 $data_string = '';
3611
3612 $this->check_dependencies( $field );
3613
3614 /**
3615 * action 'redux/field/{opt_name}/{field.type}/fieldset/before/{opt_name}'
3616 *
3617 * @param array $field field data
3618 * @param string $value field id
3619 */
3620 do_action_ref_array(
3621 "redux/field/{$this->args['opt_name']}/{$field['type']}/fieldset/before/{$this->args['opt_name']}",
3622 array(
3623 &$field,
3624 &$value,
3625 )
3626 );
3627
3628 /**
3629 * action 'redux/field/{opt_name}/fieldset/before/{opt_name}'
3630 *
3631 * @param array $field field data
3632 * @param string $value field id
3633 */
3634 do_action_ref_array(
3635 "redux/field/{$this->args['opt_name']}/fieldset/before/{$this->args['opt_name']}",
3636 array(
3637 &$field,
3638 &$value,
3639 )
3640 );
3641
3642 // if ( ! isset( $field['fields'] ) || empty( $field['fields'] ) ) {
3643 $hidden = '';
3644 if ( isset( $field['hidden'] ) && $field['hidden'] ) {
3645 $hidden = 'hidden ';
3646 }
3647
3648 if ( isset( $field['full_width'] ) && $field['full_width'] == true ) {
3649 $class_string .= 'redux_remove_th';
3650 }
3651
3652 if ( isset( $field['fieldset_class'] ) && ! empty( $field['fieldset_class'] ) ) {
3653 $class_string .= ' ' . $field['fieldset_class'];
3654 }
3655
3656 echo '<fieldset id="' . $this->args['opt_name'] . '-' . $field['id'] . '" class="' . $hidden . 'redux-field-container redux-field redux-field-init redux-container-' . $field['type'] . ' ' . $class_string . '" data-id="' . $field['id'] . '" ' . $data_string . ' data-type="' . $field['type'] . '">';
3657 // }
3658
3659 echo $_render;
3660
3661 if ( ! empty( $field['desc'] ) ) {
3662 $field['description'] = $field['desc'];
3663 }
3664
3665 echo ( isset( $field['description'] ) && $field['type'] != 'info' && $field['type'] !== 'section' && ! empty( $field['description'] ) ) ? '<div class="description field-desc">' . $field['description'] . '</div>' : '';
3666
3667 // if ( ! isset( $field['fields'] ) || empty( $field['fields'] ) ) {
3668 echo '</fieldset>';
3669 // }
3670
3671 /**
3672 * action 'redux-after-field-{opt_name}'
3673 *
3674 * @deprecated
3675 *
3676 * @param array $field field data
3677 * @param string $value field id
3678 */
3679 do_action( "redux-after-field-{$this->args['opt_name']}", $field, $value ); // REMOVE
3680
3681 /**
3682 * action 'redux/field/{opt_name}/{field.type}/fieldset/after/{opt_name}'
3683 *
3684 * @param array $field field data
3685 * @param string $value field id
3686 */
3687 do_action_ref_array(
3688 "redux/field/{$this->args['opt_name']}/{$field['type']}/fieldset/after/{$this->args['opt_name']}",
3689 array(
3690 &$field,
3691 &$value,
3692 )
3693 );
3694
3695 /**
3696 * action 'redux/field/{opt_name}/fieldset/after/{opt_name}'
3697 *
3698 * @param array $field field data
3699 * @param string $value field id
3700 */
3701 do_action_ref_array(
3702 "redux/field/{$this->args['opt_name']}/fieldset/after/{$this->args['opt_name']}",
3703 array(
3704 &$field,
3705 &$value,
3706 )
3707 );
3708 }
3709 }
3710 }
3711 // _field_input()
3712
3713 /**
3714 * Can Output CSS
3715 * Check if a field meets its requirements before outputting to CSS
3716 *
3717 * @param $field
3718 *
3719 * @return bool
3720 */
3721 public function _can_output_css( $field ) {
3722 $return = true;
3723
3724 $field = apply_filters( "redux/field/{$this->args['opt_name']}/_can_output_css", $field );
3725 if ( isset( $field['force_output'] ) && $field['force_output'] == true ) {
3726 return $return;
3727 }
3728
3729 if ( ! empty( $field['required'] ) ) {
3730 if ( isset( $field['required'][0] ) ) {
3731 if ( ! is_array( $field['required'][0] ) && count( $field['required'] ) == 3 ) {
3732 $parentValue = isset( $GLOBALS[ $this->args['global_variable'] ][ $field['required'][0] ] ) ? $GLOBALS[ $this->args['global_variable'] ][ $field['required'][0] ] : '';
3733 $checkValue = $field['required'][2];
3734 $operation = $field['required'][1];
3735 $return = $this->compareValueDependencies( $parentValue, $checkValue, $operation );
3736 } elseif ( is_array( $field['required'][0] ) ) {
3737 foreach ( $field['required'] as $required ) {
3738 if ( ! is_array( $required[0] ) && count( $required ) == 3 ) {
3739 $parentValue = $GLOBALS[ $this->args['global_variable'] ][ $required[0] ];
3740 $checkValue = $required[2];
3741 $operation = $required[1];
3742 $return = $this->compareValueDependencies( $parentValue, $checkValue, $operation );
3743 }
3744 if ( ! $return ) {
3745 return $return;
3746 }
3747 }
3748 }
3749 }
3750 }
3751
3752 return $return;
3753 }
3754 // _can_output_css
3755
3756 /**
3757 * Checks dependencies between objects based on the $field['required'] array
3758 * If the array is set it needs to have exactly 3 entries.
3759 * The first entry describes which field should be monitored by the current field. eg: "content"
3760 * The second entry describes the comparison parameter. eg: "equals, not, is_larger, is_smaller ,contains"
3761 * The third entry describes the value that we are comparing against.
3762 * Example: if the required array is set to array('content','equals','Hello World'); then the current
3763 * field will only be displayed if the field with id "content" has exactly the value "Hello World"
3764 *
3765 * @param array $field
3766 *
3767 * @return array $params
3768 */
3769 public function check_dependencies( $field ) {
3770 // $params = array('data_string' => "", 'class_string' => "");
3771 if ( isset( $field['ajax_save'] ) && $field['ajax_save'] == false ) {
3772 $this->reload_fields[] = $field['id'];
3773 }
3774
3775 if ( ! empty( $field['required'] ) ) {
3776 if ( ! isset( $this->required_child[ $field['id'] ] ) ) {
3777 $this->required_child[ $field['id'] ] = array();
3778 }
3779
3780 if ( ! isset( $this->required[ $field['id'] ] ) ) {
3781 $this->required[ $field['id'] ] = array();
3782 }
3783
3784 if ( is_array( $field['required'][0] ) ) {
3785
3786 foreach ( $field['required'] as $value ) {
3787 if ( is_array( $value ) && count( $value ) == 3 ) {
3788 $data = array();
3789 $data['parent'] = $value[0];
3790 $data['operation'] = $value[1];
3791 $data['checkValue'] = $value[2];
3792
3793 $this->required[ $data['parent'] ][ $field['id'] ][] = $data;
3794
3795 if ( ! in_array( $data['parent'], $this->required_child[ $field['id'] ] ) ) {
3796 $this->required_child[ $field['id'] ][] = $data;
3797 }
3798
3799 $this->checkRequiredDependencies( $field, $data );
3800 }
3801 }
3802 } else {
3803 $data = array();
3804 $data['parent'] = $field['required'][0];
3805 $data['operation'] = $field['required'][1];
3806 $data['checkValue'] = $field['required'][2];
3807
3808 $this->required[ $data['parent'] ][ $field['id'] ][] = $data;
3809
3810 if ( ! in_array( $data['parent'], $this->required_child[ $field['id'] ] ) ) {
3811 $this->required_child[ $field['id'] ][] = $data;
3812 }
3813
3814 $this->checkRequiredDependencies( $field, $data );
3815 }
3816 }
3817 // return $params;
3818 }
3819
3820 // Compare data for required field
3821 private function compareValueDependencies( $parentValue, $checkValue, $operation ) {
3822 $return = false;
3823 switch ( $operation ) {
3824 case '=':
3825 case 'equals':
3826 $data['operation'] = '=';
3827
3828 if ( is_array( $parentValue ) ) {
3829 foreach ( $parentValue as $idx => $val ) {
3830 if ( is_array( $checkValue ) ) {
3831 foreach ( $checkValue as $i => $v ) {
3832 if ( ReduxLegacy_Helpers::makeBoolStr( $val ) === ReduxLegacy_Helpers::makeBoolStr( $v ) ) {
3833 $return = true;
3834 }
3835 }
3836 } elseif ( ReduxLegacy_Helpers::makeBoolStr( $val ) === ReduxLegacy_Helpers::makeBoolStr( $checkValue ) ) {
3837 $return = true;
3838 }
3839 }
3840 } else {
3841 // var_dump($checkValue);
3842 if ( is_array( $checkValue ) ) {
3843 foreach ( $checkValue as $i => $v ) {
3844 if ( ReduxLegacy_Helpers::makeBoolStr( $parentValue ) === ReduxLegacy_Helpers::makeBoolStr( $v ) ) {
3845 $return = true;
3846 }
3847 }
3848 } elseif ( ReduxLegacy_Helpers::makeBoolStr( $parentValue ) === ReduxLegacy_Helpers::makeBoolStr( $checkValue ) ) {
3849 $return = true;
3850 }
3851 }
3852 break;
3853
3854 case '!=':
3855 case 'not':
3856 $data['operation'] = '!==';
3857 if ( is_array( $parentValue ) ) {
3858 foreach ( $parentValue as $idx => $val ) {
3859 if ( is_array( $checkValue ) ) {
3860 foreach ( $checkValue as $i => $v ) {
3861 if ( ReduxLegacy_Helpers::makeBoolStr( $val ) !== ReduxLegacy_Helpers::makeBoolStr( $v ) ) {
3862 $return = true;
3863 }
3864 }
3865 } elseif ( ReduxLegacy_Helpers::makeBoolStr( $val ) !== ReduxLegacy_Helpers::makeBoolStr( $checkValue ) ) {
3866 $return = true;
3867 }
3868 }
3869 } elseif ( is_array( $checkValue ) ) {
3870 foreach ( $checkValue as $i => $v ) {
3871 if ( ReduxLegacy_Helpers::makeBoolStr( $parentValue ) !== ReduxLegacy_Helpers::makeBoolStr( $v ) ) {
3872 $return = true;
3873 }
3874 }
3875 } elseif ( ReduxLegacy_Helpers::makeBoolStr( $parentValue ) !== ReduxLegacy_Helpers::makeBoolStr( $checkValue ) ) {
3876 $return = true;
3877 }
3878
3879 // if ( is_array( $checkValue ) ) {
3880 // if ( ! in_array( $parentValue, $checkValue ) ) {
3881 // $return = true;
3882 // }
3883 // } else {
3884 // if ( $parentValue != $checkValue ) {
3885 // $return = true;
3886 // } else if ( is_array( $parentValue ) ) {
3887 // if ( ! in_array( $checkValue, $parentValue ) ) {
3888 // $return = true;
3889 // }
3890 // }
3891 // }
3892 break;
3893 case '>':
3894 case 'greater':
3895 case 'is_larger':
3896 $data['operation'] = '>';
3897 if ( $parentValue > $checkValue ) {
3898 $return = true;
3899 }
3900 break;
3901 case '>=':
3902 case 'greater_equal':
3903 case 'is_larger_equal':
3904 $data['operation'] = '>=';
3905 if ( $parentValue >= $checkValue ) {
3906 $return = true;
3907 }
3908 break;
3909 case '<':
3910 case 'less':
3911 case 'is_smaller':
3912 $data['operation'] = '<';
3913 if ( $parentValue < $checkValue ) {
3914 $return = true;
3915 }
3916 break;
3917 case '<=':
3918 case 'less_equal':
3919 case 'is_smaller_equal':
3920 $data['operation'] = '<=';
3921 if ( $parentValue <= $checkValue ) {
3922 $return = true;
3923 }
3924 break;
3925 case 'contains':
3926 if ( is_array( $parentValue ) ) {
3927 $parentValue = implode( ',', $parentValue );
3928 }
3929
3930 if ( is_array( $checkValue ) ) {
3931 foreach ( $checkValue as $idx => $opt ) {
3932 if ( strpos( $parentValue, (string) $opt ) !== false ) {
3933 $return = true;
3934 }
3935 }
3936 } elseif ( strpos( $parentValue, (string) $checkValue ) !== false ) {
3937 $return = true;
3938 }
3939
3940 break;
3941 case 'doesnt_contain':
3942 case 'not_contain':
3943 if ( is_array( $parentValue ) ) {
3944 $parentValue = implode( ',', $parentValue );
3945 }
3946
3947 if ( is_array( $checkValue ) ) {
3948 foreach ( $checkValue as $idx => $opt ) {
3949 if ( strpos( $parentValue, (string) $opt ) === false ) {
3950 $return = true;
3951 }
3952 }
3953 } elseif ( strpos( $parentValue, (string) $checkValue ) === false ) {
3954 $return = true;
3955 }
3956
3957 break;
3958 case 'is_empty_or':
3959 if ( empty( $parentValue ) || $parentValue == $checkValue ) {
3960 $return = true;
3961 }
3962 break;
3963 case 'not_empty_and':
3964 if ( ! empty( $parentValue ) && $parentValue != $checkValue ) {
3965 $return = true;
3966 }
3967 break;
3968 case 'is_empty':
3969 case 'empty':
3970 case '!isset':
3971 if ( empty( $parentValue ) || $parentValue == '' || $parentValue == null ) {
3972 $return = true;
3973 }
3974 break;
3975 case 'not_empty':
3976 case '!empty':
3977 case 'isset':
3978 if ( ! empty( $parentValue ) && $parentValue != '' && $parentValue != null ) {
3979 $return = true;
3980 }
3981 break;
3982 }
3983
3984 return $return;
3985 }
3986
3987 private function checkRequiredDependencies( $field, $data ) {
3988 // required field must not be hidden. otherwise hide this one by default
3989
3990 if ( ! in_array( $data['parent'], $this->fieldsHidden ) && ( ! isset( $this->folds[ $field['id'] ] ) || $this->folds[ $field['id'] ] != 'hide' ) ) {
3991 if ( isset( $this->options[ $data['parent'] ] ) ) {
3992 $return = $this->compareValueDependencies( $this->options[ $data['parent'] ], $data['checkValue'], $data['operation'] );
3993 // $return = $this->compareValueDependencies( $data['parent'], $data['checkValue'], $data['operation'] );
3994 }
3995 }
3996
3997 if ( ( isset( $return ) && $return ) && ( ! isset( $this->folds[ $field['id'] ] ) || $this->folds[ $field['id'] ] != 'hide' ) ) {
3998 $this->folds[ $field['id'] ] = 'show';
3999 } else {
4000 $this->folds[ $field['id'] ] = 'hide';
4001 if ( ! in_array( $field['id'], $this->fieldsHidden ) ) {
4002 $this->fieldsHidden[] = $field['id'];
4003 }
4004 }
4005 }
4006
4007 /**
4008 * converts an array into a html data string
4009 *
4010 * @param array $data example input: array('id'=>'true')
4011 *
4012 * @return string $data_string example output: data-id='true'
4013 */
4014 public function create_data_string( $data = array() ) {
4015 $data_string = '';
4016
4017 foreach ( $data as $key => $value ) {
4018 if ( is_array( $value ) ) {
4019 $value = implode( '|', $value );
4020 }
4021 $data_string .= " data-$key='$value' ";
4022 }
4023
4024 return $data_string;
4025 }
4026
4027 /**
4028 * Parses the string into variables without the max_input_vars limitation.
4029 *
4030 * @since 3.5.7.11
4031 * @author harunbasic
4032 * @access public
4033 *
4034 * @param string $string
4035 *
4036 * @return array $result
4037 */
4038 function redux_parse_str( $string ) {
4039 if ( '' == $string ) {
4040 return false;
4041 }
4042
4043 $result = array();
4044 $pairs = explode( '&', $string );
4045
4046 foreach ( $pairs as $key => $pair ) {
4047 // use the original parse_str() on each element
4048 parse_str( $pair, $params );
4049
4050 $k = key( $params );
4051
4052 if ( ! isset( $result[ $k ] ) ) {
4053 $result += $params;
4054 } else {
4055 $result[ $k ] = $this->redux_array_merge_recursive_distinct( $result[ $k ], $params[ $k ] );
4056 }
4057 }
4058
4059 return $result;
4060 }
4061
4062
4063 /**
4064 * Merge arrays without converting values with duplicate keys to arrays as array_merge_recursive does.
4065 * As seen here http://php.net/manual/en/function.array-merge-recursive.php#92195
4066 *
4067 * @since 3.5.7.11
4068 * @author harunbasic
4069 * @access public
4070 *
4071 * @param array $array1
4072 * @param array $array2
4073 *
4074 * @return array $merged
4075 */
4076 function redux_array_merge_recursive_distinct( array $array1, array $array2 ) {
4077 $merged = $array1;
4078
4079 foreach ( $array2 as $key => $value ) {
4080 if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
4081 $merged[ $key ] = $this->redux_array_merge_recursive_distinct( $merged[ $key ], $value );
4082 } elseif ( is_numeric( $key ) && isset( $merged[ $key ] ) ) {
4083 $merged[] = $value;
4084 } else {
4085 $merged[ $key ] = $value;
4086 }
4087 }
4088
4089 return $merged;
4090 }
4091
4092 private function change_demo_defaults() {
4093 if ( $this->args['dev_mode'] == true || ReduxLegacy_Helpers::isLocalHost() == true ) {
4094 if ( ! empty( $this->args['admin_bar_links'] ) ) {
4095 foreach ( $this->args['admin_bar_links'] as $idx => $arr ) {
4096 if ( is_array( $arr ) && ! empty( $arr ) ) {
4097 foreach ( $arr as $x => $y ) {
4098 if ( strpos( strtolower( $y ), 'redux' ) !== false ) {
4099 $msg = __( '<strong>Redux Framework Notice: </strong>There are references to the Redux Framework support site in your config\'s <code>admin_bar_links</code> argument. This is sample data. Please change or remove this data before shipping your product.', 'redux-framework' );
4100 $this->display_arg_change_notice( 'admin', $msg );
4101 $this->omit_admin_items = true;
4102 continue;
4103 }
4104 }
4105 }
4106 }
4107 }
4108
4109 if ( ! empty( $this->args['share_icons'] ) ) {
4110 foreach ( $this->args['share_icons'] as $idx => $arr ) {
4111 if ( is_array( $arr ) && ! empty( $arr ) ) {
4112 foreach ( $arr as $x => $y ) {
4113 if ( ! $this->omit_share_icons ) {
4114 if ( strpos( strtolower( $y ), 'redux' ) !== false ) {
4115 $msg = __( '<strong>Redux Framework Notice: </strong>There are references to the Redux Framework support site in your config\'s <code>share_icons</code> argument. This is sample data. Please change or remove this data before shipping your product.', 'redux-framework' );
4116 $this->display_arg_change_notice( 'share', $msg );
4117 $this->omit_share_icons = true;
4118 continue;
4119 }
4120 }
4121 }
4122 }
4123 }
4124 }
4125 }
4126 }
4127
4128 private function display_arg_change_notice( $mode, $msg = '' ) {
4129 if ( $mode == 'admin' ) {
4130 if ( ! $this->omit_admin_items ) {
4131 $data = array(
4132 'parent' => $this,
4133 'type' => 'error',
4134 'msg' => $msg,
4135 'id' => 'admin_config',
4136 'dismiss' => true,
4137 );
4138
4139 ReduxLegacy_Admin_Notices::set_notice( $data );
4140 }
4141 }
4142
4143 if ( $mode == 'share' ) {
4144 if ( ! $this->omit_share_icons ) {
4145 $data = array(
4146 'parent' => $this,
4147 'type' => 'error',
4148 'msg' => $msg,
4149 'id' => 'share_config',
4150 'dismiss' => true,
4151 );
4152
4153 ReduxLegacy_Admin_Notices::set_notice( $data );
4154 }
4155 }
4156 }
4157
4158
4159 /**
4160 * Checks a nested capabilities array or string to determine if the current user meets the requirements.
4161 *
4162 * @since 3.6.3.4
4163 *
4164 * @param string|array $capabilities Permission string or array to check. See self::user_can() for details.
4165 * @param int $object_id (Optional) ID of the specific object to check against if capability is a "meta" cap.
4166 * e.g. 'edit_post', 'edit_user', 'edit_page', etc.,
4167 *
4168 * @return bool Whether or not the user meets the requirements. False on invalid user.
4169 */
4170 public static function current_user_can( $capabilities ) {
4171 $current_user = wp_get_current_user();
4172
4173 if ( empty( $current_user ) ) {
4174 return false;
4175 }
4176
4177 $name_arr = func_get_args();
4178 $args = array_merge( array( $current_user ), $name_arr );
4179
4180 return self::user_can( ...$args );
4181 // return call_user_func_array( array( 'self', 'user_can' ), $args );
4182 }
4183
4184
4185 /**
4186 * Checks a nested capabilities array or string to determine if the user meets the requirements.
4187 *
4188 * You can pass in a simple string like 'edit_posts' or an array of conditions.
4189 *
4190 * The capability 'relation' is reserved for controlling the relation mode (AND/OR), which defaults to AND.
4191 *
4192 * Max depth of 30 levels. False is returned for any conditions exceeding max depth.
4193 *
4194 * If you want to check meta caps, you must also pass the object ID on which to check against.
4195 * If you get the error: PHP Notice: Undefined offset: 0 in /wp-includes/capabilities.php, you didn't
4196 * pass the required $object_id.
4197 *
4198 * @since 3.6.3.4
4199 *
4200 * @example
4201 * ::user_can( 42, 'edit_pages' ); // Checks if user ID 42 has the 'edit_pages' cap.
4202 * ::user_can( 42, 'edit_page', 17433 ); // Checks if user ID 42 has the 'edit_page' cap for post ID 17433.
4203 * ::user_can( 42, array( 'edit_pages', 'edit_posts' ) ); // Checks if user ID 42 has both the 'edit_pages' and 'edit_posts' caps.
4204 *
4205 * @param int|object $user User ID or WP_User object to check. Defaults to the current user.
4206 * @param string|array $capabilities Capability string or array to check. The array lets you use multiple
4207 * conditions to determine if a user has permission.
4208 * Invalid conditions are skipped (conditions which aren't a string/array/bool/number(cast to bool)).
4209 * Example array where the user needs to have either the 'edit_posts' capability OR doesn't have the
4210 * 'delete_pages' cap OR has the 'update_plugins' AND 'add_users' capabilities.
4211 * array(
4212 * 'relation' => 'OR', // Optional, defaults to AND.
4213 * 'edit_posts', // Equivalent to 'edit_posts' => true,
4214 * 'delete_pages' => false, // Tests that the user DOESN'T have this capability
4215 * array( // Nested conditions array (up to 30 nestings)
4216 * 'update_plugins',
4217 * 'add_users',
4218 * ),
4219 * )
4220 *
4221 * @param int $object_id (Optional) ID of the specific object to check against if capability is a "meta" cap.
4222 * e.g. 'edit_post', 'edit_user', 'edit_page', etc.,
4223 *
4224 * @return bool Whether or not the user meets the requirements.
4225 * Will always return false for:
4226 * - Invalid/missing user
4227 * - If the $capabilities is not a string or array
4228 * - Max nesting depth exceeded (for that level)
4229 */
4230 public static function user_can( $user, $capabilities, $object_id = null ) {
4231 static $depth = 0;
4232
4233 if ( $depth >= 30 ) {
4234 return false;
4235 }
4236
4237 if ( empty( $user ) ) {
4238 return false;
4239 }
4240
4241 if ( ! is_object( $user ) ) {
4242 $user = get_userdata( $user );
4243 }
4244
4245 if ( is_string( $capabilities ) ) {
4246 // Simple string capability check
4247 $args = array(
4248 $user,
4249 $capabilities,
4250 );
4251
4252 if ( $object_id !== null ) {
4253 $args[] = $object_id;
4254 }
4255
4256 return call_user_func_array( 'user_can', $args );
4257 } else {
4258 // Only strings and arrays are allowed as valid capabilities
4259 if ( ! is_array( $capabilities ) ) {
4260 return false;
4261 }
4262 }
4263
4264 // Capability array check
4265 $or = false;
4266
4267 foreach ( $capabilities as $key => $value ) {
4268 if ( $key === 'relation' ) {
4269 if ( $value === 'OR' ) {
4270 $or = true;
4271 }
4272
4273 continue;
4274 }
4275
4276 /**
4277 * Rules can be in 4 different formats:
4278 * [
4279 * [0] => 'foobar',
4280 * [1] => array(...),
4281 * 'foobar' => false,
4282 * 'foobar' => array(...),
4283 * ]
4284 */
4285 if ( is_numeric( $key ) ) {
4286 // Numeric key
4287 if ( is_string( $value ) ) {
4288 // Numeric key with a string value is the capability string to check
4289 // [0] => 'foobar'
4290 $args = array( $user, $value );
4291
4292 if ( $object_id !== null ) {
4293 $args[] = $object_id;
4294 }
4295
4296 $expression_result = call_user_func_array( 'user_can', $args ) === true;
4297 } elseif ( is_array( $value ) ) {
4298 // [0] => array(...)
4299 ++$depth;
4300
4301 $expression_result = self::user_can( $user, $value, $object_id );
4302
4303 --$depth;
4304 } else {
4305 // Invalid types are skipped
4306 continue;
4307 }
4308 } else {
4309 // Non-numeric key
4310 if ( is_scalar( $value ) ) {
4311 // 'foobar' => false
4312 $args = array( $user, $key );
4313
4314 if ( $object_id !== null ) {
4315 $args[] = $object_id;
4316 }
4317
4318 $expression_result = call_user_func_array( 'user_can', $args ) === (bool) $value;
4319 } elseif ( is_array( $value ) ) {
4320 // 'foobar' => array(...)
4321 ++$depth;
4322
4323 $expression_result = self::user_can( $user, $value, $object_id );
4324
4325 --$depth;
4326 } else {
4327 // Invalid types are skipped
4328 continue;
4329 }
4330 }
4331
4332 // Check after every evaluation if we know enough to return a definitive answer
4333 if ( $or ) {
4334 if ( $expression_result ) {
4335 // If the relation is OR, return on the first true expression
4336 return true;
4337 }
4338 } elseif ( ! $expression_result ) {
4339 // If the relation is AND, return on the first false expression
4340 return false;
4341 }
4342 }
4343
4344 // If we get this far on an OR, then it failed
4345 // If we get this far on an AND, then it succeeded
4346 return ! $or;
4347 }
4348 }
4349
4350 // ReduxFrameworkLegacy
4351
4352 /**
4353 * action 'redux/init'
4354 *
4355 * @param null
4356 */
4357 ReduxFrameworkLegacy::init();
4358 do_action( 'redux/init' );
4359
4360 } // class_exists('ReduxFrameworkLegacy')
4361