Pages

Pages

Basics

Page is the foundation of the MoonShine admin panel. The main purpose of Page is to display components.

Pages with similar logic can be combined into a Resource.

Creating a Page

To create a page class, you can use the console command:

php artisan moonshine:page

After entering the class name, a file will be created that serves as the basis for the page in the admin panel. By default, it is located in the app/MoonShine/Pages directory.

Pages are automatically registered in the system when the command is executed, but if you create a page manually, it must be registered in the MoonShineServiceProvider in the $core->pages() method.

You can also specify the class name and the directory location in the command.

php artisan moonshine:page OrderStatistics --dir=Pages/Statistics

The OrderStatistics file will be created in the app/MoonShine/Pages/Statistics directory.

Title

The page title can be set through the title property, and the subtitle can be set through subtitle:

use MoonShine\Laravel\Pages\Page;
 
class CustomPage extends Page
{
protected string $title = 'CustomPage';
 
protected string $subtitle = 'Subtitle';
 
//...
}

If some logic is required for the title and subtitle, the title() and subtitle() methods allow you to implement it:

class CustomPage extends Page
{
// ...
 
public function getTitle(): string
{
return $this->title ?: 'CustomPage';
}
 
public function getSubtitle(): string
{
return $this->subtitle ?: 'Subtitle';
}
 
//...
}

Components

To register the components of the page, the components() method is used.

class CustomPage extends Page
{
// ...
 
protected function components(): iterable
{
return [
Grid::make([
Column::make([
Box::make([
//
])
])->columnSpan(6),
Column::make([
Box::make([
//
])
])->columnSpan(6),
])
];
}
 
//...
}

For more detailed information, refer to the Components section.

The getBreadcrumbs() method is responsible for generating the breadcrumbs.

use MoonShine\Pages\Page;
 
class CustomPage extends Page
{
// ...
 
public function getBreadcrumbs(): array
{
return [
'#' => $this->getTitle()
];
}
 
//...
}

Layout

By default, pages use the AppLayout or CompactLayout display template. For more information about templates, see the Layout section.

use MoonShine\Laravel\Layouts\AppLayout;
 
class CustomPage extends Page
{
protected ?string $layout = AppLayout::class;
 
//...
}

Modifying Layout

When developing an admin panel using MoonShine, there is often a need for flexible management of templates. Instead of creating numerous separate templates for various situations, MoonShine provides an opportunity to dynamically modify existing templates. This is achieved through the modifyLayout method.

The modifyLayout method allows you to access the template after creating its instance and make necessary changes. This is especially useful when you need to adapt the template to specific conditions or add dynamic content.

Example usage Consider an example from the moonshine-software/two-factor package that demonstrates how to use modifyLayout for customizing the authentication template:

/**
* @param LoginLayout $layout
*/
protected function modifyLayout(LayoutContract $layout): LayoutContract
{
return $layout->title(
__('moonshine-two-factor::ui.2fa')
)->description(
__('moonshine-two-factor::ui.confirm')
);
}

Alias

If you need to change the page alias, this can be done through the alias property.

class CustomPage extends Page
{
protected ?string $alias = null;
 
//...
}

You can also override the getAlias() method.

use MoonShine\Pages\Page;
 
class CustomPage extends Page
{
public function getAlias(): ?string
{
return 'custom_page';
}
 
//...
}

Rendering

You can display the page outside of MoonShine by simply returning it in a controller:

class ProfileController extends Controller
{
public function __invoke(ProfilePage $page): ProfilePage
{
return $page->loaded();
}
}

Or with Fortify

Fortify::loginView(static fn() => app(ProfilePage::class));

Before Rendering

The prepareBeforeRender() method allows you to execute actions before displaying the page.

class CustomPage extends Page
{
protected function prepareBeforeRender(): void
{
parent::prepareBeforeRender();
 
if (auth()->user()->moonshine_user_role_id !== MoonshineUserRole::DEFAULT_ROLE_ID) {
abort(403);
}
}
}

Response Modifier

By default, the page is rendered through the PageController, invoking the render() method. However, there are times when it's necessary to change the standard response, such as redirecting under certain conditions. In such cases, the modifyResponse() method can be used.

The modifyResponse() method allows you to modify the page response before it is sent. Here’s an example of its usage:

protected function modifyResponse(): ?Response
{
if (request()->has('id')) {
return redirect()->to('/admin/article-resource/index-page');
}
 
return null;
}

Using modifyResponse() provides a flexible way to manage the page response, allowing for complex request and response handling logic in the admin panel.

Lifecycle

Page has several different methods to hook into various parts of its lifecycle. Let’s go through them:

Active Page

The onLoad method allows integration at the moment when the page is loaded and is currently active.

namespace App\MoonShine\Pages;
 
use MoonShine\Laravel\Pages\Page;
 
class PostPage extends Page
{
// ...
protected function onLoad(): void
{
parent::onLoad();
 
//
}
// ...
}

Booting Instance

The booted method allows integration at the moment when MoonShine creates an instance of the page in the system.

namespace App\MoonShine\Pages;
 
use MoonShine\Laravel\Pages\Page;
 
class PostPage extends Page
{
// ...
protected function booted(): void
{
parent::booted();
 
//
}
// ...
}

In this example, to create a link to a new page, we'll use the ActionButton and the getPageUrl method.

/**
* @throws Throwable
*/
public function indexButtons(): ListOf
{
return parent::indexButtons()->add(
ActionButton::make('To custom page',
url: fn($model) => $this->getPageUrl(
PostPage::class, params: ['resourceItem' => $model->getKey()]
),
),
);
}

Assets

protected function onLoad(): void
{
parent::onLoad();
 
$this->getAssetManager()
->add(Css::make('/css/app.css'))
->append(Js::make('/js/app.js'));
}