make:subdomain Command
Scaffolds a new subdomain portal: its CSS/JS entries, Blade layout, a starter Livewire dashboard page, a route file, and an access-control role.
php artisan make:subdomain blogThe name must be lowercase alphanumeric with hyphens (e.g. blog, partner-portal), can't already exist in config('multidomain.sub_domains'), and can't be run while APP_SINGLE_DOMAIN=true (a fresh / route would collide with the existing portals).
Prompts
- Who should be able to access this portal? —
open(no login required) orauth. - Access level (only if
auth) — the portal's own role (recommended: ablogrole, gated byportal:blog),user(same gate asapp), orstaff(same gate asbackoffice). - Should visitors be able to sign up for this portal themselves, from the public register page? — if yes, asks for a label (e.g. "Blog Writer") to show on the sign-up form.
The access answers decide the middleware written into the generated route file. The self-registration answer decides whether a 5th manual step (below) is printed.
What it creates
resources/css/blog.css
resources/js/blog.js
resources/views/layouts/blog.blade.php
resources/views/pages/blog/⚡dashboard/dashboard.php
resources/views/pages/blog/⚡dashboard/dashboard.blade.php
routes/blog.phpPlus a blog role (via spatie/laravel-permission), created immediately so it's ready to assign — protected from deletion in the backoffice roles screen, since User::redirect() uses role names to decide which portal to send a user to after login (see Backoffice).
What it doesn't do
It won't rewrite config/multidomain.php or routes/web.php for you. Editing PHP source programmatically is fragile — a formatting quirk or unusual structure in your own edits could break the rewrite silently. Instead, the command prints the exact lines to add:
1. Add 'blog' => 'blog.'.env('APP_MAIN_DOMAIN') to config/multidomain.php sub_domains array
2. Add this block to routes/web.php:
Route::domain(config('multidomain.sub_domains.blog'))->name('blog.')->group(fn () => include __DIR__.'/blog.php');
3. Add blog.<APP_MAIN_DOMAIN> to your local hosts/Herd config
4. Assign the "blog" role to any user who should access this portal and be redirected here after login.
5. (only if self-registration was enabled) Add 'blog' => 'Blog Writer' to config/multidomain.php registerable_portals arrayvite.config.js needs no edit — it picks up new resources/css/* and resources/js/* entries automatically.
Self-registration
The dashboard stub always ships with a guarded Register CTA and the register page always ships with a guarded "Select the user type" dropdown — both keyed off config('multidomain.registerable_portals'). Nothing shows up until that config array is populated (step 5), so scaffolding a portal without self-registration is a no-op for both. Once populated, registering with that user type assigns the matching role, which User::redirect() then uses to route the new user straight to their portal (see Backoffice for how role names double as portal keys).
Small, safe manual edits — versus a code generator quietly mangling files you'll want to hand-tune anyway.
Stubs
Templates live in stubs/subdomain/ at the project root:
| Stub | Produces |
|---|---|
css.stub | resources/css/{name}.css — imports the shared resources/css/theme.css |
js.stub | resources/js/{name}.js — empty, matching the existing convention |
layout.stub | resources/views/layouts/{name}.blade.php |
route.stub | routes/{name}.php |
dashboard.stub / dashboard.blade.stub | the starter Livewire dashboard page |
Edit these stubs to change what every newly scaffolded portal looks like.