Custom Themes
Tenants can install custom storefront themes packaged as Composer libraries. Themes register slot variants — the EYalla layout editor exposes those variants for tenants to mix & match per page.
Quick start
Scaffold the whole package — composer.json, slot catalog, service provider, a first variant and a README — in one command:
php artisan theme:scaffold coastal --name="Coastal" --template=restaurant --slot=hero
The command validates the target before it writes anything. Themes extend slots
the template already declares, so a mistyped --slot would produce a theme
that registers cleanly and renders nothing; instead you get the list of real
slots on that page and no half-written package.
Options: --template (default ecommerce), --page (default home),
--slot (default hero), --name, --path, --force.
The output tells you how to autoload the package. Nothing registers until the service provider boots.
Anatomy
A theme package looks like:
mytheme/
├── composer.json
├── src/
│ └── Providers/
│ └── MyThemeServiceProvider.php
├── resources/
│ ├── views/
│ │ ├── home/
│ │ │ ├── hero/
│ │ │ │ ├── full-bleed.blade.php
│ │ │ │ └── split-image.blade.php
│ │ │ └── featured-products/
│ │ │ └── carousel-3up.blade.php
│ │ └── partials/
│ │ └── footer.blade.php
│ └── css/
│ └── theme.css
└── config/
└── mytheme.php # slot catalog
composer.json
{
"name": "yourname/eyalla-theme-elegance",
"type": "library",
"require": {
"php": ">=8.4",
"laravel/framework": "^13.0",
"eyalla/template-ecommerce": "^0.4"
},
"extra": {
"laravel": {
"providers": [
"YourName\\EyallaThemeElegance\\Providers\\ThemeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"YourName\\EyallaThemeElegance\\": "src/"
}
}
}
Slot catalog
config/mytheme.php:
return [
'name' => 'Elegance',
'compatible_templates' => ['ecommerce'],
'pages' => [
'home' => [
'slots' => [
'hero' => [
'variants' => [
'full-bleed' => [
'label' => 'Full-bleed image',
'view' => 'mytheme::home.hero.full-bleed',
'props_schema' => [
'headline' => ['type' => 'text', 'default' => 'Discover'],
'cta_label' => ['type' => 'text', 'default' => 'Shop now'],
'cta_url' => ['type' => 'url', 'default' => '/products'],
],
],
],
],
],
],
],
];
Service provider
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../../resources/views', 'mytheme');
$this->mergeConfigFrom(__DIR__.'/../../config/mytheme.php', 'mytheme');
// Register the theme with the EYalla theme registry.
app(\App\Domain\Customization\Services\ThemeRegistry::class)
->register('elegance', __DIR__.'/../../config/mytheme.php');
}
Best practices
- Mobile-first. Test at 360×640 before anything wider. Lighthouse mobile score < 85 is a release-blocker.
- RTL aware. Use Tailwind's
rtl:variant or logical properties (me-2notmr-2). - Bilingual ready. Pull all customer-facing strings from
__('key')and ship alang/{en,ar}/theme.php. - No JS-required. Storefronts must render without JavaScript for SEO. Progressive enhance.
- Compatible templates — declare which vertical templates your theme works with (typically just
ecommerce).
Publishing
Once your theme is stable:
- Tag a v1.0.0 release on your VCS.
- Submit to packagist.org.
- Email
developers@eyalla.comwith the package name — we'll list it in the official theme catalog after a security review.
The theme gallery
Once installed, a theme appears to merchants under Storefront → Themes as a single card: its name, description, and every section it restyles. Apply theme writes all of its variants at once, and preserves each slot's saved props — a merchant's headline, CTA copy and uploaded imagery survive the swap, because a theme changes the framing, not the content.
Only themes whose compatible_templates include the tenant's active template
are listed, and that filter is the authorization boundary, not just a display
convenience: a restaurant theme cannot be applied to a shop even if its slug is
posted directly.
Give your theme a description in the slot catalog — it is the one line a
merchant reads when choosing.
Coming soon
- Theme preview (try a theme in a sandbox tenant before applying it).
- Hot-reload during development.
- Asset versioning via composer hash.