%3$s
%2$s
', $report, esc_html__( 'Congratulations, all system checks have passed. Your hosting configuration is compatible with Divi.', 'et-core' ), 'et-system-status' ); } return $report; } /** * Convert size string with "shorthand byte" notation to raw byte value for comparisons. * * @since 3.20 * * @param string $size * * @return int size in bytes */ protected function get_size_in_bytes( $size = '' ) { // Capture the denomination and convert to uppercase, then do math to it switch ( strtoupper( substr( $size, -1 ) ) ) { // Terabytes case 'T': return (int) $size * 1099511627776; // Gigabytes case 'G': return (int) $size * 1073741824; // Megabytes case 'M': return (int) $size * 1048576; // Kilobytes case 'K': return (int) $size * 1024; default: return (int) $size; } } /** * Convert size string with "shorthand byte" notation to raw byte value for comparisons. * * @since 3.20 * * @param int $bytes * @param int $precision * * @return string size in "shorthand byte" notation */ protected function get_size_in_shorthand( $bytes = 0, $precision = 2 ) { $units = array( ' bytes', 'KB', 'MB', 'GB', 'TB' ); $i = 0; while ( $bytes > 1024 ) { $bytes /= 1024; $i++; } return round( $bytes, $precision ) . $units[ $i ]; } /** * Size comparisons between two values using a variety of calculation methods. * * @since 3.20.2 * * @param string|int|float $a Our value to compare against * @param string|int|float $b Server value being compared * @param string $type Comparison type * * @return bool Whether the second value is equal to or greater than the first */ protected function value_is_at_least( $a, $b, $type = 'size' ) { switch ( $type ) { case 'truthy_falsy': return $this->value_is_falsy( $a ) === $this->value_is_falsy( $b ); case 'version': return (float) $a <= (float) $b; case 'seconds': return (int) $a <= (int) $b; case 'size': default: return $this->get_size_in_bytes( $a ) <= $this->get_size_in_bytes( $b ); } } /** * Check value against a collection of "falsy" values * * @since 3.23 * * @param string|int|float $a Value to compare against * * @return bool Whether the second value is equal to or greater than the first */ protected function value_is_falsy( $a ) { // Accept falsy strings regardless of case (e.g. 'off', 'Off', 'OFF', 'oFf') if ( is_string( $a ) ) { $a = strtolower( $a ); } return in_array( $a, array( false, 'false', 0, '0', 'off' ), true ); } /** * SUPPORT CENTER :: REMOTE ACCESS */ /** * Add Support Center options to the Role Editor screen * * @see ET_Core_SupportCenter::current_user_can() * * @since 3.20 * * @param $all_role_options * * @return array */ public function support_user_add_role_options( $all_role_options ) { // get all the roles that can edit theme options. $applicability_roles = et_core_get_roles_by_capabilities( [ 'edit_theme_options' ] ); $all_role_options['support_center'] = array( 'section_title' => esc_attr__( 'Support Center', 'et-core' ), 'applicability' => $applicability_roles, 'options' => array( 'et_support_center' => array( 'name' => esc_attr__( 'Divi Support Center Page', 'et-core' ), ), 'et_support_center_system' => array( 'name' => esc_attr__( 'System Status', 'et-core' ), ), 'et_support_center_remote_access' => array( 'name' => esc_attr__( 'Remote Access', 'et-core' ), ), 'et_support_center_documentation' => array( 'name' => esc_attr__( 'Divi Documentation & Help', 'et-core' ), ), 'et_support_center_safe_mode' => array( 'name' => esc_attr__( 'Safe Mode', 'et-core' ), ), 'et_support_center_logs' => array( 'name' => esc_attr__( 'Logs', 'et-core' ), ), ), ); return $all_role_options; } /** * Add third party capabilities to Remote Access roles * * @return array Capabilities to add to the Remote Access user roles. */ public function support_user_extra_caps_standard( $extra_capabilities = array() ) { // The Events Calendar (if active on the site) if ( class_exists( 'Tribe__Events__Main' ) ) { $the_events_calendar = array( // Events 'edit_tribe_event' => 1, 'read_tribe_event' => 1, 'delete_tribe_event' => 1, 'delete_tribe_events' => 1, 'edit_tribe_events' => 1, 'edit_others_tribe_events' => 1, 'delete_others_tribe_events' => 1, 'publish_tribe_events' => 1, 'edit_published_tribe_events' => 1, 'delete_published_tribe_events' => 1, 'delete_private_tribe_events' => 1, 'edit_private_tribe_events' => 1, 'read_private_tribe_events' => 1, // Venues 'edit_tribe_venue' => 1, 'read_tribe_venue' => 1, 'delete_tribe_venue' => 1, 'delete_tribe_venues' => 1, 'edit_tribe_venues' => 1, 'edit_others_tribe_venues' => 1, 'delete_others_tribe_venues' => 1, 'publish_tribe_venues' => 1, 'edit_published_tribe_venues' => 1, 'delete_published_tribe_venues' => 1, 'delete_private_tribe_venues' => 1, 'edit_private_tribe_venues' => 1, 'read_private_tribe_venues' => 1, // Organizers 'edit_tribe_organizer' => 1, 'read_tribe_organizer' => 1, 'delete_tribe_organizer' => 1, 'delete_tribe_organizers' => 1, 'edit_tribe_organizers' => 1, 'edit_others_tribe_organizers' => 1, 'delete_others_tribe_organizers' => 1, 'publish_tribe_organizers' => 1, 'edit_published_tribe_organizers' => 1, 'delete_published_tribe_organizers' => 1, 'delete_private_tribe_organizers' => 1, 'edit_private_tribe_organizers' => 1, 'read_private_tribe_organizers' => 1, ); $extra_capabilities = array_merge( $extra_capabilities, $the_events_calendar ); } return $extra_capabilities; } /** * Add third party capabilities to the *Elevated* Remote Access role only * * @return array Capabilities to add to the Elevated Remote Access user role. */ public function support_user_extra_caps_elevated() { $extra_capabilities = array(); return $extra_capabilities; } /** * Create the Divi Support user (if it doesn't already exist) * * @since 3.20 * * @return void|WP_Error */ public function support_user_maybe_create_user() { if ( username_exists( $this->support_user_account_name ) ) { return; } // Define user roles that will be used to control ET Support User permissions $this->support_user_create_roles(); $token = $this->support_user_generate_token(); $password = $this->support_user_generate_password( $token ); if ( is_wp_error( $password ) ) { return $password; } $user_id = wp_insert_user( array( 'user_login' => $this->support_user_account_name, 'user_pass' => $password, 'first_name' => 'Elegant Themes', 'last_name' => 'Support', 'display_name' => 'Elegant Themes Support', 'role' => 'et_support', ) ); if ( is_wp_error( $user_id ) ) { return $user_id; } $account_settings = array( 'date_created' => time(), 'token' => $token, ); update_option( $this->support_user_options_name, $account_settings ); // update options variable $this->support_user_get_options(); $this->support_user_init_cron_delete_account(); } /** * Define both Standard and Elevated roles for the Divi Support user * * @since 3.22 Added filters to extend the list of capabilities for the ET Support User * @since 3.20 */ public function support_user_create_roles() { // Make sure old versions of these roles do not exist $this->support_user_remove_roles(); // Divi Support :: Standard $standard_capabilities = array( 'assign_product_terms' => true, 'delete_pages' => true, 'delete_posts' => true, 'delete_private_pages' => true, 'delete_private_posts' => true, 'delete_private_products' => true, 'delete_product' => true, 'delete_product_terms' => true, 'delete_products' => true, 'delete_published_pages' => true, 'delete_published_posts' => true, 'delete_published_products' => true, 'edit_dashboard' => true, 'edit_files' => true, 'edit_others_pages' => true, 'edit_others_posts' => true, 'edit_others_products' => true, 'edit_pages' => true, 'edit_posts' => true, 'edit_private_pages' => true, 'edit_private_posts' => true, 'edit_private_products' => true, 'edit_product' => true, 'edit_product_terms' => true, 'edit_products' => true, 'edit_published_pages' => true, 'edit_published_posts' => true, 'edit_published_products' => true, 'edit_theme_options' => true, 'list_users' => true, 'manage_categories' => true, 'manage_links' => true, 'manage_options' => true, 'manage_product_terms' => true, 'moderate_comments' => true, 'publish_pages' => true, 'publish_posts' => true, 'publish_products' => true, 'read' => true, 'read_private_pages' => true, 'read_private_posts' => true, 'read_private_products' => true, 'read_product' => true, 'unfiltered_html' => true, 'upload_files' => true, // Divi 'ab_testing' => true, 'add_library' => true, 'disable_module' => true, 'divi_builder_control' => true, 'divi_ai' => true, 'divi_library' => true, 'edit_borders' => true, 'edit_buttons' => true, 'edit_colors' => true, 'edit_configuration' => true, 'edit_content' => true, 'edit_global_library' => true, 'edit_layout' => true, 'export' => true, 'lock_module' => true, 'page_options' => true, 'portability' => true, 'read_dynamic_content_custom_fields' => true, 'save_library' => true, 'use_visual_builder' => true, 'theme_builder' => true, // WooCommerce Capabilities 'manage_woocommerce' => true, ); // Divi Support :: Elevated $elevated_capabilities = array_merge( $standard_capabilities, array( 'activate_plugins' => true, 'delete_plugins' => true, 'delete_themes' => true, 'edit_plugins' => true, 'edit_themes' => true, 'install_plugins' => true, 'install_themes' => true, 'switch_themes' => true, 'update_plugins' => true, 'update_themes' => true, ) ); // Filters to allow other code to extend the list of capabilities $additional_standard = apply_filters( 'add_et_support_standard_capabilities', array() ); $additional_elevated = apply_filters( 'add_et_support_elevated_capabilities', array() ); // Apply filter capabilities to our definitions $standard_capabilities = array_merge( $additional_standard, $standard_capabilities ); // Just like Elevated gets all of Standard's capabilities, it also inherits Standard's filter caps $elevated_capabilities = array_merge( $additional_standard, $additional_elevated, $elevated_capabilities ); // Create the standard ET Support role add_role( 'et_support', 'ET Support', $standard_capabilities ); $et_support_role = get_role( 'et_support' ); foreach ( $standard_capabilities as $cap ) { $et_support_role->add_cap( $cap ); } // Create the elevated ET Support role add_role( 'et_support_elevated', 'ET Support - Elevated', $elevated_capabilities ); $et_support_elevated_role = get_role( 'et_support_elevated' ); foreach ( $elevated_capabilities as $cap ) { $et_support_elevated_role->add_cap( $cap ); } } /** * Remove our Standard and Elevated Support roles * * @since 3.20 */ public function support_user_remove_roles() { // Divi Support :: Standard remove_role( 'et_support' ); // Divi Support :: Elevated remove_role( 'et_support_elevated' ); } /** * Set the ET Support User's role * * @since 3.20 * * @param string $role */ public function support_user_set_role( $role = '' ) { // Get the Divi Support User object $support_user = new WP_User( $this->support_user_account_name ); // Set the new Role switch ( $role ) { case 'et_support': $support_user->set_role( 'et_support' ); break; case 'et_support_elevated': $support_user->set_role( 'et_support_elevated' ); break; case '': default: $support_user->set_role( '' ); } } /** * Ensure the `unfiltered_html` capability is added to the ET Support roles in Multisite * * @since 3.22 * * @param array $caps An array of capabilities. * @param string $cap The capability being requested. * @param int $user_id The current user's ID. * * @return array Modified array of user capabilities. */ function support_user_map_meta_cap( $caps, $cap, $user_id ) { if ( ! $this->is_support_user( $user_id ) ) { return $caps; } // This user is in an ET Support user role, so add the capability if ( 'unfiltered_html' === $cap ) { $caps = array( 'unfiltered_html' ); } return $caps; } /** * Remove KSES filters on ET Support User's content * * @since 3.22 */ function support_user_kses_remove_filters() { if ( $this->is_support_user() ) { kses_remove_filters(); } } /** * Clear "Delete Account" cron hook * * @since 3.20 * * @return void */ public function support_user_clear_delete_cron() { wp_clear_scheduled_hook( $this->support_user_cron_name ); } /** * Delete the support account if it's expired or the expiration date is not set * * @since 3.20 * * @return void */ public function support_user_cron_maybe_delete_account() { if ( ! username_exists( $this->support_user_account_name ) ) { return; } if ( isset( $this->support_user_options['date_created'] ) ) { $this->support_user_maybe_delete_expired_account(); } else { // if the expiration date isn't set, delete the account anyway $this->support_user_delete_account(); } } /** * Schedule account removal check * * @since 3.20 * * @return void */ public function support_user_init_cron_delete_account() { $this->support_user_clear_delete_cron(); wp_schedule_event( time(), 'hourly', $this->support_user_cron_name ); } /** * Get plugin options * * @since 3.20 * * @return void */ public function support_user_get_options() { $this->support_user_options = get_option( $this->support_user_options_name ); } /** * Generate random token * * @since 3.20 * * @param integer $length Token Length * @param bool $include_symbols Whether to include special characters (or just stick to alphanumeric) * * @return string $token Generated token */ public function support_user_generate_token( $length = 17, $include_symbols = true ) { $alphanum = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $symbols = '!@$^*()-=+'; $token = substr( str_shuffle( $include_symbols ? $alphanum . $symbols : $alphanum ), 0, $length ); return $token; } /** * Generate password from token * * @since 3.20 * * @param string $token Token * * @return string|WP_Error Generated password if successful, WP Error object otherwise */ public function support_user_generate_password( $token ) { global $wp_version; $salt = ''; /** @see ET_Core_SupportCenter::maybe_set_site_id() */ $site_id = get_option( 'et_support_site_id' ); if ( empty( $site_id ) ) { return false; } // Site ID must be a string if ( ! is_string( $site_id ) ) { return false; } $et_license = $this->get_et_license(); if ( ! $et_license ) { return false; } $send_to_api = array( 'action' => 'get_salt', 'site_id' => esc_attr( $site_id ), 'username' => esc_attr( $et_license['username'] ), 'api_key' => esc_attr( $et_license['api_key'] ), 'site_url' => esc_url( home_url( '/' ) ), 'login_url' => 'https://www.elegantthemes.com/members-area/admin/token/' . '?url=' . urlencode( wp_login_url() ) . '&token=' . urlencode( $token . '|' . $site_id ), ); $support_user_options = array( 'timeout' => 30, 'body' => $send_to_api, 'user-agent' => 'WordPress/' . $wp_version . '; Support Center/' . ET_CORE_VERSION . '; ' . home_url( '/' ), ); $request = wp_remote_post( 'https://www.elegantthemes.com/api/token.php', $support_user_options ); // Early exit if we don't get a good HTTP response from the API server if ( 200 !== intval( wp_remote_retrieve_response_code( $request ) ) ) { return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: HTTP error in API response', 'et-core' ) ); } // Early exit and pass along WP_Error report if the server response is an error if ( is_wp_error( $request ) ) { return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: WordPress Error in API response', 'et-core' ) ); } // Otherwise the response is good - let's load it and continue $response = unserialize( wp_remote_retrieve_body( $request ) ); // If the API returns an error, we will return and log the accompanying message $response_is_error = array_key_exists( 'error', $response ); $response_has_error_message = array_key_exists( 'message', $response ); if ( $response_is_error && $response_has_error_message ) { return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: ' . $response['message'], 'et-core' ) ); } // If we get an "Incorrect Token" response, delete the generated Site ID from database $response_is_token_error = array_key_exists( 'incorrect_token', $response ); if ( $response_is_token_error && ! empty( $response['incorrect_token'] ) ) { delete_option( 'et_support_site_id' ); return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: Incorrect Token. Please, try again.', 'et-core' ) ); } // If we get a normal-looking response, but it doesn't contain the salt we need if ( empty( $response['salt'] ) ) { return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: The API response was missing required data.', 'et-core' ) ); } // We have the salt; let's clean it and make sure we can use it $salt = sanitize_text_field( $response['salt'] ); if ( empty( $salt ) ) { return new WP_Error( 'et_remote_access', esc_html__( 'Elegant Themes API Error: The API responded, but the response was empty.', 'et-core' ) ); } // Generate the password using the token we were initially passed & the salt from the API $password = hash( 'sha256', $token . $salt ); return $password; } /** * Delete the account if it's expired * * @since 3.20 * * @return void */ public function support_user_maybe_delete_expired_account() { if ( empty( $this->support_user_options['date_created'] ) ) { return; } $expiration_date_unix = strtotime( $this->support_user_expiration_time, $this->support_user_options['date_created'] ); // Delete the user account if the expiration date is in the past if ( time() >= $expiration_date_unix ) { $this->support_user_delete_account(); } return; } /** * Delete support account and the plugin options ( token, expiration date ) * * @since 3.20 * * @return string | WP_Error Confirmation message on success, WP_Error on failure */ public function support_user_delete_account() { if ( defined( 'DOING_CRON' ) ) { require_once( ABSPATH . 'wp-admin/includes/user.php' ); } if ( ! username_exists( $this->support_user_account_name ) ) { return new WP_Error( 'get_user_data', esc_html__( 'Support account doesn\'t exist.', 'et-core' ) ); } $support_account_data = get_user_by( 'login', $this->support_user_account_name ); if ( $support_account_data ) { $support_account_id = $support_account_data->ID; if ( ( is_multisite() && ! wpmu_delete_user( $support_account_id ) ) || ( ! is_multisite() && ! wp_delete_user( $support_account_id ) ) ) { return new WP_Error( 'delete_user', esc_html__( 'Support account hasn\'t been removed. Try to regenerate token again.', 'et-core' ) ); } delete_option( $this->support_user_options_name ); } else { return new WP_Error( 'get_user_data', esc_html__( 'Cannot get the support account data. Try to regenerate token again.', 'et-core' ) ); } $this->support_user_remove_roles(); $this->support_user_remove_site_id(); $this->support_user_clear_delete_cron(); // update options variable $this->support_user_get_options(); new WP_Error( 'get_user_data', esc_html__( 'Token has been deleted successfully.', 'et-core' ) ); return esc_html__( 'Token has been deleted successfully. ', 'et-core' ); } /** * Maybe delete support account and the plugin options when switching themes * * If a theme change is one of: * - [Divi/Extra] > [Divi/Extra] child theme * - [Divi/Extra] child theme > [Divi/Extra] child theme * - [Divi/Extra] child theme > [Divi/Extra] * ...then we won't change the state of the Remote Access toggle. * * @since 3.23 * * @return string | WP_Error Confirmation message on success, WP_Error on failure */ public function maybe_deactivate_on_theme_switch() { // Don't do anything if the user isn't logged in if ( ! is_user_logged_in() ) { return; } // Don't do anything if the parent theme's name matches the parent of this Support Center instance if ( get_option( 'template' ) === $this->parent_nicename ) { return; } // Leaving Divi/Extra environment; deactivate Support Center $this->support_user_delete_account(); $this->unlist_support_center(); $this->support_center_capabilities_teardown(); } /** * Is this user the ET Support User? * * @since 3.22 * * @param int|null $user_id Pass a User ID to check. We'll get the current user's ID otherwise. * * @return bool Returns whether this user is the ET Support User. */ function is_support_user( $user_id = null ) { $user_id = $user_id ? (int) $user_id : get_current_user_id(); if ( ! $user_id ) { return false; } $user = get_userdata( $user_id ); if ( ! is_object( $user ) || ! property_exists( $user, 'roles' ) ) { return false; } // Gather this user's associated role(s). $user_roles = (array) $user->roles; $user_is_support = false; // First, check the username. if ( ! $this->support_user_account_name === $user->user_login ) { return $user_is_support; } // Determine whether this user has the ET Support User role. if ( in_array( 'et_support', $user_roles, true ) ) { $user_is_support = true; } if ( in_array( 'et_support_elevated', $user_roles, true ) ) { $user_is_support = true; } return $user_is_support; } /** * Delete support account and the plugin options ( token, expiration date ) * * @since 3.20 * * @return void */ public function unlist_support_center() { delete_option( 'et_support_center_installed' ); } /** * */ public function support_user_remove_site_id() { $site_id = get_option( 'et_support_site_id' ); if ( empty( $site_id ) ) { return; } // Site ID must be a string if ( ! is_string( $site_id ) ) { return; } $et_license = $this->get_et_license(); if ( ! $et_license ) { return; } $send_to_api = array( 'action' => 'remove_site_id', 'site_id' => esc_attr( $site_id ), 'username' => esc_attr( $et_license['username'] ), 'api_key' => esc_attr( $et_license['api_key'] ), 'site_url' => esc_url( home_url( '/' ) ), ); $settings = array( 'timeout' => 30, 'body' => $send_to_api, ); $request = wp_remote_post( 'https://www.elegantthemes.com/api/token.php', $settings ); } function support_user_update_via_ajax() { // Verify nonce et_core_security_check( 'manage_options', 'support_center', 'nonce' ); // Get POST data $support_update = sanitize_text_field( $_POST['support_update'] ); $response = array(); // Update option(s) if ( 'activate' === $support_update ) { $maybe_create_user = $this->support_user_maybe_create_user(); // Only activate if we have a User ID and Password if ( ! is_wp_error( $maybe_create_user ) ) { $this->support_user_set_role( 'et_support' ); $account_settings = get_option( $this->support_user_options_name ); $site_id = get_option( 'et_support_site_id' ); $response['expiry'] = strtotime( date( 'Y-m-d H:i:s ', $this->support_user_options['date_created'] ) . $this->support_user_expiration_time ); $response['token'] = ''; if ( ! empty( $site_id ) && is_string( $site_id ) ) { $account_setting_token = isset( $account_settings['token'] ) ? $account_settings['token'] : ''; $response['token'] = $account_setting_token . '|' . $site_id; } $response['message'] = esc_html__( 'ET Support User role has been activated.', 'et-core' ); } else { et_error( $maybe_create_user->get_error_message() ); $response['error'] = $maybe_create_user->get_error_message(); } } if ( 'elevate' === $support_update ) { $this->support_user_set_role( 'et_support_elevated' ); $response['message'] = esc_html__( 'ET Support User role has been elevated.', 'et-core' ); } if ( 'deactivate' === $support_update ) { $this->support_user_set_role( '' ); $this->support_user_delete_account(); $this->support_user_clear_delete_cron(); $response['message'] = esc_html__( 'ET Support User role has been deactivated.', 'et-core' ); } // `echo` data to return if ( isset( $response ) ) { echo json_encode( $response ); } // `die` when we're done wp_die(); } /** * SUPPORT CENTER :: SAFE MODE */ /** * ET Product Allowlist * * @since 3.28 * * @param string $product Potential ET product name that we want to confirm is on the list. * * @return string|false If the product is on our list, we return the "nice name" we have for it. Otherwise, we return FALSE. */ protected function is_allowlisted_product( $product = '' ) { switch ( $product ) { case 'divi_builder_plugin': case 'divi_theme': case 'extra_theme': case 'monarch_plugin': case 'bloom_plugin': case 'divi_dash_plugin': return $this->get_parent_nicename( $product ); break; default: return false; } } /** * Safe Mode: Set session cookie to temporarily disable Plugins * * @since 3.20 * * @return void */ function safe_mode_update_via_ajax() { et_core_security_check( 'manage_options', 'support_center', 'nonce' ); $response = array(); // Get POST data $support_update = sanitize_text_field( $_POST['support_update'] ); // Update option(s) if ( 'activate' === $support_update ) { // Check the ET product that is activating Safe Mode $safe_mode_activator = sanitize_key( $_POST['product'] ); // Confirm that this is a allowlisted product $allowlisted_product = $this->is_allowlisted_product( $safe_mode_activator ); if ( ! $allowlisted_product ) { // Send a failure code and exit the function header( "HTTP/1.0 403 Forbidden" ); print 'Bad or malformed ET product name.'; wp_die(); } $this->toggle_safe_mode( true, $safe_mode_activator ); $response['message'] = esc_html__( 'ET Safe Mode has been activated.', 'et-core' ); } if ( 'deactivate' === $support_update ) { $this->toggle_safe_mode( false ); $response['message'] = esc_html__( 'ET Safe Mode has been deactivated.', 'et-core' ); } $this->set_safe_mode_cookie(); // `echo` data to return if ( isset( $response ) ) { echo json_encode( $response ); } // `die` when we're done wp_die(); } /** * Toggle Safe Mode * * @since 3.20 * * @param bool $activate TRUE if enabling Safe Mode, FALSE if disabling Safe mode. * @param string $product Name of ET product that is activating Safe Mode (@see ET_Core_SupportCenter::get_parent_nicename()). */ public function toggle_safe_mode( $activate = true, $product = '' ) { $activate = (bool) $activate; $user_id = get_current_user_id(); $allowlisted_product = $this->is_allowlisted_product( $product ); // Only proceed with an activation request if it comes from a allowlisted product if ( $activate && ! $allowlisted_product ) { return; } update_user_meta( $user_id, '_et_support_center_safe_mode', $activate ? 'on' : 'off' ); update_user_meta( $user_id, '_et_support_center_safe_mode_product', $activate ? sanitize_text_field( $allowlisted_product ) : '' ); $activate ? $this->maybe_add_mu_autoloader() : $this->maybe_remove_mu_autoloader(); /** * Fires when safe mode is toggled on or off. * * @since 3.25.4 * * @param bool $state True if toggled on, false if toggled off. */ do_action( 'et_support_center_toggle_safe_mode', $activate ); } /** * Set Safe Mode Cookie * * @since 3.20 * * @return void */ function set_safe_mode_cookie() { if ( et_core_is_safe_mode_active() ) { // This random string ensures old cookies aren't used to view the site in Safe Mode $passport = md5( rand() ); update_option( 'et-support-center-safe-mode-verify', $passport ); setcookie( 'et-support-center-safe-mode', $passport, time() + DAY_IN_SECONDS, SITECOOKIEPATH, false, is_ssl() ); } else { // Force-expire the cookie setcookie( 'et-support-center-safe-mode', '', 1, SITECOOKIEPATH, false, is_ssl() ); } } /** * Render modal that intercepts plugin activation/deactivation * * @since 3.20 * * @return void */ public function render_safe_mode_block_restricted() { if ( ! et_core_is_safe_mode_active() ) { return; } // Get the name of the ET product that activated Safe Mode $safe_mode_activator = get_user_meta( get_current_user_id(), '_et_support_center_safe_mode_product', true ); $verified_activator = $this->is_allowlisted_product( $safe_mode_activator ); ?> is_allowlisted_product( $safe_mode_activator ); print sprintf( '%3$s', 'et-safe-mode-indicator', esc_url( get_admin_url( null, 'admin.php?page=et_support_center#et_card_safe_mode' ) ), esc_html__( sprintf( 'Turn Off %1$s Safe Mode', $verified_activator ), 'et-core' ) ); print 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.
', 'et-core' ); $support_account = $this->get_et_support_user(); $is_et_support_user_active = 0; $has_et_license = $this->get_et_license(); if ( ! $has_et_license ) { $card_content .= sprintf( '%2$s
'
. ''
. '' . 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' ) . '
' . '' . esc_html__( 'Get Divi VIP Today!', 'et-core' ) . '' . '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[] = 'Plugins cannot be disabled because your wp-content directory has inconsistent file permissions. Click here for more information.
%1$s
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.
'; if ( isset( $wp_debug_log['error'] ) ) { $card_content .= '
%1$s