Widget Development

For the full guide with all field types, real-world examples, and legacy migration, see WIDGET-DEVELOPMENT.md.


Quick Example

namespace Plugins\PageBuilder\Widgets;

use Xgenious\PageBuilder\Core\BaseWidget;
use Xgenious\PageBuilder\Core\ControlManager;
use Xgenious\PageBuilder\Core\FieldManager;
use Xgenious\PageBuilder\Core\WidgetCategory;

class CallToActionWidget extends BaseWidget
{
    protected function getWidgetType(): string       { return 'call_to_action'; }
    protected function getWidgetName(): string       { return 'Call to Action'; }
    protected function getWidgetIcon(): string|array { return 'las la-bullhorn'; }  // format: 'las la-ICONNAME'
    protected function getCategory(): string         { return WidgetCategory::MARKETING; }

    public function getGeneralFields(): array
    {
        $control = new ControlManager();

        $control->addGroup('content', 'Content')
            ->registerField('title',       FieldManager::TEXT()->setLabel('Title')->setDefault('Get Started Today'))
            ->registerField('button_text', FieldManager::TEXT()->setLabel('Button Text')->setDefault('Sign Up'))
            ->registerField('button_url',  FieldManager::URL()->setLabel('Button URL')->setDefault('#'))
            ->endGroup();

        return $control->getFields();
    }

    public function getStyleFields(): array { return []; }

    public function render(array $settings = []): string
    {
        $content = $settings['general']['content'] ?? [];

        return view('pagebuilder::widgets.cta', [
            'title'      => $content['title']       ?? '',
            'buttonText' => $content['button_text'] ?? '',
            'buttonUrl'  => $content['button_url']  ?? '#',
        ])->render();
    }
}

Blade view:

```blade<div class="cta-section"> <h2></h2> </div>


**Register:**

```php
// config/xgpagebuilder.php
'custom_widgets' => [
    \Plugins\PageBuilder\Widgets\CallToActionWidget::class,
],
php artisan config:clear

Key Field Types

Field Usage
FieldManager::TEXT() Single-line text
FieldManager::TEXTAREA() Multi-line text
FieldManager::WYSIWYG() Rich text editor
FieldManager::NUMBER() Number input
FieldManager::TOGGLE() Boolean switch
FieldManager::SELECT() Dropdown
FieldManager::COLOR() Color picker
FieldManager::IMAGE() Image upload → returns array ['url'=>..., 'id'=>...]
FieldManager::VIDEO() Video upload → returns array ['url'=>..., 'poster'=>...]
FieldManager::URL() Link field
FieldManager::ICON() Icon picker
FieldManager::REPEATER() Repeatable group of fields
FieldManager::DIMENSION() Margin/padding with CSS selector binding

IMAGE and VIDEO fields return arrays. Extract the URL with $value['url'] ?? ''.


Widget Categories

use Xgenious\PageBuilder\Core\WidgetCategory;

WidgetCategory::THEME        // theme-specific sections
WidgetCategory::BASIC        // basic content
WidgetCategory::CONTENT      // content widgets
WidgetCategory::MEDIA        // image, video, gallery
WidgetCategory::INTERACTIVE  // tabs, accordion, slider
WidgetCategory::MARKETING    // CTA, pricing, testimonials


CSS in Widgets — Two Approaches

Approach 1 — Inline <style> block in blade (for fixed layout / values from render())

Scope to # so multiple instances on the same page don’t clash:

<style>
    # .my-section { background-color: ; }
</style>
<section id="" class="my-section">...</section>

Pass 'uid' => 'prefix_' . uniqid() from render().

Approach 2 — getStyleFields() with setSelectors() (for values the editor user sets in the Style tab)

public function getStyleFields(): array
{
    $control = new ControlManager();
    $control->addGroup('section', 'Section')
        ->registerField('margin', FieldManager::DIMENSION()
            ->setLabel('Margin')->asMargin()
            ->setSelectors([' .my-section'])
        )
        ->endGroup();
    return $control->getFields();
}

`` is replaced with .pb-widget-{widgetId} — each instance is isolated automatically. This CSS lands in $page->pagebuilder_generated_styles and is output once in the page <style> block.

Use both together: inline blade CSS for values you set in render(), getStyleFields() for spacing/colors the editor user configures.


For all field types, style CSS generation, and complete examples → WIDGET-DEVELOPMENT.md