Add Menu Template functionality: Created MenuTemplate resource with CRUD pages, schemas, and table configuration. Implemented localization for menu template fields and integrated menu rendering capabilities. Enhanced TemplatePreviewController to support menu templates and updated dynamic template documentation accordingly.

This commit is contained in:
Ümit Tunç
2025-11-03 15:43:47 -03:00
parent 9629652d0a
commit 4a2a66c55c
18 changed files with 768 additions and 1 deletions
+121
View File
@@ -0,0 +1,121 @@
<?php
namespace App\Services;
use App\Models\Page;
use Illuminate\Support\Facades\Cache;
class MenuService
{
/**
* Render menu structure as HTML
*
* @param array|null $menuTemplate Optional menu template data
* @return string Rendered menu HTML
*/
public static function render(?array $menuTemplate = null): string
{
// Get menu items from Pages
$menuItems = Cache::remember('menu_items', 3600, function () {
return Page::with(['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();
});
// If menu template is provided, use it to wrap the menu
if ($menuTemplate && !empty($menuTemplate['html_content'])) {
$html = $menuTemplate['html_content'];
// Replace {menu} placeholder with rendered menu structure
$renderedMenu = self::buildMenuStructure($menuItems);
$html = str_replace('{menu}', $renderedMenu, $html);
return $html;
}
// Otherwise, return default menu structure
return self::buildMenuStructure($menuItems);
}
/**
* Build menu structure HTML from menu items
*
* @param \Illuminate\Support\Collection $menuItems
* @return string HTML structure
*/
protected static function buildMenuStructure($menuItems): string
{
if ($menuItems->isEmpty()) {
return '';
}
$html = '<ul class="menu">';
foreach ($menuItems as $item) {
$hasChildren = $item->children->isNotEmpty();
$html .= '<li class="menu-item">';
$html .= '<a href="' . route('page.show', $item->slug) . '" class="menu-link">';
$html .= e($item->title);
$html .= '</a>';
if ($hasChildren) {
$html .= self::buildSubmenu($item->children);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
/**
* Build submenu structure recursively
*
* @param \Illuminate\Support\Collection $children
* @return string Submenu HTML
*/
protected static function buildSubmenu($children): string
{
$html = '<ul class="submenu">';
foreach ($children as $child) {
$hasChildren = $child->children->isNotEmpty();
$html .= '<li class="submenu-item">';
$html .= '<a href="' . route('page.show', $child->slug) . '" class="submenu-link">';
$html .= e($child->title);
$html .= '</a>';
if ($hasChildren) {
$html .= self::buildSubmenu($child->children);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
/**
* Clear menu cache
*/
public static function clearCache(): void
{
Cache::forget('menu_items');
}
}
+1
View File
@@ -214,6 +214,7 @@ class TemplatePreviewService
$bodyContent = match($type) {
'header' => $content,
'footer' => $content,
'menu' => $content,
'section' => '<div class="container py-8">' . $content . '</div>',
default => $content,
};
+7
View File
@@ -267,9 +267,16 @@ class TemplateService
/**
* Replace placeholders in HTML with actual data
* Supports both {text.title} and {{text.title}} formats
* Also supports {menu} placeholder for menu rendering
*/
public static function replacePlaceholders(string $html, array $data): string
{
// Handle special {menu} placeholder first
if (str_contains($html, '{menu}')) {
$renderedMenu = \App\Services\MenuService::render();
$html = str_replace('{menu}', $renderedMenu, $html);
}
// First, parse all placeholders in the format {type.field_name}
preg_match_all('/\{([a-z]+\.[a-z_]+)\}/i', $html, $matches);
$placeholders = array_unique($matches[1] ?? []);