diff --git a/app/Filament/Admin/Resources/Pages/Schemas/Sections/FooterTemplateSection.php b/app/Filament/Admin/Resources/Pages/Schemas/Sections/FooterTemplateSection.php index 150fb23..91f9a50 100644 --- a/app/Filament/Admin/Resources/Pages/Schemas/Sections/FooterTemplateSection.php +++ b/app/Filament/Admin/Resources/Pages/Schemas/Sections/FooterTemplateSection.php @@ -10,6 +10,8 @@ use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Utilities\Set; +use Illuminate\Support\Facades\File; + class FooterTemplateSection { public static function make(): Section @@ -17,9 +19,35 @@ class FooterTemplateSection return Section::make(__('pages.form_section_footer_template')) ->description(__('pages.form_section_footer_template_desc')) ->schema([ + Select::make('custom_footer_blade') + ->label('Custom Footer Blade') + ->options(function () { + $files = File::glob(resource_path('views/partials/*.blade.php')); + $options = []; + foreach ($files as $file) { + $name = basename($file, '.blade.php'); + $options["partials.{$name}"] = "Partial: {$name}"; + } + + // Add other directories if needed + $componentFiles = File::glob(resource_path('views/components/front/*.blade.php')); + foreach ($componentFiles as $file) { + $name = basename($file, '.blade.php'); + $options["components.front.{$name}"] = "Component: {$name}"; + } + + return $options; + }) + ->searchable() + ->preload() + ->helperText('Select a physical Blade file to use as footer instead of a database template.') + ->live() + ->columnSpanFull(), + Select::make('footer_template_id') ->label(__('pages.footer_template_field')) ->options(FooterTemplate::where('is_active', true)->pluck('title', 'id')) + ->visible(fn (Get $get) => empty($get('custom_footer_blade'))) ->searchable() ->live() ->afterStateUpdated(function ($state, Set $set, Get $get) { diff --git a/app/Filament/Admin/Resources/Pages/Schemas/Sections/HeaderTemplateSection.php b/app/Filament/Admin/Resources/Pages/Schemas/Sections/HeaderTemplateSection.php index 4c2ec67..4d62140 100644 --- a/app/Filament/Admin/Resources/Pages/Schemas/Sections/HeaderTemplateSection.php +++ b/app/Filament/Admin/Resources/Pages/Schemas/Sections/HeaderTemplateSection.php @@ -10,6 +10,8 @@ use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Utilities\Set; +use Illuminate\Support\Facades\File; + class HeaderTemplateSection { public static function make(): Section @@ -17,9 +19,35 @@ class HeaderTemplateSection return Section::make(__('pages.form_section_header_template')) ->description(__('pages.form_section_header_template_desc')) ->schema([ + Select::make('custom_header_blade') + ->label('Custom Header Blade') + ->options(function () { + $files = File::glob(resource_path('views/partials/*.blade.php')); + $options = []; + foreach ($files as $file) { + $name = basename($file, '.blade.php'); + $options["partials.{$name}"] = "Partial: {$name}"; + } + + // Add other directories if needed + $componentFiles = File::glob(resource_path('views/components/front/*.blade.php')); + foreach ($componentFiles as $file) { + $name = basename($file, '.blade.php'); + $options["components.front.{$name}"] = "Component: {$name}"; + } + + return $options; + }) + ->searchable() + ->preload() + ->helperText('Select a physical Blade file to use as header instead of a database template.') + ->live() + ->columnSpanFull(), + Select::make('header_template_id') ->label(__('pages.header_template_field')) ->options(HeaderTemplate::where('is_active', true)->pluck('title', 'id')) + ->visible(fn (Get $get) => empty($get('custom_header_blade'))) ->searchable() ->live() ->afterStateUpdated(function ($state, Set $set, Get $get) { diff --git a/app/Filament/Admin/Resources/Pages/Schemas/Sections/PageSettingsSection.php b/app/Filament/Admin/Resources/Pages/Schemas/Sections/PageSettingsSection.php index d6ccec4..fadba52 100644 --- a/app/Filament/Admin/Resources/Pages/Schemas/Sections/PageSettingsSection.php +++ b/app/Filament/Admin/Resources/Pages/Schemas/Sections/PageSettingsSection.php @@ -69,13 +69,14 @@ class PageSettingsSection 'landing' => __('pages.template_landing'), 'blog' => __('pages.template_blog'), 'contact' => __('pages.template_contact'), + 'home' => 'Home', ]) ->default('default') ->columnSpanFull(), - TextInput::make('sort_order') - ->label(__('pages.sort_order_field')) - ->numeric() + TextInput::make('sort_order') + ->label(__('pages.sort_order_field')) + ->numeric() ->default(0) ->helperText(__('pages.sort_order_helper_text')) ->columnSpanFull(), diff --git a/app/Filament/Admin/Resources/ProductCategories/Tables/ProductCategoriesTable.php b/app/Filament/Admin/Resources/ProductCategories/Tables/ProductCategoriesTable.php index ca4299a..05f81dd 100644 --- a/app/Filament/Admin/Resources/ProductCategories/Tables/ProductCategoriesTable.php +++ b/app/Filament/Admin/Resources/ProductCategories/Tables/ProductCategoriesTable.php @@ -18,14 +18,14 @@ class ProductCategoriesTable ->columns([ TextColumn::make('title') ->label(__('product_categories.title')) - ->formatStateUsing(fn ($state) => is_array($state) ? ($state[app()->getLocale()] ?? reset($state)) : $state) + ->formatStateUsing(fn ($state, $record) => $record->translate('title')) ->searchable() ->sortable(), TextColumn::make('slug') ->label(__('product_categories.slug')) ->searchable(), - TextColumn::make('parent.title') // This might fail if parent title is JSON - ->formatStateUsing(fn ($state) => is_array($state) ? ($state[app()->getLocale()] ?? reset($state)) : $state) + TextColumn::make('parent.title') + ->formatStateUsing(fn ($state, $record) => $record->parent?->translate('title')) ->label(__('product_categories.parent')), TextColumn::make('sort_order') ->label(__('product_categories.sort_order')) diff --git a/app/Filament/Admin/Resources/Products/Schemas/ProductForm.php b/app/Filament/Admin/Resources/Products/Schemas/ProductForm.php index d593e84..2af3c63 100644 --- a/app/Filament/Admin/Resources/Products/Schemas/ProductForm.php +++ b/app/Filament/Admin/Resources/Products/Schemas/ProductForm.php @@ -10,6 +10,9 @@ use Filament\Forms\Components\FileUpload; use Filament\Schemas\Components\Section; use App\Filament\Admin\Resources\Components\TranslationTabs; use App\Models\ProductCategory; +use Illuminate\Support\Str; +use Filament\Forms\Get; +use Filament\Forms\Set; class ProductForm { @@ -19,6 +22,16 @@ class ProductForm ->schema([ Section::make(__('products.general_section')) ->schema([ + TextInput::make('title') + ->label(__('products.title')) + ->required() + ->live(onBlur: true) + ->afterStateUpdated(function (Get $get, Set $set, ?string $state) { + $set('slug', Str::slug($state)); + $set('translations.' . app()->getLocale() . '.title', $state); + }) + ->formatStateUsing(fn ($record) => $record?->translate('title')) + ->dehydrated(false), TextInput::make('slug') ->label(__('products.slug')) ->required() @@ -41,6 +54,7 @@ class ProductForm FileUpload::make('hero_image') ->label(__('products.hero_image')) ->image() + ->disk('public') ->directory('products'), TextInput::make('view_template') ->label(__('products.view_template')) diff --git a/app/Filament/Admin/Resources/Products/Tables/ProductsTable.php b/app/Filament/Admin/Resources/Products/Tables/ProductsTable.php index 94e5645..76f2d8e 100644 --- a/app/Filament/Admin/Resources/Products/Tables/ProductsTable.php +++ b/app/Filament/Admin/Resources/Products/Tables/ProductsTable.php @@ -21,7 +21,7 @@ class ProductsTable ->label(__('products.hero_image')), TextColumn::make('title') ->label(__('products.title')) - ->formatStateUsing(fn ($state) => is_array($state) ? ($state[app()->getLocale()] ?? reset($state)) : $state) + ->formatStateUsing(fn ($state, $record) => $record->translate('title')) ->searchable() ->sortable(), TextColumn::make('type') @@ -38,7 +38,7 @@ class ProductsTable default => $state, }), TextColumn::make('category.title') - ->formatStateUsing(fn ($state) => is_array($state) ? ($state[app()->getLocale()] ?? reset($state)) : $state) + ->formatStateUsing(fn ($state, $record) => $record->category?->translate('title')) ->label(__('products.category')), ToggleColumn::make('is_active') ->label(__('products.is_active')), diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 9621edd..3b81bdb 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -143,52 +143,66 @@ class PageController extends Controller // Render Header Template $renderedHeader = null; - $headerTemplate = $page->headerTemplate; - - // Eğer sayfa için header seçilmemişse, en son aktif header template'i kullan - if (!$headerTemplate) { - $defaultHeaderId = $settings->default_header ?? null; - if ($defaultHeaderId) { - $headerTemplate = HeaderTemplate::find($defaultHeaderId); - } - } - - if ($headerTemplate) { - // Merge template defaults with page data (page data overrides defaults) - $templateDefaults = $headerTemplate->default_data ?? []; - $pageData = $page->header_data ?? []; - $mergedHeaderData = array_merge($templateDefaults, $pageData); + + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_header_blade) && view()->exists($page->custom_header_blade)) { + $renderedHeader = view($page->custom_header_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Header Template sistemini kullan + $headerTemplate = $page->headerTemplate; - $renderedHeader = TemplateService::replacePlaceholders( - $headerTemplate->html_content, - $mergedHeaderData, - $page - ); + // Eğer sayfa için header seçilmemişse, en son aktif header template'i kullan + if (!$headerTemplate) { + $defaultHeaderId = $settings->default_header ?? null; + if ($defaultHeaderId) { + $headerTemplate = HeaderTemplate::find($defaultHeaderId); + } + } + + if ($headerTemplate) { + // Merge template defaults with page data (page data overrides defaults) + $templateDefaults = $headerTemplate->default_data ?? []; + $pageData = $page->header_data ?? []; + $mergedHeaderData = array_merge($templateDefaults, $pageData); + + $renderedHeader = TemplateService::replacePlaceholders( + $headerTemplate->html_content, + $mergedHeaderData, + $page + ); + } } // Render Footer Template $renderedFooter = null; - $footerTemplate = $page->footerTemplate; - - // Eğer sayfa için footer seçilmemişse, en son aktif footer template'i kullan - if (!$footerTemplate) { - $defaultFooterId = $settings->default_footer ?? null; - if ($defaultFooterId) { - $footerTemplate = FooterTemplate::find($defaultFooterId); - } - } - - if ($footerTemplate) { - // Merge template defaults with page data (page data overrides defaults) - $templateDefaults = $footerTemplate->default_data ?? []; - $pageData = $page->footer_data ?? []; - $mergedFooterData = array_merge($templateDefaults, $pageData); + + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_footer_blade) && view()->exists($page->custom_footer_blade)) { + $renderedFooter = view($page->custom_footer_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Footer Template sistemini kullan + $footerTemplate = $page->footerTemplate; - $renderedFooter = TemplateService::replacePlaceholders( - $footerTemplate->html_content, - $mergedFooterData, - $page - ); + // Eğer sayfa için footer seçilmemişse, en son aktif footer template'i kullan + if (!$footerTemplate) { + $defaultFooterId = $settings->default_footer ?? null; + if ($defaultFooterId) { + $footerTemplate = FooterTemplate::find($defaultFooterId); + } + } + + if ($footerTemplate) { + // Merge template defaults with page data (page data overrides defaults) + $templateDefaults = $footerTemplate->default_data ?? []; + $pageData = $page->footer_data ?? []; + $mergedFooterData = array_merge($templateDefaults, $pageData); + + $renderedFooter = TemplateService::replacePlaceholders( + $footerTemplate->html_content, + $mergedFooterData, + $page + ); + } } return view($view, [ @@ -240,37 +254,48 @@ class PageController extends Controller $renderedFooter = null; if ($page) { - // Render Header Template - $headerTemplate = $page->headerTemplate; - if (!$headerTemplate) { - $defaultHeaderId = $settings->default_header ?? null; - if ($defaultHeaderId) { - $headerTemplate = HeaderTemplate::find($defaultHeaderId); - } - } - - if ($headerTemplate) { - $templateDefaults = $headerTemplate->default_data ?? []; - $pageData = $page->header_data ?? []; - $mergedHeaderData = array_merge($templateDefaults, $pageData); - $renderedHeader = TemplateService::replacePlaceholders($headerTemplate->html_content, $mergedHeaderData, $page); + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_header_blade) && view()->exists($page->custom_header_blade)) { + $renderedHeader = view($page->custom_header_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Header Template sistemini kullan + $headerTemplate = $page->headerTemplate; + if (!$headerTemplate) { + $defaultHeaderId = $settings->default_header ?? null; + if ($defaultHeaderId) { + $headerTemplate = HeaderTemplate::find($defaultHeaderId); + } + } + + if ($headerTemplate) { + $templateDefaults = $headerTemplate->default_data ?? []; + $pageData = $page->header_data ?? []; + $mergedHeaderData = array_merge($templateDefaults, $pageData); + $renderedHeader = TemplateService::replacePlaceholders($headerTemplate->html_content, $mergedHeaderData, $page); + } } - // Render Footer Template - $footerTemplate = $page->footerTemplate; - - if (!$footerTemplate) { - $defaultFooterId = $settings->default_footer ?? null; - if ($defaultFooterId) { - $footerTemplate = FooterTemplate::find($defaultFooterId); - } - } - - if ($footerTemplate) { - $templateDefaults = $footerTemplate->default_data ?? []; - $pageData = $page->footer_data ?? []; - $mergedFooterData = array_merge($templateDefaults, $pageData); - $renderedFooter = TemplateService::replacePlaceholders($footerTemplate->html_content, $mergedFooterData, $page); + // Footer Render + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_footer_blade) && view()->exists($page->custom_footer_blade)) { + $renderedFooter = view($page->custom_footer_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Footer Template sistemini kullan + $footerTemplate = $page->footerTemplate; + + if (!$footerTemplate) { + $defaultFooterId = $settings->default_footer ?? null; + if ($defaultFooterId) { + $footerTemplate = FooterTemplate::find($defaultFooterId); + } + } + + if ($footerTemplate) { + $templateDefaults = $footerTemplate->default_data ?? []; + $pageData = $page->footer_data ?? []; + $mergedFooterData = array_merge($templateDefaults, $pageData); + $renderedFooter = TemplateService::replacePlaceholders($footerTemplate->html_content, $mergedFooterData, $page); + } } } @@ -324,52 +349,66 @@ class PageController extends Controller // Render Header Template $renderedHeader = null; - $headerTemplate = $page->headerTemplate; - - // Eğer sayfa için header seçilmemişse, en son aktif header template'i kullan - if (!$headerTemplate) { - $defaultHeaderId = $settings->default_header ?? null; - if ($defaultHeaderId) { - $headerTemplate = HeaderTemplate::find($defaultHeaderId); - } - } - - if ($headerTemplate) { - // Merge template defaults with page data (page data overrides defaults) - $templateDefaults = $headerTemplate->default_data ?? []; - $pageData = $page->header_data ?? []; - $mergedHeaderData = array_merge($templateDefaults, $pageData); + + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_header_blade) && view()->exists($page->custom_header_blade)) { + $renderedHeader = view($page->custom_header_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Header Template sistemini kullan + $headerTemplate = $page->headerTemplate; - $renderedHeader = TemplateService::replacePlaceholders( - $headerTemplate->html_content, - $mergedHeaderData, - $page - ); + // Eğer sayfa için header seçilmemişse, en son aktif header template'i kullan + if (!$headerTemplate) { + $defaultHeaderId = $settings->default_header ?? null; + if ($defaultHeaderId) { + $headerTemplate = HeaderTemplate::find($defaultHeaderId); + } + } + + if ($headerTemplate) { + // Merge template defaults with page data (page data overrides defaults) + $templateDefaults = $headerTemplate->default_data ?? []; + $pageData = $page->header_data ?? []; + $mergedHeaderData = array_merge($templateDefaults, $pageData); + + $renderedHeader = TemplateService::replacePlaceholders( + $headerTemplate->html_content, + $mergedHeaderData, + $page + ); + } } // Render Footer Template $renderedFooter = null; - $footerTemplate = $page->footerTemplate; - - // Eğer sayfa için footer seçilmemişse, en son aktif footer template'i kullan - if (!$footerTemplate) { - $defaultFooterId = $settings->default_footer ?? null; - if ($defaultFooterId) { - $footerTemplate = FooterTemplate::find($defaultFooterId); - } - } - - if ($footerTemplate) { - // Merge template defaults with page data (page data overrides defaults) - $templateDefaults = $footerTemplate->default_data ?? []; - $pageData = $page->footer_data ?? []; - $mergedFooterData = array_merge($templateDefaults, $pageData); + + // 1. Önce özel blade dosyası var mı kontrol et + if (!empty($page->custom_footer_blade) && view()->exists($page->custom_footer_blade)) { + $renderedFooter = view($page->custom_footer_blade, ['page' => $page])->render(); + } else { + // 2. Yoksa Footer Template sistemini kullan + $footerTemplate = $page->footerTemplate; - $renderedFooter = TemplateService::replacePlaceholders( - $footerTemplate->html_content, - $mergedFooterData, - $page - ); + // Eğer sayfa için footer seçilmemişse, en son aktif footer template'i kullan + if (!$footerTemplate) { + $defaultFooterId = $settings->default_footer ?? null; + if ($defaultFooterId) { + $footerTemplate = FooterTemplate::find($defaultFooterId); + } + } + + if ($footerTemplate) { + // Merge template defaults with page data (page data overrides defaults) + $templateDefaults = $footerTemplate->default_data ?? []; + $pageData = $page->footer_data ?? []; + $mergedFooterData = array_merge($templateDefaults, $pageData); + + $renderedFooter = TemplateService::replacePlaceholders( + $footerTemplate->html_content, + $mergedFooterData, + $page + ); + } } return view($view, [ diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 66f8c8b..f878c34 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -3,6 +3,10 @@ namespace App\Http\Controllers; use App\Models\Product; +use App\Models\Setting; +use App\Models\HeaderTemplate; +use App\Models\FooterTemplate; +use App\Services\TemplateService; use Illuminate\Http\Request; class ProductController extends Controller @@ -13,11 +17,61 @@ class ProductController extends Controller ->where('is_active', true) ->with('category') ->firstOrFail(); - - if ($product->view_template && view()->exists($product->view_template)) { - return view($product->view_template, compact('product')); + + // Get Settings + $settings = new \stdClass(); + $allSettings = Setting::where('is_active', true)->get(); + foreach ($allSettings as $setting) { + $settings->{$setting->key} = $setting->value; } - return view('front.products.show', compact('product')); + // --- Header Logic --- + $renderedHeader = null; + $defaultHeaderId = $settings->default_header ?? null; + + if ($defaultHeaderId) { + $headerTemplate = HeaderTemplate::find($defaultHeaderId); + if ($headerTemplate) { + $templateDefaults = $headerTemplate->default_data ?? []; + $productData = []; // Ürünlere özel header datası eklenebilir + $mergedHeaderData = array_merge($templateDefaults, $productData); + + $renderedHeader = TemplateService::replacePlaceholders( + $headerTemplate->html_content, + $mergedHeaderData, + $product // Model context + ); + } + } + + // --- Footer Logic --- + $renderedFooter = null; + $defaultFooterId = $settings->default_footer ?? null; + + if ($defaultFooterId) { + $footerTemplate = FooterTemplate::find($defaultFooterId); + if ($footerTemplate) { + $templateDefaults = $footerTemplate->default_data ?? []; + $productData = []; // Ürünlere özel footer datası eklenebilir + $mergedFooterData = array_merge($templateDefaults, $productData); + + $renderedFooter = TemplateService::replacePlaceholders( + $footerTemplate->html_content, + $mergedFooterData, + $product // Model context + ); + } + } + + $meta = [ + 'title' => $product->translate('title'), + 'description' => \Str::limit(strip_tags($product->translate('content')), 160), + ]; + + if ($product->view_template && view()->exists($product->view_template)) { + return view($product->view_template, compact('product', 'settings', 'renderedHeader', 'renderedFooter', 'meta')); + } + + return view('front.products.show', compact('product', 'settings', 'renderedHeader', 'renderedFooter', 'meta')); } } diff --git a/app/Models/Page.php b/app/Models/Page.php index 983657f..eec6984 100644 --- a/app/Models/Page.php +++ b/app/Models/Page.php @@ -34,8 +34,10 @@ class Page extends Model // Template System 'header_template_id', 'header_data', + 'custom_header_blade', 'footer_template_id', 'footer_data', + 'custom_footer_blade', 'sections_data', ]; diff --git a/config/livewire.php b/config/livewire.php index f52ed46..908b9e6 100644 --- a/config/livewire.php +++ b/config/livewire.php @@ -64,7 +64,7 @@ return [ */ 'temporary_file_upload' => [ - 'disk' => 'uploads', // Example: 'local', 's3' | Default: 'default' + 'disk' => 'public', // Example: 'local', 's3' | Default: 'default' 'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB) 'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp' 'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1' diff --git a/database/migrations/2026_01_01_065719_add_custom_header_footer_blade_to_pages_table.php b/database/migrations/2026_01_01_065719_add_custom_header_footer_blade_to_pages_table.php new file mode 100644 index 0000000..95c9d7e --- /dev/null +++ b/database/migrations/2026_01_01_065719_add_custom_header_footer_blade_to_pages_table.php @@ -0,0 +1,29 @@ +string('custom_header_blade')->nullable()->after('header_data'); + $table->string('custom_footer_blade')->nullable()->after('footer_data'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pages', function (Blueprint $table) { + $table->dropColumn(['custom_header_blade', 'custom_footer_blade']); + }); + } +}; diff --git a/resources/views/components/custom/menu.blade.php b/resources/views/components/custom/menu.blade.php index 17e213d..42c6bad 100644 --- a/resources/views/components/custom/menu.blade.php +++ b/resources/views/components/custom/menu.blade.php @@ -22,105 +22,7 @@ $menuItems = \App\Models\Page::with(['children' => function ($query) { @if($menuItems->isNotEmpty())
@endif diff --git a/resources/views/components/front/footer.blade.php b/resources/views/components/front/footer.blade.php new file mode 100644 index 0000000..16941cd --- /dev/null +++ b/resources/views/components/front/footer.blade.php @@ -0,0 +1,79 @@ + diff --git a/resources/views/components/front/header.blade.php b/resources/views/components/front/header.blade.php new file mode 100644 index 0000000..76a85b0 --- /dev/null +++ b/resources/views/components/front/header.blade.php @@ -0,0 +1,93 @@ +@php +// Get menu items from Pages with nested children +$menuItems = \App\Models\Page::with(['children' => function ($query) { + $query->where('status', 'published') + ->where('show_in_menu', true) + ->orderBy('sort_order', 'asc') + ->orderBy('title', 'asc'); + }, 'children.children' => function ($query) { + $query->where('status', 'published') + ->where('show_in_menu', true) + ->orderBy('sort_order', 'asc') + ->orderBy('title', 'asc'); + }]) + ->whereNull('parent_id') + ->where('status', 'published') + ->where('show_in_menu', true) + ->orderBy('sort_order', 'asc') + ->orderBy('title', 'asc') + ->get(); + +$midPoint = ceil($menuItems->count() / 2); +$leftMenuItems = $menuItems->slice(0, $midPoint); +$rightMenuItems = $menuItems->slice($midPoint); +@endphp +