Running a site
Moving from another CMS
Import pages, translations, files, redirects and menus from code.
From WordPress, the importer does the work. From any other CMS, write an import: an Artisan command or a seeder that reads the old site and writes Aurora's models. This page shows each part. The tables behind them are in the Data reference.
Pages and their blocks
A page's blocks are one flat list for every language. Write them as a tree, and BlockTreeBuilder::flatten() makes the list, giving each block an id:
use Aurora\Enums\PageStatus;
use Aurora\Models\Layout;
use Aurora\Models\Page;
use Aurora\Support\BlockTreeBuilder;
$blocks = BlockTreeBuilder::flatten([
['type' => 'heading', 'data' => ['text' => $old->title, 'level' => 'h1']],
['type' => 'band', 'data' => ['background' => 'muted'], 'children' => [
'content' => [ // the band's slot
['type' => 'rich-text', 'data' => ['body' => $old->html]],
],
]],
]);
$page = Page::query()->create([
'title' => $old->title,
'slug' => $old->slug,
'excerpt' => $old->summary,
'layout_id' => Layout::query()->where('handle', 'standard')->value('id'),
'status' => PageStatus::Published,
'published_at' => $old->published_at,
'blocks' => $blocks,
]);
Translations
Title, address, summary and SEO fields are stored per language. Block text in other languages goes in block_translations, by block id and field, text only:
$page->setTranslation('title', 'nb', $old->title_nb);
$page->setTranslation('slug', 'nb', $old->slug_nb);
$page->block_translations = [
'nb' => [
$blocks[0]['id'] => ['text' => $old->title_nb],
],
];
$page->save();
Layout fields
A layout's own fields are set with settingsWithLayoutValues(), naming the layout or its handle:
$page->settings = $page->settingsWithLayoutValues(['background' => $asset->id], 'campaign');
$page->save();
Files
AssetLibrary::fromFile() adds a file to the media library. Give it an id, made from the old file's address, and running the import again finds the file rather than adding it twice. Use the asset's id wherever blocks take a file or an image.
use Aurora\Support\AssetLibrary;
use Ramsey\Uuid\Uuid;
$asset = AssetLibrary::fromFile($path, [
'id' => Uuid::uuid5(Uuid::NAMESPACE_URL, $old->image_url)->toString(),
'title' => $old->image_title,
'alt' => $old->image_alt,
'folder' => 'Imported/2026',
]);
['type' => 'image', 'data' => ['src' => $asset->id, 'alt' => $old->image_alt]];
Files larger than the media library takes are refused: 10 MB for images and 50 MB for other files, unless aurora.media.max_image_mb and max_file_mb say otherwise. Raise them for the import if you need to.
Redirects and menus
use Aurora\Models\Menu;
use Aurora\Models\MenuItem;
use Aurora\Models\Redirect;
// The old address keeps working, and follows the page if its address changes.
Redirect::query()->create(['from_path' => '/about.html', 'page_id' => $page->id, 'status_code' => 301]);
$menu = Menu::query()->create(['name' => 'Main navigation', 'is_visible' => true]);
$menu->locations()->create(['location' => 'header']);
MenuItem::query()->create([
'menu_id' => $menu->id,
'linkable_type' => $page->getMorphClass(),
'linkable_id' => $page->id,
'order' => 1,
]);
Good to know
- Saves from code go straight on the page, live or not. Only the page form, the visual editor and AI tools keep a live page's changes waiting as unpublished changes.
- Several sites: import into another site with
CurrentSite::using($site, fn () => …). - Search: rebuild the index once the import is done, with
php artisan aurora:reindex.