: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( $this->DEBUG_ET_SUPPORT_CENTER ) {
et_error( 'Support Center Safe Mode: mu-plugin installed.' );
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
public function maybe_set_site_id() {
$site_id = get_option( 'et_support_site_id' );
if ( ! empty( $site_id ) ) {
'action' => 'get_site_id',
$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
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.
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' ) ) {
$menu_title = esc_html__( 'Support Center', 'et-core' );
$parent_menu_slug = null;
$capability = 'manage_options';
// Define parent and child menu slugs
switch ( $this->parent ) {
$menu_slug = 'et_support_center_bloom';
$parent_menu_slug = 'et_bloom_options';
$menu_title = esc_html__( 'Monarch Support Center', 'et-core' );
$menu_slug = 'et_support_center_monarch';
$parent_menu_slug = 'tools.php';
$menu_slug = 'et_support_center_extra';
$parent_menu_slug = 'et_extra_options';
case 'divi_builder_plugin':
$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
array( $this, 'add_support_center' )
* Add class name to Support Center page
* @param string $admin_classes Current class names for the body tag.
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
* @param $hook string Unique identifier for WP admin page.
public function admin_enqueue_scripts_styles( $hook ) {
et_core_register_admin_assets();
wp_enqueue_style( 'et-core-admin' );
wp_enqueue_script( 'et-core-admin' );
// Load only on `_et_support_center` pages
if ( strpos( $hook, '_et_support_center' ) ) {
wp_enqueue_style( 'et-core',
$this->local_path . 'admin/css/core.css',
wp_enqueue_style( 'et-wp-admin',
$this->local_path . 'admin/css/wp-admin.css',
wp_enqueue_style( 'et-support-center',
$this->local_path . 'admin/css/support-center.css',
// 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
* @param $hook string Unique identifier for WP admin page.
public function enqueue_scripts_styles( $hook ) {
// We only need to add this for authenticated users on the frontend
if ( ! is_user_logged_in() ) {
wp_enqueue_script( 'et-support-center',
$this->local_path . 'admin/js/support-center.js',
array( 'jquery', 'underscore' ),
$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
protected function add_support_center_card( $attrs = array( 'title' => '', 'content' => '' ) ) {
if ( array_key_exists( 'additional_classes', $attrs ) ) {
$card_classes = array_merge( $card_classes, $attrs['additional_classes'] );
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(
'<button class="%2$s" data-key="%3$s" data-product="%4$s" %5$s type="button" ><span class="et-dismiss-button-label">%1$s</span></button>',
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 . '<div class="' . esc_attr( implode( ' ', $card_classes ) ) . '">' .
PHP_EOL . "\t" . '<h2>' . esc_html( $attrs['title'] ) . '</h2>' .
PHP_EOL . "\t" . '<div class="main">' . et_core_intentionally_unescaped( $attrs['content'], 'html' ) . '</div>' .
et_core_esc_previously( $dismiss_button ) .
* Divi Support Center :: Dismiss a Card via Ajax
public function dismiss_support_center_card_via_ajax() {
et_core_security_check( 'manage_options', 'support_center', 'nonce' );
// Check the ET product that dismissing the card
$et_product = sanitize_key( $_POST['product'] );
// Confirm that this is a allowlisted product
$allowlisted_product = $this->is_allowlisted_product( $et_product );
if ( ! $allowlisted_product ) {
// Send a failure code and exit the function
header( "HTTP/1.0 403 Forbidden" );
print 'Bad or malformed ET product name.';
// Check the Card key against Cards that has a dismiss button
$card_key = sanitize_key( $_POST['card_key'] );
if ( ! in_array( $card_key, $this->card_with_dismiss_button, true ) ) {
// Send a failure code and exit the function
header( "HTTP/1.0 403 Forbidden" );
print 'Card does not exists.';
update_option( "{$card_key}_dismissed", true );
// For Divi Hosting Card, update the status via ET API
if ( $card_key === 'et_hosting_card' ) {
$settings = $this->get_et_api_request_settings( 'disable_hosting_card' );
$et_username = et_()->array_get( $settings, 'body.username', '' );
$et_api_key = et_()->array_get( $settings, 'body.api_key', '' );
// Exit if ET Username and/or ET API Key is not found
if ( $et_username === '' || $et_api_key === '' ) {
et_maybe_update_hosting_card_status();
$response['message'] = sprintf(
esc_html__( 'Card (%1$s) has been dismissed successfully.', 'et-core' ),
if ( isset( $response ) ) {
wp_send_json_success( $response );
* Prepare the "Divi Documentation & Help" video player block
* @since 3.28 Added support for Bloom, Monarch, and Divi Builer plugins.
* @param bool $formatted Return either a formatted HTML block (true) or an array (false)
protected function get_documentation_video_player( $formatted = true ) {
switch ( $this->parent ) {
$documentation_videos = array(
'name' => esc_attr__( 'A Basic Overview Of Extra', 'et-core' ),
'youtube_id' => 'JDSg9eq4LIc',
'name' => esc_attr__( 'Using Premade Layout Packs', 'et-core' ),
'youtube_id' => '9eqXcrLcnoc',
'name' => esc_attr__( 'Creating Category Layouts', 'et-core' ),
'youtube_id' => '30SVxnjdnxcE',
case 'divi_builder_plugin':
$documentation_videos = array(
'name' => esc_attr__( 'Getting Started With The Divi Builder', 'et-core' ),
'youtube_id' => 'T-Oe01_J62c',
'name' => esc_attr__( 'Using Premade Layout Packs', 'et-core' ),
'youtube_id' => '9eqXcrLcnoc',
'name' => esc_attr__( 'The Divi Library', 'et-core' ),
'youtube_id' => 'boNZZ0MYU0E',
$documentation_videos = array(
'name' => esc_attr__( 'A Basic Overview Of The Bloom Plugin', 'et-core' ),
'youtube_id' => 'E4nfXFjuRRI',
'name' => esc_attr__( 'How To Update The Bloom Plugin', 'et-core' ),
'youtube_id' => '-IIdkRLskuA',
'name' => esc_attr__( 'How To Add Mailing List Accounts', 'et-core' ),
'youtube_id' => 'nEdWkHIgQwY',
$documentation_videos = array(
'name' => esc_attr__( 'A Complete Overviw Of Monarch', 'et-core' ),
'youtube_id' => 'RlMUEVkbMrs',
'name' => esc_attr__( 'Adding Social Networks', 'et-core' ),
'youtube_id' => 'ZabKCiKQJLM',
'name' => esc_attr__( 'Configuring Social Follower APIs', 'et-core' ),
'youtube_id' => 'vmE8uFhbzos',
$documentation_videos = array();
// If we just want the array (not a formatted HTML block), return that now
if ( false === $formatted ) {
return $documentation_videos;
foreach ( $documentation_videos as $key => $video ) {
$extra = ' class="active"';
$videos_list_html .= sprintf( '<li %1$s data-ytid="%2$s">%3$s%4$s</li>',
esc_attr( $video['youtube_id'] ),
'<span class="dashicons dashicons-arrow-right"></span>',
et_core_intentionally_unescaped( $video['name'], 'fixed_string' )
$playlist[] = et_core_intentionally_unescaped( $video['youtube_id'], 'fixed_string' );
$html = sprintf( '<div class="et_docs_videos">'
. '<div class="wrapper"><div id="et_documentation_player" data-playlist="%1$s"></div></div>'
. '<ul class="et_documentation_videos_list">%2$s</ul>'
esc_attr( implode( ',', $playlist ) ),
* Prepare the "Divi Documentation & Help" articles list
* @since 3.28 Added support for Bloom, Monarch, and Divi Builer plugins.
* @param bool $formatted Return either a formatted HTML block (true) or an array (false)
protected function get_documentation_articles_list( $formatted = true ) {
$articles_list_html = '';
switch ( $this->parent ) {
'title' => esc_attr__( 'Getting Started With Extra', 'et-core' ),
'url' => 'https://www.elegantthemes.com/documentation/extra/overview-extra/',
'title' => esc_attr__( 'Setting Up The Extra Theme Options', 'et-core' ),
'url' => 'https://www.elegantthemes.com/documentation/extra/theme-options-extra/',
'title' => esc_attr__( 'The Extra Category Builder', 'et-core' ),
'url' => 'https://www.elegantthemes.com/documentation/extra/category-builder/',
'title' => esc_attr__( 'Getting Started With The Divi Builder', 'et-core' ),
'url' => 'https://www.elegantthemes.com/documentation/divi/visual-builder/',
'title' => esc_attr__( 'How To Update The Extra Theme', 'et-core' ),
'url' => 'https://www.elegantthemes.com/documentation/divi/update-divi/',