Builder Elements

Custom elements are the easiest way to extend the functionality of the YOOtheme Pro page builder. Copy an existing element and customize its markup and settings, or create a new element from scratch with custom functionalities.

Custom elements can be added to the page builder by using a child-theme or a Joomla plugin. Using a child theme is the easiest way to add an element and typically used for client projects. A Joomla plugin should be used when developing a 3rd party extension for YOOtheme Pro. Take a look at the extensions page to see what is available from the developer community.


Create an Element

An element has its own directory with configuration and template files. To create a new one, either start from scratch, use the example element or copy one of the included elements. Once the element is added to the page builder using a child-theme or a Joomla plugin it will appear under Custom in the element library.

Custom Element in the Element Library

The example element on Github demonstrates how to configure an element, how to extend its functionality and how to make use of the different field types. Simply download and unzip the example element.

To create a new element by customizing an existing element, simply copy one of the included elements and give it a unique name in the element.json configuration. Included elements can be found in the respective module directory under vendor/yootheme in YOOtheme Pro.

Directory Elements
builder/elements accordion, alert, button, code, column, countdown, description_list, divider, gallery, grid, headline, html, icon, image, layout, list, map, overlay, panel, popover, quotation, row, section, slider, slideshow, social, subnav, switcher, table, text, totop, video
builder-newsletter/elements newsletter
builder-joomla/elements breadcrumbs, module, module_position
builder-wordpress/elements breadcrumbs, module, module_position
builder-joomla-source/elements pagination
builder-wordpress-source/elements comments, pagination

File Structure

An element has its own directory with the following files.

File Description
element.json Defines the element configuration, fields and settings.
element.php Extends the element functionality with custom transforms or update functions. This file is optional and has to be imported through the element.json.
templates/template.php Renders the element layout. The rendering is often split into template partials prefixed with template-.
templates/content.php Renders the element content without layout-specific markup. The content is saved in the Joomla page. It's used by the Joomla search and remains when discontinuing using YOOtheme Pro.
images/icon.svg The icon shown in the element library.
images/iconSmall.svg The icon shown in the page builder..

JSON Configuration

The element.json defines the element's name, icons, fields and how the editing interface should look like inside the builder. Make sure to set a unique element name, for example my_element, that is not taken by an existing element. The following example shows a simple element configuration without any fields.

{
    "name": "example",
    "title": "Example",
    "icon": "${url:images/icon.svg}",
    "iconSmall": "${url:images/iconSmall.svg}",
    "element": true,
    "width": 500,
    "templates": {
        "render": "./templates/template.php",
        "content": "./templates/content.php"
    }
}
Property Description
name Name of the element. Must be unique.
title Label in the page builder.
icon Path to the icon used in the element library.
iconSmall Path to the icon used in the page builder.
element Show element in the element library.
width Width of the customizer sidebar when editing the element.
templates Paths to the two required template files.

Group Property

By default, custom elements are grouped under Custom in the element library. To create a dedicated group for elements set the group property. This is recommended if elements are shared across different projects or when developing a 3rd party extension for YOOtheme Pro.

"group": "company name",

Fields

Fields of an element can be defined in the fields object in the element.json file. Just add a field name and its field definition. To show the field when editing an element it needs to be set in the default fieldset object which defines the order and layout of the fields in the page builder.

"fields": {
    "my_field": {}
},
"fieldset": {
    "default": {
        "fields": [
            "my_field"
        ]
    }
}

Properties

Every field is defined by its type and further properties. The following properties are available for all field types.

Property Description
type Set the field input type. By default it's text which displays an input field.
label Display a field label above the field.
description Display a field description below the field.
attrs Add additional HTML attributes to the rendered field.
show Show field only if a specific condition is met.
enable Enable field only if a specific condition is met.

In the following example an input field named Content is shown.

"fields": {
    "content": {
        "label": "Content",
        "description": "A description text.",
        "type": "text",
        "attrs": {
            "placeholder": "Enter text"
        }
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content"
        ]
    }
}

Field Type Text

In the following example the style option can only be selected if the content field is filled out and the icon picker is only shown if the content field is filled out and the style is set to primary.

"fields": {
    "content": {
        "label": "Content"
    }
    "style": {
        "label": "Style",
        "type": "select",
        "options": {
            "None": "",
            "Primary": "primary",
            "Secondary": "secondary"
        },
        "enable": "content"
    }
    "icon": {
        "label": "Icon",
        "type": "icon",
        "show": "content && style=='primary'"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content",
            "style",
            "icon"
        ]
    }
}

