/** * @param Page $page * @param int $level */ public function listPages($page, $level) { $indent = 4; $title = $page->title . ' { ' . $page->id . ', ' . $page->template . ' }'; switch ($this->indent) { case 0: $out = '|-- ' . $title; break; default: $i = $this->indent - $indent / 2; $j = $indent / 2 + 1; $out = '|' . str_pad(' ' . $title, strlen($title) + $j, '-', STR_PAD_LEFT); $out = '|' . str_pad($out, strlen($out) + $i, ' ', STR_PAD_LEFT); } $this->output->writeln($out); if ($page->numChildren) { $this->indent = $this->indent + $indent; foreach ($page->children($this->select) as $child) { if ($level === 0 || $level != 0 && $level >= $this->indent / $indent) { $this->listPages($child, $level); } } $this->indent = $this->indent - $indent; } }
/** * Return number of children, optionally with conditions * * Use this over $page->numChildren property when you want to specify a selector or when you want the result to * include only visible children. See the options for the $selector argument. * * @param Page $page * @param bool|string $selector * When not specified, result includes all children without conditions, same as $page->numChildren property. * When a string, a selector string is assumed and quantity will be counted based on selector. * When boolean true, number includes only visible children (excludes unpublished, hidden, no-access, etc.) * When boolean false, number includes all children without conditions, including unpublished, hidden, no-access, etc. * @return int Number of children * */ public function numChildren(Page $page, $selector = null) { if (is_bool($selector)) { // onlyVisible takes the place of selector $onlyVisible = $selector; if (!$onlyVisible) { return $page->get('numChildren'); } return $page->children('limit=2')->getTotal(); } else { if (empty($selector) || !is_string($selector)) { return $page->get('numChildren'); } else { return wire('pages')->count("parent_id={$page->id}, {$selector}"); } } }
/** * Render a single top navigation item for the given page * * This function designed primarily to be called by the renderTopNavItems() function. * * @param Page $p * @param int $level Recursion level (default=0) * @return string * */ public function renderTopNavItem(Page $p, $level = 0) { $isSuperuser = $this->wire('user')->isSuperuser(); $showItem = $isSuperuser; $children = $p->numChildren && !$level && $p->name != 'page' ? $p->children("check_access=0") : array(); $adminURL = $this->wire('config')->urls->admin; $out = ''; if (!$showItem) { $checkPages = count($children) ? $children : array($p); foreach ($checkPages as $child) { if ($child->viewable()) { $showItem = true; break; } } } if (!$showItem) { return ''; } $class = strpos(wire('page')->path, $p->path) === 0 ? 'on' : ''; $title = strip_tags((string) $p->get('title|name')); $title = $this->_($title); // translate from context of default.php $out .= "<li>"; if (!$level && count($children)) { $class = trim("{$class} dropdown-toggle"); $out .= "<a href='{$p->url}' id='topnav-page-{$p}' data-from='topnav-page-{$p->parent}' class='{$class}'>{$title}</a>"; $my = 'left-1 top'; if ($p->name == 'access') { $my = 'left top'; } $out .= "<ul class='dropdown-menu topnav' data-my='{$my}' data-at='left bottom'>"; foreach ($children as $c) { if ($isSuperuser && ($c->id == 11 || $c->id == 16)) { // has ajax items $addLabel = $this->_('Add New'); $out .= "<li><a class='has-ajax-items' data-from='topnav-page-{$p}' href='{$c->url}'>" . $this->_($c->title) . "</a><ul>" . "<li class='add'><a href='{$c->url}add'><i class='fa fa-plus-circle'></i> {$addLabel}</a></li>" . "</ul></li>"; } else { $out .= $this->renderTopNavItem($c, $level + 1); } } $out .= "</ul>"; } else { $class = $class ? " class='{$class}'" : ''; $out .= "<a href='{$p->url}'{$class}>{$title}</a>"; } $out .= "</li>"; return $out; }
/** * Render a side navigation items * * This function designed primarily to be called by the renderSideNavItems() function. * * @param Page $p * @return string * */ public function renderSideNavItem(Page $p) { $isSuperuser = $this->wire('user')->isSuperuser(); $sanitizer = $this->wire('sanitizer'); $modules = $this->wire('modules'); $showItem = $isSuperuser; $children = $p->numChildren() ? $p->children("check_access=0") : array(); $out = ''; $iconName = $p->name; $icon = $this->wire('adminTheme')->{$iconName}; if (!$icon) { $icon = 'fa-file-text-o'; } $numViewable = 0; if (!$showItem) { $checkPages = count($children) ? $children : array($p); foreach ($checkPages as $child) { if ($child->viewable()) { $showItem = true; $numViewable++; if ($numViewable > 1) { break; } // we don't need to know about any more } } } // don't bother with a drop-down here if only 1 child if ($p->name == 'page' && !$isSuperuser && $numViewable < 2) { $children = array(); } if (!$showItem) { return ''; } if ($p->process) { $moduleInfo = $modules->getModuleInfo($p->process); $textdomain = str_replace($this->wire('config')->paths->root, '/', $this->wire('modules')->getModuleFile($p->process)); } else { $moduleInfo = array(); $textdomain = ''; } if (!count($children) && !empty($moduleInfo['nav'])) { $children = $moduleInfo['nav']; } $class = strpos($this->wire('page')->path, $p->path) === 0 ? 'current' : ''; // current class $class .= count($children) > 0 ? " parent" : ''; // parent class $title = $sanitizer->entities1((string) $this->_($p->get('title|name'))); $currentPagePath = $this->wire('page')->url; // use URL to support sub directory installs $out .= "<li>"; if (count($children)) { $out .= "<a href='{$p->url}' class='{$class} {$p->name} '><i class='fa {$icon}'></i> {$title}</a>"; $out .= "<ul>"; foreach ($children as $c) { $navJSON = ''; if (is_array($c)) { // $c is moduleInfo nav array $moduleInfo = array(); if (isset($c['permission']) && !$this->wire('user')->hasPermission($c['permission'])) { continue; } $segments = $this->input->urlSegments ? implode("/", $this->input->urlSegments) . '/' : ''; $class = $currentPagePath . $segments == $p->path . $c['url'] ? 'current' : ''; $title = $sanitizer->entities1(__($c['label'], $textdomain)); $url = $p->url . $c['url']; if (isset($c['navJSON'])) { $navJSON = $c['navJSON']; // url part $moduleInfo['useNavJSON'] = true; } $c = $p; // substitute } else { // $c is a Page object $list = array(wire('config')->urls->admin . "page/", wire('config')->urls->admin . "page/edit/"); in_array($currentPagePath, $list) ? $currentPagePath = wire('config')->urls->admin . "page/list/" : ''; $class = strpos($currentPagePath, $c->url) === 0 ? 'current' : ''; // child current class $name = $c->name; if (!$c->viewable()) { continue; } $moduleInfo = $c->process ? $modules->getModuleInfo($c->process) : array(); $title = $this->getPageTitle($c); if (!strlen($title)) { continue; } $url = $c->url; // The /page/ and /page/list/ are the same process, so just keep them on /page/ instead. if (strpos($url, '/page/list/') !== false) { $url = str_replace('/page/list/', '/page/', $url); } } $quicklinks = ''; if (!empty($moduleInfo['useNavJSON'])) { // NOTE: 'useNavJSON' comes before 'nav' for AdminThemeReno only, since it does not support navJSON beyond one level // meaning this bypasses 'nav' if the module happens to also provide navJSON (see ProcessRecentPages example) if (empty($navJSON)) { $navJSON = "navJSON/"; } $quicklinks = $this->renderQuicklinks($c, array(), $title, $navJSON); } else { if (!empty($moduleInfo['nav'])) { $quicklinks = $this->renderQuicklinks($c, $moduleInfo['nav'], $title); } } $icon = isset($moduleInfo['icon']) ? $moduleInfo['icon'] : ''; $toggle = $quicklinks ? "<i class='quicklink-open fa fa-bolt'></i>" : ""; if ($class == 'current' && $icon) { $title = "<i class='fa fa-fw fa-{$icon} current-icon'></i>{$title}"; } if ($quicklinks) { $class .= " has-quicklinks"; } $out .= "<li><a href='{$url}' class='{$class}' data-icon='{$icon}'><span>{$title}</span>{$toggle}</a>" . $quicklinks; $out .= "</li>"; } $out .= "</ul>"; } else { $class = $class ? " class='{$class} {$p->name}'" : "class='{$p->name}'"; $out .= "<a href='{$p->url}' {$class}><i class='fa {$icon}'></i> <span>{$title}</span></a>"; } $out .= "</li>"; return $out; }
/** * Render a single top navigation item for the given page * * This function designed primarily to be called by the renderTopNavItems() function. * * @param Page $p * @param int $level Recursion level (default=0) * @return string * */ public function renderTopNavItem(Page $p, $level = 0) { $isSuperuser = $this->wire('user')->isSuperuser(); $showItem = $isSuperuser; $children = $p->numChildren && !$level ? $p->children("check_access=0") : array(); $numChildren = count($children); $out = ''; if (!$showItem) { $checkPages = $numChildren ? $children : array($p); foreach ($checkPages as $child) { if ($child->viewable()) { $showItem = true; break; } } } if (!$showItem) { return ''; } $class = strpos($this->wire('page')->path, $p->path) === 0 ? 'on' : ''; $title = strip_tags((string) $p->title); if (!strlen($title)) { $title = $p->name; } $title = $this->_($title); // translate from context of default.php $out .= "<li>"; if (!$numChildren && $p->template == 'admin' && $p->process) { $moduleInfo = $this->wire('modules')->getModuleInfo($p->process); if (!empty($moduleInfo['nav'])) { $children = $moduleInfo['nav']; } } if (!$level && count($children)) { $class = trim("{$class} dropdown-toggle"); $out .= "<a href='{$p->url}' id='topnav-page-{$p}' data-from='topnav-page-{$p->parent}' class='{$class}'>{$title}</a>"; $my = 'left-1 top'; if (in_array($p->name, array('access', 'page', 'module'))) { $my = 'left top'; } $out .= "<ul class='dropdown-menu topnav' data-my='{$my}' data-at='left bottom'>"; if ($children instanceof PageArray) { foreach ($children as $c) { if (!$c->process) { continue; } $moduleInfo = $this->wire('modules')->getModuleInfo($c->process); if ($isSuperuser) { $hasPermission = true; } else { if (!empty($moduleInfo['permissionMethod'])) { $hasPermission = $c->viewable(); } else { if (!empty($moduleInfo['permission'])) { $hasPermission = $this->wire('user')->hasPermission($moduleInfo['permission']); } else { $hasPermission = false; } } } if (!$hasPermission) { continue; } if (!empty($moduleInfo['nav'])) { // process defines its own subnav $icon = $this->getPageIcon($c); $title = $this->_($c->title); if (!$title) { $title = $c->name; } $out .= "<li><a class='has-items' data-from='topnav-page-{$p}' href='{$c->url}'>{$icon}{$title}</a>" . "<ul>" . $this->renderTopNavItemArray($c, $moduleInfo['nav']) . "</ul></li>"; } else { if (!empty($moduleInfo['useNavJSON'])) { // has ajax items $title = $this->getPageTitle($c); if (!strlen($title)) { continue; } $icon = $this->getPageIcon($c); $out .= "<li><a class='has-items has-ajax-items' data-from='topnav-page-{$p}' data-json='{$c->url}navJSON/' " . "href='{$c->url}'>{$icon}{$title}</a><ul></ul></li>"; } else { // regular nav item $out .= $this->renderTopNavItem($c, $level + 1); } } } } else { if (is_array($children) && count($children)) { $out .= $this->renderTopNavItemArray($p, $children); } } $out .= "</ul>"; } else { $class = $class ? " class='{$class}'" : ''; $url = $p->url; $icon = $level > 0 ? $this->getPageIcon($p) : ''; // The /page/ and /page/list/ are the same process, so just keep them on /page/ instead. if (strpos($url, '/page/list/') !== false) { $url = str_replace('/page/list/', '/page/', $url); } $out .= "<a href='{$url}'{$class}>{$icon}{$title}</a>"; } $out .= "</li>"; return $out; }
/** * Render a side navigation items * * This function designed primarily to be called by the renderSideNavItems() function. * * @param Page $p * @return string * */ public function renderSideNavItem(Page $p) { $isSuperuser = $this->wire('user')->isSuperuser(); $showItem = $isSuperuser; $children = $p->numChildren ? $p->children("check_access=0") : array(); $adminURL = $this->wire('config')->urls->admin; $quicklinks = array('11', '16'); // array of page ids that use quicklinks. $out = ''; $iconName = $p->name; $this->adminTheme()->{$iconName} ? $icon = $this->adminTheme()->{$iconName} : ($icon = 'fa-file-text-o'); // don't bother with a drop-down here if only 1 child if ($p->name == 'page' && !$isSuperuser) { $children = array(); } if (!$showItem) { $checkPages = count($children) ? $children : array($p); foreach ($checkPages as $child) { if ($child->viewable()) { $showItem = true; break; } } } if (!$showItem) { return ''; } $class = strpos(wire('page')->path, $p->path) === 0 ? 'current' : ''; // current class $class .= count($children) > 0 ? " parent" : ''; // parent class $title = strip_tags((string) $p->get('title|name')); $title = $this->_($title); // translate from context of default.php $out .= "<li>"; if (count($children)) { $out .= "<a href='{$p->url}' class='{$class} {$p->name} '><i class='fa {$icon}'></i> {$title}</a>"; $out .= "<ul>"; foreach ($children as $c) { $showQuickLinks = false; $class = strpos(wire('page')->path, $c->path) === 0 ? 'current' : ''; // child current class if ($c->viewable()) { $isSuperuser && in_array($c->id, $quicklinks) ? $showQuickLinks = true : ''; $showQuickLinks ? $qlink = "<i class='quicklink-open fa fa-bolt'></i>" : ($qlink = ''); $url = $c->url; // The /page/ and /page/list/ are the same process, so just keep them on /page/ instead. if (strpos($url, '/page/list/') !== false) { $url = str_replace('/page/list/', '/page/', $url); } $out .= "<li><a href='{$url}' class='{$class}'>" . $this->_($c->title) . $qlink . "</a>"; if ($showQuickLinks) { $c->id == 11 ? $type = "templates" : ''; $c->id == 16 ? $type = "fields" : ''; $out .= $this->renderQuicklinks(wire($type)); // not thrilled with this solution. Explore options. } $out .= "</li>"; } } $out .= "</ul>"; } else { $class = $class ? " class='{$class} {$p->name}'" : "class='{$p->name}'"; $out .= "<a href='{$p->url}' {$class}><i class='fa {$icon}'></i> {$title}</a>"; } $out .= "</li>"; return $out; }
/** * Clone an entire page, it's assets and children and return it. * * @param Page $page Page that you want to clone * @param Page $parent New parent, if different (default=same parent) * @param bool $recursive Clone the children too? (default=true) * @return Page the newly cloned page or a NullPage() with id=0 if unsuccessful. * */ public function ___clone(Page $page, Page $parent = null, $recursive = true) { // if parent is not changing, we have to modify name now if (is_null($parent)) { $parent = $page->parent; $n = 1; $name = $page->name . '-' . $n; } else { $name = $page->name; $n = 0; } // make sure that we have a unique name while (count($parent->children("name={$name}"))) { $name = $page->name . '-' . ++$n; } // Ensure all data is loaded for the page foreach ($page->template->fieldgroup as $field) { $page->get($field->name); } // clone in memory $copy = clone $page; $copy->id = 0; $copy->setIsNew(true); $copy->name = $name; $copy->parent = $parent; // tell PW that all the data needs to be saved foreach ($copy->template->fieldgroup as $field) { $copy->trackChange($field->name); } $o = $copy->outputFormatting; $copy->setOutputFormatting(false); $this->save($copy); $copy->setOutputFormatting($o); // check to make sure the clone has worked so far if (!$copy->id || $copy->id == $page->id) { return new NullPage(); } // copy $page's files over to new page $copy->filesManager->init($copy); $page->filesManager->copyFiles($copy->filesManager->path()); // if there are children, then recurisvely clone them too if ($page->numChildren && $recursive) { foreach ($page->children("include=all") as $child) { $this->clone($child, $copy); } } $this->cloned($page, $copy); $this->debugLog('clone', "page={$page}, parent={$parent}", $copy); return $copy; }
/** * Render a single top navigation item for the given page * * This function designed primarily to be called by the renderTopNavItems() function. * * @param Page $p * @param int $level Recursion level (default=0) * @return string * */ public function renderTopNavItem(Page $p, $level = 0) { $isSuperuser = $this->wire('user')->isSuperuser(); $showItem = $isSuperuser; $children = $p->numChildren && !$level ? $p->children("check_access=0") : array(); $numChildren = count($children); $out = ''; if (!$showItem) { $checkPages = $numChildren ? $children : array($p); foreach ($checkPages as $child) { if ($child->viewable()) { $showItem = true; break; } } } if (!$showItem) { return ''; } if ($numChildren && $p->name == 'page') { // don't bother with a drop-down for "Pages" if user will only see 1 "tree" item, duplicating the tab if ($numChildren == 2 && !$isSuperuser && !$this->wire('user')->hasPermission('page-lister')) { $children = array(); } if ($numChildren == 1) { $children = array(); } } $class = strpos($this->wire('page')->path, $p->path) === 0 ? 'on' : ''; $title = strip_tags((string) $p->title); if (!strlen($title)) { $title = $p->name; } $title = $this->_($title); // translate from context of default.php $out .= "<li>"; if (!$level && count($children)) { $class = trim("{$class} dropdown-toggle"); $out .= "<a href='{$p->url}' id='topnav-page-{$p}' data-from='topnav-page-{$p->parent}' class='{$class}'>{$title}</a>"; $my = 'left-1 top'; if (in_array($p->name, array('access', 'page'))) { $my = 'left top'; } $out .= "<ul class='dropdown-menu topnav' data-my='{$my}' data-at='left bottom'>"; foreach ($children as $c) { if ($isSuperuser && ($c->id == 11 || $c->id == 16)) { // has ajax items $icon = $this->getPageIcon($c); $addLabel = $this->_('Add New'); $out .= "<li><a class='has-ajax-items' data-from='topnav-page-{$p}' href='{$c->url}'>{$icon}" . $this->_($c->title) . "</a><ul>" . "<li class='add'><a href='{$c->url}add'><i class='fa fa-plus-circle'></i> {$addLabel}</a></li>" . "</ul></li>"; } else { $out .= $this->renderTopNavItem($c, $level + 1); } } $out .= "</ul>"; } else { $class = $class ? " class='{$class}'" : ''; $url = $p->url; $icon = $level > 0 ? $this->getPageIcon($p) : ''; // The /page/ and /page/list/ are the same process, so just keep them on /page/ instead. if (strpos($url, '/page/list/') !== false) { $url = str_replace('/page/list/', '/page/', $url); } $out .= "<a href='{$url}'{$class}>{$icon}{$title}</a>"; } $out .= "</li>"; return $out; }