: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// Quick exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
* Elegant Themes Support Center adds a new page to the WP Admin menu.
* Here we note system settings that could potentially cause problems. An extended view (displaying all settings we
* check, not just those with problematic results) can be toggled, with an option to copy this report to the
* clipboard so it can be pasted in a support ticket.
* If Remote Access is enabled in this section, Elegant Themes Support will be granted limited access to the user's site
* (@see ET_Core_SupportCenter::support_user_maybe_create_user()). When this is activated, a second toggle appears
* for the user that will allow them to enable "Full Admin Privileges" which has no restrictions (only certain ET
* Support staff will be able to request that the user enables this). Full Admin Privileges can be disabled at any
* time, but are automatically disabled whenever the Remote Access is disabled (manually or by timeout). Time
* remaining until Remote Access is automatically deactivated is indicated alongside the toggle. A link for
* initiating a chat https://www.elegantthemes.com/members-area/help/ is also available in this section.
* Divi Documentation & Help
* This section contains common help videos, articles, and a link to full documentation. This is not meant to be a
* full service documentation center; it's mainly a launch off point.
* A quick and easy way for users and support to quickly disable plugins and scripts to see if Divi is the cause of
* an issue. This call to action disables active plugins, custom css, child themes, scripts in the Integrations tab,
* static css, and combination/minification of CSS and JS. When enabling this, the user will be presented with a
* list of plugins that will be affected (disabled). Sitewide (not including the Visual Builder), there will be a
* floating indicator in the upper right or left corner of the website that will indicate that Safe Mode is enabled
* and will contain a link that takes you to the Support Page to disabled it.
* If WP_DEBUG_LOG is enabled, WordPress related errors will be archived in a log file. We load the most recent entries
* of this log file for convienient viewing here, with a link to download the full log, as well as an option to copy
* the log to the clipboard so it can be pasted in a support ticket.
* @package ET\Core\SupportCenter
* @author Elegant Themes <http://www.elegantthemes.com>
* @license GNU General Public License v2 <http://www.gnu.org/licenses/gpl-2.0.html>
* @since 3.24.1 Renamed from `ET_Support_Center` to `ET_Core_SupportCenter`.
class ET_Core_SupportCenter {
* Catch whether the ET_DEBUG flag is set.
protected $DEBUG_ET_SUPPORT_CENTER = false;
* Identifier for the parent theme or plugin activating the Support Center.
* "Nice name" for the parent theme or plugin activating the Support Center.
protected $parent_nicename = '';
* Whether the Support Center was activated through a `plugin` or a `theme`.
protected $child_of = '';
* Identifier for the parent theme or plugin activating the Support Center.
protected $support_user_options;
* Support User account name
protected $support_user_account_name = 'elegant_themes_support';
* Support options name in the database
protected $support_user_options_name = 'et_support_options';
* Name of the cron job we use to auto-delete the Support User account
protected $support_user_cron_name = 'et_cron_delete_support_account';
* Expiration time to auto-delete the Support User account via cron
protected $support_user_expiration_time = '+4 days';
* Provide nicename equivalents for boolean values
protected $boolean_label = array( 'False', 'True' );
* Collection of plugins that we will NOT disable when Safe Mode is activated.
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
'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.
protected $support_center_administrator_caps = array(
'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.
protected $card_with_dismiss_button = array(
* Core functionality of the class
* @since 4.4.7 Added WP AJAX action for dismissible button for a card
* @param string $parent Identifier for the parent theme or plugin activating the Support Center.
public function __construct( $parent = '' ) {
// 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.
// Get `et_support_options` settings & set $this->support_user_options
$this->support_user_get_options();
// Set the Site ID data via Elegant Themes API & token
$this->maybe_set_site_id();
// Set the plugins allowlist for Safe Mode
$this->set_safe_mode_plugins_allowlist();
* WordPress action & filter setup
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' ) );
// 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 );
add_filter( 'add_et_support_elevated_capabilities', array( $this, 'support_user_extra_caps_elevated' ), 10, 1 );
// Make sure that our Support Account's roles are 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()`.
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()`.
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
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/' );
$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
public function get_parent_nicename( $parent ) {
case 'divi_builder_plugin':
* Prevent any possible conflicts with the Elegant Themes Support plugin
public function deactivate_conflicting_plugins() {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
// Load WP user management functions
require_once( ABSPATH . 'wp-admin/includes/ms.php' );
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' ) ) {
if ( ! is_multisite() && function_exists( 'wp_delete_user' ) ) {
if ( $can_delete_user ) {
deactivate_plugins( '/elegant-themes-support/elegant-themes-support.php' );
et_error( 'Support Center: Unable to deactivate the ET Support Plugin.' );
* @param string $capability
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
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.' );
$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.' );
// 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.' );
// 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 ) ) {
$copy_file = @copy( $plugin, $new_file_path );
if ( ! $this->DEBUG_ET_SUPPORT_CENTER ) {
et_error( 'Support Center Safe Mode: mu-plugin [' . $plugin . '] installed.' );
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 ) ) {
$copy_file = @copy( $pathname_from, $pathname_to );