Creating A Custom Divi Module or Extension Plugin in WordPress

Creating A Custom Divi Module or Extension Plugin in WordPress

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('https://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('https://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('https://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!!!

Norman Pleitez

Technical Co-Founder at Cloz?Me | Senior Front-End Developer at Trane Technologies | UI/UX Expert

2 年

It would've been nice to see it working live

回复
Chinemerem Orunta

Information Technology Support Specialist

2 年

Lovely.

要查看或添加评论,请登录

Chigozie Orunta的更多文章

  • Common Mistakes WP Engineers Make

    Common Mistakes WP Engineers Make

    WordPress is famous for being one of the most popular content management systems (CMS) worldwide, powering millions of…

  • Applying SOLID Principles to WordPress Development

    Applying SOLID Principles to WordPress Development

    SOLID Principles in modern software development refers to the design approach intended in making software code more…

    2 条评论
  • Speed Up Your WordPress Website

    Speed Up Your WordPress Website

    As a website owner, you probably already know how important it is for your site to load fast and efficiently so that…

    1 条评论
  • Building A Custom Gutenberg Block In WordPress

    Building A Custom Gutenberg Block In WordPress

    Gutenberg Blocks in WordPress have been around for a while, ever since the builder was released on the WordPress…

  • Working With WordPress Hooks, How To Create & Use Them.

    Working With WordPress Hooks, How To Create & Use Them.

    WordPress Hooks are one of the most powerful features in theme and plugin development. They enable WP developers to add…

  • Setting Up A PHP CodeSniffer For WordPress using Composer

    Setting Up A PHP CodeSniffer For WordPress using Composer

    A PHP CodeSniffer is a program that helps developers keep code clean and uniform or in sync across teams. In PHP, you…

    2 条评论
  • Most Useful WordPress Plugins in 2022

    Most Useful WordPress Plugins in 2022

    Plugins are an invaluable tool for today’s WordPress websites. There are extremely few websites that exist today that…

    1 条评论
  • Safeguarding Your WordPress Site

    Safeguarding Your WordPress Site

    WordPress accounts for almost 30% of all websites on the Internet and is one of the most popular CMS (Content…

  • 4 Ways To Style Your React Components

    4 Ways To Style Your React Components

    So you’ve built your first React Component but don’t know how to style it. Well, here are 4 quick ways to style your…

    1 条评论

社区洞察

其他会员也浏览了