Creating A Custom Divi Gallery Module plugin in WordPress

Chigozie Orunta
7 min readMar 29, 2022

Divi is one of the most powerful WordPress page builders out there in the market. Its ease of use and WYSIWYG nature makes it a desirable tool of choice for building WordPress websites fairly quickly.

Interestingly, the creators of Divi have gone a step ahead to provide an elegant API that enables developers to create custom modules of their choice so you can easily drag and drop your favourite creations into your website.

In this article, we’ll be looking at how to create a custom Gallery module using a mixture of PHP, React and the WordPress API. For starters, you can go ahead and create a fresh installation of WordPress and then make sure you have the Divi theme installed into your WordPress site. You will also need to create a custom post type called Gallery in your newly created WP site, you can do this using a popular plugin called CPT UI.

Just to be clear, there are 2 parts to this: the PHP and React side of things. The PHP side takes care of what you and your users see when looking at your WP site from the front end. While the React side takes care of what you and your users see when building your website on the backend using the Divi Builder module.

PHP Part

Step 1 — Create A Custom Divi Module plugin

Using your terminal, go to your WordPress plugin folder and run the following command to create a custom Divi module or extension:

npx create-divi-extension custom-divi-extensions

Step 2 — Define Your Custom Divi Module Class

Look into your newly created repo and locate the includes/modules folder. Now create a new directory or folder and call it MyGallery. All Divi modules are defined using a PHP class and ours isn’t going to be any different. So, in your new folder create a MyGallery.php file and type in the following code:

