function et_add_divi_menu() {
$core_page = add_menu_page( 'Divi', 'Divi', 'edit_theme_options', 'et_divi_options', 'et_build_epanel' );
// Add Theme Options menu only if it's enabled for current user
if ( et_pb_is_allowed( 'theme_options' ) ) {
if ( isset( $_GET['page'] ) && 'et_divi_options' === $_GET['page'] && isset( $_POST['action'] ) ) {
( isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'epanel_nonce' ) )
( 'reset' === $_POST['action'] && isset( $_POST['_wpnonce_reset'] ) && wp_verify_nonce( $_POST['_wpnonce_reset'], 'et-nojs-reset_epanel' ) )
epanel_save_data( 'js_disabled' ); //saves data when javascript is disabled
add_submenu_page( 'et_divi_options', esc_html__( 'Theme Options', 'Divi' ), esc_html__( 'Theme Options', 'Divi' ), 'manage_options', 'et_divi_options' );
et_theme_builder_add_admin_page( 'et_divi_options' );
// Add Theme Customizer menu only if it's enabled for current user
if ( et_pb_is_allowed( 'theme_customizer' ) ) {
add_submenu_page( 'et_divi_options', esc_html__( 'Theme Customizer', 'Divi' ), esc_html__( 'Theme Customizer', 'Divi' ), 'manage_options', 'customize.php?et_customizer_option_set=theme' );
add_submenu_page( 'et_divi_options', esc_html__( 'Role Editor', 'Divi' ), esc_html__( 'Role Editor', 'Divi' ), 'manage_options', 'et_divi_role_editor', 'et_pb_display_role_editor' );
// Add Divi Library menu only if it's enabled for current user
if ( et_pb_is_allowed( 'divi_library' ) ) {
add_submenu_page( 'et_divi_options', esc_html__( 'Divi Library', 'Divi' ), esc_html__( 'Divi Library', 'Divi' ), 'manage_options', 'edit.php?post_type=et_pb_layout' );
add_action( "load-{$core_page}", 'et_pb_check_options_access' ); // load function to check the permissions of current user
add_action( "load-{$core_page}", 'et_epanel_hook_scripts' );
add_action( "admin_print_scripts-{$core_page}", 'et_epanel_admin_js' );
add_action( "admin_head-{$core_page}", 'et_epanel_css_admin');
add_action( "admin_print_scripts-{$core_page}", 'et_epanel_media_upload_scripts');
add_action( "admin_head-{$core_page}", 'et_epanel_media_upload_styles');
add_action('admin_menu', 'et_add_divi_menu');
function add_divi_customizer_admin_menu() {
if ( ! current_user_can( 'customize' ) ) {
$current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$customize_url = add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() );
// add Theme Customizer admin menu only if it's enabled for current user
if ( et_pb_is_allowed( 'theme_customizer' ) ) {
$wp_admin_bar->add_menu( array(
'parent' => 'appearance',
'id' => 'customize-divi-theme',
'title' => esc_html__( 'Theme Customizer', 'Divi' ),
'href' => $customize_url . '&et_customizer_option_set=theme',
'class' => 'hide-if-no-customize',
$wp_admin_bar->remove_menu( 'customize' );
add_action( 'admin_bar_menu', 'add_divi_customizer_admin_menu', 999 );
function et_pb_hide_options_menu() {
// do nothing if theme options should be displayed in the menu
if ( et_pb_is_allowed( 'theme_options' ) ) {
$theme_version = et_get_theme_version();
wp_enqueue_script( 'divi-custom-admin-menu', get_template_directory_uri() . '/js/menu_fix.js', array( 'jquery' ), $theme_version, true );
add_action( 'admin_enqueue_scripts', 'et_pb_hide_options_menu' );
function et_pb_check_options_access() {
// display wp error screen if theme customizer disabled for current user
if ( ! et_pb_is_allowed( 'theme_options' ) ) {
wp_die( esc_html__( "you don't have sufficient permissions to access this page", 'Divi' ) );
function et_add_divi_support_center() {
$support_center = new ET_Core_SupportCenter( 'divi_theme' );
add_action( 'init', 'et_add_divi_support_center' );
* Allowing blog and portfolio module pagination to work in non-hierarchical singular page.
* Normally, WP_Query based modules wouldn't work in non-hierarchical single post type page
* due to canonical redirect to prevent page duplication which could lead to SEO penalty.
* @see redirect_canonical()
* @return mixed string|bool
function et_modify_canonical_redirect( $redirect_url, $requested_url ) {
$allowed_shortcodes = array( 'et_pb_blog', 'et_pb_portfolio' );
$is_overwrite_canonical_redirect = false;
// Look for $allowed_shortcodes in content. Once detected, set $is_overwrite_canonical_redirect to true
foreach ( $allowed_shortcodes as $shortcode ) {
if ( !empty( $post ) && has_shortcode( $post->post_content, $shortcode ) ) {
$is_overwrite_canonical_redirect = true;
// Only alter canonical redirect in 2 cases:
// 1) If current page is singular, has paged and $allowed_shortcodes
// 2) If current page is front_page, has page and $allowed_shortcodes
if ( ( is_singular() & ! is_home() && get_query_var( 'paged' ) && $is_overwrite_canonical_redirect ) || ( is_front_page() && get_query_var( 'page' ) && $is_overwrite_canonical_redirect ) ) {
add_filter( 'redirect_canonical', 'et_modify_canonical_redirect', 10, 2 );
* Determines how many related products should be displayed on single product page
* @param array related products arguments
* @return array modified related products arguments
function et_divi_woocommerce_output_related_products_args( $args ) {
$related_posts = 4; // default number
if ( is_singular( 'product' ) ) {
$page_layout = get_post_meta( get_the_ID(), '_et_pb_page_layout', true );
if ( 'et_full_width_page' !== $page_layout ) {
$related_posts = 3; // set to 3 if page has sidebar
// Modify related and up-sell products args
$args['posts_per_page'] = $related_posts;
$args['columns'] = $related_posts;
add_filter( 'woocommerce_upsell_display_args', 'et_divi_woocommerce_output_related_products_args' );
add_filter( 'woocommerce_output_related_products_args', 'et_divi_woocommerce_output_related_products_args' );
function et_divi_maybe_change_frontend_locale( $locale ) {
$option_name = 'divi_disable_translations';
$theme_options = get_option( 'et_divi' );
$disable_translations = isset ( $theme_options[ $option_name ] ) ? $theme_options[ $option_name ] : false;
if ( 'on' === $disable_translations ) {
add_filter( 'locale', 'et_divi_maybe_change_frontend_locale' );
* Enable Divi gallery override if user activates it
function et_divi_gallery_layout_enable( $option ) {
$setting = et_get_option( 'divi_gallery_layout_enable' );
return ( 'on' === $setting ) ? true : $option;
add_filter( 'et_gallery_layout_enable', 'et_divi_gallery_layout_enable' );
* Enable GB gallery to shortcode conversion
function et_divi_gb_gallery_to_shortcode() {
return et_divi_gallery_layout_enable( false );
add_filter( 'et_gb_gallery_to_shortcode', 'et_divi_gb_gallery_to_shortcode' );
* Register theme and modules Customizer portability.
function et_divi_register_customizer_portability() {
// Make sure the Portability is loaded.
et_core_load_component( 'portability' );
// Exclude ePanel options.
foreach ( $options as $option ) {
if ( isset( $option['id'] ) ) {
$exclude[ $option['id'] ] = true;
// Register the portability.
et_core_portability_register( 'et_divi_mods', array(
'name' => esc_html__( 'Divi Customizer Settings', 'Divi' ),
'view' => is_customize_preview(),
add_action( 'admin_init', 'et_divi_register_customizer_portability' );
function et_register_updates_component() {
et_core_enable_automatic_updates( get_template_directory_uri(), ET_CORE_VERSION );
add_action( 'admin_init', 'et_register_updates_component', 9 );
* Register theme and modules Customizer portability link.
* @return bool Always return true.
function et_divi_customizer_link() {
if ( is_customize_preview() ) {
echo et_builder_portability_link( 'et_divi_mods', array( 'class' => 'et-core-customize-controls-close' ) );
add_action( 'customize_controls_print_footer_scripts', 'et_divi_customizer_link' );
* Added body class to make it possible to identify the Divi theme on frontend
function et_divi_theme_body_class( $classes ) {
$classes[] = 'et_divi_theme';
add_filter( 'body_class', 'et_divi_theme_body_class' );
* Determine if it's a fresh Divi install by checking for the existence of 'divi_logo' key in 'et_divi' options array.
if ( ! function_exists( 'et_divi_is_fresh_install' ) ):
function et_divi_is_fresh_install() {
return false === et_get_option( 'divi_logo' );
if ( ! function_exists( 'et_get_original_footer_credits' ) ) :
function et_get_original_footer_credits() {
return sprintf( __( 'Designed by %1$s | Powered by %2$s', 'Divi' ), '<a href="http://www.elegantthemes.com" title="Premium WordPress Themes">Elegant Themes</a>', '<a href="http://www.wordpress.org">WordPress</a>' );
if ( ! function_exists( 'et_get_footer_credits' ) ) :
function et_get_footer_credits() {
$original_footer_credits = et_get_original_footer_credits();
$disable_custom_credits = et_get_option( 'disable_custom_footer_credits', false );
if ( $disable_custom_credits ) {
$credits_format = '<%2$s id="footer-info">%1$s</%2$s>';
$footer_credits = et_get_option( 'custom_footer_credits', '' );
if ( '' === trim( $footer_credits ) ) {
return et_get_safe_localization( sprintf( $credits_format, $original_footer_credits, 'p' ) );
return et_get_safe_localization( sprintf( $credits_format, $footer_credits, 'div' ) );
if ( ! function_exists( 'et_divi_filter_et_core_is_builder_used_on_current_request' ) ):
function et_divi_filter_et_core_is_builder_used_on_current_request( $is_builder_used ) {
if ( $is_builder_used && ! is_singular() ) {
$is_builder_used = 'on' === et_get_option( 'divi_blog_style', 'false' );
add_filter( 'et_core_is_builder_used_on_current_request', 'et_divi_filter_et_core_is_builder_used_on_current_request' );
if ( ! function_exists( 'et_divi_version_rollback' ) ) :
function et_divi_version_rollback() {
global $themename, $shortname;
if ( null === $instance ) {
$instance = new ET_Core_VersionRollback( $themename, $shortname, et_get_theme_version() );
* Filter the list of post types the Divi Builder is enabled on based on theme options.
* @param array<string, string> $options
* @return array<string, string>
if ( ! function_exists( 'et_divi_filter_enabled_builder_post_type_options' ) ) :
function et_divi_filter_enabled_builder_post_type_options( $options ) {
// Cache results to avoid unnecessary option fetching multiple times per request.
static $stored_options = null;
if ( null === $stored_options ) {
$stored_options = et_get_option( 'et_pb_post_type_integration', array() );
add_filter( 'et_builder_enabled_builder_post_type_options', 'et_divi_filter_enabled_builder_post_type_options' );
* Caches expensive generation of truncate_post content
if ( ! function_exists( 'et_divi_truncate_post_use_custom_content' ) ) :
function et_divi_truncate_post_use_custom_content( $custom, $content, $post ) {
// If post doesn't use builder, no need to compute a custom value
if ( ! et_pb_is_pagebuilder_used( $post->ID ) ) {
$cached = get_post_meta( $post->ID, '_et_pb_truncate_post', true );
$cached_date = get_post_meta( $post->ID, '_et_pb_truncate_post_date', true );
$cached_date = $cached_date ? $cached_date : get_post_field( 'post_modified', $post->ID );
$global_modules = array();
preg_match_all( '/'. get_shortcode_regex() .'/s', $content, $shortcodes );
if ( is_array( $shortcodes ) && isset( $shortcodes[3] ) ) {
foreach ( $shortcodes[3] as $raw_attributes ) {
$attributes = shortcode_parse_atts( $raw_attributes );
$attributes = is_array( $attributes ) ? $attributes : array();
$global_id = (int) et_()->array_get( $attributes, 'global_module', 0 );
$global_modules[] = $global_id;
foreach ( $global_modules as $module_post_id ) {
// Dates are using the Y-m-d H:i:s format so we can compare them as strings for simplicity.
if ( strcmp( get_post_field( 'post_modified', $module_post_id ), $cached_date ) > 0 ) {
// A global module used in the post has been updated more recently than
// the post's cached excerpt so we need to invalidate the cache.
$custom = apply_filters( 'the_content', $content );
// Save the result because expensive to compute.
update_post_meta( $post->ID, '_et_pb_truncate_post', $custom );
update_post_meta( $post->ID, '_et_pb_truncate_post_date', date( 'Y-m-d H:i:s' ) );
add_filter( 'et_truncate_post_use_custom_content', 'et_divi_truncate_post_use_custom_content', 10, 3 );
* Caches expensive generation of et_first_image
if ( ! function_exists( 'et_divi_first_image_use_custom_content' ) ) :
function et_divi_first_image_use_custom_content( $custom, $content, $post ) {
// If post doesn't use builder, no need to compute a custom value
if ( ! et_pb_is_pagebuilder_used( $post->ID ) ) {
$cached = get_post_meta( $post->ID, '_et_pb_first_image', true );
$custom = apply_filters( 'the_content', $content );
// Save the result because expensive to compute.
update_post_meta( $post->ID, '_et_pb_first_image', $custom );
add_filter( 'et_first_image_use_custom_content', 'et_divi_first_image_use_custom_content', 10, 3 );
* Fired when post is saved in VB / BFB / BB
* @param integer $post_id
if ( ! function_exists( 'et_divi_save_post' ) ) :
function et_divi_save_post( $post_id ) {
update_post_meta( $post_id, '_et_pb_first_image', false );
update_post_meta( $post_id, '_et_pb_truncate_post', false );
update_post_meta( $post_id, '_et_pb_truncate_post_date', '' );
add_action( 'et_save_post', 'et_divi_save_post', 1 );
if ( ! function_exists( 'et_divi_footer_active_sidebars' ) ):
function et_divi_footer_active_sidebars() {
$et_active_sidebar = array( 2, 3, 4, 5, 6, 7 );
if ( ! is_customize_preview() ) {
if ( ! is_active_sidebar( 2 )
&& ! is_active_sidebar( 3 )
&& ! is_active_sidebar( 4 )
&& ! is_active_sidebar( 5 )
&& ! is_active_sidebar( 6 )
&& ! is_active_sidebar( 7 ) ) {
$footer_columns = et_get_option( 'footer_columns', '4' );
switch ( $footer_columns ) {
$et_active_sidebar = array();
for ( $i = 1; $i <= $footer_columns; $i++ ) {
array_push( $et_active_sidebar, ( $i + 1 ) );
$et_active_sidebar = array( 2, 3 );