class-redux-options-constructor.php (33110B)
1 <?php 2 /** 3 * Redux Options Class 4 * 5 * @class Redux_Options 6 * @version 3.0.0 7 * @package Redux Framework/Classes 8 */ 9 10 defined( 'ABSPATH' ) || exit; 11 12 if ( ! class_exists( 'Redux_Options_Constructor', false ) ) { 13 14 /** 15 * Class Redux_Options 16 */ 17 class Redux_Options_Constructor extends Redux_Class { 18 19 /** 20 * Array to hold single panel data. 21 * 22 * @var array 23 */ 24 public $no_panel = array(); 25 26 /** 27 * Array to hold single panel sections. 28 * 29 * @var array 30 */ 31 private $no_panel_section = array(); 32 33 /** 34 * Array to hold hidden fields. 35 * 36 * @var array 37 */ 38 private $hidden_perm_fields = array(); 39 40 /** 41 * Array to hold hidden sections. 42 * 43 * @var array 44 */ 45 public $hidden_perm_sections = array(); 46 47 /** 48 * Redux_Options constructor. 49 * 50 * @param object $parent ReduxFramework pointer. 51 */ 52 public function __construct( $parent ) { 53 parent::__construct( $parent ); 54 55 add_action( 'admin_init', array( $this, 'register' ) ); 56 57 } 58 59 /** 60 * If we switch language in wpml the id of the post/page selected will be in the wrong language 61 * So it won't appear as selected in the list of options and will be lost on next save, this fixes this by translating this id 62 * Bonus it also gives the user the id of the post in the right language when they retrieve it 63 * The recursion allows for it to work in a repeatable field. 64 * 65 * @param array $sections Sections array. 66 * @param array $options_values Values array. 67 */ 68 private function translate_data_field_recursive( array $sections, array &$options_values ) { 69 foreach ( $sections as $key => $section ) { 70 if ( 'fields' === $key ) { 71 foreach ( $section as $field ) { 72 if ( ! empty( $field['id'] ) && ! empty( $field['data'] ) && ! empty( $options_values[ $field['id'] ] ) && \Redux_Helpers::is_integer( $options_values[ $field['id'] ] ) ) { 73 $options_values[ $field['id'] ] = apply_filters( 'wpml_object_id', $options_values[ $field['id'] ], $field['data'], true ); 74 } 75 } 76 } elseif ( is_array( $section ) && ! empty( $section ) ) { 77 $this->translate_data_field_recursive( $section, $options_values ); 78 } 79 } 80 } 81 82 /** 83 * Retrieves the options. 84 */ 85 public function get() { 86 $core = $this->core(); 87 88 $defaults = false; 89 90 if ( ! empty( $core->defaults ) ) { 91 $defaults = $core->defaults; 92 } 93 94 if ( empty( $core->args ) ) { 95 return; 96 } 97 98 switch ( $core->args['database'] ) { 99 case 'transient': 100 $result = get_transient( $core->args['opt_name'] . '-transient' ); 101 break; 102 case 'theme_mods': 103 $result = get_theme_mod( $core->args['opt_name'] . '-mods' ); 104 break; 105 case 'theme_mods_expanded': 106 $result = get_theme_mods(); 107 break; 108 case 'network': 109 $result = get_site_option( $core->args['opt_name'], array() ); 110 break; 111 default: 112 $result = get_option( $core->args['opt_name'], array() ); 113 114 } 115 116 if ( empty( $result ) && empty( $defaults ) ) { 117 return; 118 } 119 120 if ( empty( $result ) && ! empty( $defaults ) ) { 121 $results = $defaults; 122 $this->set( $results ); 123 } else { 124 $core->options = $result; 125 } 126 127 // Don't iterate unnecessarily. 128 if ( has_filter( 'wpml_object_id' ) ) { 129 $this->translate_data_field_recursive( $core->sections, $core->options ); 130 } 131 132 /** 133 * Action 'redux/options/{opt_name}/options' 134 * 135 * @param mixed $value option values 136 */ 137 138 // phpcs:ignore WordPress.NamingConventions.ValidHookName 139 $core->options = apply_filters( "redux/options/{$core->args['opt_name']}/options", $core->options, $core->sections ); 140 141 // Get transient values. 142 $core->transient_class->get(); 143 144 // Set a global variable by the global_variable argument. 145 $this->set_global_variable( $core ); 146 } 147 148 /** 149 * ->set_options(); This is used to set an arbitrary option in the options array 150 * 151 * @since ReduxFramework 3.0.0 152 * 153 * @param string|array $value the value of the option being added. 154 */ 155 public function set( $value = '' ) { 156 $core = $this->core(); 157 158 $core->transients['last_save'] = time(); 159 160 if ( ! empty( $value ) ) { 161 $core->options = $value; 162 163 switch ( $core->args['database'] ) { 164 case 'transient': 165 set_transient( $core->args['opt_name'] . '-transient', $value, $core->args['transient_time'] ); 166 break; 167 case 'theme_mods': 168 set_theme_mod( $core->args['opt_name'] . '-mods', $value ); 169 break; 170 case 'theme_mods_expanded': 171 foreach ( $value as $k => $v ) { 172 set_theme_mod( $k, $v ); 173 } 174 break; 175 case 'network': 176 update_site_option( $core->args['opt_name'], $value ); 177 break; 178 default: 179 update_option( $core->args['opt_name'], $value ); 180 181 } 182 183 // Store the changed values in the transient. 184 if ( $value !== $core->options ) { 185 foreach ( $value as $k => $v ) { 186 if ( ! isset( $core->options[ $k ] ) ) { 187 $core->options[ $k ] = ''; 188 } elseif ( $v === $core->options[ $k ] ) { 189 unset( $core->options[ $k ] ); 190 } 191 } 192 193 $core->transients['changed_values'] = $core->options; 194 } 195 196 $core->options = $value; 197 198 // Set a global variable by the global_variable argument. 199 $this->set_global_variable( $core ); 200 201 // Saving the transient values. 202 $core->transient_class->set(); 203 } 204 } 205 206 /** 207 * Set a global variable by the global_variable argument 208 * 209 * @param object $core ReduxFramework core object. 210 * 211 * @return void (global was set) 212 * @since 3.1.5 213 */ 214 private function set_global_variable( $core ): void { 215 if ( ! empty( $core->args['global_variable'] ) ) { 216 $options_global = $core->args['global_variable']; 217 218 /** 219 * Filter 'redux/options/{opt_name}/global_variable' 220 * 221 * @param array $value option value to set global_variable with 222 */ 223 224 // phpcs:ignore WordPress.NamingConventions.ValidHookName 225 $GLOBALS[ $options_global ] = apply_filters( "redux/options/{$core->args['opt_name']}/global_variable", $core->options ); 226 227 // Last save key. 228 if ( isset( $core->transients['last_save'] ) ) { 229 $GLOBALS[ $options_global ]['REDUX_LAST_SAVE'] = $core->transients['last_save']; 230 } 231 232 // Last compiler hook key. 233 if ( isset( $core->transients['last_compiler'] ) ) { 234 $GLOBALS[ $options_global ]['REDUX_LAST_COMPILER'] = $core->transients['last_compiler']; 235 } 236 } 237 } 238 239 /** 240 * Register Option for use 241 * 242 * @since 1.0.0 243 * @access public 244 * @return void 245 */ 246 public function register() { 247 $core = $this->core(); 248 249 if ( ! is_object( $core ) ) { 250 return; 251 } 252 253 if ( true === $core->args['options_api'] ) { 254 register_setting( 255 $core->args['opt_name'] . '_group', 256 $core->args['opt_name'], 257 array( 258 $this, 259 'validate_options', 260 ) 261 ); 262 } 263 264 if ( is_null( $core->sections ) ) { 265 return; 266 } 267 268 if ( empty( $core->options_defaults ) ) { 269 $core->options_defaults = $core->_default_values(); 270 } 271 272 $run_update = false; 273 274 foreach ( $core->sections as $k => $section ) { 275 if ( isset( $section['type'] ) && 'divide' === $section['type'] ) { 276 continue; 277 } 278 279 $display = true; 280 281 if ( isset( $_GET['page'] ) && $_GET['page'] === $core->args['page_slug'] ) { // phpcs:ignore WordPress.Security.NonceVerification 282 if ( isset( $section['panel'] ) && false === $section['panel'] ) { 283 $display = false; 284 } 285 } 286 287 /** 288 * Filter 'redux/options/{opt_name}/section/{section.id}' 289 * 290 * @param array $section section configuration 291 */ 292 if ( isset( $section['id'] ) ) { 293 // phpcs:ignore WordPress.NamingConventions.ValidHookName 294 $section = apply_filters( "redux/options/{$core->args['opt_name']}/section/{$section['id']}", $section ); 295 } 296 297 if ( empty( $section ) ) { 298 unset( $core->sections[ $k ] ); 299 continue; 300 } 301 302 if ( ! isset( $section['title'] ) ) { 303 $section['title'] = ''; 304 } 305 306 if ( isset( $section['customizer_only'] ) && true === $section['customizer_only'] ) { 307 $section['panel'] = false; 308 $core->sections[ $k ] = $section; 309 } 310 311 $heading = $section['heading'] ?? $section['title']; 312 313 if ( isset( $section['permissions'] ) && false !== $section['permissions'] ) { 314 if ( ! Redux_Helpers::current_user_can( $section['permissions'] ) ) { 315 $core->hidden_perm_sections[] = $section['title']; 316 317 foreach ( $section['fields'] as $num => $field_data ) { 318 $field_type = $field_data['type']; 319 320 if ( 'section' !== $field_type || 'divide' !== $field_type || 'info' !== $field_type || 'raw' !== $field_type ) { 321 $field_id = $field_data['id']; 322 $default = $core->options_defaults[ $field_id ] ?? ''; 323 $data = $core->options[ $field_id ] ?? $default; 324 325 $this->hidden_perm_fields[ $field_id ] = $data; 326 } 327 } 328 329 continue; 330 } 331 } 332 333 if ( ! $display || ! function_exists( 'add_settings_section' ) ) { 334 $this->no_panel_section[ $k ] = $section; 335 } else { 336 add_settings_section( 337 $core->args['opt_name'] . $k . '_section', 338 $heading, 339 array( 340 $core->render_class, 341 'section_desc', 342 ), 343 $core->args['opt_name'] . $k . '_section_group' 344 ); 345 } 346 347 $section_ident = false; 348 if ( isset( $section['fields'] ) ) { 349 foreach ( $section['fields'] as $fieldk => $field ) { 350 if ( ! isset( $field['type'] ) ) { 351 continue; // You need a type! 352 } 353 354 if ( 'info' === $field['type'] && isset( $field['raw_html'] ) && true === $field['raw_html'] ) { 355 $field['type'] = 'raw'; 356 $field['content'] = $field['desc']; 357 $field['desc'] = ''; 358 $core->sections[ $k ]['fields'][ $fieldk ] = $field; 359 } elseif ( 'info' === $field['type'] ) { 360 if ( ! isset( $field['full_width'] ) ) { 361 $field['full_width'] = true; 362 $core->sections[ $k ]['fields'][ $fieldk ] = $field; 363 } 364 } 365 366 if ( 'raw' === $field['type'] ) { 367 if ( isset( $field['align'] ) ) { 368 $field['full_width'] = ! $field['align']; 369 unset( $field['align'] ); 370 } elseif ( ! isset( $field['full_width'] ) ) { 371 $field['full_width'] = true; 372 } 373 $core->sections[ $k ]['fields'][ $fieldk ] = $field; 374 } 375 376 /** 377 * Filter 'redux/options/{opt_name}/field/{field.id}' 378 * 379 * @param array $field field config 380 */ 381 382 // phpcs:ignore WordPress.NamingConventions.ValidHookName 383 $field = apply_filters( "redux/options/{$core->args['opt_name']}/field/{$field['id']}/register", $field ); 384 385 $core->field_types[ $field['type'] ] = $core->field_types[ $field['type'] ] ?? array(); 386 387 $core->field_sections[ $field['type'] ][ $field['id'] ] = $k; 388 389 $display = true; 390 391 if ( isset( $_GET['page'] ) && $core->args['page_slug'] === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification 392 if ( isset( $field['panel'] ) && false === $field['panel'] ) { 393 $display = false; 394 } 395 } 396 if ( isset( $field['customizer_only'] ) && true === $field['customizer_only'] ) { 397 $display = false; 398 } 399 400 if ( isset( $section['customizer'] ) ) { 401 $field['customizer'] = $section['customizer']; 402 $core->sections[ $k ]['fields'][ $fieldk ] = $field; 403 } 404 405 if ( isset( $field['permissions'] ) && false !== $field['permissions'] ) { 406 if ( ! Redux_Helpers::current_user_can( $field['permissions'] ) ) { 407 $data = $core->options[ $field['id'] ] ?? $core->options_defaults[ $field['id'] ]; 408 409 $this->hidden_perm_fields[ $field['id'] ] = $data; 410 411 continue; 412 } 413 } 414 415 if ( ! isset( $field['id'] ) ) { 416 echo '<br /><h3>No field ID is set.</h3><pre>'; 417 418 // phpcs:ignore WordPress.PHP.DevelopmentFunctions 419 print_r( $field ); 420 421 echo '</pre><br />'; 422 423 continue; 424 } 425 426 if ( isset( $field['type'] ) && 'section' === $field['type'] ) { 427 if ( isset( $field['indent'] ) && true === $field['indent'] ) { 428 $section_ident = true; 429 } else { 430 $section_ident = false; 431 } 432 } 433 434 if ( isset( $field['type'] ) && 'info' === $field['type'] && $section_ident ) { 435 $field['indent'] = true; 436 } 437 438 $th = $core->render_class->get_header_html( $field ); 439 440 $field['name'] = $core->args['opt_name'] . '[' . $field['id'] . ']'; 441 442 // Set the default value if present. 443 $core->options_defaults[ $field['id'] ] = $core->options_defaults[ $field['id'] ] ?? ''; 444 445 // Set the defaults to the value if not present. 446 $do_update = false; 447 448 // Check fields for values in the default parameter. 449 if ( ! isset( $core->options[ $field['id'] ] ) && isset( $field['default'] ) ) { 450 $core->options_defaults[ $field['id'] ] = $field['default']; 451 $core->options[ $field['id'] ] = $field['default']; 452 $do_update = true; 453 454 // Check fields that hae no default value, but an options value with settings to 455 // be saved by default. 456 } elseif ( ! isset( $core->options[ $field['id'] ] ) && isset( $field['options'] ) ) { 457 458 // If sorter field, check for options and save them as defaults. 459 if ( 'sorter' === $field['type'] || 'sortable' === $field['type'] ) { 460 $core->options_defaults[ $field['id'] ] = $field['options']; 461 $core->options[ $field['id'] ] = $field['options']; 462 $do_update = true; 463 } 464 } 465 466 // CORRECT URLS if media URLs are wrong, but attachment IDs are present. 467 if ( 'media' === $field['type'] ) { 468 if ( isset( $core->options[ $field['id'] ]['id'] ) && isset( $core->options[ $field['id'] ]['url'] ) && ! empty( $core->options[ $field['id'] ]['url'] ) && strpos( $core->options[ $field['id'] ]['url'], str_replace( 'http://', '', WP_CONTENT_URL ) ) === false ) { 469 $data = wp_get_attachment_url( $core->options[ $field['id'] ]['id'] ); 470 471 if ( isset( $data ) && ! empty( $data ) ) { 472 $core->options[ $field['id'] ]['url'] = $data; 473 474 $data = wp_get_attachment_image_src( 475 $core->options[ $field['id'] ]['id'], 476 array( 477 150, 478 150, 479 ) 480 ); 481 482 $core->options[ $field['id'] ]['thumbnail'] = $data[0]; 483 $do_update = true; 484 } 485 } 486 } 487 488 if ( 'background' === $field['type'] ) { 489 if ( isset( $core->options[ $field['id'] ]['media']['id'] ) && isset( $core->options[ $field['id'] ]['background-image'] ) && ! empty( $core->options[ $field['id'] ]['background-image'] ) && strpos( $core->options[ $field['id'] ]['background-image'], str_replace( array( 'http://', 'https://' ), '', WP_CONTENT_URL ) ) === false ) { 490 $data = wp_get_attachment_url( $core->options[ $field['id'] ]['media']['id'] ); 491 492 if ( isset( $data ) && ! empty( $data ) ) { 493 $core->options[ $field['id'] ]['background-image'] = $data; 494 495 $data = wp_get_attachment_image_src( 496 $core->options[ $field['id'] ]['media']['id'], 497 array( 498 150, 499 150, 500 ) 501 ); 502 503 $core->options[ $field['id'] ]['media']['thumbnail'] = $data[0]; 504 $do_update = true; 505 } 506 } 507 } 508 509 if ( 'slides' === $field['type'] ) { 510 if ( isset( $core->options[ $field['id'] ] ) && is_array( $core->options[ $field['id'] ] ) && isset( $core->options[ $field['id'] ][0]['attachment_id'] ) && isset( $core->options[ $field['id'] ][0]['image'] ) && ! empty( $core->options[ $field['id'] ][0]['image'] ) && strpos( $core->options[ $field['id'] ][0]['image'], str_replace( array( 'http://', 'https://' ), '', WP_CONTENT_URL ) ) === false ) { 511 foreach ( $core->options[ $field['id'] ] as $key => $val ) { 512 $data = wp_get_attachment_url( $val['attachment_id'] ); 513 514 if ( isset( $data ) && ! empty( $data ) ) { 515 $core->options[ $field['id'] ][ $key ]['image'] = $data; 516 517 $data = wp_get_attachment_image_src( 518 $val['attachment_id'], 519 array( 520 150, 521 150, 522 ) 523 ); 524 525 $core->options[ $field['id'] ][ $key ]['thumb'] = $data[0]; 526 $do_update = true; 527 } 528 } 529 } 530 } 531 // END -> CORRECT URLS if media URLs are wrong, but attachment IDs are present. 532 if ( true === $do_update && ! isset( $core->never_save_to_db ) ) { 533 if ( $core->args['save_defaults'] ) { // Only save that to the DB if allowed to. 534 $run_update = true; 535 } 536 } 537 538 if ( ! isset( $field['class'] ) ) { // No errors please. 539 $field['class'] = ''; 540 } 541 $id = $field['id']; 542 543 /** 544 * Filter 'redux/options/{opt_name}/field/{field.id}'. 545 * 546 * @param array $field field config 547 */ 548 549 // phpcs:ignore WordPress.NamingConventions.ValidHookName 550 $field = apply_filters( "redux/options/{$core->args['opt_name']}/field/{$field['id']}", $field ); 551 552 if ( empty( $field ) || ! $field ) { 553 unset( $core->sections[ $k ]['fields'][ $fieldk ] ); 554 continue; 555 } 556 557 if ( ! empty( $core->folds[ $field['id'] ]['parent'] ) ) { // This has some fold items, hide it by default. 558 $field['class'] .= ' fold'; 559 } 560 561 if ( ! empty( $core->folds[ $field['id'] ]['children'] ) ) { // Sets the values you shoe fold children on. 562 $field['class'] .= ' fold-parent'; 563 } 564 565 if ( ! empty( $field['compiler'] ) ) { 566 $field['class'] .= ' compiler'; 567 $core->compiler_fields[ $field['id'] ] = 1; 568 } 569 570 if ( isset( $field['unit'] ) && ! isset( $field['units'] ) ) { 571 $field['units'] = $field['unit']; 572 unset( $field['unit'] ); 573 } 574 575 $core->sections[ $k ]['fields'][ $fieldk ] = $field; 576 577 if ( isset( $core->args['display_source'] ) ) { 578 // phpcs:ignore WordPress.PHP.DevelopmentFunctions 579 $th .= '<div id="' . $field['id'] . '-settings" style="display:none;"><pre>' . var_export( $core->sections[ $k ]['fields'][ $fieldk ], true ) . '</pre></div>'; 580 $th .= '<br /><a href="#TB_inline?width=600&height=800&inlineId=' . $field['id'] . '-settings" class="thickbox"><small>View Source</small></a>'; 581 } 582 583 /** 584 * Action 'redux/options/{opt_name}/field/{field.type}/register' 585 */ 586 587 // phpcs:ignore WordPress.NamingConventions.ValidHookName 588 do_action( "redux/options/{$core->args['opt_name']}/field/{$field['type']}/register", $field ); 589 590 $core->required_class->check_dependencies( $field ); 591 $core->field_head[ $field['id'] ] = $th; 592 593 if ( ! $display || isset( $this->no_panel_section[ $k ] ) ) { 594 $this->no_panel[] = $field['id']; 595 } else { 596 if ( isset( $field['disabled'] ) && $field['disabled'] ) { 597 $field['label_for'] = 'redux_disable_field'; 598 } 599 600 if ( isset( $field['hidden'] ) && $field['hidden'] ) { 601 $field['label_for'] = 'redux_hide_field'; 602 } 603 604 if ( true === $core->args['options_api'] ) { 605 add_settings_field( 606 "{$fieldk}_field", 607 $th, 608 array( 609 $core->render_class, 610 'field_input', 611 ), 612 "{$core->args['opt_name']}{$k}_section_group", 613 "{$core->args['opt_name']}{$k}_section", 614 $field 615 ); 616 } 617 } 618 } 619 } 620 } 621 622 /** 623 * Action 'redux/options/{opt_name}/register' 624 * 625 * @param array option sections 626 */ 627 628 // phpcs:ignore WordPress.NamingConventions.ValidHookName 629 do_action( "redux/options/{$core->args['opt_name']}/register", $core->sections ); 630 631 if ( $run_update && ! isset( $core->never_save_to_db ) ) { // Always update the DB with new fields. 632 $this->set( $core->options ); 633 } 634 635 if ( isset( $core->transients['run_compiler'] ) && $core->transients['run_compiler'] ) { 636 637 $core->no_output = true; 638 $temp = $core->args['output_variables_prefix']; 639 // Allow the override of variable's prefix for use by SCSS or LESS. 640 if ( isset( $core->args['compiler_output_variables_prefix'] ) ) { 641 $core->args['output_variables_prefix'] = $core->args['compiler_output_variables_prefix']; 642 } 643 $core->output_class->enqueue(); 644 $core->args['output_variables_prefix'] = $temp; 645 646 /** 647 * Action 'redux/options/{opt_name}/compiler' 648 * 649 * @param array options 650 * @param string CSS that get sent to the compiler hook 651 */ 652 653 // phpcs:ignore WordPress.NamingConventions.ValidVariableName 654 $compiler_css = $core->compilerCSS; 655 656 // phpcs:ignore WordPress.NamingConventions.ValidHookName 657 do_action( "redux/options/{$core->args['opt_name']}/compiler", $core->options, $compiler_css, $core->transients['changed_values'], $core->output_variables ); 658 659 /** 660 * Action 'redux/options/{opt_name}/compiler/advanced' 661 * 662 * @param array options 663 * @param string CSS that get sent to the compiler hook, which sends the full Redux object 664 */ 665 666 // phpcs:ignore WordPress.NamingConventions.ValidHookName 667 do_action( "redux/options/{$core->args['opt_name']}/compiler/advanced", $core ); 668 669 unset( $core->transients['run_compiler'] ); 670 $core->transient_class->set(); 671 } 672 } 673 674 /** 675 * Get default options into an array suitable for the settings API 676 * 677 * @since 1.0.0 678 * @access public 679 * @return array $this->options_defaults 680 */ 681 public function default_values(): array { 682 $core = $this->core(); 683 684 if ( ! is_null( $core->sections ) && is_null( $core->options_defaults ) ) { 685 $core->options_defaults = $core->options_defaults_class->default_values( $core->args['opt_name'], $core->sections, $core->wordpress_data ); 686 } 687 688 /** 689 * Filter 'redux/options/{opt_name}/defaults' 690 * 691 * @param array $defaults option default values 692 */ 693 694 $core->transients['changed_values'] = $core->transients['changed_values'] ?? array(); 695 696 // phpcs:ignore WordPress.NamingConventions.ValidHookName 697 $core->options_defaults = apply_filters( "redux/options/{$core->args['opt_name']}/defaults", $core->options_defaults, $core->transients['changed_values'] ); 698 699 return $core->options_defaults; 700 } 701 702 /** 703 * Validate the Options before insertion 704 * 705 * @param array $plugin_options The options array. 706 * 707 * @return array|mixed|string 708 * @since 3.0.0 709 * @access public 710 */ 711 public function validate_options( array $plugin_options ) { 712 $core = $this->core(); 713 714 if ( isset( $core->validation_ran ) ) { 715 return $plugin_options; 716 } 717 718 $core->validation_ran = 1; 719 720 // Save the values not in the panel. 721 if ( isset( $plugin_options['redux-no_panel'] ) ) { 722 $keys = explode( '|', $plugin_options['redux-no_panel'] ); 723 foreach ( $keys as $key ) { 724 $plugin_options[ $key ] = $core->options[ $key ]; 725 } 726 if ( isset( $plugin_options['redux-no_panel'] ) ) { 727 unset( $plugin_options['redux-no_panel'] ); 728 } 729 } 730 731 if ( is_array( $this->hidden_perm_fields ) && ! empty( $this->hidden_perm_fields ) ) { 732 foreach ( $this->hidden_perm_fields as $id => $data ) { 733 $plugin_options[ $id ] = $data; 734 } 735 } 736 737 if ( $plugin_options === $core->options ) { 738 return $plugin_options; 739 } 740 741 $time = time(); 742 743 // Sets last saved time. 744 $core->transients['last_save'] = $time; 745 746 $imported_options = array(); 747 748 if ( isset( $plugin_options['import_link'] ) && '' !== $plugin_options['import_link'] && ! ! wp_http_validate_url( $plugin_options['import_link'] ) ) { 749 $import = wp_remote_retrieve_body( wp_remote_get( $plugin_options['import_link'] ) ); 750 $imported_options = json_decode( $import, true ); 751 } 752 if ( isset( $plugin_options['import_code'] ) && '' !== $plugin_options['import_code'] ) { 753 $imported_options = json_decode( $plugin_options['import_code'], true ); 754 } 755 756 // Import. 757 $core->transients['last_save_mode'] = 'import'; // Last save mode. 758 $core->transients['last_compiler'] = $time; 759 $core->transients['last_import'] = $time; 760 $core->transients['run_compiler'] = 1; 761 762 if ( is_array( $imported_options ) && ! empty( $imported_options ) && isset( $imported_options['redux-backup'] ) && ( 1 === $imported_options['redux-backup'] || '1' === $imported_options['redux-backup'] ) ) { 763 $core->transients['changed_values'] = array(); 764 foreach ( $plugin_options as $key => $value ) { 765 if ( isset( $imported_options[ $key ] ) && $value !== $imported_options[ $key ] ) { 766 $plugin_options[ $key ] = $value; 767 $core->transients['changed_values'][ $key ] = $value; 768 } 769 } 770 771 /** 772 * Action 'redux/options/{opt_name}/import'. 773 * 774 * @param &array [&$plugin_options, redux_options] 775 */ 776 777 // phpcs:ignore WordPress.NamingConventions.ValidHookName 778 do_action_ref_array( 779 "redux/options/{$core->args['opt_name']}/import", // phpcs:ignore WordPress.NamingConventions.ValidHookName 780 array( 781 &$plugin_options, 782 $imported_options, 783 $core->transients['changed_values'], 784 ) 785 ); 786 787 setcookie( 'redux_current_tab_' . $core->args['opt_name'], '', 1, '/', $time + 1000, '/' ); 788 $_COOKIE[ 'redux_current_tab_' . $core->args['opt_name'] ] = 1; 789 790 unset( $plugin_options['defaults'], $plugin_options['compiler'], $plugin_options['import'], $plugin_options['import_code'] ); 791 if ( in_array( $core->args['database'], array( 'transient', 'theme_mods', 'theme_mods_expanded', 'network' ), true ) ) { 792 $this->set( $plugin_options ); 793 794 return; 795 } 796 797 $plugin_options = wp_parse_args( $imported_options, $plugin_options ); 798 799 $core->transient_class->set(); 800 801 return $plugin_options; 802 } 803 804 // Reset all to defaults. 805 if ( ! empty( $plugin_options['defaults'] ) ) { 806 if ( empty( $core->options_defaults ) ) { 807 $core->options_defaults = $core->_default_values(); 808 } 809 810 /** 811 * Filter: 'redux/validate/{opt_name}/defaults'. 812 * 813 * @param &array [ $this->options_defaults, $plugin_options] 814 */ 815 816 // phpcs:ignore WordPress.NamingConventions.ValidHookName 817 $plugin_options = apply_filters( "redux/validate/{$core->args['opt_name']}/defaults", $core->options_defaults ); 818 819 $core->transients['changed_values'] = array(); 820 821 if ( empty( $core->options ) ) { 822 $core->options = $core->options_defaults; 823 } 824 825 foreach ( $core->options as $key => $value ) { 826 if ( isset( $plugin_options[ $key ] ) && $plugin_options[ $key ] !== $value ) { 827 $core->transients['changed_values'][ $key ] = $value; 828 } 829 } 830 831 $core->transients['run_compiler'] = 1; 832 $core->transients['last_save_mode'] = 'defaults'; // Last save mode. 833 834 $core->transient_class->set(); 835 836 return $plugin_options; 837 } 838 839 // Section reset to defaults. 840 if ( ! empty( $plugin_options['defaults-section'] ) ) { 841 if ( isset( $plugin_options['redux-section'] ) && isset( $core->sections[ $plugin_options['redux-section'] ]['fields'] ) ) { 842 if ( empty( $core->options_defaults ) ) { 843 $core->options_defaults = $core->_default_values(); 844 } 845 846 foreach ( $core->sections[ $plugin_options['redux-section'] ]['fields'] as $field ) { 847 if ( isset( $core->options_defaults[ $field['id'] ] ) ) { 848 $plugin_options[ $field['id'] ] = $core->options_defaults[ $field['id'] ]; 849 } else { 850 $plugin_options[ $field['id'] ] = ''; 851 } 852 853 if ( isset( $field['compiler'] ) ) { 854 $compiler = true; 855 } 856 } 857 858 /** 859 * Filter: 'redux/validate/{opt_name}/defaults_section'. 860 * 861 * @param &array [ $this->options_defaults, $plugin_options] 862 */ 863 864 // phpcs:ignore WordPress.NamingConventions.ValidHookName 865 $plugin_options = apply_filters( "redux/validate/{$core->args['opt_name']}/defaults_section", $plugin_options ); 866 } 867 868 $core->transients['changed_values'] = array(); 869 foreach ( $core->options as $key => $value ) { 870 if ( isset( $plugin_options[ $key ] ) && $plugin_options[ $key ] !== $value ) { 871 $core->transients['changed_values'][ $key ] = $value; 872 } 873 } 874 875 if ( isset( $compiler ) ) { 876 $core->transients['last_compiler'] = $time; 877 $core->transients['run_compiler'] = 1; 878 } 879 880 $core->transients['last_save_mode'] = 'defaults_section'; // Last save mode. 881 882 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'] ); 883 884 $core->transient_class->set(); 885 886 return $plugin_options; 887 } 888 889 $core->transients['last_save_mode'] = 'normal'; // Last save mode. 890 891 /** 892 * Filter: 'redux/validate/{opt_name}/before_validation' 893 * 894 * @param &array [&$plugin_options, redux_options] 895 */ 896 897 // phpcs:ignore WordPress.NamingConventions.ValidHookName 898 $plugin_options = apply_filters( "redux/validate/{$core->args['opt_name']}/before_validation", $plugin_options, $core->options ); 899 900 // Validate fields (if needed). 901 $plugin_options = $core->validate_class->validate( $plugin_options, $core->options, $core->sections ); 902 903 // Sanitize options, if needed. 904 $plugin_options = $core->sanitize_class->sanitize( $plugin_options, $core->options, $core->sections ); 905 906 if ( ! empty( $core->errors ) || ! empty( $core->warnings ) || ! empty( $core->sanitize ) ) { 907 $core->transients['notices'] = array( 908 'errors' => $core->errors, 909 'warnings' => $core->warnings, 910 'sanitize' => $core->sanitize, 911 ); 912 } 913 914 if ( ! isset( $core->transients['changed_values'] ) ) { 915 $core->transients['changed_values'] = array(); 916 } 917 918 /** 919 * Action 'redux/options/{opt_name}/validate' 920 * 921 * @param &array [&$plugin_options, redux_options] 922 */ 923 // phpcs:ignore WordPress.NamingConventions.ValidHookName 924 do_action_ref_array( 925 // phpcs:ignore WordPress.NamingConventions.ValidHookName 926 "redux/options/{$core->args['opt_name']}/validate", 927 array( 928 &$plugin_options, 929 $core->options, 930 $core->transients['changed_values'], 931 ) 932 ); 933 934 if ( ! empty( $plugin_options['compiler'] ) ) { 935 unset( $plugin_options['compiler'] ); 936 937 $core->transients['last_compiler'] = $time; 938 $core->transients['run_compiler'] = 1; 939 } 940 941 $core->transients['changed_values'] = array(); // Changed values since last save. 942 943 if ( ! empty( $core->options ) ) { 944 foreach ( $core->options as $key => $value ) { 945 if ( isset( $plugin_options[ $key ] ) && $plugin_options[ $key ] !== $value ) { 946 $core->transients['changed_values'][ $key ] = $value; 947 } 948 } 949 } 950 951 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'] ); 952 if ( in_array( $core->args['database'], array( 'transient', 'theme_mods', 'theme_mods_expanded' ), true ) ) { 953 $core->set( $core->args['opt_name'], $plugin_options ); 954 return; 955 } 956 957 if ( defined( 'WP_CACHE' ) && WP_CACHE && class_exists( 'W3_ObjectCache' ) && function_exists( 'w3_instance' ) ) { 958 $w3_inst = w3_instance( 'W3_ObjectCache' ); 959 $w3 = $w3_inst->instance(); 960 $key = $w3->_get_cache_key( $core->args['opt_name'] . '-transients', 'transient' ); 961 $w3->delete( $key, 'transient', true ); 962 } 963 964 $core->transient_class->set(); 965 966 return $plugin_options; 967 } 968 969 /** 970 * ->get_default(); This is used to return the default value if default_show is set. 971 * 972 * @param string $opt_name The option name to return. 973 * @param mixed $default (null) The value to return if default not set. 974 * 975 * @return mixed $default 976 * @since 1.0.1 977 * @access public 978 */ 979 public function get_default( string $opt_name, $default = null ) { 980 if ( true === $this->args['default_show'] ) { 981 982 if ( empty( $this->options_defaults ) ) { 983 $this->default_values(); // fill cache. 984 } 985 986 $default = array_key_exists( $opt_name, $this->options_defaults ) ? $this->options_defaults[ $opt_name ] : $default; 987 } 988 989 return $default; 990 } 991 992 /** 993 * Get the default value for an option 994 * 995 * @param string $key The option's ID. 996 * @param string $array_key The key of the default's array. 997 * 998 * @return mixed 999 * @since 3.3.6 1000 * @access public 1001 */ 1002 public function get_default_value( string $key, $array_key = false ) { 1003 if ( empty( $this->options_defaults ) ) { 1004 $this->options_defaults = $this->default_values(); 1005 } 1006 1007 $defaults = $this->options_defaults; 1008 $value = ''; 1009 1010 if ( isset( $defaults[ $key ] ) ) { 1011 if ( false !== $array_key && isset( $defaults[ $key ][ $array_key ] ) ) { 1012 $value = $defaults[ $key ][ $array_key ]; 1013 } else { 1014 $value = $defaults[ $key ]; 1015 } 1016 } 1017 1018 return $value; 1019 } 1020 } 1021 }