<?php	class MyGallery extends ET_Builder_Module {		public $slug       = 'my_gallery';
public $vb_support = 'on';

public function init() {
$this->name = esc_html__( 'My Gallery', 'my-gallery' );
}

public function get_fields() {
return array(
'heading' => array(
'label' => esc_html__( 'Heading', 'my-gallery' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery heading here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
'content' => array(
'label' => esc_html__( 'Content', 'my-gallery' ),
'type' => 'tiny_mce',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery footnote here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
);
}
public function render( $unprocessed_props, $content, $render_slug ) {
return sprintf(
'<h1 class="my-gallery-heading">%1$s</h1>
<div class="my-gallery-footnote">%2$s</div>',
esc_html( $this->props['heading'] ),
$this->props['content']
);
}
}

new MyGallery;

In the above code, we’ve set up a heading and footnote to display when the Gallery module is in use. Our Gallery class basically extends the parent Divi Module class called ET_Builder_Module and the public methods defined, do the following:

  • The init method sets up the name of our custom module.
  • The get_fields method defines the fields where users can type in a heading and footnote for our custom Gallery module.
  • The render method basically outputs the heading and footnote to the screen for users to see.

Step 3 — Retrieve Gallery Posts in Gallery CPT

Now let’s define another method to retrieve the posts within the Gallery CPT like so:

public function get_photos() {

$query = new WP_Query( array( 'post_type' => 'gallery' ) );
$posts = $query->posts;
foreach($posts as $post) { if ( has_post_thumbnail( $post->ID ) ) { $image = wp_get_attachment_image_src(
get_post_thumbnail_id( $post->ID ),
'medium'
);
$photo_image = $image[0];
$photo_title = get_the_title( $post->ID );
$photos .= sprintf(
'<div><img src="%1$s"><p>%2$s</p></div>',
$photo_image,
$photo_title

);
}

}
return $photos;}

Now we can go ahead and call the get_photos method within our render method and retrieve the photos like so:

<?php

class MyGallery extends ET_Builder_Module {
public $slug = 'my_gallery';
public $vb_support = 'on';

public function init() {
$this->name = esc_html__( 'My Gallery', 'my-gallery' );
}
public function get_fields() {
return array(
'heading' => array(
'label' => esc_html__( 'Heading', 'my-gallery' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery heading here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
'content' => array(
'label' => esc_html__( 'Content', 'my-gallery' ),
'type' => 'tiny_mce',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery footnote here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
);
}
public function get_photos() {
$query = new WP_Query( array( 'post_type' => 'gallery' ) );
$posts = $query->posts;
foreach($posts as $post) { if ( has_post_thumbnail( $post->ID ) ) {
$image = wp_get_attachment_image_src(
get_post_thumbnail_id( $post->ID ),
'medium'
);
$photo_image = $image[0];
$photo_title = get_the_title( $post->ID );
$photos .= sprintf(
'<div><img src="%1$s"><p>%2$s</p></div>',
$photo_image,
$photo_title

);
} } return $photos;
}
public function render( $unprocessed_props, $content, $render_slug ) {
return sprintf(
'<h1 class="my-gallery-heading">%1$s</h1>
<div class="my-gallery-footnote">%2$s</div>
<div class="my-gallery">%3$s</div>',
esc_html( $this->props['heading'] ),
$this->props['content'],
$this->get_photos()
);
}
}

new MyGallery;

Step 4 — Create and Enqueue CSS file for Gallery styling

Create a new CSS file called gallery.css in your MyGallery directory and define the styling with some CSS rules like so:

.my-gallery-heading
.my-gallery-footnote {
text-align: center;
}
.my-gallery {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
margin-top: 3em;
}
.my-gallery div {
width: 22.5%;
box-sizing: border-box;
margin-bottom: 25px;
}
.my-gallery div > img {
margin: 0 auto;
max-width: 100%;
height: auto;
}
.my-gallery div > p {
margin-top: 0.5em;
text-align: center;
}

Next, we enqueue the CSS file into our WP site using the init method like so:

public function init() {
$this->name = esc_html__( 'My Gallery', 'my-gallery' );
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'my-gallery-css', './gallery.css' );
});
}

Your class should now look like this:

<?php    class MyGallery extends ET_Builder_Module {

public $slug = 'my_gallery';
public $vb_support = 'on';
public function init() {
$this->name = esc_html__( 'My Gallery', 'my-gallery' );
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'my-gallery-css', './gallery.css' );
});
}
public function get_fields() {
return array(
'heading' => array(
'label' => esc_html__( 'Heading', 'my-gallery' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery heading here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
'content' => array(
'label' => esc_html__( 'Content', 'my-gallery' ),
'type' => 'tiny_mce',
'option_category' => 'basic_option',
'description' => esc_html__( 'Gallery footnote here.', 'my-gallery' ),
'toggle_slug' => 'main_content',
),
);
}
public function get_photos() {
$query = new WP_Query( array( 'post_type' => 'gallery' ) );
$posts = $query->posts;
foreach($posts as $post) { if ( has_post_thumbnail( $post->ID ) ) {
$image = wp_get_attachment_image_src(
get_post_thumbnail_id( $post->ID ),
'medium'
);
$photo_image = $image[0];
$photo_title = get_the_title( $post->ID );
$photos .= sprintf(
'<div><img src="%1$s"><p>%2$s</p></div>',
$photo_image,
$photo_title

);
} } return $photos;
}
public function render( $unprocessed_props, $content, $render_slug ) {
return sprintf(
'<h1 class="my-gallery-heading">%1$s</h1>
<div class="my-gallery-footnote">%2$s</div>
<div class="my-gallery">%3$s</div>',
esc_html( $this->props['heading'] ),
$this->props['content'],
$this->get_photos()
);
}
}
new MyGallery;

If you’ve made it this far, then you’re in luck, cos all that’s left is the React part!

React Part

As I stated earlier, this part takes care of what you see in your Divi Builder when you are building your website using your custom module.

Step 1 — Create A JavaScript File

Create a JavaScript file and call it MyGallery.jsx. This file will contain our JSX implementation for our custom module like so:

import React, { Component, Fragment } from 'react';

import './gallery.css';

class MyGallery extends Component {

static slug = 'my_gallery';
state = {
photos: []
}

render() {
return (
<Fragment>
<h1 className="my-gallery-heading">{this.props.heading}</h1>
<div className="my-gallery-footnote">{this.props.content()}</div>
</Fragment>
);
}
}

export default MyGallery;

In the above script, we simply declare a class component and use the render method to display the heading and footnote of our custom module.

Step 2 — Retrieve Gallery Posts from WordPress API

One of the many advantages of WordPress is that it is one of the most popular CMS that ships with its own API right out of the box. We can use this API to retrieve the photos from our Gallery custom post type within the componentDidMount method.

In React, the componentDidMount() is a life-cycle method that allows us to execute the React code when the component is already placed in the DOM (Document Object Model). This method is called during the Mounting phase of the React Life-cycle i.e after the component is rendered.

Here’s what it would look like:

componentDidMount() {    fetch('http://yoursite.com/wp-json/wp/v2/gallery')
.then((response) => response.json())
.then(allPhotos => {
this.setState({ photos: allPhotos });
})
.catch(error => console.log('Error:', error));
}

You can replace “yoursite.com” with your website’s URL address or localhost address if you’re working locally. Your component should now look this:

import React, { Component, Fragment } from 'react';

import './gallery.css';

class MyGallery extends Component {

static slug = 'my_gallery';
state = {
photos: []
}
componentDidMount() { fetch('http://yoursite.com/wp-json/wp/v2/gallery')
.then((response) => response.json())
.then(allPhotos => {
this.setState({ photos: allPhotos });
})
.catch(error => console.log('Error:', error));
}

render() {
return (
<Fragment>
<h1 className="my-gallery-heading">{this.props.heading}</h1>
<div className="my-gallery-footnote">{this.props.content()}</div>
</Fragment>
);
}
}

export default MyGallery;

Step 3 — Map Photos

Next, we loop through our photos to display them properly in our React component using the Map function like so:

import React, { Component, Fragment } from 'react';

import './gallery.css';

class MyGallery extends Component {

static slug = 'my_gallery';
state = {
photos: []
}
componentDidMount() { fetch('http://yoursite.com/wp-json/wp/v2/gallery')
.then((response) => response.json())
.then(allPhotos => {
this.setState({ photos: allPhotos });
})
.catch(error => console.log('Error:', error));
}

render() {
return (
<Fragment>
<h1 className="my-gallery-heading">{this.props.heading}</h1>
<div className="my-gallery-footnote">{this.props.content()}</div>
<div className="my-gallery">
{this.state.photos.map((photo) => (
<div>
<img src={photo.id} alt={photo.id} />
<p>{photo.title.rendered}</p>
</div>
))}
</div>
</Fragment>
);
}
}

export default MyGallery;

Finally, run the command: yarn start on your terminal to build your JSX component and start using your custom Gallery module.

yarn start

And that’s it!!!

--

--