Coding Builder Modules

This tutorial will show you how to code your own custom addons/modules for Themify Builder.

Let's Get Started

Each module in the Builder consists of three files, a module-*.php file (only registers the module to Builder), and a template-*.php file (handles the display of the module), and a JavaScript file that does most everything else: controls the options displayed when editing the module, how data is saved for the module, renders the live preview, etc. For the default modules in Builder, the module PHP files are located in themify-builder/modules directory inside the Builder, the template files can be found in the themify-builder/templates and the JS files can be found in themify-builder/js/editor/modules folder.

We can add new modules via a plugin, or include them in the theme.

Example 1: Hello World module

Let's start by creating a simple module that displays a Hello World message. First under wp-content/plugins/ directory of your WordPress installation create a new folder (you can name this folder anything that you would like). This folder will hold all of the files required for the module. Inside that folder create a file named "init.php" and paste this inside:


<?php
/*
Plugin Name:  Hello World
Version:      2.0
Author:       Themify
Description:  Sample Builder module to greet the world!
*/

defined( 'ABSPATH' ) or die;

This is all that is needed for WordPress to identify the plugin, now if you head over to the Plugins manager in admin dashboard, you can activate it.

Now let's add the codes to load our module PHP file:


function hello_world_register_module() {
    Themify_Builder_Model::add_module( plugin_dir_path( __FILE__ ) . 'modules/module-hello-world.php' );
}
add_action( 'themify_builder_setup_modules', 'hello_world_register_module' );

This tells the Builder that when needed, load the modules/module-helloworld.php file inside the plugin. So let's create "module-hello-world.php" file inside the modules folder:

<?php

class TB_HelloWorld_Module extends Themify_Builder_Component_Module {

    public static function get_module_name():string{
        add_filter( 'themify_builder_active_vars', [ __CLASS__, 'builder_active_enqueue' ] );
        return __( 'Hello World', 'hello-world' );
    }
    public static function builder_active_enqueue( array $vars ):array {
        $url = plugin_dir_url( dirname( __FILE__ ) ) . 'assets/active.js';
        $version = '1.0';
        $vars['addons'][ $url ] = $version;

        return $vars;
    }
}

Note the "TB_" prefix and "_Module" suffix for our module's classname. This is the naming convention that you must follow in order for Builder to recognize the module. The "get_module_name" method returns the name of the module (this shows up in the editor interface), but also adds a filter to load an script file named "active.js" when Builder is active. As mentioned, this JavaScript file is where the module is actually defined. So next step, let's create that file:


((api,createElement,themifyBuilder ) => {
    'use strict';
    api.ModuleHelloWorld = class extends api.Module {

        constructor(fields) {
            super(fields);
        }

        static getOptions() {
            return [];
        }

        static default(){
            return {};
        }

        static builderSave(settings){
            super.builderSave(settings);
        }
    };
})(tb_app,tb_createElement,themifyBuilder);

The script creates a class named "ModuleHelloWorld" that extends "tb_app.Module". Note the "Module" prefix for the module name, this is required. The getOptions() method returns an array of options to show when you're editing the module, the "default()" method return an object of option_name : option_value pairs that define the default values those options will have, and the builderSave() method which is called when the module is saved, this can be useful if you want to validate or cleanup the module data before saving.

Now our module is ready. You can open the Builder editor and add this to your page:

module-title-option

So what does the module display on the front end? At the moment, nothing. We haven't add the template file for the module that will actually render it, to do that create "template-hello-world.php" file inside the /templates folder and paste this in:

	<h1> Hello World! </h1>

Viola! Now if add the module to a page and view that page on front end, you can see the output:

hello-world

Showing the same HTML snippet each time we add the module might be what we need, however often you want to add options to the module that dynamically changes it's output, so let's change the getOptions method to show an option where we can change who we want to say hello to:


static getOptions() {
    return [
        {
            id : 'say_hello',
            type : 'text',
            label : 'Hello Text'
        }
    ];
}

In the module's template file the options are accessible using the $args['mod_settings'] array, every key of this array is an option saved for the module, so now change the template file:


