class-redux-enable-gutenberg.php (15597B)
1 <?php 2 /** 3 * Redux Enable Gutenberg Class 4 * 5 * @class Redux_Enable_Gutenberg 6 * @version 4.0.0 7 * @package Redux Framework 8 * @author Dovy Pauksts of Redux.io 9 */ 10 11 // Exit if accessed directly. 12 defined( 'ABSPATH' ) || exit; 13 14 15 if ( ! class_exists( 'Redux_Enable_Gutenberg', false ) ) { 16 17 /** 18 * Main Feedback Notice Class 19 */ 20 class Redux_Enable_Gutenberg { 21 22 /** 23 * Slug. 24 * 25 * @var string $slug 26 */ 27 private $slug; 28 29 /** 30 * No Bug Option. 31 * 32 * @var string $nobug_option 33 */ 34 public $nobug_option; 35 36 /** 37 * Auto Enable Option. 38 * 39 * @var string $autoenable_option 40 */ 41 public $autoenable_option; 42 43 /** 44 * Auto deactivate Option. 45 * 46 * @var string $decativate_option 47 */ 48 public $decativate_option; 49 50 /** 51 * Nonce string. 52 * 53 * @var string $nonce 54 */ 55 public $nonce; 56 57 /** 58 * Disabled by the theme. 59 * 60 * @var bool 61 */ 62 protected static $theme_disabled = false; 63 64 /** 65 * Disabled at all. 66 * 67 * @var bool 68 */ 69 public static $is_disabled = false; 70 71 /** 72 * Quick fix known plugins that disable. 73 * 74 * @var array 75 */ 76 protected static $known_plugins = array(); 77 78 /** 79 * Class constructor. 80 * 81 * @param array $args Arguments. 82 */ 83 public function __construct( array $args = array() ) { 84 global $pagenow; 85 86 $defaults = array( 87 'slug' => '', 88 'name' => '', 89 ); 90 $args = wp_parse_args( $args, $defaults ); 91 92 if ( empty( $args['slug'] ) ) { 93 echo 'You must pass a slug to the Redux_Enable_Gutenberg() constructor.'; 94 95 return; 96 } 97 98 if ( strpos( $args['slug'], 'gutenberg' ) === false ) { 99 $args['slug'] .= '-gutenberg'; 100 } 101 $this->slug = $args['slug']; 102 $this->nobug_option = $this->slug . '-no-bug'; 103 $this->nonce = $this->slug . '-nonce'; 104 $this->autoenable_option = $this->slug . '-force-enable'; 105 $this->decativate_option = $this->slug . '-deactivate-plugins'; 106 107 if ( is_admin() && ! self::$is_disabled && ( 'post-new.php' === $pagenow || 'post.php' === $pagenow ) && ! get_site_option( $this->nobug_option ) ) { 108 // We only want to do this for posts or pages. 109 if ( ! isset( $_GET['post_type'] ) || ( isset( $_GET['post_type'] ) && 'page' === $_GET['post_type'] ) ) { // phpcs:ignore 110 add_action( 'init', array( $this, 'check_init' ), 998 ); 111 add_action( 'init', array( $this, 'run_user_actions' ), 999 ); 112 if ( ! get_site_option( $this->nobug_option ) ) { 113 add_action( 'plugins_loaded', array( $this, 'check_plugin' ), 999 ); 114 add_action( 'after_setup_theme', array( $this, 'check_theme' ), 999 ); 115 add_action( 'admin_notices', array( $this, 'display_admin_notice' ) ); 116 } 117 } 118 } 119 } 120 121 /** 122 * Cleanup for plugin deactivation. 123 * 124 * @param string $slug Slug for instance. 125 */ 126 public static function cleanup_options( string $slug = '' ) { 127 if ( ! empty( $slug ) ) { 128 $obj = new Redux_Enable_Gutenberg( 129 array( 130 'slug' => $slug, 131 'name' => '', 132 ) 133 ); 134 delete_site_option( $obj->autoenable_option ); 135 delete_site_option( $obj->nobug_option ); 136 } 137 } 138 139 /** 140 * Display the admin notice. 141 */ 142 public function display_admin_notice() { 143 if ( ! self::$is_disabled ) { 144 return; 145 } 146 global $pagenow; 147 148 $clean_get = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 149 if ( isset( $clean_get[ $this->nobug_option ] ) ) { 150 unset( $clean_get[ $this->nobug_option ] ); 151 } 152 if ( isset( $clean_get[ $this->autoenable_option ] ) ) { 153 unset( $clean_get[ $this->autoenable_option ] ); 154 } 155 if ( isset( $clean_get[ $this->decativate_option ] ) ) { 156 unset( $clean_get[ $this->decativate_option ] ); 157 } 158 $base_url = admin_url( add_query_arg( $clean_get, $pagenow ) ); 159 160 $no_bug_url = wp_nonce_url( add_query_arg( $this->nobug_option, true, $base_url ), $this->nonce ); 161 $auto_enable_url = wp_nonce_url( add_query_arg( $this->autoenable_option, true, $base_url ), $this->nonce ); 162 $deativate_url = wp_nonce_url( add_query_arg( $this->decativate_option, true, $base_url ), $this->nonce ); 163 164 $data = array( 165 'url' => '', 166 'content' => '', 167 'header' => __( 'Gutenberg is currently disabled!', 'redux-framework' ), 168 'button' => '', 169 ); 170 171 if ( isset( $_GET[ $this->decativate_option ] ) || empty( self::$known_plugins ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended 172 173 if ( isset( $_GET[ $this->decativate_option ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended 174 // That didn't work. 175 $data['header'] = __( 'Hmm, it seems something else is disabling Gutenberg...', 'redux-framework' ); 176 $data['content'] = sprintf( '<p>' . esc_html( "Well seems like we have more to do. Don't worry, we can still fix this! Click the $1%sEnable Gutenberg$2%s button and Redux will enable Gutenberg for you." ) . '</p>', '<strong>', '</strong>' ); 177 } elseif ( self::$theme_disabled ) { 178 $data['header'] = __( 'Your theme author has disabled Gutenberg!', 'redux-framework' ); 179 $data['content'] .= sprintf( '<p>' . esc_html( "It looks like your theme has disabled Gutenberg. Don\'t panic though! Click the $1%sEnable Gutenberg$2%s button to the right and Redux will enable Gutenberg for you." ) . '</p>', '<strong>', '</strong>' ); 180 } else { 181 $data['header'] = __( 'Looks like something has disabled Gutenberg?', 'redux-framework' ); 182 $data['content'] .= sprintf( '<p>' . esc_html( "Did you know that Gutenberg is disabled? If that\'s intended you can dismiss this notice, not what you intended? Click $1%sEnable Gutenberg$2%s and Redux will automatically fix this for you." ) . '</p>', '<strong>', '</strong>' ); 183 } 184 185 $data['url'] = $auto_enable_url; 186 $data['button'] = __( 'Enable Gutenberg', 'redux-framework' ); 187 188 } elseif ( empty( self::$known_plugins ) ) { 189 // Disabled by the theme or other. 190 $data['header'] = __( 'Your theme', 'redux-framework' ); 191 $data['url'] = $auto_enable_url; 192 $data['button'] = __( 'Enable Gutenberg', 'redux-framework' ); 193 } else { 194 // Disable Plugins! 195 $all_plugins = get_plugins(); 196 197 $plugins = ''; 198 199 foreach ( self::$known_plugins as $slug ) { 200 if ( isset( $all_plugins[ $slug ] ) ) { 201 if ( ! empty( $plugins ) ) { 202 $plugins .= ', '; 203 } 204 $plugins .= '<code>' . esc_html( $all_plugins[ $slug ]['Name'] ) . '</code>'; 205 } 206 } 207 208 $data['url'] = $deativate_url; 209 if ( 1 === count( self::$known_plugins ) ) { 210 $data['button'] = __( 'Disable Plugin', 'redux-framework' ); 211 $data['content'] = sprintf( '<p>The following plugin is preventing Gutenberg from working: %s. To automatically fix the issue click the <strong>Disable Plugin</strong> button on the right and Redux will enable it for you.</p>', $plugins, esc_url( 'https://kinsta.com/blog/gutenberg-wordpress-editor/' ) ); 212 } else { 213 $data['button'] = __( 'Disable Plugins', 'redux-framework' ); 214 $data['content'] = sprintf( '<p>The following plugin is preventing Gutenberg from working: %s. To automatically fix the issue click the <strong>Disable Plugins</strong> button on the right and Redux will enable it for you.</p>', $plugins, esc_url( 'https://kinsta.com/blog/gutenberg-wordpress-editor/' ) ); 215 } 216 } 217 218 ?> 219 <style> 220 .notice.redux-notice { 221 border-left-color: #24b0a6 !important; 222 padding: 20px; 223 } 224 225 .rtl .notice.redux-notice { 226 border-right-color: #19837c !important; 227 } 228 229 .notice.notice.redux-notice .redux-notice-inner { 230 display: table; 231 width: 100%; 232 } 233 234 .notice.redux-notice .redux-notice-inner .redux-notice-icon, 235 .notice.redux-notice .redux-notice-inner .redux-notice-content, 236 .notice.redux-notice .redux-notice-inner .redux-install-now { 237 display: table-cell; 238 vertical-align: middle; 239 } 240 241 .notice.redux-notice .redux-notice-icon { 242 color: #509ed2; 243 font-size: 13px; 244 width: 60px; 245 } 246 247 .notice.redux-notice .redux-notice-icon img { 248 width: 64px; 249 } 250 251 .notice.redux-notice .redux-notice-content { 252 padding: 0 40px 0 20px; 253 } 254 255 .notice.redux-notice p { 256 padding: 0; 257 margin: 0; 258 } 259 260 .notice.redux-notice h3 { 261 margin: 0 0 5px; 262 } 263 264 .notice.redux-notice .redux-install-now { 265 text-align: center; 266 width: 20%; 267 } 268 269 .notice.redux-notice .redux-install-now .redux-install-button { 270 padding: 6px 50px; 271 height: auto; 272 line-height: 20px; 273 background: #24b0a6; 274 border-color: transparent; 275 font-weight: bold; 276 } 277 278 .notice.redux-notice .redux-install-now .redux-install-button:hover { 279 background: #19837c; 280 } 281 282 .notice.redux-notice a.no-thanks { 283 display: block; 284 margin-top: 10px; 285 color: #72777c; 286 text-decoration: none; 287 } 288 289 .notice.redux-notice a.no-thanks:hover { 290 color: #444; 291 } 292 293 @media (max-width: 767px) { 294 295 .notice.notice.redux-notice .redux-notice-inner { 296 display: block; 297 } 298 299 .notice.redux-notice { 300 padding: 20px !important; 301 } 302 303 .notice.redux-noticee .redux-notice-inner { 304 display: block; 305 } 306 307 .notice.redux-notice .redux-notice-inner .redux-notice-content { 308 display: block; 309 padding: 0; 310 } 311 312 .notice.redux-notice .redux-notice-inner .redux-notice-icon { 313 display: none; 314 } 315 316 .notice.redux-notice .redux-notice-inner .redux-install-now { 317 margin-top: 20px; 318 display: block; 319 text-align: left; 320 } 321 322 .notice.redux-notice .redux-notice-inner .no-thanks { 323 display: inline-block; 324 margin-left: 15px; 325 } 326 } 327 </style> 328 <div class="notice updated redux-notice"> 329 <div class="redux-notice-inner"> 330 <div class="redux-notice-icon"> 331 <?php /* translators: 1. Name */ ?> 332 <img src="<?php echo esc_url( Redux_Core::$url . '/assets/img/icon--color.svg' ); ?>" alt="<?php echo esc_attr__( 'Redux WordPress Plugin', 'redux-framework' ); ?>"/> 333 </div> 334 <div class="redux-notice-content"> 335 <?php /* translators: 1. Name */ ?> 336 <h3><?php printf( esc_html( $data['header'] ) ); ?></h3> 337 <?php printf( $data['content'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> 338 </div> 339 <div class="redux-install-now"> 340 <?php printf( '<a href="%1$s" class="button button-primary redux-install-button">%2$s</a>', esc_url( $data['url'] ), esc_html( $data['button'] ) ); ?> 341 <a href="<?php echo esc_url( $no_bug_url ); ?>" class="no-thanks"><?php echo esc_html__( 'No Thanks', 'redux-framework' ); ?></a> 342 </div> 343 </div> 344 </div> 345 <?php 346 } 347 348 /** 349 * Set the plugin to no longer bug users if user asks not to be. 350 */ 351 public function run_user_actions() { 352 // Bail out if not on correct page. 353 // phpcs:ignore 354 if ( ! isset( $_GET['_wpnonce'] ) || ( ! wp_verify_nonce( $_GET['_wpnonce'], $this->nonce ) || ! is_admin() || ! current_user_can( 'manage_options' ) ) ) { 355 return; 356 } 357 358 if ( isset( $_GET[ $this->nobug_option ] ) ) { // User doesn't want to see this anymore. 359 add_site_option( $this->nobug_option, true ); 360 } elseif ( isset( $_GET[ $this->autoenable_option ] ) ) { // User has opted to just auto-enable Gutenberg. 361 unset( $_GET[ $this->autoenable_option ] ); 362 add_site_option( $this->autoenable_option, true ); 363 } elseif ( isset( $_GET[ $this->decativate_option ] ) && ! empty( self::$known_plugins ) ) { // User has opted to disable known gutenberg plugins. 364 deactivate_plugins( self::$known_plugins ); 365 } 366 global $pagenow; 367 unset( $_GET['_wpnonce'] ); 368 $url = admin_url( add_query_arg( $_GET, $pagenow ) ); 369 wp_safe_redirect( $url ); 370 371 exit(); 372 373 } 374 375 /** 376 * Set the plugin to no longer bug users if user asks not to be. 377 */ 378 public function set_auto_disable() { 379 380 // Bail out if not on correct page. 381 // phpcs:ignore 382 if ( ! isset( $_GET['_wpnonce'] ) || ( ! wp_verify_nonce( $_GET['_wpnonce'], $this->nonce ) || ! is_admin() || ! isset( $_GET[ $this->autoenable_option ] ) || ! current_user_can( 'manage_options' ) ) ) { 383 return; 384 } 385 386 add_site_option( $this->autoenable_option, true ); 387 } 388 389 /** 390 * Check for filter method. 391 */ 392 private function check_for_filter(): bool { 393 if ( version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' ) ) { 394 if ( has_filter( 'use_block_editor_for_post_type', '__return_false' ) ) { 395 return true; 396 } 397 } else { 398 if ( has_filter( 'gutenberg_can_edit_post_type', '__return_false' ) ) { 399 return true; // WP < 5 beta. 400 } 401 } 402 403 return false; 404 } 405 406 /** 407 * Remove the Gutenberg disable filter for posts and pages only. 408 */ 409 private function remove_filter() { 410 global $pagenow; 411 412 if ( is_admin() && ( 'post-new.php' === $pagenow || 'post.php' === $pagenow ) ) { 413 // We only want to do this for posts or pages. 414 if ( ! isset( $_GET['post_type'] ) || ( isset( $_GET['post_type'] ) && 'page' === $_GET['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended 415 if ( version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' ) ) { 416 // WP > 5 beta. 417 remove_filter( 'use_block_editor_for_post_type', '__return_false' ); 418 } else { 419 // WP < 5 beta. 420 remove_filter( 'gutenberg_can_edit_post_type', '__return_false' ); 421 } 422 } 423 } 424 } 425 426 /** 427 * Quick checks against known plugins for disabling. 428 */ 429 public function quick_checks() { 430 // Testing for known plugins if they're loaded, save on filters and performance. 431 if ( class_exists( 'Classic_Editor' ) ) { 432 $a = new \ReflectionClass( 'Classic_Editor' ); 433 self::$known_plugins[] = plugin_basename( $a->getFileName() ); 434 } 435 436 if ( defined( 'DISABLE_GUTENBERG_FILE' ) ) { 437 self::$known_plugins[] = plugin_basename( DISABLE_GUTENBERG_FILE ); 438 } 439 440 if ( defined( 'ADE_PLUGIN_DIR_PATH' ) ) { 441 if ( class_exists( 'CodePopular_disable_gutenburg' ) ) { 442 $a = new \ReflectionClass( 'CodePopular_disable_gutenburg' ); 443 self::$known_plugins[] = plugin_basename( $a->getFileName() ); 444 } else { 445 self::$known_plugins[] = plugin_basename( ADE_PLUGIN_DIR_PATH ) . '/auto-disable-gutenberg.php'; 446 } 447 } 448 self::$known_plugins[] = 'no-gutenberg/no-gutenberg.php'; 449 self::$known_plugins[] = 'enable-classic-editor/enable-classic-editor.php'; 450 451 $plugins = get_option( 'active_plugins' ); 452 $results = array_intersect( $plugins, self::$known_plugins ); 453 self::$known_plugins = $results; 454 if ( ! empty( self::$known_plugins ) ) { 455 self::$is_disabled = true; 456 } 457 } 458 459 /** 460 * Check if plugins have the disable filter. 461 */ 462 public function check_plugin() { 463 $this->quick_checks(); 464 if ( ! self::$is_disabled && $this->check_for_filter() ) { 465 self::$is_disabled = true; 466 } 467 } 468 469 /** 470 * Check if the theme have the disable filter. 471 */ 472 public function check_theme() { 473 if ( ! self::$is_disabled && $this->check_for_filter() ) { 474 self::$theme_disabled = true; 475 self::$is_disabled = true; 476 } 477 } 478 479 /** 480 * Check if init hook still has the disable filter. 481 */ 482 public function check_init() { 483 if ( ! self::$is_disabled ) { 484 if ( $this->check_for_filter() ) { 485 self::$is_disabled = true; 486 } 487 } 488 489 if ( self::$is_disabled && get_site_option( $this->autoenable_option ) ) { 490 $this->remove_filter(); 491 } 492 493 } 494 } 495 496 /* 497 * Instantiate the Redux_Enable_Gutenberg class. 498 */ 499 new Redux_Enable_Gutenberg( 500 array( 501 'slug' => 'redux-framework', 502 'name' => __( 'Redux', 'redux-framework' ), 503 ) 504 ); 505 506 }