balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-redux-framework-plugin.php (16438B)


      1 <?php
      2 /**
      3  * Redux_Framework_Plugin main class
      4  *
      5  * @package     Redux Framework
      6  * @since       3.0.0
      7  */
      8 
      9 // Exit if accessed directly.
     10 defined( 'ABSPATH' ) || exit;
     11 
     12 if ( ! class_exists( 'Redux_Framework_Plugin', false ) ) {
     13 
     14 	/**
     15 	 * Main Redux_Framework_Plugin class
     16 	 *
     17 	 * @since       3.0.0
     18 	 */
     19 	class Redux_Framework_Plugin {
     20 
     21 		/**
     22 		 * Option array for demo mode.
     23 		 *
     24 		 * @access      protected
     25 		 * @var         array $options Array of config options, used to check for demo mode
     26 		 * @since       3.0.0
     27 		 */
     28 		protected $options = array();
     29 
     30 		/**
     31 		 * Use this value as the text domain when translating strings from this plugin. It should match
     32 		 * the Text Domain field set in the plugin header, as well as the directory name of the plugin.
     33 		 * Additionally, text domains should only contain letters, number and hypens, not underscores
     34 		 * or spaces.
     35 		 *
     36 		 * @access      protected
     37 		 * @var         string $plugin_slug The unique ID (slug) of this plugin
     38 		 * @since       3.0.0
     39 		 */
     40 		protected $plugin_slug = 'redux-framework';
     41 
     42 		/**
     43 		 * Set on network activate.
     44 		 *
     45 		 * @access      protected
     46 		 * @var         string $plugin_network_activated Check for plugin network activation
     47 		 * @since       3.0.0
     48 		 */
     49 		protected $plugin_network_activated = null;
     50 
     51 		/**
     52 		 * Class instance.
     53 		 *
     54 		 * @access      private
     55 		 * @var         \Redux_Framework_Plugin $instance The one true Redux_Framework_Plugin
     56 		 * @since       3.0.0
     57 		 */
     58 		private static $instance;
     59 
     60 		/**
     61 		 * Crash flag.
     62 		 *
     63 		 * @access      private
     64 		 * @var         \Redux_Framework_Plugin $crash Crash flag if inside a crash.
     65 		 * @since       4.1.15
     66 		 */
     67 		public static $crash = false;
     68 
     69 		/**
     70 		 * Get active instance
     71 		 *
     72 		 * @access      public
     73 		 * @since       3.1.3
     74 		 * @return      self::$instance The one true Redux_Framework_Plugin
     75 		 */
     76 		public static function instance(): ?Redux_Framework_Plugin {
     77 			$path = REDUX_PLUGIN_FILE;
     78 
     79 			if ( function_exists( 'get_plugin_data' ) && file_exists( $path ) ) {
     80 				$data = get_plugin_data( $path );
     81 
     82 				if ( isset( $data ) && isset( $data['Version'] ) && '' !== $data['Version'] ) {
     83 					$res = version_compare( $data['Version'], '4', '<' );
     84 				}
     85 
     86 				if ( is_plugin_active( 'redux-framework/redux-framework.php' ) && true === $res ) {
     87 					echo '<div class="error"><p>' . esc_html__( 'Redux Framework version 4 is activated but not loaded. Redux Framework version 3 is still installed and activated.  Please deactivate Redux Framework version 3.', 'redux-framework' ) . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput
     88 					return null;
     89 				}
     90 			}
     91 
     92 			if ( ! self::$instance ) {
     93 				self::$instance = new self();
     94 				if ( class_exists( 'ReduxFramework' ) ) {
     95 					self::$instance->load_first();
     96 				} else {
     97 					self::$instance->get_redux_options();
     98 					self::$instance->includes();
     99 					self::$instance->hooks();
    100 				}
    101 			}
    102 
    103 			return self::$instance;
    104 		}
    105 
    106 		/**
    107 		 * Shim for geting instance
    108 		 *
    109 		 * @access      public
    110 		 * @since       4.0.1
    111 		 * @return      self::$instance The one true Redux_Framework_Plugin
    112 		 */
    113 		public static function get_instance(): ?Redux_Framework_Plugin {
    114 			return self::instance();
    115 		}
    116 
    117 		/**
    118 		 * Get Redux options
    119 		 *
    120 		 * @access      public
    121 		 * @since       3.1.3
    122 		 * @return      void
    123 		 */
    124 		public function get_redux_options() {
    125 
    126 			// Setup defaults.
    127 			$defaults = array(
    128 				'demo' => false,
    129 			);
    130 
    131 			// If multisite is enabled.
    132 			if ( is_multisite() ) {
    133 
    134 				// Get network activated plugins.
    135 				$plugins = get_site_option( 'active_sitewide_plugins' );
    136 
    137 				foreach ( $plugins as $file => $plugin ) {
    138 					if ( strpos( $file, 'redux-framework.php' ) !== false ) {
    139 						$this->plugin_network_activated = true;
    140 						$this->options                  = get_site_option( 'ReduxFrameworkPlugin', $defaults );
    141 					}
    142 				}
    143 			}
    144 
    145 			// If options aren't set, grab them now!
    146 			if ( empty( $this->options ) ) {
    147 				$this->options = get_option( 'ReduxFrameworkPlugin', $defaults );
    148 			}
    149 		}
    150 
    151 		/**
    152 		 * Include necessary files
    153 		 *
    154 		 * @access      public
    155 		 * @since       3.1.3
    156 		 * @return      void
    157 		 */
    158 		public function includes() {
    159 
    160 			// Include Redux_Core.
    161 			if ( file_exists( dirname( __FILE__ ) . '/redux-core/framework.php' ) ) {
    162 				require_once dirname( __FILE__ ) . '/redux-core/framework.php';
    163 			}
    164 
    165 			// Including extendify sdk.
    166 			if ( true === (bool) get_option( 'use_extendify_templates', true ) ) {
    167 				if ( file_exists( plugin_dir_path( REDUX_PLUGIN_FILE ) . 'extendify-sdk/loader.php' ) ) {
    168 					$GLOBALS['extendifySdkSourcePlugin'] = 'Redux';
    169 					require_once dirname( __FILE__ ) . '/extendify-sdk/loader.php';
    170 				}
    171 			}
    172 
    173 			if ( file_exists( dirname( __FILE__ ) . '/redux-templates/redux-templates.php' ) ) {
    174 				require_once dirname( __FILE__ ) . '/redux-templates/redux-templates.php';
    175 			}
    176 
    177 			if ( isset( Redux_Core::$as_plugin ) ) {
    178 				Redux_Core::$as_plugin = true;
    179 			}
    180 
    181 			add_action( 'setup_theme', array( $this, 'load_sample_config' ) );
    182 
    183 		}
    184 
    185 		/**
    186 		 * Loads the sample config after everything is loaded.
    187 		 *
    188 		 * @access      public
    189 		 * @since       4.0.2
    190 		 * @return      void
    191 		 */
    192 		public function load_sample_config() {
    193 			// Include demo config, if demo mode is active.
    194 			if ( $this->options['demo'] && file_exists( dirname( __FILE__ ) . '/sample/sample-config.php' ) ) {
    195 				require_once dirname( __FILE__ ) . '/sample/sample-config.php';
    196 			}
    197 		}
    198 
    199 		/**
    200 		 * Run action and filter hooks
    201 		 *
    202 		 * @access      private
    203 		 * @since       3.1.3
    204 		 * @return      void
    205 		 */
    206 		private function hooks() {
    207 			add_action( 'activated_plugin', array( $this, 'load_first' ) );
    208 			add_action( 'wp_loaded', array( $this, 'options_toggle_check' ) );
    209 
    210 			// Activate plugin when new blog is added.
    211 			add_action( 'wpmu_new_blog', array( $this, 'activate_new_site' ) );
    212 
    213 			// Display admin notices.
    214 			add_action( 'admin_notices', array( $this, 'admin_notices' ) );
    215 
    216 			// Edit plugin metalinks.
    217 			add_filter( 'plugin_row_meta', array( $this, 'plugin_metalinks' ), null, 2 );
    218 			add_filter( 'network_admin_plugin_action_links', array( $this, 'add_settings_link' ), 1, 2 );
    219 			add_filter( 'plugin_action_links', array( $this, 'add_settings_link' ), 1, 2 );
    220 
    221 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    222 			do_action( 'redux/plugin/hooks', $this );
    223 		}
    224 
    225 		/**
    226 		 * Pushes Redux to top of plugin load list, so it initializes before any plugin that may use it.
    227 		 */
    228 		public function load_first() {
    229 			if ( ! class_exists( 'Redux_Functions_Ex' ) ) {
    230 				require_once dirname( __FILE__ ) . '/redux-core/inc/classes/class-redux-functions-ex.php';
    231 			}
    232 
    233 			$plugin_dir = Redux_Functions_Ex::wp_normalize_path( WP_PLUGIN_DIR ) . '/';
    234 			$self_file  = Redux_Functions_Ex::wp_normalize_path( __FILE__ );
    235 
    236 			$path = str_replace( $plugin_dir, '', $self_file );
    237 			$path = str_replace( 'class-redux-framework-plugin.php', 'redux-framework.php', $path );
    238 
    239 			$plugins = get_option( 'active_plugins' );
    240 
    241 			if ( $plugins ) {
    242 				$key = array_search( $path, $plugins, true );
    243 
    244 				if ( false !== $key ) {
    245 					array_splice( $plugins, $key, 1 );
    246 					array_unshift( $plugins, $path );
    247 					update_option( 'active_plugins', $plugins );
    248 				}
    249 
    250 				if ( class_exists( 'Redux_Pro' ) ) {
    251 					$self_file = Redux_Functions_Ex::wp_normalize_path( Redux_Pro::$dir );
    252 					$path      = str_replace( $plugin_dir, '', $self_file );
    253 
    254 					// phpcs:ignore WordPress.NamingConventions.ValidHookName
    255 					$basename = apply_filters( 'redux/pro/basename', 'redux-pro.php' );
    256 
    257 					$key = array_search( $path . '/' . $basename, $plugins, true );
    258 					if ( false !== $key ) {
    259 						array_splice( $plugins, $key, 1 );
    260 						array_unshift( $plugins, $path . '/' . $basename );
    261 						update_option( 'active_plugins', $plugins );
    262 					}
    263 				}
    264 			}
    265 		}
    266 
    267 		/**
    268 		 * Fired on plugin activation
    269 		 *
    270 		 * @access      public
    271 		 * @since       3.0.0
    272 		 *
    273 		 * @param       boolean $network_wide True if plugin is network activated, false otherwise.
    274 		 *
    275 		 * @return      void
    276 		 */
    277 		public static function activate( bool $network_wide ) {
    278 			// phpcs:disable
    279 			//if ( function_exists( 'is_multisite' ) && is_multisite() ) {
    280 			//	if ( $network_wide ) {
    281 			//		// Get all blog IDs.
    282 			//		$blog_ids = self::get_blog_ids();
    283 			//
    284 			//		foreach ( $blog_ids as $blog_id ) {
    285 			//			switch_to_blog( $blog_id );
    286 			//			self::single_activate();
    287 			//		}
    288 			//		restore_current_blog();
    289 			//	} else {
    290 			//		self::single_activate();
    291 			//	}
    292 			//} else {
    293 			//	self::single_activate();
    294 			//}
    295 			// phpcs:enable
    296 
    297 			delete_site_transient( 'update_plugins' );
    298 		}
    299 
    300 		/**
    301 		 * Fired when plugin is deactivated
    302 		 *
    303 		 * @access      public
    304 		 * @since       3.0.0
    305 		 *
    306 		 * @param       boolean $network_wide True if plugin is network activated, false otherwise.
    307 		 *
    308 		 * @return      void
    309 		 */
    310 		public static function deactivate( bool $network_wide ) {
    311 			if ( function_exists( 'is_multisite' ) && is_multisite() ) {
    312 				if ( $network_wide ) {
    313 					// Get all blog IDs.
    314 					$blog_ids = self::get_blog_ids();
    315 
    316 					foreach ( $blog_ids as $blog_id ) {
    317 						switch_to_blog( $blog_id );
    318 						self::single_deactivate();
    319 					}
    320 					restore_current_blog();
    321 				} else {
    322 					self::single_deactivate();
    323 				}
    324 			} else {
    325 				self::single_deactivate();
    326 			}
    327 
    328 			delete_option( 'ReduxFrameworkPlugin' );
    329 			Redux_Enable_Gutenberg::cleanup_options( 'redux-framework' ); // Auto disable Gutenberg and all that.
    330 		}
    331 
    332 		/**
    333 		 * Fired when a new WPMU site is activated
    334 		 *
    335 		 * @access      public
    336 		 *
    337 		 * @param       int $blog_id The ID of the new blog.
    338 		 *
    339 		 * @return      void
    340 		 * @since       3.0.0
    341 		 */
    342 		public function activate_new_site( int $blog_id ) {
    343 			if ( 1 !== did_action( 'wpmu_new_blog' ) ) {
    344 				return;
    345 			}
    346 
    347 			switch_to_blog( $blog_id );
    348 			self::single_activate();
    349 			restore_current_blog();
    350 		}
    351 
    352 		/**
    353 		 * Get all IDs of blogs that are not activated, not spam, and not deleted
    354 		 *
    355 		 * @access      private
    356 		 * @since       3.0.0
    357 		 * @global      object $wpdb
    358 		 * @return      array|false Array of IDs or false if none are found
    359 		 */
    360 		private static function get_blog_ids() {
    361 			global $wpdb;
    362 
    363 			$var = '0';
    364 
    365 			// Get an array of IDs (We have to do it this way because WordPress says so, however reduntant).
    366 			$result = wp_cache_get( 'redux-blog-ids' );
    367 			if ( false === $result ) {
    368 
    369 				// WordPress asys get_col is discouraged?  I found no alternative.  So...ignore! - kp.
    370 				// phpcs:ignore WordPress.DB.DirectDatabaseQuery
    371 				$result = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE archived = %s AND spam = %s AND deleted = %s", $var, $var, $var ) );
    372 
    373 				wp_cache_set( 'redux-blog-ids', $result );
    374 			}
    375 
    376 			return $result;
    377 		}
    378 
    379 		/**
    380 		 * Fired for each WPMS blog on plugin activation
    381 		 *
    382 		 * @access      private
    383 		 * @since       3.0.0
    384 		 * @return      void
    385 		 */
    386 		private static function single_activate() {
    387 			$notices = array();
    388 
    389 			$nonce = wp_create_nonce( 'redux_framework_demo' );
    390 
    391 			$notices   = get_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', array() );
    392 			$notices[] = esc_html__( 'Redux Framework has an embedded demo.', 'redux-framework' ) . ' <a href="./plugins.php?redux-framework-plugin=demo&nonce=' . $nonce . '">' . esc_html__( 'Click here to activate the sample config file.', 'redux-framework' ) . '</a>';
    393 
    394 			update_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', $notices );
    395 		}
    396 
    397 		/**
    398 		 * Display admin notices
    399 		 *
    400 		 * @access      public
    401 		 * @since       3.0.0
    402 		 * @return      void
    403 		 */
    404 		public function admin_notices() {
    405 			do_action( 'redux_framework_plugin_admin_notice' );
    406 			$notices = get_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', '' );
    407 			if ( ! empty( $notices ) ) {
    408 				foreach ( $notices as $notice ) {
    409 					echo '<div class="updated notice is-dismissible"><p>' . $notice . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput
    410 				}
    411 
    412 				delete_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES' );
    413 			}
    414 		}
    415 
    416 		/**
    417 		 * Fired for each blog when the plugin is deactivated
    418 		 *
    419 		 * @access      private
    420 		 * @since       3.0.0
    421 		 * @return      void
    422 		 */
    423 		private static function single_deactivate() {
    424 			delete_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES' );
    425 		}
    426 
    427 		/**
    428 		 * Turn on or off
    429 		 *
    430 		 * @access      public
    431 		 * @since       3.0.0
    432 		 * @global      string $pagenow The current page being displayed
    433 		 * @return      void
    434 		 */
    435 		public function options_toggle_check() {
    436 			global $pagenow;
    437 
    438 			if ( isset( $_GET['nonce'] ) && wp_verify_nonce( sanitize_key( $_GET['nonce'] ), 'redux_framework_demo' ) ) {
    439 				if ( isset( $_GET['redux-framework-plugin'] ) && 'demo' === $_GET['redux-framework-plugin'] ) {
    440 					$url = admin_url( add_query_arg( array( 'page' => 'redux-framework' ), 'options-general.php' ) );
    441 
    442 					if ( false === $this->options['demo'] ) {
    443 						$this->options['demo'] = true;
    444 						$url                   = admin_url( add_query_arg( array( 'page' => 'redux_demo' ), 'admin.php' ) );
    445 					} else {
    446 						$this->options['demo'] = false;
    447 					}
    448 
    449 					if ( is_multisite() && $this->plugin_network_activated ) {
    450 						update_site_option( 'ReduxFrameworkPlugin', $this->options );
    451 					} else {
    452 						update_option( 'ReduxFrameworkPlugin', $this->options );
    453 					}
    454 
    455 					wp_safe_redirect( esc_url( $url ) );
    456 
    457 					exit();
    458 				}
    459 			}
    460 		}
    461 
    462 
    463 		/**
    464 		 * Add a settings link to the Redux entry in the plugin overview screen
    465 		 *
    466 		 * @param array  $links Links array.
    467 		 * @param string $file  Plugin filename/slug.
    468 		 *
    469 		 * @return array
    470 		 * @see   filter:plugin_action_links
    471 		 * @since 1.0
    472 		 */
    473 		public function add_settings_link( array $links, string $file ): array {
    474 
    475 			if ( strpos( REDUX_PLUGIN_FILE, $file ) === false ) {
    476 				return $links;
    477 			}
    478 
    479 			if ( ! class_exists( 'Redux_Pro' ) ) {
    480 				$links[] = sprintf(
    481 					'<a href="%s" target="_blank">%s</a>',
    482 					esc_url( $this->get_site_utm_url( '', 'upgrade' ) ),
    483 					sprintf(
    484 						'<span style="font-weight: bold;">%s</span>',
    485 						__( 'Go Pro', 'redux-framework' )
    486 					)
    487 				);
    488 			}
    489 
    490 			return $links;
    491 		}
    492 
    493 		/**
    494 		 * Get the url where the Admin Columns website is hosted
    495 		 *
    496 		 * @param string $path Path to add to url.
    497 		 *
    498 		 * @return string
    499 		 */
    500 		private function get_site_url( string $path = '' ): string {
    501 			$url = 'https://redux.io';
    502 
    503 			if ( ! empty( $path ) ) {
    504 				$url .= '/' . trim( $path, '/' ) . '/';
    505 			}
    506 
    507 			return $url;
    508 		}
    509 
    510 		/**
    511 		 * Url with utm tags
    512 		 *
    513 		 * @param string      $path         Path on site.
    514 		 * @param string      $utm_medium   Medium var.
    515 		 * @param string|null $utm_content  Content var.
    516 		 * @param bool        $utm_campaign Campaign var.
    517 		 *
    518 		 * @return string
    519 		 */
    520 		public function get_site_utm_url( string $path, string $utm_medium, string $utm_content = null, bool $utm_campaign = false ): string {
    521 			$url = self::get_site_url( $path );
    522 
    523 			if ( ! $utm_campaign ) {
    524 				$utm_campaign = 'plugin-installation';
    525 			}
    526 
    527 			$args = array(
    528 				// Referrer: plugin.
    529 				'utm_source'   => 'plugin-installation',
    530 
    531 				// Specific promotions or sales.
    532 				'utm_campaign' => $utm_campaign,
    533 
    534 				// Marketing medium: banner, documentation or email.
    535 				'utm_medium'   => $utm_medium,
    536 
    537 				// Used for differentiation of medium.
    538 				'utm_content'  => $utm_content,
    539 			);
    540 
    541 			$args = array_map( 'sanitize_key', array_filter( $args ) );
    542 
    543 			return add_query_arg( $args, $url );
    544 		}
    545 
    546 		/**
    547 		 * Edit plugin metalinks
    548 		 *
    549 		 * @access      public
    550 		 *
    551 		 * @param array  $links The current array of links.
    552 		 * @param string $file  A specific plugin row.
    553 		 *
    554 		 * @return      array The modified array of links
    555 		 * @since       3.0.0
    556 		 */
    557 		public function plugin_metalinks( array $links, string $file ): array {
    558 			if ( strpos( $file, 'redux-framework.php' ) !== false && is_plugin_active( $file ) ) {
    559 				$links[] = '<a href="' . esc_url( admin_url( add_query_arg( array( 'page' => 'redux-framework' ), 'options-general.php' ) ) ) . '">' . esc_html__( 'What is this?', 'redux-framework' ) . '</a>';
    560 
    561 				if ( true === Redux_Core::$redux_templates_enabled ) {
    562 					$links[] = '<a href="' . esc_url( admin_url( add_query_arg( array( 'post_type' => 'page' ), 'post-new.php' ) ) ) . '#redux_templates=1">' . esc_html__( 'Template Library', 'redux-framework' ) . '</a>';
    563 				}
    564 			}
    565 
    566 			return $links;
    567 		}
    568 	}
    569 	if ( ! class_exists( 'ReduxFrameworkPlugin' ) ) {
    570 		class_alias( 'Redux_Framework_Plugin', 'ReduxFrameworkPlugin' );
    571 	}
    572 }