## Saving

Click the Filament **Save** button to persist your page. On every save:

1. Content is validated structurally (rows have columns, columns have widgets, widgets have types)
2. Widget-level validation runs (e.g., buttons need a label and URL)
3. If revisions are enabled, a revision snapshot is created automatically
4. If safelist auto-sync is enabled, the Tailwind safelist file is regenerated

Validation warnings are logged but do not block the save. This lets editors save work in progress without losing data.

## Publishing

Set the **Status** field to `published` to make the page live. Draft pages are only visible in the admin panel.

### Scheduled publishing

Set the status to `scheduled` and pick a future **Publish at** date and time. Layup auto-registers the `layup:publish-scheduled` console command on the application scheduler (every minute), so the page flips to `published` once its publish time arrives without any extra wiring -- as long as your app's scheduler is actually running (`php artisan schedule:work` in development, the standard cron in production).

If you'd rather control the command yourself (for example, run it on a single worker), set `layup.scheduling.auto_publish` to `false` in `config/layup.php` and call `layup:publish-scheduled` from your own scheduler. The command supports `--dry-run` to preview which pages would be promoted:

```bash
php artisan layup:publish-scheduled --dry-run
```

### Frontend routes

When `frontend.enabled` is `true` in `config/layup.php` (the default), published pages are served at:

```
/{prefix}/{slug}
```

The default prefix is `pages`, so a page with slug `about-us` would be at `/pages/about-us`.

Configure the prefix, middleware, domain, layout, and view in the `frontend` section of the config:

```php
'frontend' => [
    'enabled' => true,
    'prefix' => 'pages',
    'middleware' => ['web'],
    'domain' => null,
    'layout' => 'app',
    'view' => 'layup::frontend.page',
    'max_width' => 'container',
    'include_scripts' => true,
    'excluded_paths' => [],
],
```

### SEO metadata

Each page supports meta fields stored in the `meta` JSON column:

- `title` -- overrides the page title for `<title>` tag
- `description` -- meta description (160 character limit in the form)
- `keywords` -- meta keywords

The frontend view receives `$page` and `$meta` variables. The `Page` model provides helper methods:

```php
$page->getMetaTitle();       // Falls back to page title
$page->getMetaDescription();
$page->getMetaKeywords();
$page->getMetaTags();        // Array of all meta tags
$page->getStructuredData();  // JSON-LD (WebPage, Article, FAQPage, BreadcrumbList)
```

### Structured data

Set `meta.schema_type` to control the JSON-LD type:

- `WebPage` (default)
- `Article` or `BlogPosting` (includes author if `meta.author` is set)
- `FAQPage` (auto-extracts questions from Accordion and Toggle widgets)

Breadcrumb structured data is generated automatically. When a page has a parent chain (`parent_id`), breadcrumbs walk that chain using real page titles. For pages without a parent chain, breadcrumbs fall back to splitting the URL path into title-cased segments.

## Duplicating pages

In the page list, use the **Duplicate** action to create a draft copy with a randomized slug. This is useful for creating variations of existing pages.

## Exporting and importing

Export a page to JSON:

```bash
php artisan layup:export --slug=about-us
```

Import from a JSON file:

```bash
php artisan layup:import path/to/page.json
```

---

## Documentation