Enable or Show Fields

Tabs

Optionally, the fieldset object type can be set to tabs which defines different tabs in which the fields are shown. In the following example a Content tab with a content field and a Settings tab with two option fields is shown.

"fields": {
    "content": {
        "label": "Content"
    },
    "option_a": {
        "label": "Select",
        "type": "select",
        "options": {
            "Option 1": 0,
            "Option 2": 1,
            "Option 3": 2
        }
    },
    "option_b": {
        "label": "Checkbox",
        "type": "checkbox",
        "text": "Some text"
    }
},
"fieldset": {
    "default": {
        "type": "tabs",
        "fields": [
            {
                "title": "Content",
                "fields": [
                    "content"
                ]
            },
            {
                "title": "Settings",
                "fields": [
                    "option_a",
                    "option_b"
                ]
            }
        ]
    }
}

Tabs with Fields

Default Values

Fields can be set to a default value when the element is added to the page builder. Default values for fields can be set in the defaults object in the element.json file. Just set the field key to the default value. In the following example the text field Content will be filled out with Some default value..

"defaults": {
    "content": "Some default value."
},
"fields": {
    "content": {
        "label": "Content",
        "type": "textarea"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content"
        ]
    }
}

Field with Default Value

Preview Placeholder

Fields can show a placeholder in the page builder preview while it has no content. Once the field is filled out, the placeholder disappears and the field value is shown. Placeholder values for fields can be set in the placeholder object in the element.json file. Just set the field key to the placeholder value. In the following example the element will show a Lorem ipsum placeholder text as long as the content field is not filled out.

"placeholder": {
    "props": {
        "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
    }
},
"fields": {
    "content": {
        "label": "Content",
        "type": "textarea"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content"
        ]
    }
}

Field with Placeholder

Interpolation Syntax

YOOtheme Pro comes with powerful interpolation syntax to reference values and to call functions. These interpolations are embedded within strings and wrapped in ${}, such as ${var.foo}.

For example, this is used for general element settings which are often the same across elements. Those fields are defined in the vendor/yootheme/builder/config/builder.json file. Their field definition can be referenced as ${builder.NAME}. The following example sets the field name maxwidth to the field definition defined in the builder.json file.

"fields": {
    "maxwidth": "${builder.maxwidth}"
},
"fieldset": {
    "default": {
        "fields": [
            "maxwidth"
        ]
    }
}

Here is the referenced field definition from the builder.json file.

"maxwidth": {
    "label": "Max Width",
    "description": "Set the maximum content width.",
    "type": "select",
    "options": {
        "None": "",
        "Small": "small",
        "Medium": "medium",
        "Large": "large",
        "X-Large": "xlarge",
        "2X-Large": "2xlarge"
    }
}

General Element Settings

Another example is the advanced setting tab which is also the same across all elements. Its fields order and layout is also referenced from the the builder.json file.

"fields": {
    "content": {
        "label": "Content",
        "type": "textarea"
    },
    "name": "${builder.name}",
    "source": "${builder.source}",
    "id": "${builder.id}",
    "status": "${builder.status}",
    "class": "${builder.cls}",
    "attributes": "${builder.attrs}",
    "css": {
        "type": "editor",
        "label": "CSS",
        "description": "Enter your own custom CSS.",
        "editor": "code",
        "mode": "css",
        "attrs": {
            "debounce": 500
        }
    }
},
"fieldset": {
    "default": {
        "type": "tabs",
        "fields": [
            {
                "title": "Content",
                "fields": [
                    "content"
                ]
            },
            "${builder.advanced}"
        ]
    }
}

Here is the referenced value from the builder.json file.

"advanced": {
    "title": "Advanced",
    "fields": [
        "name",
        "status",
        "source",
        "id",
        "class",
        "attributes",
        "css"
    ]
}

Advanced Element Settings


Dynamic Content

To add the dynamic content field, reference the Source fields from the builder.json file. If the advanced settings tab is already referenced, like in the example above, it's already included.

"source": "${builder.source}"

Dynamic Content Source Fields

For each field, which should be able to map dynamic content, the source property has to be set to true.

"fields": {
    "content": {
        "label": "Content",
        "description": "A text field that can be mapped to a field of a content source.",
        "source": true
    }
}

Dynamic Content Field Mapping


Field Types

Here is a list of all content field types in YOOtheme Pro.

