Your first step to enable Dynamic Content is to add a new configuration option to your fields of choice:
'title' => array(
'label' => esc_html__( 'Title', 'simp-simple-extension' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Input your desired title here.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
// Enable dynamic content. The value should be 'text', 'image' or 'url'
// depending on what type of content you wish to have in your field.
'dynamic_content' => 'text',
),
Using dynamic content on the frontend requires a minor adjustment to the render()
method:
public function render( $unprocessed_props, $content = null, $render_slug ) {
$title = $this->_esc_attr( 'title' );
$content = $this->_esc_attr( 'content', 'full' );
return sprintf(
'<div>
<h2>%1$s</h2>
%2$s
</div>',
$title,
$content
);
}
In the above example you can see the usage of the new _esc_attr( $attribute, $html )
utility method which:
- Escapes html in static user input, unless
$html
is set to'full'
. - Resolves dynamic content, if the field contains any.
Fields which have dynamic content support declared will automatically become available in a special utility dynamic
prop in your React component:
render() {
const title = this.props.dynamic.title;
const content = this.props.dynamic.content;
return (
<div>
<h2>{title.render()}</h2>
<div>{content.render('full')}</div>
</div>
);
}
Each field in the dynamic
prop is an object with a couple of properties:
Property | Type | Description |
---|---|---|
value |
String |
The resolved value. If the user has not selected dynamic content, this will hold the value the user has entered manually. |
type |
String |
The type of dynamic content as specified in the field configuration. |
dynamic |
Boolean |
Shows whether the current value is dynamic or not. |
loading |
Boolean |
Shows whether the current value is still being resolved. |
hasValue |
Boolean |
Shows whether the value is loading or is not empty. |
render |
Function |
A utility function which handles rendering a loading state, dynamic content or static content. Renders an editable rich text field for tiny_mce fields when the value is not dynamic. |
Here we will demonstrate how you can build a simple blurb module with a title, a title link, an image and a content field.
The module's PHP class:
<?php
class SIMP_SimpleBlurb extends ET_Builder_Module {
public $slug = 'simp_simple_blurb';
public $vb_support = 'on';
protected $module_credits = array(
'module_uri' => '',
'author' => '',
'author_uri' => '',
);
public function init() {
$this->name = esc_html__( 'Simple Blurb', 'simp-simple-extension' );
}
public function get_fields() {
return array(
'title' => array(
'label' => esc_html__( 'Title', 'simp-simple-extension' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Input your desired title here.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
// We need text values so we specify 'text' as the dynamic content type.
'dynamic_content' => 'text',
),
'title_link' => array(
'label' => esc_html__( 'Title Link', 'simp-simple-extension' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Input your desired title link here.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
// We need URL values so we specify 'url' as the dynamic content type.
'dynamic_content' => 'url',
),
'image' => array(
'label' => esc_html__( 'Heading', 'simp-simple-extension' ),
'type' => 'upload',
'option_category' => 'basic_option',
'description' => esc_html__( 'Select your desired image here.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
// We need image URL values so we specify 'image' as the dynamic content type.
'dynamic_content' => 'image',
),
'content' => array(
'label' => esc_html__( 'Content', 'simp-simple-extension' ),
'type' => 'tiny_mce',
'option_category' => 'basic_option',
'description' => esc_html__( 'Content entered here will appear below the title text.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
// We need text values so we specify 'text' as the dynamic content type.
'dynamic_content' => 'text',
),
);
}
public function render( $attrs, $content = null, $render_slug ) {
$title = $this->_esc_attr( 'title' );
$title_link = $this->_esc_attr( 'title_link' );
$image = $this->_esc_attr( 'image' );
// We pass 'full' as the second argument so html is not escaped in the resulting value.
$content = $this->_esc_attr( 'content', 'full' );
if ( ! empty( $title ) ) {
if ( ! empty( $title_link ) ) {
$title = sprintf(
'<a href="%1$s">%2$s</a>',
esc_url( $title_link ),
$title
);
}
$title = sprintf(
'<h2>%1$s</h2>',
$title
);
}
if ( ! empty( $image ) ) {
$image = sprintf(
'<img src="%1$s" alt="" />',
esc_url( $image )
);
}
return sprintf(
'
%2$s
%1$s
%3$s
',
$title,
$image,
$content
);
}
}
new SIMP_SimpleBlurb;
The module's React component:
// External Dependencies
import React, { Component, Fragment } from 'react';
// Internal Dependencies
import './style.css';
class SimpleBlurb extends Component {
static slug = 'simp_simple_blurb';
_renderTitle() {
const title = this.props.dynamic.title;
const titleLink = this.props.dynamic.title_link;
let titleComponent = title.render();
if (title.loading) {
// Let Divi render the loading placeholder.
return titleComponent;
}
if (titleLink.hasValue) {
// Wrap the title in a link
titleComponent = (
<a href={titleLink.value}>
{titleComponent}
</a>
);
}
return (
<h2>
{titleComponent}
</h2>
);
}
_renderImage() {
const image = this.props.dynamic.image;
if (image.loading) {
// Let Divi render the loading placeholder.
return image.render();
}
if (!image.hasValue) {
// No image selected or the dynamic content selected does resolves to an empty value.
// This can happen in cases where the user selects "Featured Image" as dynamic
// content, but has not assigned a feature image to the post.
return null;
}
return (
<img src={image.value} alt="" />
);
}
_renderContent() {
const content = this.props.dynamic.content;
// Let Divi handle all of the rendering.
return content.render('full');
}
render() {
return (
<Fragment>
{this._renderImage()}
{this._renderTitle()}
{this._renderContent()}
</Fragment>
);
}
}
export default SimpleBlurb;