File: /home/xedaptot/ai.naniguide.com/database/seeders/TemplateSeeder.php
<?php
namespace Database\Seeders;
use App\Library\File;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Model\SystemTemplate;
use App\Model\Template;
use App\Model\TemplateCategory;
use App\Model\SystemEmailTemplate;
use App\Model\FormTemplate;
use App\Library\StringHelper;
class TemplateSeeder extends Seeder
{
protected function getThemeBasePath()
{
return resource_path('themes');
}
/**
* Run the database seeds.
*/
public function run(): void
{
$this->resetTemplateCategories();
$this->resetSystemTemplates();
$this->resetSystemEmailTemplates();
$this->resetFormTemplates();
$this->resetPageTemplates();
/*
// reset template categories
$this->resetTemplateCategories();
// Reset all system templates
$this->resetSystemTemplates();
// Reset all mail list default templates
foreach (\App\Model\MailList::all() as $mailList) {
$mailList->resetDefaultTemplates();
}
// reset system email templates
$this->resetSystemEmailTemplates();
// reset system email templates
$this->resetFormTemplates();
*/
// reset mail lists templates : @@@@support tạo template mới cho các list đã có từ trước pages
foreach (\App\Model\MailList::whereHas('customer')->get() as $mailList) {
if ($mailList->mailListTemplates()->count() == 0) { // những list mà dùng legacy pages table hồi trước
$mailList->resetDefaultTemplates(); // clone template system_template content json/html vào mail_list_templates
}
}
}
public function resetTemplateCategories()
{
// DELETE categories
TemplateCategory::query()->delete();
// Unified taxonomy (2026-04-09): only Base + Extended remain.
// Legacy "Basic" / "Featured" / "Popup" style categories all dropped —
// every system email template AND form template is classified ONLY as
// Base (canonical, shipped starting points) or Extended (admin-curated derivatives).
TemplateCategory::create(['name' => 'Base']);
TemplateCategory::create(['name' => 'Extended']);
}
public function resetSystemTemplates()
{
foreach(SystemTemplate::get() as $sysTemplate) {
$sysTemplate->deleteAndCleanup();
}
// LIST all system templates here
$templateMetas = [
'sender_verification_email' => [
'theme' => 'default',
'name' => 'Sender Verification Email',
// For default data
'json' => 'master/sample/system/sender_verification_email.json',
'html' => 'master/sample/system/sender_verification_email.html',
'thumbnail' => 'master/sample/system/sender_verification_email.svg',
],
'sender_verification_email_for_amazon_ses' => [
'theme' => 'default',
'name' => 'Sender Verification Email for Amazon SES',
// For default data
'json' => 'master/sample/system/sender_verification_email_for_amazon_ses.json',
'html' => 'master/sample/system/sender_verification_email_for_amazon_ses.html',
'thumbnail' => 'master/sample/system/sender_verification_email_for_amazon_ses.svg',
],
'sign_up_form' => [
'theme' => 'default',
'name' => 'Sign Up Form',
// For default data
'json' => 'master/sample/system/sign_up_form.json',
'html' => 'master/sample/system/sign_up_form.html',
'thumbnail' => 'master/sample/system/sign_up_form.svg',
],
'sign_up_confirmation_page' => [
'theme' => 'default',
'name' => 'Sign Up Thank You Page',
// For default data
'json' => 'master/sample/system/sign_up_confirmation_page.json',
'html' => 'master/sample/system/sign_up_confirmation_page.html',
'thumbnail' => 'master/sample/system/sign_up_confirmation_page.svg',
],
'sign_up_confirmation_email' => [
'theme' => 'default',
'name' => 'Sign Up Confirmation Email',
// For default data
'json' => 'master/sample/system/sign_up_confirmation_email.json',
'html' => 'master/sample/system/sign_up_confirmation_email.html',
'thumbnail' => 'master/sample/system/sign_up_confirmation_email.svg',
],
'sign_up_thankyou_page' => [
'theme' => 'default',
'name' => 'Thank You page',
// For default data
'json' => 'master/sample/system/sign_up_thankyou_page.json',
'html' => 'master/sample/system/sign_up_thankyou_page.html',
'thumbnail' => 'master/sample/system/sign_up_thankyou_page.svg',
],
'sign_up_welcome_email' => [
'theme' => 'default',
'name' => 'Sign Up Welcome Email',
// For default data
'json' => 'master/sample/system/sign_up_welcome_email.json',
'html' => 'master/sample/system/sign_up_welcome_email.html',
'thumbnail' => 'master/sample/system/sign_up_welcome_email.svg',
],
'unsubscribe_form' => [
'theme' => 'default',
'name' => 'Unsubscribe Form',
// For default data
'json' => 'master/sample/system/unsubscribe_form.json',
'html' => 'master/sample/system/unsubscribe_form.html',
'thumbnail' => 'master/sample/system/unsubscribe_form.svg',
],
'unsubscribe_success_page' => [
'theme' => 'default',
'name' => 'Unsubscribe Success Page',
// For default data
'json' => 'master/sample/system/unsubscribe_success_page.json',
'html' => 'master/sample/system/unsubscribe_success_page.html',
'thumbnail' => 'master/sample/system/unsubscribe_success_page.svg',
],
'unsubscribe_goodbye_email' => [
'theme' => 'default',
'name' => 'Unsubscribe Goodbye Email',
// For default data
'json' => 'master/sample/system/unsubscribe_goodbye_email.json',
'html' => 'master/sample/system/unsubscribe_goodbye_email.html',
'thumbnail' => 'master/sample/system/unsubscribe_goodbye_email.svg',
],
'profile_update_email' => [
'theme' => 'default',
'name' => 'Profile Update Email',
// For default data
'json' => 'master/sample/system/profile_update_email.json',
'html' => 'master/sample/system/profile_update_email.html',
'thumbnail' => 'master/sample/system/profile_update_email.svg',
],
'profile_update_form' => [
'theme' => 'default',
'name' => 'Profile Update Form',
// For default data
'json' => 'master/sample/system/profile_update_form.json',
'html' => 'master/sample/system/profile_update_form.html',
'thumbnail' => 'master/sample/system/profile_update_form.svg',
],
'profile_update_success_page' => [
'theme' => 'default',
'name' => 'Profile Update Success Page',
// For default data
'json' => 'master/sample/system/profile_update_success_page.json',
'html' => 'master/sample/system/profile_update_success_page.html',
'thumbnail' => 'master/sample/system/profile_update_success_page.svg',
],
'profile_update_email_sent' => [
'theme' => 'default',
'name' => 'Profile Update Email Sent',
// For default data
'json' => 'master/sample/system/profile_update_email_sent.json',
'html' => 'master/sample/system/profile_update_email_sent.html',
'thumbnail' => 'master/sample/system/profile_update_email_sent.svg',
],
'unsubscribe_notification_for_list_owner' => [
'theme' => 'default',
'name' => 'Unsubscribe Notification for List Owner',
// For default data
'json' => 'master/sample/system/unsubscribe_notification_for_list_owner.json',
'html' => 'master/sample/system/unsubscribe_notification_for_list_owner.html',
'thumbnail' => 'master/sample/system/unsubscribe_notification_for_list_owner.svg',
],
'subscribe_notification_for_list_owner' => [
'theme' => 'default',
'name' => 'Subscribe Notification for List Owner',
// For default data
'json' => 'master/sample/system/subscribe_notification_for_list_owner.json',
'html' => 'master/sample/system/subscribe_notification_for_list_owner.html',
'thumbnail' => 'master/sample/system/subscribe_notification_for_list_owner.svg',
],
'registration_confirmation_email' => [
'theme' => 'default',
'name' => 'Registration Confirmation Email',
// For default data
'json' => 'master/sample/system/registration_confirmation_email.json',
'html' => 'master/sample/system/registration_confirmation_email.html',
'thumbnail' => 'master/sample/system/registration_confirmation_email.svg',
],
'default_campaign_api_template' => [
'theme' => 'default',
'name' => 'Default Campaign API Template',
// For default data
'json' => 'master/sample/system/default_campaign_api_template.json',
'html' => 'master/sample/system/default_campaign_api_template.html',
'thumbnail' => 'master/sample/system/default_campaign_api_template.svg',
],
'pricing_page' => [
'theme' => 'default',
'name' => 'Pricing Page',
// For default data
'json' => 'master/sample/system/pricing_page.json',
'html' => 'master/sample/system/pricing_page.html',
'thumbnail' => 'master/sample/system/pricing_page.svg',
],
'terms_and_policy_page' => [
'theme' => 'default',
'name' => 'Terms & Policy Page',
// For default data
'json' => 'master/sample/system/terms_and_policy_page.json',
'html' => 'master/sample/system/terms_and_policy_page.html',
'thumbnail' => 'master/sample/system/terms_and_policy_page.svg',
],
'invoice_template' => [
'theme' => 'default',
'name' => 'Invoice Template',
// For default data
'json' => 'master/sample/system/invoice_template.json',
'html' => 'master/sample/system/invoice_template.html',
'thumbnail' => 'master/sample/system/invoice_template.svg',
],
];
// Create system template
foreach ($templateMetas as $alias => $meta) {
$json = $this->replaceJsonUrl(
json_decode(file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['json'])), true),
$meta['theme'],
);
$json = json_encode($json);
$html = $this->replaceHtmlUrl(
file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['html'])),
$meta['theme'],
);
// Create template
$template = Template::createTemplate($meta['theme'], $meta['name'], $json, $html);
//
$template->updateThumbnailFromPath(join_paths($this->getThemeBasePath(), $meta['theme'], $meta['thumbnail']));
// Create system template
$systemTemplate = SystemTemplate::make([
'alias' => $alias,
]);
$systemTemplate->template_id = $template->id;
$systemTemplate->save();
}
// reset all lists (only those with a valid customer FK)
foreach (\App\Model\MailList::whereHas('customer')->get() as $list) {
$list->resetDefaultTemplates();
}
}
public function resetSystemEmailTemplates()
{
foreach(SystemEmailTemplate::get() as $t) {
$t->deleteAndCleanup();
}
// Unified taxonomy (2026-04-09): only Base + Extended (legacy Basic/Featured removed).
// The 'tier' key in each template meta below decides classification.
$categoryBase = TemplateCategory::whereName('Base')->first();
$categoryExtended = TemplateCategory::whereName('Extended')->first();
// LIST all default templates here
$templates = [
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/Blank.json',
'html' => 'master/sample/email/Blank.html',
//
'name' => 'Blank',
'thumbnail' => 'master/sample/email/Blank.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/Minimal.json',
'html' => 'master/sample/email/Minimal.html',
//
'name' => 'Minimal',
'thumbnail' => 'master/sample/email/Minimal.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/SimpleText.json',
'html' => 'master/sample/email/SimpleText.html',
//
'name' => 'Simple Text',
'thumbnail' => 'master/sample/email/SimpleText.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/Gallery.json',
'html' => 'master/sample/email/Gallery.html',
//
'name' => 'Gallery',
'thumbnail' => 'master/sample/email/Gallery.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/SellProducts.json',
'html' => 'master/sample/email/SellProducts.html',
//
'name' => 'Sell Products',
'thumbnail' => 'master/sample/email/SellProducts.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/1-2-1_Column.json',
'html' => 'master/sample/email/1-2-1_Column.html',
//
'name' => '1:2:1 Column',
'thumbnail' => 'master/sample/email/1-2-1_Column.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/1-3_Column.json',
'html' => 'master/sample/email/1-3_Column.html',
//
'name' => '1:3 Column',
'thumbnail' => 'master/sample/email/1-3_Column.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/TellAStory.json',
'html' => 'master/sample/email/TellAStory.html',
//
'name' => 'Tell a story',
'thumbnail' => 'master/sample/email/TellAStory.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/FeaturedProduct.json',
'html' => 'master/sample/email/FeaturedProduct.html',
//
'name' => 'Featured Product',
'thumbnail' => 'master/sample/email/FeaturedProduct.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/PromoteProducts.json',
'html' => 'master/sample/email/PromoteProducts.html',
//
'name' => 'Promote products',
'thumbnail' => 'master/sample/email/PromoteProducts.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/EventInvitation.json',
'html' => 'master/sample/email/EventInvitation.html',
//
'name' => 'Event invitation',
'thumbnail' => 'master/sample/email/EventInvitation.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/RetailServices.json',
'html' => 'master/sample/email/RetailServices.html',
//
'name' => 'Retail services',
'thumbnail' => 'master/sample/email/RetailServices.svg',
],
[
'theme' => 'default',
'tier' => 'base',
// for default data
'json' => 'master/sample/email/MakeAnAnnouncement.json',
'html' => 'master/sample/email/MakeAnAnnouncement.html',
//
'name' => 'Make an announcement',
'thumbnail' => 'master/sample/email/MakeAnAnnouncement.svg',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/SitewideSale.json',
'html' => 'master/sample/email/SitewideSale.html',
//
'name' => 'Sitewide sale',
'thumbnail' => 'master/sample/email/SitewideSale.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/WelcomeCustomers.json',
'html' => 'master/sample/email/WelcomeCustomers.html',
//
'name' => 'Welcome customers',
'thumbnail' => 'master/sample/email/WelcomeCustomers.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/AdvertiseApp.json',
'html' => 'master/sample/email/AdvertiseApp.html',
//
'name' => 'Advertise app',
'thumbnail' => 'master/sample/email/AdvertiseApp.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/ClassThankYou.json',
'html' => 'master/sample/email/ClassThankYou.html',
//
'name' => 'Class thank you',
'thumbnail' => 'master/sample/email/ClassThankYou.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/AboutOurServices.json',
'html' => 'master/sample/email/AboutOurServices.html',
//
'name' => 'About our services',
'thumbnail' => 'master/sample/email/AboutOurServices.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/ThankYouPersonalized.json',
'html' => 'master/sample/email/ThankYouPersonalized.html',
//
'name' => 'Thank you personalized',
'thumbnail' => 'master/sample/email/ThankYouPersonalized.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/Editorial_Newsletter.json',
'html' => 'master/sample/email/Editorial_Newsletter.html',
//
'name' => 'Editorial Newsletter',
'thumbnail' => 'master/sample/email/Editorial_Newsletter.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/MemorialDay.json',
'html' => 'master/sample/email/MemorialDay.html',
//
'name' => 'Memorial Day',
'thumbnail' => 'master/sample/email/MemorialDay.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/RemembranceDayRun.json',
'html' => 'master/sample/email/RemembranceDayRun.html',
//
'name' => 'Remembrance Day Run',
'thumbnail' => 'master/sample/email/RemembranceDayRun.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/ThanksgivingOffer.json',
'html' => 'master/sample/email/ThanksgivingOffer.html',
//
'name' => 'Thanksgiving Offer',
'thumbnail' => 'master/sample/email/ThanksgivingOffer.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/OpenHouseInvite.json',
'html' => 'master/sample/email/OpenHouseInvite.html',
//
'name' => 'Open House Invite',
'thumbnail' => 'master/sample/email/OpenHouseInvite.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/Educational.json',
'html' => 'master/sample/email/Educational.html',
//
'name' => 'Educational Theme',
'thumbnail' => 'master/sample/email/Educational.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/OrderAgain.json',
'html' => 'master/sample/email/OrderAgain.html',
//
'name' => 'Order Again',
'thumbnail' => 'master/sample/email/OrderAgain.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/EventLineup.json',
'html' => 'master/sample/email/EventLineup.html',
//
'name' => 'Event Lineup',
'thumbnail' => 'master/sample/email/EventLineup.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/RealEstateInvite.json',
'html' => 'master/sample/email/RealEstateInvite.html',
//
'name' => 'Real estate invite',
'thumbnail' => 'master/sample/email/RealEstateInvite.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/EventAgendaDark.json',
'html' => 'master/sample/email/EventAgendaDark.html',
//
'name' => 'Event Agenda Dark',
'thumbnail' => 'master/sample/email/EventAgendaDark.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/AboutUs.json',
'html' => 'master/sample/email/AboutUs.html',
//
'name' => 'About Us',
'thumbnail' => 'master/sample/email/AboutUs.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/ProductPromotion.json',
'html' => 'master/sample/email/ProductPromotion.html',
//
'name' => 'Product Promotion',
'thumbnail' => 'master/sample/email/ProductPromotion.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/FathersDaySpecials.json',
'html' => 'master/sample/email/FathersDaySpecials.html',
//
'name' => 'Fathers Day Specials',
'thumbnail' => 'master/sample/email/FathersDaySpecials.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/InternationalWomensDay.json',
'html' => 'master/sample/email/InternationalWomensDay.html',
//
'name' => 'International Womens Day',
'thumbnail' => 'master/sample/email/InternationalWomensDay.png',
],
[
'theme' => 'default',
'tier' => 'extended',
// for default data
'json' => 'master/sample/email/WorkspaceAIInvite.json',
'html' => 'master/sample/email/WorkspaceAIInvite.html',
//
'name' => 'Workspace AI Invite',
'thumbnail' => 'master/sample/email/WorkspaceAIInvite.png',
],
];
// Delete existing template and create again with new updates
foreach ($templates as $meta) {
$json = $this->replaceJsonUrl(
json_decode(file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['json'])), true),
$meta['theme'],
);
$json = json_encode($json);
$html = $this->replaceHtmlUrl(
file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['html'])),
$meta['theme'],
);
// Create template
$template = Template::createTemplate($meta['theme'], $meta['name'], $json, $html);
//
$template->updateThumbnailFromPath(join_paths($this->getThemeBasePath(), $meta['theme'], $meta['thumbnail']));
// Unified classification — tier is 'base' (canonical) or 'extended' (pre-designed).
$tier = $meta['tier'] ?? 'base';
if ($tier === 'extended' && $categoryExtended) {
$template->categories()->attach([$categoryExtended->id]);
} elseif ($categoryBase) {
$template->categories()->attach([$categoryBase->id]);
}
// Create system email template
$systemEmailTemplate = SystemEmailTemplate::newDefault();
$systemEmailTemplate->name = $meta['name'];
$systemEmailTemplate->template_id = $template->id;
$systemEmailTemplate->save();
}
}
public function resetFormTemplates()
{
foreach(FormTemplate::get() as $t) {
$t->deleteAndCleanup();
}
$categoryBase = TemplateCategory::whereName('Base')->first();
// LIST all default templates here — all classified as Base (no Popup category anymore)
$templates = [
// Popup form templates
[
'theme' => 'default',
// for default data
'json' => 'master/sample/form/Popup_Form_Left_Banner.json',
'html' => 'master/sample/form/Popup_Form_Left_Banner.html',
//
'name' => 'Popup Form Banner',
'thumbnail' => 'master/sample/form/Popup_Form_Left_Banner.svg',
],
[
'theme' => 'default',
// for default data
'json' => 'master/sample/form/Popup_Form_Right_Banner.json',
'html' => 'master/sample/form/Popup_Form_Right_Banner.html',
//
'name' => 'Popup Form Right Banner',
'thumbnail' => 'master/sample/form/Popup_Form_Right_Banner.svg',
],
[
'theme' => 'default',
// for default data
'json' => 'master/sample/form/Popup_Form_Top_Banner.json',
'html' => 'master/sample/form/Popup_Form_Top_Banner.html',
//
'name' => 'Popup Form Top Banner',
'thumbnail' => 'master/sample/form/Popup_Form_Top_Banner.svg',
],
[
'theme' => 'default',
// for default data
'json' => 'master/sample/form/Popup_Form_Bottom_Banner.json',
'html' => 'master/sample/form/Popup_Form_Bottom_Banner.html',
//
'name' => 'Popup Form Bottom Banner',
'thumbnail' => 'master/sample/form/Popup_Form_Bottom_Banner.svg',
],
];
// Delete existing template and create again with new updates
foreach ($templates as $meta) {
//
$json = $this->replaceJsonUrl(
json_decode(file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['json'])), true),
$meta['theme'],
);
$json = json_encode($json);
$html = $this->replaceHtmlUrl(
file_get_contents(join_paths($this->getThemeBasePath(), $meta['theme'] , $meta['html'])),
$meta['theme'],
);
// Create template
$template = Template::createTemplate($meta['theme'], $meta['name'], $json, $html);
//
$template->updateThumbnailFromPath(join_paths($this->getThemeBasePath(), $meta['theme'], $meta['thumbnail']));
// All seeded form templates are classified as Base
if ($categoryBase) {
$template->categories()->attach([$categoryBase->id]);
}
// Create form template
$formTemplate = FormTemplate::newDefault();
$formTemplate->name = $meta['name'];
$formTemplate->template_id = $template->id;
$formTemplate->save();
}
}
public function resetPageTemplates()
{
foreach (\App\Model\PageTemplate::get() as $t) {
\App\Services\TemplateService::for($t)->deleteSubjectAndTemplate();
}
$categoryBase = TemplateCategory::whereName('Base')->first();
$categoryExtended = TemplateCategory::whereName('Extended')->first();
// Page templates shipped via BuilderJS (copy.sh --type=master).
// - Base : Mc* MailChimp-style simple pages (monochrome, placeholder-driven)
// - Extended : Rich commerce funnel (ProductShowcase → ShoppingCart → Checkout → OrderComplete)
$templates = [
// Base tier — 5 monochrome MC-style simple pages
[
'tier' => 'base',
'theme' => 'default',
'json' => 'master/sample/page/McShowcase.json',
'html' => 'master/sample/page/McShowcase.html',
'name' => 'Simple Showcase',
'thumbnail' => 'master/sample/page/McShowcase.png',
],
[
'tier' => 'base',
'theme' => 'default',
'json' => 'master/sample/page/McProductShowcase.json',
'html' => 'master/sample/page/McProductShowcase.html',
'name' => 'Simple Product',
'thumbnail' => 'master/sample/page/McProductShowcase.png',
],
[
'tier' => 'base',
'theme' => 'default',
'json' => 'master/sample/page/McShoppingCart.json',
'html' => 'master/sample/page/McShoppingCart.html',
'name' => 'Simple Cart',
'thumbnail' => 'master/sample/page/McShoppingCart.png',
],
[
'tier' => 'base',
'theme' => 'default',
'json' => 'master/sample/page/McCheckout.json',
'html' => 'master/sample/page/McCheckout.html',
'name' => 'Simple Checkout',
'thumbnail' => 'master/sample/page/McCheckout.png',
],
[
'tier' => 'base',
'theme' => 'default',
'json' => 'master/sample/page/McComplete.json',
'html' => 'master/sample/page/McComplete.html',
'name' => 'Simple Order Complete',
'thumbnail' => 'master/sample/page/McComplete.png',
],
// Extended tier — 4 rich commerce funnel pages
[
'tier' => 'extended',
'theme' => 'default',
'json' => 'master/sample/page/ProductShowcase.json',
'html' => 'master/sample/page/ProductShowcase.html',
'name' => 'Product Showcase',
'thumbnail' => 'master/sample/page/ProductShowcase.png',
],
[
'tier' => 'extended',
'theme' => 'default',
'json' => 'master/sample/page/ShoppingCart.json',
'html' => 'master/sample/page/ShoppingCart.html',
'name' => 'Shopping Cart',
'thumbnail' => 'master/sample/page/ShoppingCart.png',
],
[
'tier' => 'extended',
'theme' => 'default',
'json' => 'master/sample/page/Checkout.json',
'html' => 'master/sample/page/Checkout.html',
'name' => 'Checkout',
'thumbnail' => 'master/sample/page/Checkout.png',
],
[
'tier' => 'extended',
'theme' => 'default',
'json' => 'master/sample/page/OrderComplete.json',
'html' => 'master/sample/page/OrderComplete.html',
'name' => 'Order Complete',
'thumbnail' => 'master/sample/page/OrderComplete.png',
],
];
foreach ($templates as $meta) {
$jsonPath = join_paths($this->getThemeBasePath(), $meta['theme'], $meta['json']);
$htmlPath = join_paths($this->getThemeBasePath(), $meta['theme'], $meta['html']);
// D-Lite safety: BuilderJS samples must be synced first (copy.sh). Skip with
// log if a file is missing so the seeder stays green during partial sync.
if (!file_exists($jsonPath) || !file_exists($htmlPath)) {
$this->command?->warn(sprintf('[PageTemplate] Skipping %s — %s missing', $meta['name'], !file_exists($jsonPath) ? $jsonPath : $htmlPath));
continue;
}
$json = $this->replaceJsonUrl(json_decode(file_get_contents($jsonPath), true), $meta['theme']);
$json = json_encode($json);
$html = $this->replaceHtmlUrl(file_get_contents($htmlPath), $meta['theme']);
// Create underlying Template row
$template = Template::createTemplate($meta['theme'], $meta['name'], $json, $html);
// Thumbnail (may be absent if gen-thumb hasn't run yet — getThumbUrl
// falls back to placeholder.jpg so admin UI still renders)
$thumbPath = join_paths($this->getThemeBasePath(), $meta['theme'], $meta['thumbnail']);
if (file_exists($thumbPath)) {
$template->updateThumbnailFromPath($thumbPath);
}
// Tier tagging
$tierCategory = $meta['tier'] === 'base' ? $categoryBase : $categoryExtended;
if ($tierCategory) {
$template->categories()->attach([$tierCategory->id]);
}
// Create the PageTemplate wrapper
$pageTemplate = \App\Model\PageTemplate::newDefault();
$pageTemplate->name = $meta['name'];
$pageTemplate->template_id = $template->id;
$pageTemplate->save();
}
}
public function replaceHtmlUrl($html, $theme)
{
// No URL transformation needed for .json files, as the theme prefix is already specfied when loading
// URL transformation is needed for .html files
return \App\Library\StringHelper::replaceUrl($html, function($element, $url) use ($theme) {
$host = parse_url($url, PHP_URL_HOST);
if ($host === null) { // meaning relative path
// Starts with "image/" or "/image/" or a tag like {{ unsubscribe_url }}
$updatedUrl = $this->generateUrl($url, $theme);
// echo "HTML transform {$updatedUrl}\n";
return $updatedUrl;
} else {
// echo "Ignore $url\n";
return $url;
}
}, $throwIfInvaildUrl = true);
}
public function replaceJsonUrl(array $json, string $theme)
{
// You can still list your search definitions if needed
$searchFor = [
["name", "ImageElement", "src"], // Node with [name=ImageElement] having a src attribute
["*", "*", "image_url"], // Any node having an image_url attribute
];
foreach ($searchFor as $info) {
list($key, $elementType, $srcAttribute) = $info;
StringHelper::iterate($json, function (&$node) use ($theme, $key, $elementType, $srcAttribute) {
// --- Determine if this node matches the pattern ---
$hasNameKey = $key !== '*' && array_key_exists($key, $node);
$hasSrcKey = $srcAttribute !== '*' && array_key_exists($srcAttribute, $node);
// Check rules
$matches =
// Fully wildcard (["*", "*", "src"])
($key === '*' && $elementType === '*' && $hasSrcKey)
// Key wildcard but name fixed (["name", "*", "src"])
|| ($key !== '*' && $elementType === '*' && $hasNameKey && $hasSrcKey)
// Exact match (["name", "ImageElement", "src"])
|| ($key !== '*' && $elementType !== '*' && ($node[$key] ?? null) === $elementType && $hasSrcKey);
if ($matches) {
$url = $node[$srcAttribute];
$host = parse_url($url, PHP_URL_HOST);
if ($host === null) {
// Starts with "image/" or "/image/"
$node[$srcAttribute] = $this->generateUrl($url, $theme);
// echo "JSON transform {$node[$srcAttribute]}\n";
} else {
// echo "Ignore $url\n";
}
}
});
}
return $json;
}
private function generateUrl($url, $theme)
{
$urlPrefix = app(\App\Services\UrlService::class)->generateThemeAssetUrl($theme, $path = null);
$updatedUrl = join_paths($urlPrefix, $url);
return $updatedUrl;
}
}