set('useAsLogin', false); } public function wired() { $this->sanitizer = $this->wire('sanitizer'); $user = $this->wire()->user; $this->isLoggedIn = $user && $user->isLoggedin(); parent::wired(); } /** * Override get() method from WireData to support additional properties * * @param string $key * @return bool|int|mixed|null|string * */ public function get($key) { switch($key) { case 'isSuperuser': $value = $this->isSuperuser; break; case 'isEditor': $value = $this->isEditor; break; case 'isLoggedIn': $value = $this->isLoggedIn; break; case 'isModal': $value = $this->isModal; break; default: $value = parent::get($key); } return $value; } /** * Initialize and attach hooks * * Note: descending classes should call this after API ready * */ public function init() { $user = $this->wire('user'); if(!$this->isLoggedIn && $this->useAsLogin) $this->setCurrent(); parent::init(); // if this is not the current admin theme, exit now so no hooks are attached if(!$this->isCurrent()) return; $this->isSuperuser = $this->isLoggedIn && $user->isSuperuser(); $this->isEditor = $this->isLoggedIn && ($this->isSuperuser || $user->hasPermission('page-edit')); $this->includeInitFile(); $modal = $this->wire('input')->get('modal'); if($modal) $this->isModal = $modal == 'inline' ? 'inline' : true; // test notices when requested if($this->wire('input')->get('test_notices') && $this->isLoggedIn) $this->testNotices(); } /** * Include the admin theme init file * */ public function includeInitFile() { $config = $this->wire('config'); $initFile = $this->path() . 'init.php'; if(file_exists($initFile)) { if(strpos($initFile, $config->paths->site) === 0) { // admin themes in /site/modules/ may be compiled $initFile = $this->wire('files')->compile($initFile); } /** @noinspection PhpIncludeInspection */ include_once($initFile); } } /** * Perform a translation, based on text from shared admin file: /wire/templates-admin/default.php * * @param string $text * @return string * */ public function _($text) { static $translate = null; if(is_null($translate)) $translate = $this->wire('languages') !== null; if($translate === false) return $text; $value = __($text, $this->wire('config')->paths->root . 'wire/templates-admin/default.php'); if($value === $text) $value = parent::_($text); return $value; } /** * Get the current page headline * * @return string * */ public function getHeadline() { $headline = $this->wire('processHeadline'); if(!$headline) $headline = $this->wire('page')->get('title|name'); if($headline !== 'en' && $this->wire('languages')) $headline = $this->_($headline); return $this->sanitizer->entities1($headline); } /** * Get navigation title for the given page, return blank if page should not be shown * * @param Page $p * @return string * */ public function getPageTitle(Page $p) { if($p->name == 'add' && $p->parent->name == 'page') { $title = $this->getAddNewLabel(); } else { $title = $this->_($p->title); } $title = $this->sanitizer->entities1($title); return $title; } /** * Get icon used by the given page * * @param Page $p * @return mixed|null|string * */ public function getPageIcon(Page $p) { $icon = ''; if($p->template == 'admin') { $info = $this->wire('modules')->getModuleInfo($p->process); if(!empty($info['icon'])) $icon = $info['icon']; } // allow for option of an admin field overriding the module icon $pageIcon = $p->get('page_icon'); if($pageIcon) $icon = $pageIcon; if(!$icon) switch($p->id) { case 22: $icon = 'gears'; break; // Setup case 21: $icon = 'plug'; break; // Modules case 28: $icon = 'key'; break; // Access } if(!$icon && $p->parent->id != $this->wire('config')->adminRootPageID) { $icon = 'file-o ui-priority-secondary'; } return $icon; } /** * Get “Add New” button actions * * - Returns array of arrays, each with 'url', 'label' and 'icon' properties. * - Returns empty array if Add New button should not be displayed. * * @return array * */ public function getAddNewActions() { $page = $this->wire('page'); $process = $this->wire('process'); $input = $this->wire('input'); if(!$this->isEditor) return array(); if($page->name != 'page' || $this->wire('input')->urlSegment1) return array(); if($input->urlSegment1 || $input->get('modal')) return array(); if(strpos($process, 'ProcessPageList') !== 0) return array(); /** @var ProcessPageAdd $module */ $module = $this->wire('modules')->getModule('ProcessPageAdd', array('noInit' => true)); $data = $module->executeNavJSON(array('getArray' => true)); $actions = array(); foreach($data['list'] as $item) { $item['url'] = $data['url'] . $item['url']; $actions[] = $item; } return $actions; } /** * Get the translated “Add New” label that’s used in a couple spots * * @return string * */ public function getAddNewLabel() { return $this->_('Add New'); } /** * Get the classes that will be used in the
tag * * @return string * */ public function getBodyClass() { $page = $this->wire('page'); $process = $this->wire('process'); $classes = array( "id-{$page->id}", "template-{$page->template->name}", "pw-init", parent::getBodyClass(), ); if($this->isModal) $classes[] = 'modal'; if($this->isModal === 'inline') $classes[] = 'modal-inline'; if($this->wire('input')->urlSegment1) $classes[] = 'hasUrlSegments'; if($process) $classes[] = $process->className(); if(!$this->isLoggedIn) $classes[] = 'pw-guest'; return implode(' ', $classes); } /** * Get Javascript that must be present in the document * * @return string * */ public function getHeadJS() { $config = $this->wire()->config; return "var ProcessWire = { config: " . wireEncodeJSON($config->js(), true, $config->debug) . " }; " . "var config = ProcessWire.config;\n"; // legacy support } /** * Allow the given Page to appear in admin theme navigation? * * @param Page $p Page to test * @param PageArray|array $children Children of page, if applicable (optional) * @param string|null $permission Specify required permission (optional) * @return bool * */ public function allowPageInNav(Page $p, $children = array(), $permission = null) { if($this->isSuperuser) return true; $pageViewable = $p->viewable(); if(!$pageViewable) return false; $allow = false; $numChildren = count($children); if($p->process == 'ProcessPageAdd') { // ProcessPageAdd: avoid showing this menu item if there are no predefined family settings to use $numAddable = $this->wire('session')->getFor('ProcessPageAdd', 'numAddable'); if($numAddable === null) { /** @var ProcessPageAdd $processPageAdd */ $processPageAdd = $this->wire('modules')->getModule('ProcessPageAdd', array('noInit' => true)); if($processPageAdd) { $addData = $processPageAdd->executeNavJSON(array('getArray' => true)); $numAddable = $addData['list']; $this->wire('session')->setFor('ProcessPageAdd', 'numAddable', $numAddable); } } // no addable options, so do not show the "Add New" item if(!$numAddable) return false; } else if(empty($permission)) { // no permission specified if(!$p->process) { // no process module present, so we delegate to just the page viewable state if no children to check if($pageViewable && !$numChildren) return true; } else if($p->process == 'ProcessList') { // page just serves as a list for children } else { // determine permission from Process module, if present $moduleInfo = $this->wire('modules')->getModuleInfo($p->process); if(!empty($moduleInfo['permission'])) $permission = $moduleInfo['permission']; } } if($permission) { // specific permission required to determine view access $allow = $this->wire('user')->hasPermission($permission); } else if($pageViewable && $p->parent_id == $this->wire('config')->adminRootPageID) { // primary nav page requires that at least one child is viewable foreach($children as $child) { if($this->allowPageInNav($child)) { $allow = true; break; } } } return $allow; } /** * Return nav array of primary navigation * * @return array * */ public function ___getPrimaryNavArray() { $items = array(); $config = $this->wire('config'); $admin = $this->wire('pages')->get($config->adminRootPageID); foreach($admin->children("check_access=0") as $p) { $item = $this->pageToNavArray($p); if($item) $items[] = $item; } return $items; } /** * Get navigation array from a Process module * * @param array|Module|string $module Module info array or Module object or string * @param Page $p Page upon which the Process module is contained * @return array * */ public function moduleToNavArray($module, Page $p) { $config = $this->wire('config'); $modules = $this->wire('modules'); $textdomain = str_replace($config->paths->root, '/', $modules->getModuleFile($p->process)); $user = $this->wire('user'); $navArray = array(); if(is_array($module)) { $moduleInfo = $module; } else { $moduleInfo = $modules->getModuleInfo($module); } foreach($moduleInfo['nav'] as $navItem) { $permission = empty($navItem['permission']) ? '' : $navItem['permission']; if($permission && !$user->hasPermission($permission)) continue; $navArray[] = array( 'id' => 0, 'parent_id' => $p->id, 'title' => $this->sanitizer->entities1(__($navItem['label'], $textdomain)), // translate from context of Process module 'name' => '', 'url' => $p->url . $navItem['url'], 'icon' => empty($navItem['icon']) ? '' : $navItem['icon'], 'children' => array(), 'navJSON' => empty($navItem['navJSON']) ? '' : $p->url . $navItem['navJSON'], ); } return $navArray; } /** * Get a navigation array the given Page, or null if page not allowed in nav * * @param Page $p * @return array|null * */ public function pageToNavArray(Page $p) { $children = $p->numChildren ? $p->children("check_access=0") : array(); if(!$this->allowPageInNav($p, $children)) return null; $navArray = array( 'id' => $p->id, 'parent_id' => $p->parent_id, 'url' => $p->url, 'name' => $p->name, 'title' => $this->getPageTitle($p), 'icon' => $this->getPageIcon($p), 'children' => array(), 'navJSON' => '', ); if(!count($children)) { // no children available if($p->template == 'admin' && $p->process) { // see if process module defines its own navigation $moduleInfo = $this->wire('modules')->getModuleInfo($p->process); if(!empty($moduleInfo['nav'])) { $navArray['children'] = $this->moduleToNavArray($moduleInfo, $p); } } else { // The /page/ and /page/list/ are the same process, so just keep them on /page/ instead. if(strpos($navArray['url'], '/page/list/') !== false) { $navArray['url'] = str_replace('/page/list/', '/page/', $navArray['url']); } } return $navArray; } // if we reach this point, then we have a PageArray of children $modules = $this->wire('modules'); foreach($children as $c) { if(!$c->process) continue; $moduleInfo = $modules->getModuleInfo($c->process); $permission = empty($moduleInfo['permission']) ? '' : $moduleInfo['permission']; if(!$this->allowPageInNav($c, array(), $permission)) continue; $childItem = array( 'id' => $c->id, 'parent_id' => $c->parent_id, 'title' => $this->getPageTitle($c), 'name' => $c->name, 'url' => $c->url, 'icon' => $this->getPageIcon($c), 'children' => array(), 'navJSON' => empty($moduleInfo['useNavJSON']) ? '' : $c->url . 'navJSON/', ); if(!empty($moduleInfo['nav'])) { $childItem['children'] = $this->moduleToNavArray($moduleInfo, $c); } $navArray['children'][] = $childItem; } // foreach return $navArray; } /** * Get navigation items for the “user” menu * * This is hookable so that something else could add stuff to it. * See the method body for details on format used. * * @return array * */ public function ___getUserNavArray() { $urls = $this->wire('urls'); $navArray = array(); $navArray[] = array( 'url' => $urls->root, 'title' => $this->_('View site'), 'target' => '_top', 'icon' => 'eye', ); if($this->wire('user')->hasPermission('profile-edit')) $navArray[] = array( 'url' => $urls->admin . 'profile/', 'title' => $this->_('Profile'), 'icon' => 'user', 'permission' => 'profile-edit', ); $navArray[] = array( 'url' => $urls->admin . 'login/logout/', 'title' => $this->_('Logout'), 'target' => '_top', 'icon' => 'power-off', ); return $navArray; } /** * Get the browser