<?php
$say_hello = isset( $args['mod_settings']['say_hello'] ) ? $args['mod_settings']['say_hello'] : '';
?>
<div class="module module-<?php echo $args['mod_name']; ?>">
    <h1> Hello <?php echo $say_hello; ?>! </h1>
</div>

Congratulations, you just made your first Builder module. You can download the complete code here.

Example 2: Quotes module

Now let's dig deeper and create a more practical module. Let's say our client runs a heavy-content website and regularly posts quotes, so to pimp up the pages let's design a quote style module that our client can use:

Custom Quotes module sample

The quote style consists of an image, the quote text itself and the name of it's author. The only problem is this requires a specific bit of HTML to make. Handing a txt file to the client to copy and paste, then change the bits and pieces is not very practical. An option is to create a shortcode that outputs the quote, however shortcodes are not user friendly either. Your client will have to remember the exact shortcode and parameters used to replicate the same output.

First step like our Hello World module, create a directory inside the wp-content/plugins/ folder, add an init.php file inside it and paste this in:

<?php
/*
Plugin Name:  Custom Quotes
Plugin URI:   https://themify.me/
Version:      2.0
Author:       Themify
Description:  Custom Quotes
*/

defined( 'ABSPATH' ) or die( '-1' );

function custom_quotes_register_module() {
	Themify_Builder_Model::add_module( plugin_dir_path( __FILE__ ) . 'modules/module-quotes.php' );
}
add_action( 'themify_builder_setup_modules', 'custom_quotes_register_module' );

Same as before, we just point Builder to the file where the module PHP is registered. Now activate the plugin in the Plugins manager.

Next create "module-quotes.php" file inside the the /modules folder and paste this in:

<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class TB_Quotes_Module extends Themify_Builder_Component_Module {

    public static function get_module_name():string {
        add_filter( 'themify_builder_active_vars', [ __CLASS__, 'builder_active_enqueue' ] );
        return __( 'Quote', 'custom-quotes' );
    }

    public static function get_module_icon():string {
        return 'quote-right';
    }

    public static function get_js_css():array {
        return array(
            'css' => plugin_dir_url( dirname( __FILE__ ) ) . 'assets/style.css'
        );
    }

    public static function builder_active_enqueue( array $vars ):array {
        $url = plugin_dir_url( dirname( __FILE__ ) ) . 'assets/active.js';
        $version = '1.0';
        $vars['addons'][ $url ] = $version;

        return $vars;
    }
}

The get_js_css() method n module returns an array which defines what files to load when the module is used on the page. In our case, we only need an stylesheet for customizing the design of the quote, so the method returns the path to an style.css file. Also the get_module_icon() is used to display an icon (from Themify icon set) for this module.
Next, create a folder named "assets" inside the plugin and add the "active.js" file in it:


((api,createElement,themifyBuilder ) => {
    'use strict';
    api.ModuleQuotes = class extends api.Module {

        constructor(fields) {
            super(fields);
        }

        static getOptions() {
            return [
                {
                    id : 'quote_text',
                    type : 'textarea',
                    label : 'Text'
                },
                {
                    id : 'quote_image',
                    type : 'image',
                    label : 'Image'
                },
                {
                    id : 'quote_author',
                    type : 'text',
                    label : 'Quote Author'
                },
                {
                    id : 'quote_link',
                    type : 'url',
                    label : 'Link'
                },
                {
                    type : 'custom_css_id'
                }
            ];
        }

        static default() {
            return {};
        }

        static builderSave(settings){
            super.builderSave(settings);
        }
    };
})(tb_app,tb_createElement,themifyBuilder);

Here we add four options in the module, three text options to put the quote text, the name of its author, and the link to the quote author's website, and an option to put the image. Now when you add the module you can see the options:

Perfect! Now for the module's template, create "template-quotes.php" in the /templates folder and add:

<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
 * Template Quotes
 * 
 * Access original fields: $args['mod_settings']
 */

$fields_default = array(
	'quote_text' => '',
	'quote_image' => '',
	'quote_author' => '',
	'quote_link' => '',
	'animation_effect' => ''
);