Name Description Properties
checkbox Define a checkbox View
color Define a color picker.
editor Define a visual and code editor. View
font Define a font picker.
icon Define an icon picker for the UIkit icon library.
image Define an image picker for files in the media library.
link Define a link picker for Joomla system links and files in the media library.
location Define an interactive map to pick a location.
number Define a numerical input field.
radio Define a group of radio buttons View
range Define an range slider with an addition input field View
select Define a select box. View
text Define an input field.
textarea Define a plain text area for multiple lines of text
video Define a video picker for files the media library.

Field types which have additional properties are described in the following.

Checkbox Field

Additional property is text.

{
    "label": "Checkbox",
    "type": "checkbox",
    "text": "The text behind the checkbox."
}

Editor Field

Additional properties are editor and mode. The editor property set to code loads the code editor instead of the visual editor. The mode property explicitly defines the code language css, js or text/html.

Example for a visual and code editor.

{
    "label": "Editor",
    "type": "editor"
}

Example for a code editor only.

{
    "label": "Code Editor",
    "type": "editor",
    "editor": "code",
    "mode": "css",
    "attrs": {
        "debounce": 500
    }
}

Note To prevent the customizer preview from updating while typing in the editor, set the debounce attribute to around 500 milliseconds .

Select Field

Additional properties are default and options.

{
    "label": "Select",
    "type": "select",
    "default": 0,
    "options": {
        "Option 1": 0,
        "Option 2": 1,
        "Option 3": 2
    }
}

Radio Field

Additional properties are default, options and name.

{
    "label": "Radio",
    "type": "radio",
    "name": "radio_group",
    "default": 0,
    "options": {
        "Option 1": 0,
        "Option 2": 1,
        "Option 3": 2
    }
}

Range Field

There are no additional properties, but its necessary to set the min, max and step HTML attributes.

{
    "label": "Range",
    "type": "range",
    "attrs": {
        "min": 1,
        "max": 10,
        "step": 0.5
    }
}

Field Layouts

In opposite to content field types there are container field types. They have a fields object with other fields and define the layout of those fields in the page builder. They are typically used in the fieldset object.

Name Description
grid Arrange fields within a grid which share a description text below.
group Arrange fields compact with label and controls side by side and the description text as tooltip.

Grid Field

Additional property is width which defines the width for all grid cells.

"fields": {
    "image": {
        "label": "Image",
        "type": "image"
    },
    "width": {
        "label": "Width"
    },
    "height": {
        "label": "Height"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "image",
            {
                "description": "A description text below the grid.",
                "type": "grid",
                "name": "_image_dimension",
                "width": "1-2",
                "fields": [
                    "width",
                    "height"
                ]
            }
        ]
    }
}

Note Inline field definitions in the fieldset object need a unique name. By default, the label property is used as fallback for the name. But if a field definition doesn't have a label like in the example above a unique name must be set. The name is not used any further which is why we mark them with a _ prefix.

Grid with Fields

Group Field

Additional property is divider which sets a divider at the bottom of the group.

"fields": {
    "content": {
        "label": "Content"
    },
    "option_a": {
        "label": "Select",
        "type": "select",
        "options": {
            "Option 1": 0,
            "Option 2": 1,
            "Option 3": 2
        }
    },
    "option_b": {
        "label": "Checkbox",
        "type": "checkbox",
        "text": "Some text"
    },
    "option_c": {
        "label": "Text"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content",
            {
                "label": "Group 1",
                "type": "group",
                "divider": true,
                "fields": [
                    "option_a",
                    "option_b"
                ]
            },
            {
                "label": "Group 2",
                "type": "group",
                "fields": [
                    "option_a",
                    "option_b"
                ]
            }
        ]
    }
}

Note In opposite to the grid field, groups have usually a label which is why a name doesn't have to be set.

Group with Fields


Template Files

Here is an overview of the variables which are available when rendering an element node in your templates.

Variable Description
$node The element node (stdClass)
$props The element properties $node->props set using the fields (array)
$children The element children $node->children, for example items (array) of a multiple items element
$builder The current builder instance used to render children (YOOtheme\Builder)

Field Properties

All element fields defined in the element.json file can be accessed as properties using $props variable. Their values are of the according field type, or null if the user has not entered a value yet.

<?php

    // Properties
    $props['option_a'];    // String
    $props['option_b'];    // Integer
    $props['option_c'];    // Boolean

?>

<?php if ($props['title']) : ?>
<h3><?= $props['title'] ?></h3>
<?php endif ?>

