sppagebuilder-custom-addon
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
1. 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
2. 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>
3. 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'
)
)
)
));
4. 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'
)
)
)
5. 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 frontendcss()- Generates dynamic CSS based on settingsgetTemplate()- Lodash template for real-time editingstylesheets()- Registers external CSS filesscripts()- Registers external JS files
Always escape output:
esc_html()- For textesc_attr()- For HTML attributesesc_url()- For URLs
6. 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
7. 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; }';
}
}
8. 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_demoplugin - 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.