From 4bd14f41dcb344fb6b4cbb6010eae8d5f8e4e43f Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 28 Jan 2021 14:25:13 -0700 Subject: [PATCH] add model methods for dynamic menu listing for sitemap --- Plugin.php | 30 ++++++++ models/Category.php | 167 +++++++++++++++++++++++++++++++++++++++++ models/Product.php | 178 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 375 insertions(+) diff --git a/Plugin.php b/Plugin.php index 544010c..d02c19e 100644 --- a/Plugin.php +++ b/Plugin.php @@ -2,6 +2,7 @@ use Backend; use System\Classes\PluginBase; +use Event; /** * Catalog Plugin Information File @@ -40,7 +41,36 @@ public function register() */ public function boot() { + // Register menu items + Event::listen('pages.menuitem.listTypes', function () { + return [ + 'catalog-category' => 'Catalog Category', + 'all-catalog-categories' => 'All Catalog Categories', + 'catalog-product' => 'Catalog Product', + 'all-catalog-products' => 'All Catalog Products', + 'category-catalog-products' => 'Catagorized Catalog Products' + ]; + }); + Event::listen('pages.menuitem.getTypeInfo', function ($type) { + if ($type == 'catalog-category' || $type == 'all-catalog-categories') { + return \Lbaig\Catalog\Models\Category::getMenuTypeInfo($type); + } + elseif ($type == 'catalog-product' || $type == 'all-catalog-products' || + $type == 'category-catalog-products') { + return \LBaig\Catalog\Models\Product::getMenuTypeInfo($type); + } + }); + + Event::listen('pages.menuitem.resolveItem', function ($type, $item, $url, $theme) { + if ($type == 'catalog-category' || $type == 'all-catalog-categories') { + return \Lbaig\Catalog\Models\Category::resolveMenuItem($item, $url, $theme); + } + elseif ($type == 'catalog-product' || $type == 'all-catalog-products' || + $type == 'category-catalog-products') { + return \LBaig\Catalog\Models\Product::resolveMenuItem($item, $url, $theme); + } + }); } /** diff --git a/models/Category.php b/models/Category.php index caf6fcf..7b20e15 100644 --- a/models/Category.php +++ b/models/Category.php @@ -1,6 +1,8 @@ self::listSubCategoryOptions(), + 'nesting' => true, + 'dynamicItems' => true + ]; + } + + if ($type == 'all-catalog-categories') { + $result = [ + 'dynamicItems' => true + ]; + } + + if ($result) { + $theme = Theme::getActiveTheme(); + $pages = CmsPage::listInTheme($theme, true); + $cmsPages = []; + foreach ($pages as $page) { + if (!$page->hasComponent('CategoryItem')) { + continue; + } + + $properties = $page->getComponentProperties('CategoryItem'); + if (!isset($properties['slug']) || !preg_match('/{{\s*:/', $properties['slug'])) { + continue; + } + + $cmsPages[] = $page; + } + + $result['cmsPages'] = $cmsPages; + } + + return $result; + } + + protected static function listSubCategoryOptions() + { + $category = self::getNested(); + + $iterator = function($categories) use (&$iterator) { + $result = []; + + foreach ($categories as $category) { + if (!$category->children) { + $result[$category->id] = $category->name; + } + else { + $result[$category->id] = [ + 'title' => $category->name, + 'items' => $iterator($category->children) + ]; + } + } + + return $result; + }; + + return $iterator($category); + } + + public static function resolveMenuItem($item, $url, $theme) + { + $result = null; + + if ($item->type == 'catalog-catagory') { + if (!$item->reference || $item->cmsPage) { + return; + } + + $category = self::find($item->reference); + if (!$category) { + return; + } + + $pageUrl = self::getCategoryPageUrl($item->cmsPage, $category, $theme); + if (!$pageUrl) { + return; + } + + $pageUrl = Url::to($pageUrl); + + $result = []; + $result['url'] = $pageUrl; + $result['isActive'] = $pageUrl == $url; + $result['mtime'] = $category->updated_at; + + if ($item->nesting) { + $categories = $category->getNested(); + $iterator = function($categories) use (&$iterator, &$item, &$theme, $url) { + $branch = []; + + foreach ($categories as $category) { + + $branchItem = []; + $branchItem['url'] = self::getCategoryPageUrl($item->cmsPage, $category, $theme); + $branchItem['isActive'] = $branchItem['url'] == $url; + $branchItem['title'] = $category->name; + $branchItem['mtime'] = $category->updated_at; + + if ($category->children) { + $branchItem['items'] = $iterator($category->children); + } + + $branch[] = $branchItem; + } + + return $branch; + }; + + $result['items'] = $iterator($categories); + } + } + elseif ($item->type == 'all-catalog-categories') { + $result = [ + 'items' => [] + ]; + + $categories = self::orderBy('name')->get(); + foreach ($categories as $category) { + $categoryItem = [ + 'title' => $category->name, + 'url' => self::getCategoryPageUrl($item->cmsPage, $category, $theme), + 'mtime' => $category->updated_at + ]; + + $categoryItem['isActive'] = $categoryItem['url'] == $url; + + $result['items'][] = $categoryItem; + } + } + + return $result; + } + + protected static function getCategoryPageUrl($pageCode, $category, $theme) + { + $page = CmsPage::loadCached($theme, $pageCode); + if (!$page) { + return; + } + + $properties = $page->getComponentProperties('CategoryItem'); + if (!isset($properties['slug'])) { + return; + } + + /* + * Extract the routing parameter name from the category filter + * eg: {{ :someRouteParam }} + */ + if (!preg_match('/^\{\{([^\}]+)\}\}$/', $properties['slug'], $matches)) { + return; + } + + $paramName = substr(trim($matches[1]), 1); + $url = CmsPage::url($page->getBaseFileName(), [$paramName => $category->slug]); + + return $url; + } } diff --git a/models/Product.php b/models/Product.php index c6476c5..7585d26 100644 --- a/models/Product.php +++ b/models/Product.php @@ -1,6 +1,9 @@ load('category'); return $this->name . ' - ' . $this->category->name . " ({$this->id})"; } + + public static function getMenuTypeInfo($type) + { + $result = []; + + if ($type == 'catalog-product') { + $references = []; + + $products = self::orderBy('name')->get(); + foreach ($products as $product) { + $references[$product->id] = $product->name; + } + + $result = [ + 'references' => $references, + 'nesting' => false, + 'dynamicItems' => false + ]; + } + + if ($type == 'all-catalog-products') { + $result = [ + 'dynamicItems' => true + ]; + } + + if ($type == 'category-catalog-products') { + $references = []; + + $categories = Category::orderBy('name')->get(); + foreach ($categories as $category) { + $references[$category->id] = $category->name; + } + + $result = [ + 'references' => $references, + 'dynamicItems' => true + ]; + } + + if ($result) { + $theme = Theme::getActiveTheme(); + $pages = CmsPage::listInTheme($theme, true); + $cmsPages = []; + foreach ($pages as $page) { + if (!$page->hasComponent('ProductItem')) { + continue; + } + + $properties = $page->getComponentProperties('ProductItem'); + if (!isset($properties['slug']) || !preg_match('/{{\s*:/', $properties['slug'])) { + continue; + } + + $cmsPages[] = $page; + } + + $result['cmsPages'] = $cmsPages; + } + + return $result; + } + + public static function resolveMenuItem($item, $url, $theme) + { + $result = null; + + if ($item->type == 'catalog-product') { + if (!$item->reference || !$item->cmsPage) { + return; + } + + $product = self::find($item->reference); + if (!$product) { + return; + } + + $pageUrl = self::getProductPageUrl($item->cmsPage, $product, $theme); + if (!$pageUrl) { + return; + } + + $pageUrl = Url::to($pageUrl); + + $result = []; + $result['url'] = $pageUrl; + $result['isActive'] = $pageUrl == $url; + $result['mtime'] = $product->updated_at; + } + elseif ($item->type == 'all-catalog-products') { + $result = [ + 'items' => [] + ]; + + $products = self::active() + ->orderBy('name') + ->get(); + + foreach ($products as $product) { + $postItem = [ + 'title' => $product->name, + 'url' => self::getProductPageUrl($item->cmsPage, $product, $theme), + 'mtime' => $product->updated_at + ]; + + $postItem['isActive'] = $postItem['url'] == $url; + + $result['items'][] = $postItem; + } + } + elseif ($item->type == 'category-blog-posts') { + if (!$item->reference || !$item->cmsPage) { + return; + } + + $category = Category::find($item->reference); + if (!$category) { + return; + } + + $result = [ + 'items' => [] + ]; + + $query = self::isPublished() + ->orderBy('name'); + + $categories = $category->getAllChildrenAndSelf()->lists('id'); + $query->whereHas('other_categories', function($q) use ($categories) { + $q->whereIn('id', $categories); + }); + + $products = $query->get(); + + foreach ($products as $product) { + $postItem = [ + 'title' => $product->name, + 'url' => self::getProductPageUrl($item->cmsPage, $product, $theme), + 'mtime' => $product->updated_at + ]; + + $postItem['isActive'] = $postItem['url'] == $url; + + $result['items'][] = $postItem; + } + } + + return $result; + } + + protected static function getProductPageUrl($pageCode, $product, $theme) + { + $page = CmsPage::loadCached($theme, $pageCode); + if (!$page) { + return; + } + + $properties = $page->getComponentProperties('ProductItem'); + if (!isset($properties['slug'])) { + return; + } + + /* + * Extract the routing parameter name from the category filter + * eg: {{ :someRouteParam }} + */ + if (!preg_match('/^\{\{([^\}]+)\}\}$/', $properties['slug'], $matches)) { + return; + } + + $paramName = substr(trim($matches[1]), 1); + $url = CmsPage::url($page->getBaseFileName(), [$paramName => $product->slug]); + + return $url; + } }