SP Page Builder - Custom Addon Development
Master the creation of custom addons for SP Page Builder (v5/6). Learn architecture, file structure, field types, dynamic rendering, and database access.
Table of Contents
-
Fundamental Architecture
-
Plugin Structure
-
Main Files
-
Field Types
-
Frontend Implementation
-
Database Access
-
Complete Example
-
Installation and Testing
- FUNDAMENTAL ARCHITECTURE
Addons are installed as Joomla plugins following the convention:
plg_sppagebuilder_{name}
Valid examples: plg_sppagebuilder_demo , plg_sppagebuilder_testimonials , plg_sppagebuilder_gallery
Directory structure:
plg_sppagebuilder_demo/ ├── demo.php (Main plugin file) ├── demo.xml (XML Manifest) ├── language/ │ └── en-GB/ │ └── en-GB.plg_sppagebuilder_demo.ini └── addons/ └── demo/ ├── admin.php (Field configuration) ├── site.php (Frontend rendering) └── assets/ └── images/icon.png (76x76 px)
Loading cycle:
-
Main plugin (demo.php) registers addon
-
Manifest (demo.xml) defines metadata
-
admin.php defines editable fields
-
site.php renders HTML on the frontend
- PLUGIN STRUCTURE
demo.php - Plugin entry point:
<?php defined('_JEXEC') or die('restricted access');
class PlgSppagebuilderDemo extends CMSPlugin { protected $autoloadLanguage = true;
public function onSppagebuilderGetAddons() {
$addon_path = dirname(__FILE__) . '/addons/demo';
if (file_exists($addon_path . '/admin.php')) {
require $addon_path . '/admin.php';
}
}
}
demo.xml - Plugin manifest:
<?xml version="1.0" encoding="utf-8"?> <extension type="plugin" group="sppagebuilder" method="upgrade"> <name>plg_sppagebuilder_demo</name> <author>Your Name</author> <version>1.0.0</version> <description>Custom addon demo for SP Page Builder</description> <license>GNU/GPLv2 or later</license>
<files>
<filename plugin="demo">demo.php</filename>
<folder>language</folder>
<folder>addons</folder>
</files>
<languages>
<language tag="es-ES">language/es-ES/es-ES.plg_sppagebuilder_demo.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field name="enabled" type="radio" label="Enabled" default="1">
<option value="0">No</option>
<option value="1">Yes</option>
</field>
</fieldset>
</fields>
</config>
</extension>
- MAIN FILES
admin.php - Defines configuration fields:
<?php defined('_JEXEC') or die('restricted access');
SpAddonsConfig::addonConfig(array( 'type' => 'content', 'addon_name' => 'sp_demo', 'title' => 'Demo Card', 'desc' => 'Custom card addon', 'category' => 'Custom', 'icon' => '', 'attr' => array( 'general' => array( 'title' => array( 'type' => 'text', 'title' => 'Title', 'std' => 'Card Title' ), 'description' => array( 'type' => 'textarea', 'title' => 'Description', 'std' => '' ), 'button_text' => array( 'type' => 'text', 'title' => 'Button Text', 'std' => 'Click Me' ), 'button_url' => array( 'type' => 'link', 'title' => 'Button URL', 'std' => '' ), 'addon_color' => array( 'type' => 'color', 'title' => 'Color', 'std' => '#333333' ) ), 'styling' => array( 'alignment' => array( 'type' => 'alignment', 'title' => 'Alignment', 'std' => 'left' ) ) ) ));
- AVAILABLE FIELD TYPES
Type Usage Example
text
Simple text Titles, names
textarea
Multiline text Descriptions
number
Numbers Sizes, limits
color
Color picker Color palettes
media
Image upload Multimedia
link
URL with options Links
select
Dropdown Selections
checkbox /radio
Boolean/option Switches
repeatable
Collections Dynamic lists
typography
Text styles Fonts
padding /margin
Spacing Margins
icon
Font Awesome Iconography
slider
Slider control Ranges
animation
CSS effects Animations
Repeatable fields for collections:
'items' => array( 'type' => 'repeatable', 'title' => 'Items', 'fields' => array( 'item_title' => array( 'type' => 'text', 'title' => 'Item Title' ), 'item_image' => array( 'type' => 'media', 'title' => 'Item Image' ), 'item_url' => array( 'type' => 'link', 'title' => 'Item URL' ) ) )
- FRONTEND IMPLEMENTATION
site.php - Renders the HTML:
<?php defined('_JEXEC') or die('restricted access');
class SppagebuilderAddonSp_demo extends SppagebuilderAddons {
public function render() {
$settings = $this->addon->settings;
$title = isset($settings->title) ? $settings->title : '';
$description = isset($settings->description) ? $settings->description : '';
$btn_text = isset($settings->button_text) ? $settings->button_text : '';
$btn_url = isset($settings->button_url) ? $settings->button_url : '';
$color = isset($settings->addon_color) ? $settings->addon_color : '#333';
$output = '<div class="sp-addon-demo" style="color: ' . esc_attr($color) . ';">';
$output .= '<h3>' . esc_html($title) . '</h3>';
$output .= '<p>' . nl2br(esc_html($description)) . '</p>';
if ($btn_url && $btn_text) {
$output .= '<a href="' . esc_attr($btn_url) . '" class="sp-demo-btn">';
$output .= esc_html($btn_text) . '</a>';
}
$output .= '</div>';
return $output;
}
public function css() {
$addon_id = '#sppb-addon-' . $this->addon->id;
$css = '';
$settings = $this->addon->settings;
if (isset($settings->alignment)) {
$css .= $addon_id . ' { text-align: ' . $settings->alignment . '; }';
}
return $css;
}
public function getTemplate() {
return '<div class="sp-addon-demo">
<h3><%= title %></h3>
<p><%= description %></p>
<% if (button_url && button_text) { %>
<a href="<%= button_url %>" class="sp-demo-btn"><%= button_text %></a>
<% } %>
</div>';
}
public function stylesheets() {
return array(
JUri::base(true) . '/plugins/sppagebuilder/demo/addons/demo/assets/css/demo.css'
);
}
public function scripts() {
return array(
JUri::base(true) . '/plugins/sppagebuilder/demo/addons/demo/assets/js/demo.js'
);
}
}
Main methods:
-
render()
-
Generates HTML for the frontend
-
css()
-
Generates dynamic CSS based on settings
-
getTemplate()
-
Lodash template for real-time editing
-
stylesheets()
-
Registers external CSS files
-
scripts()
-
Registers external JS files
Always escape output:
-
esc_html()
-
For text
-
esc_attr()
-
For HTML attributes
-
esc_url()
-
For URLs
- DATABASE ACCESS
Fetch articles dynamically:
public function render() { $settings = $this->addon->settings; $output = '';
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('a.id, a.title, a.introtext')
->from($db->quoteName('#__content', 'a'))
->where('a.state = 1')
->order('a.created DESC')
->setLimit(isset($settings->limit) ? (int)$settings->limit : 5);
$db->setQuery($query);
$articles = $db->loadObjectList();
if (count($articles)) {
$output .= '<ul class="sp-articles">';
foreach ($articles as $article) {
$output .= '<li>';
$output .= '<h4>' . esc_html($article->title) . '</h4>';
$output .= '<p>' . substr(strip_tags($article->introtext), 0, 100) . '...</p>';
$output .= '</li>';
}
$output .= '</ul>';
}
return $output;
}
Database best practices:
-
Use JFactory::getDbo() to get the instance
-
Implement access control
-
Use limits in queries
-
Always escape output
-
Cache results when possible
- COMPLETE EXAMPLE - TESTIMONIALS ADDON
admin.php:
<?php SpAddonsConfig::addonConfig(array( 'addon_name' => 'sp_testimonios', 'title' => 'Testimonials', 'category' => 'Custom', 'attr' => array( 'general' => array( 'testimonios' => array( 'type' => 'repeatable', 'fields' => array( 'nombre' => array('type' => 'text', 'title' => 'Name'), 'cargo' => array('type' => 'text', 'title' => 'Position'), 'texto' => array('type' => 'textarea', 'title' => 'Testimonial'), 'foto' => array('type' => 'media', 'title' => 'Photo') ) ) ) ) ));
site.php:
<?php class SppagebuilderAddonSp_testimonios extends SppagebuilderAddons { public function render() { $settings = $this->addon->settings; $items = isset($settings->testimonios) ? $settings->testimonios : array(); $output = '<div class="sp-testimonios">';
foreach ($items as $item) {
$output .= '<div class="testimonio">';
if (isset($item->foto)) {
$output .= '<img src="' . esc_attr($item->foto) . '" alt="">';
}
$output .= '<p>' . esc_html($item->texto) . '</p>';
$output .= '<strong>' . esc_html($item->nombre) . '</strong>';
$output .= '<small>' . esc_html($item->cargo) . '</small>';
$output .= '</div>';
}
$output .= '</div>';
return $output;
}
public function css() {
return '#sppb-addon-' . $this->addon->id . ' { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; }';
}
}
- INSTALLATION AND TESTING
Create a ZIP with the correct structure:
plg_sppagebuilder_demo.zip └── plg_sppagebuilder_demo/ ├── demo.php ├── demo.xml ├── language/ │ └── es-ES/ │ └── es-ES.plg_sppagebuilder_demo.ini └── addons/ └── demo/ ├── admin.php ├── site.php └── assets/ └── images/icon.png
Install in Joomla:
-
System -> Install -> Extensions
-
Upload the ZIP file
-
System -> Manage -> Plugins
-
Enable the plg_sppagebuilder_demo plugin
-
Edit a page with SP Page Builder
-
The addon will appear in the "Custom" category
Testing checklist:
-
Plugin appears in the plugins list
-
Addon is visible in SP Page Builder
-
Fields load correctly
-
Frontend rendering is correct
-
No errors in error_log
-
CSS/JS load properly
-
Responsive on mobile
-
Browser compatibility
-
XSS protection (escaping)
-
Access for unauthorized users
REFERENCES
Official documentation:
-
JoomShaper Custom Addon Creation
-
SP Page Builder Admin File
-
SP Page Builder Site File
-
Joomla Plugin Development
See references/ for complete examples, snippets, and reusable templates.