1. Update composer.json
Change the package version in your composer.json:
{
"require": {
"moonshine/moonshine": "^3.0"
}
}
{
"require": {
"moonshine/moonshine": "^3.0"
}
}
{
"require": {
"moonshine/moonshine": "^3.0"
}
}
2. Create Backups
Before updating, you need to back up the following files:
mv config/moonshine.php config/moonshine_old.php
mv app/Providers/MoonShineServiceProvider.php app/Providers/MoonShineServiceProvider_old.php
mv app/MoonShine/Pages/Dashboard.php app/MoonShine/Pages/Dashboard_old.php
mv config/moonshine.php config/moonshine_old.php
mv app/Providers/MoonShineServiceProvider.php app/Providers/MoonShineServiceProvider_old.php
mv app/MoonShine/Pages/Dashboard.php app/MoonShine/Pages/Dashboard_old.php
mv config/moonshine.php config/moonshine_old.php
mv app/Providers/MoonShineServiceProvider.php app/Providers/MoonShineServiceProvider_old.php
mv app/MoonShine/Pages/Dashboard.php app/MoonShine/Pages/Dashboard_old.php
These files will be needed for transferring configurations and settings. See the Changelog section.
3. Update Application Configuration
If you have Laravel < 11, you need to find and remove App\Providers\MoonShineServiceProvider::class
from the config/app.php
configuration.
After running the moonshine:install
command, the service provider will be added automatically.
4. Run the Update
composer update
composer update
composer update
1. Install the New Version
Run the command:
php artisan moonshine:install
php artisan moonshine:install
php artisan moonshine:install
This command will create:
- A new service provider
- Updated configuration
- A new Layout
- A new Dashboard
2. Migrate Settings
- Transfer the parameters from the old config (
moonshine_old.php
) to the new one. See the documentation on configuration.
- The menu structure has changed in the new version:
- Open
app/MoonShine/Layouts/MoonShineLayout.php
.
- Copy the old menu from
MoonShineServiceProvider_old.php
to the menu
method.
- Remove the
heroicons.outline.
prefix from icons.
- Update all resource instances to string classes:
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
// Was
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
// Now
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
// Was
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
// Now
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
3. Register Resources and Pages
In the new MoonShineServiceProvider.php
, you need to register all resources and pages:
$core->resources([
MoonShineUserResource::class,
MoonShineUserRoleResource::class,
]);
$core->pages([
...$config->getPages(),
SettingPage::class,
]);
$core->resources([
MoonShineUserResource::class,
MoonShineUserRoleResource::class,
// Add all your resources
]);
$core->pages([
...$config->getPages(),
SettingPage::class,
]);
$core->resources([
MoonShineUserResource::class,
MoonShineUserRoleResource::class,
// Add all your resources
]);
$core->pages([
...$config->getPages(),
SettingPage::class,
]);
Commands to generate lists:
For importing namespaces:
find app/MoonShine/Resources -type f | sed "s/app/use App/" | sed "s|/|\\\|g" | sed "s/.php/;/" | sort
find app/MoonShine/Resources -type f | sed "s/app/use App/" | sed "s|/|\\\|g" | sed "s/.php/;/" | sort
find app/MoonShine/Resources -type f | sed "s/app/use App/" | sed "s|/|\\\|g" | sed "s/.php/;/" | sort
For the list of resources:
find app/MoonShine/Resources -type f -exec basename {} \; | sed "s/.php/::class,/" | sort
find app/MoonShine/Resources -type f -exec basename {} \; | sed "s/.php/::class,/" | sort
find app/MoonShine/Resources -type f -exec basename {} \; | sed "s/.php/::class,/" | sort
4. Update Dashboard
- Move required components from
Dashboard_old.php
to the new Dashboard.php
.
- Take note of the changes in the Changelog section.
5. Remove Old Files
After successful migration, remove:
# Old Layout (if it exists)
rm app/MoonShine/MoonShineLayout.php
# Backups of files from 2.x
rm config/moonshine_old.php
rm app/Providers/MoonShineServiceProvider_old.php
rm app/MoonShine/Pages/Dashboard_old.php
# Old Layout (if it exists)
rm app/MoonShine/MoonShineLayout.php
# Backups of files from 2.x
rm config/moonshine_old.php
rm app/Providers/MoonShineServiceProvider_old.php
rm app/MoonShine/Pages/Dashboard_old.php
# Old Layout (if it exists)
rm app/MoonShine/MoonShineLayout.php
# Backups of files from 2.x
rm config/moonshine_old.php
rm app/Providers/MoonShineServiceProvider_old.php
rm app/MoonShine/Pages/Dashboard_old.php
Main Changes
MoonShine\Resources\ → MoonShine\Laravel\Resources\
MoonShine\Fields\Relationships\ → MoonShine\Laravel\Fields\Relationships\
MoonShine\Fields\Slug → MoonShine\Laravel\Fields\Slug
MoonShine\Fields\ → MoonShine\UI\Fields\
MoonShine\Decorations\Block → MoonShine\UI\Components\Layout\Box
MoonShine\Decorations\ → MoonShine\UI\Components\Layout\*
(some to MoonShine\UI\Components\, check manually)
MoonShine\Enums\ → MoonShine\Support\Enums\
MoonShine\Pages\ → MoonShine\Laravel\Pages\
MoonShine\Models\ → MoonShine\Laravel\Models\
MoonShine\QueryTags\ → MoonShine\Laravel\QueryTags\
MoonShine\Attributes\ → MoonShine\Support\Attributes\
MoonShine\Components\ → MoonShine\UI\Components\
MoonShine\Metrics\ → MoonShine\UI\Components\Metrics\Wrapped\
MoonShine\ActionButtons\ → MoonShine\UI\Components\
MoonShine\Http\Responses\ → MoonShine\Laravel\Http\Responses\
MoonShine\Http\Controllers\ → MoonShine\Laravel\Http\Controllers\
MoonShine\MoonShineAuth → MoonShine\Laravel\MoonShineAuth
MoonShine\Resources\ → MoonShine\Laravel\Resources\
MoonShine\Fields\Relationships\ → MoonShine\Laravel\Fields\Relationships\
MoonShine\Fields\Slug → MoonShine\Laravel\Fields\Slug
MoonShine\Fields\ → MoonShine\UI\Fields\
MoonShine\Decorations\Block → MoonShine\UI\Components\Layout\Box
MoonShine\Decorations\ → MoonShine\UI\Components\Layout\*
(some to MoonShine\UI\Components\, check manually)
MoonShine\Enums\ → MoonShine\Support\Enums\
MoonShine\Pages\ → MoonShine\Laravel\Pages\
MoonShine\Models\ → MoonShine\Laravel\Models\
MoonShine\QueryTags\ → MoonShine\Laravel\QueryTags\
MoonShine\Attributes\ → MoonShine\Support\Attributes\
MoonShine\Components\ → MoonShine\UI\Components\
MoonShine\Metrics\ → MoonShine\UI\Components\Metrics\Wrapped\
MoonShine\ActionButtons\ → MoonShine\UI\Components\
MoonShine\Http\Responses\ → MoonShine\Laravel\Http\Responses\
MoonShine\Http\Controllers\ → MoonShine\Laravel\Http\Controllers\
MoonShine\MoonShineAuth → MoonShine\Laravel\MoonShineAuth
MoonShine\Resources\ → MoonShine\Laravel\Resources\
MoonShine\Fields\Relationships\ → MoonShine\Laravel\Fields\Relationships\
MoonShine\Fields\Slug → MoonShine\Laravel\Fields\Slug
MoonShine\Fields\ → MoonShine\UI\Fields\
MoonShine\Decorations\Block → MoonShine\UI\Components\Layout\Box
MoonShine\Decorations\ → MoonShine\UI\Components\Layout\*
(some to MoonShine\UI\Components\, check manually)
MoonShine\Enums\ → MoonShine\Support\Enums\
MoonShine\Pages\ → MoonShine\Laravel\Pages\
MoonShine\Models\ → MoonShine\Laravel\Models\
MoonShine\QueryTags\ → MoonShine\Laravel\QueryTags\
MoonShine\Attributes\ → MoonShine\Support\Attributes\
MoonShine\Components\ → MoonShine\UI\Components\
MoonShine\Metrics\ → MoonShine\UI\Components\Metrics\Wrapped\
MoonShine\ActionButtons\ → MoonShine\UI\Components\
MoonShine\Http\Responses\ → MoonShine\Laravel\Http\Responses\
MoonShine\Http\Controllers\ → MoonShine\Laravel\Http\Controllers\
MoonShine\MoonShineAuth → MoonShine\Laravel\MoonShineAuth
Additional Packages
If needed, install and update namespaces for:
- Import/Export:
MoonShine\Laravel\Handlers\ExportHandler
MoonShine\Laravel\Handlers\ImportHandler
- Apexcharts:
MoonShine\UI\Components\Metrics\Wrapped\DonutChartMetric
MoonShine\UI\Components\Metrics\Wrapped\LineChartMetric
- Ace Editor:
- EasyMDE:
MoonShine\Fields\Markdown
- TinyMce:
Main Changes
- Creating instances of resources and pages:
new NameResource()
app(NameResource::class)
// Was
new NameResource()
// Now
// Recommended via DI
// or:
app(NameResource::class)
// Was
new NameResource()
// Now
// Recommended via DI
// or:
app(NameResource::class)
- Method signatures:
public function components(): array
public function title(): string
public function breadcrumbs(): string
public function rules(Model $item): array
protected function afterUpdated(Model $user): Model
public function detailButtons(): array
public function modifyListComponent(MoonShineRenderable|TableBuilder $table): MoonShineRenderable
$field->getData()
detailPageUrl
MoonShineAuth::guard()
getActiveActions()
protected function components(): iterable
public function getTitle(): string
public function getBreadcrumbs(): string
protected function rules($item): array
protected function afterUpdated($user): Model
public function detailButtons(): ListOf
public function modifyListComponent(ComponentContract $table): ComponentContract
$field->getData()->getOriginal()
getDetailPageUrl
MoonShineAuth::getGuard()
activeActions()
// Was
public function components(): array
public function title(): string
public function breadcrumbs(): string
public function rules(Model $item): array
protected function afterUpdated(Model $user): Model
public function detailButtons(): array
public function modifyListComponent(MoonShineRenderable|TableBuilder $table): MoonShineRenderable
$field->getData()
detailPageUrl
MoonShineAuth::guard()
getActiveActions()
// Now
protected function components(): iterable
public function getTitle(): string
public function getBreadcrumbs(): string
protected function rules($item): array
protected function afterUpdated($user): Model
public function detailButtons(): ListOf
public function modifyListComponent(ComponentContract $table): ComponentContract
$field->getData()->getOriginal()
getDetailPageUrl
MoonShineAuth::getGuard()
activeActions()
// Was
public function components(): array
public function title(): string
public function breadcrumbs(): string
public function rules(Model $item): array
protected function afterUpdated(Model $user): Model
public function detailButtons(): array
public function modifyListComponent(MoonShineRenderable|TableBuilder $table): MoonShineRenderable
$field->getData()
detailPageUrl
MoonShineAuth::guard()
getActiveActions()
// Now
protected function components(): iterable
public function getTitle(): string
public function getBreadcrumbs(): string
protected function rules($item): array
protected function afterUpdated($user): Model
public function detailButtons(): ListOf
public function modifyListComponent(ComponentContract $table): ComponentContract
$field->getData()->getOriginal()
getDetailPageUrl
MoonShineAuth::getGuard()
activeActions()
- Changes in field methods:
public function fields(): array
protected function indexFields(): iterable protected function detailFields(): iterable
protected function formFields(): iterable
// Was
public function fields(): array
// Now
protected function indexFields(): iterable // only accepts fields
protected function detailFields(): iterable
protected function formFields(): iterable
// Was
public function fields(): array
// Now
protected function indexFields(): iterable // only accepts fields
protected function detailFields(): iterable
protected function formFields(): iterable
- Table attributes:
TableBuilder::make()
->tdAttributes(fn(mixed $data, int $row, TableBuilder $table): array =>
$row === 3 ? ['class' => 'bgc-yellow'] : []
)
->tdAttributes(fn(mixed $data, int $row, int $cell, TableBuilder $table): array =>
$cell === 3 ? ['align' => 'right'] : []
)
// New format
TableBuilder::make()
->tdAttributes(fn(mixed $data, int $row, TableBuilder $table): array =>
$row === 3 ? ['class' => 'bgc-yellow'] : []
)
->tdAttributes(fn(mixed $data, int $row, int $cell, TableBuilder $table): array =>
$cell === 3 ? ['align' => 'right'] : []
)
// New format
TableBuilder::make()
->tdAttributes(fn(mixed $data, int $row, TableBuilder $table): array =>
$row === 3 ? ['class' => 'bgc-yellow'] : []
)
->tdAttributes(fn(mixed $data, int $row, int $cell, TableBuilder $table): array =>
$cell === 3 ? ['align' => 'right'] : []
)
- Changes in other methods:
- Helper
to_page
→ toPage
- Instead of the
columnSpan
method in components, use the component method Column
: Column::make([...])->columnSpan(..)
- Instead of
expansion('url')
, use the suffix('url')
method
Removed Methods
- Field display methods:
- hideOnIndex, showOnIndex
- hideOnForm, showOnForm
- hideOnCreate, showOnCreate
- hideOnUpdate, showOnUpdate
- hideOnDetail, showOnDetail
- hideOnAll
- hideOnExport, showOnExport
- useOnImport (use the import-export package)
In the Routes section you can find alternative methods
- Helpers:
Main Changes
- Icons:
- Remove the
heroicons.outline
and heroicons.solid
prefixes.
- These icons are now available by default.
- Menu:
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
// Was
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
// Now
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
// Was
MenuItem::make('Settings', new SettingResource(), 'heroicons.outline.adjustments-vertical')
// Now
MenuItem::make('Settings', SettingResource::class, 'adjustments-vertical')
- Asynchronous events:
->async(asyncUrl: ..., asyncEvents: ...)
'table-updated-{name}'
->async(url: ..., events: ...)
AlpineJs::event(JsEvent::TABLE_UPDATED, {name})
// Was
->async(asyncUrl: ..., asyncEvents: ...)
'table-updated-{name}'
// Now
->async(url: ..., events: ...)
AlpineJs::event(JsEvent::TABLE_UPDATED, {name})
// Was
->async(asyncUrl: ..., asyncEvents: ...)
'table-updated-{name}'
// Now
->async(url: ..., events: ...)
AlpineJs::event(JsEvent::TABLE_UPDATED, {name})
- Sort direction:
protected string $sortDirection = 'ASC';
protected SortDirection $sortDirection = SortDirection::ASC;
// Was
protected string $sortDirection = 'ASC';
// Now
protected SortDirection $sortDirection = SortDirection::ASC;
// Was
protected string $sortDirection = 'ASC';
// Now
protected SortDirection $sortDirection = SortDirection::ASC;
- Assets:
$assets
$assets For management, use [AssetManager](/docs/3.x/appearance/assets).
// Was
$assets // strings
// Now
$assets // accepts AssetElementContract, such as Css, InlineCss, Js, InlineJs
For management, use [AssetManager](/docs/3.x/appearance/assets).
// Was
$assets // strings
// Now
$assets // accepts AssetElementContract, such as Css, InlineCss, Js, InlineJs
For management, use [AssetManager](/docs/3.x/appearance/assets).
Removed Variables
protected bool $isAsync = true;
(now enabled by default)