Skip to content

Frontend Pages

v1.3

Modules can add public-facing pages (visible to guests and logged-in users) that integrate with the active store theme.


Two tracks

TrackWhen to useHow
1 — Extend active themePages that should blend into the store (pricing page, landing pages)@extends('theme::layouts.app')
2 — Custom layoutFully branded UI separate from the storeShip your own layout blade

You can use both tracks in the same module for different pages.


Track 1 — Extend the active theme

blade
@extends('theme::layouts.app', ['title' => 'My Page'])

@section('content')
    <div class="max-w-5xl mx-auto px-4 py-16">
        <h1 class="text-4xl font-bold">Hello</h1>
    </div>
@endsection

theme:: resolves to whichever theme is currently active (currently tailwind). Your page inherits the header, footer, navigation, and dark mode support automatically.

Available stacks

Push content into the layout's stacks from any view:

blade
@push('ch_head')
    <link rel="stylesheet" href="{{ asset('modules/my-plugin/css/styles.css') }}">
@endpush

@push('ch_footer')
    <script src="{{ asset('modules/my-plugin/js/app.js') }}"></script>
@endpush
StackPosition
ch_headInside <head>, after core styles
ch_footerBefore </body>, after core scripts

Track 2 — Custom layout

Ship a layout blade inside your module and extend it from your page views:

modules/MyPlugin/
└── resources/
    └── views/
        ├── layouts/
        │   └── app.blade.php      ← your custom layout
        └── pages/
            └── dashboard.blade.php
blade
{{-- layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
    <title>@yield('title', 'My App')</title>
    <link rel="stylesheet" href="{{ asset('modules/my-plugin/css/app.css') }}">
</head>
<body class="bg-gray-950 text-white">
    @yield('content')
    <script src="{{ asset('modules/my-plugin/js/app.js') }}"></script>
</body>
</html>
blade
{{-- pages/dashboard.blade.php --}}
@extends('my-plugin::layouts.app', ['title' => 'Dashboard'])

@section('content')
    <div>Your fully custom UI here.</div>
@endsection

Registering public routes

Add public routes in routes/web.php. No authentication middleware is required unless you want to restrict access:

php
Route::prefix('my-plugin')
    ->middleware(['web'])
    ->name('my-plugin.')
    ->group(function () {
        Route::get('/pricing', [PricingController::class, 'index'])->name('pricing');
        Route::get('/features', [FeaturesController::class, 'index'])->name('features');
    });

Assets

Compile module CSS/JS to public/modules/my-plugin/ so they're web-accessible. Reference them with asset():

php
asset('modules/my-plugin/css/app.css')
asset('modules/my-plugin/js/app.js')

If you use a build tool (Vite/Mix), configure its output to target public/modules/my-plugin/. The module folder itself only needs to contain source files — compiled output goes to public/.


Flash messages

The tailwind theme's layout renders a flash partial automatically. Use standard Laravel session flashing from your controllers:

php
return redirect()->route('my-plugin.pricing')
    ->with('success', 'Done!')
    ->with('error', 'Something went wrong.');

Released under the Commercial License.