$fields_args = wp_parse_args( $args['mod_settings'], $fields_default );
unset( $args['mod_settings'] );

$container_class = apply_filters( 'themify_builder_module_classes', array(
		'module', 'module-' . $args['mod_name'], $args['module_ID'], self::parse_animation_effect( $fields_args['animation_effect'] )
	), $args['mod_name'], $args['module_ID'], $fields_args );
if ( ! empty( $args['element_id'] ) ) {
	$container_class[] = 'tb_' . $args['element_id'];
}
if ( ! empty( $fields_args['global_styles'] ) && Themify_Builder::$frontedit_active === false ) {
	$container_class[] = $fields_args['global_styles'];
}
$container_props = apply_filters( 'themify_builder_module_container_props', array(
	'id' => $args['module_ID'],
	'class' => implode(' ', $container_class),
), $fields_args, $args['mod_name'], $args['module_ID'] );
?>

<div <?php echo self::get_element_attributes( $container_props, $fields_args ); ?>>
	<?php $container_props=$container_class=null;?>
	<?php do_action( 'themify_builder_before_template_content_render' ); ?>
	<div class="quote-wrap">

		<?php if( '' !== $fields_args['quote_image'] ) : ?>
			<img class="quote-image" src="<?php echo esc_url( $fields_args['quote_image'] ); ?>" alt="<?php echo $fields_args['quote_author']; ?>" />
		<?php endif; ?>

		<div class="quote-content">

			<div class="quote-text">
				<span><?php echo $fields_args['quote_text']; ?></span>
			</div>

			<div class="quote-author">
				<?php if ( '' ===$fields_args['quote_link']  ) : ?>
					<span><?php echo $fields_args['quote_author']; ?></span>
				<?php else : ?>
					<a href="<?php echo $fields_args['quote_link']; ?>"><span><?php echo $fields_args['quote_author']; ?></span></a>
				<?php endif; ?>
			</div>

		</div>

	</div>

	<?php do_action( 'themify_builder_after_template_content_render' ); ?>
</div><!-- .module-<?php echo $args['mod_name']; ?> -->

The snippet is pretty straight forward, we just check if some options in the module are set and if so output the proper markup.

NOTE: To set the default options for the module we use wp_parse_args function and pass it two things: $args['mod_settings'] array that holds the saved settings of the module, and an array of defaults, this way we'll have a default value. Also the extract function is used to turn each of the options into a separate variable, this makes working with them easier.
The rest of the code is just spitting out the proper markup we need to show the quote.

Last step is to add the CSS codes that style the quote, if you recall in TB_Quotes_Module class we used the get_js_css() to set a path for an stylesheet, so in the "assets" folder create a file named "style.css" add the CSS codes. You can get that from the this link.
You can download the finished plugin here which includes an alternative layout for quotes, and also sets up the Styling options for the module.

Field Types

The Builder has a variety of field types you can use to create the options for the modules, the table below lists some of available field types:

Type Description * Repeatable?
text General text box to input texts. You can set the "colorpicker" parameter to true to turn the text box into a color picker field. Yes
icon Icon picker, user can choose from the icons included in the Builder. For an example of this check the Feature module. Yes
image Image uploader, user can upload images or select one from the Media Library. Yes
textarea Multi-line text input. Yes
wp_editor Shows the TinyMCE editor to input formatted texts. Yes
radio Multiple choice option where only one can be chosen. Yes
checkbox Multiple choice option where none or any number of the choices can be chosen. Yes
builder "builder" field can be used to create repeatable rows of data (for example Accordion and Tabs modules use this feature), field types that in this table are highlighted as Repeatble can be used in the "builder" field type.

* whether the field type is repeatable and can be used in "builder" fields.

Override module templates in themes

The built-in Builder modules are also customizable, where you can change the look using the options provided by the module. However sometimes you need to change how the modules structure its output, and in such cases overriding the template files of the modules comes very handy. To achieve this first navigate to <theme_root>/themify/themify-builder/templates/ directory, here you can find the template files used by various modules. Now copy the template file for the module you want to change and paste it in <child_theme_root>/themify-builder/ directory and customize it.

Themify 7.5 has released! Please read the update notes.