class-redux-core.php (18330B)
1 <?php 2 /** 3 * Redux Core Class 4 * 5 * @class Redux_Core 6 * @version 4.0.0 7 * @package Redux Framework 8 */ 9 10 defined( 'ABSPATH' ) || exit; 11 12 if ( ! class_exists( 'Redux_Core', false ) ) { 13 14 /** 15 * Class Redux_Core 16 */ 17 class Redux_Core { 18 19 /** 20 * Class instance. 21 * 22 * @var object 23 */ 24 public static $instance; 25 26 /** 27 * Project version 28 * 29 * @var project string 30 */ 31 public static $version; 32 33 /** 34 * Project directory. 35 * 36 * @var project string. 37 */ 38 public static $dir; 39 40 /** 41 * Project URL. 42 * 43 * @var project URL. 44 */ 45 public static $url; 46 47 /** 48 * Base directory path. 49 * 50 * @var string 51 */ 52 public static $redux_path; 53 54 /** 55 * Absolute direction path to WordPress upload directory. 56 * 57 * @var null 58 */ 59 public static $upload_dir = null; 60 61 /** 62 * Full URL to WordPress upload directory. 63 * 64 * @var string 65 */ 66 public static $upload_url = null; 67 68 /** 69 * Set when Redux is run as a plugin. 70 * 71 * @var bool 72 */ 73 public static $is_plugin = true; 74 75 /** 76 * Indicated in_theme or in_plugin. 77 * 78 * @var string 79 */ 80 public static $installed = ''; 81 82 /** 83 * Set when Redux is run as a plugin. 84 * 85 * @var bool 86 */ 87 public static $as_plugin = false; 88 89 /** 90 * Set when Redux is embedded within a theme. 91 * 92 * @var bool 93 */ 94 public static $in_theme = false; 95 96 /** 97 * Set when Redux Pro plugin is loaded and active. 98 * 99 * @var bool 100 */ 101 public static $pro_loaded = false; 102 103 /** 104 * Pointer to updated google fonts array. 105 * 106 * @var array 107 */ 108 public static $google_fonts = array(); 109 110 /** 111 * List of files calling Redux. 112 * 113 * @var array 114 */ 115 public static $callers = array(); 116 117 /** 118 * Nonce. 119 * 120 * @var string 121 */ 122 public static $wp_nonce; 123 124 /** 125 * Pointer to _SERVER global. 126 * 127 * @var null 128 */ 129 public static $server = null; 130 131 /** 132 * Pointer to the thirdparty fixes class. 133 * 134 * @var null 135 */ 136 public static $third_party_fixes = null; 137 138 /** 139 * Redux Welcome screen object. 140 * 141 * @var null 142 */ 143 public static $welcome = null; 144 145 /** 146 * Redux Appsero object. 147 * 148 * @var null 149 */ 150 public static $appsero = null; 151 152 /** 153 * Redux Insights object. 154 * 155 * @var null 156 */ 157 public static $insights = null; 158 159 /** 160 * Flag for Redux Template snables status. 161 * 162 * @var bool 163 */ 164 public static $redux_templates_enabled = false; 165 166 /** 167 * Flag for Extendify Template snables status. 168 * 169 * @var bool 170 */ 171 public static $extendify_templates_enabled = true; 172 173 /** 174 * Creates instance of class. 175 * 176 * @return Redux_Core 177 * @throws Exception Comment. 178 */ 179 public static function instance() { 180 if ( ! self::$instance ) { 181 self::$instance = new self(); 182 183 self::$instance->includes(); 184 self::$instance->init(); 185 self::$instance->hooks(); 186 187 add_action( 'plugins_loaded', array( 'Redux_Core', 'plugins_loaded' ) ); 188 } 189 190 return self::$instance; 191 } 192 193 /** 194 * Things to run after pluggable.php had loaded. 195 */ 196 public static function plugins_loaded() { 197 Redux_Functions_Ex::pro_to_ext(); 198 } 199 200 /** 201 * Class init. 202 */ 203 private function init() { 204 205 self::$server = array( 206 'SERVER_SOFTWARE' => '', 207 'REMOTE_ADDR' => Redux_Helpers::is_local_host() ? '127.0.0.1' : '', 208 'HTTP_USER_AGENT' => '', 209 'HTTP_HOST' => '', 210 'REQUEST_URI' => '', 211 ); 212 213 // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase 214 if ( ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) { 215 self::$server['SERVER_SOFTWARE'] = sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ); 216 } 217 if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) { 218 self::$server['REMOTE_ADDR'] = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); 219 } 220 if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { 221 self::$server['HTTP_USER_AGENT'] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ); 222 } 223 if ( ! empty( $_SERVER['HTTP_HOST'] ) ) { 224 self::$server['HTTP_HOST'] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ); 225 } 226 if ( ! empty( $_SERVER['REQUEST_URI'] ) ) { 227 self::$server['REQUEST_URI'] = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ); 228 } 229 230 // phpcs:enable 231 232 self::$dir = trailingslashit( wp_normalize_path( dirname( realpath( __FILE__ ) ) ) ); 233 234 Redux_Functions_Ex::generator(); 235 236 if ( ! class_exists( 'ReduxAppsero\Client' ) ) { 237 require_once Redux_Path::get_path( '/appsero/Client.php' ); 238 } 239 240 if ( defined( 'REDUX_PLUGIN_FILE' ) ) { 241 $client = new ReduxAppsero\Client( 'f6b61361-757e-4600-bb0f-fe404ae9871b', 'Redux Framework', REDUX_PLUGIN_FILE ); 242 $plugin_info = Redux_Functions_Ex::is_inside_plugin( REDUX_PLUGIN_FILE ); 243 } else { 244 $client = new ReduxAppsero\Client( 'f6b61361-757e-4600-bb0f-fe404ae9871b', 'Redux Framework', __FILE__ ); 245 // See if Redux is a plugin or not. 246 247 $client->slug = 'redux-framework'; 248 $client->textdomain = 'redux-framework'; 249 $client->version = self::$version; 250 } 251 252 $plugin_info = Redux_Functions_Ex::is_inside_plugin( __FILE__ ); 253 254 if ( false !== $plugin_info ) { 255 self::$installed = class_exists( 'Redux_Framework_Plugin' ) ? 'plugin' : 'in_plugin'; 256 self::$is_plugin = class_exists( 'Redux_Framework_Plugin' ); 257 self::$as_plugin = true; 258 self::$url = trailingslashit( dirname( $plugin_info['url'] ) ); 259 if ( isset( $plugin_info['slug'] ) && ! empty( $plugin_info['slug'] ) ) { 260 $client->slug = $plugin_info['slug']; 261 } 262 $client->type = 'plugin'; 263 } else { 264 $theme_info = Redux_Functions_Ex::is_inside_theme( __FILE__ ); 265 if ( false !== $theme_info ) { 266 self::$url = trailingslashit( dirname( $theme_info['url'] ) ); 267 self::$in_theme = true; 268 self::$installed = 'in_theme'; 269 if ( isset( $theme_info['slug'] ) && ! empty( $theme_info['slug'] ) ) { 270 $client->slug = $theme_info['slug']; 271 } 272 $client->type = 'theme'; 273 } 274 } 275 276 self::$appsero = $client; 277 278 // Activate insights. 279 self::$insights = self::$appsero->insights(); 280 281 if ( class_exists( 'Redux_Pro' ) ) { 282 self::$insights->add_extra( 283 array( 284 'pro' => Redux_Pro::$version, 285 'mokama' => Redux_Helpers::mokama(), 286 ) 287 ); 288 } 289 290 self::$insights->hide_notice()->init(); 291 if ( ! defined( 'REDUX_PLUGIN_FILE' ) ) { 292 remove_action( 'admin_footer', array( self::$insights, 'deactivate_scripts' ) ); 293 } 294 295 if ( ! self::$insights->tracking_allowed() ) { 296 if ( ! self::$insights->notice_dismissed() ) { 297 // Old tracking permissions. 298 $tracking_options = get_option( 'redux-framework-tracking', array() ); 299 if ( ! empty( $tracking_options ) ) { 300 if ( isset( $tracking_options['allow_tracking'] ) && 'yes' === $tracking_options['allow_tracking'] ) { 301 Redux_Functions_Ex::set_activated(); 302 } 303 } 304 } 305 } 306 307 remove_action( 'redux_admin_notices_run', array( 'ReduxAppsero\Insights', 'admin_notice' ) ); 308 309 // phpcs:ignore WordPress.NamingConventions.ValidHookName 310 self::$url = apply_filters( 'redux/url', self::$url ); 311 312 // phpcs:ignore WordPress.NamingConventions.ValidHookName 313 self::$dir = apply_filters( 'redux/dir', self::$dir ); 314 315 // phpcs:ignore WordPress.NamingConventions.ValidHookName 316 self::$is_plugin = apply_filters( 'redux/is_plugin', self::$is_plugin ); 317 318 if ( ! function_exists( 'current_time' ) ) { 319 require_once ABSPATH . '/wp-includes/functions.php'; 320 } 321 322 $upload_dir = wp_upload_dir(); 323 self::$upload_dir = $upload_dir['basedir'] . '/redux/'; 324 self::$upload_url = str_replace( array( 'https://', 'http://' ), '//', $upload_dir['baseurl'] . '/redux/' ); 325 326 // phpcs:ignore WordPress.NamingConventions.ValidHookName 327 self::$upload_dir = apply_filters( 'redux/upload_dir', self::$upload_dir ); 328 329 // phpcs:ignore WordPress.NamingConventions.ValidHookName 330 self::$upload_url = apply_filters( 'redux/upload_url', self::$upload_url ); 331 332 self::$redux_templates_enabled = (bool) get_option( 'use_redux_templates' ); 333 self::$extendify_templates_enabled = (bool) get_option( 'use_extendify_templates', true ); 334 } 335 336 /** 337 * Code to execute on framework __construct. 338 * 339 * @param object $parent Pointer to ReduxFramework object. 340 * @param array $args Global arguments array. 341 */ 342 public static function core_construct( $parent, array $args ) { 343 self::$third_party_fixes = new Redux_ThirdParty_Fixes( $parent ); 344 345 Redux_ThemeCheck::get_instance(); 346 347 } 348 349 /** 350 * Autoregister run. 351 * 352 * @throws Exception Comment. 353 */ 354 private function includes() { 355 if ( class_exists( 'Redux_Pro' ) && isset( Redux_Pro::$dir ) ) { 356 self::$pro_loaded = true; 357 } 358 359 require_once dirname( __FILE__ ) . '/inc/classes/class-redux-path.php'; 360 require_once dirname( __FILE__ ) . '/inc/classes/class-redux-functions-ex.php'; 361 require_once dirname( __FILE__ ) . '/inc/classes/class-redux-helpers.php'; 362 require_once dirname( __FILE__ ) . '/inc/classes/class-redux-enable-gutenberg.php'; 363 require_once dirname( __FILE__ ) . '/inc/classes/class-redux-instances.php'; 364 Redux_Functions_Ex::register_class_path( 'Redux', dirname( __FILE__ ) . '/inc/classes' ); 365 Redux_Functions_Ex::register_class_path( 'Redux', dirname( __FILE__ ) . '/inc/welcome' ); 366 spl_autoload_register( array( $this, 'register_classes' ) ); 367 368 self::$welcome = new Redux_Welcome(); 369 new Redux_Rest_Api_Builder( $this ); 370 371 add_action( 'admin_init', array( $this, 'admin_init' ) ); 372 373 add_filter( 'debug_information', array( $this, 'add_debug_info' ) ); 374 add_filter( 'redux/tracking/options', array( 'Redux_Helpers', 'redux_stats_additions' ) ); 375 } 376 377 /** 378 * Add debug infor the WP Site Health screen. 379 * 380 * @param array $debug_info Debug data. 381 * 382 * @return array 383 */ 384 public function add_debug_info( array $debug_info ): array { 385 386 // Get browser data. 387 if ( ! class_exists( 'Browser' ) ) { 388 require_once self::$dir . 'inc/lib/browser.php'; 389 } 390 391 $browser = new Browser(); 392 393 $browser_data = array( 394 'Agent' => $browser->getUserAgent(), 395 'Browser' => $browser->getBrowser(), 396 'Version' => $browser->getVersion(), 397 'Platform' => $browser->getPlatform(), 398 ); 399 400 // Set Redux dir permission results to Site Health screen. 401 $debug_info['wp-filesystem']['fields'][] = array( 402 'label' => esc_html__( 'The Redux upload directory', 'redux-framework' ), 403 'value' => wp_is_writable( self::$upload_dir ) ? 'Writable' : 'Not writable', 404 ); 405 406 // Set Redux plugin results to Site Health screen. 407 $debug_info['redux-framework'] = array( 408 'label' => esc_html__( 'Redux Framework', 'redux-framework' ), 409 'description' => esc_html__( 'Debug information specific to Redux Framework.', 'redux-framework' ), 410 'fields' => array( 411 'version' => array( 412 'label' => esc_html__( 'Version', 'redux-framework' ), 413 'value' => self::$version, 414 ), 415 'installation' => array( 416 'label' => esc_html__( 'Installation', 'redux-framework' ), 417 'value' => self::$installed, 418 ), 419 'data directory' => array( 420 'label' => esc_html__( 'Data directory', 'redux-framerwork' ), 421 'value' => self::$dir, 422 ), 423 'browser' => array( 424 'label' => esc_html__( 'Browser', 'redux-framework' ), 425 'value' => $browser_data, 426 ), 427 ), 428 ); 429 430 $redux = Redux::all_instances(); 431 432 if ( ! empty( $redux ) && is_array( $redux ) ) { 433 foreach ( $redux as $inst => $data ) { 434 Redux::init( $inst ); 435 436 $inst_name = ucwords( str_replace( array( '_', '-' ), ' ', $inst ) ); 437 $args = $data->args; 438 439 $ext = Redux::get_extensions( $inst ); 440 if ( ! empty( $ext ) && is_array( $ext ) ) { 441 ksort( $ext ); 442 443 foreach ( $ext as $name => $arr ) { 444 $ver = $arr['version']; 445 446 $ex = esc_html( ucwords( str_replace( array( '_', '-' ), ' ', $name ) ) ); 447 448 $extensions[ $ex ] = esc_html( $ver ); 449 } 450 } 451 452 // Output Redux instances. 453 $debug_info[ 'redux-instance-' . $inst ] = array( 454 // translators: %s = Instance name. 455 'label' => sprintf( esc_html__( 'Redux Instance: %s', 'redux-framework' ), $inst_name ), 456 // translators: %s = Instance name w/ HTML. 457 'description' => sprintf( esc_html__( 'Debug information for the %s Redux instance.', 'redux-framework' ), '<code>' . $inst . '</code>' ), 458 'fields' => array( 459 'opt_name' => array( 460 'label' => esc_html( 'opt_name' ), 461 'value' => $args['opt_name'], 462 ), 463 'global_variable' => array( 464 'label' => esc_html( 'global_variable' ), 465 'value' => $args['global_variable'], 466 ), 467 'dev_mode' => array( 468 'label' => esc_html( 'dev_mode' ), 469 'value' => $args['dev_mode'] ? 'true' : 'false', 470 ), 471 'ajax_save' => array( 472 'label' => esc_html( 'ajax_save' ), 473 'value' => $args['ajax_save'] ? 'true' : 'false', 474 ), 475 'page_slug' => array( 476 'label' => esc_html( 'page_slug' ), 477 'value' => $args['page_slug'], 478 ), 479 'page_permissions' => array( 480 'label' => esc_html( 'page_permissions' ), 481 'value' => $args['page_permissions'], 482 ), 483 'menu_type' => array( 484 'label' => esc_html( 'menu_type' ), 485 'value' => $args['menu_type'], 486 ), 487 'page_parent' => array( 488 'label' => esc_html( 'page_parent' ), 489 'value' => $args['page_parent'], 490 ), 491 'compiler' => array( 492 'label' => esc_html( 'compiler' ), 493 'value' => $args['compiler'] ? 'true' : 'false', 494 ), 495 'output' => array( 496 'label' => esc_html( 'output' ), 497 'value' => $args['output'] ? 'true' : 'false', 498 ), 499 'output_tag' => array( 500 'label' => esc_html( 'output_tag' ), 501 'value' => $args['output_tag'] ? 'true' : 'false', 502 ), 503 'templates_path' => array( 504 'label' => esc_html( 'templates_path' ), 505 'value' => $args['templates_path'], 506 ), 507 'extensions' => array( 508 'label' => esc_html( 'extensions' ), 509 'value' => $extensions, 510 ), 511 ), 512 ); 513 } 514 } 515 516 return $debug_info; 517 } 518 519 /** 520 * Register callback for autoload. 521 * 522 * @param string $class_name name of class. 523 */ 524 public function register_classes( string $class_name ) { 525 $class_name_test = self::strtolower( $class_name ); 526 527 if ( strpos( $class_name_test, 'redux' ) === false ) { 528 return; 529 } 530 531 if ( ! class_exists( 'Redux_Functions_Ex' ) ) { 532 require_once Redux_Path::get_path( '/inc/classes/class-redux-functions-ex.php' ); 533 } 534 535 if ( ! class_exists( $class_name ) ) { 536 // Backward compatibility for extensions sucks! 537 if ( 'Redux_Instances' === $class_name ) { 538 require_once Redux_Path::get_path( '/inc/classes/class-redux-instances.php' ); 539 require_once Redux_Path::get_path( '/inc/lib/redux-instances.php' ); 540 541 return; 542 } 543 544 // Load Redux APIs. 545 if ( 'Redux' === $class_name ) { 546 require_once Redux_Path::get_path( '/inc/classes/class-redux-api.php' ); 547 548 return; 549 } 550 551 // Redux extra theme checks. 552 if ( 'Redux_ThemeCheck' === $class_name ) { 553 require_once Redux_Path::get_path( '/inc/themecheck/class-redux-themecheck.php' ); 554 555 return; 556 } 557 558 if ( 'Redux_Welcome' === $class_name ) { 559 require_once Redux_Path::get_path( '/inc/welcome/class-redux-welcome.php' ); 560 561 return; 562 } 563 564 $mappings = array( 565 'ReduxFrameworkInstances' => 'Redux_Instances', 566 'reduxCoreEnqueue' => '', 567 'reduxCorePanel' => 'Redux_Panel', 568 'reduxCoreEnqueue' => 'Redux_Enqueue', 569 'Redux_Abstract_Extension' => 'Redux_Extension_Abstract', 570 ); 571 $alias = false; 572 if ( isset( $mappings[ $class_name ] ) ) { 573 $alias = $class_name; 574 $class_name = $mappings[ $class_name ]; 575 } 576 577 // Everything else. 578 $file = 'class.' . $class_name_test . '.php'; 579 580 $class_path = Redux_Path::get_path( '/inc/classes/' . $file ); 581 582 if ( ! file_exists( $class_path ) ) { 583 $class_file_name = str_replace( '_', '-', $class_name ); 584 $file = 'class-' . $class_name_test . '.php'; 585 $class_path = Redux_Path::get_path( '/inc/classes/' . $file ); 586 } 587 588 if ( file_exists( $class_path ) && ! class_exists( $class_name ) ) { 589 require_once $class_path; 590 } 591 if ( class_exists( $class_name ) && ! empty( $alias ) && ! class_exists( $alias ) ) { 592 class_alias( $class_name, $alias ); 593 } 594 } 595 596 // phpcs:ignore WordPress.NamingConventions.ValidHookName 597 do_action( 'redux/core/includes', $this ); 598 } 599 600 /** 601 * Hooks to run on instance creation. 602 */ 603 private function hooks() { 604 // phpcs:ignore WordPress.NamingConventions.ValidHookName 605 do_action( 'redux/core/hooks', $this ); 606 } 607 608 /** 609 * Display the connection banner. 610 */ 611 public function admin_init() { 612 Redux_Connection_Banner::init(); 613 } 614 615 /** 616 * Action to run on WordPress heartbeat. 617 * 618 * @return bool 619 */ 620 public static function is_heartbeat(): bool { 621 // Disregard WP AJAX 'heartbeat'call. Why waste resources? 622 if ( isset( $_POST ) && isset( $_POST['_nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_nonce'] ) ), 'heartbeat-nonce' ) ) { 623 624 if ( isset( $_POST['action'] ) && 'heartbeat' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) { 625 626 // Hook, for purists. 627 if ( has_action( 'redux/ajax/heartbeat' ) ) { 628 // phpcs:ignore WordPress.NamingConventions.ValidHookName 629 do_action( 'redux/ajax/heartbeat' ); 630 } 631 632 return true; 633 } 634 635 return false; 636 } 637 638 // Buh bye! 639 return false; 640 } 641 642 /** 643 * Helper method to check for mb_strtolower or to use the standard strtolower. 644 * 645 * @param string $str String to make lowercase. 646 * 647 * @return string|null 648 */ 649 public static function strtolower( ?string $str ): string { 650 if ( function_exists( 'mb_strtolower' ) && function_exists( 'mb_detect_encoding' ) ) { 651 return mb_strtolower( $str, mb_detect_encoding( $str ) ); 652 } else { 653 return strtolower( $str ); 654 } 655 } 656 } 657 658 /* 659 * Backwards comparability alias 660 */ 661 class_alias( 'Redux_Core', 'redux-core' ); 662 }