PluginProbe
QuadMenu – Mega Menu / 2.0.3
QuadMenu – Mega Menu v2.0.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 / lib / ReduxCore / framework.php

framework.php in QuadMenu – Mega Menu 2.0.3, at lib/ReduxCore/framework.php

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