A powerful, self-contained page builder package for Laravel with a modern React frontend. Build beautiful pages with drag-and-drop widgets, extensible architecture, and zero conflicts with your existing application.
- Visual Page Builder — Modern React drag-and-drop interface
- Extensible Widget System — 9+ built-in widgets with easy custom widget creation
- Advanced Styling — Comprehensive style controls with live CSS preview
- Responsive Design — Desktop / Tablet / Mobile preview modes
- Highly Configurable — Works seamlessly with existing Laravel apps
- Performance Optimized — Efficient CSS generation and caching
- Secure — XSS protection and input sanitization
- Self-Contained Assets — Pre-built React assets, no Node.js needed in your host app
- PHP: 8.2 or higher
- Laravel: 11.0 or 12.0
- Database: MySQL 5.7+ or PostgreSQL 10+
composer require xgenious/xgpagebuilderphp artisan vendor:publish --tag=page-builder-config
php artisan vendor:publish --tag=page-builder-assets
php artisan migrate
php artisan config:clearCreate a new migration:
Schema::table('pages', function (Blueprint $table) {
$table->boolean('use_page_builder')->default(false);
$table->string('page_builder_status')->default('off'); // 'on' or 'off'
});Two flags are needed:
use_page_builder— triggersrenderPage()in the controllerpage_builder_status— gates display in the blade view ('on'= show builder content)
In app/Providers/AppServiceProvider.php:
public function boot(): void
{
$this->loadViewsFrom(base_path('plugins/PageBuilder/views'), 'pagebuilder');
}Adjust the path to wherever your widget blade views live. This is required for view('pagebuilder::...') to work inside widget render() methods.
// app/Models/Backend/Page.php
public function pageBuilderContent()
{
return $this->hasOne(\Xgenious\PageBuilder\Models\PageBuilderContent::class, 'page_id');
}// config/xgpagebuilder.php
'models' => [
'page' => \App\Models\Backend\Page::class,
'admin' => \App\Models\Backend\Admin::class,
],use Xgenious\PageBuilder\Services\PageBuilderRenderService;
public function show($slug)
{
$page = Page::where('slug', $slug)->firstOrFail();
if ($page->use_page_builder) {
$result = app(PageBuilderRenderService::class)->renderPage($page, true);
$page->rendered_content = $result['html'] ?? '';
$page->pagebuilder_generated_styles = $result['css'] ?? '';
}
return view('frontend.pages.show', compact('page'));
}Always pass
trueas the second argument torenderPage(). Without it, CSS from style fields is silently dropped.
@if($page->page_builder_status === 'on')
@if(isset($page->rendered_content))
<style>{!! $page->pagebuilder_generated_styles !!}</style>
{!! $page->rendered_content !!}
@endif
@else
{!! $page->content !!}
@endif@if($page->use_page_builder)
<a href="{{ route('admin.page-builder.edit', $page->id) }}" target="_blank">
Open Page Builder
</a>
@endifnamespace 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'; }
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();
}
}Icon format: always use Line Awesome format
'las la-ICONNAME'(e.g.'las la-bullhorn','las la-star').
IMAGE and VIDEO fields return an array
['url' => '...', 'id' => ...], not a plain string. Always extract the URL:$value['url'] ?? ''.
Register in config and clear cache:
// config/xgpagebuilder.php
'custom_widgets' => [
\Plugins\PageBuilder\Widgets\CallToActionWidget::class,
],php artisan config:clearSee Widget Development Guide for all field types and real-world examples.
- Header Widget — Hero sections with titles, subtitles, and CTAs
- Features Widget — Feature grids with icons and descriptions
- Testimonial Widget — Customer testimonials and reviews
- Image Widget — Responsive images with captions
- Image Gallery Widget — Photo galleries with lightbox
- Video Widget — Embedded videos (YouTube, Vimeo, self-hosted)
- Icon Widget — Icon displays with customization
- Tabs Widget — Tabbed content sections
- Code Widget — Syntax-highlighted code blocks
- Setup & Integration Guide — Full installation, configuration, and host-app integration
- Widget Development Guide — Create custom widgets and migrate legacy addons
- Frontend Integration — CSS pipeline, JS, responsive, media library
- Field Reference — All available PHP fields with examples
- Online Documentation — Full documentation website
- Editor URL:
/{route_prefix}/edit/{pageId}(default:/page-builder/edit/{pageId}) - API Endpoints:
/api/page-builder/* - Config file:
config/xgpagebuilder.php
# Configuration
php artisan vendor:publish --tag=page-builder-config
# Pre-built frontend assets (required)
php artisan vendor:publish --tag=page-builder-assets
# Views (for customization)
php artisan vendor:publish --tag=page-builder-views
# Migrations
php artisan vendor:publish --tag=page-builder-migrationscd vendor/xgenious/xgpagebuilder
npm install && npm run build
cd ../../..
php artisan vendor:publish --tag=page-builder-assets --forceAssets are published to
public/assets/vendor/page-builder/— not/vendor/page-builder/. nginx commonly blocks/vendor/URL paths as a security rule.
php artisan vendor:publish --tag=page-builder-views --force
php artisan view:clear && php artisan config:clearphp artisan config:clearVerify the widget class is listed in custom_widgets in config and extends BaseWidget.
- Check
page_builder_statusis'on'for the page - Check
use_page_builderistrue - Verify blade outputs
$page->pagebuilder_generated_stylesin a<style>tag before$page->rendered_content
// config/xgpagebuilder.php
'route_prefix' => 'admin/page-builder',- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes
- Push to the branch
- Open a Pull Request
This package is open-sourced software licensed under the MIT license.
- Email: support@xgenious.com
- Issues: GitHub Issues
Made with ❤️ by Xgenious