<?php if ($props['content']) : ?>
<div><?= $props['content'] ?></div>
<?php endif ?>

Template Partials

Rendering the element layout is often split into template partials prefixed with template- using the helper function $this->render(). The following example renders the template-content.php file and passes the element properties $props.

<?= $this->render("{$__dir}/template-content", compact('props')) ?>

Template Engine

The YOOtheme Pro template engine provides a HTML helper function $this->el() to create HTML elements using a compact interpolation syntax for the $props variable and to allow merging attributes easily.

Syntax Description
foo-{bar} Adds foo-{bar} if $props['bar'] has a value and substitutes {bar} with the value.
foo {@bar} Adds foo if $props['bar'] has a value.
foo {@!bar} Adds foo if $props['bar'] has no value.
foo {@bar: value} Adds foo if $props['bar'] is set to value.
foo {@bar: value1|value2} Adds foo if $props['bar'] is set to value1 or value2.
foobar [foo {@bar}] Adds foobar while foo is only added if $props['bar'] has a value.
<?php

// Create the wrapping element container
$el = $this->el('div', [
    'class' => [
        // Adds two classes if a style is set
        'uk-card uk-card-{style}',
        // Adds a class if no style is set
        'uk-panel {@!style}',
        // Adds two classes if a style is set and another class if a size is also set
        'uk-card uk-card-{style} [uk-card-{size}]', 
    ],
    'style' => [
        // Sets the min-height if it's set
        'min-height: {min_height}px',
    ],
    // Adds the HTML attribute `uk-grid`
    'uk-grid' => true,
]);

// Create the wrapping content container
$content = $this->el('div', [

    'class' => [
        // Adds a class if a style is set
        'uk-card-body {@style}',
        // Adds a size class like `uk-margin-small` and if it's not set just `uk-margin`
        'uk-margin[-{margin_size}]',
    ],

]);

?>

<?= $el($props, $attrs) // Renders the opening HTML tag ?>

    <?php if ($props['content']) : ?>
    <?= $content($props, $props['content']) // Renders the whole HTML element ?>
    <?php endif ?>

<?= $el->end() // Renders the closing HTML tag ?>

There are severals arguments which are passed to the HTML element rendering.

Argument Type Description
$params array Pass the required element properties $props.
$attrs array Optionally, pass additional attributes which should be merged. Attributes needed for the general and advanced element settings are stored in the attrs variable and should be passed to the element wrapping HTML element.
$contents mixed Optionally, pass any content, for example $props['content'] and the whole HTML element will get rendered.

Transforms and Updates

The element.php is an optional file which extends the element functionality with custom transforms or update functions. It has to be imported through the element.json file.

{
    "@import": "./element.php",
    "name": "example",
    "title": "Example",
    "icon": "${url:images/icon.svg}",
    "iconSmall": "${url:images/iconSmall.svg}",
    "element": true,
    "width": 500,
    "templates": {
        "render": "./templates/template.php",
        "content": "./templates/content.php"
    }
}

Here is an example on how to define transforms and updates for the element node and which objects and parameters are available.

<?php

return [

    // Define transforms for the element node
    'transforms' => [

        // The function is executed before the template is rendered
        'render' => function ($node, array $params) {

            // Element object (stdClass)
            $node->type; // Type name (string)
            $node->props; // Field properties (array)
            $node->children; // All children (array)

            // Parameter array
            $params['path']; // All parent elements (array)
            $params['parent']; // Parent element (stdClass)
            $params['builder']; // Builder instance (YOOtheme\Builder)
            $params['type']; // Element definition (YOOtheme\Builder\ElementType)

        },

    ],

    // Define updates for the element node
    'updates' => [

        '1.18.0' => function ($node, array $params) {

        },

    ],

];

Collapsing Layout

To make an element work according to the collapsing layout cascade, it shouldn't be rendered if its content fields are empty.

return [

    'transforms' => [

        'render' => function ($node) {

            // Don't render element if the title or content field is empty
            return $node->props['title'] || $node->props['content'];

        },

    ],

];

Mind, that if it's just one content field the return value has to be casted to a boolean.

return [

    'transforms' => [

        'render' => function ($node) {

            // Don't render element if the content field is empty
            return (bool) $node->props['content'];

        },

    ],

];

Updates

Define element updates for new versions of YOOtheme Pro.

