Changing Divi Page Builder modules
If you find this tweak helpful:
Beginners
Tweaking Elegant Themes involves creating a child theme and editing PHP and CSS files within a text editor. If you have never done this you may want to read our guide on creating a child theme. All tweaks are written with the assumption that you have a default installation of your theme. Any tweaks or changes you may have previously made to your theme could affect the outcome of the tweaks on this site. All tweaks should be tested before applying to a live site.
This tweak will show you how to properly replace a Divi Page Builder module with your own version, overwriting the default module in the functions.php file with the new version in your child theme. This is great for changing the way the blog module displays posts, the behavior of the portfolio module, or changing any module in general.
We have developed a plugin that will now let you easily create your own custom modules! Check out the demo on our website dedicated to Divi plugins:
First I’ll give you the code so those familiar with PHP can get what they need and move on. For anyone who doesn’t understand it, I’ll explain it below so you can apply it to your situation.
PHP
UPDATE:
I have updated this tutorial again with instructions for Divi 3.0+
Divi version 3.0 and up
The first thing you’ll need to do is create a new folder inside your child theme, called custom-modules.
In custom-modules, create a new file called cfwpm.php and paste this code inside:
1 2 3 4 5 6 7 8 9 10 11 |
<?php class Custom_ET_Builder_Module_Portfolio extends ET_Builder_Module { function init() { $this->name = __( 'Portfolio', 'et_builder' ); $this->slug = 'et_pb_portfolio'; $this->fb_support = true; insert the code for the module you want to replace here. The name and slug above should match the name and slug of the module you want to replace. All of this can be found inside /Divi/includes/builder/main-modules.php |
Next you’ll need to a new file in your child theme folder and name it functions.php
Your new file location should be this /wp-content/themes/Divi-child/functions.php
In your new functions.php file, add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function divi_child_theme_setup() { if ( ! class_exists('ET_Builder_Module') ) { return; } get_template_part( 'custom-modules/cfwpm' ); $cfwpm = new Custom_ET_Builder_Module_Portfolio(); remove_shortcode( 'et_pb_portfolio' ); add_shortcode( 'et_pb_portfolio', array($cfwpm, '_shortcode_callback') ); } add_action( 'wp', 'divi_child_theme_setup', 9999 ); |
UPDATE:
I have updated this tutorial with instructions for Divi 2.4+ below followed by the instructions for versions prior to Divi 2.4.
Divi version 2.4 and up
The first thing you’ll want to do is create a new file in your child theme folder and name it functions.php
Your new file location should be this /wp-content/themes/Divi-child/functions.php
For this example, I’m going to change the Portfolio Module in Divi 2.5.5
Copy and paste the following code into your new functions.php file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
<?php function divi_child_theme_setup() { if ( class_exists('ET_Builder_Module')) { class CHILD_ET_Builder_Module_Portfolio extends ET_Builder_Module { function init() { $this->name = __( 'Portfolio', 'et_builder' ); $this->slug = 'et_pb_portfolio'; $this->whitelisted_fields = array( 'fullwidth', 'posts_number', 'include_categories', 'show_title', 'show_categories', 'show_pagination', 'background_layout', 'admin_label', 'module_id', 'module_class', 'zoom_icon_color', 'hover_overlay_color', 'hover_icon', ); $this->fields_defaults = array( 'fullwidth' => array( 'on' ), 'posts_number' => array( 10, 'add_default_setting' ), 'show_title' => array( 'on' ), 'show_categories' => array( 'on' ), 'show_pagination' => array( 'on' ), 'background_layout' => array( 'light' ), ); $this->main_css_element = '%%order_class%% .et_pb_portfolio_item'; $this->advanced_options = array( 'fonts' => array( 'title' => array( 'label' => __( 'Title', 'et_builder' ), 'css' => array( 'main' => "{$this->main_css_element} h2", 'important' => 'all', ), ), 'caption' => array( 'label' => __( 'Meta', 'et_builder' ), 'css' => array( 'main' => "{$this->main_css_element} .post-meta, {$this->main_css_element} .post-meta a", ), ), ), 'background' => array( 'settings' => array( 'color' => 'alpha', ), ), 'border' => array(), ); $this->custom_css_options = array( 'portfolio_image' => array( 'label' => __( 'Portfolio Image', 'et_builder' ), 'selector' => '.et_portfolio_image', ), 'overlay' => array( 'label' => __( 'Overlay', 'et_builder' ), 'selector' => '.et_overlay', ), 'overlay_icon' => array( 'label' => __( 'Overlay Icon', 'et_builder' ), 'selector' => '.et_overlay:before', ), 'portfolio_title' => array( 'label' => __( 'Portfolio Title', 'et_builder' ), 'selector' => '.et_pb_portfolio_item h2', ), 'portfolio_post_meta' => array( 'label' => __( 'Portfolio Post Meta', 'et_builder' ), 'selector' => '.et_pb_portfolio_item .post-meta', ), ); } function get_fields() { $fields = array( 'fullwidth' => array( 'label' => __( 'Layout', 'et_builder' ), 'type' => 'select', 'option_category' => 'layout', 'options' => array( 'on' => __( 'Fullwidth', 'et_builder' ), 'off' => __( 'Grid', 'et_builder' ), ), 'description' => __( 'Choose your desired portfolio layout style.', 'et_builder' ), ), 'posts_number' => array( 'label' => __( 'Posts Number', 'et_builder' ), 'type' => 'text', 'option_category' => 'configuration', 'description' => __( 'Define the number of projects that should be displayed per page.', 'et_builder' ), ), 'include_categories' => array( 'label' => __( 'Include Categories', 'et_builder' ), 'renderer' => 'et_builder_include_categories_option', 'option_category' => 'basic_option', 'description' => __( 'Select the categories that you would like to include in the feed.', 'et_builder' ), ), 'show_title' => array( 'label' => __( 'Show Title', 'et_builder' ), 'type' => 'yes_no_button', 'option_category' => 'configuration', 'options' => array( 'on' => __( 'Yes', 'et_builder' ), 'off' => __( 'No', 'et_builder' ), ), 'description' => __( 'Turn project titles on or off.', 'et_builder' ), ), 'show_categories' => array( 'label' => __( 'Show Categories', 'et_builder' ), 'type' => 'yes_no_button', 'option_category' => 'configuration', 'options' => array( 'on' => __( 'Yes', 'et_builder' ), 'off' => __( 'No', 'et_builder' ), ), 'description' => __( 'Turn the category links on or off.', 'et_builder' ), ), 'show_pagination' => array( 'label' => __( 'Show Pagination', 'et_builder' ), 'type' => 'yes_no_button', 'option_category' => 'configuration', 'options' => array( 'on' => __( 'Yes', 'et_builder' ), 'off' => __( 'No', 'et_builder' ), ), 'description' => __( 'Enable or disable pagination for this feed.', 'et_builder' ), ), 'background_layout' => array( 'label' => __( 'Text Color', 'et_builder' ), 'type' => 'select', 'option_category' => 'color_option', 'options' => array( 'light' => __( 'Dark', 'et_builder' ), 'dark' => __( 'Light', 'et_builder' ), ), 'description' => __( 'Here you can choose whether your text should be light or dark. If you are working with a dark background, then your text should be light. If your background is light, then your text should be set to dark.', 'et_builder' ), ), 'admin_label' => array( 'label' => __( 'Admin Label', 'et_builder' ), 'type' => 'text', 'description' => __( 'This will change the label of the module in the builder for easy identification.', 'et_builder' ), ), 'module_id' => array( 'label' => __( 'CSS ID', 'et_builder' ), 'type' => 'text', 'option_category' => 'configuration', 'description' => __( 'Enter an optional CSS ID to be used for this module. An ID can be used to create custom CSS styling, or to create links to particular sections of your page.', 'et_builder' ), ), 'module_class' => array( 'label' => __( 'CSS Class', 'et_builder' ), 'type' => 'text', 'option_category' => 'configuration', 'description' => __( 'Enter optional CSS classes to be used for this module. A CSS class can be used to create custom CSS styling. You can add multiple classes, separated with a space.', 'et_builder' ), ), 'zoom_icon_color' => array( 'label' => __( 'Zoom Icon Color', 'et_builder' ), 'type' => 'color', 'custom_color' => true, 'tab_slug' => 'advanced', ), 'hover_overlay_color' => array( 'label' => __( 'Hover Overlay Color', 'et_builder' ), 'type' => 'color-alpha', 'custom_color' => true, 'tab_slug' => 'advanced', ), 'hover_icon' => array( 'label' => __( 'Hover Icon Picker', 'et_builder' ), 'type' => 'text', 'option_category' => 'configuration', 'class' => array( 'et-pb-font-icon' ), 'renderer' => 'et_pb_get_font_icon_list', 'renderer_with_field' => true, 'tab_slug' => 'advanced', ), ); return $fields; } function shortcode_callback( $atts, $content = null, $function_name ) { $module_id = $this->shortcode_atts['module_id']; $module_class = $this->shortcode_atts['module_class']; $fullwidth = $this->shortcode_atts['fullwidth']; $posts_number = $this->shortcode_atts['posts_number']; $include_categories = $this->shortcode_atts['include_categories']; $show_title = $this->shortcode_atts['show_title']; $show_categories = $this->shortcode_atts['show_categories']; $show_pagination = $this->shortcode_atts['show_pagination']; $background_layout = $this->shortcode_atts['background_layout']; $zoom_icon_color = $this->shortcode_atts['zoom_icon_color']; $hover_overlay_color = $this->shortcode_atts['hover_overlay_color']; $hover_icon = $this->shortcode_atts['hover_icon']; global $paged; $module_class = ET_Builder_Element::add_module_order_class( $module_class, $function_name ); if ( '' !== $zoom_icon_color ) { ET_Builder_Element::set_style( $function_name, array( 'selector' => '%%order_class%% .et_overlay:before', 'declaration' => sprintf( 'color: %1$s !important;', esc_html( $zoom_icon_color ) ), ) ); } if ( '' !== $hover_overlay_color ) { ET_Builder_Element::set_style( $function_name, array( 'selector' => '%%order_class%% .et_overlay', 'declaration' => sprintf( 'background-color: %1$s; border-color: %1$s;', esc_html( $hover_overlay_color ) ), ) ); } $container_is_closed = false; $args = array( 'posts_per_page' => (int) $posts_number, 'post_type' => 'project', ); $et_paged = is_front_page() ? get_query_var( 'page' ) : get_query_var( 'paged' ); if ( is_front_page() ) { $paged = $et_paged; } if ( '' !== $include_categories ) $args['tax_query'] = array( array( 'taxonomy' => 'project_category', 'field' => 'id', 'terms' => explode( ',', $include_categories ), 'operator' => 'IN', ) ); if ( ! is_search() ) { $args['paged'] = $et_paged; } $main_post_class = sprintf( 'et_pb_portfolio_item%1$s', ( 'on' !== $fullwidth ? ' et_pb_grid_item' : '' ) ); ob_start(); query_posts( $args ); if ( have_posts() ) { while ( have_posts() ) { the_post(); ?> <div id="post-<?php the_ID(); ?>" <?php post_class( $main_post_class ); ?>> <?php $thumb = ''; $width = 'on' === $fullwidth ? 1080 : 400; $width = (int) apply_filters( 'et_pb_portfolio_image_width', $width ); $height = 'on' === $fullwidth ? 9999 : 284; $height = (int) apply_filters( 'et_pb_portfolio_image_height', $height ); $classtext = 'on' === $fullwidth ? 'et_pb_post_main_image' : ''; $titletext = get_the_title(); $thumbnail = get_thumbnail( $width, $height, $classtext, $titletext, $titletext, false, 'Blogimage' ); $thumb = $thumbnail["thumb"]; $post_url = get_post_meta(get_the_ID(), custom_url, true); if ( '' !== $thumb ) : ?> <a href="<?php echo $post_url; ?>"> <?php if ( 'on' !== $fullwidth ) : ?> <span class="et_portfolio_image"> <?php endif; ?> <?php print_thumbnail( $thumb, $thumbnail["use_timthumb"], $titletext, $width, $height ); ?> <?php if ( 'on' !== $fullwidth ) : $data_icon = '' !== $hover_icon ? sprintf( ' data-icon="%1$s"', esc_attr( et_pb_process_font_icon( $hover_icon ) ) ) : ''; printf( '<span class="et_overlay%1$s"%2$s></span>', ( '' !== $hover_icon ? ' et_pb_inline_icon' : '' ), $data_icon ); ?> </span> <?php endif; ?> </a> <?php endif; ?> <?php if ( 'on' === $show_title ) : ?> <h2><a href="<?php echo $post_url; ?>"><?php the_title(); ?></a></h2> <?php endif; ?> <?php if ( 'on' === $show_categories ) : ?> <p class="post-meta"><?php echo get_the_term_list( get_the_ID(), 'project_category', '', ', ' ); ?></p> <?php endif; ?> </div> <!-- .et_pb_portfolio_item --> <?php } if ( 'on' === $show_pagination && ! is_search() ) { echo '</div> <!-- .et_pb_portfolio -->'; $container_is_closed = true; if ( function_exists( 'wp_pagenavi' ) ) { wp_pagenavi(); } else { if ( et_is_builder_plugin_active() ) { include( ET_BUILDER_PLUGIN_DIR . 'includes/navigation.php' ); } else { get_template_part( 'includes/navigation', 'index' ); } } } wp_reset_query(); } else { if ( et_is_builder_plugin_active() ) { include( ET_BUILDER_PLUGIN_DIR . 'includes/no-results.php' ); } else { get_template_part( 'includes/no-results', 'index' ); } } $posts = ob_get_contents(); ob_end_clean(); $class = " et_pb_module et_pb_bg_layout_{$background_layout}"; $output = sprintf( '<div%5$s class="%1$s%3$s%6$s"> %2$s %4$s', ( 'on' === $fullwidth ? 'et_pb_portfolio' : 'et_pb_portfolio_grid clearfix' ), $posts, esc_attr( $class ), ( ! $container_is_closed ? '</div> <!-- .et_pb_portfolio -->' : '' ), ( '' !== $module_id ? sprintf( ' id="%1$s"', esc_attr( $module_id ) ) : '' ), ( '' !== $module_class ? sprintf( ' %1$s', esc_attr( $module_class ) ) : '' ) ); return $output; } } $cgm = new CHILD_ET_Builder_Module_Portfolio(); remove_shortcode( 'et_pb_portfolio' ); add_shortcode( 'et_pb_portfolio', array($cgm, '_shortcode_callback') ); } } add_action('wp', 'divi_child_theme_setup', 9999); ?> |
My new custom module changes the portfolio module to link to a custom URL I set in each project using a custom field. I stored the new URL in a variable with this line:
1 |
$post_url = get_post_meta(get_the_ID(), custom_url, true); |
You can change custom_url to whatever you want but it needs to be the same as the custom field name you add to each project. Now just go to your projects, add a new custom field called custom_url and insert any URL you like in the value field. Your image and title should now link to the custom URL.
If you want to change a module other than the portfolio module, use the following guidelines:
- Change line 6 in the code above to better reflect the name of your custom module. Basically just copy and paste the original module class but add CHILD_ in front of it.
- Change line 371 in the code above to match the new custom class name from guideline 1.
- In lines 372 and 373, change et_pb_portfolio to the slug value of the module you want to modify. In the code above, you can see the slug value on line 9. Each module will have a unique slug value. Just make sure you change lines 372 and 373 to this value.
Divi version 2.3.2 and under
The first thing you’ll want to do is create a new file in your child theme folder and name it functions.php
Your new file location should be this /wp-content/themes/Divi-child/functions.php
For this example, I’m going to change the Blog Module in Divi 2.3.1
Copy and paste the following code into your new functions.php file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
<?php function override_parent() { remove_shortcode( 'et_pb_blog', 'et_pb_blog' ); add_shortcode( 'et_pb_blog', 'et_pb_blog_custom' ); } add_action('after_setup_theme','override_parent'); function et_pb_blog_custom( $atts ) { extract( shortcode_atts( array( 'module_id' => '', 'module_class' => '', 'fullwidth' => 'on', 'posts_number' => 10, 'include_categories' => '', 'meta_date' => 'M j, Y', 'show_thumbnail' => 'on', 'show_content' => 'off', 'show_author' => 'on', 'show_date' => 'on', 'show_categories' => 'on', 'show_pagination' => 'on', 'offset_number' => 0, 'background_layout' => 'light', 'show_more' => 'off', ), $atts ) ); global $paged; $container_is_closed = false; if ( 'on' !== $fullwidth ){ wp_enqueue_script( 'jquery-masonry-3' ); $background_layout = 'light'; } $args = array( 'posts_per_page' => (int) $posts_number ); $et_paged = is_front_page() ? get_query_var( 'page' ) : get_query_var( 'paged' ); if ( is_front_page() ) { $paged = $et_paged; } if ( '' !== $include_categories ) $args['cat'] = $include_categories; if ( ! is_search() ) { $args['paged'] = $et_paged; } if ( '' !== $offset_number && ! empty( $offset_number ) ) { $args['offset'] = (int) $offset_number; } ob_start(); query_posts( $args ); if ( have_posts() ) { while ( have_posts() ) { the_post(); $post_format = get_post_format(); $thumb = ''; $width = 'on' === $fullwidth ? 1080 : 400; $width = (int) apply_filters( 'et_pb_blog_image_width', $width ); $height = 'on' === $fullwidth ? 675 : 250; $height = (int) apply_filters( 'et_pb_blog_image_height', $height ); $classtext = 'on' === $fullwidth ? 'et_pb_post_main_image' : ''; $titletext = get_the_title(); $thumbnail = get_thumbnail( $width, $height, $classtext, $titletext, $titletext, false, 'Blogimage' ); $thumb = $thumbnail["thumb"]; $no_thumb_class = '' === $thumb || 'off' === $show_thumbnail ? ' et_pb_no_thumb' : ''; if ( in_array( $post_format, array( 'video', 'gallery' ) ) ) { $no_thumb_class = ''; } ?> <article id="post-<?php the_ID(); ?>" <?php post_class( 'et_pb_post' . $no_thumb_class ); ?>> <?php et_divi_post_format_content(); if ( ! in_array( $post_format, array( 'link', 'audio', 'quote' ) ) ) { if ( 'video' === $post_format && false !== ( $first_video = et_get_first_video() ) ) : printf( '<div class="et_main_video_container"> %1$s </div>', $first_video ); elseif ( 'gallery' === $post_format ) : et_gallery_images(); elseif ( '' !== $thumb && 'on' === $show_thumbnail ) : if ( 'on' !== $fullwidth ) echo '<div class="et_pb_image_container">'; ?> <a href="<?php the_permalink(); ?>"> <?php print_thumbnail( $thumb, $thumbnail["use_timthumb"], $titletext, $width, $height ); ?> </a> <?php if ( 'on' !== $fullwidth ) echo '</div> <!-- .et_pb_image_container -->'; endif; } ?> <?php if ( 'off' === $fullwidth || ! in_array( $post_format, array( 'link', 'audio', 'quote', 'gallery' ) ) ) { ?> <?php if ( ! in_array( $post_format, array( 'link', 'audio' ) ) ) { ?> <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2> <?php } ?> <?php if ( 'on' === $show_author || 'on' === $show_date || 'on' === $show_categories ) { printf( '<p class="post-meta">%1$s %2$s %3$s %4$s %5$s</p>', ( 'on' === $show_author ? sprintf( __( 'by %s', 'Divi' ), et_get_the_author_posts_link() ) : '' ), ( ( 'on' === $show_author && 'on' === $show_date ) ? ' | ' : '' ), ( 'on' === $show_date ? sprintf( __( '%s', 'Divi' ), get_the_date( $meta_date ) ) : '' ), ( (( 'on' === $show_author || 'on' === $show_date ) && 'on' === $show_categories) ? ' | ' : '' ), ( 'on' === $show_categories ? get_the_category_list(', ') : '' ) ); } if ( 'on' === $show_content ) { global $more; $more = null; the_content( __( 'read more...', 'Divi' ) ); } else { if ( has_excerpt() ) { the_excerpt(); } else { truncate_post( 270 ); } $more = 'on' == $show_more ? sprintf( ' <a href="%1$s" class="more-link" >%2$s</a>' , esc_url( get_permalink() ), __( 'read more', 'Divi' ) ) : ''; echo $more; } ?> <?php } // 'off' === $fullwidth || ! in_array( $post_format, array( 'link', 'audio', 'quote', 'gallery' ?> </article> <!-- .et_pb_post --> <?php } // endwhile if ( 'on' === $show_pagination && ! is_search() ) { echo '</div> <!-- .et_pb_posts -->'; $container_is_closed = true; if ( function_exists( 'wp_pagenavi' ) ) wp_pagenavi(); else get_template_part( 'includes/navigation', 'index' ); } wp_reset_query(); } else { get_template_part( 'includes/no-results', 'index' ); } $posts = ob_get_contents(); ob_end_clean(); $class = " et_pb_bg_layout_{$background_layout}"; $output = sprintf( '<div%5$s class="%1$s%3$s%6$s"> %2$s %4$s', ( 'on' === $fullwidth ? 'et_pb_posts' : 'et_pb_blog_grid clearfix' ), $posts, esc_attr( $class ), ( ! $container_is_closed ? '</div> <!-- .et_pb_posts -->' : '' ), ( '' !== $module_id ? sprintf( ' id="%1$s"', esc_attr( $module_id ) ) : '' ), ( '' !== $module_class ? sprintf( ' %1$s', esc_attr( $module_class ) ) : '' ) ); if ( 'on' !== $fullwidth ) $output = sprintf( '<div class="et_pb_blog_grid_wrapper">%1$s</div>', $output ); return $output; } ?> |
In a nutshell, the code above says “Remove the original blog module and replace it with my version”. Now you can make any changes you want and they will not be overwritten the next time you update Divi. I chose the blog module because that is the most common module that I change on a client’s website. Most requests involve changing the order of how the content is displayed. A lot of clients want the title and meta information ABOVE the image, which can all be rearranged in your new function. Just keep in mind this only applies to the blog module. You would still have to change the single.php file and index.php file if you wanted to change how they are displayed on each post and archive page.
Now let’s explain what is happening so you can apply it to other modules.
The first thing you need to know is that the functions.php file must begin with <?php and end with ?>
Then we insert the function that replaces the module with our version:
1 2 3 4 5 |
function override_parent() { remove_shortcode( 'et_pb_blog', 'et_pb_blog' ); add_shortcode( 'et_pb_blog', 'et_pb_blog_custom' ); } add_action('after_setup_theme','override_parent'); |
The override_parent() function wraps all of the code we need to run into one function that can be applied at the right time. When Divi created modules, they used nicknames or shortcodes ie: et_pb_blog. For each shortcode, they created a function with the code necessary to display the module. The shortcode and the function have the same name, which can make the code above confusing. In the remove_shortcode line, we remove the et_pb_blog function from the shortcode. In the add_shortcode line, we add the shortcode back in, but assign it to our new custom function. After the add_action line, we add our custom function.
All we’re doing here is creating a function that first removes the original module and then adds our new module. It doesn’t have to be called ‘et_pb_blog_custom’. It can be anything you like. But the ‘et_pb_blog’ text must be exact because it references the original function and shortcode. You’ll need to find the name of the shortcode in the original functions.php file which I’ll explain later.
The default behavior of a child theme’s function.php file is to load BEFORE the parent theme’s function.php file. This is bad because if it was even allowed, the parent function would override the child function. But since two functions with the same name cannot be declared, you would get an error anyway. So the code above performs two important actions. It tells WordPress to wait until AFTER the parent functions.php file has been loaded to load our function. And then the function that gets loaded is removing the original shortcode and replacing with our new version.
As a side note, Elegant Themes has added code to the functions.php file for many functions to make our jobs easier. If you look in this file and see a function that begins with this: if ( ! function_exists( you are in luck. This more or less tells WordPress that if the function already exists in the child functions.php file, ignore the parent. You can simply copy the function into your child theme, make the changes you want, and it will automatically overwrite the parent. It doesn’t help us in this situation, but a good thing to know for other situations.
Back to replacing the modules. You can use everything you learned from the tutorial above and apply it to any Page Builder module. Using a text editor, search (CTRL + F) for the shortcode that matches the module you want to change. The shortcode will be the ‘et_pb_’ followed by the module name: et_pb_blog, et_pb_number_counter, et_pb_cta (call to action), etc. Once you find the location in the functions.php file, copy the function code and apply the same techniques as above to overwrite it. Here is one more example that would replace the Divider module:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
function override_parent() { remove_shortcode( 'et_pb_divider', 'et_pb_divider' ); add_shortcode( 'et_pb_divider', 'et_pb_divider_custom' ); } add_action('after_setup_theme','override_parent'); function et_pb_divider_custom( $atts, $content = null ) { extract( shortcode_atts( array( 'module_id' => '', 'module_class' => '', 'color' => '', 'show_divider' => 'off', 'height' => '', ), $atts ) ); $style = ''; if ( '' !== $color && 'on' === $show_divider ) $style .= sprintf( 'border-color: %s;', esc_attr( $color ) ); if ( '' !== $height ) $style .= sprintf( 'height:%spx;', esc_attr( $height ) ); $style = '' !== $style ? " style='{$style}'" : ''; $output = sprintf( '<hr%3$s class="et_pb_space%1$s%4$s"%2$s />', ( 'on' === $show_divider ? ' et_pb_divider' : '' ), $style, ( '' !== $module_id ? sprintf( ' id="%1$s"', esc_attr( $module_id ) ) : '' ), ( '' !== $module_class ? sprintf( ' %1$s', esc_attr( $module_class ) ) : '' ) ); return $output; } |
A final but important note is in the situation in which you would want to replace more than one function. To do this, you would want to remove the old shortcode and add the new one in the first function override_parent(). So in the examples above, if you wanted to replace both the blog and divider modules, the override_parent() function would look like this:
1 2 3 4 5 6 7 |
function override_parent() { remove_shortcode( 'et_pb_blog', 'et_pb_blog' ); remove_shortcode( 'et_pb_divider', 'et_pb_divider' ); add_shortcode( 'et_pb_blog', 'et_pb_blog_custom' ); add_shortcode( 'et_pb_divider', 'et_pb_divider_custom' ); } add_action('after_setup_theme','override_parent'); |
You would then follow up with the new custom functions just like we did in each example, making sure each function is wrapped in { } tags. Also remember your child functions.php file MUST begin with <?php and end with ?>.
71 Comments
The second function in the example must hace a different name.
Wrong: function override_parent()
Correct: function execute_override_parent()
to prevent redeclare function error.
Great article.
May 12, 2015
Hi Jaime,
Sorry for the confusion. If you create the functions separately, then yes they need to have unique names. In my example, I combined the removal and adding of two shortcodes into one function so if you follow the tutorial, you would not need a second function.
May 12, 2015
I’ve been messing with this for hours and I’m just worn out… Creating the Divi-child was quite simple. But, I don’t know PHP and I haven’t been able to grasp what the necessary coding changes are, in the functions.php file, in order to modify the Viewport Meta function.
May 15, 2015
Hey Mitch. Maybe someone can give a better answer but you can try this solution:
http://www.eleganttweaks.com/divi/add-ability-zoom-mobile-devices-tablets/
I’m sure there’s a way to do this in a child theme but unfortunately I don’t know how 🙁 You could always put it in your child function.php file and comment it out for reference. /* comments go inside these tags */
May 19, 2015
Brad,
Yes it would be super simple to modify the code in the Divi functions.php file. But, every time that the Divi theme is updated the modification would be overwritten.
I wonder why the viewport default is such that it does not allow you to zoom-in using a handheld device. Wouldn’t it make more sense to allow people to zoom-in by default? And, those who don’t want to allow visitors to zoom-in can make an adjustment in the functions.php file… I’m scratching my head as to who wouldn’t want to let visitors zoom-in.
May 19, 2015
Great article! Could you kindly explain how to make all blog pages masonry by default using the functions page?
Cheers
May 22, 2015
Have you thought about just saving the page template and using that template on other pages? When you load a template on a new page, you can uncheck the “Replace layout….” and it would just append the sections from the saved template to the current layout in the new page.
May 26, 2015
Hi Brad,
Great article!
Does this also work with Divi 2.4.x?
July 30, 2015
Thanks Andras. It does NOT work with Divi 2.4.x. They completely changed the backend in the new version. Hoping to get this updated and possibly release a plugin instead of editing the child function.
August 6, 2015
Any more news on an updated version or the plugin you mentioned? Being able to create your own custom Divi modules would be an amazing plugin that I have been looking for a long time.
September 18, 2015
Hi Andy. I agree. That is a much needed plugin. I am trying to put the finishing touches on a plugin that lets you use posts with the portfolio module layouts. http://www.diviplugins.com/plugins/portfolio-layout-posts/ Once that is completed, I might look into this. Thanks
September 21, 2015
Hi,
I want to work this folder includes/builder/main-modules.php on my child theme, i already copied the folder files on my child theme but still doesn`t overide when i tried to test customization the blog module.
November 6, 2015
Hi Richard. It doesn’t work like that unfortunately. I’ve updated this tutorial to work with Divi 2.4+
November 6, 2015
Hi Brad,
So the customization will still work on parent?
Do you have any alternative way just to make it work on child?
Thanks,
Richard
November 7, 2015
Yes, the customization will override the default module in Divi. It is possible to have both the default module and a custom module but it’s well beyond a simple tutorial.
November 13, 2015
Hi,
This would really be great if this is updated to the latest DIVI theme. I wanted to customize the blog module but I couldn’t do it in the child so all the customization disappears after the parent theme update.
Cheers
November 6, 2015
I agree Jessica. This was long overdue. Updated 🙂
November 6, 2015
Where? for about 2.5?
November 11, 2015
The instructions for 2.4+ apply to all versions of Divi 2.4 and up – including 2.5
November 13, 2015
Is it also possible to ADD a custom module? I have 2 categories of post types: news and calendar. On agenda post items I added a customfield ‘calendar_date’.
In the blogmodule I would like to display the ‘calendar_date’ field for calendar items but not for the news items. So my idea is to add a second blog module that also displays the calendar_date
November 24, 2015
Hi Luc. Adding a custom module is a lengthy and complex endeavor. You could just wrap the calendar_date output in an if is_page statement assuming the two are on different pages: https://codex.wordpress.org/Function_Reference/is_page
If not, you could wrap the calendar_date field in a span with a class like calendar-date. Then give the news item an ID like #news-items . Then in CSS:
#news-items span.calendar-date {display: none;}
December 9, 2015
Hey, when I try to modify the blog post module, so I can have share icons in the blog grid, my css breaks, leaving all of my images really big, and the WordPress admin bar disappears (left as a white space). I’m running Divi 2.4.4
December 29, 2015
Hi Matthew,
I faced the same issue. The problem was that I was removing the default code present in the functions.php file which was responsible for enqueuing the parent’s style. Adding back that code made the styles work again
April 2, 2016
Hi!
I used the tutorial to customize the blog module with success! However, I would customize an other module (portfolio) in the same functions.php. how to have 2 customs modules?
Thanks a lot
January 4, 2016
Maybe you could help me. I am trying to modify the blog module as well, but after following the above instructions, all of my styles break.
February 17, 2016
Hi, I’m having the same issue right now. I thought just duplicating the process would work, but something is throwing a Fatal error before this line is used a second time:
add_action('wp', 'divi_child_theme_setup', 9999);
There’s some fundamental PHP logic I’m missing. Perhaps someone else can share? Pretty please? :DAY
March 11, 2016
I figured out my issue. It was a matter of nesting the modules one after another and duplicating the remove/add shortcode lines at the end, all within the divi_child_theme_setup function.
March 13, 2016
Would it be possible to modify the blog module so that it support other post types, for for example CPTs articles, white_paper, news_item and press_release. These where all CPTs created in Pods.
Thanks in advance.
January 10, 2016
The changes for Divi 2.4+ aren’t working for me. I have tried to change name of Signup module and no change is taking place.
January 16, 2016
I
ve try to use the code for 2.4 and up to make the Fullwidth Portfolio module with custom urls but i couldn
t do it. Is there any way to help me with it. I use 2.5.3 and I want to use the Fullwidth Portfolio module (carousel_mode) with custom links.Thank you!
January 26, 2016
realiza un VIDEO TUTORIAL NO ME FUNCIONA
January 31, 2016
Thanks for this, with a couple of changes it allowed me to output the excerpt for each portfolio item. Great tweak!
February 9, 2016
Brad, what are you doin’ to me man? I thought we were friends!
February 11, 2016
🙂 Of course we’re still friends!
March 15, 2016
I need to change the text of the post listing order i.e. “Popular”, “Latest,””Most rated” to equivalent Danish terms.
I would love it if you could point me in the right directions as to where this is done?
February 16, 2016
For anyone having issues with this tweak. I have just tested it with Divi 2.6.4.4 and it still works. Copy the first example exactly above and make a minor change. Put “TEST” inside of the h2 tag on line 314 of the first example and you’ll see “TEST” output in your layout.
You have to be very careful and follow the directions exactly. For anyone having major issues, disable any caching or minifying plugins and try again. Those seem to be the biggest culprit of causing conflicts with Divi customizations.
March 15, 2016
Hi and thanks for the tutorilal!
I succesfully modified the member and blog module with your instructions and saved my changes in a custom plugin..
But after updating Divi to 2.6 only my changes to the blog module are still there.
The member module is reverted back to the standard input fields. If i change something in my shortcode_callback i see the changes in the frontend, but the fields in the backend show no modification. Even if i modify the fields or labels in the original main-modules.php, i don’t see any changes. It’s like wordpress/divi doesn’t recognize these changes at all.
I disabled my caching plugin (w3 total), but it didn’t made any difference.
Is there a special cache for these modules? What could i do?
Thanks
Torsten
March 29, 2016
Ok, seems like i found the culprit.
The field settings are stored locally in local storage. I deleted them and got my modifications back.
March 30, 2016
Thanks Torsten. Yes, Divi is now caching modules in your local storage to speed up load times so you’ll need to delete your local storage or clear your browser’s cache to see the changes
May 19, 2016
Fatal error: Class ‘ET_Builder_Module’ not found in my child theme.
I am trying to customize portfolio module using divi child theme but faced class not found error. Below is my code
———————-Custom_ET_Builder_Module_Filterable_Portfolio.php——————–
class Custom_ET_Builder_Module_Filterable_Portfolio extends ET_Builder_Module {
function init() {
$this->name = __( ‘Filterable Portfolio custom’, ‘et_builder’ );
$this->slug = ‘et_pb_filterable_portfolio’;
}
}
————————–Function.php———————–
function divi_child_theme_setup() {
get_template_part( ‘custom-modules/Custom_ET_Builder_Module_Filterable_Portfolio’ );
$custom_filtrabl = new Custom_ET_Builder_Module_Filterable_Portfolio();
remove_shortcode( ‘et_pb_filterable_portfolio’ );
add_shortcode( ‘et_pb_filterable_portfolio’, array($custom_filtrabl, ‘_shortcode_callback’) );
}
Please help my if you have any solution
add_action(‘wp’, ‘divi_child_theme_setup’, 9999);
March 30, 2016
Looks like you forgot the first part of the code. The function itself and then the check if the class exists:
if ( class_exists(‘ET_Builder_Module’)) {
May 19, 2016
How do I add a custom field to an existing Divi module? Meaning, how do I add another row in the module setting in the page builder for let’s say another text field that I can later display on the front end?
July 19, 2016
Hi,
I’m having issues with this. I’m trying to modify blog modules and fix the sorting of blog.
I followed your instructions for Divi 2.4 and up…
However, the output only shows the shortcode of the blog module.
I tried to remove this code: add_action(‘wp’, ‘divi_child_theme_setup’, 9999);
The shortcode was gone and the blogs were showing. However, my changes did not refect.
Please help. Thanks
September 15, 2016
Hi,
I can’t make it work I don’t know if I did it wrong or does this still working on the latest Divi Update?
Regards,
October 11, 2016
Hi Brad,
Can you update this to Divi 3.12?
October 19, 2016
Does this work with the Newest Divi?
January 25, 2017
I’ve tried a few suggestions for doing this but yours is the only approach that seems to work in the latest version of Divi. I have this working fine in Divi 3.0.39.
Thank you!
April 3, 2017
Hello
July 29, 2017
Updated to latest version of Divi
August 17, 2017
In modules.php there is a class “class ET_Builder_Module_Posts extends ET_Builder_Module {}” . In this class there is function named “category_field_renderer( $field )” .
in this function there is a call to get_Category function like this: $cats_array = get_categories( ‘ ‘hide_empty’ => 0′);. i want to change this with this code : $argus = array(
‘hide_empty’ => 0,
‘taxonomy’ => array(‘category’, ‘resort_category’)
);
$cats_array = get_categories( $argus);
Baically i need to add taxonomy in that. Its working good in parent theme. But I need to change this by child theme. How I cant access this class
October 18, 2017
hey, when i used the code-snippet of you in functions.php – it happen to a white page. Whats wrong?
I use Divi 3.0.9anything..
November 14, 2017
hii,
how to override blog.php file in divi theme, i create divi-child theme and add a folder include/builder/module/ blog.php is going to overwrite but the changes are not show …….?????
November 27, 2017
I tried rewrite fullWidthPortfolio and after copied class – i has an error – Project not found.
But portfolio is in admin panel)
Debuging show that not working $this->shortcode_atts replace with extract($atts); – all work fine! Please fix it for the next time.
January 29, 2018
Hi Brad,
Great work. I would like to change the category behavior of the divi blog module (and other posts / extra divi modules). Have looking for a while without result, maybe you can help. When you select more than one category into the module, the post / page will display the posts from each categories. I would like this selection to be conditional, I mean if I select category A and B, only the posts belonging to these 2 categories should be displayed. May be possible with ‘operator’ => ‘AND’ but I don’t know where to custom this.
Thank you for your time.
February 19, 2018
Thanks for this. Little documentation is available online for free.
For your readers and yourself, please note this is the wrong hook that is called in the functions.php for newer version of DIVi and Extra theme users. Since it was not working for me, I have checked online and instead of “wp” hook,
use this one >>>> add_action(‘et_builder_ready’, ‘FUNCTIONTOCAL’, 9999); then the rest is magic! 🙂
April 7, 2018
thank you my friend, I searched a lot and your hook is the only working! unfortunately visual builder is not working with this.. is this the same for you? many thanks
October 26, 2018
Thanks for the article, it’s useful.
May 9, 2018
This is exactly what I’ve been looking for! However, I’m having trouble with it breaking my site. I’ve tried following what Maxime posted above here in the comments, and although I no longer get an “Internal Error 500” or whatever, the changes I’ve done to my module won’t appear. Would love an update to fix this!
June 24, 2018
Hello
This article very useful. Thank you
I used Extra and I modify blog module accordingly you manual
All works – but now I have some kind nested module
like this
etc…..
Maybe you have idea why this happened ?
July 7, 2018
Please update article for latest core edits …. exm. includes/builder/modules/moduLe extends ET_Builder_Module_Type_PostBased etc …
November 14, 2018
Please update for latest core edits. 3.0 and upwards doesn’t work anymore
January 9, 2019
This is just great! Works fine. Thank you!
July 23, 2019
Hi, thanks for this post. Please provide an update to do this with the latest Divi 4.1.
Thank you.
December 15, 2019
how to integrate in divi theme?
September 9, 2020
With respect !!!
December 20, 2020
Hi, this was working well until the latest Divi update (Version: 4.10.4)
Now it is broken.
Any chance of an update for the latest version?
Thanks.
August 24, 2021
Same problem here, have you solve it?
Thank you in advance.
August 27, 2021
This no longer works for 4.10.>
August 26, 2021
Same problem here, have you solve it?
=[
August 31, 2021
Hello! Thank you for this, I used this post a few years ago to customize the rendering of the blog module, but it’s no longer working and I’ve messed with it for hours now and it’s all loading but isn’t allowing the shortcode to be replaced. Any assistance would be greatly appreciated.
September 7, 2021
Hi,
Same here : this no longer works for Divi > 4.10.
Any help appreciated.
October 14, 2021