diff --git a/CHANGELOG.md b/CHANGELOG.md index b21218b..b3f6cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.0] - 2019-12-25 + +### Added +- Support for passing in a prepopulated PageArray of menu items via the menu_items option. + +### Fixed +- Fixed an issue where include option root_page wasn't being properly reset (since 0.7.0). + ## [0.7.0] - 2019-12-18 ### Added diff --git a/MarkupMenu.info.json b/MarkupMenu.info.json index f92ad85..8597168 100644 --- a/MarkupMenu.info.json +++ b/MarkupMenu.info.json @@ -1,7 +1,7 @@ { "title": "MarkupMenu", "summary": "MarkupMenu is a module for generating menu markup.", - "version": "0.7.0", + "version": "0.8.0", "author": "Teppo Koivula", "href": "https://github.com/teppokoivula/MarkupMenu", "requires": [ diff --git a/MarkupMenu.module.php b/MarkupMenu.module.php index f5addc4..329e569 100644 --- a/MarkupMenu.module.php +++ b/MarkupMenu.module.php @@ -8,7 +8,7 @@ * MarkupMenu is a module for generating menu markup. See README.md for more details. * Some ideas and code in this module are based on the Markup Simple Navigation module. * - * @version 0.7.0 + * @version 0.8.0 * @author Teppo Koivula * @license Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/ */ @@ -21,6 +21,7 @@ class MarkupMenu extends WireData implements Module { */ public static $defaultOptions = [ 'root_page' => null, + 'menu_items' => null, 'current_page' => null, 'templates' => [ 'nav' => '', @@ -71,7 +72,7 @@ public function render(array $options = []): string { ); // get the root page - $options['root_page'] = $this->getPage($options['root_page'], '/'); + $options['root_page'] = $this->getPage($options['root_page'], empty($options['menu_items']) ? '/' : null); // get current page $options['current_page'] = $this->getPage($options['current_page']); @@ -79,26 +80,33 @@ public function render(array $options = []): string { // load MarkupMenuData require_once __DIR__ . '/MarkupMenuData.php'; - // generate and return menu markup - $menu = $this->renderTree($options, $options['root_page']); + // generate menu markup + $menu = ''; + if (!empty($options['root_page'] || !empty($options['menu_items']))) { + $menu = $this->renderTree($options, $options['root_page'], $options['menu_items']); + } + return $menu; - } /** * Render tree of items using recursion * * @param array $options Options for rendering - * @param Page $root Root page for the menu + * @param Page|null $root Root page for the menu + * @param PageArray|null $items Menu items * @param int $level Current tree level (depth) * @return string Rendered menu markup */ - protected function renderTree(array $options = [], Page $root, int $level = 1): string { + protected function renderTree(array $options = [], Page $root = null, PageArray $items = null, int $level = 1): string { $out = ''; - // get items - $items = $this->getItems($options, $root, $level); + // get items and make sure that root page is only prepended once + if (empty($items)) { + $items = $this->getItems($options, $root, $level); + $options['include']['root_page'] = false; + } // iterate items and render markup for each separately foreach ($items as $item) { @@ -124,28 +132,26 @@ protected function renderTree(array $options = [], Page $root, int $level = 1): } return $out; - } /** * Get menu items for rendering * - * @param array $options Options array. - * @param Page $root Root page for the menu + * @param array $options Options array + * @param Page|null $root Root page for the menu * @param int $level Current tree level (depth) * @return PageArray Menu items */ - protected function ___getItems(array $options, Page $root, int $level): PageArray { + protected function ___getItems(array $options, Page $root = null, int $level): PageArray { // fetch items (children of the root page), optionally filtered by a selector string $items = new PageArray(); - if (!$options['include']['root_page'] || $options['flat_root']) { + if (!empty($root) && (!$options['include']['root_page'] || $options['flat_root'])) { $items->add($root->children($options['include']['selector'])); } - // optionally prepend the root page itself – but only once! - if ($options['include']['root_page']) { - $options['include']['root_page'] = false; + // optionally prepend the root page itself + if ($options['include']['root_page'] && !empty($root)) { $items->prepend($root); } @@ -162,11 +168,12 @@ protected function ___getItems(array $options, Page $root, int $level): PageArra * * @param array $options Options for rendering * @param Page $item Menu item being rendered + * @param Page|null $root Root page for the menu * @param bool $with_children Include markup for child pages? * @param int $level Current tree level (depth) * @return string Rendered menu item markup */ - protected function ___renderTreeItem(array $options = [], Page $item, Page $root, int $level = 1): string { + protected function ___renderTreeItem(array $options = [], Page $item, Page $root = null, int $level = 1): string { $out = ''; @@ -186,14 +193,14 @@ protected function ___renderTreeItem(array $options = [], Page $item, Page $root if ($item_is_current) $classes['current'] = $options['classes']['current']; // is this a parent page? - $item_is_parent = !$item_is_current && ($item->id !== $root->id || !$options['flat_root']) && $options['current_page'] && $options['current_page']->parents->has($item); + $item_is_parent = !$item_is_current && (!empty($root) && $item->id !== $root->id || !$options['flat_root']) && $options['current_page'] && $options['current_page']->parents->has($item); if ($item_is_parent) $classes['parent'] = $options['classes']['parent']; // have we reached the level limit? $level_limit_reached = $options['exclude']['level_greater_than'] && $level >= $options['exclude']['level_greater_than']; // does this page have children? - $has_children = ($item->id !== $root->id || !$options['flat_root']) && !$level_limit_reached && $item->hasChildren; + $has_children = (!empty($root) && $item->id !== $root->id || !$options['flat_root']) && !$level_limit_reached && $item->hasChildren; if ($has_children) $classes['has_children'] = $options['classes']['has_children']; // should we render the children for this item? @@ -222,14 +229,13 @@ protected function ___renderTreeItem(array $options = [], Page $item, Page $root // generate markup for menu item children if ($with_children) { - $item_markup .= $this->renderTree($options, $item, $level + 1); + $item_markup .= $this->renderTree($options, $item, null, $level + 1); } // generate markup for current list item $out .= $this->applyTemplate('list_item', $item_markup, $placeholders, $options, $item); return $out; - } /** @@ -254,7 +260,6 @@ protected function getPage($source = null, $default = null): ?Page { } return $page; - } /** @@ -301,7 +306,6 @@ protected function applyTemplate(string $template_name, string $content, array $ } return $out; - } /** @@ -337,7 +341,6 @@ protected function parseClassesString(array $placeholders, array $options, strin } return $out; - } } diff --git a/README.md b/README.md index ccf783f..210c6a9 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ echo $modules->get('MarkupMenu')->render([ ]); ``` -Note: if you omit root_page, site root page is used by default. If you omit current_page, the menu -will be rendered, but current (active) page won't be highlighted. +Note: if you omit root_page, site root page is used by default – unless you've specified the menu_items +option instead, in which case a root page is not necessary. If you omit current_page, the menu will be +rendered, but current (active) page can't be highlighted. ## Options @@ -30,9 +31,13 @@ via site config setting `$config->MarkupMenu`. ``` [ - // 'root_page' is the starting point for the menu. + // 'root_page' is the starting point for the menu. This is optional if you specify the 'menu_items' + // option instead, but leaving *both* empty will make MarkupMenu::render() return an empty string. 'root_page' => null, + // 'menu_items' is an optional, prepopulated PageArray of first level menu items. + 'menu_items' => null, + // 'current' page is the current or active menu page. 'current_page' => null,