* ET_Core_CompatibilityWarning class file.
* @class ET_Core_CompatibilityWarning
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
if ( ! class_exists( 'ET_Core_CompatibilityWarning' ) ) :
* Plugin & theme compatibility warning system backported from WP 5.5.
* This system is only intended for users who use Divi theme with WP 5.4.2 below and Divi
* Builder plugin with WP 5.2 below. There are some areas where it overrides or modifies
* the themes & plugins management template to show warnings when the current WP and/or
* PHP versions doesn't work with the current and/or upcoming ET plugins/themes.
* 1. Plugins list section.
* 2. Themes list section.
* On each of incompatible themes, shows warning and disables Activate & Live Preview
* buttons when the theme is not activated yet.
* 1. Themes List (tmpl-theme).
* 2. Theme Details (tmpl-theme-single).
* On each of incompatible themes, shows warning and disables Live Preview button when
* the theme is not activated yet. In addition, disable Publish button for the current
* 1. Themes List (tmpl-theme).
* 2. Theme Details (tmpl-theme-single).
* 3. Publish Button for current active theme.
* 1. Plugins List via `after_plugin_row_` action hook.
* 2. Plugin activation warning. ET plugins that want to use this warning should
* register `maybe_deactivate_incompatible_plugin()` on their activation hook.
class ET_Core_CompatibilityWarning {
* @var ET_Core_CompatibilityWarning
public static $instance_class;
* WP version where the official warning system is introduced.
public $supported_wp_version = array(
public function __construct() {
// Ensure the system is loaded on lower version of supported version.
if ( version_compare( $wp_version, $this->supported_wp_version[ ET_CORE_TYPE ], '>=' ) ) {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
// A. Update Core - Overrides plugins and themes updates table body.
add_action( 'admin_print_footer_scripts-update-core.php', array( $this, 'overrides_update_core_plugins_table_body' ) );
add_action( 'admin_print_footer_scripts-update-core.php', array( $this, 'overrides_update_core_themes_table_body' ) );
// B. Manage Themes - Overrides themes list & details templates.
add_filter( 'wp_prepare_themes_for_js', array( $this, 'set_theme_additional_properties' ) );
add_action( 'admin_print_footer_scripts-themes.php', array( $this, 'overrides_tmpl_theme' ) );
// C. Theme Customizer - Overrides themes list & details templates.
add_action( 'customize_controls_print_footer_scripts', array( $this, 'overrides_tmpl_customize_control_theme_content' ) );
// D. Plugins - Overrides current plugin list. Default priority is 20.
add_action( 'load-plugins.php', array( $this, 'overrides_plugins_table_rows' ), 21 );
* Returns instance of the class.
* @return ET_Core_CompatibilityWarning
public static function instance() {
if ( ! isset( self::$instance_class ) ) {
self::$instance_class = new self();
return self::$instance_class;
* Set theme additional properties before it's rendered on Manage Themes page.
* @param array $prepared_themes List of available themes.
public function set_theme_additional_properties( $prepared_themes ) {
// Bail early if the $prepared_themes is empty.
if ( empty( $prepared_themes ) ) {
// 1. Get available themes update.
$theme_updates = array();
if ( current_user_can( 'update_themes' ) ) {
$updates_themes_transient = get_site_transient( 'update_themes' );
if ( isset( $updates_themes_transient->response ) ) {
$theme_updates = $updates_themes_transient->response;
// 2. Assign compatibility properties.
$themes = $prepared_themes;
foreach ( $themes as $theme_slug => $theme_info ) {
// Ensure style.css file exist.
$theme_root = get_theme_root( $theme_slug );
$theme_file = "{$theme_root}/{$theme_slug}/style.css";
if ( ! file_exists( $theme_file ) ) {
// Get WP & PHP compatibility info.
$theme_headers = get_file_data(
'RequiresWP' => 'Requires at least',
'RequiresPHP' => 'Requires PHP',
$require_wp = et_()->array_get( $theme_headers, 'RequiresWP', null );
$require_php = et_()->array_get( $theme_headers, 'RequiresPHP', null );
$update_requires_wp = et_()->array_get( $theme_updates, array( $theme_slug, 'requires' ), null );
$update_requires_php = et_()->array_get( $theme_updates, array( $theme_slug, 'requires_php' ), null );
$compatibility_properties = array(
'compatibleWP' => is_wp_version_compatible( $require_wp ),
'compatiblePHP' => is_php_version_compatible( $require_php ),
'updateResponse' => array(
'compatibleWP' => is_wp_version_compatible( $update_requires_wp ),
'compatiblePHP' => is_php_version_compatible( $update_requires_php ),
$prepared_themes[ $theme_slug ] = array_merge( $prepared_themes[ $theme_slug ], $compatibility_properties );
* Get plugins data for Update Core page.
* The data processing is backported from WP 5.5 with few modification.
* @see {list_plugin_updates()} of WP 5.5
public function get_update_core_plugins_data() {
$plugin_updates = get_plugin_updates();
$plugin_processed = array();
// Bail early if there is no plugin updates.
if ( empty( $plugin_updates ) ) {
foreach ( $plugin_updates as $plugin_file => $plugin_data ) {
// reason: The properties come from WP plugin data.
// phpcs:disable ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase
$plugin_name = $plugin_data->Name;
$plugin_version = $plugin_data->Version;
// a. Get current and update WP version.
$wp_version = get_bloginfo( 'version' );
$cur_wp_version = preg_replace( '/-.*$/', '', $wp_version );
$core_updates = get_core_updates();
if ( ! isset( $core_updates[0]->response ) || 'latest' === $core_updates[0]->response || 'development' === $core_updates[0]->response || version_compare( $core_updates[0]->current, $cur_wp_version, '=' ) ) {
$core_update_version = false;
$core_update_version = $core_updates[0]->current;
// b. Check PHP versions compatibility. WP doesn't check WP versions compatibility.
$requires_php = isset( $plugin_data->update->requires_php ) ? $plugin_data->update->requires_php : null;
$compatible_php = is_php_version_compatible( $requires_php );
$icon = '<span class="dashicons dashicons-admin-plugins"></span>';
$preferred_icons = array( 'svg', '2x', '1x', 'default' );
foreach ( $preferred_icons as $preferred_icon ) {
if ( ! empty( $plugin_data->update->icons[ $preferred_icon ] ) ) {
$icon = '<img src="' . esc_url( $plugin_data->update->icons[ $preferred_icon ] ) . '" alt="" />';
// d. Process compatibility warning text.
// Get plugin compat for running version of WordPress.
if ( isset( $plugin_data->update->tested ) && version_compare( $plugin_data->update->tested, $cur_wp_version, '>=' ) ) {
/* translators: %s: WordPress version. */
$compat = '<br />' . sprintf( __( 'Compatibility with WordPress %s: 100%% (according to its author)' ), $cur_wp_version );
/* translators: %s: WordPress version. */
$compat = '<br />' . sprintf( __( 'Compatibility with WordPress %s: Unknown' ), $cur_wp_version );
// Get plugin compat for updated version of WordPress.
if ( $core_update_version ) {
if ( isset( $plugin_data->update->tested ) && version_compare( $plugin_data->update->tested, $core_update_version, '>=' ) ) {
/* translators: %s: WordPress version. */
$compat .= '<br />' . sprintf( __( 'Compatibility with WordPress %s: 100%% (according to its author)' ), $core_update_version );
/* translators: %s: WordPress version. */
$compat .= '<br />' . sprintf( __( 'Compatibility with WordPress %s: Unknown' ), $core_update_version );
// Get plugin compat for updated version of PHP.
if ( ! $compatible_php && current_user_can( 'update_php' ) ) {
$compat .= '<br>' . __( 'This update doesn’t work with your version of PHP.' ) . ' ';
/* translators: %s: URL to Update PHP page. */
__( '<a href="%s">Learn more about updating PHP</a>.' ),
esc_url( wp_get_update_php_url() )
$annotation = wp_get_update_php_annotation();
$compat .= '</p><p><em>' . $annotation . '</em>';
// Get the upgrade notice for the new plugin version.
if ( isset( $plugin_data->update->upgrade_notice ) ) {
$upgrade_notice = '<br />' . wp_strip_all_tags( $plugin_data->update->upgrade_notice );
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data->update->slug . '§ion=changelog&TB_iframe=true&width=640&height=662' );
'<a href="%1$s" class="thickbox open-plugin-details-modal" aria-label="%2$s">%3$s</a>',
/* translators: 1: Plugin name, 2: Version number. */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $plugin_data->update->new_version ) ),
/* translators: %s: Plugin version. */
sprintf( __( 'View version %s details.' ), $plugin_data->update->new_version )
$checkbox_id = 'checkbox_' . md5( $plugin_name );
// Plugin template properties. There is no compatible_wp property passed here.
$plugin_processed[ $plugin_file ] = array(
'plugin_file' => esc_attr( $plugin_file ),
'name' => esc_attr( $plugin_name ),
'checkbox_id' => esc_attr( 'checkbox_' . md5( $plugin_name ) ),
'icon' => et_core_intentionally_unescaped( $icon, 'html' ),
'version' => esc_attr( $plugin_version ),
'new_version' => esc_attr( $plugin_data->update->new_version ),
'compatible_php' => $compatible_php,
'compat' => et_core_intentionally_unescaped( $compat, 'html' ),
'upgrade_notice' => et_core_intentionally_unescaped( $upgrade_notice, 'html' ),
'details' => et_core_intentionally_unescaped( $details, 'html' ),
return $plugin_processed;
* Get themes data for Update Core page.
public function get_update_core_themes_data() {
$theme_updates = get_theme_updates();
$theme_processed = array();
// Bail early if there is no theme updates.
if ( empty( $theme_updates ) ) {
foreach ( $theme_updates as $stylesheet => $theme ) {
// a. Check compatibility.
$requires_wp = et_()->array_get( $theme->update, 'requires', null );
$requires_php = et_()->array_get( $theme->update, 'requires_php', null );
$compatible_wp = is_wp_version_compatible( $requires_wp );
$compatible_php = is_php_version_compatible( $requires_php );
// b. Process compatibility warning text.
if ( ! $compatible_wp && ! $compatible_php ) {
$compat .= '<br>' . __( 'This update doesn’t work with your versions of WordPress and PHP.' ) . ' ';
if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
__( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
esc_url( self_admin_url( 'update-core.php' ) ),
esc_url( wp_get_update_php_url() )
$annotation = wp_get_update_php_annotation();
$compat .= '</p><p><em>' . $annotation . '</em>';
} elseif ( current_user_can( 'update_core' ) ) {
/* translators: %s: URL to WordPress Updates screen. */
__( '<a href="%s">Please update WordPress</a>.' ),
esc_url( self_admin_url( 'update-core.php' ) )
} elseif ( current_user_can( 'update_php' ) ) {
/* translators: %s: URL to Update PHP page. */
__( '<a href="%s">Learn more about updating PHP</a>.' ),
esc_url( wp_get_update_php_url() )
$annotation = wp_get_update_php_annotation();
$compat .= '</p><p><em>' . $annotation . '</em>';
} elseif ( ! $compatible_wp ) {
$compat .= '<br>' . __( 'This update doesn’t work with your version of WordPress.' ) . ' ';
if ( current_user_can( 'update_core' ) ) {
/* translators: %s: URL to WordPress Updates screen. */
__( '<a href="%s">Please update WordPress</a>.' ),
esc_url( self_admin_url( 'update-core.php' ) )
} elseif ( ! $compatible_php ) {
$compat .= '<br>' . __( 'This update doesn’t work with your version of PHP.' ) . ' ';
if ( current_user_can( 'update_php' ) ) {
/* translators: %s: URL to Update PHP page. */
__( '<a href="%s">Learn more about updating PHP</a>.' ),
esc_url( wp_get_update_php_url() )
$annotation = wp_get_update_php_annotation();
$compat .= '</p><p><em>' . $annotation . '</em>';
// Theme template properties.
$theme_processed[ $stylesheet ] = array(
'stylesheet' => esc_attr( $stylesheet ),
'name' => esc_attr( $theme->display( 'Name' ) ),
'checkbox_id' => esc_attr( 'checkbox_' . md5( $theme->get( 'Name' ) ) ),
'screenshot' => esc_url( $theme->get_screenshot() ),
'version' => esc_attr( $theme->display( 'Version' ) ),
'new_version' => esc_attr( et_()->array_get( $theme->update, 'new_version', '' ) ),
'compatible_wp' => $compatible_wp,
'compatible_php' => $compatible_php,
'compat' => et_core_esc_previously( $compat ),
* Enqueue compatibility warning scripts and its local data.
public function enqueue_scripts() {
global $pagenow, $wp_customize;
// Bail early if the current page is not one of the allowed pages.
if ( ! in_array( $pagenow, $allowed_pages, true ) ) {
wp_enqueue_script( 'et_compatibility_warning_script', ET_CORE_URL . 'admin/js/compatibility-warning.js', array( 'jquery' ), ET_CORE_VERSION, true );
$compatibility_warning = array();
if ( 'update-core.php' === $pagenow ) {
$compatibility_warning['update_core_data'] = array(
'plugins' => self::get_update_core_plugins_data(),
'themes' => self::get_update_core_themes_data(),
} elseif ( 'themes.php' === $pagenow ) {
$compatibility_warning['manage_themes_data'] = true;
} elseif ( 'customize.php' === $pagenow ) {
// Theme Customizer - Used for disable publish button.
$compatibility_warning['customizer_data'] = array(
'compatible_wp' => is_wp_version_compatible( $wp_customize->theme()->get( 'RequiresWP' ) ),
'compatible_php' => is_php_version_compatible( $wp_customize->theme()->get( 'RequiresPHP' ) ),
'disabled_text' => esc_html_x( 'Cannot Activate', 'theme' ),
wp_localize_script( 'et_compatibility_warning_script', 'et_compatibility_warning', $compatibility_warning );
* Overrides table body of plugin updates section.
* The structure is backported from WP 5.5 without any modification.
* @see {list_plugin_updates()} of WP 5.5
public function overrides_update_core_plugins_table_body() {
// Bail early if there is no plugin updates.
if ( empty( get_plugin_updates() ) ) {
<script type="text/html" id="tmpl-et-update-core-plugins-table-body">
<# if (data.plugins) { #>
<# _.each(data.plugins, function(plugin, slug) { #>
<td class="check-column">
<# if (plugin.compatible_php) { #>
<input type="checkbox" name="checked[]" id="{{plugin.checkbox_id}}" value="{{plugin.plugin_file}}" />
<label for="{{plugin.checkbox_id}}" class="screen-reader-text">
/* translators: %s: Plugin name. */
printf( esc_html__( 'Select %s' ), '{{plugin.name}}' );
<td class="plugin-title"><p>
<strong>{{plugin.name}}</strong>
/* translators: 1: Plugin version, 2: New version. */
esc_html__( 'You have version %1$s installed. Update to %2$s.' ),
echo ' {{{plugin.details}}}{{{plugin.compat}}}{{{plugin.upgrade_notice}}}';