The page builder includes an AI assistant that writes sections and rewrites text. For plugin authors the important part is that it can place your shortcodes on a page, using only the information in your shortcode definition.
Inactive out of the box
The assistant's code, editor panel and endpoint are part of the core, but this release registers no settings screen for it. It stays hidden until the page_builder_ai_* settings described below are written, and the signed-in user holds edit page. Treat it as an optional capability: your shortcodes must work fine without it.
Editor chat panel (ai-agent.js)
-> POST admin/page-builder/ai/generate route admin.page-builder.ai.generate
middleware: admin stack (auth, verified, 2fa), throttle:page-builder-ai (default 20/min per user), can:edit page
-> PageBuilderAiManager::generate()
prompt = request + page context + capability catalogue (PageBuilderCapabilityCatalog)
provider adapter (OpenAI, Anthropic, Gemini, Azure OpenAI, OpenAI-compatible)
-> PageBuilderAiSanitizer strips anything not allowed, reports warnings
-> editor inserts the HTML (and any approved images, imported to the media library)The capability catalogue lists every registered shortcode unless its definition opts out. For each one the model receives:
| Catalogue field | Comes from |
|---|---|
id, name, tag, group | The arguments of ShortcodeDefinition::make($id, $name, $tag, $category) |
description | ->description(): write it for a reader who has never seen your plugin |
attributes | Your traits: name, label, type, required, default, allowed values (the trait's options), min, max |
module | ->ai(['module' => 'testimonials']); defaults to core |
functional_form | ->ai(['form_handler' => '...']), for shortcodes that render a working form (the core contact form, Booking's form) |
php — in your shortcode definition
return ShortcodeDefinition::make('testimonials', __('testimonials::testimonials.block'), 'x-shortcode-testimonials', 'testimonials')
->description('Shows published customer testimonials as cards or a slider.')
->ai(['enabled' => true, 'module' => 'testimonials'])
// ... defaults(), traits() ...
;
// A block that only makes sense when placed by hand:
->ai(['enabled' => false])Opt out for shortcodes that show personal data, depend on context the AI cannot know (a "current product" block), or are only useful inside one template.
Everything the model returns passes through PageBuilderAiSanitizer before it reaches the canvas:
options is removed with a warning. Inner content is dropped; your component renders it.config/page_builder.php (Bootstrap grid, spacing, display and colour utilities, common components, and names starting with tru-, theme-, echo-, shortcode- or page-builder-).The practical rule: give your traits real options lists and sensible defaults. The tighter the trait, the more likely the assistant produces a working block.
The assistant reads these settings (database settings, read with setting()):
| Setting | Default | Meaning |
|---|---|---|
page_builder_ai_enabled | false | Master switch |
page_builder_ai_provider | openai | openai, anthropic, gemini, azure_openai or openai_compatible |
page_builder_ai_model | the provider's default | A model id from PageBuilderAiRegistry::providers() |
page_builder_ai_{provider}_api_key | — | Encrypted. Store the value returned by PageBuilderAiSecretStore::encrypt(); a plain value is treated as missing |
page_builder_ai_{provider}_endpoint, _base_url, _deployment, _custom_model, _organization_id, _project_id | — | Provider-specific, required where the registry says so (Azure needs endpoint and deployment; OpenAI-compatible needs base URL and model) |
page_builder_ai_temperature, _max_output_tokens, _timeout | 0.4, 2000, 45 | Generation limits |
page_builder_ai_rate_limit | 20 | Requests per minute per user (1–120) |
page_builder_ai_text_rewriting, _section_generation, _context_enabled | true | Turn individual actions and page context off |
page_builder_ai_max_prompt_length, _max_context_size | 6000, 30000 | Characters |
php — e.g. in a deployment command or your own settings handler
use Akaunting\Setting\Facade as Setting;
use App\Services\PageBuilder\AI\PageBuilderAiSecretStore;
Setting::set('page_builder_ai_enabled', true);
Setting::set('page_builder_ai_provider', 'anthropic');
Setting::set('page_builder_ai_anthropic_api_key', app(PageBuilderAiSecretStore::class)->encrypt($apiKey));
Setting::save();The secret store encrypts with the application key, so a key saved on one site cannot be read on another, and rotating APP_KEY invalidates it.
PageBuilderAiRegistry returns a hard-coded array and has no registration hook. The OpenAI-compatible adapter covers most self-hosted and third-party endpoints.EncryptedPassword, ProviderModelSelect) exist in app/Services/Settings/Fields but are not in the list of field types a settings section can use, so a plugin cannot reuse them through SettingsManager.