return [

    'updates' => [

        '2.1.0-beta.1' => function ($node) {

            // Rename a field value
            if (@$node->props['width'] === 'xxlarge') {
                $node->props['width'] = '2xlarge';
            }

        },

        '1.20.2' => function ($node) {

             // Rename a field key
            if (isset($node->props['breakpoint'])) {
                $node->props['grid_breakpoint'] = $node->props['breakpoint'];
                unset($node->props['breakpoint']);
            }

        },

    ],

];

Note Currently, element updates are tied to the updates of YOOtheme Pro. They don't have their own version numbers and can only be updated when the YOOtheme Pro version number changes.


Content Items

Elements which have content items, like the Grid element, are parent elements which in turn contain child elements. To create a container element set the container property to true in the element-json file. To add a field which shows an interface to manage the content items use the content-items field type and set the item property to the name of the child element.

{
    "name": "example",
    "title": "Example",
    "icon": "${url:images/icon.svg}",
    "iconSmall": "${url:images/iconSmall.svg}",
    "element": true,
    "container": true,
    "width": 500,
    "templates": {
        "render": "./templates/template.php",
        "content": "./templates/content.php"
    },
    "fields": {
        "content": {
            "label": "Items",
            "type": "content-items",
            "item": "example_item"
        }
    },
    "fieldset": {
        "default": {
            "fields": [
                "content"
            ]
        }
    }
}

A child element has its own directory, JSON configuration with a unique element name and template files, just like any other element. It's not shown in the element library which is why it also hasn't any icons. Typically a child element has also an advanced setting tab which is the same across all child elements. Its fields order and layout is referenced from the the builder.json file.

{
    "name": "example_item",
    "title": "Item",
    "width": 500,
    "templates": {
        "render": "./templates/template.php",
        "content": "./templates/content.php"
    },
    "fields": {
        "title": {
            "label": "Title",
            "source": true
        },
        "content": {
            "label": "Content",
            "type": "editor",
            "source": true
        },
        "image": {
            "label": "Image",
            "type": "image",
            "source": true
        },
        "status": "${builder.statusItem}",
        "source": "${builder.source}"
    },
    "fieldset": {
        "default": {
            "type": "tabs",
            "fields": [
                {
                    "title": "Content",
                    "fields": [
                        "title",
                        "content",
                        "image"
                    ]
                },
                "${builder.advancedItem}"
            ]
        }
    }
}

The child element should have at least a title field and an optional image field. Both will be shown in the list of content items created by the content-items field in the parent element.

Element with Content Items

Template Files

All child elements are accessible through the $children array and can be rendered using the the helper function $builder->render().

<?php foreach ($children as $child) : ?>
<?= $builder->render($child, ['element' => $props]) ?>
<?php endforeach ?>

Typically, the $props variable of the parent element is passed as $element to the child element, so all fields of the parent element can be accessed template files of the child element.

<?php

    // Property of the parent element
    $element['option_a'];

?>

Add Media Button

By default, the content-items field shows an Add Item button to create a new content item. Optionally, an Add Media button can be added. It allows to add multiple items at once from images picked in the media manager. For each selected image, a new item will be added. The image and title field will be automatically filled out.

To create a Add Media button simply define the media object with the type property set to image and an item object which defines to which fields the image title and src should be set.

"fields": {
    "content": {
        "label": "Items",
        "type": "content-items",
        "item": "example_item",
        "media": {
            "type": "image",
            "item": {"title": "title", "image": "src"}
        }
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content"
        ]
    }
}

Content Items with Add Media Button

Preview Placeholder

Elements can show placeholder items in the page builder preview while no content items are created yet. Once a content item is created, the placeholder items will disappear and the content item is shown instead. Placeholder items can be set in the children object in the placeholder object in the element.json file. Create an object for each placeholder item with the type property set to the name of the child element.

"placeholder": {
    "children": [
        {"type": "example_item", "props": {}},
        {"type": "example_item", "props": {}},
        {"type": "example_item", "props": {}}
    ]
},
"fields": {
    "content": {
        "label": "Items",
        "type": "content-items",
        "item": "example_item"
    }
},
"fieldset": {
    "default": {
        "fields": [
            "content"
        ]
    }
}

Content Items with Placeholder

If necessary, different placeholder values for fields of the placeholder item can be set in the props object.

"placeholder": {
    "children": [
        {"type": "example_item", "props": {"position_x": 20, "position_y": 50}},
        {"type": "example_item", "props": {"position_x": 50, "position_y": 20}},
        {"type": "example_item", "props": {"position_x": 70, "position_y": 70}}
    ]
}
YOOtheme Pro Documentation