* @license GNU General Public License v2
*
* @since 3.24.1 Renamed from `ET_Support_Center` to `ET_Core_SupportCenter`.
* @since 3.20
*/
class ET_Core_SupportCenter {
/**
* Catch whether the ET_DEBUG flag is set.
*
* @since 3.20
*
* @type string
*/
protected $DEBUG_ET_SUPPORT_CENTER = false;
/**
* Identifier for the parent theme or plugin activating the Support Center.
*
* @since 3.20
*
* @type string
*/
protected $parent = '';
/**
* "Nice name" for the parent theme or plugin activating the Support Center.
*
* @since 3.20
*
* @type string
*/
protected $parent_nicename = '';
/**
* Whether the Support Center was activated through a `plugin` or a `theme`.
*
* @since 3.20
*
* @type string
*/
protected $child_of = '';
/**
* Identifier for the parent theme or plugin activating the Support Center.
*
* @since 3.20
*
* @type string
*/
protected $local_path;
/**
* Support User options
*
* @since 3.20
*
* @type array
*/
protected $support_user_options;
/**
* Support User account name
*
* @since 3.20
*
* @type string
*/
protected $support_user_account_name = 'elegant_themes_support';
/**
* Support options name in the database
*
* @since 3.20
*
* @type string
*/
protected $support_user_options_name = 'et_support_options';
/**
* Name of the cron job we use to auto-delete the Support User account
*
* @since 3.20
*
* @type string
*/
protected $support_user_cron_name = 'et_cron_delete_support_account';
/**
* Expiration time to auto-delete the Support User account via cron
*
* @since 3.20
*
* @type string
*/
protected $support_user_expiration_time = '+4 days';
/**
* Provide nicename equivalents for boolean values
*
* @since 3.23
*
* @type array
*/
protected $boolean_label = array( 'False', 'True' );
/**
* Collection of plugins that we will NOT disable when Safe Mode is activated.
*
* @since 3.20
*
* @type array
*/
protected $safe_mode_plugins_allowlist = array(
'etdev/etdev.php', // ET Development Workspace
'bloom/bloom.php', // ET Bloom Plugin
'monarch/monarch.php', // ET Monarch Plugin
'divi-builder/divi-builder.php', // ET Divi Builder Plugin
'divi-dash/divi-dash.php', // Divi Dash Plugin
'ari-adminer/ari-adminer.php', // ARI Adminer
'query-monitor/query-monitor.php', // Query Monitor
'woocommerce/woocommerce.php', // WooCommerce
'really-simple-ssl/rlrsssl-really-simple-ssl.php', // Really Simple SSL
);
/**
* Capabilities that should be granted to the Administrator role on activation.
*
* @since 3.28
*
* @type array
*/
protected $support_center_administrator_caps = array(
'et_support_center',
'et_support_center_system',
'et_support_center_remote_access',
'et_support_center_documentation',
'et_support_center_safe_mode',
'et_support_center_logs',
);
/**
* Collection of Cards that has button to dismiss the Card.
*
* @since 4.4.7
*
* @type array
*/
protected $card_with_dismiss_button = array(
'et_hosting_card',
);
/**
* Core functionality of the class
*
* @since 4.4.7 Added WP AJAX action for dismissible button for a card
* @since 3.20
*
* @param string $parent Identifier for the parent theme or plugin activating the Support Center.
*/
public function __construct( $parent = '' ) {
// Dont run if the user is not logged in.
if ( ! is_user_logged_in() ) {
return;
}
// Verbose logging: only log if `wp-config.php` has defined `ET_DEBUG='support_center'`
$this->DEBUG_ET_SUPPORT_CENTER = defined( 'ET_DEBUG' ) && 'support_center' === ET_DEBUG;
// Set the identifier for the parent theme or plugin activating the Support Center.
$this->parent = $parent;
// Get `et_support_options` settings & set $this->support_user_options
$this->support_user_get_options();
// Set the plugins allowlist for Safe Mode
$this->set_safe_mode_plugins_allowlist();
}
/**
* WordPress action & filter setup
*
* @since 3.20
*/
public function init() {
// Dont run if the user is not logged in.
if ( ! is_user_logged_in() ) {
return;
}
// Set the Support Center as installed.
update_option( 'et_support_center_installed', 'true' );
// Establish which theme or plugin has loaded the Support Center
$this->set_parent_properties();
// When initialized, deactivate conflicting plugins
$this->deactivate_conflicting_plugins();
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) );
// SC scripts are only used in FE for the "Turn Off Divi Safe Mode" floating button.
if ( et_core_is_safe_mode_active() ) {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) );
}
// Get Site ID with Elegant Themes API & token (needed in advance for Remote Access).
add_action( 'admin_init', array( $this, 'maybe_set_site_id' ) );
// Add extra User Role capabilities needed for Remote Access to work with 3rd party software
add_filter( 'add_et_support_standard_capabilities', array( $this, 'support_user_extra_caps_standard' ), 10, 1 );
// Make sure that our Support Account's role is set up.
add_filter( 'add_et_builder_role_options', array( $this, 'support_user_add_role_options' ), 10, 1 );
// On Multisite installs, grant `unfiltered_html` capabilities to the Support User
add_filter( 'map_meta_cap', array( $this, 'support_user_map_meta_cap' ), 1, 3 );
// Add CSS class name(s) to the Support Center page's body tag
add_filter( 'admin_body_class', array( $this, 'add_admin_body_class_name' ) );
// Add a link to the Support Center in the admin menu
add_filter( 'admin_menu', array( $this, 'add_admin_menu_item' ) );
// When Safe Mode is enabled, add floating frontend indicator
add_action( 'admin_footer', array( $this, 'maybe_add_safe_mode_indicator' ) );
add_action( 'wp_footer', array( $this, 'maybe_add_safe_mode_indicator' ) );
// Add User capabilities to the Administrator Role
add_action( 'admin_init', array( $this, 'support_center_capabilities_setup' ) );
if ( 'plugin' === $this->child_of ) {
// Delete our Support User settings on deactivation
register_deactivation_hook( __FILE__, array( $this, 'support_user_delete_account' ) );
register_deactivation_hook( __FILE__, array( $this, 'unlist_support_center' ) );
register_deactivation_hook( __FILE__, array( $this, 'support_center_capabilities_teardown' ) );
}
if ( 'theme' === $this->child_of ) {
// Delete our Support User settings on deactivation
add_action( 'switch_theme', array( $this, 'maybe_deactivate_on_theme_switch' ) );
}
// Automatically delete our Support User when the time runs out
add_action( $this->support_user_cron_name, array( $this, 'support_user_cron_maybe_delete_account' ) );
add_action( 'init', array( $this, 'support_user_maybe_delete_expired_account' ) );
add_action( 'admin_init', array( $this, 'support_user_maybe_delete_expired_account' ) );
// Remove KSES filters for ET Support User
add_action( 'admin_init', array( $this, 'support_user_kses_remove_filters' ) );
// Update Support User settings via AJAX
add_action( 'wp_ajax_et_support_user_update', array( $this, 'support_user_update_via_ajax' ) );
// Toggle Safe Mode via AJAX
add_action( 'wp_ajax_et_safe_mode_update', array( $this, 'safe_mode_update_via_ajax' ) );
// Safe Mode: Block restricted actions when Safe Mode active
add_action( 'admin_footer', array( $this, 'render_safe_mode_block_restricted' ) );
// Safe Mode: Temporarily disable Custom CSS
add_action( 'init', array( $this, 'maybe_disable_custom_css' ) );
// Safe Mode: Remove "Additional CSS" from WP Head action hook
if ( et_core_is_safe_mode_active() ) {
remove_action( 'wp_head', 'wp_custom_css_cb', 101 );
}
// Support Center Card: Handle Dismiss Button
add_action( 'wp_ajax_et_dismiss_support_center_card', array( $this, 'dismiss_support_center_card_via_ajax' ) );
}
/**
* Add User capabilities to the Administrator Role (if it exists) on first run
*
* @since 3.29.2 Added check to verify the Administrator Role exists before attempting to run `add_cap()`.
* @since 3.28
*/
public function support_center_capabilities_setup() {
$support_capabilities = get_option( 'et_support_center_setup_done' );
$administrator_role = get_role( 'administrator' );
if ( $administrator_role && ! $support_capabilities ) {
foreach ( $this->support_center_administrator_caps as $cap ) {
$administrator_role->add_cap( $cap );
}
update_option( 'et_support_center_setup_done', 'processed' );
}
}
/**
* Remove User capabilities from the Administrator Role when product with Support Center is removed
*
* @since 3.29.2 Added check to verify the Administrator Role exists before attempting to run `remove_cap()`.
* @since 3.28
*/
public function support_center_capabilities_teardown() {
$support_capabilities = get_option( 'et_support_center_setup_done' );
$administrator_role = get_role( 'administrator' );
if ( $administrator_role && $support_capabilities ) {
foreach ( $this->support_center_administrator_caps as $cap ) {
$administrator_role->remove_cap( $cap );
}
delete_option( 'et_support_center_setup_done' );
}
}
/**
* Set variables that change depending on whether a theme or a plugin activated the Support Center
*
* @since 3.20
*/
public function set_parent_properties() {
$core_path = _et_core_normalize_path( trailingslashit( dirname( __FILE__ ) ) );
$theme_dir = _et_core_normalize_path( trailingslashit( realpath( get_template_directory() ) ) );
if ( 0 === strpos( $core_path, $theme_dir ) ) {
$this->child_of = 'theme';
$this->local_path = trailingslashit( get_template_directory_uri() . '/core/' );
} else {
$this->child_of = 'plugin';
$this->local_path = plugins_url( '/', dirname( __FILE__ ) );
}
$this->parent_nicename = $this->get_parent_nicename( $this->parent );
}
/**
* Get the "Nice Name" for the parent theme/plugin
*
* @param $parent
*
* @return bool|string
*/
public function get_parent_nicename( $parent ) {
switch ( $parent ) {
case 'bloom_plugin':
return 'Bloom';
break;
case 'monarch_plugin':
return 'Monarch';
break;
case 'extra_theme':
return 'Extra';
break;
case 'divi_theme':
return 'Divi';
break;
case 'divi_builder_plugin':
return 'Divi Builder';
break;
case 'divi_dash_plugin':
return 'Divi Dash';
break;
default:
return false;
}
}
/**
* Prevent any possible conflicts with the Elegant Themes Support plugin
*
* @since 3.20
*/
public function deactivate_conflicting_plugins() {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
// Load WP user management functions
if ( is_multisite() ) {
require_once( ABSPATH . 'wp-admin/includes/ms.php' );
} else {
require_once( ABSPATH . 'wp-admin/includes/user.php' );
}
// Verify that WP user management functions are available
$can_delete_user = false;
if ( is_multisite() && function_exists( 'wpmu_delete_user' ) ) {
$can_delete_user = true;
}
if ( ! is_multisite() && function_exists( 'wp_delete_user' ) ) {
$can_delete_user = true;
}
if ( $can_delete_user ) {
deactivate_plugins( '/elegant-themes-support/elegant-themes-support.php' );
} else {
et_error( 'Support Center: Unable to deactivate the ET Support Plugin.' );
}
}
/**
* @param string $capability
*
* @return bool
*/
protected function current_user_can( $capability = '' ) {
if ( function_exists( 'et_is_builder_plugin_active' ) ) {
return et_pb_is_allowed( $capability );
}
return current_user_can( $capability );
}
/**
* Add Safe Mode Autoloader Must-Use Plugin
*
* @since 3.20
*/
public function maybe_add_mu_autoloader() {
$file_name = '/SupportCenterMUAutoloader.php';
$file_path = dirname( __FILE__ );
// Exit if the `mu-plugins` directory doesn't exist & we're unable to create it
if ( ! wp_mkdir_p( WPMU_PLUGIN_DIR ) ) {
et_error( 'Support Center Safe Mode: mu-plugin folder not found.' );
return;
}
$pathname_to = WPMU_PLUGIN_DIR . $file_name;
$pathname_from = $file_path . $file_name;
// Exit if we can't find the mu-plugins autoloader
if ( ! file_exists( $pathname_from ) ) {
et_error( 'Support Center Safe Mode: mu-plugin autoloader not found.' );
return;
}
// Try to create a new subdirectory for our mu-plugins; if it fails, log an error message
$pathname_plugins_from = dirname( __FILE__ ) . '/mu-plugins';
$pathname_plugins_to = WPMU_PLUGIN_DIR . '/et-safe-mode';
if ( ! wp_mkdir_p( $pathname_plugins_to ) ) {
et_error( 'Support Center Safe Mode: mu-plugins subfolder not found.' );
return;
}
// Try to copy the mu-plugins; if any fail, log an error message
if ( $mu_plugins = glob( dirname( __FILE__ ) . '/mu-plugins/*.php' ) ) {
foreach ( $mu_plugins as $plugin ) {
$new_file_path = str_replace( $pathname_plugins_from, $pathname_plugins_to, $plugin );
// Skip if this particular mu-plugin hasn't changed
if ( file_exists( $new_file_path ) && md5_file( $new_file_path ) === md5_file( $plugin ) ) {
continue;
}
$copy_file = @copy( $plugin, $new_file_path );
if ( ! $this->DEBUG_ET_SUPPORT_CENTER ) {
continue;
}
if ( $copy_file ) {
et_error( 'Support Center Safe Mode: mu-plugin [' . $plugin . '] installed.' );
} else {
et_error( 'Support Center Safe Mode: mu-plugin [' . $plugin . '] failed installation. ' );
}
}
}
// Finally, try to copy the autoloader file; if it fails, log an error message
// Skip if the mu-plugins autoloader hasn't changed
if ( file_exists( $pathname_to ) && md5_file( $pathname_to ) === md5_file( $pathname_from ) ) {
return;
}
$copy_file = @copy( $pathname_from, $pathname_to );
if ( $this->DEBUG_ET_SUPPORT_CENTER ) {
if ( $copy_file ) {
et_error( 'Support Center Safe Mode: mu-plugin installed.' );
} else {
et_error( 'Support Center Safe Mode: mu-plugin failed installation. ' );
}
}
}
public function maybe_remove_mu_autoloader() {
@unlink( WPMU_PLUGIN_DIR . '/SupportCenterMUAutoloader.php' );
@unlink( WPMU_PLUGIN_DIR . '/et-safe-mode/SupportCenterSafeModeDisablePlugins.php' );
et_()->remove_empty_directories( WPMU_PLUGIN_DIR . '/et-safe-mode' );
}
/**
* Update the Site ID data via Elegant Themes API
*
* @since ?.? Early exit if no Site ID, but also no API credentials to use for a request.
* @since 3.20
*
* @return void
*/
public function maybe_set_site_id() {
// Early exit if the user doesn't have Support Center access.
if ( ! $this->current_user_can( 'et_support_center' ) ) {
return;
}
$site_id = get_option( 'et_support_site_id' );
// If we already have a saved Site ID for support, then we don't need to request a new ID.
if ( ! empty( $site_id ) ) {
return;
}
// If there are no saved API credentials, then we can't use the API to request a Site ID for support.
if ( ! $this->get_et_license() ) {
return;
}
$site_id = '';
$send_to_api = array(
'action' => 'get_site_id',
);
$settings = array(
'timeout' => 30,
'body' => $send_to_api,
);
$request = wp_remote_post( 'https://www.elegantthemes.com/api/token.php', $settings );
if ( ! is_wp_error( $request ) && 200 == wp_remote_retrieve_response_code( $request ) ) {
$response = unserialize( wp_remote_retrieve_body( $request ) );
if ( ! empty( $response['site_id'] ) ) {
$site_id = esc_attr( $response['site_id'] );
}
}
update_option( 'et_support_site_id', $site_id );
}
/**
* Safe Mode temporarily deactivates all plugins *except* those in the allowlist option set here
*
* @since 3.20
*
* @return void
*/
public function set_safe_mode_plugins_allowlist() {
update_option( 'et_safe_mode_plugins_allowlist', $this->safe_mode_plugins_allowlist );
}
/**
* Add Support Center menu item (but only if it's enabled for current user)
*
* When initialized we were given an identifier for the plugin or theme doing the initializing. We're going to use
* that identifier here to insert the Support Center menu item in the correct location within the WP Admin Menu.
*
* @since 3.28 Expanded sub-menu links with support for additional ET products.
* @since 3.20
*/
public function add_admin_menu_item() {
// Early exit if the user doesn't have Support Center access
if ( ! $this->current_user_can( 'et_support_center' ) ) {
return;
}
$menu_title = esc_html__( 'Support Center', 'et-core' );
$menu_slug = null;
$parent_menu_slug = null;
// By default, only user with `manage_options` capability which is "administrator"
// can see Support Center menu and access the page.
$capability = 'manage_options';
// Define parent and child menu slugs
switch ( $this->parent ) {
case 'bloom_plugin':
$menu_slug = 'et_support_center_bloom';
$parent_menu_slug = 'et_bloom_options';
break;
case 'monarch_plugin':
$menu_title = esc_html__( 'Monarch Support Center', 'et-core' );
$menu_slug = 'et_support_center_monarch';
$parent_menu_slug = 'tools.php';
break;
case 'extra_theme':
$menu_slug = 'et_support_center_extra';
$parent_menu_slug = 'et_extra_options';
break;
case 'divi_theme':
case 'divi_builder_plugin':
// In the Roles Editor, other user roles may have access to the Support Center.
// But, most likely they don't have `manage_options` capability. So, if current
// user can't `manage_options`, we will set the submenu capability into the
// `edit_theme_options`, so other roles with `edit_theme_options` capability
// can access the Support Center.
if ( ! current_user_can( 'manage_options' ) ) {
$capability = 'edit_theme_options';
}
// However, that's not enough. We still need to check whether current user with
// `manage_options` or `edit_theme_options` is allowed to access Support Center.
if ( ! et_pb_is_allowed( 'support_center' ) ) {
return;
}
$menu_slug = 'et_support_center_divi';
$parent_menu_slug = 'et_divi_options';
}
// If there's no menu slug, then this product doesn't have Support Center enabled
if ( ! $menu_slug ) {
return;
}
// Build the link
add_submenu_page(
$parent_menu_slug,
$menu_title,
$menu_title,
$capability,
$menu_slug,
array( $this, 'add_support_center' )
);
}
/**
* Add class name to Support Center page
*
* @since 3.20
*
* @param string $admin_classes Current class names for the body tag.
*
* @return string
*/
public function add_admin_body_class_name( $admin_classes = '' ) {
$classes = explode( ' ', $admin_classes );
$classes[] = 'et-admin-page';
if ( et_core_is_safe_mode_active() ) {
$classes[] = 'et-safe-mode-active';
}
return implode( ' ', $classes );
}
/**
* Support Center admin page JS
*
* @since 3.20
*
* @param $hook string Unique identifier for WP admin page.
*
* @return void
*/
public function admin_enqueue_scripts_styles( $hook ) {
et_core_register_admin_assets();
wp_enqueue_style( 'et-core-admin' );
wp_enqueue_script( 'et-core-admin' );
et_core_load_main_fonts();
// Load only on `_et_support_center` pages.
if ( strpos( $hook, '_et_support_center' ) ) {
// Core Admin CSS
wp_enqueue_style( 'et-core',
$this->local_path . 'admin/css/core.css',
array(),
ET_CORE_VERSION
);
// ePanel CSS
wp_enqueue_style( 'et-wp-admin',
$this->local_path . 'admin/css/wp-admin.css',
array(),
ET_CORE_VERSION
);
// Support Center CSS
wp_enqueue_style( 'et-support-center',
$this->local_path . 'admin/css/support-center.css',
array(),
ET_CORE_VERSION
);
// Support Center uses ePanel controls, so include the necessary scripts
if ( function_exists( 'et_core_enqueue_js_admin' ) ) {
et_core_enqueue_js_admin();
}
}
}
/**
* Support Center frontend CSS/JS
*
* @since 3.20
*
* @param $hook string Unique identifier for WP admin page.
*
* @return void
*/
public function enqueue_scripts_styles( $hook ) {
// We only need to add this for authenticated users on the frontend
if ( ! is_user_logged_in() ) {
return;
}
// Support Center JS
wp_enqueue_script( 'et-support-center',
$this->local_path . 'admin/js/support-center.js',
array( 'jquery', 'underscore' ),
ET_CORE_VERSION,
true
);
$support_center_nonce = wp_create_nonce( 'support_center' );
$etSupportCenterSettings = array(
'ajaxLoaderImg' => esc_url( $this->local_path . 'admin/images/ajax-loader.gif' ),
'ajaxURL' => admin_url( 'admin-ajax.php' ),
'siteURL' => get_site_url(),
'supportCenterURL' => get_admin_url( null, 'admin.php?page=et_support_center#et_card_safe_mode' ),
'nonce' => $support_center_nonce,
);
wp_localize_script( 'et-support-center', 'etSupportCenter', $etSupportCenterSettings );
}
/**
* Divi Support Center :: Card
*
* Take an array of attributes and build a WP Card block for display on the Divi Support Center page.
*
* @since 4.4.7 Added optional dismissible button
* @since 3.20
*
* @param array $attrs
*
* @return string
*/
protected function add_support_center_card( $attrs = array( 'title' => '', 'content' => '' ) ) {
$card_classes = array(
'card',
);
if ( array_key_exists( 'additional_classes', $attrs ) ) {
$card_classes = array_merge( $card_classes, $attrs['additional_classes'] );
}
$dismiss_button = '';
if ( array_key_exists( 'dismiss_button', $attrs ) ) {
// Update card class to indicate the presence of the dismiss button
$card_classes = array_merge( $card_classes, array( 'has-dismiss-button' ) );
// Prepare Class for the Dismiss button
$dismiss_button_classes = array( 'et-dismiss-button' );
if ( array_key_exists( 'additional_classes', $attrs['dismiss_button'] ) ) {
$dismiss_button_classes = array_merge( $dismiss_button_classes, $attrs['dismiss_button']['additional_classes'] );
}
// Whether to display tooltip for the dismiss button
$dismiss_button_has_tooltip = array_key_exists( 'tooltip', $attrs['dismiss_button'] );
// HTML Template for the dismiss button
$dismiss_button = PHP_EOL . "\t" . sprintf(
'',
esc_html__( 'Dismiss', 'et-core' ),
esc_attr( implode( ' ', $dismiss_button_classes ) ),
esc_attr( $attrs['dismiss_button']['card_key'] ),
esc_attr( $this->parent ),
$dismiss_button_has_tooltip ? 'data-tippy-content="' . esc_attr( $attrs['dismiss_button']['tooltip'] ) . '"' : ''
);
}
$card = PHP_EOL . '
',
$articles_list_html
);
return $html;
}
/**
* Look for Elegant Themes Support Account
*
* @since 3.20
*
* @return WP_User|false WP_User object on success, false on failure.
*/
public function get_et_support_user() {
return get_user_by( 'slug', $this->support_user_account_name );
}
/**
* Look for saved Elegant Themes Username & API Key
*
* @since 3.20
*
* @return array|false license credentials on success, false on failure.
*/
public function get_et_license() {
/** @var array License credentials [username|api_key] */
if ( ! $et_license = get_site_option( 'et_automatic_updates_options' ) ) {
$et_license = get_option( 'et_automatic_updates_options', array() );
}
if ( ! et_()->array_get( $et_license, 'username' ) ) {
return false;
}
if ( ! et_()->array_get( $et_license, 'api_key' ) ) {
return false;
}
return $et_license;
}
/**
* Try to load the WP debug log. If found, return the last [$lines_to_return] lines of the file and the filesize.
*
* @since 3.20
*
* @param int $lines_to_return Number of lines to read and return from the end of the wp_debug.log file.
*
* @return array
*/
protected function get_wp_debug_log( $lines_to_return = 10 ) {
$log = array(
'entries' => '',
'size' => 0,
);
// Early exit: internal PHP function `file_get_contents()` appears to be on lockdown
if ( ! function_exists( 'file_get_contents' ) ) {
$log['error'] = esc_attr__( 'Divi Support Center :: WordPress debug log cannot be read.', 'et-core' );
if ( defined( 'ET_DEBUG' ) ) {
et_error( $log['error'] );
}
return $log;
}
// Early exit: WP_DEBUG_LOG isn't defined in wp-config.php (or it's defined, but it's empty)
if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) {
$log['error'] = esc_attr__( 'Divi Support Center :: WordPress debug.log is not configured.', 'et-core' );
if ( defined( 'ET_DEBUG' ) ) {
et_error( $log['error'] );
}
return $log;
}
/**
* WordPress 5.1 introduces the option to define a custom path for the WP_DEBUG_LOG file.
*
* @see wp_debug_mode()
*
* @since 3.20
*/
if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
$wp_debug_log_path = realpath( WP_CONTENT_DIR . '/debug.log' );
} else if ( is_string( WP_DEBUG_LOG ) ) {
$wp_debug_log_path = realpath( WP_DEBUG_LOG );
}
// Early exit: `debug.log` doesn't exist or otherwise can't be read
if ( ! isset( $wp_debug_log_path ) || ! file_exists( $wp_debug_log_path ) || ! is_readable( $wp_debug_log_path ) ) {
$log['error'] = esc_attr__( 'Divi Support Center :: WordPress debug log cannot be found.', 'et-core' );
if ( defined( 'ET_DEBUG' ) ) {
et_error( $log['error'] );
}
return $log;
}
/**
* At this point, we know:
* (1) `$wp_debug_log_path` is set,
* (2) it points to a valid location, and
* (3) what it points to is readable.
*
* Before we continue, we'll ensure `$wp_debug_log_path` does not point to a directory.
*/
// Early exit: debug log definition points to a directory, not a file.
if ( is_dir( $wp_debug_log_path ) ) {
$log['error'] = esc_attr__(
'Divi Support Center :: WordPress debug log setting points to a directory, but should point to a file.',
'et-core'
);
if ( defined( 'ET_DEBUG' ) ) {
et_error( $log['error'] );
}
return $log;
}
// Load the debug.log file
$file = new SplFileObject( $wp_debug_log_path );
// Get the filesize of debug.log
$log['size'] = $this->get_size_in_shorthand( 0 + $file->getSize() );
// If $lines_to_return is a positive integer, fetch the last [$lines_to_return] lines of the log file
$lines_to_return = (int) $lines_to_return;
if ( $lines_to_return > 0 ) {
$file->seek( PHP_INT_MAX );
$total_lines = $file->key();
// If the file is smaller than the number of lines requested, return the entire file.
$reader = new LimitIterator( $file, max( 0, $total_lines - $lines_to_return ) );
$log['entries'] = '';
foreach ( $reader as $line ) {
$log['entries'] .= $line;
}
}
// Unload the SplFileObject
$file = null;
return $log;
}
/**
* When a predefined system setting is passed to this function, it will return the observed value.
*
* @since 3.20
*
* @param bool $formatted Whether to return a formatted report or just the data array
* @param string $format Return the report as either a `div` or `plain` text (if $formatted = true)
*
* @return array|string
*/
protected function system_diagnostics_generate_report( $formatted = true, $format = 'plain' ) {
/** @var array Collection of system settings to run diagnostic checks on. */
global $wp_version;
global $shortname;
$divi_builder_plugin_active = et_is_builder_plugin_active();
if ( $divi_builder_plugin_active ) {
$options = get_option( 'et_pb_builder_options', array() );
}
if ( 'divi' === $shortname ) {
$performance_options_url = get_admin_url() . 'admin.php?page=et_divi_options#general-2';
$builder_options_url = get_admin_url() . 'admin.php?page=et_divi_options#builder-2';
} elseif ( 'extra' === $shortname ) {
$performance_options_url = get_admin_url() . 'admin.php?page=et_extra_options#general-2';
$builder_options_url = get_admin_url() . 'admin.php?page=et_extra_options#builder-2';
} else {
$performance_options_url = get_admin_url() . 'admin.php?page=et_divi_options#tab_et_dashboard_tab_content_performance_main';
$builder_options_url = get_admin_url() . 'admin.php?page=et_divi_options#tab_et_dashboard_tab_content_advanced_main';
}
$system_diagnostics_settings = array(
array(
'name' => esc_attr__( 'Writable wp-content Directory', 'et-core' ),
'environment' => 'server',
'type' => 'truthy_falsy',
'pass_minus_one' => null,
'pass_zero' => null,
'minimum' => null,
'recommended' => true,
'actual' => wp_is_writable( WP_CONTENT_DIR ),
'help_text' => et_core_intentionally_unescaped( __( 'We recommend that the wp-content directory on your server be writable by WordPress in order to ensure the full functionality of Divi Builder themes and plugins.', 'et-core' ), 'html' ),
'learn_more' => 'https://wordpress.org/support/article/changing-file-permissions/',
),
array(
'name' => esc_attr__( 'Writable et-cache Directory', 'et-core' ),
'environment' => 'server',
'type' => 'truthy_falsy',
'pass_minus_one' => null,
'pass_zero' => null,
'minimum' => null,
'recommended' => true,
'actual' => wp_is_writable( WP_CONTENT_DIR . '/et-cache' ),
'help_text' => et_core_intentionally_unescaped( __( 'We recommend that the et-cache directory on your server be writable by WordPress in order to ensure the full functionality of Divi Builder themes and plugins.', 'et-core' ), 'html' ),
'learn_more' => 'https://wordpress.org/support/article/changing-file-permissions/',
),
array(
'name' => esc_attr__( 'PHP: Version', 'et-core' ),
'environment' => 'server',
'type' => 'version',
'pass_minus_one' => false,
'pass_zero' => false,
'minimum' => null,
'recommended' => '7.4 or higher',
'actual' => (float) phpversion(),
'help_text' => et_core_intentionally_unescaped( __( 'We recommend using the latest stable version of PHP. This will not only ensure compatibility with Divi, but it will also greatly speed up your website leading to less memory and CPU related issues.', 'et-core' ), 'html' ),
'learn_more' => 'http://php.net/releases/',
),
array(
'name' => esc_attr__( 'WordPress Version', 'et-core' ),
'environment' => 'server',
'type' => 'version',
'pass_minus_one' => false,
'pass_zero' => false,
'minimum' => null,
'recommended' => '5.3 or higher',
'actual' => $wp_version,
'help_text' => et_core_intentionally_unescaped( __( 'We recommend using the latest stable version of WordPress. This will not only ensure compatibility with Divi, but it will also greatly speed up your website leading to less memory and CPU related issues.', 'et-core' ), 'html' ),
'learn_more' => 'https://wordpress.org/download/releases/',
),
array(
'name' => esc_attr__( 'PHP: memory_limit', 'et-core' ),
'environment' => 'server',
'type' => 'size',
'pass_minus_one' => true,
'pass_zero' => false,
'minimum' => null,
'recommended' => '128M',
'actual' => ini_get( 'memory_limit' ),
'help_text' => et_get_safe_localization( sprintf( __( 'By default, memory limits set by your host or by WordPress may be too low. This will lead to applications crashing as PHP reaches the artificial limit. You can adjust your memory limit within your php.ini file, or by contacting your host for assistance. You may also need to define a memory limited in wp-config.php.', 'et-core' ), 'http://php.net/manual/en/ini.core.php#ini.memory-limit', 'https://codex.wordpress.org/Editing_wp-config.php' ) ),
'learn_more' => 'http://php.net/manual/en/ini.core.php#ini.memory-limit',
),
array(
'name' => esc_attr__( 'PHP: post_max_size', 'et-core' ),
'environment' => 'server',
'type' => 'size',
'pass_minus_one' => false,
'pass_zero' => true,
'minimum' => null,
'recommended' => '64M',
'actual' => ini_get( 'post_max_size' ),
'help_text' => et_get_safe_localization( sprintf( __( 'Post Max Size limits how large a page or file can be on your website. If your page is larger than the limit set in PHP, it will fail to load. Post sizes can become quite large when using the Divi Builder, so it is important to increase this limit. It also affects file size upload/download, which can prevent large layouts from being imported into the builder. You can adjust your max post size within your php.ini file, or by contacting your host for assistance.', 'et_core' ), 'http://php.net/manual/en/ini.core.php#ini.post-max-size' ) ),
'learn_more' => 'http://php.net/manual/en/ini.core.php#ini.post-max-size',
),
array(
'name' => esc_attr__( 'PHP: max_execution_time', 'et-core' ),
'environment' => 'server',
'type' => 'seconds',
'pass_minus_one' => false,
'pass_zero' => true,
'minimum' => null,
'recommended' => '120',
'actual' => ini_get( 'max_execution_time' ),
'help_text' => et_get_safe_localization( sprintf( __( 'Max Execution Time affects how long a page is allowed to load before it times out. If the limit is too low, you may not be able to import large layouts and files into the builder. You can adjust your max execution time within your php.ini file, or by contacting your host for assistance.', 'et-core' ), 'http://php.net/manual/en/info.configuration.php#ini.max-execution-time' ) ),
'learn_more' => 'http://php.net/manual/en/info.configuration.php#ini.max-execution-time',
),
array(
'name' => esc_attr__( 'PHP: upload_max_filesize', 'et-core' ),
'environment' => 'server',
'type' => 'size',
'pass_minus_one' => false,
'pass_zero' => true,
'minimum' => null,
'recommended' => '64M',
'actual' => ini_get( 'upload_max_filesize' ),
'help_text' => et_get_safe_localization( sprintf( __( 'Upload Max File Size determines that maximum file size that you are allowed to upload to your server. If the limit is too low, you may not be able to import large collections of layouts into the Divi Library. You can adjust your max file size within your php.ini file, or by contacting your host for assistance.', 'et-core' ), 'http://php.net/manual/en/ini.core.php#ini.upload-max-filesize' ) ),
'learn_more' => 'http://php.net/manual/en/ini.core.php#ini.upload-max-filesize',
),
array(
'name' => esc_attr__( 'PHP: max_input_time', 'et-core' ),
'environment' => 'server',
'type' => 'seconds',
'pass_minus_one' => true,
'pass_zero' => true,
'minimum' => null,
'recommended' => '60',
'actual' => ini_get( 'max_input_time' ),
'help_text' => et_get_safe_localization( sprintf( __( 'This sets the maximum time in seconds a script is allowed to parse input data. If the limit is too low, the Divi Builder may time out before it is allowed to load. You can adjust your max input time within your php.ini file, or by contacting your host for assistance.', 'et-core' ), 'http://php.net/manual/en/info.configuration.php#ini.max-input-time' ) ),
'learn_more' => 'http://php.net/manual/en/info.configuration.php#ini.max-input-time',
),
array(
'name' => esc_attr__( 'PHP: max_input_vars', 'et-core' ),
'environment' => 'server',
'type' => 'size',
'pass_minus_one' => false,
'pass_zero' => false,
'minimum' => null,
'recommended' => '1000',
'actual' => ini_get( 'max_input_vars' ),
'help_text' => et_get_safe_localization( sprintf( __( 'This setting affects how many input variables may be accepted. If the limit is too low, it may prevent the Divi Builder from loading. You can adjust your max input variables within your php.ini file, or by contacting your host for assistance.', 'et-core' ), 'http://php.net/manual/en/info.configuration.php#ini.max-input-vars' ) ),
'learn_more' => 'http://php.net/manual/en/info.configuration.php#ini.max-input-vars',
),
array(
'name' => esc_attr__( 'PHP: display_errors', 'et-core' ),
'environment' => 'server',
'type' => 'truthy_falsy',
'pass_minus_one' => null,
'pass_zero' => null,
'pass_exact' => null,
'minimum' => null,
'recommended' => '0',
'actual' => ! ini_get( 'display_errors' ) ? '0' : ini_get( 'display_errors' ),
'help_text' => et_get_safe_localization( sprintf( __( 'This setting determines whether or not errors should be printed as part of the page output. This is a feature to support your site\'s development and should never be used on production sites. You can edit this setting within your php.ini file, or by contacting your host for assistance.', 'et-core' ), 'http://php.net/manual/en/errorfunc.configuration.php#ini.display-errors' ) ),
'learn_more' => 'http://php.net/manual/en/errorfunc.configuration.php#ini.display-errors',
),
// TODO feat(D5, Optimization) Remove this check if we remove this setting for Divi 5.
// This is forced on for the beta because we don't want people to hurt their own performance.
// We'll remove the option entirely if are confident that there are no bugs.
//
//array(
// 'name' => esc_attr__( 'Dynamic CSS', 'et-core' ),
// 'environment' => 'performance',
// 'type' => 'truthy_falsy',
// 'pass_minus_one' => null,
// 'pass_zero' => null,
// 'pass_exact' => null,
// 'minimum' => null,
// 'recommended' => 'on',
// 'actual' => $divi_builder_plugin_active ? ( isset( $options['performance_main_dynamic_css'] ) ? $options['performance_main_dynamic_css'] : 'on' ) : et_get_option( $shortname . '_dynamic_css', 'on' ),
// 'help_text' => et_get_safe_localization( sprintf( __( 'This is a very important performance setting that should be turned on. Dynamic CSS greatly reduces your website\'s CSS size, speeds up page load times and improves Google PageSpeed scores. You can turn this setting on in the Theme Options.', 'et-core' ), $performance_options_url ) ),
// 'learn_more' => $performance_options_url,
//),
array(
'name' => esc_attr__( 'Dynamic Framework', 'et-core' ),
'environment' => 'performance',
'type' => 'truthy_falsy',
'pass_minus_one' => null,
'pass_zero' => null,
'pass_exact' => null,
'minimum' => null,
'recommended' => 'on',
'actual' => $divi_builder_plugin_active ? ( isset( $options['performance_main_dynamic_module_framework'] ) ? $options['performance_main_dynamic_module_framework'] : 'on' ) : et_get_option( $shortname . '_dynamic_module_framework', 'on' ),
'help_text' => et_get_safe_localization( sprintf( __( 'This is a very important performance setting that should be turned on. The Dynamic Framework removes bloat from the back-end. This greatly reduces CPU and Memory usage and improves website speed. You can turn this setting on in the Theme Options.', 'et-core' ), $performance_options_url ) ),
'learn_more' => $performance_options_url,
),
// TODO feat(D5, Optimization) Remove this check if we remove this setting for Divi 5.
// This is forced on for the beta because we don't want people to hurt their own performance.
// We'll remove the option entirely if are confident that there are no bugs.
//
//array(
// 'name' => esc_attr__( 'Dynamic JavaScript', 'et-core' ),
// 'environment' => 'performance',
// 'type' => 'truthy_falsy',
// 'pass_minus_one' => null,
// 'pass_zero' => null,
// 'pass_exact' => null,
// 'minimum' => null,
// 'recommended' => 'on',
// 'actual' => $divi_builder_plugin_active ? ( isset( $options['performance_main_dynamic_css'] ) ? $options['performance_main_dynamic_css'] : 'on' ) : et_get_option( $shortname . '_dynamic_js_libraries', 'on' ),
// 'help_text' => et_get_safe_localization( sprintf( __( 'This is a very important performance setting that should be turned on. Dynamic JavaScript removes unused scripts and improves website speed by loading JavaScript files only when they are needed. You can turn this setting on in the Theme Options.', 'et-core' ), $performance_options_url ) ),
// 'learn_more' => $performance_options_url,
//),
array(
'name' => esc_attr__( 'Critical CSS', 'et-core' ),
'environment' => 'performance',
'type' => 'truthy_falsy',
'pass_minus_one' => null,
'pass_zero' => null,
'pass_exact' => null,
'minimum' => null,
'recommended' => 'on',
'actual' => $divi_builder_plugin_active ? ( isset( $options['performance_main_critical_css'] ) ? $options['performance_main_dynamic_css'] : 'on' ) : et_get_option( $shortname . '_critical_css', 'on' ),
'help_text' => et_get_safe_localization( sprintf( __( 'This is a very important performance setting that should be turned on. Critical CSS greatly improves website loading speeds by deferring "below the fold" styles and removing render blocking requests for critical styles. You can turn this setting on in the Theme Options.', 'et-core' ), $performance_options_url ) ),
'learn_more' => $performance_options_url,
),
// TODO feat(D5, Optimization) Remove this check if we remove this setting for Divi 5.
// This is forced on for the beta because we don't want people to hurt their own performance.
// We'll remove the option entirely if are confident that there are no bugs.
//
//array(
// 'name' => esc_attr__( 'Static CSS', 'et-core' ),
// 'environment' => 'performance',
// 'type' => 'truthy_falsy',
// 'pass_minus_one' => null,
// 'pass_zero' => null,
// 'pass_exact' => null,
// 'minimum' => null,
// 'recommended' => 'on',
// 'actual' => et_core_is_static_css_enabled(),
// 'help_text' => et_get_safe_localization( sprintf( __( 'This is a very important performance setting that should be turned on, even if you are using a caching plugin. Static CSS caches the builder CSS for each page so that it doesn\'t need to be processed on every page load. Even if you are using a caching plugin, this setting should still be turned on so that dynamic pages benefit. You can turn this setting on in the Theme Options.', 'et-core' ), $builder_options_url ) ),
// 'learn_more' => $builder_options_url,
//),
);
/** @var string Formatted report. */
$report = '';
// pass/fail Should be one of pass|minimal|fail|unknown. Defaults to 'unknown'.
foreach ( $system_diagnostics_settings as $i => $scan ) {
/**
* 'pass_fail': four-step process to set its value:
* - begin with `unknown` state;
* - if recommended value exists, change to `fail`;
* - if minimum value exists, compare against it & change to `minimal` if it passes;
* - compare against recommended value & change to `pass` if it passes.
*/
$system_diagnostics_settings[ $i ]['pass_fail'] = 'unknown';
if ( ! is_null( $scan['recommended'] ) ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'fail';
}
if ( ! is_null( $scan['minimum'] ) && $this->value_is_at_least( $scan['minimum'], $scan['actual'], $scan['type'] ) ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'minimal';
}
if ( empty( $scan['pass_exact'] ) && ! is_null( $scan['recommended'] ) && $this->value_is_at_least( $scan['recommended'], $scan['actual'], $scan['type'] ) ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'pass';
}
if ( $scan['pass_minus_one'] && -1 === (int) $scan['actual'] ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'pass';
}
if ( $scan['pass_zero'] && 0 === (int) $scan['actual'] ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'pass';
}
if ( ! empty( $scan['pass_exact'] ) && $scan['recommended'] === $scan['actual'] ) {
$system_diagnostics_settings[ $i ]['pass_fail'] = 'pass';
}
/**
* Build messaging for minimum required values
*/
$message_minimum = '';
if ( ! is_null( $scan['minimum'] ) && 'fail' === $system_diagnostics_settings[ $i ]['pass_fail'] ) {
$message_minimum = sprintf(
esc_html__( 'This fails to meet our minimum required value of %1$s. ', 'et-core' ),
esc_html( is_bool( $scan['minimum'] ) ? $this->boolean_label[ $scan['minimum'] ] : $scan['minimum'] )
);
}
if ( ! is_null( $scan['minimum'] ) && 'minimal' === $system_diagnostics_settings[ $i ]['pass_fail'] ) {
$message_minimum = sprintf(
esc_html__( 'This meets our minimum required value of %1$s. ', 'et-core' ),
esc_html( is_bool( $scan['minimum'] ) ? $this->boolean_label[ $scan['minimum'] ] : $scan['minimum'] )
);
}
/**
* Build description messaging for results & recommendation
*/
$learn_more_link = '';
if ( ! is_null( $scan['learn_more'] ) ) {
$learn_more_link = sprintf( ' %2$s',
esc_url( $scan['learn_more'] ),
esc_html__( 'server' === $scan['environment'] ? 'Learn More.' : 'Enable Option.', 'et-core' )
);
}
switch ( $system_diagnostics_settings[ $i ]['pass_fail'] ) {
case 'pass':
$system_diagnostics_settings[ $i ]['description'] = sprintf(
'- %1$s %2$s',
sprintf(
esc_html__( 'performance' === $scan['environment'] ? 'Perfect! We recommend enabling this option.' : 'Congratulations! This meets or exceeds our recommendation of %1$s.', 'et-core' ),
esc_html( is_bool( $scan['recommended'] ) ? $this->boolean_label[ $scan['recommended'] ] : $scan['recommended'] )
),
et_core_intentionally_unescaped( $learn_more_link, 'html' )
);
break;
case 'minimal':
case 'fail':
$system_diagnostics_settings[ $i ]['description'] = sprintf(
'- %1$s%2$s %3$s',
esc_html( $message_minimum ),
sprintf(
esc_html__( 'performance' === $scan['environment'] ? 'Enable for optimal performance.' : 'We recommend %1$s for the best experience.', 'et-core' ),
esc_html( is_bool( $scan['recommended'] ) ? $this->boolean_label[ $scan['recommended'] ] : $scan['recommended'] )
),
et_core_intentionally_unescaped( $learn_more_link, 'html' )
);
break;
case 'unknown':
default:
$system_diagnostics_settings[ $i ]['description'] = sprintf(
esc_html__( '- We are unable to determine your setting. %1$s', 'et-core' ),
et_core_intentionally_unescaped( $learn_more_link, 'html' )
);
}
}
// If we just want the array (not a formatted HTML block), return that now
if ( false === $formatted ) {
return $system_diagnostics_settings;
}
foreach ( $system_diagnostics_settings as $item ) {
// Add reported setting to plaintext report:
if ( 'plain' === $format ) {
switch ( $item['pass_fail'] ) {
case 'pass':
$status = ' ';
break;
case 'minimal':
$status = '~ ';
break;
case 'fail':
$status = "! ";
break;
case 'unknown':
default:
$status = '? ';
}
$report .= $status . $item['name'] . PHP_EOL
. ' ' . $item['actual'] . PHP_EOL . PHP_EOL;
}
// Add reported setting to table:
if ( 'div' === $format ) {
$help_text = '';
if ( ! is_null( $item['help_text'] ) ) {
$help_text = $item['help_text'];
}
$report .= sprintf( '
Enabling Remote Access will give the Elegant Themes support team limited access to your WordPress Dashboard. If requested, you can also enable full admin privileges. Remote Access should only be turned on if requested by the Elegant Themes support team. Remote Access is automatically disabled after 4 days.
',
esc_html__( 'Remote Access', 'et-core' ),
__( 'Remote Access cannot be enabled because you do not have a valid API Key or your Elegant Themes subscription has expired. You can find your API Key by logging in to your Elegant Themes account. It should then be added to your Options Panel.', 'et-core' )
);
} else {
if ( is_object( $support_account ) && property_exists( $support_account, 'roles' ) ) {
if ( in_array( 'et_support', $support_account->roles, true ) ) {
$is_et_support_user_active = 1;
}
if ( in_array( 'administrator', $support_account->roles, true ) ) {
$is_et_support_user_active = 2;
}
}
$support_user_active_state = ( intval( $is_et_support_user_active ) > 0 ) ? ' et_pb_on_state' : ' et_pb_off_state';
$expiry = '';
if ( ! empty( $this->support_user_options['date_created'] ) ) {
// Calculate the 'Created Date' plus the 'Time To Expire'
$date_created = date( 'Y-m-d H:i:s ', $this->support_user_options['date_created'] );
$expiry = strtotime( $date_created . $this->support_user_expiration_time );
}
// Toggle Support User activation
$card_content .= sprintf( '
%1$s
'
. '
'
. '
'
. '%3$s'
. ''
. '%4$s'
. '
'
. '%6$s'
. ''
. ''
. ''
. '
'
. '
',
esc_html__( 'Remote Access', 'et-core' ),
esc_attr( $support_user_active_state ),
esc_html__( 'Enabled', 'et-core' ),
esc_html__( 'Disabled', 'et-core' ),
esc_attr( $expiry ),
esc_html__( 'Remote Access will be automatically disabled in: ', 'et-core' ),
'et_pb_yes_no_button',
'et_pb_value_text'
);
// Toggle Support User role elevation (only visible if Support User is active)
$extra_css = ( intval( $is_et_support_user_active ) > 0 ) ? 'style="display:block;"' : '';
$support_user_elevated_state = ( intval( $is_et_support_user_active ) > 1 ) ? ' et_pb_on_state' : ' et_pb_off_state';
$card_content .= sprintf( '
' . esc_html__( 'Get More With Divi VIP', 'et-core' ) . '
'
. '
' . esc_html__( 'The Best Support, Even Faster.', 'et-core' ) . '
'
. '
'
. esc_html__( 'We want to provide exactly the level of support any of our customers need to be successful. With Divi VIP, you get faster support (Under 30 minutes response times around the clock). Keep your clients happy by letting us solve their problems faster.', 'et-core' )
. '
';
print $this->add_support_center_card( array(
'title' => $card_title,
'content' => $card_content,
'additional_classes' => array(
'et_documentation_help',
'et-epanel-box',
),
) );
}
/**
* Run code after the 3rd Support Center card has been output
*
* @since 3.20
*/
do_action( 'et_support_center_below_position_3' );
// Build Card :: Safe Mode
if ( $this->current_user_can( 'et_support_center_safe_mode' ) ) {
$card_title = esc_html__( 'Safe Mode', 'et-core' );
$card_content = __( '
Enabling Safe Mode will temporarily disable features and plugins that may be causing problems with your Elegant Themes product. This includes all Plugins, Child Themes, and Custom Code added to your integration areas. These items are only disabled for your current user session so your visitors will not be disrupted. Enabling Safe Mode makes it easy to figure out what is causing problems on your website by identifying or eliminating third party plugins and code as potential causes.
', 'et-core' );
$error_message = '';
$safe_mode_active = ( et_core_is_safe_mode_active() ) ? ' et_pb_on_state' : ' et_pb_off_state';
$plugins_list = array();
$plugins_output = '';
$has_mu_plugins_dir = wp_mkdir_p( WPMU_PLUGIN_DIR ) && wp_is_writable( WPMU_PLUGIN_DIR );
$can_create_mu_plugins_dir = wp_is_writable( WP_CONTENT_DIR ) && ! wp_mkdir_p( WPMU_PLUGIN_DIR );
if ( $has_mu_plugins_dir || $can_create_mu_plugins_dir ) {
// Gather list of plugins that will be temporarily deactivated in Safe Mode
$all_plugins = get_plugins();
$active_plugins = get_option( 'active_plugins' );
foreach ( $active_plugins as $plugin ) {
// Verify this 'active' plugin actually exists in the plugins directory
if ( ! in_array( $plugin, array_keys( $all_plugins ) ) ) {
continue;
}
// If it's not in our allowlist, add it to the list of plugins we'll disable
if ( ! in_array( $plugin, $this->safe_mode_plugins_allowlist ) ) {
$plugins_list[] = '
If you have WP_DEBUG_LOG enabled, WordPress related errors will be archived in a log file. For your convenience, we have aggregated the contents of this log file so that you and the Elegant Themes support team can view it easily. The file cannot be edited here.
';
}
print $this->add_support_center_card( array(
'title' => $card_title,
'content' => $card_content,
'additional_classes' => array(
'et_system_logs',
'et-epanel-box',
),
) );
}
/**
* Run code after all of the Support Center cards have been output
*
* @since 3.20
*/
do_action( 'et_support_center_below_cards' );
?>
current_user_can( 'et_support_center_system' ) ) {
return;
}
// Exit if Admin dismissed the Divi Hosting Card
if ( get_option( 'et_hosting_card_dismissed', false ) ) {
return;
}
// Show the Divi Hosting Card
add_action( 'et_support_center_below_position_1', array( $this, 'print_divi_hosting_card' ) );
}
/**
* Prepare Settings for ET API request
* Returns false when ET username/api_key is not found, and ET subscription is not active
*
* @since 4.4.7
* @param string $action
*
* @return bool|array
*/
protected function get_et_api_request_settings( $action ) {
$et_account = et_core_get_et_account();
$et_username = et_()->array_get( $et_account, 'et_username', '' );
$et_api_key = et_()->array_get( $et_account, 'et_api_key', '' );
// Only when ET Username and ET API Key is found
if ( '' !== $et_username && '' !== $et_api_key ) {
global $wp_version;
// Prepare settings for API request
return array(
'timeout' => 30,
'body' => array(
'action' => $action,
'username' => $et_username,
'api_key' => $et_api_key,
),
'user-agent' => 'WordPress/' . $wp_version . '; Support Center/' . ET_CORE_VERSION . '; ' . home_url( '/' ),
);
}
return false;
}
/**
* Check ET API whether ET User has disabled Divi Hosting Card
*
* @since 4.4.7
*
* @return bool
*/
protected function maybe_api_has_hosting_card_disabled() {
// Get API settings
$api_settings = $this->get_et_api_request_settings( 'check_hosting_card_status' );
// Check API only when ET Username, ET API Key is found and Account is active
if ( is_array( $api_settings ) ) {
$request = wp_remote_post( 'https://www.elegantthemes.com/api/api.php', $api_settings );
$request_response_code = wp_remote_retrieve_response_code( $request );
// Do not show the Hosting Card when API Request, or, API Response has any error
if ( is_wp_error( $request ) || 200 !== $request_response_code ) {
return true;
}
$response_body = wp_remote_retrieve_body( $request );
$response = (array) json_decode( $response_body );
// Check whether the User has disabled the card
if ( et_()->array_get( $response, 'success' ) && et_()->array_get( $response, 'status' ) === 'disabled' ) {
// Mark it dismissed, so it won't be displayed anymore on this website
update_option( 'et_hosting_card_dismissed', true );
// Do not show the Hosting Card
return true;
}
}
// Show the Hosting Card
return false;
}
/**
* Return Data for Divi Hosting Card
*
* @since 4.4.7
*
* @return array
*/
protected function get_divi_hosting_features() {
return array(
'title' => esc_html__( 'Get Recommended Divi Hosting', 'et-core' ),
'summary' => esc_html__( 'Upgrade your hosting to the most reliable, Divi-compatible hosting. Enjoy perfectly configured hosting environments pre-installed with the tools you need to be successful with Divi.', 'et-core' ),
'url' => 'https://www.elegantthemes.com/hosting/',
'learn_more' => esc_html__( 'Learn About Divi Hosting', 'et-core' ),
'dismiss_tooltip' => esc_html__( 'Remove This Recommendation On All Of Your Websites And Your Client\'s Websites Forever', 'et-core' ),
'features' => array(
'server' => array(
'title' => esc_html__( 'Divi-Optimized Servers', 'et-core' ),
'tooltip' => esc_html__( "We worked with our parters to make sure that their hosting solutions meet all of Divi's requirements out of the box. No hosting headaches on Divi Hosting.", 'et-core' ),
),
'speed' => array(
'title' => esc_html__( 'Blazing Fast Speed', 'et-core' ),
'tooltip' => esc_html__( 'Divi Hosting is powered by fast networks, modern hosting infrastructures and the latest server software. Plus you will enjoy automatic caching and a free CDN.', 'et-core' ),
),
'security' => array(
'title' => esc_html__( 'A Focus On Security', 'et-core' ),
'tooltip' => esc_html__( 'All of our hosting partners are dedicated to security. That means up-to-date server software and secure hosting practices.', 'et-core' ),
),
'backups' => array(
'title' => esc_html__( 'Automatic Backups', 'et-core' ),
'tooltip' => esc_html__( 'Every website needs backups! Each of our hosting partners provide automatic daily backups. If disaster strikes, these hosting companies have your back.', 'et-core' ),
),
'migrate' => array(
'title' => esc_html__( 'Easy Site Migration', 'et-core' ),
'tooltip' => esc_html__( "Already have a Divi website hosted somewhere else? All of our hosting partners provide migration tools or professional assisted migration. It's easy to switch to Divi Hosting!", 'et-core' ),
),
'staging' => array(
'title' => esc_html__( 'Easy Staging Sites', 'et-core' ),
'tooltip' => esc_html__( 'Automatic staging sites make it easy to develop new designs for your clients without disrupting visitors. Finish your work and push it live all at once.', 'et-core' ),
),
),
);
}
/**
* Build and display Divi Hosting Card
*
* @since 4.4.7
*/
public function print_divi_hosting_card() {
// Gather System status data
$report = $this->system_diagnostics_generate_report( false );
$result = array();
// Prepare the report data to check against when to show the Divi Hosting Card
foreach ( $report as $status ) {
$result[] = et_()->array_get( $status, 'pass_fail' );
}
// Exit if any system status item is not in a warning state (red dot indicator)
if ( ! in_array( 'fail', array_values( $result ), true ) ) {
return;
}
// Exit if ET User has disabled the Divi Hosting card
if ( $this->maybe_api_has_hosting_card_disabled() ) {
return;
}
// JS dependency for Tooltips
wp_enqueue_script( 'popper', $this->local_path . 'admin/js/popper.min.js', array( 'jquery' ), ET_CORE_VERSION );
wp_enqueue_script( 'tippy', $this->local_path . 'admin/js/tippy.min.js', array( 'jquery', 'popper' ), ET_CORE_VERSION );
$card = $this->get_divi_hosting_features();
$features = '';
// HTML Template for Features of the Divi Hosting Card
foreach ( $card['features'] as $name => $feature ) {
$features .= sprintf(
'
%2$s
%3$s
',
esc_html( $feature['tooltip'] ),
sprintf(
'',
esc_url( "{$this->local_path}admin/images/svg/{$name}.svg" )
),
esc_html( $feature['title'] )
);
}
// HTML Template for the Divi Hosting Card
$card_content = sprintf(
'