PluginProbe ʕ •ᴥ•ʔ
Redux Framework / 4.3.8
Redux Framework v4.3.8
trunk 4.3.0 4.3.1 4.3.10 4.3.11 4.3.12 4.3.13 4.3.14 4.3.15 4.3.16 4.3.17 4.3.18 4.3.19 4.3.2 4.3.20 4.3.21 4.3.22 4.3.24 4.3.25 4.3.26 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.10 4.4.11 4.4.12 4.4.13 4.4.14 4.4.15 4.4.16 4.4.17 4.4.18 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1 4.5.10 4.5.11 4.5.2 4.5.3 4.5.4 4.5.6 4.5.7 4.5.8 4.5.9
redux-framework / class-redux-framework-plugin.php
redux-framework Last commit date
ReduxCore 4 years ago extendify-sdk 4 years ago redux-core 4 years ago redux-templates 4 years ago sample 4 years ago class-redux-framework-plugin.php 4 years ago index.php 4 years ago license.txt 4 years ago readme.txt 4 years ago redux-framework.php 4 years ago uninstall.php 4 years ago wpml-config.xml 4 years ago
class-redux-framework-plugin.php
550 lines
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 hyphens, 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 $res = false;
79
80 if ( function_exists( 'get_plugin_data' ) && file_exists( $path ) ) {
81 $data = get_plugin_data( $path );
82
83 if ( isset( $data ) && isset( $data['Version'] ) && '' !== $data['Version'] ) {
84 $res = version_compare( $data['Version'], '4', '<' );
85 }
86
87 if ( is_plugin_active( 'redux-framework/redux-framework.php' ) && true === $res ) {
88 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
89 return null;
90 }
91 }
92
93 if ( ! self::$instance ) {
94 self::$instance = new self();
95 if ( class_exists( 'ReduxFramework' ) ) {
96 self::$instance->load_first();
97 } else {
98 self::$instance->get_redux_options();
99 self::$instance->includes();
100 self::$instance->hooks();
101 }
102 }
103
104 return self::$instance;
105 }
106
107 /**
108 * Shim for getting instance
109 *
110 * @access public
111 * @since 4.0.1
112 * @return self::$instance The one true Redux_Framework_Plugin
113 */
114 public static function get_instance(): ?Redux_Framework_Plugin {
115 return self::instance();
116 }
117
118 /**
119 * Get Redux options
120 *
121 * @access public
122 * @since 3.1.3
123 * @return void
124 */
125 public function get_redux_options() {
126
127 // Setup defaults.
128 $defaults = array(
129 'demo' => false,
130 );
131
132 // If multisite is enabled.
133 if ( is_multisite() ) {
134
135 // Get network activated plugins.
136 $plugins = get_site_option( 'active_sitewide_plugins' );
137
138 foreach ( $plugins as $file => $plugin ) {
139 if ( strpos( $file, 'redux-framework.php' ) !== false ) {
140 $this->plugin_network_activated = true;
141 $this->options = get_site_option( 'ReduxFrameworkPlugin', $defaults );
142 }
143 }
144 }
145
146 // If options aren't set, grab them now!
147 if ( empty( $this->options ) ) {
148 $this->options = get_option( 'ReduxFrameworkPlugin', $defaults );
149 }
150 }
151
152 /**
153 * Include necessary files
154 *
155 * @access public
156 * @since 3.1.3
157 * @return void
158 */
159 public function includes() {
160
161 // Include Redux_Core.
162 if ( file_exists( dirname( __FILE__ ) . '/redux-core/framework.php' ) ) {
163 require_once dirname( __FILE__ ) . '/redux-core/framework.php';
164 }
165
166 Redux_Core::$redux_templates_enabled = (bool) get_option( 'use_redux_templates' );
167 Redux_Core::$extendify_templates_enabled = (bool) get_option( 'use_extendify_templates', true );
168
169 // Including extendify sdk.
170 if ( true === (bool) get_option( 'use_extendify_templates', true ) ) {
171 if ( file_exists( dirname( __FILE__ ) . '/extendify-sdk/loader.php' ) ) {
172 $GLOBALS['extendify_sdk_partner'] = 'Redux';
173 require_once dirname( __FILE__ ) . '/extendify-sdk/loader.php';
174 }
175 }
176
177 if ( file_exists( dirname( __FILE__ ) . '/redux-templates/redux-templates.php' ) ) {
178 require_once dirname( __FILE__ ) . '/redux-templates/redux-templates.php';
179 }
180
181 if ( isset( Redux_Core::$as_plugin ) ) {
182 Redux_Core::$as_plugin = true;
183 }
184
185 add_action( 'setup_theme', array( $this, 'load_sample_config' ) );
186
187 }
188
189 /**
190 * Loads the sample config after everything is loaded.
191 *
192 * @access public
193 * @since 4.0.2
194 * @return void
195 */
196 public function load_sample_config() {
197 // Include demo config, if demo mode is active.
198 if ( $this->options['demo'] && file_exists( dirname( __FILE__ ) . '/sample/sample-config.php' ) ) {
199 require_once dirname( __FILE__ ) . '/sample/sample-config.php';
200 }
201 }
202
203 /**
204 * Run action and filter hooks
205 *
206 * @access private
207 * @since 3.1.3
208 * @return void
209 */
210 private function hooks() {
211 add_action( 'activated_plugin', array( $this, 'load_first' ) );
212 add_action( 'wp_loaded', array( $this, 'options_toggle_check' ) );
213
214 // Activate plugin when new blog is added.
215 add_action( 'wpmu_new_blog', array( $this, 'activate_new_site' ) );
216
217 // Display admin notices.
218 add_action( 'admin_notices', array( $this, 'admin_notices' ) );
219
220 // Edit plugin metalinks.
221 add_filter( 'plugin_row_meta', array( $this, 'plugin_metalinks' ), null, 2 );
222 add_filter( 'network_admin_plugin_action_links', array( $this, 'add_settings_link' ), 1, 2 );
223 add_filter( 'plugin_action_links', array( $this, 'add_settings_link' ), 1, 2 );
224
225 // phpcs:ignore WordPress.NamingConventions.ValidHookName
226 do_action( 'redux/plugin/hooks', $this );
227 }
228
229 /**
230 * Pushes Redux to top of plugin load list, so it initializes before any plugin that may use it.
231 */
232 public function load_first() {
233 if ( ! class_exists( 'Redux_Functions_Ex' ) ) {
234 require_once dirname( __FILE__ ) . '/redux-core/inc/classes/class-redux-functions-ex.php';
235 }
236
237 $plugin_dir = Redux_Functions_Ex::wp_normalize_path( WP_PLUGIN_DIR ) . '/';
238 $self_file = Redux_Functions_Ex::wp_normalize_path( __FILE__ );
239
240 $path = str_replace( $plugin_dir, '', $self_file );
241 $path = str_replace( 'class-redux-framework-plugin.php', 'redux-framework.php', $path );
242
243 $plugins = get_option( 'active_plugins' );
244
245 if ( $plugins ) {
246 $key = array_search( $path, $plugins, true );
247
248 if ( false !== $key ) {
249 array_splice( $plugins, $key, 1 );
250 array_unshift( $plugins, $path );
251 update_option( 'active_plugins', $plugins );
252 }
253
254 if ( class_exists( 'Redux_Pro' ) ) {
255 $self_file = Redux_Functions_Ex::wp_normalize_path( Redux_Pro::$dir );
256 $path = str_replace( $plugin_dir, '', $self_file );
257
258 // phpcs:ignore WordPress.NamingConventions.ValidHookName
259 $basename = apply_filters( 'redux/pro/basename', 'redux-pro.php' );
260
261 $key = array_search( $path . '/' . $basename, $plugins, true );
262 if ( false !== $key ) {
263 array_splice( $plugins, $key, 1 );
264 array_unshift( $plugins, $path . '/' . $basename );
265 update_option( 'active_plugins', $plugins );
266 }
267 }
268 }
269 }
270
271 /**
272 * Fired on plugin activation
273 *
274 * @access public
275 * @return void
276 * @since 3.0.0
277 */
278 public static function activate() {
279 delete_site_transient( 'update_plugins' );
280 }
281
282 /**
283 * Fired when plugin is deactivated
284 *
285 * @access public
286 * @since 3.0.0
287 *
288 * @param boolean $network_wide True if plugin is network activated, false otherwise.
289 *
290 * @return void
291 */
292 public static function deactivate( ?bool $network_wide ) {
293 if ( function_exists( 'is_multisite' ) && is_multisite() ) {
294 if ( $network_wide ) {
295 // Get all blog IDs.
296 $blog_ids = self::get_blog_ids();
297
298 foreach ( $blog_ids as $blog_id ) {
299 switch_to_blog( $blog_id );
300 self::single_deactivate();
301 }
302 restore_current_blog();
303 } else {
304 self::single_deactivate();
305 }
306 } else {
307 self::single_deactivate();
308 }
309
310 delete_option( 'ReduxFrameworkPlugin' );
311 Redux_Enable_Gutenberg::cleanup_options( 'redux-framework' ); // Auto disable Gutenberg and all that.
312 }
313
314 /**
315 * Fired when a new WPMU site is activated
316 *
317 * @access public
318 *
319 * @param int $blog_id The ID of the new blog.
320 *
321 * @return void
322 * @since 3.0.0
323 */
324 public function activate_new_site( int $blog_id ) {
325 if ( 1 !== did_action( 'wpmu_new_blog' ) ) {
326 return;
327 }
328
329 switch_to_blog( $blog_id );
330 self::single_activate();
331 restore_current_blog();
332 }
333
334 /**
335 * Get all IDs of blogs that are not activated, not spam, and not deleted
336 *
337 * @access private
338 * @since 3.0.0
339 * @global object $wpdb
340 * @return array|false Array of IDs or false if none are found
341 */
342 private static function get_blog_ids() {
343 global $wpdb;
344
345 $var = '0';
346
347 // Get an array of IDs (We have to do it this way because WordPress says so, however redundant).
348 $result = wp_cache_get( 'redux-blog-ids' );
349 if ( false === $result ) {
350
351 // WordPress says get_col is discouraged? I found no alternative. So...ignore! - kp.
352 // phpcs:ignore WordPress.DB.DirectDatabaseQuery
353 $result = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE archived = %s AND spam = %s AND deleted = %s", $var, $var, $var ) );
354
355 wp_cache_set( 'redux-blog-ids', $result );
356 }
357
358 return $result;
359 }
360
361 /**
362 * Fired for each WPMS blog on plugin activation
363 *
364 * @access private
365 * @since 3.0.0
366 * @return void
367 */
368 private static function single_activate() {
369 $nonce = wp_create_nonce( 'redux_framework_demo' );
370
371 $notices = get_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', array() );
372 $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>';
373
374 update_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', $notices );
375 }
376
377 /**
378 * Display admin notices
379 *
380 * @access public
381 * @since 3.0.0
382 * @return void
383 */
384 public function admin_notices() {
385 do_action( 'redux_framework_plugin_admin_notice' );
386 $notices = get_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES', '' );
387 if ( ! empty( $notices ) ) {
388 foreach ( $notices as $notice ) {
389 echo '<div class="updated notice is-dismissible"><p>' . $notice . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput
390 }
391
392 delete_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES' );
393 }
394 }
395
396 /**
397 * Fired for each blog when the plugin is deactivated
398 *
399 * @access private
400 * @since 3.0.0
401 * @return void
402 */
403 private static function single_deactivate() {
404 delete_option( 'ReduxFrameworkPlugin_ACTIVATED_NOTICES' );
405 }
406
407 /**
408 * Turn on or off
409 *
410 * @access public
411 * @since 3.0.0
412 * @return void
413 */
414 public function options_toggle_check() {
415 if ( isset( $_GET['nonce'] ) && wp_verify_nonce( sanitize_key( $_GET['nonce'] ), 'redux_framework_demo' ) ) {
416 if ( isset( $_GET['redux-framework-plugin'] ) && 'demo' === $_GET['redux-framework-plugin'] ) {
417 $url = admin_url( add_query_arg( array( 'page' => 'redux-framework' ), 'options-general.php' ) );
418
419 if ( false === $this->options['demo'] ) {
420 $this->options['demo'] = true;
421 $url = admin_url( add_query_arg( array( 'page' => 'redux_demo' ), 'admin.php' ) );
422 } else {
423 $this->options['demo'] = false;
424 }
425
426 if ( is_multisite() && $this->plugin_network_activated ) {
427 update_site_option( 'ReduxFrameworkPlugin', $this->options );
428 } else {
429 update_option( 'ReduxFrameworkPlugin', $this->options );
430 }
431
432 wp_safe_redirect( esc_url( $url ) );
433
434 exit();
435 }
436 }
437 }
438
439
440 /**
441 * Add a settings link to the Redux entry in the plugin overview screen
442 *
443 * @param array $links Links array.
444 * @param string $file Plugin filename/slug.
445 *
446 * @return array
447 * @see filter:plugin_action_links
448 * @since 1.0
449 */
450 public function add_settings_link( array $links, string $file ): array {
451
452 if ( strpos( REDUX_PLUGIN_FILE, $file ) === false ) {
453 return $links;
454 }
455
456 if ( ! class_exists( 'Redux_Pro' ) ) {
457 $links[] = sprintf(
458 '<a href="%s" target="_blank">%s</a>',
459 esc_url( $this->get_site_utm_url( '', 'upgrade' ) ),
460 sprintf(
461 '<span style="font-weight: bold;">%s</span>',
462 __( 'Go Pro', 'redux-framework' )
463 )
464 );
465 }
466
467 return $links;
468 }
469
470 /**
471 * Get the url where the Admin Columns website is hosted
472 *
473 * @param string $path Path to add to url.
474 *
475 * @return string
476 */
477 private function get_site_url( string $path = '' ): string {
478 $url = 'https://redux.io';
479
480 if ( ! empty( $path ) ) {
481 $url .= '/' . trim( $path, '/' ) . '/';
482 }
483
484 return $url;
485 }
486
487 /**
488 * Url with utm tags
489 *
490 * @param string $path Path on site.
491 * @param string $utm_medium Medium var.
492 * @param string|null $utm_content Content var.
493 * @param bool $utm_campaign Campaign var.
494 *
495 * @return string
496 */
497 public function get_site_utm_url( string $path, string $utm_medium, string $utm_content = null, bool $utm_campaign = false ): string {
498 $url = self::get_site_url( $path );
499
500 if ( ! $utm_campaign ) {
501 $utm_campaign = 'plugin-installation';
502 }
503
504 $args = array(
505 // Referrer: plugin.
506 'utm_source' => 'plugin-installation',
507
508 // Specific promotions or sales.
509 'utm_campaign' => $utm_campaign,
510
511 // Marketing medium: banner, documentation or email.
512 'utm_medium' => $utm_medium,
513
514 // Used for differentiation of medium.
515 'utm_content' => $utm_content,
516 );
517
518 $args = array_map( 'sanitize_key', array_filter( $args ) );
519
520 return add_query_arg( $args, $url );
521 }
522
523 /**
524 * Edit plugin metalinks
525 *
526 * @access public
527 *
528 * @param array $links The current array of links.
529 * @param string $file A specific plugin row.
530 *
531 * @return array The modified array of links
532 * @since 3.0.0
533 */
534 public function plugin_metalinks( array $links, string $file ): array {
535 if ( strpos( $file, 'redux-framework.php' ) !== false && is_plugin_active( $file ) ) {
536 $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>';
537
538 if ( true === Redux_Core::$redux_templates_enabled ) {
539 $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>';
540 }
541 }
542
543 return $links;
544 }
545 }
546 if ( ! class_exists( 'ReduxFrameworkPlugin' ) ) {
547 class_alias( 'Redux_Framework_Plugin', 'ReduxFrameworkPlugin' );
548 }
549 }
550