---
url: /introduction/what-is-bagisto-visual.md
---
# What is Bagisto Visual?
**Bagisto Visual** is the missing piece in the Bagisto ecosystem: a modern theme framework and visual editor that makes building and customizing storefronts simple, flexible, and powerful.
Inspired by the best systems in the e-commerce world, Bagisto Visual transforms theme development from a tedious, technical task into an intuitive experience — empowering both developers and merchants to create beautiful, high-performing stores without complexity.
## Why Bagisto Visual?
Building and maintaining Bagisto themes traditionally comes with real pain points:
* Developers must dive deep into Bagisto's internals with little documentation.
* There is no standardized, structured way to create custom themes.
* Every small change or update requires developer intervention.
* Merchants are often stuck, unable to tweak their store without costly and time-consuming help.
Whenever a merchant needed even a small visual update — a color change, a new section, a layout adjustment — they had to call a developer, causing unnecessary delays, frustration, and added costs.
**Bagisto Visual solves this problem.**
It introduces a modern theme architecture and a visual editor that empower merchants to take control of their storefronts, while giving developers a faster, cleaner way to build flexible, maintainable themes.
## Who Is Bagisto Visual For?
Bagisto Visual is designed to serve multiple audiences:
* **Merchants:**
Easily customize the look and feel of your store without writing a single line of code. Control sections, templates, content, and layout visually.
* **Developers:**
Build themes faster with a standardized, modular structure. Create powerful, flexible sections and templates without reinventing the wheel each time.
* **Agencies and Freelancers:**
Deliver projects faster, empower clients to manage their storefronts independently, and reduce post-launch maintenance workload.
Bagisto Visual democratizes storefront customization — no matter if you're a store owner, a developer, or a full agency team.
---
---
url: /introduction/features-benefits.md
---
# Features and Benefits
Bagisto Visual simplifies theme development and customization in Bagisto — built for both **developers** and **merchants**. With a visual editor and structured framework, it makes building and managing storefronts faster, easier, and more collaborative.
## Key Features
### 1. **Visual Theme Editor**
A powerful drag-and-drop interface where merchants customize their storefront without touching code.
**Key capabilities:**
* **Real-Time Preview** – See exactly what you're building as you build it
* **Drag-and-Drop Interface** – Add, remove, and reorder content visually
* **No Code Required** – Designed for non-technical users
**What merchants can do:** Customize layouts, rearrange content, change colors and typography, manage sections, and build unique storefronts — all visually in the editor.
***
### 2. **Modern Theme Framework**
A structured, maintainable foundation for building Bagisto themes that scale.
**Architecture benefits:**
* **Modular Structure** – Clean folder layout for layouts, templates, sections, and assets
* **Section-Based Architecture** – Organize your theme into reusable sections (Hero, Features, Product Grid, Footer)
* **Blade & Livewire Support** – Build custom sections using familiar Laravel tools
**For developers:** Build themes faster with less code duplication. Create reusable components that work across multiple projects. Maintain consistency while enabling merchant customization.
***
### 3. **Reusable Components**
Build once, use everywhere. Create components that work across your entire theme.
**Component features:**
* **Blocks System** – Reusable building blocks that work in any section
* **Custom Sections** – Build new sections in Blade or Livewire
* **Settings & Configuration** – Define what merchants can customize
* **Cross-Theme Compatibility** – Share components between projects
* **Update Once, Change Everywhere** – Modifications propagate automatically
**Real example:** Create a button component once, use it in Hero sections, product pages, banners, and CTAs. Update the style once, every instance updates automatically.
## Benefits
### 1. **Put Merchants in Control**
Merchants can update their site without needing a developer for every minor change — saving time and improving agility.
### 2. **Faster Development Cycles**
Developers no longer need to reinvent the wheel for every project.
The framework enables rapid theme creation, reuse, and extension.
### 3. **Reduces Costs**
Since merchants can manage most of their design changes independently, it reduces the number of hours developers need to spend on small updates. This leads to a significant reduction in costs over time.
### 4. **Flexible & Customer-Centric Design**
Themes are fully customizable via templates and sections, allowing teams to create storefronts that align with brand identity and deliver a great user experience.
---
---
url: /introduction/getting-started.md
---
# Getting Started
Bagisto Visual gives you a full visual editing experience for your storefront — with real-time preview, drag-and-drop sections, and theme customization.
This guide will help you:
1. Install Bagisto Visual
2. Add the default starter theme
3. Launch the visual editor
4. Add and edit content
5. Create your first custom section
## Prerequisites
Before you begin, make sure you have:
* PHP version **8.2 or later**
* A running Bagisto store (version **2.3 or later**)
## Step 1: Install Bagisto Visual
Install the package via Composer:
::: info
If you're installing an alpha/beta version, ensure your project accepts dev packages:
```bash
composer config minimum-stability dev && composer config prefer-stable true
```
This allows Composer to install pre-release versions of Bagisto Visual.
:::
```bash
composer require bagistoplus/visual:^2.0@dev
```
Then publish the assets:
```bash
php artisan vendor:publish --tag=visual-assets
```
This installs Bagisto Visual and prepares your store for theme customization.
### Optional: Enable Template Assignments
Template assignments let products, categories, and CMS pages use custom templates from the Bagisto admin. This feature stores assignments in the database, so enable it only when you need persistent per-resource templates.
Add the environment flag:
```env
BAGISTO_VISUAL_TEMPLATE_ASSIGNMENTS=true
```
Then run the package migrations:
```bash
php artisan migrate
```
## Step 2: Install the Starter Theme
Install the default theme package:
```bash
composer require bagistoplus/visual-debut:^2.0@dev
```
And publish its assets:
```bash
php artisan vendor:publish --tag=visual-debut-assets
```
Once installed, the theme will appear in your Bagisto admin under the menu **Bagisto Visual** -> **Themes**.
Click **Customize** to launch the visual editor.
## Step 3: Launch the Visual Editor
From the admin panel, navigate to **Bagisto Visual** → **Themes** and click **Customize** on the Visual Debut theme.
**The editor interface has three main areas:**
* **Left Sidebar** – Browse pages, add sections, manage content structure
* **Center Preview** – Live preview of your storefront with real-time updates
* **Right Panel** – Edit settings for the selected section or block
**Editor tools:**
* **Page Selector** – Switch between Home, Product, Collection, and other pages
* **Device Preview** – Test mobile, tablet, and desktop layouts
* **Language Switcher** – Customize content for different locales
* **Save** – Save your work as draft
* **Publish** – Make changes live on your storefront
::: tip
Changes in the editor are not visible to customers until you click **Publish**. This lets you experiment freely.
:::
> ℹ️ For a full breakdown of the interface, see [Theme Editor: Interface Guide](../theme-editor/interface-guide.md)
## Step 4: Add and Edit Content
### Adding Sections
Sections are the building blocks of your pages. To add a new section:
1. Click **Add Section** in the left sidebar
2. Browse available sections (Hero, Newsletter, Featured Products, etc.)
3. Click a section to add it to your page
4. The section appears in both the preview and sidebar
### Customizing Sections
Once a section is added:
1. **Click the section** in the preview or sidebar to select it
2. The right panel shows available settings:
* Text fields for headings and descriptions
* Image uploads for backgrounds and media
* Color pickers for styling
* Link fields for buttons and CTAs
* Layout options for columns and spacing
3. **Changes appear instantly** in the preview
4. **Drag sections** in the sidebar to reorder them
### Working with Blocks
In v2 themes, sections can contain blocks — reusable components you can add, remove, and rearrange:
* Click **Add Block** within a section to add components
* Drag blocks to reorder them
* Each block has its own settings
* Blocks can be nested (columns inside tabs, galleries inside accordions)
::: tip
Use the **undo/redo** buttons if you make a mistake. Your changes are only saved when you click **Save** or **Publish**.
:::
## Step 5: Create a Custom Section
Ready to build your own sections? Use the Artisan command:
```bash
php artisan visual:make-section MyBanner
```
**This generates two files:**
1. **PHP class:** `app/Visual/Sections/MyBanner.php`
* Defines section settings (text fields, images, selects)
* Configures which blocks it accepts
* Controls section behavior
2. **Blade template:** `resources/views/sections/my-banner.blade.php`
* The HTML structure of your section
* Access settings via `$section` variable
* Render child blocks with `@children`
**Example section class:**
```php
public static function settings(): array
{
return [
Text::make('heading', 'Heading')->default('Welcome'),
Textarea::make('description', 'Description'),
Image::make('background', 'Background Image'),
];
}
```
Once created, your section will appear in the **Add Section** menu in the editor.
> 🧱 For complete guides on building sections and blocks, see:
>
> * [Creating Sections](../building-theme/adding-sections/creating-section)
> * [Creating Blocks](../building-theme/adding-blocks/creating-block)
## Troubleshooting
### Composer installation fails
**Check minimum stability settings:**
```bash
composer config minimum-stability dev
composer config prefer-stable true
```
### Assets not loading
**Republish assets:**
```bash
php artisan vendor:publish --tag=visual-assets --force
php artisan vendor:publish --tag=visual-debut-assets --force
```
## What's Next?
**Learn the fundamentals:**
* [Sections](../core-concepts/sections) – Understand sections
* [Blocks](../core-concepts/blocks) – Understand blocks
* [Theme Editor Guide](../theme-editor/interface-guide) – Master the visual editor
**Start building:**
* [Creating Sections](../building-theme/adding-sections/creating-section) – Build custom sections
* [Creating Blocks](../building-theme/adding-blocks/creating-block) – Create reusable blocks
* [Settings Guide](../core-concepts/settings/overview) – Add configuration options
***
You're ready to build a beautiful, customized storefront — visually.
---
---
url: /introduction/llms.md
---
# LLMs.txt
Make AI coding assistants and chat interfaces understand Bagisto Visual's architecture, conventions, and patterns.
## What is `llms.txt`?
`llms.txt` is a standardized format that helps AI tools understand your framework or project. Bagisto Visual provides these files so AI assistants like GitHub Copilot, Cursor, ChatGPT, and Claude can:
* **Suggest better code** – Autocomplete section structures, settings, and Blade templates accurately
* **Follow conventions** – Use correct naming patterns, file locations, and API methods
* **Understand context** – Know about blocks, sections, templates, and how they relate
* **Provide accurate help** – Answer questions about Bagisto Visual with up-to-date information
* **Generate valid code** – Create sections and blocks that follow framework patterns
Instead of generic suggestions, AI tools can provide recommendations specific to Bagisto Visual's architecture.
## Available Files
We provide the following routes:
* [`llms.txt`](/llms.txt): A compact overview of Bagisto Visual, including keywords and top-level concepts
* [`llms-full.txt`](/llms-full.txt): A detailed description of the framework, its architecture, usage patterns, and terminology
These files are designed for easy ingestion by AI tools and indexing systems.
## Using with AI Tools
### Code Assistants (Copilot, Cursor, etc.)
AI code completion tools can reference llms.txt for context-aware suggestions:
**In Cursor:**
```
@Docs https://visual.bagistoplus.com/llms-full.txt
```
This loads Bagisto Visual documentation into Cursor's context, enabling:
* Accurate section/block scaffolding
* Correct settings field syntax
* Proper Blade directive usage
* Convention-following code generation
Learn more: [Cursor @Docs](https://docs.cursor.com/context/@-symbols/@-docs)
***
### Chat Interfaces (ChatGPT, Claude)
When asking AI chat tools about Bagisto Visual:
**Share the context:**
"I'm working with Bagisto Visual. Reference https://visual.bagistoplus.com/llms-full.txt for documentation."
The AI will then:
* Understand framework-specific terminology
* Suggest code that matches conventions
* Reference actual API methods
* Provide accurate troubleshooting
***
### Custom Integrations
Building tools that work with Bagisto Visual? Use llms.txt files for:
* **RAG Pipelines** – Embed framework knowledge in your AI system
* **Code Generators** – Generate valid sections/blocks/templates automatically
* **Documentation Chatbots** – Answer framework questions accurately
* **IDE Extensions** – Power autocomplete with framework context
Parse the files to extract structure, examples, and patterns for your use case.
---
---
url: /core-concepts/architecture.md
---
# Anatomy of a Theme
Bagisto Visual brings a **modern, flexible theme system** to Bagisto — **heavily inspired by Shopify's proven architecture**.
At its core, a theme is a **structured collection of layouts, templates, sections, blocks, and settings**, allowing both developers and store owners to collaboratively build and manage storefronts with ease.
By adopting a system modeled after Shopify, Bagisto Visual empowers **merchants** and **theme developers** to take full control of the storefront experience — crafting **beautiful, fully customized online stores** that stand out from the competition.
This section explains **how a Bagisto Visual theme is organized**, **how the core parts fit together**, and **how developers and merchants can collaborate** to build dynamic, customizable storefronts.

## Theme Structure
A theme is made up of the following main parts:
| Number | Part | Description |
| ------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | **Layout** | The base structure of the page. Defines global elements and includes regions using `@visualRegion()`. |
| 2 | **Template** | Define what to render and where. Each page of the storefront has its own associated template. Templates can be Blade (with dynamic logic), JSON/YAML, or PHP. Only one template is rendered per page. |
| 3,4 | **Region** | Customizable zones (like header, footer) shared across all pages. Merchants can add/remove sections in regions through the Visual Editor. See [Regions](./regions.md). |
| 5 | **Template section** | Modular, reusable containers that compose blocks into layouts. Used inside templates. |
| 6 | **Block** | Atomic, reusable components that provide content. Shared across multiple sections. The fundamental building units of v2 themes. |
> **Note:**
> Templates define the structure of different page types in your storefront, such as the homepage, product pages, category pages, cart, and more. Each page is rendered based on its associated template, making it easy to create custom layouts for different parts of your store.
## Folder Structure
```plaintext
/theme/
├── resources/
│ ├── views/
│ ├── components/ # Custom Blade or Livewire components
│ ├── layouts/ # Layouts (default layout is mandatory)
│ ├── blocks/ # Block Blade files (v2)
│ ├── sections/ # Section Blade files
│ ├── templates/ # Page templates (JSON, YAML, PHP, or Blade)
│ ├── regions/ # Region templates (header, footer, etc.)
├── src/
│ ├── Blocks/ # PHP classes for custom blocks (v2)
│ ├── Sections/ # PHP classes for custom sections
│ ├── Presets/ # Preset classes for reusable configurations
```
## Key Concepts
### Layouts
* Define the **global structure** of your pages.
* Must include a `default.blade.php` layout inside `/resources/views/layouts/`.
* Layouts typically contain the `
`, header, footer, and dynamic content area.
### Templates
* Represent **individual pages** (e.g., homepage, product page).
* Can be written in **Blade**, **JSON**, **YAML**, or **PHP**.
* Templates **list sections** in the desired order.
* Only one template is rendered at a time based on the page being viewed.
### Regions
* **Customizable zones shared across all templates** (e.g., header, footer).
* Merchants can **add, remove, and reorder sections** in regions through the Visual Editor.
* Created using the same formats as templates (JSON, YAML, or PHP).
* Included in layouts using the `@visualRegion()` directive.
* See [Regions](./regions.md) for detailed documentation.
### Blocks (v2)
* **Atomic, reusable components** that provide content (buttons, images, headings, testimonials, product elements).
* **Shared across multiple sections** - define once, use everywhere.
* Created as PHP classes in `src/Blocks/` with Blade views in `resources/views/blocks/`.
* Can be **nested** (container blocks accept child blocks) for complex layouts.
* Two types: **Dynamic** (merchant-controlled) and **Static** (developer-controlled).
* See [Core Concepts: Blocks](/core-concepts/blocks) for details.
### Sections
* **Containers that compose blocks** into cohesive layouts.
* Accept and arrange blocks according to their schema.
* Created using PHP classes in `src/Sections/` with Blade views in `resources/views/sections/`.
* Sections provide structure; blocks provide content.
---
---
url: /core-concepts/layouts.md
---
# Layouts
Layouts are the **foundation** of every page in a Bagisto Visual theme.
They define the **global structure** shared across templates, including key elements like the **header**, **footer**, **meta tags**, and **scripts**.
Layouts also establish the **dynamic content area** where page-specific templates and sections are rendered.
In Bagisto Visual, layouts are built using **Blade templates** and are located under:
```plaintext
/theme/
├── resources/
│ ├── views/
│ ├── layouts/
│ ├── default.blade.php
│ ...
```
Every theme must include at least one layout file, typically named:
```
default.blade.php
```
## Core Responsibilities of a Layout
* **Render the page structure** (HTML skeleton, head, body).
* **Include regions** for shared areas (header, footer) using `@visualRegion()`.
* **Define placeholders** for dynamic template content.
* **Load styles and scripts** correctly.
## Minimal Required Layout
At minimum, every layout must include:
* `@stack('styles')` inside `` — to inject page-specific styles.
* `@visual_layout_content` inside `` — where template and section content is rendered.
* `@stack('scripts')` at the bottom of `` — to inject page-specific scripts.
Here's a minimal working example:
```blade
@stack('styles')
{{-- Header region (shared across all pages) --}}
@visualRegion('header')
{{-- Page-specific template content --}}
@visual_layout_content
{{-- Footer region (shared across all pages) --}}
@visualRegion('footer')
@stack('scripts')
```
### `@stack('styles')`
The `@stack('styles')` directive is used to inject **page-specific CSS styles** into the `` section of your layout.
* Templates and sections can push additional styles to this stack using `@push('styles')`.
* This allows different pages to include their own CSS without modifying the layout manually.
### `@stack('scripts')`
The `@stack('scripts')` directive is used to inject page-specific JavaScript at the end of the `` tag.
* Templates and sections can push additional JavaScript to this stack using `@push('scripts')`.
* This ensures scripts are loaded after the page content, improving performance and avoiding blocking issues.
### `@visual_layout_content`
The `@visual_layout_content` directive is a Bagisto Visual special directive that renders the content of the selected template.
* It dynamically outputs the page's sections based on the currently active template (e.g., homepage, product page).
* Without @visual\_layout\_content, the storefront will not display the page-specific content.
Important: Every layout must include @visual\_layout\_content inside the `` (or equivalent) block.
### `@visualRegion()`
The `@visualRegion()` directive renders a region template (e.g., header, footer) that is shared across all pages.
* Regions are customizable by merchants through the Visual Editor.
* Common regions include `header` and `footer`.
* Example: `@visualRegion('header')` renders the header region.
See [Regions](./regions.md) for detailed documentation on creating and using regions.
## Special Layout for Customer Accounts
Bagisto Visual optionally supports a special layout for customer account pages, named:
```
account.blade.php
```
This layout can be used to create a **cleaner, simplified structure** for customer-specific areas such as login, registration, dashboard, and order management.
> **Note:**
> Using `account.blade.php` is **optional**. If not provided, customer account pages will automatically fallback to the `default.blade.php` layout.
## Developer Flexibility
Developers are **free to create and use additional layouts** based on the needs of their project.
You can define layouts for specific purposes like checkout, landing pages, or other specialized flows — there are no restrictions.
Simply create the desired layout inside `/resources/views/layouts/` and extend it in your templates:
```blade
@extends('layouts.custom-layout')
```
---
---
url: /core-concepts/templates/overview.md
---
# Templates
Templates control **the structure and layout of individual pages** in a Bagisto Visual theme.
Each storefront page — such as the homepage, a product page, a cart page, or a category listing — is linked to a **template** that defines **what content to render** and **how to organize it**.
Templates act as **blueprints** for pages by specifying:
* Which **sections** appear.
* The **order** they appear in.
* How the page content is assembled.
## Key Characteristics
* **Each page type has an associated template.**
Templates define how the content of that page is structured.
* **Templates use Blade, JSON, YAML, or PHP formats.**
Developers can choose between:
* **Blade templates** (`.blade.php`) for dynamic, code-driven pages.
* **JSON or YAML templates** (`.json`, `.yaml`) for lightweight, section-driven pages.
* **PHP templates** (`.visual.php`) for programmatic, type-safe section configurations.
* **Only one template is rendered per page.**
When a user navigates to a page, Bagisto Visual selects and renders the corresponding template.
* **Templates organize sections, not content directly.**
Sections provide the actual content and functionality.
* **Templates are page-specific, regions are shared.**
Unlike [regions](../regions.md) (which are shared across all pages), templates define content for individual page types.
## Location of Templates
Templates are stored inside the following directory:
```plaintext
/theme/
└── resources/
└── views/
└── templates/
```
Example:
```plaintext
/templates/
├── index.blade.php # Homepage template (Blade)
├── product.visual.php # Product page (PHP)
├── product/
│ └── gift-box.json # Custom product template
├── category.json # Category page (JSON)
├── category/
│ └── sale.yaml # Custom category template
├── cart.yaml # Cart page (YAML)
├── checkout.yaml # Checkout page (YAML)
├── page.yaml # CMS pages (YAML)
├── page/
│ └── landing.visual.php # Custom CMS page template
├── search.json # Search results page (JSON)
```
## Template Variants
Product, category, and CMS page templates can have custom variants. A variant is an alternate template for one resource type, such as `product.gift-box`, `category.sale`, or `page.landing`.
Variants are stored in type-first directories:
```plaintext
templates/product/gift-box.json
templates/category/sale.yaml
templates/page/landing.visual.php
```
Merchants can create variants in the Visual Editor and assign them to individual products, categories, or CMS pages from the Bagisto admin.
Learn more in [Custom Templates](./custom-templates.md).
## Template Format Comparison
| Format | Description | When to Use |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Blade** | Full Laravel Blade templates. Allow dynamic PHP, Livewire components, and advanced logic. **Blade templates cannot be customized or rearranged through the Theme Editor.** | Use Blade when you need maximum flexibility, dynamic behavior, or complex layouts. |
| **JSON/YAML** | Static templates that define a list of sections in order. **Sections can be added, removed, and reordered visually by merchants through the Theme Editor.** | Use JSON/YAML when you prefer simple text file syntax and direct editing. |
| **PHP** (`.visual.php`) | Interchangeable with JSON/YAML using `TemplateBuilder` API. Provides IDE support, type safety, and PHP features. **Fully compatible with Theme Editor like JSON/YAML.** | Use PHP templates when you want IDE autocomplete, type safety, and the ability to use PHP features like variables and loops. |
> \[!TIP]
>
> * **[JSON/YAML templates](./json-yaml.md)** - Simple syntax, edit directly in text files
> * **[PHP templates](./php-templates.md)** - Same result, but with IDE autocomplete, type safety, and PHP features
> * Both JSON/YAML and PHP formats are fully interchangeable and produce identical results in the Theme Editor
> * **Blade templates** are suited for pages with strict structure or advanced dynamic functionality
---
---
url: /core-concepts/templates/json-yaml.md
---
# JSON & YAML Templates
JSON and YAML templates define **how sections are organized on a page** in Bagisto Visual using a simple, declarative format.
Rather than coding in PHP, templates use a configuration file that lists sections, their settings, and their order. This allows **merchants** to **customize, add, remove, and reorder sections** easily through the **Theme Editor**.
::: tip Prefer PHP Syntax?
JSON/YAML and PHP templates are interchangeable - they produce identical results. PHP templates offer IDE autocomplete and type safety while maintaining the same functionality. See **[PHP Templates](./php-templates.md)**.
:::
## How JSON Templates Work
* **Each page** has a template that defines which **sections** appear and in what **order**.
* **Each section** can have:
* **Settings** (customizable fields for merchants).
* **Blocks** (repeatable, configurable pieces inside a section).
* The **Theme Editor** reads the template and lets merchants **visually control** the storefront layout.
## Template Structure
A JSON (or YAML) template contains:
* A **sections** object — defines the sections on the page.
* Each section can have **settings** (customizable properties) and **blocks** (reusable components).
* **Blocks can be nested** — container blocks (Columns, Tabs, Accordion) can contain other blocks, enabling deep nesting and complex page builder-style layouts.
* An **order** array — determines the order sections are rendered.
Example basic structure:
:::: tabs
::: tab JSON
```json
{
"sections": {
"hero": {
"type": "visual-hero",
"settings": {
"image": "https://example.com/banner.jpg",
"size": "medium"
}
}
},
"order": ["hero"]
}
```
:::
::: tab YAML
```yaml
sections:
hero:
type: visul-hero
settings:
image: https://example.com/banner.jpg
size: medium
order:
- hero
```
:::
::::
## Example: Full Home Page Template
:::: tabs
::: tab JSON
```json
{
"sections": {
"hero": {
"type": "visual-hero",
"settings": {
"image": "https://images.unsplash.com/photo-1441984904996-e0b6ba687e04",
"size": "medium"
},
"blocks": {
"heading": {
"type": "heading",
"settings": {
"heading": "Talk about your brand"
}
},
"text": {
"type": "subheading",
"settings": {
"subheading": "Share details about your store"
}
},
"button": {
"type": "button",
"settings": {
"text": "Browse store",
"link": "/",
"style": "secondary"
}
}
}
},
"category-list": {
"type": "visual-category-list",
"settings": {
"heading": "Shop by category"
},
"blocks": {
"category-1": {
"type": "category",
"settings": {
"category": 2
}
},
"category-2": {
"type": "category",
"settings": {
"category": 3
}
}
}
},
"featured-products": {
"type": "visual-featured-products",
"settings": {
"heading": "Featured products",
"product_type": "featured",
"nb_products": 4
}
},
"newsletter": {
"type": "visual-newsletter"
}
},
"order": ["hero", "category-list", "featured-products", "newsletter"]
}
```
:::
::: tab YAML
```yaml
sections:
hero:
type: visual-hero
settings:
image: https://images.unsplash.com/photo-1441984904996-e0b6ba687e04
size: medium
blocks:
heading:
type: heading
settings:
heading: Talk about your brand
text:
type: subheading
settings:
subheading: Share details about your store
button:
type: button
settings:
text: Browse store
link: /
style: secondary
category-list:
type: visual-category-list
settings:
heading: Shop by category
blocks:
category-1:
type: category
settings:
category: 2
category-2:
type: category
settings:
category: 3
featured-products:
type: visual-featured-products
settings:
heading: Featured products
product_type: featured
nb_products: 4
newsletter:
type: visual-newsletter
order:
- hero
- category-list
- featured-products
- newsletter
```
:::
::::
## Section Schema
Each section object inside a template follows this structure:
:::: tabs
::: tab JSON
```json
{
: {
"type": ,
"settings": {
:
},
"blocks": {
: {
"type": ,
"settings": {
:
},
"blocks": {
: {
"type": ,
"settings": { ... }
}
},
"order": []
}
},
"order": []
}
}
```
:::
::: tab YAML
```yaml
:
type:
settings:
:
...
blocks:
:
type:
settings:
:
...
blocks:
:
type:
settings: ...
order: []
order: []
```
:::
::::
### Description of fields:
| Field | Required | Description |
| ------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| **\** | - | Unique ID or handle used in the template (e.g., `hero`, `category-list`). |
| **\** | Yes | Slug of the section to render (e.g., `visual-hero`, `visual-featured-products`). |
| **\** | - | Unique ID of the block |
| **\** | Yes | Type of the block to render as defined in the section's `accepts` property |
| **\** | No | An array of block IDs defining render order. Can be used at section level (for blocks) or block level (for nested blocks). |
| **\** | - | Unique ID of a nested block inside another block |
| **\** | Yes | Type of the nested block |
| **\** | - | ID of the settings defined in the section/block settings config |
| **\** | - | Value of the setting (can use dynamic sources with `@` prefix) |
> \[!NOTE]
> Blocks are optional, not all sections need to have blocks.
## Dynamic Sources in Templates
Setting values can use **dynamic sources** to resolve from runtime context using the `@path.to.value` syntax:
:::: tabs
::: tab JSON
```json
{
"sections": {
"product-hero": {
"type": "@awesome-theme/product-hero",
"settings": {
"productName": "@product.name",
"price": "@product.price",
"image": "@product.base_image.url",
"description": "@product.description"
}
}
},
"order": ["product-hero"]
}
```
:::
::: tab YAML
```yaml
sections:
product-hero:
type: '@awesome-theme/product-hero'
settings:
productName: '@product.name'
price: '@product.price'
image: '@product.base_image.url'
description: '@product.description'
order:
- product-hero
```
:::
::::
The `@` prefix enables templates to access:
* **Page context** - Variables passed from controllers (e.g., `$product`, `$category`)
* **Model properties** - Using dot notation (e.g., `@product.base_image.url`)
* **Nested data** - Deep property access (e.g., `@post.author.name`)
This is particularly useful when creating templates for dynamic pages like product details, category pages, or blog posts where content comes from the database.
**Learn more:** [Dynamic Sources](/core-concepts/dynamic-sources)
> \[!NOTE]
> Container blocks (Columns, Tabs, Accordion) can have their own `blocks` object containing nested blocks. This structure is recursive - nested blocks can also contain blocks, enabling deep nesting for complex page builder-style layouts.
## Order
The `order` array defines **in which sequence** sections/blocks are displayed on the page.
* If a section/block is missing from the `order`, it **won't be rendered**.
* If `order` is not defined, Bagisto Visual will automatically use the default order of the sections/blocks as they appear in the `sections` object.
* If `order` is defined, it strictly controls the rendering sequence
> \[!TIP]
> Defining an order manually is still recommended for better clarity, flexibility, and merchant control inside the Theme Editor.
## Working with the Theme Editor
When merchants open the Theme Editor:
* They can **rearrange sections** listed in `order`.
* They can **edit section settings**.
* They can **add, remove, and reorder blocks** within sections.
* They can **edit block settings** for each individual block.
* They can **nest blocks** inside container blocks (Columns, Tabs, Accordion) by adding blocks to those containers.
* They can **rearrange nested blocks** to create custom layouts.
This gives merchants **complete control** over the page structure and layout without touching code, from high-level sections down to deeply nested blocks.
## Best Practices
* **Always define an `order`** matching your sections.
* **Use clear section names**.
* **Use settings and blocks** to maximize flexibility for merchants.
* **Prefer YAML** for better manual editing readability when templates grow.
* **For complex templates**, consider using [PHP Templates](./php-templates.md) for IDE support.
## Next Steps
* **[PHP Templates](./php-templates.md)** - Programmatic alternative with IDE support
* **[Template Overview](./overview.md)** - Compare all template formats
* **[Available Templates](./available.md)** - See all default page templates
* **[Adding Sections](../../building-theme/adding-sections/overview.md)** - Learn to create sections
---
---
url: /core-concepts/templates/php-templates.md
---
# PHP Templates
PHP templates (`.visual.php`) provide a **programmatic, type-safe, IDE-friendly alternative** to JSON and YAML templates. They use the `TemplateBuilder` fluent API to define page structure while maintaining full compatibility with the Theme Editor.
::: tip Alternative to JSON/YAML
PHP templates are a **first-class alternative** to JSON/YAML templates, not a replacement. Choose the format that best fits your workflow:
* **JSON/YAML**: Simple, declarative, designer-friendly → [Learn more](./json-yaml.md)
* **PHP**: Programmatic, IDE support, developer-friendly
:::
## Why Use PHP Templates?
PHP templates offer developer-focused benefits while producing the same merchant-editable result as JSON/YAML:
✅ **IDE Autocomplete** - Full IntelliSense support
✅ **Type Safety** - Catch errors at development time
✅ **PHP Features** - Use variables, loops, conditionals
✅ **Preset Classes** - Import and use preset classes directly
✅ **Refactoring** - Easy to rename, move, and organize
✅ **Comments** - Document complex logic inline
✅ **Theme Editor Compatible** - Merchants can still customize everything visually
## Quick Comparison
Here's the same template in JSON and PHP:
:::: tabs
::: tab JSON
```json
{
"sections": {
"hero": {
"type": "visual-hero",
"settings": {
"image": "https://example.com/hero.jpg",
"size": "large"
}
},
"newsletter": {
"type": "visual-newsletter"
}
},
"order": ["hero", "newsletter"]
}
```
:::
::: tab PHP
```php
section('hero', 'visual-hero', fn($section) => $section
->settings([
'image' => 'https://example.com/hero.jpg',
'size' => 'large',
])
)
->section('newsletter', 'visual-newsletter')
->order(['hero', 'newsletter']);
```
:::
::::
Both produce identical results in the Theme Editor. PHP provides better IDE support and type safety.
## Basic Structure
PHP templates return a `TemplateBuilder` instance configured with sections and their order:
```php
section('', '')
->section('', '', fn($section) => $section
->settings([...])
->blocks([...])
)
->order(['', '']);
```
## TemplateBuilder API
The `TemplateBuilder` class provides these methods:
| Method | Description |
| ------------------------------------------------------------- | ------------------------------------------- |
| `make()` | Create a new template builder instance |
| `section(string $id, string $type, ?callable $config = null)` | Add a section to the template |
| `order(array $order)` | Define the rendering order of sections |
| `id(string $id)` | Set region ID (for header/footer regions) |
| `name(string $name)` | Set region name (for header/footer regions) |
**Section configuration callback** receives a `BlockBuilder` instance with:
| Method | Description |
| ------------------------------- | ------------------------------- |
| `settings(array $settings)` | Set section settings/properties |
| `blocks(array $blocks)` | Add child blocks to the section |
## Example: Simple Homepage
```php
section('hero', 'visual-hero', fn($section) => $section
->settings([
'image' => 'https://example.com/hero.jpg',
'size' => 'large',
])
)
->section('featured-products', 'visual-featured-products', fn($section) => $section
->settings([
'heading' => 'Featured Products',
'nb_products' => 8,
])
)
->section('newsletter', 'visual-newsletter')
->order(['hero', 'featured-products', 'newsletter']);
```
## Using Preset Classes
PHP templates can directly reference preset classes, making configuration reusable and type-safe:
```php
section('hero-banner', HeroBanner::class)
->section('category-list', CategoryGrid::class)
->section('newsletter', 'visual-newsletter')
->order(['hero-banner', 'category-list', 'newsletter']);
```
::: tip Learn More About Presets
See [Presets documentation](../presets.md) to learn about creating standalone preset classes that can be reused across templates.
:::
## Adding Blocks to Sections
Use `PresetBlock` to define child blocks within sections:
```php
section('hero', 'visual-hero', fn($section) => $section
->settings([
'layout' => 'centered',
'padding' => 'large',
])
->blocks([
PresetBlock::make('heading')
->id('hero-title')
->settings([
'text' => 'Welcome to Our Store',
'level' => 1,
]),
PresetBlock::make('paragraph')
->id('hero-text')
->settings([
'text' => 'Discover amazing products',
]),
PresetBlock::make('button')
->id('hero-cta')
->settings([
'text' => 'Shop Now',
'style' => 'primary',
])
->static(), // Lock from editing
])
)
->order(['hero']);
```
## Advanced: Nested Blocks
PresetBlock supports deep nesting with the `->children()` method:
```php
PresetBlock::make('container')
->id('feature-grid')
->settings(['layout' => 'grid', 'columns' => 3])
->children([
PresetBlock::make('container')
->children([
PresetBlock::make('icon')->settings(['icon' => 'star']),
PresetBlock::make('heading')->settings(['text' => 'Quality']),
]),
PresetBlock::make('container')
->children([
PresetBlock::make('icon')->settings(['icon' => 'truck']),
PresetBlock::make('heading')->settings(['text' => 'Fast Shipping']),
]),
]),
```
## Example: Product Page Template
```php
section('breadcrumbs', 'visual-breadcrumbs')
->section('product-info', 'visual-product-information', fn($section) => $section
->settings([
'section_width' => 'container',
'media_position' => 'left',
'gap' => 8,
])
->blocks([
PresetBlock::make('product-media-gallery')
->id('media')
->static()
->settings([
'aspect_ratio' => 'adapt',
'zoom' => true,
]),
PresetBlock::make('product-details')
->id('details')
->static()
->children([
PresetBlock::make('product-title')->id('title'),
PresetBlock::make('product-price')->id('price'),
PresetBlock::make('product-variant-picker')->id('variants'),
PresetBlock::make('product-buy-buttons')->id('buy-buttons'),
]),
])
)
->section('product-reviews', 'visual-product-reviews')
->order(['breadcrumbs', 'product-info', 'product-reviews']);
```
## Using PHP Features
PHP templates can leverage PHP's full power for dynamic configuration:
### Variables and Loops
```php
PresetBlock::make('category')
->id("category-{$id}")
->settings(['category' => $id]),
$featuredCategories
);
return TemplateBuilder::make()
->section('categories', 'visual-category-list', fn($section) => $section
->settings(['heading' => 'Shop by Category'])
->blocks($categoryBlocks)
)
->order(['categories']);
```
### Conditionals
```php
section('hero', 'visual-hero');
// Add promotional banner only during sales
if (config('store.sale_active')) {
$builder->section('promo-banner', 'visual-promo-banner');
}
$builder->section('products', 'visual-product-list');
return $builder->order(['hero', 'promo-banner', 'products']);
```
### Helper Functions
```php
id($id)
->children([
PresetBlock::make('icon')->settings(['icon' => $icon]),
PresetBlock::make('heading')->settings(['text' => $title]),
PresetBlock::make('paragraph')->settings(['text' => $text]),
]);
}
return TemplateBuilder::make()
->section('features', 'visual-features', fn($section) => $section
->blocks([
createFeatureBlock('fast-ship', 'truck', 'Fast Shipping', '2-3 day delivery'),
createFeatureBlock('secure', 'shield', 'Secure Payment', 'Your data is safe'),
createFeatureBlock('support', 'headset', '24/7 Support', 'Always here to help'),
])
)
->order(['features']);
```
## Choosing Between PHP and JSON/YAML
Both formats are fully interchangeable and produce identical results. Choose based on your **editing experience preference**:
| Choose PHP Templates When You Want | Choose JSON/YAML When You Want |
| ------------------------------------- | ------------------------------- |
| IDE autocomplete and IntelliSense | Simple text file editing |
| Type safety and error checking | Direct, minimal syntax |
| To use PHP variables and loops | Quick manual editing |
| To reference preset classes directly | No PHP knowledge required |
| Code refactoring tools | Lightweight configuration files |
| Inline PHP comments and documentation | Visual, declarative structure |
| Working in PhpStorm/VSCode with PHP | Editing in any text editor |
**Both formats:**
* ✅ Are fully customizable by merchants in the Theme Editor
* ✅ Support sections, blocks, settings, and all features
* ✅ Generate the same output
* ✅ Allow the same level of merchant control
## Migrating from JSON/YAML
To convert a JSON/YAML template to PHP:
1. **Create new `.visual.php` file** with same name
2. **Import TemplateBuilder**
3. **Convert sections** to `->section()` calls
4. **Convert settings** to `->settings()` arrays
5. **Convert blocks** to `PresetBlock::make()` calls
6. **Add `->order()` at the end**
Example migration:
:::: tabs
::: tab Before (JSON)
```json
{
"sections": {
"hero": {
"type": "visual-hero",
"settings": {
"size": "large"
},
"blocks": {
"title": {
"type": "heading",
"settings": {
"text": "Welcome"
}
}
}
}
},
"order": ["hero"]
}
```
:::
::: tab After (PHP)
```php
section('hero', 'visual-hero', fn($section) => $section
->settings(['size' => 'large'])
->blocks([
PresetBlock::make('heading')
->id('title')
->settings(['text' => 'Welcome']),
])
)
->order(['hero']);
```
:::
::::
## Next Steps
* **[JSON & YAML Templates](./json-yaml.md)** - Learn about the declarative alternative
* **[Template Overview](./overview.md)** - Compare all template formats
* **[Presets](../presets.md)** - Create reusable preset classes for templates
* **[Available Templates](./available.md)** - See all default page templates
---
---
url: /core-concepts/templates/available.md
---
# Available Templates
Templates define the structure and behavior of pages in Bagisto Visual storefronts.
Each template determines:
* Which sections appear on the page
* Which data is available to sections
* How customers interact with the store
Bagisto Visual uses a flexible system where templates can be built with **Blade**, **JSON**, or **YAML** formats.
Each template may automatically expose **some variables** (like `$product`, `$category`, `$order`) to the sections it loads, making it easy to create dynamic, data-driven content.
## About This Page
This page documents:
* All available default templates provided by Bagisto Visual
* The variables each template shares with its sections
* Where templates are located in the theme directory
* Example usage of shared variables in Blade sections
## cart
The **Cart Template** displays the contents of a customer's shopping cart.
It is used to show the list of products that the customer has added to their cart, along with quantities, totals, and checkout options.
### Location
```plaintext
/theme/resources/views/templates/cart.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ---------- | ----------------------------------- |
| $cart | Cart model | The current shopping cart instance. |
### Example
Example inside a section Blade file:
```blade
@if (isset($cart))
@endif
```
## category
The **Category Template** is used to display a list of products belonging to a specific category.
It typically includes features like filters, sorting options, product grids, and category banners.
Category templates support custom variants such as `category.sale`. Custom category templates receive the same `$category` variable as the default category template.
### Location
```plaintext
/theme/resources/views/templates/category.json
```
### Shared variables
| Variable | Type | Description |
| --------- | -------------- | ------------------------------------- |
| $category | Category model | The currently viewed category object. |
### Example
Example inside a section Blade file:
```blade
@if (isset($category))
{{ $category->name }}
{{ $category->description }}
@endif
```
## checkout-success
The **Checkout Success Template** displays the order confirmation page after a successful checkout.
It shows the customer a summary of their completed order and any next steps or messages.
### Location
```plaintext
/theme/resources/views/templates/checkout-success.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ----------- | ----------------------------------- |
| $order | Order model | The recently placed order instance. |
### Example
Example inside a section Blade file:
```blade
@if (isset($order))
@endif
```
## checkout
The **Checkout Template** is used to display the checkout process, including customer information, shipping, and payment details.
It typically shows a summary of the cart and allows customers to complete their purchase.
### Location
```plaintext
/theme/resources/views/templates/checkout.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ---------- | ----------------------------------- |
| $cart | Cart model | The current shopping cart instance. |
### Example
Example inside a section Blade file:
```blade
@if (isset($cart))
@endif
```
## compare
The **Compare Template** is used to display a side-by-side comparison of selected products.
It allows customers to view product attributes and differences to help them make purchasing decisions.
### Location
```plaintext
/theme/resources/views/templates/compare.json
```
### Shared variables
| Variable | Type | Description |
| --------------------- | ----- | -------------------------------------------- |
| $comparableAttributes | array | Attributes available for product comparison. |
### Example
Example inside a section Blade file
```blade
@if (!empty($comparableAttributes))
Compare Products By:
@foreach ($comparableAttributes as $attribute)
{{ $attribute['name'] }}
@endforeach
@endif
```
## error
The **Error Template** is used to display an error page when something goes wrong.
It shows an error message and error code based on what occurred (e.g., 404 not found, 500 server error).
### Location
```plaintext
/theme/resources/views/templates/error.blade.php
```
### Shared variables
| Variable | Type | Description |
| ---------- | ------- | -------------------- |
| $errorCode | integer | The HTTP error code. |
### Example
```blade
@if (isset($errorCode))
Error {{ $errorCode }}
Sorry, something went wrong.
@endif
```
## index
The **Index Template** is used to display the homepage of the storefront.
It typically features banners, featured collections, featured products, and custom landing page content.
### Location
```plaintext
/theme/resources/views/templates/index.yaml
```
### Shared variables
There are **no specific shared variables** automatically passed to sections in the index template.
Sections are responsible for fetching and displaying the homepage content themselves.
### Example
Since no variable is automatically exposed, a typical section might look like:
```blade
Welcome to our Store!
```
## page
The **Page Template** is used to render CMS pages created from the admin panel.
It displays static content like About Us, Contact, Terms, or any custom page.
CMS page templates support custom variants such as `page.landing`. Custom page templates receive the same `$page` variable as the default page template.
### Location
```plaintext
/theme/resources/views/templates/page.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ------------ | -------------------------- |
| $page | `Page` model | The CMS page being viewed. |
### Example
Example inside a section Blade file:
```blade
@if (isset($page))
{{ $page->title }}
{!! $page->content !!}
@endif
```
## product
The **Product Template** is used to display the details of a single product.
It includes the product title, description, images, price, reviews, and add-to-cart functionality.
Product templates support custom variants such as `product.gift-box`. Custom product templates receive the same `$product` variable as the default product template.
### Location
```plaintext
/theme/resources/views/templates/product.json
```
### Shared variables
| Variable | Type | Description |
| -------- | --------------- | ----------------------------------- |
| $product | `Product` model | The product currently being viewed. |
### Example
Example inside a section Blade file:
```blade
@if (isset($product))
{{ $product->name }}
{{ $product->short_description }}
Price: {{ core()->currency($product->price) }}
@endif
```
## search
The **Search Template** is used to display search results based on a customer’s query.
It renders product listings that match keywords, tags, categories, or other filters.
### Location
```plaintext
/theme/resources/views/templates/search.json
```
### Shared variables
There are **no specific shared variables** exposed automatically by the search template.
Sections should retrieve search results using request query parameters or internal APIs.
### Example
A simple section might handle search results like this:
```blade
@php
$query = request()->get('term');
@endphp
Results for "{{ $query }}"
@livewire('search-results', ['term' => $query])
```
## auth/forgot-password
The **Forgot Password Template** displays a form that allows users to request a password reset link.
It is typically accessed from the login page if a user forgets their credentials.
### Location
```plaintext
/theme/resources/views/templates/auth/forgot-password.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
```blade
Forgot your password?
```
## auth/login
The **Login Template** displays the customer login form.
It allows users to enter their email and password to access their account.
### Location
```plaintext
/theme/resources/views/templates/auth/login.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example section for the login form:
```blade
Customer Login
```
## auth/register
The **Register Template** displays the customer registration form.
It allows new users to create an account by providing personal and login information.
### Location
```plaintext
/theme/resources/views/templates/auth/register.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example registration form inside a section:
```blade
Create an Account
```
## auth/reset-password
The **Reset Password Template** displays a form to allow users to reset their password after receiving a reset link.
This page is accessed via the password reset email sent from the Forgot Password flow.
### Location
```plaintext
/theme/resources/views/templates/auth/reset-password.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example form inside a section:
```blade
Reset Your Password
```
## account/add-address
The **Add Address Template** displays a form that allows customers to add a new address to their account.
It typically includes fields for name, address, city, country, and contact information.
### Location
```plaintext
/theme/resources/views/templates/account/add-address.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example form inside a section:
```blade
Add New Address
```
## account/addresses
The **Addresses Template** displays a list of all addresses saved by a customer in their account.
It allows customers to view, edit, or delete their saved addresses.
### Location
```plaintext
/theme/resources/views/templates/account/addresses.blade.php
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example section to list addresses:
```blade
My Addresses
@foreach (auth('customer')->user()->addresses as $address)
@endforeach
```
## account/downloadables
The **Downloadables Template** displays a list of downloadable products that a customer has purchased.
It allows customers to download digital files like e-books, software, or media after purchase.
### Location
```plaintext
/theme/resources/views/templates/account/downloadables.yaml
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example section for listing downloadable items
```blade
My Downloadable Products
@foreach (auth('customer')->user()->downloadable_products as $download)
@endforeach
```
## account/edit-address
The **Edit Address Template** displays a form that allows customers to update an existing address saved in their account.
### Location
```plaintext
/theme/resources/views/templates/account/edit-address.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | --------------- | ---------------------------------- |
| $address | `Address` model | The address instance being edited. |
### Example
Example section for editing an address:
```blade
Edit Address
```
## account/edit-profile
The **Edit Profile Template** displays a form that allows customers to update their personal account information, such as name, gender, date of birth, and email.
### Location
```plaintext
/theme/resources/views/templates/account/edit-profile.yaml
```
### Shared variables
There are **no special shared variables** passed directly into this template.
> Sections are expected to use `auth('customer')->user()` to retrieve and update the authenticated customer's data.
### Example
Example section for editing profile:
```blade
Edit Profile
```
## account/order-details
The **Order Details Template** displays the complete details of a specific customer order.
It shows the order items, shipping address, billing address, totals, and current status.
### Location
```plaintext
/theme/resources/views/templates/account/order-details.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ------------- | ---------------------------- |
| $order | `Order` model | The customer's order object. |
### Example
Example section to display order information:
```blade
Order #{{ $order->id }}
Order Date: {{ $order->created_at->format('M d, Y') }}
```
## accounts/orders
The **Orders Template** displays a list of all past orders placed by the customer.
Customers can view order summaries and access order details pages from here.
It typically uses a datagrid component to render the list dynamically, including pagination, filtering, and view links.
### Location
```plaintext
/theme/resources/views/templates/account/orders.yaml
```
### Shared variables
There are **no shared variables** exposed by this template.
> Customer orders are typically listed using bagisto datagrid component or retrieved inside sections manually.
### Example
Example section for embedding a datagrid component
```blade
My Orders
```
Or a minimal manual fetch:
```blade
My Orders
@foreach (auth('customer')->user()->orders as $order)
Order #{{ $order->id }} placed on {{ $order->created_at->format('M d, Y') }}
@endforeach
```
## account/profile
The **Profile Template** displays the customer's personal information such as name, email, and contact details.
It also typically provides options to update profile information or change the password.
### Location
```plaintext
/theme/resources/views/templates/account/profile.yaml
```
### Shared variables
There are **no shared variables** exposed by this template.
> Sections are expected to use `auth('customer')->user()` to access the currently authenticated customer's profile information.
### Example
Example section to display the customer profile:
```blade
Edit Profile
```
## account/reviews
The **Reviews Template** displays all product reviews submitted by the customer.
It shows the products reviewed, ratings given, and review comments.
### Location
```plaintext
/theme/resources/views/templates/account/reviews.yaml
```
### Shared variables
| Variable | Type | Description |
| -------- | ---------------------------- | ---------------------------------------------- |
| $reviews | Collection of `Review` model | The list of reviews submitted by the customer. |
### Example
Example section to list customer reviews:
```blade
My Reviews
@foreach ($reviews as $review)
{{ $review->product->name }}
Rating: {{ $review->rating }} / 5
{{ $review->comment }}
@endforeach
```
## account/wishlist
The **Wishlist Template** displays the products that a customer has added to their wishlist.
Customers can view, manage, and move wishlist items to the cart.
### Location
```plaintext
/theme/resources/views/templates/account/wishlist.yaml
```
### Shared variables
There are **no shared variables** exposed by this template.
### Example
Example section to display wishlist items:
```blade
My Wishlist
@foreach (auth('customer')->user()->wishlist_items as $item)
@endforeach
```
---
---
url: /core-concepts/templates/custom-templates.md
---
# Custom Templates
Custom templates let merchants create alternate layouts for products, categories, and CMS pages, then assign those layouts to individual resources from the Bagisto admin.
For example, a store can use the default product template for most products, but assign a custom Gift Box template to products that need a different layout.
## Supported Types
Custom templates are supported for:
* `product`
* `category`
* `page`
## Theme Files
Developers can ship custom templates with a theme by placing them in a type-first directory:
```text
resources/views/templates/
├── product/
│ └── gift-box.json
├── category/
│ └── sale.yaml
└── page/
└── landing.visual.php
```
Supported data template extensions are:
* `.json`
* `.yaml`
* `.yml`
* `.visual.php`
The default product, category, or CMS page template can live either at the root of `templates` or as `index` inside the type directory:
```text
resources/views/templates/page.yaml
resources/views/templates/page/index.yaml
```
The same pattern applies to `product` and `category`.
## Creating Templates In The Editor
Open the template selector in the Visual Editor, then open the variant panel for Products, Categories, or Pages.

The variant panel shows:
* The default template for that type.
* Existing custom templates for that type.
* A **Create template** action.
The create modal asks for a template name and a base template.

Creation options:
* **Empty template** starts with an empty main content area.
* **Default product/category/page** starts from the default template when the theme provides editable template data for that type.
* Existing templates can be duplicated as a starting point.
Shared regions, such as the header and footer, stay shared across templates.
## Assigning Templates
Template assignment is optional. Enable it with `BAGISTO_VISUAL_TEMPLATE_ASSIGNMENTS=true` and run `php artisan migrate` before assigning custom templates in the Bagisto admin.
After a custom template is published, assign it from the relevant Bagisto admin form.

Assignment behavior:
| Resource | Admin location | Behavior |
| -------- | ------------------------ | ------------------------------ |
| Product | General panel | Can vary by channel and locale |
| Category | Theme template accordion | Can vary by locale |
| CMS page | Theme template accordion | Can vary by locale |
Empty/default assignment means the resource uses the default template for its type.
CMS pages with a valid assigned custom page template also show shortcuts to open that page directly in the Visual Editor.
## Storefront Behavior
On the storefront, Bagisto Visual renders the assigned custom template when the resource has one. Otherwise it falls back to the default product, category, or CMS page template.
In the editor, you can preview a custom template before assigning it to a resource.
## Limitations
* Custom templates are supported only for `product`, `category`, and `page`.
---
---
url: /core-concepts/sections.md
---
# Sections
Sections are **containers that compose blocks into cohesive layouts** on storefront pages. They define structure and accept blocks that provide the content.
Each section is built as a **PHP class** and paired with a **Blade view** for rendering.
## Sections vs Blocks
Understanding the relationship between sections and blocks is key to v2:
* **Blocks** are atomic, reusable components (buttons, images, testimonials)
* **Sections** are containers that arrange blocks into layouts (hero, product grid, features)
Think of blocks as LEGO bricks and sections as the base plates you build on.
## Why Sections Matter
* **For Developers**: Create flexible containers that accept and arrange blocks without hardcoding content.
* **For Merchants**: Build custom layouts by adding, removing, and arranging blocks within sections using the Theme Editor.
Sections empower merchants to build custom page layouts without code.
## Anatomy of a Section
A section consists of:
* A **view** - Blade template defining the section's layout structure
* **Settings** - Section-level configuration (colors, layout options, etc.)
* **Rendering logic** - How accepted blocks are arranged and displayed
Sections provide structure; blocks fill that structure with content.
## Section Directory Structure
```plaintext
/theme/
├── src/Sections/
│ ├── AnnouncementBar.php
│ ├── CategoryList.php
├── resources/views/sections/
│ ├── announcement-bar.blade.php
│ └── category-list.blade.php
```
* `src/Sections/` contains the PHP section classes.
* `resources/views/sections/` contains the corresponding Blade templates.
## Basic Section Example
### PHP Section Class
```php
namespace Themes\YourTheme\Sections;
use BagistoPlus\Visual\Section\SimpleSection;
use BagistoPlus\Visual\Settings\Text;
use BagistoPlus\Visual\Settings\Link;
use BagistoPlus\Visual\Settings\Color;
class AnnouncementBar extends SimpleSection
{
protected static string $view = 'shop::sections.announcement-bar';
public static function settings(): array
{
return [
Text::make('text', 'Banner text')
->default('Welcome to our store!'),
Link::make('link', 'Banner link'),
Color::make('background_color', 'Background color')
->default('#4f46e5'),
Color::make('text_color', 'Text color')
->default('#ffffff'),
];
}
}
```
***
### Blade View Example
```blade
```
✅ A `$section` object representing the section is automatically injected into each Blade view. Setting values can be accessed via `$section->settings`.
---
---
url: /core-concepts/regions.md
---
# Regions
Regions are **customizable zones shared across all templates** in your theme. They allow merchants to fully control shared areas like headers and footers through the Visual Editor—adding, removing, and rearranging sections without touching code.
## What Are Regions?
Regions are layout zones where sections can be placed and rendered. Think of them as placeholders in your layouts that can contain one or more sections. Common examples include:
* **Header** - Site navigation, logo, search, cart preview
* **Footer** - Company info, links, newsletter signup
Unlike page-specific templates, regions are **shared across your entire store**. When a merchant customizes the header region, those changes appear on every page that includes the header.
## Why Regions Matter
### The Problem with v1 (Single Static Section)
In Visual v1, shared elements like headers and footers were **single sections** that merchants could customize in the Visual Editor. However:
* Merchants could only configure the **one header section** provided by the developer
* They couldn't **add additional sections** to the header/footer zones (e.g., announcement bar above header)
* They couldn't **remove or reorder** multiple sections in these zones
* Adding new elements required a developer to modify the header section code
**Example v1 limitation**: If a merchant wanted to add a promotional announcement bar above the header, they needed a developer to either add it to the existing header section code or create a custom solution.
### The v2 Solution (Customizable Regions)
Regions make shared areas **fully customizable** through the Visual Editor by allowing **multiple sections** in header/footer zones. Merchants can:
* ✅ Add new sections to the header or footer region (announcement bars, promotional banners, etc.)
* ✅ Remove or hide existing sections
* ✅ Reorder sections visually within the region
* ✅ Configure each section's settings independently
* ✅ Create multiple header/footer variations
**Same example in v2**: Merchants can simply add an announcement bar section to the header region themselves—no code required. The header region can contain multiple sections that merchants manage.
## Region Structure
Each region has the following structure:
```json
{
"id": "header", // Required unique identifier (used in @visualRegion('header'))
"name": "Header", // Required display name (shown in editor)
"sections": { // Sections in this region
"announcement": {
"type": "visual-announcement-bar",
"settings": { ... }
},
"main-header": {
"type": "visual-header",
"settings": { ... },
"blocks": { ... },
"order": [ ... ]
}
},
"order": ["announcement", "main-header"] // Section render order
}
```
**Properties:**
| Property | Required | Description | Example |
| -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| **`id`** | Yes | Unique identifier used in the `@visualRegion('id')` directive to render the region | `"header"`, `"footer"` |
| **`name`** | Yes | Display name shown in the Visual Editor | `"Site Header"`, `"Main Footer"` |
| **`sections`** | No | Object containing sections that belong to this region. Each section follows the same structure as sections in templates (with `type`, `settings`, `blocks`, and `order` properties). See [Templates](./templates/overview.md) | See examples below |
| **`order`** | No | Array of section IDs defining render order. If not defined, sections are rendered in the order they appear in the `sections` object. | `["announcement", "main-header"]` |
## Defining Regions
Regions use the same formats as templates: **JSON**, **YAML**, or **PHP**.
### Method 1: JSON Format
Create a region file in `resources/views/regions/`:
```json
// resources/views/regions/header.json
{
"id": "header",
"name": "Header",
"blocks": {
"announcement-bar": {
"type": "@visual-debut/announcement-bar"
},
"main-header": {
"type": "@visual-debut/header",
"properties": {
"content_width": "container"
}
}
},
"order": ["announcement-bar", "main-header"]
}
```
### Method 2: YAML Format
```yaml
# resources/views/regions/footer.yaml
id: footer
name: Footer
blocks:
newsletter:
type: '@visual-debut/newsletter'
properties:
heading: 'Stay Connected'
main-footer:
type: '@visual-debut/footer'
properties:
content_width: 'container'
order:
- newsletter
- main-footer
```
### Method 3: PHP Format
PHP templates provide IDE support and type safety:
```php
id('header')
->name('Header')
->section('announcement-bar', '@visual-debut/announcement-bar')
->section('main-header', '@visual-debut/header', fn($section) => $section
->properties([
'content_width' => 'container',
])
->blocks([
PresetBlock::make('@visual-debut/group')
->id('container-logo')
->name('Logo')
->blocks([
PresetBlock::make('@visual-debut/logo')->name('Logo'),
]),
PresetBlock::make('@visual-debut/group')
->id('container-nav')
->name('Navigation')
->blocks([
PresetBlock::make('@visual-debut/header-nav')->name('Navigation'),
]),
])
)
->order(['announcement-bar', 'main-header']);
```
> \[!NOTE]
> The region filename should match the `id` property. For example, a region with `"id": "header"` should be saved as `header.json`, `header.yaml`, or `header.visual.php`.
## Using Regions in Layouts
Include regions in your layout files using the `@visualRegion()` directive:
```blade
@include('shop::partials.head')
{{-- Header region (shared across all pages) --}}
@visualRegion('header')
{{-- Page-specific template content --}}
@section('body')
@visual_layout_content
@show
{{-- Footer region (shared across all pages) --}}
@visualRegion('footer')
```
The directive renders the customized region content that merchants configure in the Visual Editor.
## Best Practices
### When to Use Regions
✅ **Use regions for:**
* Elements that appear on multiple pages (header, footer)
* Store-wide announcements
* Shared sidebars or toolbars
* Elements merchants should control globally
❌ **Don't use regions for:**
* Page-specific content (use templates instead)
* One-off elements on a single page
* Content that varies by page type
### Naming Conventions
* **IDs**: Use lowercase with hyphens: `header`, `main-footer`
* **Names**: Use descriptive titles: `"Site Header"`, `"Main Footer"`
## Related Concepts
* **[Templates](./templates/overview.md)** - Page-specific structures (homepage, product page, etc.)
* **[Sections](./sections.md)** - Individual content blocks used in regions and templates
* **[PHP Templates](./templates/php-templates.md)** - Programmatic way to define regions with IDE support
---
---
url: /core-concepts/blocks.md
---
# Blocks
Blocks are **the fundamental building units** of Bagisto Visual themes. They are **reusable, configurable components** with configurable settings that can be shared across multiple sections, enabling merchants to build custom layouts without touching code.
Each block is built as a **PHP class** paired with a **Blade view** for rendering, similar to sections but designed for granular reusability.
## Why Blocks Matter
In v1, each section's repeatable content (like buttons, testimonials, or product cards) was scoped to that section alone. A button defined in your hero section couldn't be reused in your features section. This led to duplication and inconsistency.
**v2's blocks system changes this fundamentally:**
* **For Developers**: Create blocks once, use them everywhere. Build libraries of reusable components that work across all sections.
* **For Merchants**: Compose custom layouts by mixing and matching blocks in the theme editor. Build product cards, hero sections, and entire pages from atomic building blocks.
Blocks transform Bagisto Visual from a customization tool into a **true page builder**.
## Blocks vs Sections
Understanding the distinction between blocks and sections is crucial:
| Aspect | Blocks | Sections |
| -------------------- | ----------------------------------------- | ------------------------------------------- |
| **Purpose** | Atomic, reusable components | Containers that compose blocks into layouts |
| **Scope** | Shared across multiple sections | Page-level or template-level containers |
| **Examples** | Button, Image, Product Title, Testimonial | Hero, Product Grid, Feature List, Footer |
| **Reusability** | Define once, use in many sections | Template-specific or globally available |
| **Merchant Control** | Add, remove, arrange within sections | Add, remove, arrange on pages |
| **Nesting** | Can contain other blocks (containers) | Contain blocks |
**Think of it this way**: Blocks are LEGO bricks, sections are the base plates you build on.
## Anatomy of a Block
A block consists of three main parts:
* **A view**: Responsible for displaying the content, typically built with Blade templates
* **Configurable settings**: Define how merchants can customize the block's appearance and behavior
* **Schema**: Defines the block's settings, presets, and whether it can accept child blocks (for container blocks)
## Block Directory Structure
```plaintext
/theme/
├── src/Blocks/
│ ├── Button.php
│ ├── Testimonial.php
│ ├── ProductTitle.php
│ └── Columns.php # Container block
├── resources/views/blocks/
│ ├── button.blade.php
│ ├── testimonial.blade.php
│ ├── product-title.blade.php
│ └── columns.blade.php
```
* `src/Blocks/` contains the PHP block classes
* `resources/views/blocks/` contains the corresponding Blade templates
## Basic Block Example
### PHP Block Class
```php
namespace Themes\YourTheme\Blocks;
use BagistoPlus\Visual\Block\SimpleBlock;
use BagistoPlus\Visual\Settings\Text;
use BagistoPlus\Visual\Settings\Link;
use BagistoPlus\Visual\Settings\Select;
class Button extends SimpleBlock
{
protected static string $view = 'shop::blocks.button';
public static function settings(): array
{
return [
Text::make('text', 'Button text')
->default('Click me'),
Link::make('url', 'Button URL'),
Select::make('style', 'Button style')
->options([
'primary' => 'Primary',
'secondary' => 'Secondary',
'outline' => 'Outline',
])
->default('primary'),
];
}
}
```
### Blade View Example
```blade
editor_attributes }} href="{{ $block->settings->url ?? '#' }}"
class="button button--{{ $block->settings->style }}">
{{ $block->settings->text }}
```
✅ A `$block` object is automatically injected into each Blade view. Settings can be accessed via `$block->settings`.
## Block Types
Bagisto Visual v2 provides three base block types:
### SimpleBlock
The most common block type. Basic blocks that can render HTML content directly or use Blade views. Most blocks extend `SimpleBlock`.
**Using a Blade view:**
```php
use BagistoPlus\Visual\Block\SimpleBlock;
class Button extends SimpleBlock
{
protected static string $view = 'shop::blocks.button';
public static function settings(): array
{
return [
// Settings configuration
];
}
}
```
**Rendering HTML directly:**
SimpleBlocks can also render HTML directly without a Blade view by implementing the `render()` method:
```php
use BagistoPlus\Visual\Block\SimpleBlock;
class Divider extends SimpleBlock
{
public function render(): string
{
return '';
}
}
```
### BladeBlock
Uses Blade components instead of Blade views. Blade components allow you to leverage component features like slots, component attributes, and encapsulated logic.
```php
use BagistoPlus\Visual\Block\BladeBlock;
class Card extends BladeBlock
{
protected static string $view = 'shop::blocks.card'; // Points to a Blade component
public static function settings(): array
{
return [
// Settings configuration
];
}
}
```
The difference is that the view is treated as a Blade component rather than a simple template.
### LivewireBlock
Blocks powered by Livewire for dynamic, interactive components.
```php
use BagistoPlus\Visual\Block\LivewireBlock;
class InteractiveBlock extends LivewireBlock
{
protected static string $component = 'shop.blocks.interactive-block';
// Livewire component methods
}
```
## Static Blocks
Static blocks enable theme developers to have more control over the layout of their sections. They are called static blocks because they are **statically rendered** in Blade instead of dynamically rendered through the theme editor.
By default, blocks are **dynamic** - merchants can add, remove, reorder, and duplicate them in the theme editor. Static blocks, however, are fixed in place by the developer.
**Static blocks can be used in various scenarios:**
* **Bring structure to the theme** - In cases where the theme design requires blocks that should not be moved or deleted by the merchant (e.g., a hero section title that must always appear, or an icon that must stay paired with text)
* **Conditionally render blocks** - Show or hide blocks based on settings or logic (e.g., display a promotional banner only when enabled)
* **Maintain layout control** - Ensure specific blocks remain in their intended positions
**In all cases, static blocks maintain the flexibility to customize the settings.** Merchants can't move or delete static blocks, but they can still configure their appearance, content, and behavior through the settings panel.
See [Static Blocks](/building-theme/adding-blocks/static-blocks) for implementation details.
## Container Blocks (Nesting)
Some blocks can **accept child blocks**, enabling deep nesting and sophisticated layouts. These are called **container blocks**.
**Examples of container blocks:**
* **Columns**: Multi-column layouts with blocks in each column
* **Tabs**: Tabbed content with blocks in each tab
* **Accordion**: Collapsible sections with blocks inside
* **Container**: Generic wrapper for grouping blocks
Merchants can nest blocks up to 8 levels deep, creating complex layouts like:
* Columns containing tabs, each tab containing images and testimonials
* Accordions with product blocks and buttons inside
* Multi-column hero sections with nested content
See [Container Blocks](/building-theme/adding-blocks/container-blocks) for implementation details.
## Next Steps
Ready to start working with blocks? Here's your learning path:
1. **[Creating a Block](/building-theme/adding-blocks/creating-block)**: Step-by-step guide to creating your first block
2. **[Block Attributes](/building-theme/adding-blocks/block-schema)**: Configure settings and nesting
3. **[Presets](/core-concepts/presets)**: Create quick-start templates for blocks
4. **[Static Blocks](/building-theme/adding-blocks/static-blocks)**: Render blocks in Blade templates
5. **[Container Blocks](/building-theme/adding-blocks/container-blocks)**: Build blocks that accept children
---
---
url: /core-concepts/presets.md
---
# Presets
Presets provide pre-configured templates for both blocks and sections, allowing merchants to quickly add common variations without manual configuration. Think of them as "starter templates" or "quick-start options" that appear in the theme editor.
You can define presets in two ways:
* **Inline**: Using the `presets()` method directly in your block/section class
* **Standalone**: Creating dedicated preset classes that extend `Preset`
## What Are Presets?
When merchants add a block or section in the Visual theme editor, they can choose from a list of **presets** - pre-configured variations with different settings, layouts, and child blocks already set up.

## Why Use Presets?
✅ **Faster setup** - Merchants get started quickly with sensible defaults
✅ **Better UX** - Guide merchants toward common patterns
✅ **Consistency** - Ensure brand-aligned variations
✅ **Discoverability** - Show what's possible with your blocks/sections
## Basic Presets
Define presets by overriding the presets() method:
```php
settings([
'text' => t('your-theme::presets.primary_cta.text'),
'style' => 'primary',
'size' => 'large',
]),
];
}
}
```
## Preset Structure
Each preset can have these properties:
| Property | Type | Description |
| ----------------- | ------ | ---------------------------------------------- |
| `name` | string | **Required**. Display name in theme editor |
| `description` | string | Optional description shown to merchants |
| `icon` | string | Icon identifier (e.g., `heroicon-o-star`) |
| `category` | string | Group presets into categories |
| `previewImageUrl` | string | URL to preview image |
| `settings` | array | Default settings values (block settings) |
| `children` | array | Default child blocks (for containers/sections) |
### Example
```php
use BagistoPlus\Visual\Support\Preset;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.alerts.success.name'))
->description(t('your-theme::presets.alerts.success.description'))
->icon('heroicon-o-check-circle')
->category(t('your-theme::presets.categories.alerts'))
->previewImageUrl('/images/presets/success-alert.png')
->settings([
'message' => t('your-theme::presets.alerts.success.message'),
'type' => 'success',
'dismissible' => true,
]),
Preset::make(t('your-theme::presets.alerts.error.name'))
->description(t('your-theme::presets.alerts.error.description'))
->icon('heroicon-o-x-circle')
->category(t('your-theme::presets.categories.alerts'))
->settings([
'message' => t('your-theme::presets.alerts.error.message'),
'type' => 'error',
'dismissible' => true,
]),
];
}
```
## Presets with Child Blocks
Sections and container blocks can include pre-configured child blocks in their presets:
### Section Preset with Child Blocks
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.hero_cta.name'))
->description(t('your-theme::presets.hero_cta.description'))
->icon('heroicon-o-photograph')
->category(t('your-theme::presets.categories.banners'))
->settings([
'layout' => 'centered',
'background_color' => '#4f46e5',
])
->blocks([
PresetBlock::make('heading')
->id('hero-title')
->settings([
'text' => t('your-theme::presets.hero_cta.heading'),
'level' => 1,
]),
PresetBlock::make('paragraph')
->id('hero-subtitle')
->settings([
'text' => t('your-theme::presets.hero_cta.subtitle'),
]),
PresetBlock::make('button')
->id('hero-cta')
->settings([
'text' => t('your-theme::presets.hero_cta.button'),
'style' => 'primary',
]),
]),
Preset::make(t('your-theme::presets.hero_signup.name'))
->description(t('your-theme::presets.hero_signup.description'))
->icon('heroicon-o-mail')
->category(t('your-theme::presets.categories.banners'))
->settings([
'layout' => 'centered',
])
->blocks([
PresetBlock::make('heading')
->settings(['text' => t('your-theme::presets.hero_signup.heading')]),
PresetBlock::make('paragraph')
->settings(['text' => t('your-theme::presets.hero_signup.subtitle')]),
PresetBlock::make('email-input'),
PresetBlock::make('button')
->settings(['text' => t('your-theme::presets.hero_signup.button')]),
]),
];
}
```
## PresetBlock API
When defining child blocks in presets, use `PresetBlock::make()`:
```php
use function BagistoPlus\Visual\t;
PresetBlock::make('button')
->id('unique-id') // Semantic ID
->name(t('your-theme::presets.blocks.button.name')) // Display name in editor
->settings([...]) // Block settings values
->static() // Lock from editing
->children([...]) // Nested child blocks
->order(['id1', 'id2']) // Rendering order
```
### Dynamic Sources in Presets
Settings values in presets can use **dynamic sources** to resolve from runtime context:
```php
PresetBlock::make('@awesome-theme/product-card')
->id('grid-card')
->static()
->settings([
'productName' => '@product.name', // Resolves from context
'price' => '@product.price',
'image' => '@product.base_image.url',
])
->children([
PresetBlock::make('@awesome-theme/product-image')
->settings([
'src' => '@product.base_image.url',
'alt' => '@product.name',
]),
PresetBlock::make('@awesome-theme/product-title')
->settings([
'text' => '@product.name',
'url' => '@product.url',
]),
])
```
The `@` prefix enables blocks to access:
* Page context (variables passed from controllers)
* Parent-shared data (via `share()` method)
* Model properties using dot notation
This is especially useful for static blocks that need to display different data based on loop context.
**Learn more:** [Dynamic Sources](/core-concepts/dynamic-sources)
### PresetBlock Methods
| Method | Description |
| ----------------- | ----------------------------------------- |
| `type(string)` | Block type (e.g., 'button', 'heading') |
| `id(string)` | Unique semantic ID for the block |
| `name(string)` | Custom display name in editor |
| `settings(array)` | Block settings values |
| `static(bool)` | Mark as static (non-editable by merchant) |
| `children(array)` | Nested child blocks |
| `order(array)` | Order of child block IDs |
## Reusable Preset Classes
For reusable, shareable, or complex presets, you can define them as standalone classes instead of inline arrays. This approach is particularly useful for:
* **Theme-wide presets** shared across multiple blocks/sections
* **Complex configurations** with deep nesting
* **Reusable templates** across different themes
* **Version-controlled presets** maintained separately
### Creating a Standalone Preset Class
Standalone preset classes extend `BagistoPlus\Visual\Support\Preset` and implement two key methods:
```php
name(t('your-theme::presets.hero_banner.name'))
->description(t('your-theme::presets.hero_banner.description'))
->icon('heroicon-o-photograph')
->category(t('your-theme::presets.categories.banners'))
->settings([
'layout' => 'centered',
'background_color' => '#4f46e5',
'padding' => 'large',
])
->blocks([
PresetBlock::make('@your-theme/heading')
->id('hero-title')
->settings([
'text' => t('your-theme::presets.hero_banner.heading'),
'level' => 1,
'color' => 'white',
]),
PresetBlock::make('@your-theme/paragraph')
->id('hero-subtitle')
->settings([
'text' => t('your-theme::presets.hero_banner.subtitle'),
'color' => 'white',
]),
PresetBlock::make('@your-theme/button')
->id('hero-cta')
->settings([
'text' => t('your-theme::presets.hero_banner.button'),
'style' => 'primary',
'size' => 'large',
]),
]);
}
}
```
### Using PresetBlock
Always use `PresetBlock` from the Visual package when defining child blocks in presets:
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.hero_banner.name'))
->blocks([
PresetBlock::make('heading')
->settings(['text' => t('your-theme::presets.hero_banner.heading')]),
PresetBlock::make('button')
->settings(['text' => t('your-theme::presets.hero_banner.button')]),
]),
];
}
```
The block type identifier can be:
* **Simple name**: `'button'`, `'heading'` (for built-in or theme blocks)
* **Namespaced**: `'@your-theme/button'`, `'@visual-debut/heading'` (explicit namespace)
### Example: Complex Nested Preset
```php
name(t('your-theme::presets.feature_grid.name'))
->description(t('your-theme::presets.feature_grid.description'))
->category(t('your-theme::presets.categories.content'))
->settings([
'layout' => 'grid',
'columns' => 3,
])
->blocks([
// First feature
PresetBlock::make('@your-theme/container')
->id('feature-1')
->settings(['alignment' => 'center'])
->children([
PresetBlock::make('@your-theme/icon')
->settings([
'icon' => 'heroicon-o-lightning-bolt',
'size' => 'large',
]),
PresetBlock::make('@your-theme/heading')
->settings([
'text' => t('your-theme::presets.feature_grid.fast_shipping.title'),
'level' => 3,
]),
PresetBlock::make('@your-theme/paragraph')
->settings([
'text' => t('your-theme::presets.feature_grid.fast_shipping.text'),
]),
]),
// Second feature
PresetBlock::make('@your-theme/container')
->id('feature-2')
->settings(['alignment' => 'center'])
->children([
PresetBlock::make('@your-theme/icon')
->settings([
'icon' => 'heroicon-o-shield-check',
'size' => 'large',
]),
PresetBlock::make('@your-theme/heading')
->settings([
'text' => t('your-theme::presets.feature_grid.secure_checkout.title'),
'level' => 3,
]),
PresetBlock::make('@your-theme/paragraph')
->settings([
'text' => t('your-theme::presets.feature_grid.secure_checkout.text'),
]),
]),
// Third feature
PresetBlock::make('@your-theme/container')
->id('feature-3')
->settings(['alignment' => 'center'])
->children([
PresetBlock::make('@your-theme/icon')
->settings([
'icon' => 'heroicon-o-heart',
'size' => 'large',
]),
PresetBlock::make('@your-theme/heading')
->settings([
'text' => t('your-theme::presets.feature_grid.satisfaction.title'),
'level' => 3,
]),
PresetBlock::make('@your-theme/paragraph')
->settings([
'text' => t('your-theme::presets.feature_grid.satisfaction.text'),
]),
]),
]);
}
}
```
### Organizing Preset Classes
Store standalone preset classes in a dedicated directory:
```
your-theme/
└── src/
└── Presets/
├── HeroBanner.php
├── FeatureGrid.php
├── TestimonialCarousel.php
└── ClassicFooter.php
```
### Registering Standalone Presets
Bagisto Visual automatically discovers standalone preset classes from:
* `app/Visual/Presets`
* `packages///src/Presets`
For other locations, you can manually register presets in a service provider:
#### Discover a directory
Use `discoverPresetsIn()` to auto-discover all preset classes in a directory. The method requires two parameters:
* The directory path containing your preset classes
* The base namespace for those presets (defaults to `'App\\Presets'`)
```php
Visual::discoverPresetsIn(
base_path('modules/Shared/Presets'),
'Modules\\Shared\\Presets'
);
```
This will automatically discover and register all preset classes in the specified directory, matching the namespace structure to the folder structure.
### When to Use Standalone Preset Classes
| Use Standalone Classes When | Use Inline presets() Method When |
| ---------------------------------------------------------- | --------------------------------- |
| Preset is complex with deep nesting | Preset is simple (2-3 properties) |
| Preset is reused across themes | Preset is specific to one block |
| Preset needs to be reused in other presets (`::asChild()`) | Preset is only used inline |
| Preset requires translations | Preset uses static values |
| Preset is version-controlled separately | Preset is quick variations |
| Multiple presets share logic | Variations are straightforward |
### Reusing Presets with `::asChild()`
Standalone preset classes can be reused as child blocks within other presets using the `::asChild()` method. This enables composition and eliminates duplication when the same preset configuration needs to appear in multiple places.
#### Basic Usage
```php
name(t('your-theme::presets.product_card_overlay.name'))
->category(t('your-theme::presets.categories.products'))
->blocks([
PresetBlock::make('@your-theme/product-image')
->settings(['aspect_ratio' => 'square']),
PresetBlock::make('@your-theme/product-title')
->settings(['size' => 'large']),
PresetBlock::make('@your-theme/product-price')
->settings(['show_compare' => true]),
]);
}
}
// Reuse it in another preset
class ProductGrid extends Preset
{
protected function getType(): string
{
return '@your-theme/product-grid';
}
protected function build(): void
{
$this
->name(t('your-theme::presets.featured_products_grid.name'))
->settings(['columns' => 4])
->blocks([
PresetBlock::make('@your-theme/heading')
->settings(['text' => t('your-theme::presets.featured_products_grid.heading')]),
// Reuse ProductCard preset as a child block
ProductCard::asChild()
->id('product-card')
->static()
->repeated(),
]);
}
}
```
## Real-World Examples
### Example 1: Testimonials Section
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.testimonials_grid.name'))
->description(t('your-theme::presets.testimonials_grid.description'))
->icon('heroicon-o-chat-bubble-left-right')
->category(t('your-theme::presets.categories.social_proof'))
->settings([
'heading' => t('your-theme::presets.testimonials_grid.heading'),
'layout' => 'grid',
])
->blocks([
PresetBlock::make('testimonial')
->settings([
'quote' => t('your-theme::presets.testimonials_grid.first.quote'),
'author' => t('your-theme::presets.testimonials_grid.first.author'),
'rating' => 5,
]),
PresetBlock::make('testimonial')
->settings([
'quote' => t('your-theme::presets.testimonials_grid.second.quote'),
'author' => t('your-theme::presets.testimonials_grid.second.author'),
'rating' => 5,
]),
PresetBlock::make('testimonial')
->settings([
'quote' => t('your-theme::presets.testimonials_grid.third.quote'),
'author' => t('your-theme::presets.testimonials_grid.third.author'),
'rating' => 5,
]),
]),
Preset::make(t('your-theme::presets.testimonials_carousel.name'))
->description(t('your-theme::presets.testimonials_carousel.description'))
->icon('heroicon-o-arrow-path')
->category(t('your-theme::presets.categories.social_proof'))
->settings([
'heading' => t('your-theme::presets.testimonials_carousel.heading'),
'layout' => 'carousel',
])
->blocks([
PresetBlock::make('testimonial')->repeated(),
PresetBlock::make('testimonial')->repeated(),
PresetBlock::make('testimonial')->repeated(),
PresetBlock::make('testimonial')->repeated(),
]),
];
}
```
### Example 2: Gallery Section
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.gallery.two_column.name'))
->category(t('your-theme::presets.categories.galleries'))
->settings(['columns' => 2])
->blocks([
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
]),
Preset::make(t('your-theme::presets.gallery.three_column_masonry.name'))
->category(t('your-theme::presets.categories.galleries'))
->settings(['columns' => 3, 'style' => 'masonry'])
->blocks([
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
PresetBlock::make('image'),
]),
Preset::make(t('your-theme::presets.gallery.carousel.name'))
->category(t('your-theme::presets.categories.galleries'))
->settings(['style' => 'carousel', 'autoplay' => true])
->blocks([
PresetBlock::make('image')->repeated(),
PresetBlock::make('image')->repeated(),
PresetBlock::make('image')->repeated(),
]),
];
}
```
### Example 3: Call-to-Action Variations
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('your-theme::presets.simple_cta.name'))
->category(t('your-theme::presets.categories.ctas'))
->settings(['layout' => 'simple'])
->blocks([
PresetBlock::make('heading')
->settings(['text' => t('your-theme::presets.simple_cta.heading')])
->static(),
PresetBlock::make('button')
->settings(['text' => t('your-theme::presets.simple_cta.button'), 'style' => 'primary']),
]),
Preset::make(t('your-theme::presets.split_cta.name'))
->category(t('your-theme::presets.categories.ctas'))
->settings(['layout' => 'split'])
->blocks([
PresetBlock::make('image')
->settings(['image' => '/default-cta.jpg'])
->static(),
PresetBlock::make('heading')
->settings(['text' => t('your-theme::presets.split_cta.heading')]),
PresetBlock::make('paragraph')
->settings(['text' => t('your-theme::presets.split_cta.text')]),
PresetBlock::make('button')
->settings(['text' => t('your-theme::presets.split_cta.button')]),
]),
];
}
```
## Preview Images
Add visual previews to help merchants choose:
```php
use BagistoPlus\Visual\Support\Preset;
use function BagistoPlus\Visual\t;
Preset::make(t('your-theme::presets.hero_image_left.name'))
->previewImageUrl('/images/presets/hero-image-left.png')
```
**Tips for preview images:**
* Use 16:9 aspect ratio (e.g., 800x450px)
* Show realistic content, not placeholders
* Keep file size under 100KB
* Use PNG or JPEG format
* Store in `public/images/presets/`
## Next Steps
* **[Block Schema](/building-theme/adding-blocks/block-schema)** - Complete guide to block settings and schema
* **[Container Blocks](/building-theme/adding-blocks/container-blocks)** - Blocks that accept children
* **[Sections Overview](/building-theme/adding-sections/overview)** - Building sections
* **[Settings Types](/core-concepts/settings/types)** - Available setting field types
---
---
url: /core-concepts/settings/overview.md
---
# Settings
Settings define the configurable attributes of your sections and blocks. Each setting has a type, label, and optional configuration like defaults,and conditional visibility.
## Overview
Settings are the backbone of how customization works in Bagisto Visual.
They allow merchants to configure sections, blocks, and even the entire storefront layout visually through the Theme Editor — without touching code.
Settings make it easy to personalize storefronts, ensuring flexibility for developers and simplicity for merchants.
Bagisto Visual settings can be used in two main places:
| Setting Type | Scope | Example |
| ---------------------- | -------------------------------------- | ----------------------------------------------- |
| Section/Block Settings | Control individual sections and blocks | Banner text, Button color, Product grid columns |
| Theme Settings | Global store-wide options | Typography, Color palette, default styles |
## How Settings Work
* **Section and Block Settings** are defined inside each section class using a structured PHP API.
* **Theme Settings** are defined globally and control the broader layout and style of the storefront.
Settings provide an abstraction that allows customization without changing the underlying code. Developers expose options, and merchants adjust them through an intuitive visual interface.
## Setting Input Types
Bagisto Visual supports a wide variety of input types for settings, including:
| Type | Purpose | Example |
| :------- | :------------------- | :---------------------------------- |
| Text | Simple text input | Section headings, Button labels |
| Textarea | Multiline text input | Detailed descriptions |
| Link | URL input | Link buttons, Banners |
| Color | Color picker | Background colors, Text colors |
| Select | Dropdown option list | Layout styles, Alignment choices |
| Range | Numeric sliders | Number of columns, Spacing settings |
| Switch | On/Off toggle | Show/Hide features |
| Category | Category selector | Featured categories, Menus |
Each input type improves merchant experience by offering the most natural way to configure the setting.
## Editing Settings in the Theme Editor
* Merchants can interact with settings directly through the **Theme Editor**.
* They can **instantly preview changes** without needing to publish.
* **Section and Block Settings** affect only their associated components.
* **Theme Settings** affect the layout and design globally across the storefront.
Settings changes are safe, reversible, and visual, making customization intuitive even for non-technical users.
## Multi-locale Starter Content
When your theme supports multiple locales, use Visual's `t()` helper for editor schema text and default content instead of Laravel's `__()` or `trans()` helpers.
Use it when the text should adapt to the active locale until the merchant customizes it:
```php
use BagistoPlus\Visual\Settings\Text;
use function BagistoPlus\Visual\t;
Text::make('heading', t('awesome-theme::blocks.hero.heading'))
->default(t('awesome-theme::blocks.hero.default_heading'));
```
Laravel translation helpers are still fine for normal Blade/runtime text. Prefer Visual's `t()` helper for settings labels, helper text, defaults, presets, block names, and section names shown in the editor.
## Dynamic Defaults
Settings can use **dynamic sources** to set default values from runtime context:
```php
use function BagistoPlus\Visual\t;
Text::make('productName', t('awesome-theme::products.name'))
->default('@product.name'), // Resolves from $product variable
Number::make('price', t('awesome-theme::products.price'))
->default('@product.price'),
Image::make('image', t('awesome-theme::products.image'))
->default('@product.base_image.url'),
```
The `@path.to.value` syntax allows settings to automatically populate from:
* Page context (variables from controllers/views)
* Parent-shared data (via the `share()` method)
This is especially useful for static blocks that need to display different data based on context while maintaining merchant-customizable settings.
**Learn more:** [Dynamic Sources](/core-concepts/dynamic-sources)
***
Settings are a key reason why Bagisto Visual empowers both developers and merchants to create rich, personalized storefronts without friction.
---
---
url: /core-concepts/settings/types.md
---
# Setting Types
Bagisto Visual includes a range of **setting types** like text inputs, color pickers, toggle switches, dropdowns, and more.
These ready-made types make it easy for developers to offer flexible customization options in sections, blocks, and themes — all through the visual editor.
## Standard Setting Attributes
Every setting type supports a few standard attributes:
| Attribute | Description | Required |
| :-------- | :------------------------------------------ | :------- |
| `id` | The unique identifier for the setting. | Yes |
| `label` | The text label shown to merchants. | Yes |
| `default` | The default value assigned to the field. | No |
| `info` | Optional helper text shown below the field. | No |
## Available Setting Types
### Text
Single-line text input. Useful for headings, labels, and short descriptions.
In addition to the standard attributes, Text type settings have the following attribute:
| Attribute | Description | Required |
| :------------ | :--------------------------------- | :------- |
| `placeholder` | A placeholder value for the input. | No |
```php
use BagistoPlus\Visual\Settings\Text;
public static function settings(): array
{
return [
Text::make('title', 'Heading')
->default('Welcome to our store')
->placeholder('Enter heading here...'),
];
}
```
In Blade:
```blade
@if ($section->settings->text)
{{ $section->settings->text }}
@endif
```
***
### Textarea
Multiline text input. Useful for longer descriptions or rich content areas.
In addition to the standard attributes, Textarea type settings have the following attribute:
| Attribute | Description | Required |
| :------------ | :------------------------------------ | :------- |
| `placeholder` | A placeholder value for the textarea. | No |
```php
use BagistoPlus\Visual\Settings\Textarea;
public static function settings(): array
{
return [
Textarea::make('description', 'Store Description')
->default('This is your store description.')
->placeholder('Write something about your store...'),
];
}
```
In Blade:
```blade
@if ($section->settings->description)
{{ $section->settings->description }}
@endif
```
***
### Checkbox
Simple true/false toggle. Useful for enabling or disabling features.
Checkbox settings do not have any additional attributes beyond the standard attributes, but support an alternative switch variant for a different visual style.
```php
use BagistoPlus\Visual\Settings\Checkbox;
public static function settings(): array
{
return [
Checkbox::make('show_banner', 'Show Banner')
->default(true),
];
}
```
#### Switch Variant
Use the `asSwitch()` method to display the checkbox as a toggle switch instead of a standard checkbox:
```php
Checkbox::make('enable_feature', 'Enable Feature')
->asSwitch()
->default(false),
```
In Blade:
```blade
@if ($section->settings->show_banner)
@endif
```
::: info
If `default` is unspecified, it defaults to `false`.
:::
***
### Radio
Single option selection via radio buttons. Useful for choosing between predefined mutually exclusive options.
In addition to the standard attributes, Radio type settings have the following attribute:
| Attribute | Description | Required |
| :-------- | :----------------------------------------------------------------------------------------- | :------- |
| `options` | Array of options formatted as `'value' => 'Label'` or `[ 'value' => ..., 'label' => ... ]` | Yes |
```php
use BagistoPlus\Visual\Settings\Radio;
public static function settings(): array
{
return [
Radio::make('alignment', 'Alignment')
->options([
'left' => 'Left',
'center' => 'Center',
'right' => 'Right',
])
->default('center'),
];
}
```
Alternative format:
```php
Radio::make('alignment', 'Alignment')
->options([
['value' => 'left', 'label' => 'Left'],
['value' => 'center', 'label' => 'Center'],
['value' => 'right', 'label' => 'Right'],
])
->default('center');
```
In Blade:
```blade
```
::: info
If default is unspecified, then the first option is selected by default.
:::
***
### Select
Dropdown selection. Useful for choosing from a list of predefined options.
In addition to the standard attributes, Select type settings have the following attribute:
| Attribute | Description | Required |
| :-------- | :----------------------------------------------------------------------------------------- | :------- |
| `options` | Array of options formatted as `'value' => 'Label'` or `[ 'value' => ..., 'label' => ... ]` | Yes |
```php
use BagistoPlus\Visual\Settings\Select;
public static function settings(): array
{
return [
Select::make('layout', 'Layout Style')
->options([
'grid' => 'Grid',
'list' => 'List',
])
->default('grid'),
];
}
```
Alternative format:
```php
Select::make('layout', 'Layout Style')
->options([
['value' => 'grid', 'label' => 'Grid'],
['value' => 'list', 'label' => 'List'],
])
->default('grid');
```
In Blade:
```blade
```
::: info
If `default` is unspecified, then the first option is selected by default.
:::
***
### Range
Numeric slider input. Useful for values like spacing, number of columns, or padding.
In addition to the standard attributes, Range type settings have the following attributes:
| Attribute | Description | Required |
| :-------- | :------------------------------ | :------- |
| `min` | Minimum value allowed | Yes |
| `max` | Maximum value allowed | Yes |
| `step` | Increment steps (default `1`) | No |
| `unit` | Optional label for unit display | No |
```php
use BagistoPlus\Visual\Settings\Range;
public static function settings(): array
{
return [
Range::make('columns', 'Number of Columns')
->min(1)
->max(6)
->step(1)
->unit('cols')
->default(3),
];
}
```
In Blade:
```blade
```
::: info
If default is unspecified, it defaults to the minimum value.
:::
***
### Number
Single-line numeric input. Useful for entering quantities, prices, padding, margins, and other number-based configurations.
In addition to the standard attributes, Number type settings have the following attributes:
| Attribute | Description | Required |
| :------------ | :--------------------------------- | :------- |
| `placeholder` | A placeholder value for the input. | No |
| `min` | Minimum value allowed | No |
| `max` | Maximum value allowed | No |
| `step` | Increment steps (default `1`) | No |
```php
use BagistoPlus\Visual\Settings\Number;
public static function settings(): array
{
return [
Number::make('max_width', 'Max Width')
->min(320)
->max(1920)
->step(10)
->default(1200)
->placeholder('Enter a maximum width...'),
];
}
```
In Blade:
```blade
```
***
### Spacing
Four-sided spacing input. Useful for controlling padding and margin values independently for each side (top, right, bottom, left).
The visual editor provides an intuitive interface with four individual number inputs and a link toggle button that allows merchants to sync all sides to the same value when enabled.
In addition to the standard attributes, Spacing type settings have the following attributes:
| Attribute | Description | Required |
| :-------- | :-------------------------- | :------- |
| `min` | Minimum value for each side | No |
| `max` | Maximum value for each side | No |
```php
use BagistoPlus\Visual\Settings\Spacing;
public static function settings(): array
{
return [
Spacing::make('padding', 'Padding')
->min(0)
->max(100)
->default(['top' => 16, 'right' => 16, 'bottom' => 16, 'left' => 16]),
Spacing::make('margin', 'Margin')
->min(-50)
->max(100),
];
}
```
In Blade:
```blade
```
::: info
* Default values: All sides default to `0` if not specified
* The visual editor includes a link toggle to sync all sides
* Negative values are supported for margins (set appropriate min value)
:::
***
### Color
Color picker input. Useful for background colors, text colors, or brand-related customization.
When accessing a color setting inside Blade, the value is either:
* `null` (if no color selected)
* an instance of [`matthieumastadenis\couleur\Color`](https://github.com/matthieumastadenis/couleur)
```php
use BagistoPlus\Visual\Settings\Color;
public static function settings(): array
{
return [
Color::make('background_color', 'Background Color')
->default('#92400e'),
];
}
```
In Blade:
```blade
@if ($section->settings->background_color)
@endif
```
***
### Gradient
Gradient picker input. Useful for hero backgrounds, banner overlays, cards, and other surfaces that need a configurable CSS gradient.
```php
use BagistoPlus\Visual\Settings\Gradient;
public static function settings(): array
{
return [
Gradient::make('background_gradient', 'Background Gradient')
->default('linear-gradient(90deg, #000000ff 0%, #ffffffff 100%)'),
];
}
```
In Blade:
```blade
@if ($section->settings->background_gradient)
@endif
```
#### Supported Formats
The visual picker supports one non-repeating CSS gradient:
* `linear-gradient(...)`
* `radial-gradient(circle, ...)`
Linear gradients support degree angles and simple direction syntax such as `to right`, `to top`, `to bottom`, `to left`, and clean diagonal directions like `to top right`.
Radial gradients support `circle` only. Ellipse gradients, size keywords, and positioned radial gradients are not supported by the visual picker.
Color stops can use concrete colors accepted by the editor color picker, including:
* Hex colors, including alpha hex
* `rgb(...)` and `rgba(...)`
* `hsl(...)` and `hsla(...)`
* Standard named colors
Stop positions support percentages. Omitted stop positions are normalized using CSS interpolation behavior.
Unsupported values include:
* `var(...)`
* `currentColor`
* `color-mix(...)`
* unresolved or advanced CSS color functions
* color hints
* multi-position stops
* non-percentage stop positions
::: info
Theme defaults should use the supported subset when the value needs to remain editable in the visual picker.
:::
***
### Link
URL input field. Useful for buttons, banners, images, and any elements that need a hyperlink.
The Link setting allows the merchant to either:
* Enter a custom URL manually
* **Select a resource** (like a Product, Category, or CMS Page) directly from the store
```php
use BagistoPlus\Visual\Settings\Link;
public static function settings(): array
{
return [
Link::make('cta_link', 'Call to Action Link')
->default('/'),
];
}
```
In Blade:
```blade
@if ($section->settings->cta_link)
Browse Collection
@endif
```
***
### Image
Image picker input. Useful for banners, logos, thumbnails, or any visual element.
The merchant can:
* Upload a new image
* Pick an existing image from the media library
* Define image metadata such as alt text and focal point
```php
use BagistoPlus\Visual\Settings\Image;
public static function settings(): array
{
return [
Image::make('banner_image', 'Banner Image'),
];
}
```
In Blade:
```blade
@if ($section->settings->banner_image)
@endif
```
Image settings are stored as image paths in older themes and as structured values when metadata is edited in the Visual Editor. Both formats are supported. The image value still casts to the image URL, so existing Blade `src` usage continues to work.
For new sections, prefer the image metadata `alt` value over creating a separate alt text setting. Existing sections that already use a separate alt setting can keep doing so and migrate gradually.
***
### Video
Video input. Useful for hero videos, product demos, banners, and other media-rich sections.
By default, video settings allow uploaded videos only:
```php
use BagistoPlus\Visual\Settings\Video;
public static function settings(): array
{
return [
Video::make('hero_video', 'Hero Video'),
];
}
```
To also allow external YouTube and Vimeo URLs:
```php
Video::make('hero_video', 'Hero Video')
->acceptsExternal();
```
You can restrict or extend the accepted external sources. Custom sources use PHP regex patterns and must point to directly playable video URLs:
```php
Video::make('hero_video', 'Hero Video')
->acceptsExternal([
'youtube',
[
'host' => 'cdn',
'label' => 'CDN video',
'pattern' => '#^https://cdn\.example\.com/.+\.(mp4|webm|ogg)(\?.*)?$#i',
],
]);
```
In Blade:
```blade
@if ($section->settings->hero_video)
{!! $section->settings->hero_video->render(['class' => 'w-full']) !!}
@endif
```
When accessing a video setting inside Blade, the value is a `VideoValue` object or `null`. It casts to the renderable video URL and exposes media information:
```blade
{{ $section->settings->hero_video->media_type }}
{{ $section->settings->hero_video->host }}
{{ $section->settings->hero_video->url }}
{{ $section->settings->hero_video->original_url }}
```
Native uploaded videos expose a `sources` array with URL and MIME type. YouTube videos expose a `preview_image` value when a thumbnail can be derived.
Video settings support string defaults for uploaded paths, YouTube/Vimeo URLs, and direct web-playable video URLs.
***
### Category
Dropdown selector input. Useful for allowing the merchant to select a category from the store catalog.
When accessing a category setting inside Blade, the value is either:
* `null` (if no category selected)
* an instance of the `Webkul\Category\Models\Category` model
```php
use BagistoPlus\Visual\Settings\Category;
public static function settings(): array
{
return [
Category::make('featured_category', 'Featured Category'),
];
}
```
In Blade:
```blade
@if ($section->settings->featured_category)
@endif
```
***
### Product
Dropdown selector input. Useful for allowing the merchant to select a product from the store catalog.
When accessing a product setting inside Blade, the value is either:
* `null` (if no product selected)
* an instance of the `Webkul\Product\Models\Product` model
```php
use BagistoPlus\Visual\Settings\Product;
public static function settings(): array
{
return [
Product::make('featured_product', 'Featured Product'),
];
}
```
In Blade:
```blade
@if ($section->settings->featured_product)
@endif
```
***
### CmsPage
Dropdown selector input. Useful for allowing the merchant to select a CMS page from the store.
When accessing a CMS page setting inside Blade, the value is either:
* `null` (if no page selected)
* an instance of the `Webkul\CMS\Models\CmsPage` model
```php
use BagistoPlus\Visual\Settings\CmsPage;
public static function settings(): array
{
return [
CmsPage::make('policy_page', 'Policy Page'),
];
}
```
In Blade:
```blade
@if ($section->settings->policy_page)
{{ $section->settings->policy_page->page_title }}
@endif
```
***
### ProductList
Multi-select picker for choosing several products from the store catalog.
When accessing the setting, the value is an `Illuminate\Support\Collection` of `Webkul\Product\Models\Product` instances, in the order chosen by the merchant. Products that no longer exist are skipped.
```php
use BagistoPlus\Visual\Settings\ProductList;
public static function settings(): array
{
return [
ProductList::make('featured_products', 'Featured Products'),
];
}
```
In Blade:
```blade
@foreach ($section->settings->featured_products as $product)
@visualBlock('@vendor/product-card', 'static-product-card', ['product' => $product])
@endforeach
```
***
### CategoryList
Multi-select picker for choosing several categories from the store catalog.
When accessing the setting, the value is an `Illuminate\Support\Collection` of `Webkul\Category\Models\Category` instances, in the order chosen by the merchant. Categories that no longer exist are skipped.
```php
use BagistoPlus\Visual\Settings\CategoryList;
public static function settings(): array
{
return [
CategoryList::make('promoted_categories', 'Promoted Categories'),
];
}
```
In Blade:
```blade
@foreach ($section->settings->promoted_categories as $category)
@visualBlock('@vendor/category-card', 'static-category-card', ['product' => $product])
@endforeach
```
***
### CmsPageList
Multi-select picker for choosing several CMS pages from the store.
When accessing the setting, the value is an `Illuminate\Support\Collection` of `Webkul\CMS\Models\CmsPage` instances, in the order chosen by the merchant. Pages that no longer exist are skipped.
```php
use BagistoPlus\Visual\Settings\CmsPageList;
public static function settings(): array
{
return [
CmsPageList::make('footer_pages', 'Footer Pages'),
];
}
```
In Blade:
```blade
@foreach ($section->settings->footer_pages as $page)
{{ $page->page_title }}
@endforeach
```
***
### RichText
WYSIWYG rich-text editor input. Useful for inserting formatted content like paragraphs, lists, links, and formatted text.
RichText fields support the following basic formatting options:
* Bold
* Italic
* Underline
* Paragraph
* Headings
* Bullet list
* Ordered list
In addition to the standard attributes, RichText type settings have the following attribute:
| Attribute | Description | Required |
| :-------- | :-------------------------------------------- | :------- |
| `inline` | Whether the editor should be rendered inline. | No |
```php
use BagistoPlus\Visual\Settings\RichText;
public static function settings(): array
{
return [
RichText::make('content', 'Content Block'),
RichText::make('highlight', 'Highlight Text')
->inline(),
];
}
```
In Blade:
```blade
@if ($section->settings->content)
{!! $section->settings->content !!}
@endif
@if ($section->settings->highlight)
{!! $section->settings->highlight !!}
@endif
```
***
### Font
Font picker input. Useful for allowing merchants to select fonts from the [Bunny Fonts](https://fonts.bunny.net/) catalog.
Font settings allow the merchant to select a web-safe font that is automatically loaded from Bunny Fonts.
```php
use BagistoPlus\Visual\Settings\Font;
public static function settings(): array
{
return [
Font::make('heading_font', 'Heading Font')->default('roboto'),
];
}
```
In Blade:
```blade
@if ($section->settings->heading_font)
@endif
```
This will render as:
```html
```
Additionally, you may use the following snippet to render any resources necessary to load the font
```blade
@pushOnce('styles')
{{ $section->settings->heading_font->toHtml() }}
@endPushOnce
```
Will render:
```html
```
***
### Icon
Icon selection input. Useful for allowing merchants to choose an icon from the installed Blade Icon sets.
Bagisto Visual ships with the [Lucide](https://lucide.dev/) icon set pre-installed by default.
Developers can manually install and configure additional Blade Icons (like Heroicons, Tabler Icons, etc.) if needed.
```php
use BagistoPlus\Visual\Settings\Icon;
public static function settings(): array
{
return [
Icon::make('button_icon', 'Button Icon'),
];
}
```
In Blade:
```blade
@if ($section->settings->button_icon)
@svg($section->settings->button_icon, ['class' => 'w-6 h-6'])
{!! $section->settings->button_icon->render(['class' => 'w-6 h-6']) !!}
@endif
```
***
### ColorScheme
The `ColorScheme` setting allows merchants to choose a color scheme defined by the theme.
Each color scheme is a named palette of colors (e.g., background, text, primary, etc.) and is defined in the theme using a `ColorSchemeGroup`.
This setting is typically used in **section settings** to let the merchant apply predefined styles to specific areas of the storefront.
***
> This setting **does not define color schemes** — it only lets the merchant pick one from those defined in the theme.
***
```php
use BagistoPlus\Visual\Settings\ColorScheme;
public static function settings(): array
{
return [
ColorScheme::make('color_scheme', 'Color Scheme')
->default('default'),
];
}
```
This creates a dropdown in the visual editor populated with all color schemes defined by the theme’s `ColorSchemeGroup`.
**In Blade:**
The recommended way to use the selected color scheme in your view is:
```blade
settings->color_scheme->attributes() !!}>
```
This will output:
```html
```
This is used to scope the color schemes tokens to this block.
***
### ColorSchemeGroup
The `ColorSchemeGroup` setting type allows theme developers to define a **set of named color schemes** that merchants can reuse across multiple sections.
Each color scheme is a collection of color roles (like `background`, `text`, `primary`, etc.) and can be selected using a [ColorScheme](#colorscheme) setting within any section.
This is typically defined once in your theme’s `config/settings.php` and is **editable by the merchant**.
* Acts as the **central registry of available color schemes**
* Enables consistency in color use across sections
* Can be extended or modified by the merchant in the theme editor
#### Usage in `config/settings.php`
```php
use BagistoPlus\Visual\Settings\ColorSchemeGroup;
return [
ColorSchemeGroup::make('color_schemes', 'Color Schemes')
->schemes([
'light' => [
'label' => 'Light',
'tokens' => [
'background' => '#ffffff',
'on-background' => '#111827',
'primary' => '#4f46e5',
'...'
],
],
'dark' => [
'label' => 'Dark',
'tokens' => [
'background' => '#111827',
'on-background' => '#f9fafb',
'primary' => '#6366f1',
'...'
],
],
]),
];
```
#### Scheme Format
Each scheme is an array with:
* A unique **key** (e.g., `light`, `dark`, `brand`)
* A **label** (used in the dropdown)
* A `tokens` array with color roles (e.g., `background`, `on-background`, `primary`, etc.)
```php
[
'light' => [
'label' => 'Light',
'tokens' => [
'background' => '#ffffff',
'on-background' => '#111827',
'primary' => '#4f46e5',
]
]
]
```
#### Behavior in the Theme Editor
* Merchants can **add, edit, or remove** color schemes directly from the theme editor
* They can:
* Rename schemes
* Change color values
* Any section using a `ColorScheme` setting will automatically reflect the updated list
#### Blade Usage
The `ColorSchemeGroup` setting is not accessed directly in sections.
However, **theme developers must output CSS variables** for every scheme so that sections using `ColorScheme` can style themselves accordingly.
Each scheme should be scoped using a `data-color-scheme` attribute:
```html
```
#### 💡 Suggestion: Include Brand Color Shades
For primary or accent colors, it’s recommended to output shades (like Tailwind’s colors).
```blade
```
These can be used in components via var(--color-primary-500) for consistent, scalable design.
If you are using tailwindcss, you could just use utility classes:
```blade
```
***
Bagisto Visual provides a helper method to generate the full CSS output automatically from the theme's color schemes:
```blade
{{-- layouts/default.blade.php --}}
```
* This will loop over every scheme
* Output all defined colors as `--color-*` tokens
* Automatically generate shades for brand color roles
#### Notes
* Only one `ColorSchemeGroup` should be defined per theme
* Sections do **not** define color schemes — they reference them via the `ColorScheme` setting
* If no `ColorSchemeGroup` is defined, `ColorScheme` fields will not be functional
-> [Read more about color schemes](../../building-theme/best-practices/styling.md)
***
### ColorToken
Semantic color token picker. Useful when a section or block should reference a role inside the active color scheme (such as `primary`, `danger`, or `success`) instead of a hardcoded literal color.
A `ColorToken` value stays a token string at every layer of the stack. At render time it resolves to a CSS variable like `var(--color-primary)`, so the same value automatically adapts to the active `data-color-scheme` on the page.
How it differs from the other color related setting types:
* [Color](#color) stores a literal color value (hex, rgba, etc.).
* [ColorScheme](#colorscheme) lets the merchant pick a whole scheme to apply to a section.
* `ColorToken` lets the merchant pick one role inside whatever scheme is currently active.
```php
use BagistoPlus\Visual\Settings\ColorToken;
public static function settings(): array
{
return [
ColorToken::make('button_color', 'Button color')
->default('primary'),
];
}
```
In Blade, call `cssVar()` on the resolved value to emit the CSS variable reference:
```blade
@if ($section->settings->button_color)
Buy now
@endif
```
Casting the value to string returns the token itself (for example `primary`), which is useful when you want to drive class names or data attributes from the token:
```blade
```
In the editor, each token swatch is rendered using the colors from the nearest active color scheme.
***
### Typography
The `Typography` setting allows merchants to select a typography preset for text styling. Typography presets are defined once in the theme's settings using [TypographyPresets](#typographypresets), and sections or blocks can reference them using this setting.
```php
use BagistoPlus\Visual\Settings\Typography;
public static function settings(): array
{
return [
Typography::make('heading_typography', 'Heading Typography'),
Typography::make('body_typography', 'Body Typography'),
];
}
```
This creates a dropdown in the visual editor populated with all typography presets defined by the theme.
**In Blade:**
Apply the selected typography using the `attributes()` method:
```blade
settings->heading_typography->attributes() }}>
Welcome to our store
```
This outputs:
```html
Welcome to our store
```
The `data-typography` attribute scopes typography CSS variables to this element.
***
### TypographyPresets
The `TypographyPresets` setting type allows theme developers to define a **set of named typography presets** that merchants can reuse across multiple sections. Each typography preset is a collection of font properties (fontFamily, fontSize, lineHeight, etc.) that can be selected using a [Typography](#typography) setting.
This is typically defined once in your theme's `config/settings.php` and is **editable by the merchant**.
* Acts as the **central registry of available typography presets**
* Enables consistency in text styling across sections
* Supports responsive typography for fontSize and lineHeight
* Merchants can add, edit, or remove presets in the theme editor
#### Usage in `config/settings.php`
```php
use BagistoPlus\Visual\Settings\TypographyPresets;
return [
TypographyPresets::make('typography_presets', 'Typography Presets')
->presets([
'heading' => [
'fontFamily' => 'Inter',
'fontWeight' => '700',
'fontSize' => '2xl',
'lineHeight' => 'tight',
'fontStyle' => 'normal',
'letterSpacing' => 'normal',
'textTransform' => 'none',
],
'body' => [
'fontFamily' => 'Inter',
'fontWeight' => '400',
'fontSize' => 'base',
'lineHeight' => 'normal',
'fontStyle' => 'normal',
'letterSpacing' => 'normal',
'textTransform' => 'none',
]
]),
];
```
#### Generating CSS
After defining typography presets, you must generate the CSS in your theme's layout file. This makes the typography styles available to all sections using the `Typography` setting.
**Basic Usage:**
```blade
{{-- layouts/default.blade.php --}}
{{-- Load fonts from Bunny Fonts --}}
@pushOnce('styles')
@foreach ($theme->settings->typography_presets as $typography)
{!! $typography->toHtml() !!}
@endforeach
@endPushOnce
```
This generates CSS for typography styles:
```css
[data-typography='heading'] {
--typography-font-family: 'Inter', sans-serif;
--typography-font-style: normal;
--typography-font-weight: 700;
--typography-font-size: 1.5rem;
--typography-line-height: 1.25;
--typography-letter-spacing: 0em;
--typography-text-transform: none;
}
[data-typography='body'] {
--typography-font-family: 'Inter', sans-serif;
--typography-font-style: normal;
--typography-font-weight: 400;
--typography-font-size: 1rem;
--typography-line-height: 1.5;
--typography-letter-spacing: 0em;
--typography-text-transform: none;
}
```
Render the font links for all typography presets once in your layout:
```blade
{{ $theme->settings->typography_presets->fontLinks() }}
```
This generates HTML to load the configured font families from Bunny Fonts. When the same font is used across multiple presets, all configured weights and styles are grouped into one request:
```html
```
**With Custom Selectors:**
You can also apply typography directly to HTML elements by passing a custom selector:
```blade
```
This generates CSS that applies to both the `data-typography` attribute AND the custom selector:
```css
[data-typography='heading'],
h1,
h2,
h3 {
--typography-font-family: 'Inter', sans-serif;
--typography-font-style: normal;
--typography-font-weight: 700;
--typography-font-size: 1.5rem;
--typography-line-height: 1.25;
--typography-letter-spacing: 0em;
--typography-text-transform: none;
}
[data-typography='body'],
p,
li,
td {
--typography-font-family: 'Inter', sans-serif;
--typography-font-style: normal;
--typography-font-weight: 400;
--typography-font-size: 1rem;
--typography-line-height: 1.5;
--typography-letter-spacing: 0em;
--typography-text-transform: none;
}
```
**Applying CSS Variables:**
In your theme's CSS, apply the generated CSS variables to elements:
```css
[data-typography] {
font-family: var(--typography-font-family);
font-style: var(--typography-font-style);
font-weight: var(--typography-font-weight);
font-size: var(--typography-font-size);
line-height: var(--typography-line-height);
letter-spacing: var(--typography-letter-spacing);
text-transform: var(--typography-text-transform);
}
```
#### Preset Format
Each preset is an array with the following properties:
| Property | Type | Description | Required | Values |
| --------------- | ------------- | -------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| `fontFamily` | string|null | Font family name | No | Any font family name |
| `fontWeight` | string | Font weight | Yes | `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900` |
| `fontSize` | string|array | Font size token or responsive config | Yes | `xs`, `sm`, `base`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `6xl`, `7xl`, `8xl`, `9xl` |
| `lineHeight` | string|array | Line height token or responsive config | Yes | `none`, `tight`, `snug`, `normal`, `relaxed`, `loose` |
| `fontStyle` | string | Font style | Yes | `normal`, `italic` |
| `letterSpacing` | string | Letter spacing token | Yes | `tighter`, `tight`, `normal`, `wide`, `wider`, `widest` |
| `textTransform` | string | Text transform | Yes | `none`, `uppercase`, `lowercase`, `capitalize` |
**Font Size Tokens:**
| Token | CSS Value | Description |
| ------ | --------- | ------------------ |
| `xs` | 0.75rem | Extra small (12px) |
| `sm` | 0.875rem | Small (14px) |
| `base` | 1rem | Base size (16px) |
| `lg` | 1.125rem | Large (18px) |
| `xl` | 1.25rem | Extra large (20px) |
| `2xl` | 1.5rem | 2x large (24px) |
| `3xl` | 1.875rem | 3x large (30px) |
| `4xl` | 2.25rem | 4x large (36px) |
| `5xl` | 3rem | 5x large (48px) |
| `6xl` | 3.75rem | 6x large (60px) |
| `7xl` | 4.5rem | 7x large (72px) |
| `8xl` | 6rem | 8x large (96px) |
| `9xl` | 8rem | 9x large (128px) |
**Line Height Tokens:**
| Token | CSS Value |
| --------- | --------- |
| `none` | 1 |
| `tight` | 1.25 |
| `snug` | 1.375 |
| `normal` | 1.5 |
| `relaxed` | 1.625 |
| `loose` | 2 |
**Letter Spacing Tokens:**
| Token | CSS Value |
| --------- | --------- |
| `tighter` | -0.05em |
| `tight` | -0.025em |
| `normal` | 0em |
| `wide` | 0.025em |
| `wider` | 0.05em |
| `widest` | 0.1em |
#### Responsive Typography
Typography supports responsive configurations for `fontSize` and `lineHeight` using an array format with breakpoint keys:
```php
TypographyPresets::make('typography_presets', 'Typography Presets')
->presets([
'responsive-heading' => [
'fontFamily' => 'Inter',
'fontWeight' => '700',
'fontSize' => [
'_default' => '2xl', // Default size
'mobile' => 'xl', // max-width: 639px
'tablet' => '2xl', // 640px - 1023px
'desktop' => '3xl', // min-width: 1024px
],
'lineHeight' => [
'_default' => 'tight',
'mobile' => 'snug',
'desktop' => 'tight',
],
'fontStyle' => 'normal',
'letterSpacing' => 'normal',
'textTransform' => 'none',
],
]);
```
**Breakpoints:**
| Breakpoint | Media Query | Description |
| ---------- | ---------------------------------------- | --------------- |
| `_default` | (none) | Default value |
| `mobile` | `max-width: 639px` | Mobile devices |
| `tablet` | `min-width: 640px and max-width: 1023px` | Tablet devices |
| `desktop` | `min-width: 1024px` | Desktop devices |
Generated responsive CSS:
```css
[data-typography='responsive-heading'] {
--typography-font-size: 1.5rem;
--typography-line-height: 1.25;
}
@media (max-width: 639px) {
[data-typography='responsive-heading'] {
--typography-font-size: 1.25rem;
--typography-line-height: 1.375;
}
}
@media (min-width: 1024px) {
[data-typography='responsive-heading'] {
--typography-font-size: 1.875rem;
--typography-line-height: 1.25;
}
}
```
#### Behavior in the Theme Editor
* Merchants can **add, edit, or remove** typography presets
* Custom presets are assigned IDs like `typography-1`, `typography-2`, etc.
* Theme-defined presets cannot be deleted (only custom ones can be removed)
* Changes are immediately reflected in sections using the `Typography` setting
#### Notes
* Only one `TypographyPresets` setting should be defined per theme
* Sections reference presets via the `Typography` setting, not directly
* If no `TypographyPresets` is defined, `Typography` fields will not be functional
* Load preset font families from Bunny Fonts with ` $theme->settings->typography_presets->fontLinks()`
* Bunny Fonts is the only supported font provider. See the [Font](#font) setting type for more details on font loading
***
### Header
Visual divider or label inside settings groups. Useful for organizing complex settings panels into meaningful sections.
Unlike other settings, the Header type:
* Does **not** require an `id`
* Only needs a **label** (text that will be displayed as a title)
* **Does not produce any setting data** (not available inside Blade)
```php
use BagistoPlus\Visual\Settings\Header;
use BagistoPlus\Visual\Settings\Color;
use BagistoPlus\Visual\Settings\Text;
public static function settings(): array
{
return [
Header::make('Design Options'),
Color::make('background_color', 'Background Color')
->default('#ffffff'),
Color::make('text_color', 'Text Color')
->default('#000000'),
Header::make('Content Settings'),
Text::make('heading', 'Heading Text')
->default('Welcome to our store'),
Text::make('subheading', 'Subheading Text')
->default('Discover amazing products'),
];
}
```
> **Note:** Header settings are **only used inside the theme editor** to visually group fields.
> They are not available inside Blade templates.
---
---
url: /core-concepts/settings/theme-settings.md
---
# Theme Settings
## Introduction
Theme settings allow developers to define global customization options for a theme.
These settings are available in the **Theme Editor** for merchants to modify things like colors, typography, social media links, and more.
Theme settings are defined in a `settings.php` file located here:
```text
theme/
├── config/
│ └── settings.php
├── resources/
├── src/
├── ...
```
They provide a centralized way to control the visual style and key configuration of the entire storefront.
## File Structure
Each theme settings file must return an **array of setting groups**.
Each group contains:
* `name`: The group title shown inside the theme editor.
* `settings`: An array of Setting types (`Color`, `Text`, `Font`, etc.) available for merchants to configure.
Example file:
```php
t('awesome-theme::settings.groups.light_scheme'),
'settings' => [
Settings\Color::make('light_background_color', t('awesome-theme::settings.light_background_color'))
->default('#ffffff')
->info(t('awesome-theme::settings.light_background_color_info')),
Settings\Color::make('light_primary_color', t('awesome-theme::settings.light_primary_color'))
->default('#92400e')
->info(t('awesome-theme::settings.light_primary_color_info')),
// More color settings...
],
],
[
'name' => t('awesome-theme::settings.groups.typography'),
'settings' => [
Settings\Font::make('heading_font', t('awesome-theme::settings.heading_font'))
->default('Inter'),
Settings\Font::make('body_font', t('awesome-theme::settings.body_font'))
->default('Roboto'),
],
],
[
'name' => t('awesome-theme::settings.groups.social_links'),
'settings' => [
Settings\Text::make('facebook_url', t('awesome-theme::settings.facebook_url'))
->default('https://www.facebook.com'),
Settings\Text::make('instagram_url', t('awesome-theme::settings.instagram_url'))
->default('https://www.instagram.com'),
Settings\Text::make('youtube_url', t('awesome-theme::settings.youtube_url'))
->default('https://www.youtube.com'),
Settings\Text::make('tiktok_url', t('awesome-theme::settings.tiktok_url'))
->default('https://www.tiktok.com'),
Settings\Text::make('twitter_url', t('awesome-theme::settings.twitter_url'))
->default('https://www.x.com'),
Settings\Text::make('snapchat_url', t('awesome-theme::settings.snapchat_url'))
->default('https://www.snapchat.com'),
],
],
];
```
Use Visual's `t()` helper for group names, labels, helper text, and default text that should adapt to the active locale until the merchant customizes it.
`Text`, `Textarea`, and `RichText` settings are localized by default. Other setting types can opt in with `->localized()`.
## Accessing Theme Settings in Blade
Theme settings are automatically injected into every view through the `$theme->settings` object.
Example:
```blade
```
## Best Practices
* Always group related settings meaningfully for a better merchant experience.
* Use informative labels and helper texts (`info()`) to guide merchants.
* Provide sensible default values for each setting to ensure good first impressions.
* Use consistent naming conventions (`light_primary_color`, `color_body_text`, etc.).
---
---
url: /core-concepts/settings/conditional-visibility.md
---
# Conditional Visibility
You can show or hide settings based on other setting values using `visibleWhen()`. This creates a cleaner, more intuitive settings panel by only displaying relevant options.
## Basic Usage
```php
Text::make('gridGap', 'Grid Gap')
->visibleWhen(fn($rule) => $rule->when('layout', 'grid'))
->default('1rem')
```
This setting will only be visible when the `layout` setting equals `'grid'`.
## Rule Methods
The callback receives a `Rule` instance with these methods:
### when()
Check if a field equals a value.
```php
->when(string $field, mixed $value)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->when('layout', 'grid'))
```
### whenNot()
Check if a field does NOT equal a value.
```php
->whenNot(string $field, mixed $value)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->whenNot('size', 'full'))
```
### whenIn()
Check if a field's value is in an array.
```php
->whenIn(string $field, array $values)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->whenIn('layout', ['grid', 'flex']))
```
### whenNotIn()
Check if a field's value is NOT in an array.
```php
->whenNotIn(string $field, array $values)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->whenNotIn('alignment', ['left', 'right']))
```
### whenGt() / whenLt()
Check if a field is greater than or less than a value.
```php
->whenGt(string $field, mixed $value)
->whenLt(string $field, mixed $value)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->whenGt('columns', 1))
```
### whenTruthy() / whenFalsy()
Check if a field is truthy or falsy.
```php
->whenTruthy(string $field)
->whenFalsy(string $field)
```
**Example:**
```php
->visibleWhen(fn($rule) => $rule->whenTruthy('showAdvanced'))
```
## Complex Conditions
Combine multiple conditions with AND/OR logic:
### Multiple AND Conditions
Chain multiple `when()` calls for AND logic:
```php
Select::make('justifyContent', 'Justify Content')
->visibleWhen(fn($rule) => $rule
->when('layout', 'grid')
->whenGt('columns', 1)
)
```
This setting is visible when `layout` is 'grid' AND `columns` is greater than 1.
### OR Logic
Use the `or()` method for OR conditions:
```php
Text::make('spacing', 'Spacing')
->visibleWhen(fn($rule) => $rule
->when('layout', 'grid')
->or(fn($r) => $r->when('type', 'image'))
)
```
This setting is visible when `layout` is 'grid' OR `type` is 'image'.
### Nested Logic
Combine AND/OR for complex rules:
```php
Select::make('borderRadius', 'Border Radius')
->visibleWhen(fn($rule) => $rule
->whenIn('layout', ['grid', 'flex'])
->whenTruthy('showAdvanced')
->or(fn($r) => $r->when('type', 'card'))
)
```
This setting is visible when:
* (`layout` is 'grid' OR 'flex' AND `showAdvanced` is true) OR
* (`type` is 'card')
## Real-World Examples
### Content Type Switcher
```php
public static function settings(): array
{
return [
Select::make('contentType', 'Content Type')
->options([
'image' => 'Image',
'video' => 'Video',
'text' => 'Text',
])
->default('image'),
Image::make('image', 'Image')
->visibleWhen(fn($rule) => $rule->when('contentType', 'image')),
Text::make('videoUrl', 'Video URL')
->visibleWhen(fn($rule) => $rule->when('contentType', 'video')),
Textarea::make('text', 'Text Content')
->visibleWhen(fn($rule) => $rule->when('contentType', 'text')),
];
}
```
### Layout-Specific Options
```php
public static function settings(): array
{
return [
Select::make('layout', 'Layout')
->options([
'grid' => 'Grid',
'list' => 'List',
'masonry' => 'Masonry',
])
->default('grid'),
Range::make('columns', 'Columns')
->visibleWhen(fn($rule) => $rule->whenIn('layout', ['grid', 'masonry']))
->min(1)
->max(6)
->default(3),
Range::make('gap', 'Gap')
->visibleWhen(fn($rule) => $rule->when('layout', 'grid'))
->min(0)
->max(100)
->default(20),
];
}
```
### Advanced Settings Toggle
```php
public static function settings(): array
{
return [
Switch::make('showAdvanced', 'Show Advanced Settings')
->default(false),
// Basic settings always visible
Text::make('title', 'Title'),
// Advanced settings only visible when toggle is on
Range::make('maxWidth', 'Max Width')
->visibleWhen(fn($rule) => $rule->whenTruthy('showAdvanced'))
->min(200)
->max(1200),
Select::make('animation', 'Animation')
->visibleWhen(fn($rule) => $rule->whenTruthy('showAdvanced'))
->options([
'none' => 'None',
'fade' => 'Fade',
'slide' => 'Slide',
]),
];
}
```
## Best Practices
### Keep Conditions Simple
```php
// ✅ Clear and simple
->visibleWhen(fn($rule) => $rule->when('layout', 'grid'))
// ❌ Overly complex
->visibleWhen(fn($rule) => $rule
->when('layout', 'grid')
->or(fn($r) => $r->when('layout', 'flex'))
->whenGt('columns', 2)
->or(fn($r) => $r->whenTruthy('force'))
)
```
### Use Descriptive Field Names
```php
// ✅ Clear field names
->visibleWhen(fn($rule) => $rule->when('showAdvancedOptions', true))
// ❌ Unclear field names
->visibleWhen(fn($rule) => $rule->when('flag', true))
```
### Provide Default Values
Always set sensible defaults for conditionally visible settings, as they may be hidden when merchants first see the settings panel.
```php
Text::make('gridGap', 'Grid Gap')
->visibleWhen(fn($rule) => $rule->when('layout', 'grid'))
->default('1rem') // ✅ Default provided
```
---
---
url: /core-concepts/dynamic-sources.md
---
# Dynamic Sources
Dynamic sources allow property values to be resolved from runtime context using `@path.to.value` syntax, enabling blocks and sections to access data from page variables, models, or parent-shared data.
## What Are Dynamic Sources?
Dynamic sources provide a way to bind block properties to runtime data without hardcoding values. Instead of static property values, you use the `@` prefix followed by a path to reference data from:
* **Page context** - Variables passed from controllers/views
* **Parent blocks/sections** - Data shared via the `share()` method
* **Models and objects** - Nested properties using dot notation
* **Arrays and collections** - Indexed or keyed access
**Static value** (hardcoded):
```json
{
"title": "iPhone 15 Pro",
"price": 999
}
```
**Dynamic source** (runtime):
```json
{
"title": "@product.name",
"price": "@product.price"
}
```
At runtime, `@product.name` resolves to the actual product name from your context.
## Basic Syntax
### Simple Path
Access a top-level context variable:
```json
{
"userName": "@user"
}
```
```php
// Context
return view('page', ['user' => 'John Doe']);
// Resolves to
$block->settings->userName; // "John Doe"
```
### Dot Notation
Navigate nested objects and arrays:
```json
{
"authorName": "@post.author.name",
"authorEmail": "@post.author.email"
}
```
```php
// Context
$post = (object)[
'author' => (object)[
'name' => 'Jane Smith',
'email' => 'jane@example.com'
]
];
// Resolves to
$block->settings->authorName; // "Jane Smith"
$block->settings->authorEmail; // "jane@example.com"
```
### Array Access
Access array elements by index:
```json
{
"firstImage": "@product.images.0.url",
"secondImage": "@product.images.1.url"
}
```
```php
// Context
$product = [
'images' => [
['url' => '/img1.jpg'],
['url' => '/img2.jpg'],
]
];
// Resolves to
$block->settings->firstImage; // "/img1.jpg"
$block->settings->secondImage; // "/img2.jpg"
```
## Context Sources
### Page Context (Controller/View)
Pass data from controllers or views to templates:
```php
// ProductController.php
public function show(Product $product)
{
return view('products.show', [
'product' => $product,
'relatedProducts' => $product->related()->take(4)->get(),
'currency' => 'USD',
]);
}
```
In your JSON/YAML template:
```yaml
sections:
- id: product-hero
type: '@awesome-theme/product-hero'
settings:
name: '@product.name'
price: '@product.price'
description: '@product.description'
currency: '@currency'
```
### Parent Shared Data
Parent blocks/sections share data with children using `share()`:
```php
class ProductCard extends SimpleBlock
{
protected static array $accepts = [
'@awesome-theme/product-image',
'@awesome-theme/product-title',
'@awesome-theme/product-price',
];
public function share(): array
{
return [
'product' => $this->block->settings->product ?? $this->context('product'),
'showPrices' => $this->block->settings->showPrices ?? true,
];
}
}
```
Child blocks access shared data using `@` syntax in presets:
```php
Preset::make('Product Card')
->blocks([
PresetBlock::make('@awesome-theme/product-image')
->settings([
'src' => '@product.base_image.url',
'alt' => '@product.name',
]),
PresetBlock::make('@awesome-theme/product-title')
->settings([
'text' => '@product.name',
]),
PresetBlock::make('@awesome-theme/product-price')
->settings([
'amount' => '@product.price',
'show' => '@showPrices',
]),
])
```
## Using in Setting Defaults
Dynamic sources can be used in setting defaults:
```php
public static function settings(): array
{
return [
Text::make('productName', 'Product Name')
->default('@product.name'),
Number::make('price', 'Price')
->default('@product.price'),
Image::make('image', 'Image')
->default('@product.base_image.url'),
];
}
```
***
**Next:** [Templates Overview](/core-concepts/templates/overview)
---
---
url: /building-theme/create-theme.md
---
# Creating a New Theme
Bagisto Visual makes it easy to create a new theme using a single command.
## Step 1: Generate a Theme
To scaffold a brand new theme, run the following Artisan command:
```bash
php artisan visual:make-theme "Awesome Theme"
```
By default, the theme will be placed under the `Themes` vendor namespace.
***
### Optional: Customize the Vendor Name
You can also customize the vendor (namespace) if needed:
```bash
php artisan visual:make-theme "Awesome Theme" --vendor="MyVendor"
```
This will generate the theme inside:
```text
src/Packages/MyVendor/AwesomeTheme/
```
If the `--vendor` option is not provided, it defaults to:
```text
src/Packages/Themes/AwesomeTheme/
```
✅ This is useful if you're developing themes under different brand or client namespaces.
## Step 2: Theme Directory Structure
Here’s what a freshly generated theme looks like:
```text
AwesomeTheme/
├── config/
│ ├── settings.php # Global theme settings (colors, fonts, social links, etc.)
│ └── theme.php # Main theme metadata (name, author, version)
├── resources/
│ ├── assets/
│ │ └── images/
│ │ └── theme-preview.png # Theme preview image
│ └── views/
│ ├── blocks/ # Blade views for blocks
│ ├── components/ # Blade components used inside sections
│ ├── layouts/ # Main layouts (default.blade.php, account.blade.php)
│ ├── sections/ # Blade views for each section
│ └── templates/ # Page templates (Blade, JSON, or YAML)
├── src/
│ ├── Blocks/ # PHP classes defining blocks
│ │ ├── ExampleBlock.php
│ │ └── ...
│ ├── Sections/ # PHP classes defining sections
│ │ ├── ExampleSection.php
│ │ └── ...
│ └── ServiceProvider.php # Registers the theme into Bagisto Visual
├── package.json # Frontend dependencies and build scripts
├── composer.json # PHP package metadata for autoloading
├── tailwind.config.js # TailwindCSS configuration (optional)
├── vite.config.ts # ViteJS configuration for assets
└── README.md # Theme documentation (optional)
```
✅
The `theme-preview.png` file will be used to visually represent your theme in the Theme Editor.
### Understanding Important Files
#### `config/theme.php`
Defines core metadata and configuration for your theme:
```php
"awesome-theme",
"name" => "Awesome Theme",
"version" => "1.0.0",
"author" => "Your Company Name",
"assets_path" => "public/themes/shop/awesome-theme",
"views_path" => "resources/themes/awesome-theme/views",
"preview_image" => "public/themes/shop/awesome-theme/preview.png",
"documentation_url" => "https://yourdomain.com/docs/themes/awesome-theme",
"vite" => [
"hot_file" => "awesome-theme-vite.hot",
"build_directory" => "themes/awesome-theme/dist",
"package_assets_directory" => "resources/assets"
]
];
```
#### `config/settings.php`
Defines editable theme-level settings such as:
* Colors
* Fonts
* Header and footer links
* Social icons
These settings are exposed in the Theme Editor and configurable by merchants.
#### `resources/views/layouts/`
Contains layout Blade files like `default.blade.php`.
All pages render inside one of these layouts.
#### `resources/views/templates/`
Templates define full pages and reference a layout and a list of sections.
They can be Blade, JSON, or YAML.
#### `resources/views/sections/`
Contains section Blade files.
Each section is a reusable UI block that can be added to templates in the visual editor.
### Starting From a Starter Theme
By default, the scaffold generates a **blank theme** with no layout, sections, or styles.
If you prefer to start with a fully built base theme, you can clone the official Bagisto Visual starter theme:
```bash
git clone https://github.com/bagistoplus/visual-debut packages/Themes/YourThemeName
```
Then, update the `composer.json` and `config/theme.php` files to reflect your own theme name and vendor.
✅
This gives you a complete, working theme based on Visual Debut, which you can customize freely — layout, colors, sections, templates, or styles.
## Step 3: Installing and Using the Theme
Once the theme is generated, it is automatically configured inside your Bagisto project using Composer's local repository system.
You can immediately install the theme by running:
```bash
composer require themes/awesome-theme
```
✅
No need to publish the theme package to Packagist or any remote server.
You only need to publish the package if you intend to distribute or share it outside your current project.
## Step 4: Preview the Theme in Admin
After installation, activate your theme in the admin panel:
1. Log into the Bagisto admin panel.
2. Go to **Bagisto Visual → Themes**.
3. You should see the newly installed theme listed.
4. Click on the **Preview** button to see a preview of the theme.
5. Optional: click of the **Customize** button to open the theme in visual editor.
✅
You can start working on your theme now.
## Next Steps
Once your theme is generated, you can continue with:
* [Adding Layouts](./adding-layouts.md)
* [Creating Templates](./adding-templates.md)
* [Creating Sections](./adding-sections/overview.md)
* [Configuring Theme Settings](../core-concepts/settings/theme-settings.md)
---
---
url: /building-theme/adding-layouts.md
---
# Adding Layouts
In Bagisto Visual, layouts define the **main HTML structure** of your pages.
Layouts are Blade files that act as **wrappers** for all templates and sections.
They typically include shared elements like the header, footer, meta tags, and asset loading.
## Creating the `default` Layout
The most important layout file is **`default.blade.php`**.
Create the file inside:
```text
resources/views/layouts/default.blade.php
```
Example content for a basic `default.blade.php`:
```blade
Awesome Theme
@bagistoVite(['resources/assets/css/app.css', 'resources/assets/js/app.js'])
@stack('meta')
@stack('styles')
@visualRegion('header')
@visual_layout_content
@visualRegion('footer')
@stack('scripts')
```
* `@visualRegion('header')` renders the header region (customizable by merchants).
* `@visualRegion('footer')` renders the footer region (customizable by merchants).
* `@visual_layout_content` renders the page content (templates and sections).
* `@bagistoVite([...])` includes theme assets correctly.
## Header and Footer Regions
Regions are customizable zones that merchants can control through the Visual Editor. Create header and footer regions:
```text
resources/views/regions/header.visual.php
resources/views/regions/footer.visual.php
```
Basic `header.visual.php` example:
```php
id('header')
->name('Header')
->sections([
// Merchants can add sections here through the Visual Editor
]);
```
Basic `footer.visual.php` example:
```php
id('footer')
->name('Footer')
->sections([
// Merchants can add sections here through the Visual Editor
]);
```
✅ Regions allow merchants to customize header and footer areas without touching code. Learn more about [Regions](../core-concepts/regions.md).
## Views Namespace
All views inside your theme are automatically registered under two namespaces:
* `shop::` (default and recommended)
* `awesome-theme::` (theme code namespace)
For example:
* `resources/views/layouts/default.blade.php` → `shop::layouts.default`
* `resources/views/sections/hero.blade.php` → `shop::sections.hero`
* `resources/views/components/button.blade.php` → ``
You could also use the `awesome-theme::` namespace (example: `shop::layouts.default` becomes `awesome-theme::layouts.default`),
but to keep it **simple and standard**, we always use the **`shop::` namespace** in this documentation.
## Checking Your Layout
After setting up your layout and regions:
1. Make sure you have created:
* `resources/views/layouts/default.blade.php`
* `resources/views/regions/header.visual.php`
* `resources/views/regions/footer.visual.php`
2. Go to your store **homepage**.
You should now see the default layout rendered —
showing your **header region**, **main area**, and **footer region**.
✅
If you see this, it means your layout setup is working correctly!
Merchants can now customize the header and footer regions through the Visual Editor by adding sections.
# Next Steps
Now that your layout is ready, you can move on to:
* [Creating Templates](./adding-templates.md)
* [Creating Sections](./adding-sections/overview.md)
---
---
url: /building-theme/adding-templates.md
---
# Adding Templates
Templates define the structure of store pages in Bagisto Visual.
They control how sections are arranged and rendered inside the main layout.
Templates can be created using multiple formats:
* **Blade templates** (`.blade.php`) — simple static content or basic Blade directives
* **JSON/YAML templates** (`.json` or `.yaml`) — fully dynamic, section-driven layouts for the Visual Editor
* **PHP templates** (`.visual.php`) — programmatic templates with IDE support and type safety
At this stage, we will start with a Blade template for simplicity.
## Creating a Blade Template
Blade templates are simple files that contain the page content.
They are injected into the layout through `@visual_layout_content`.
To create a homepage template:
1. Create a new file:
```text
resources/views/templates/index.blade.php
```
2. Add the following example content:
```blade
Welcome to Awesome Theme
Your new store is ready to be customized.
```
This content will be rendered inside your theme’s default layout.
There is no need to use `@extends` or `@section`.
## Viewing the Template
Once the template file is created:
* Visit your store homepage in the browser.
* You should see the header and footer rendered from the layout.
* The page body will display the content from `index.blade.php`.
At this stage, no sections are included yet.
Templates are static until sections are added.
## JSON, YAML, and PHP Templates
Bagisto Visual also supports creating templates using JSON, YAML, or PHP files.
These templates enable merchants to visually edit pages, add sections dynamically, and control page structure without touching code.
### JSON/YAML Templates
Use `.json` or `.yaml` files for simple, declarative template definitions:
```json
{
"sections": {
"hero": {
"type": "visual-hero",
"settings": {
"image" => "https://example.com/banner.jpg"
}
}
},
"order": ["hero"]
}
```
### PHP Templates (`.visual.php`)
For more complex templates with IDE support and type safety, use `.visual.php` files:
```php
section('hero', HeroBanner::class)
->section('featured-products', 'visual-featured-products', fn($section) => $section
->properties([
'heading' => 'Featured Products',
'nb_products' => 4,
])
)
->order(['hero', 'featured-products']);
```
**Benefits of PHP templates:**
* ✅ IDE autocomplete and type checking
* ✅ Import and use preset classes directly
* ✅ Use PHP variables, loops, and conditionals
* ✅ Better refactoring support
The structure and behavior of template formats are explained in:
* [JSON & YAML Templates](../core-concepts/templates/json-yaml.md) - Declarative templates
* [PHP Templates](../core-concepts/templates/php-templates.md) - Programmatic templates with IDE support
## Creating Custom Product, Category, and Page Templates
Product, category, and CMS page templates can have custom variants. These variants are assigned to individual resources from the Bagisto admin.
Place custom templates in a type-first directory:
```text
resources/views/templates/
├── product/
│ └── gift-box.json
├── category/
│ └── sale.yaml
└── page/
└── landing.visual.php
```
These files create the template keys `product.gift-box`, `category.sale`, and `page.landing`.
Custom templates use the same JSON, YAML, or `.visual.php` structure as default templates:
```yaml
sections:
product-information:
type: '@awesome-theme/product-information'
order:
- product-information
```
The default data template can also be placed at either `templates/product.yaml` or `templates/product/index.yaml`. The same pattern applies to `category` and `page`.
For the full workflow, see [Custom Templates](../core-concepts/templates/custom-templates.md).
In the next chapter, we will cover:
* How to create sections
* How to use sections inside templates to build dynamic pages
For now, starting with a simple Blade template is sufficient to initialize your theme.
## Summary
* Templates define page content and are rendered inside layouts.
* Blade templates are static and easy to start with.
* JSON/YAML/PHP templates enable full dynamic editing and will be introduced after learning about sections.
* PHP templates (`.visual.php`) provide IDE support and type safety.
* Templates must be placed in `resources/views/templates/`.
Read more about [available default templates](../core-concepts/templates/available.md)
## Next Steps
* [Adding Sections](./adding-sections/overview.md)
---
---
url: /building-theme/adding-sections/overview.md
---
# Working with Sections
In Bagisto Visual, sections are the building blocks of page templates. They are reusable, configurable components that render dynamic content, and can be defined using Blade or Livewire.
This guide walks you through everything you need to know about creating, configuring, and using sections in themes and templates.
## Topics Covered
* [Creating a Section](./creating-section.md)
Generate a new section using Artisan and understand where the files are placed.
* [Section Attributes](./section-attributes.md)
Learn about common properties like `type`, `name`, `view`, `wrapper`, settings, and how to configure blocks.
* [Writing section view](./writing-section-view.md)
Use settings and blocks in the Blade view to produce structured and styled HTML output.
* [Using Sections in Templates](./using-section.md)
Reference sections in JSON/YAML templates with examples and field details.
---
---
url: /building-theme/adding-sections/creating-section.md
---
# Creating a Section
A section is a configurable UI component used to compose templates in Bagisto Visual.
Basically a section is just a Blade or Livewire component that defines structure, behavior, settings, and rendering logic.
## Generate a Section
To generate a new section, use the `visual:make-section` Artisan command:
```bash
php artisan visual:make-section AnnouncementBar --theme=awesome-theme
```
This will create a basic section class named `AnnouncementBar` inside the awesome-theme package:
```text
packages/Themes/AwesomeTheme/src/Sections/AnnouncementBar.php
packages/Themes/AwesomeTheme/resources/views/sections/announcement-bar.blade.php
```
### Interactive Mode
You can omit arguments to use interactive prompts:
```bash
php artisan visual:make-section
```
The command will prompt you for:
* **Section name** (e.g., `AnnouncementBar`)
* **Target theme** (selects from installed Visual themes or `app/Visual`)
## Command Options
### Section Types
The command generates different section types based on flags:
| Option | Section Type | Description |
|--------|--------------|-------------|
| *(none)* | `SimpleSection` | **Default.** Lightweight section. Best for simple sections that don't need component features. |
| `--component` | `BladeSection` | Blade component-based section. Use when you prefer Blade component patterns. |
| `--livewire` | `LivewireSection` | Livewire component-based section. Use when you need reactive behavior or real-time updates. |
::: info
All section types support child blocks. The choice between `SimpleSection`, `BladeSection`, and `LivewireSection` is based on your preferred development style and feature needs.
:::
::: warning
You cannot use both `--component` and `--livewire` flags together.
:::
### Other Options
| Option | Description |
|--------|-------------|
| `--theme=awesome-theme` | Target theme slug. Omit to use interactive selection. |
| `--force` | Overwrite existing section files if they already exist. |
## Generated Files
### Default Section (SimpleSection)
**Command:**
```bash
php artisan visual:make-section AnnouncementBar --theme=awesome-theme
```
**Generated class:**
```php
```
### Blade Component Section (BladeSection)
**Command:**
```bash
php artisan visual:make-section Header --component --theme=awesome-theme
```
**Generated class:**
```php
In default app
```
This generates files in your application directory:
```text
app/Visual/Sections/AnnouncementBar.php
resources/views/sections/announcement-bar.blade.php
```
**Namespace:** `App\Visual\Sections`
::: info
Sections in `app/Visual` are useful for:
* Quick prototyping
* Application-specific sections not tied to a theme
* Shared sections used across multiple themes
:::
## Overwriting Existing Files
Use the `--force` flag to overwrite existing section files:
```bash
php artisan visual:make-section AnnouncementBar --theme=awesome-theme --force
```
Without `--force`, the command will error if files already exist:
```
❌ Section class already exists: packages/.../AnnouncementBar.php (use --force to overwrite)
```
## Registering Sections
Bagisto Visual automatically discovers sections from:
* `app/Visual/Sections`
* `packages///src/Sections`
For other locations, you can manually register sections in a service provider:
### Discover a directory
Use `discoverSectionsIn()` to auto-discover all sections in a directory. The method requires two parameters:
* The directory path containing your section classes
* The base namespace for those sections (defaults to `'App\\Sections'`)
```php
Visual::discoverSectionsIn(
base_path('modules/Shared/Sections'),
'Modules\\Shared\\Sections'
);
```
This will automatically discover and register all section classes in the specified directory, matching the namespace structure to the folder structure.
### Register a single class
```php
Visual::registerSection(\App\Custom\Sections\PromoBanner::class);
```
Or for theme packages:
```php
Visual::registerSection(\Themes\AwesomeTheme\Sections\AnnouncementBar::class);
```
## Examples
### Create a simple section in a theme
```bash
php artisan visual:make-section Hero --theme=awesome-theme
```
### Create a Blade component section
```bash
php artisan visual:make-section Footer --component --theme=awesome-theme
```
### Create a Livewire section for interactive features
```bash
php artisan visual:make-section SearchFilters --livewire --theme=awesome-theme
```
### Create in app/Visual with interactive prompts
```bash
php artisan visual:make-section
# Select "In default app" from the menu
```
### Force overwrite existing section
```bash
php artisan visual:make-section Hero --theme=awesome-theme --force
```
***
Next: [Section Attributes](./section-attributes.md)
---
---
url: /building-theme/adding-sections/section-attributes.md
---
# Section Attributes
Section classes in Bagisto Visual can define a number of attributes that control how they are identified, rendered, and displayed in the editor.
## type
The block type identifier used to reference this section in templates and the Visual Editor.
```php
protected static string $type = '@awesome-theme/announcement-bar';
```
or
```php
public static function type(): string
{
return '@awesome-theme/announcement-bar';
}
```
**Default:**
If omitted, the type is generated from the class name using kebab-case.
`AnnouncementBar` becomes `announcement-bar`
**Recommended format:** `@vendor/section-type`
It's recommended to include a vendor prefix (e.g., `@awesome-theme/announcement-bar`) to avoid collisions, especially when sections come from packages. This ensures uniqueness across different themes and packages.
This is the identifier used in templates:
```json
{
"sections": {
"my-announcement": {
"type": "@awesome-theme/announcement-bar"
}
}
}
```
## name
Display name in the section editor.
```php
protected static string $name = 'Announcement Bar';
```
or
```php
use function BagistoPlus\Visual\t;
public static function name(): string
{
return t('awesome-theme::sections.announcement_bar.name');
}
```
**Default:**
Derived from the class name, title-cased.
Example: `AnnouncementBar` becomes "Announcement Bar".
## view
Blade view used to render the section.
```php
protected static string $view = 'shop::sections.announcement-bar';
```
**Default:**
* For theme sections: `shop::sections.{slug}`
* For non-theme sections: `sections.{slug}`
## wrapper
HTML wrapper using a simplified Emmet-style syntax. When a wrapper is defined, the necessary attributes for the Visual Editor are injected automatically.
```php
protected static string $wrapper = 'section#announcement-bar>div.container';
```
Results in:
```html
```
**Default:** `section`
### Without a wrapper
When no wrapper is defined, you must manually add the editor attributes to the root element in your Blade view so the section can be handled in the Visual Editor:
```blade
editor_attributes }}>
```
The editor\_attributes helper injects the necessary data attributes required for the Visual Editor to identify and interact with the section.
## description
Short description shown in the section picker in the theme editor.
```php
protected static string $description = 'Used for banners or alerts.';
```
or
```php
use function BagistoPlus\Visual\t;
public static function description(): string
{
return t('awesome-theme::sections.announcement_bar.description');
}
```
## category
Groups sections together in the section picker of the Visual Editor.
```php
protected static string $category = 'Marketing';
```
or
```php
use function BagistoPlus\Visual\t;
public static function category(): string
{
return t('awesome-theme::sections.categories.marketing');
}
```
Sections with the same category will be grouped together in the section picker, making it easier for merchants to find related sections.
Common categories: `Header`, `Hero`, `Marketing`, `Products`, `Content`, `Footer`, `Forms`
## icon
Icon displayed in the section picker in the Visual Editor. Must be a raw SVG string.
```php
protected static string $icon = '';
```
or
```php
public static function icon(): string
{
return '';
}
```
**Default:** A default stack icon is used if not specified.
## previewImageUrl
Path to a preview image, relative to the `public/` directory or a full URL.
Displayed in the section picker in the theme editor
```php
protected static string $previewImageUrl = 'images/sections/announcement-bar-preview.png';
```
or
```php
public static function previewImageUrl(): string
{
return url('images/sections/announcement-bar-preview.png');
}
```
**Default:**
* Theme: `vendor/themes/awesome-theme/assets/images/sections/{slug}-preview.png`
* Non-theme: `images/sections/{slug}-preview.png`
## previewDescription
Optional text shown below the preview image.
```php
protected static string $previewDescription = 'Displays a rotating announcement banner.';
```
or
```php
use function BagistoPlus\Visual\t;
public static function previewDescription(): string
{
return t('awesome-theme::sections.announcement_bar.preview_description');
}
```
## accepts
Defines which block types can be added to this section.
```php
protected static array $accepts = [
'@awesome-theme/heading',
'@awesome-theme/button',
'@awesome-theme/image',
];
```
### Wildcards:
Accept all blocks:
```php
protected static array $accepts = ['*'];
```
Accept all blocks from a specific vendor/package:
```php
protected static array $accepts = ['@awesome-theme/*'];
```
### Using block classes:
You can also reference blocks using their PHP class names:
```php
use Themes\AwesomeTheme\Blocks\Heading;
use Themes\AwesomeTheme\Blocks\Button;
protected static array $accepts = [
Heading::class,
Button::class,
];
```
**Default:** `['*']`
Render blocks in your section view using `@children`:
```blade
@children
```
## presets
Defines pre-configured variations of the section that merchants can choose from when adding the section. Presets allow you to provide quick-start templates with predefined settings and blocks.
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('awesome-theme::presets.hero.centered.name'))
->description(t('awesome-theme::presets.hero.centered.description'))
->settings([
'heading' => t('awesome-theme::presets.hero.centered.heading'),
'layout' => 'centered',
'background_color' => '#4f46e5',
])
->blocks([
PresetBlock::make('@awesome-theme/heading')
->id('hero-title')
->settings(['text' => t('awesome-theme::presets.hero.centered.heading'), 'level' => 1]),
PresetBlock::make('@awesome-theme/button')
->id('hero-cta')
->settings(['text' => t('awesome-theme::presets.hero.centered.cta'), 'style' => 'primary']),
]),
Preset::make(t('awesome-theme::presets.hero.image_left.name'))
->description(t('awesome-theme::presets.hero.image_left.description'))
->settings([
'heading' => t('awesome-theme::presets.hero.image_left.heading'),
'layout' => 'left',
]),
];
}
```
Presets support:
* `name()` - Display name in the preset picker
* `description()` - Optional description text
* `settings()` - Default settings values
* `children` - Pre-configured child blocks using PresetBlock
* `icon()` - Optional icon (SVG string)
* `category()` - Optional category for grouping
* `previewImageUrl()` - Optional preview image URL
For comprehensive documentation on creating presets with nested blocks, categories, and advanced features, see the [Presets Guide](../../core-concepts/presets.md).
## settings
Defines the configurable fields for the section that appear in the Visual Editor's settings panel.
```php
use BagistoPlus\Visual\Settings\Text;
use BagistoPlus\Visual\Settings\Color;
use BagistoPlus\Visual\Settings\Link;
use function BagistoPlus\Visual\t;
public static function settings(): array
{
return [
Text::make('heading', t('awesome-theme::sections.hero.heading'))
->default(t('awesome-theme::sections.hero.default_heading')),
Color::make('background_color', t('awesome-theme::sections.hero.background_color'))
->default('#4f46e5'),
Link::make('cta_link', t('awesome-theme::sections.hero.cta_link')),
];
}
```
### Dynamic Defaults
Settings can use **dynamic sources** to populate defaults from runtime context:
```php
use function BagistoPlus\Visual\t;
public static function settings(): array
{
return [
Text::make('productName', t('awesome-theme::products.name'))
->default('@product.name'),
Number::make('price', t('awesome-theme::products.price'))
->default('@product.price'),
Image::make('image', t('awesome-theme::products.image'))
->default('@product.base_image.url'),
];
}
```
The `@path.to.value` syntax resolves from page context (controller variables) or parent-shared data. **[Learn more about Dynamic Sources](/core-concepts/dynamic-sources)**
For all available setting types and their options, see the [Settings documentation](../../core-concepts/settings/types.md).
## enabledOn
Specifies which **templates** and **regions** this section can be added to.
```php
protected static array $enabledOn = [
'templates' => ['index', 'product', 'account/*'],
'regions' => ['header', 'footer'],
];
```
* `templates` - Array of template types where this section can be added (optional)
* `regions` - Array of region IDs where this section can be added (optional)
Both keys are optional. You can specify templates only, regions only, or both.
**Examples:**
Restrict to specific templates only:
```php
protected static array $enabledOn = [
'templates' => ['index', 'product'],
];
```
Restrict to specific regions only:
```php
protected static array $enabledOn = [
'regions' => ['header', 'footer'],
];
```
Restrict to both templates and regions:
```php
protected static array $enabledOn = [
'templates' => ['index', 'product'],
'regions' => ['header'],
];
```
Wildcards are supported in templates:
* `'account/*'` matches account/profile, account/addresses, etc.
* `'*'` matches all templates
**Default:** No restrictions (can be added anywhere)
## disabledOn
Specifies which **templates** and **regions** this section should be excluded from.
```php
protected static array $disabledOn = [
'templates' => ['checkout', 'auth/*'],
'regions' => ['sidebar'],
];
```
* `templates` - Array of template types to exclude this section from (optional)
* `regions` - Array of region IDs to exclude this section from (optional)
Both keys are optional. You can exclude from templates only, regions only, or both.
**Example:**
Exclude from checkout templates:
```php
protected static array $disabledOn = [
'templates' => ['checkout'],
];
```
`disabledOn` takes priority over `enabledOn` when both are specified.
**Default:** No exclusions
***
Next: [Writing the Section View](./writing-section-view.md)
---
---
url: /building-theme/adding-sections/writing-section-view.md
---
# Rendering a Section
Each section has an associated Blade view that defines how its settings and blocks are displayed. The view is automatically injected with a `$section` object.
## Accessing Data in the View
In your Blade file (e.g. `resources/views/sections/announcement-bar.blade.php`), use:
* `$section->settings` — for static fields defined in `settings()`
* `$section->children` — for accessing child blocks added by merchants
* `$section->editor_attributes` — for Visual Editor attributes (required when no wrapper is defined)
## Editor Attributes
When your section doesn't define a `wrapper` attribute, you must add {{ $section->editor\_attributes }} to the root element of your view. This injects the necessary data attributes for the Visual Editor to identify and interact with the section.
```blade
editor_attributes }} class="announcement-bar">
```
If your section defines a `wrapper` attribute, the editor attributes are automatically injected and you don't need to add them manually. See [Section Attributes - wrapper](./section-attributes.md#wrapper) for more details.
## Example: Rotating Announcement Bar
This example demonstrates an announcement bar section that accepts multiple announcement blocks.
### Section Class
```php
default('#facc15'),
Color::make('text_color', 'Text Color')->default('#000000'),
];
}
protected static array $accepts = ['@awesome-theme/announcement'];
public static function presets(): array
{
return [
Preset::make('Default Announcements')
->description('Announcement bar with three sample messages')
->settings([
'background_color' => '#facc15',
'text_color' => '#000000',
])
->blocks([
PresetBlock::make('@awesome-theme/announcement')
->settings(['text' => 'Free shipping on all orders over $50']),
PresetBlock::make('@awesome-theme/announcement')
->settings(['text' => 'Extended returns until January 31st']),
PresetBlock::make('@awesome-theme/announcement')
->settings(['text' => 'New arrivals just added - Shop now!']),
]),
];
}
}
```
### Section Blade View
The section view (`resources/views/sections/announcement-bar.blade.php`):
```blade
editor_attributes }}
class="announcement-bar py-3 text-center font-medium"
style="background-color: {{ $section->settings->background_color }}; color: {{ $section->settings->text_color }}"
x-data="{
current: 0,
total: {{ $section->childrenCount() }},
init() {
if (this.total > 1) {
setInterval(() => {
this.current = (this.current + 1) % this.total
}, 5000)
}
}
}"
>
@if($section->childrenCount() > 1)
@endif
@children
@if($section->childrenCount() > 1)
@endif
```
### Announcement Block
The announcement block that will be used inside the section. For more details on creating blocks, see [Creating a Block](../adding-blocks/creating-block.md).
**Block class** (`src/Blocks/Announcement.php`):
```php
default('Your announcement message here'),
];
}
}
```
**Block view** (`resources/views/blocks/announcement.blade.php`):
```blade
```
### How it works
* The section auto-rotates announcements every 5 seconds when there are multiple messages
* Navigation arrows appear only when there's more than one announcement
* The section uses `@children` to render all announcement blocks
* Each announcement block uses `$block->index` to show/hide based on the section's `current` state
* Alpine.js transitions in the block view provide smooth fade effects
## Notes
* Use `$section->settings->key` to access section settings.
* Use `@children` to render all child blocks that merchants add through the Visual Editor.
* Always include {{ $section->editor\_attributes }} on the root element when not using a wrapper.
* For complex interactions like carousels or tabs, consider implementing the logic in JavaScript that wraps around the rendered children.
***
Next: [Using Sections in Templates](./using-section.md)
---
---
url: /building-theme/adding-sections/using-section.md
---
# Using Sections in Templates
Once a section is defined, it can be used in a page template a layout.
## Usage in JSON Templates
Sections can be used in JSON or YAML template files. See [JSON/YAML Templates](../../core-concepts/templates/json-yaml.md) for more details.
:::: tabs
::: tab JSON
```json
{
"sections": {
"announcement-bar": {
"type": "@awesome-theme/announcement-bar",
"settings": {
"text": "Free shipping on all orders",
"background_color": "#facc15",
"text_color": "#000000"
},
"blocks": {
"first": {
"type": "@awesome-theme/announcement",
"settings": {
"text": "Extended returns until Jan 31"
}
},
"second": {
"type": "@awesome-theme/announcement",
"settings": {
"text": "Free delivery on orders over $50"
}
}
}
}
},
"order": ["announcement-bar"]
}
```
:::
::: tab YAML
```yaml
sections:
announcement-bar:
type: '@awesome-theme/announcement-bar'
settings:
text: Free shipping on all orders
background_color: '#facc15'
text_color: '#000000'
blocks:
first:
type: '@awesome-theme/announcement'
settings:
text: Extended returns until Jan 31
second:
type: '@awesome-theme/announcement'
settings:
text: Free delivery on orders over $50
order:
- announcement-bar
```
:::
::::
### Fields
| Field | Description |
| ---------- | ----------------------------------------------------------------- |
| `sections` | Map of section instances keyed by a unique name |
| `order` | List of section keys (from `sections`) to control rendering order |
| | |
| `type` | Section type (e.g., `@awesome-theme/announcement-bar`) |
| `settings` | Section-level settings |
| `blocks` | Named blocks, each with a `type` and `settings` |
## Usage in PHP Templates
You can also use sections programmatically using the `TemplateBuilder` API in PHP templates. See [PHP Templates](../../core-concepts/templates/php-templates.md) for more details.
```php
section('announcement-bar', '@awesome-theme/announcement-bar', fn($section) => $section
->settings([
'text' => 'Free shipping on all orders',
'background_color' => '#facc15',
'text_color' => '#000000',
])
->blocks([
$section->block('first', '@awesome-theme/announcement', fn($block) => $block
->settings(['text' => 'Extended returns until Jan 31'])
),
$section->block('second', '@awesome-theme/announcement', fn($block) => $block
->settings(['text' => 'Free delivery on orders over $50'])
),
])
)
->order(['announcement-bar']);
```
The `section()` method accepts:
* A unique section key
* The section type (`@vendor/section-name`)
* A closure that configures the section's settings and blocks
***
Next: [Section Attributes](./section-attributes.md)
---
---
url: /building-theme/adding-blocks/overview.md
---
# Adding Blocks - Overview
Blocks are the atomic building units of Bagisto Visual. This guide will walk you through creating custom blocks for your theme.
## What You'll Learn
This section covers everything you need to know about building blocks:
* **[Creating a Block](/building-theme/adding-blocks/creating-block)**: Step-by-step guide to creating your first block
* **[Block Attributes](/building-theme/adding-blocks/block-schema)**: Configuring settings, presets, and nested blocks
* **[Static Blocks](/building-theme/adding-blocks/static-blocks)**: Rendering blocks in Blade templates
* **[Container Blocks](/building-theme/adding-blocks/container-blocks)**: Creating blocks that accept child blocks
## When to Create Custom Blocks
Create custom blocks when you need:
* **Reusable components** that appear across multiple sections (buttons, testimonials, badges)
* **E-commerce elements** specific to your store (custom product cards, pricing displays)
* **Branded components** that reflect your design system (CTAs, social proof, icons)
* **Content types** that merchants will manage repeatedly (team members, features, FAQs)
## Block Types Overview
Bagisto Visual provides three base block types to extend:
### BladeBlock
The most common block type. Uses Blade templates for rendering.
**Best for:**
* Standard content blocks (text, images, buttons)
* Blocks with settings but no complex logic
* Most use cases
### LivewireBlock
Dynamic blocks powered by Livewire components.
**Best for:**
* Interactive blocks (forms, calculators, live search)
* Blocks that need real-time updates
* AJAX-based functionality
### SimpleBlock
Minimal blocks without settings or logic.
**Best for:**
* Structural elements (dividers, spacers)
* Static content
* Pure presentation blocks
## Quick Example
Here's a simple block to get you started:
**PHP Class** (`src/Blocks/Testimonial.php`):
```php
namespace Themes\YourTheme\Blocks;
use BagistoPlus\Visual\Block\BladeBlock;
use BagistoPlus\Visual\Settings\Text;
use BagistoPlus\Visual\Settings\Textarea;
use BagistoPlus\Visual\Settings\Image;
class Testimonial extends BladeBlock
{
protected static string $view = 'shop::blocks.testimonial';
public static function settings(): array
{
return [
Text::make('name', 'Customer name'),
Textarea::make('quote', 'Testimonial quote'),
Image::make('photo', 'Customer photo'),
];
}
}
```
**Blade View** (`resources/views/blocks/testimonial.blade.php`):
```blade
@if($block->settings->photo)
@endif
{{ $block->settings->quote }}
{{ $block->settings->name }}
```
That's it! This Testimonial block can now be used in any section that accepts it.
## Directory Structure
```plaintext
/theme/
├── src/
│ └── Blocks/
│ ├── Button.php
│ ├── Testimonial.php
│ ├── ProductCard.php
│ └── Columns.php # Container block
├── resources/
│ └── views/
│ └── blocks/
│ ├── button.blade.php
│ ├── testimonial.blade.php
│ ├── product-card.blade.php
│ └── columns.blade.php
```
**Key points:**
* PHP classes go in `src/Blocks/`
* Blade views go in `resources/views/blocks/`
* One PHP class per block, one Blade view per block
* Class names should be PascalCase, view names should be kebab-case
## Development Workflow
1. **Plan your block**: Decide what settings it needs and where it will be used
2. **Create the PHP class**: Extend BladeBlock, LivewireBlock, or SimpleBlock
3. **Define settings**: Use the settings() method to configure merchant-editable options
4. **Create the Blade view**: Implement the block's HTML and styling
5. **Test in sections**: Add your block to sections and test in the theme editor
6. **Refine**: Iterate based on how merchants use it
## Best Practices
✅ **Keep blocks focused**: One purpose per block (button, testimonial, image)
✅ **Make them reusable**: Design for multiple contexts, not one specific section
✅ **Provide sensible defaults**: Settings should have good default values
✅ **Use clear naming**: Block names should clearly describe their purpose
✅ **Document settings**: Use descriptive labels for merchant-facing settings
✅ **Test responsiveness**: Blocks should work on all screen sizes
## Next Steps
Ready to create your first block? Start with **[Creating a Block](/building-theme/adding-blocks/creating-block)** to build a block step-by-step.
---
---
url: /building-theme/adding-blocks/creating-block.md
---
# Creating a Block
A block is a reusable UI component that can be added to sections in Bagisto Visual.
This guide walks you through creating a custom block step-by-step. We'll build a **Feature** block that displays an icon, heading, and description.
## Generate a Block
To generate a new block, use the `visual:make-block` Artisan command:
```bash
php artisan visual:make-block Feature --theme=awesome-theme
```
This will create a basic block class named `Feature` inside the awesome-theme package:
```text
packages/Themes/AwesomeTheme/src/Blocks/Feature.php
packages/Themes/AwesomeTheme/resources/views/blocks/feature.blade.php
```
### Interactive Mode
You can omit arguments to use interactive prompts:
```bash
php artisan visual:make-block
```
The command will prompt you for:
* **Block name** (e.g., `Feature`)
* **Target theme** (selects from installed Visual themes or `app/Visual`)
## Command Options
### Block Types
The command generates different block types based on flags:
| Option | Block Type | Description |
|--------|------------|-------------|
| *(none)* | `SimpleBlock` | **Default.** Lightweight block. Best for simple blocks that don't need component features. |
| `--component` | `BladeBlock` | Blade component-based block. Use when you prefer Blade component patterns. |
| `--livewire` | `LivewireBlock` | Livewire component-based block. Use when you need reactive behavior or real-time updates. |
::: info
The choice between `SimpleBlock`, `BladeBlock`, and `LivewireBlock` is based on your preferred development style and feature needs.
:::
::: warning
You cannot use both `--component` and `--livewire` flags together.
:::
### Other Options
| Option | Description |
|--------|-------------|
| `--theme=awesome-theme` | Target theme slug. Omit to use interactive selection. |
| `--force` | Overwrite existing block files if they already exist. |
## Generated Files
### Default Block (SimpleBlock)
**Command:**
```bash
php artisan visual:make-block Feature --theme=awesome-theme
```
**Generated class:**
```php
```
### Blade Component Block (BladeBlock)
**Command:**
```bash
php artisan visual:make-block Feature --component --theme=awesome-theme
```
**Generated class:**
```php
In default app
```
This generates files in your application directory:
```text
app/Visual/Blocks/Feature.php
resources/views/blocks/feature.blade.php
```
**Namespace:** `App\Visual\Blocks`
::: info
Blocks in `app/Visual` are useful for:
* Quick prototyping
* Application-specific blocks not tied to a theme
* Shared blocks used across multiple themes
:::
## Overwriting Existing Files
Use the `--force` flag to overwrite existing block files:
```bash
php artisan visual:make-block Feature --theme=awesome-theme --force
```
Without `--force`, the command will error if files already exist:
```
❌ Block class already exists: packages/.../Feature.php (use --force to overwrite)
```
## Registering Blocks
Bagisto Visual automatically discovers blocks from:
* `app/Visual/Blocks`
* `packages///src/Blocks`
For other locations, you can manually register blocks in a service provider:
### Discover a directory
Use `discoverBlocksIn()` to auto-discover all blocks in a directory. The method requires two parameters:
* The directory path containing your block classes
* The base namespace for those blocks (defaults to `'App\\Blocks'`)
```php
Visual::discoverBlocksIn(
base_path('modules/Shared/Blocks'),
'Modules\\Shared\\Blocks'
);
```
This will automatically discover and register all block classes in the specified directory, matching the namespace structure to the folder structure.
### Register a single class
```php
Visual::registerBlock(\App\Custom\Blocks\Feature::class);
```
Or for theme packages:
```php
Visual::registerBlock(\Themes\AwesomeTheme\Blocks\Feature::class);
```
## Complete Example
Let's build a complete **Feature** block with settings and a view:
### Step 1: Add Settings to the Block Class
Edit the generated `Feature.php` class to add settings:
```php
default('heroicon-o-star'),
Text::make('heading', 'Heading')
->default('Amazing Feature'),
Textarea::make('description', 'Description')
->default('This feature will transform your business.'),
Color::make('icon_color', 'Icon color')
->default('#4f46e5'),
];
}
}
```
### Step 2: Create the Blade View
Update the generated view in `resources/views/blocks/feature.blade.php`:
```blade
editor_attributes }} class="feature-block">
{{ $block->settings->heading }}
{{ $block->settings->description }}
```
### The $block Object
The `$block` variable is automatically injected into every block view:
* `$block->settings` - Access block settings
* `$block->id` - Unique block identifier
* `$block->type` - Block type name
* `$block->editor_attributes` - Required attributes for Visual Editor integration
* `$block->index` - Block's position index (useful for conditional rendering)
***
Next: [Block Schema](./block-schema.md)
---
---
url: /building-theme/adding-blocks/block-schema.md
---
# Block Attributes
Block classes in Bagisto Visual can define a number of attributes that control how they are identified, rendered, and displayed in the editor.
## type
The block type identifier used to reference this block in sections and the Visual Editor.
```php
protected static string $type = '@awesome-theme/product-card';
```
or
```php
public static function type(): string
{
return '@awesome-theme/product-card';
}
```
**Default:**
If omitted, the type is generated from the class name using kebab-case.
`ProductCard` becomes `product-card`
**Recommended format:** `@vendor/block-type`
It's recommended to include a vendor prefix (e.g., `@awesome-theme/product-card`) to avoid collisions, especially when blocks come from packages. This ensures uniqueness across different themes and packages.
## name
Display name in the block picker.
```php
protected static string $name = 'Product Card';
```
or
```php
use function BagistoPlus\Visual\t;
public static function name(): string
{
return t('awesome-theme::blocks.product_card.name');
}
```
**Default:**
Derived from the class name, title-cased.
Example: `ProductCard` becomes "Product Card".
## view
Blade view used to render the block.
```php
protected static string $view = 'shop::blocks.product-card';
```
**Default:**
* For theme blocks: `shop::blocks.{slug}`
* For non-theme blocks: `blocks.{slug}`
## wrapper
HTML wrapper using a simplified Emmet-style syntax. When a wrapper is defined, the necessary attributes for the Visual Editor are injected automatically.
```php
protected static string $wrapper = 'div.product-card>div.card-content';
```
Results in:
```html
```
**Default:** `div`
### Without a wrapper
When no wrapper is defined, you must manually add the editor attributes to the root element in your Blade view so the block can be handled in the Visual Editor:
```blade
editor_attributes }} class="product-card">
```
The editor\_attributes helper injects the necessary data attributes required for the Visual Editor to identify and interact with the block.
## description
Short description shown in the block picker in the theme editor.
```php
protected static string $description = 'Displays a product with image, title, and price.';
```
or
```php
use function BagistoPlus\Visual\t;
public static function description(): string
{
return t('awesome-theme::blocks.product_card.description');
}
```
## category
Groups blocks together in the block picker of the Visual Editor.
```php
protected static string $category = 'Product';
```
or
```php
use function BagistoPlus\Visual\t;
public static function category(): string
{
return t('awesome-theme::blocks.categories.product');
}
```
Blocks with the same category will be grouped together in the block picker, making it easier for merchants to find related blocks.
Common categories: `Content`, `Product`, `Layout`, `Media`, `Forms`, `Marketing`
## icon
Icon displayed in the block picker in the Visual Editor. Must be a raw SVG string.
```php
protected static string $icon = '';
```
or
```php
public static function icon(): string
{
return '';
}
```
**Default:** A default block icon is used if not specified.
## previewImageUrl
Path to a preview image, relative to the `public/` directory or a full URL.
Displayed in the block picker in the theme editor.
```php
protected static string $previewImageUrl = 'images/blocks/product-card-preview.png';
```
or
```php
public static function previewImageUrl(): string
{
return url('images/blocks/product-card-preview.png');
}
```
**Default:**
* Theme: `vendor/themes/awesome-theme/assets/images/blocks/{slug}-preview.png`
* Non-theme: `images/blocks/{slug}-preview.png`
## previewDescription
Optional text shown below the preview image.
```php
protected static string $previewDescription = 'Shows product information in a card layout.';
```
or
```php
use function BagistoPlus\Visual\t;
public static function previewDescription(): string
{
return t('awesome-theme::blocks.product_card.preview_description');
}
```
## accepts
For container blocks that can accept child blocks, defines which block types can be nested inside.
```php
protected static array $accepts = [
'@awesome-theme/heading',
'@awesome-theme/button',
'@awesome-theme/image',
];
```
### Wildcards:
Accept all blocks:
```php
protected static array $accepts = ['*'];
```
Accept all blocks from a specific vendor/package:
```php
protected static array $accepts = ['@awesome-theme/*'];
```
### Using block classes:
You can also reference blocks using their PHP class names:
```php
use Themes\AwesomeTheme\Blocks\Heading;
use Themes\AwesomeTheme\Blocks\Button;
protected static array $accepts = [
Heading::class,
Button::class,
];
```
**Default:** `[]` (does not accept children)
### Rendering Children
Render child blocks in your block view using `@children`:
```blade
editor_attributes }} class="card">
{{ $block->settings->title }}
@children
```
## presets
Defines pre-configured variations of the block that merchants can choose from when adding the block. Presets allow you to provide quick-start templates with predefined settings.
```php
use BagistoPlus\Visual\Support\Preset;
use function BagistoPlus\Visual\t;
public static function presets(): array
{
return [
Preset::make(t('awesome-theme::presets.buttons.primary.name'))
->description(t('awesome-theme::presets.buttons.primary.description'))
->settings([
'text' => t('awesome-theme::presets.buttons.primary.text'),
'style' => 'primary',
'size' => 'large',
]),
Preset::make(t('awesome-theme::presets.buttons.secondary.name'))
->description(t('awesome-theme::presets.buttons.secondary.description'))
->settings([
'text' => t('awesome-theme::presets.buttons.secondary.text'),
'style' => 'secondary',
'size' => 'medium',
]),
Preset::make(t('awesome-theme::presets.buttons.outline.name'))
->description(t('awesome-theme::presets.buttons.outline.description'))
->settings([
'text' => t('awesome-theme::presets.buttons.outline.text'),
'style' => 'outline',
'size' => 'medium',
]),
];
}
```
Presets support:
* `name()` - Display name in the preset picker
* `description()` - Optional description text
* `settings()` - Default settings values
* `icon()` - Optional icon (SVG string)
* `category()` - Optional category for grouping
* `previewImageUrl()` - Optional preview image URL
For comprehensive documentation on creating presets, see the [Presets Guide](../../core-concepts/presets.md).
## settings
Defines the configurable fields for the block that appear in the Visual Editor's settings panel.
```php
use BagistoPlus\Visual\Settings\Text;
use BagistoPlus\Visual\Settings\Textarea;
use BagistoPlus\Visual\Settings\Color;
use BagistoPlus\Visual\Settings\Icon;
use function BagistoPlus\Visual\t;
public static function settings(): array
{
return [
Icon::make('icon', t('awesome-theme::blocks.feature.icon'))
->default('heroicon-o-star'),
Text::make('heading', t('awesome-theme::blocks.feature.heading'))
->default(t('awesome-theme::blocks.feature.default_heading')),
Textarea::make('description', t('awesome-theme::blocks.feature.description'))
->default(t('awesome-theme::blocks.feature.default_description')),
Color::make('icon_color', t('awesome-theme::blocks.feature.icon_color'))
->default('#4f46e5'),
];
}
```
For all available setting types and their options, see the [Settings documentation](../../core-concepts/settings/types.md).
## private
Controls whether the block appears in the general block picker. Private blocks are hidden from the main picker but can be made available to specific parent blocks or sections through explicit accepts listing.
```php
protected static bool $private = true;
```
**Default:** `false` (block is public and appears in pickers)
### Visibility Rules
Private blocks follow strict visibility rules:
1. **Hidden from General Picker**: Never appear in the main block picker
2. **Explicit Accepts Required**: Only visible when explicitly listed in a parent's `accepts` array
3. **Wildcards Don't Include Private**: Patterns like `'*'` or `'@vendor/*'` do NOT make private blocks visible
**Example:**
```php
// Private block - only usable within specific contexts
class TabItem extends SimpleBlock
{
protected static bool $private = true;
}
// Section that explicitly accepts the private block
class Tabs extends SimpleSection
{
protected static array $accepts = [
'@awesome-theme/tab-item', // Explicit - TabItem will appear
];
}
// Section with wildcard - private block still hidden
class Container extends SimpleSection
{
protected static array $accepts = ['*']; // TabItem NOT included
}
```
Use private blocks for:
* Component parts (like tab items, accordion panels)
* Blocks that only make sense in specific contexts
* Internal/structural blocks not meant for direct use
***
Next: [Static Blocks](./static-blocks.md)
---
---
url: /building-theme/adding-blocks/static-blocks.md
---
# Static Blocks
Static blocks are blocks that are rendered directly in Blade templates rather than being added through the Visual Editor. They provide a way for developers to maintain control over section structure while still allowing merchants to customize block settings.
Unlike dynamic blocks (which merchants can add, remove, and reorder through the editor), static blocks have a fixed position in the section layout defined by the developer.
::: info Why Use Static Blocks Instead of Direct Components?
Even though static blocks have a fixed position, they remain fully editable in the Visual Editor. Merchants can click on static blocks and customize their settings (text, colors, images, etc.). Static blocks can even accept their own children that merchants can add, remove, and reorder — making the content fully dynamic and merchant-controlled while the structure remains developer-controlled.
:::
## When to Use Static Blocks
Static blocks are ideal for:
* **Structural consistency**: Elements that are core to the section's design and shouldn't be removed
* **Conditional rendering**: Blocks that appear or disappear based on section settings
* **Fixed relationships**: Elements that must always appear together (like an icon paired with a heading)
* **Layout controls**: UI elements like slideshow navigation arrows or accordion icons
## Rendering Static Blocks
To render a static block in your section's Blade view, use the `@visualBlock` directive:
```blade
@visualBlock('type', 'unique-id')
```
### Parameters
* **`type`**: The block type (e.g., `'heading'`, `'@awesome-theme/button'`)
* **`id`**: A unique identifier for this block instance within the section
### Basic Example
```blade
{{-- Static heading block - merchants can edit the text --}}
@visualBlock('heading', 'hero-title')
{{-- Static paragraph block - merchants can edit the content --}}
@visualBlock('paragraph', 'hero-description')
{{-- Dynamic blocks area - merchants can add/remove/reorder blocks --}}
@children
```
::: warning Important
The `id` parameter must be unique within the section. Use descriptive IDs that indicate the block's purpose (e.g., `'hero-title'`, `'footer-logo'`, `'slide-1-caption'`).
:::
## Passing Data to Static Blocks
You can pass custom data to static blocks using an optional third parameter. These attributes are injected into the block's view context and accessible as variables.
### Syntax
```blade
@visualBlock('type', 'id', ['attribute' => 'value'])
```
### Basic Example
```blade
@visualBlock('@awesome-theme/heading', 'hero-title', [
'title' => 'Welcome to Our Store',
'subtitle' => 'Shop the latest trends'
])
```
In the block's view, these attributes are accessible as variables:
```blade
editor_attributes }}>
{{ $title }}
{{ $subtitle }}
```
### With Dynamic Data
Pass data from the section or other sources:
```blade
@visualBlock('@awesome-theme/product-card', 'featured-product', [
'product' => $featuredProduct,
'showPrice' => true,
])
```
Block view:
```blade
editor_attributes }} class="product-card">
{{ $product->name }}
@if($showPrice)
{{ $product->price }}
@endif
```
## Conditional Rendering
One of the key advantages of static blocks is the ability to conditionally render them based on section settings:
```blade
```
The Visual Editor provides visual cues to merchants when conditional static blocks are hidden, helping them understand why a block isn't currently visible.
### Rendering in Loops
Static blocks can also be rendered in loops. Each instance will share the same structure and settings configured by the merchant in the Visual Editor:
```blade
```
In this example:
* The merchant can customize the `testimonial-item` block's settings (colors, layout, etc.) **once** in the Visual Editor
* All instances in the loop share the same configuration
* Each instance receives different data via the attributes array (`$testimonial`)
This is useful for displaying dynamic lists (products, testimonials, blog posts) where you want:
* ✅ Consistent styling across all items (merchant controls design)
* ✅ Different data for each item (developer controls data)
* ✅ Fixed structure (developer controls which items appear)
## Configuring Static Blocks in Presets
One powerful feature of static blocks is the ability to pre-configure them in section presets. When you define a static block with an ID, you can reference that ID in the preset to provide default settings and child block structure.
**Section Blade:**
```blade
@foreach ($products as $product)
{{-- Static block repeated in loop --}}
@visualBlock('@awesome-theme/product-card', 'static-product-card', [
'product' => $product,
])
@endforeach
```
**Section Preset:**
```php
use BagistoPlus\Visual\Support\Preset;
use BagistoPlus\Visual\Support\PresetBlock;
public static function presets(): array
{
return [
Preset::make('Product Grid')
->settings([
'columns' => 4,
'gap' => 4,
])
->blocks([
PresetBlock::make('@awesome-theme/heading')
->settings(['text' => 'Featured Products']),
// Configure the static product card default structure
PresetBlock::make('@awesome-theme/product-card')
->id('static-product-card') // References static block by ID
->static() // Marks as static (required)
->settings([
'border_radius' => 'lg',
'shadow' => true,
])
->children([ // Define default child structure
PresetBlock::make('@awesome-theme/product-image')
->settings([
'aspect_ratio' => 'square',
'object_fit' => 'cover',
]),
PresetBlock::make('@awesome-theme/product-title')
->settings([
'tag' => 'h3',
'size' => 'lg',
]),
PresetBlock::make('@awesome-theme/product-price')
->settings(['show_compare_price' => true]),
PresetBlock::make('@awesome-theme/button')
->settings([
'text' => 'Add to Cart',
'style' => 'primary',
]),
])
])
];
}
```
When a merchant adds this section from the preset, the Visual Editor shows one instance of the static `static-product-card` block with:
* Pre-configured settings (border radius, shadow)
* All child blocks already in place (image, title, price, button)
* Each child block with its own default settings
The merchant customizes this one instance in the Visual Editor, and the configuration applies to all cards in the loop on the storefront.
Merchants can:
* ✅ Edit settings of the static block and its children (applies to all instances)
* ✅ Add, remove, or reorder the child blocks inside (applies to all instances)
* ❌ Cannot move or remove the block itself (it's static and controlled by the loop)
This provides a complete, ready-to-use structure with consistent styling across all loop instances.
***
Next: [Container Blocks](./container-blocks.md)
---
---
url: /building-theme/adding-blocks/container-blocks.md
---
# Container Blocks (Nesting)
Container blocks are blocks that accept child blocks, enabling deep nesting and sophisticated page layouts. This feature transforms the theme editor into a true page builder.
## What are Container Blocks?
Container blocks are regular blocks with one key difference: they can accept other blocks as children. This enables:
* **Multi-column layouts** with different content in each column
* **Tabbed content** with blocks inside each tab
* **Accordions** with rich content in each panel
* **Nested structures** up to 8 levels deep
## Creating a Container Block
To create a container block, define the `$accepts` property:
```php
options([
'2' => '2 Columns',
'3' => '3 Columns',
'4' => '4 Columns',
])
->default('3'),
];
}
}
```
## Rendering Child Blocks
In the container block's view, use the `@children` directive to render child blocks:
```blade
{{-- resources/views/blocks/columns.blade.php --}}
@children
```
## Sharing Data with Child Blocks
Container blocks can share data with their children using the `share()` method. Data returned from `share()` is automatically passed down the entire nested structure, making it available to all descendant blocks.
### How It Works
The `share()` method returns an array of data that becomes available in:
1. **Child block classes**: Access via `$this->context('key', 'default')`
2. **Child block views**: Available as variables (e.g., `$product`, `$category`)
3. **Child block presets**: Use dynamic sources with `@key` syntax (e.g., `'@product.name'`)
4. **Deeply nested blocks**: Automatically cascades to grandchildren and beyond
### Example 1: Product Card Sharing Product Data
The ProductCard container shares the product object so child blocks don't need their own product settings:
```php
class ProductCard extends SimpleBlock
{
protected static string $view = 'shop::blocks.product-card';
protected static array $accepts = [
'@awesome-theme/product-image',
'@awesome-theme/product-title',
'@awesome-theme/product-price',
];
public static function settings(): array
{
return [
Product::make('product', 'Product'),
];
}
public function share(): array
{
return [
'product' => $this->block->settings->product ?? $this->context('product')
];
}
}
```
Now child blocks can access the shared product data:
**In child block classes:**
```php
class ProductImage extends SimpleBlock
{
protected function getViewData(): array
{
$product = $this->context('product');
return [
'imageUrl' => $product?->base_image->url,
];
}
}
```
**In child block views:**
```blade
{{-- In product-image.blade.php view --}}
@if($product)
@endif
```
**In child block presets using dynamic sources:**
```php
PresetBlock::make('@awesome-theme/product-image')
->settings([
'src' => '@product.base_image.url',
'alt' => '@product.name',
]),
PresetBlock::make('@awesome-theme/product-title')
->settings([
'text' => '@product.name',
'url' => '@product.url',
]),
```
The `@` syntax automatically resolves to the shared data at runtime.
### Example 2: Accordion Sharing Icon Type
The Accordion container shares its icon setting with all accordion items:
```php
class Accordion extends SimpleBlock
{
protected static string $view = 'shop::blocks.accordion';
protected static array $accepts = ['@awesome-theme/accordion-item'];
public static function settings(): array
{
return [
Select::make('icon', 'Icon Type')
->options([
'caret' => 'Caret',
'plus' => 'Plus/Minus',
])
->default('caret'),
];
}
public function share(): array
{
return [
'accordionIconType' => $this->block->settings->icon ?? 'caret',
];
}
}
```
All accordion items automatically receive the icon type:
```blade
{{-- In accordion-item.blade.php view --}}
```
***
## Next Steps
* **[Block Attributes](/building-theme/adding-blocks/block-schema)**: Configure accepted blocks and limits
* **[Section Attributes](/building-theme/adding-sections/section-attributes)**: Configure which blocks sections accept
---
---
url: /building-theme/best-practices/overview.md
---
# Best Practices for building theme
Bagisto Visual gives developers a powerful and flexible system for building customizable storefronts. But with flexibility comes the need for consistency and thoughtful design.
This section outlines best practices for creating maintainable, accessible, and performant visual themes and sections.
Whether you're building a full theme or just a single reusable section, these guidelines will help ensure your work:
* Integrates smoothly with the visual editor
* Adheres to accessible and semantic markup
* Works reliably across templates and devices
* Supports theme-level customization and branding
## Topics Covered
* [Styling and Color System](./styling.md)
Use the shared design token system to ensure theme compatibility and customization.
* [Accessibility](./accessibility.md)
Build for users of all abilities with semantic HTML and keyboard support.
* [Performance](./performance.md)
Deliver lightweight, responsive sections and themes.
***
Following these practices helps you build better themes — and helps merchants build better stores.
---
---
url: /building-theme/best-practices/integrating-editor.md
---
# Integrating with the Visual Editor
Bagisto Visual includes a live preview editor that allows merchants to build and customize storefront pages interactively, without reloading the page. When a section or block is added, updated, or removed through the editor, its HTML is dynamically re-rendered from the backend and injected into the DOM in place—without triggering a full page reload.
However, any JavaScript behavior associated with sections or blocks (like carousels, modals, or event listeners) is not automatically re-initialized. Additionally, some setting changes—such as text, image URLs, or inline styles—can be updated instantly in the browser, without requiring a backend re-render.
This guide explains how to:
* Reinitialize JavaScript behavior when sections or blocks are re-rendered
* Enable instant, client-side updates for simple setting types
* Ensure blocks are visible and interactable when being edited
By integrating with these editor behaviors, your sections and blocks will feel fast, predictable, and intuitive to customize.
## 1. Reinitializing JavaScript
When a section or block is updated in the editor, its DOM is replaced. Any interactive JavaScript (like sliders or dropdowns) must be reattached.
Bagisto Visual emits events during this lifecycle:
### Common Events
| Event | Timing | Use case |
| ----------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `visual:section:load` | After section is added or re-rendered | Re-run any necessary JavaScript to ensure the section functions and displays correctly, as if the page were freshly loaded. You may also want to restore the section state. |
| `visual:section:unload` | Before section is removed or re-rendered | Make sure to clean up event listeners, variables, and anything else to prevent issues when interacting with the page and avoid memory leaks. Also, save the section state. |
| `visual:block:load` | After block is added or re-rendered | Re-run block-specific JavaScript behavior. |
| `visual:block:unload` | Before block is removed or re-rendered | Clean up block-specific event listeners and state. |
### Lifecycle Events
| Event | Timing |
| ------------------------------- | ----------------------------- |
| `visual:section:adding` | Before section is added |
| `visual:section:added` | After section is added |
| `visual:section:removing` | Before section is removed |
| `visual:section:removed` | After section is removed |
| `visual:section:updating` | Before section is updated |
| `visual:section:updated` | After section is updated |
| `visual:section:moving` | Before section is moved |
| `visual:section:moved` | After section is moved |
| `visual:section:setting:updated` | When a section setting changes |
| `visual:block:adding` | Before block is added |
| `visual:block:added` | After block is added |
| `visual:block:removing` | Before block is removed |
| `visual:block:removed` | After block is removed |
| `visual:block:updating` | Before block is updated |
| `visual:block:updated` | After block is updated |
| `visual:block:moving` | Before block is moved |
| `visual:block:moved` | After block is moved |
| `visual:block:setting:updated` | When a block setting changes |
All block and section events also emit scoped variants when the relevant id is available:
| Scoped event pattern | Use case |
| -------------------------------------------- | --------------------------------------------- |
| `visual:block:{event}:{blockId}` | Listen to one block instance |
| `visual:section:{event}:{sectionBlockId}` | Listen to one section instance |
| `visual:block:setting:updated:{settingId}` | Listen to one block setting across instances |
| `visual:section:setting:updated:{settingId}` | Listen to one section setting across sections |
Sections are top-level blocks in the editor data model. Section-scoped events therefore use the section block id, and they only fire when the event payload block has no `parentId`.
Each event exposes:
```ts
event.detail = {
sectionId, // Section ID
section, // Section object
blockId, // Block ID (when applicable)
block, // Block object (when applicable)
};
```
### Detect the Theme Editor
Use `@visual_design_mode` and `@end_visual_design_mode` directives to scope code that should only run in the Visual Editor live preview.
```blade
@visual_design_mode
You are in design mode
@pushOnce('scripts')
@endPushOnce
@end_visual_design_mode
```
This prevents editor-specific code from running on the live storefront, keeping your production code clean and performant.
### Section Example
```blade
@visual_design_mode
@pushOnce('scripts')
@endPushOnce
@end_visual_design_mode
```
### Block Example
```blade
@visual_design_mode
@pushOnce('scripts')
@endPushOnce
@end_visual_design_mode
```
If you are using `Alpine.js` or `Livewire`, your state will automatically persist between updates—no additional setup is needed. However, if you rely on vanilla JS or third-party libraries, you should reinitialize them after every update.
## 2. Enabling Instant Setting Updates
For simple updates (text, image URLs, classes), you can avoid full re-renders and apply changes directly in the DOM to provide instant preview without delay.
Bagisto Visual supports this via:
***
### Option 1: `liveUpdate()` Blade Directives
Use `$section->liveUpdate()` or `$block->liveUpdate()` to bind settings to elements.
These helpers inject metadata to enable the editor to update the live preview without requiring a server-side re-render.
#### `->text(string $settingId)`
**Updates the element's `textContent`** whenever the specified setting changes.
```blade
```
#### `->attr(string $settingId, string $attributeName)`
**Updates the specified HTML attribute** (e.g. `src`, `href`, `alt`) with the setting value.
```blade
liveUpdate()->attr('image', 'src') }}>
```
#### `->style(string $settingId, string $property)`
**Updates a specific CSS style property** on the element using the setting value.
```blade
```
### Option 2: JavaScript API (`Visual.handleLiveUpdate()`)
For more complex cases (e.g. multiple targets, transform logic, or styling), use `Visual.handleLiveUpdate()`:
```blade
@visual_design_mode
@pushOnce('scripts')
@endPushOnce
@end_visual_design_mode
```
***
### API Reference: `handleLiveUpdate`
```ts
handleLiveUpdate(
sectionType: string,
mappings: {
section?: Record;
blocks?: Record>;
}
)
```
### LiveUpdateOptions
| Option | Description |
| ----------- | ---------------------------------------- |
| `target` | CSS selector within the section |
| `text` | Replace text content |
| `html` | Replace inner HTML |
| `attr` | Set a DOM attribute (e.g. `src`, `href`) |
| `style` | Set a CSS style property |
| `handler` | Custom JS function `(el, value) => {}` |
| `transform` | Modify the value before applying it |
## 3. Keep Edited Blocks Visible
When a merchant is editing a block, that block should remain visible — even if it's part of a carousel, tab, or other dynamic view.
**Best Practice:**
* When rendering blocks dynamically (e.g. in a slider), ensure the currently edited block is active or in view.
* This enhances clarity and ensures live changes are reflected immediately.
> You can detect which block is being edited using the `visual:section:updated` event and `event.detail`.
No JavaScript is strictly required, but your UI logic should accommodate visibility for active blocks.
## 4. Summary
* Use `@visual_design_mode` to scope editor-specific behavior
* Use `liveUpdate()` for simple instant updates
* Use `handleLiveUpdate()` for advanced DOM control
* Reinitialize JavaScript using `visual:section:load` and `visual:block:load`
* Make edited blocks clearly visible in the preview
These patterns help ensure your sections and blocks behave consistently and responsively within the live editor environment.
---
---
url: /building-theme/best-practices/styling.md
---
# Styling and the Color System
To ensure consistent design and easy customization across themes and third-party sections, **Bagisto Visual promotes a shared, semantic color system**.
This system is implemented in the default `visual-debut` theme and is strongly recommended for all themes and section packages.
Inspired by the [DaisyUI color system](https://daisyui.com/docs/colors/), this approach uses role-based tokens to ensure legibility, adaptability, and design consistency.
## 1. Color Roles
Each color has a **semantic role** that defines its purpose in the interface. These roles provide a stable design language that works across themes and sections.
| Role | Description | Common Use |
| ---------------- | ----------------------------------------- | ------------------------------------ |
| `primary` | Main brand color | Buttons, links, CTAs |
| `on-primary` | Foreground on `primary` | Text/icons on primary backgrounds |
| `secondary` | Supporting tone | Headings, badges, accents |
| `on-secondary` | Foreground on `secondary` | Text/icons on secondary backgrounds |
| `accent` | Decorative or promotional highlights | Banners, badges |
| `on-accent` | Foreground on `accent` | Text/icons on accent elements |
| `neutral` | General-purpose text and passive surfaces | Body text, input borders |
| `on-neutral` | Foreground on `neutral` | Text/icons on neutral surfaces |
| `background` | Page background | Layout wrappers, full-width sections |
| `on-background` | Foreground on `background` | Body text, links |
| `surface` | Component or section background | Cards, forms, sidebars |
| `on-surface` | Foreground on `surface` | Section text, icons |
| `surface-alt` | Alternate surface (hover, nesting layer) | Hover states, dropdowns |
| `on-surface-alt` | Foreground on `surface-alt` | Icons or overlays |
| `success` | Positive feedback | Alerts, tags, confirmations |
| `on-success` | Foreground on `success` | Text/icons on success backgrounds |
| `warning` | Attention or caution | Notices, validation warnings |
| `on-warning` | Foreground on `warning` | Text/icons on warning backgrounds |
| `danger` | Critical or destructive state | Errors, danger zones |
| `on-danger` | Foreground on `error` | Text/icons on error messages |
| `info` | Informational messages | Tooltips, banners, guidance |
| `on-info` | Foreground on `info` | Text/icons on info sections |
Each background is paired with a `on-*` foreground token for text and icon contrast.
## 2. Color Schemes
A **color scheme** is a named set of color tokens that defines the look and feel of a section or page.
Color schemes let themes support multiple visual styles (light, dark, promotional), and allow merchants to assign schemes without writing code.
### How They Work
* Color schemes are defined by the theme using the [ColorSchemeGroup](../../core-concepts/settings/types.md#colorschemegroup) setting type
* Each scheme includes:
* A unique **key** (e.g. `default`, `dark`, `highlight`)
* A **label** for display in the Visual Editor
* A complete set of semantic tokens (see list above)
* The `default` (or first) scheme is applied to the entire page
* Sections can override the global scheme using the [ColorScheme](../../core-concepts/settings/types.md#colorscheme) setting
* Selected schemes are applied using a `data-color-scheme` attribute, which scopes CSS variables
### Important
> 💡 **Every scheme must define a value for all color roles documented above.**
> This ensures that any section relying on semantic tokens can render correctly and remain compatible.
***
### Why They Matter
* **Consistent branding** across all pages and sections
* **Flexible design** with support for dark mode, promotional themes, etc.
* **Third-party compatibility** without visual clashes
* **Merchant control** over appearance via the Visual Editor
***
### Best Practices
* Define **every required token** (`primary`, `on-primary`, `background`, etc.)
* Ensure strong contrast between background and `on-*` foregrounds
* Offer 2–5 thoughtful schemes with clear visual identity
* Render all scheme tokens in your layout using:
```blade
@foreach ($theme->settings->color_schemes as $scheme)
[data-color-scheme="{{ $scheme->id }}"] {
{!! $scheme->outputCssVars() !!}
}
@endforeach
```
## 3. Usage Guidelines
Use role-based classes and tokens instead of hardcoded colors.
### ✅ Recommended
```blade
Section Title
Section body content goes here.
```
### 🚫 Avoid
```blade
This will break compatibility with color schemes.
```
## 4. Theme Developer Responsibilities
Theme developers must:
* Define all required tokens per scheme using CSS variables:
```css
--color-primary, --color-on-primary,
--color-surface, --color-on-surface, etc.
```
* Use **kebab-case** naming for consistency
* Ensure visual contrast between paired tokens (e.g., `on-background` and `background`)
* Store the token definitions inside a single `ColorSchemeGroup` setting
## 5. Section Developer Responsibilities
Section developers should:
* Use **only semantic tokens** (`bg-surface`, `text-on-primary`, etc.)
* **Never** use hardcoded hex values or shortcuts like `text-white`
* Always pair foreground text with its appropriate background token
* Avoid relying on color alone to communicate meaning — use icons, labels, or layout cues
* Make sections compatible with any theme or scheme
## 6. Common Patterns
### Buttons
```blade
```
### Alerts
```blade
Please check your shipping details.
```
### Cards
```blade
Your Benefits
Free shipping
Easy returns
```
## Summary
* Use **role-based tokens** like `primary`, `surface`, `error`, etc.
* Always include `on-*` counterparts for text and icon contrast
* Define color schemes centrally using `ColorSchemeGroup`
* Let sections reference schemes using `ColorScheme`
* Avoid fixed colors — rely on design tokens and scoping for flexibility
This color system makes your sections consistent, theme-compatible, and easy to adapt for any brand or layout.
---
---
url: /building-theme/best-practices/accessibility.md
---
# Accessibility
Bagisto Visual is designed to help merchants create beautiful storefronts — but beauty should be accessible to everyone. As a theme or section developer, it’s your responsibility to ensure that the interfaces you build can be used by all visitors, including those with disabilities.
This guide outlines practical ways to make your themes and sections accessible by default.
## Why Accessibility Matters
* It ensures your store is usable by people with visual, motor, cognitive, and hearing impairments
* It improves SEO, performance, and mobile usability
* It's required by law in many countries
* It's good design
> Accessibility is not an optional layer — it should be part of every design decision.
## 1. Use Semantic HTML
Write markup that reflects the structure and purpose of content.
| Instead of... | Use... |
| ------------------------- | ------------------------------ |
| `