- [Introduction](https://documentation.crumbls.com/layup/-/index.md)
- [Introduction](https://documentation.crumbls.com/layup/-/introduction.md)
- [v1](https://documentation.crumbls.com/layup/-/_index.md)
- [Installation](https://documentation.crumbls.com/layup/-/installation.md)
- [Contributing to Layup](https://documentation.crumbls.com/layup/-/CONTRIBUTING.md)
- [Usage](https://documentation.crumbls.com/layup/-/usage.md)
- [Configuration](https://documentation.crumbls.com/layup/-/configuration.md)
- [Examples](https://documentation.crumbls.com/layup/-/examples.md)
- [Grid System](https://documentation.crumbls.com/layup/-/grid-system.md)
- [Field-only Installation](https://documentation.crumbls.com/layup/-/field-only-installation.md)
- [Embedding the Field](https://documentation.crumbls.com/layup/-/embedding-the-field.md)
- [Widgets](https://documentation.crumbls.com/layup/-/widgets/_index.md)
- [Getting Started](https://documentation.crumbls.com/layup/-/getting-started/_index.md)
- [Customization](https://documentation.crumbls.com/layup/-/customization/_index.md)
- [API Reference](https://documentation.crumbls.com/layup/-/api-reference/_index.md)
- [Upgrade guide](https://documentation.crumbls.com/layup/-/upgrade-guide.md)
- [Troubleshooting](https://documentation.crumbls.com/layup/-/troubleshooting.md)
- [Changelog](https://documentation.crumbls.com/layup/-/CHANGELOG.md)
- [🔐 Security Policy](https://documentation.crumbls.com/layup/-/SECURITY.md)
- [The MIT License (MIT)](https://documentation.crumbls.com/layup/-/LICENSE.md)
- [Layup Widget Development Guide for AI Agents](https://documentation.crumbls.com/layup/-/AGENTS.md)
- [Layup — Sprint TODO (overnight Feb 23-24)](https://documentation.crumbls.com/layup/-/TODO.md)
- [Vision](https://documentation.crumbls.com/layup/-/VISION.md)
- [Content Widgets](https://documentation.crumbls.com/layup/-/widgets/content.md)
- [Media Widgets](https://documentation.crumbls.com/layup/-/widgets/media.md)
- [Interactive Widgets](https://documentation.crumbls.com/layup/-/widgets/interactive.md)
- [Layout Widgets](https://documentation.crumbls.com/layup/-/widgets/layout.md)
- [Advanced Widgets](https://documentation.crumbls.com/layup/-/widgets/advanced.md)
- [Creating Pages](https://documentation.crumbls.com/layup/-/getting-started/creating-pages.md)
- [Adding Widgets](https://documentation.crumbls.com/layup/-/getting-started/adding-widgets.md)
- [Disable the Pages Resource](https://documentation.crumbls.com/layup/-/customization/disable-pages-resource.md)
- [Rendering Content](https://documentation.crumbls.com/layup/-/customization/rendering-content.md)
- [Frontend Rendering](https://documentation.crumbls.com/layup/-/customization/frontend-rendering.md)
- [Creating Custom Widgets](https://documentation.crumbls.com/layup/-/customization/custom-widgets.md)
- [Extending Existing Widgets](https://documentation.crumbls.com/layup/-/customization/extending-widgets.md)
- [Livewire-rendered widgets](https://documentation.crumbls.com/layup/-/customization/livewire-widgets.md)
- [Filament Plugin API](https://documentation.crumbls.com/layup/-/customization/filament-plugin-api.md)
- [Theme System](https://documentation.crumbls.com/layup/-/customization/theme-system.md)
- [Tailwind Safelist](https://documentation.crumbls.com/layup/-/customization/tailwind-safelist.md)
- [SEO Meta](https://documentation.crumbls.com/layup/-/customization/seo-meta.md)
- [Page Templates](https://documentation.crumbls.com/layup/-/customization/page-templates.md)
- [Revision History](https://documentation.crumbls.com/layup/-/customization/revision-history.md)
- [Swapping the Page Model](https://documentation.crumbls.com/layup/-/customization/swapping-the-page-model.md)
- [Testing](https://documentation.crumbls.com/layup/-/customization/testing.md)
- [Widget Contract](https://documentation.crumbls.com/layup/-/api-reference/widget-contract.md)
- [Models](https://documentation.crumbls.com/layup/-/api-reference/models.md)
- [Service Provider](https://documentation.crumbls.com/layup/-/api-reference/service-provider.md)
- [Support Classes](https://documentation.crumbls.com/layup/-/api-reference/support-classes.md)
- [Commands](https://documentation.crumbls.com/layup/-/api-reference/commands.md)
