cache = Cache::for('dashboard')->connect('post'); if (JVB_TESTING) { $this->cache->flush(); } $this->buildPages(); $this->buildSections(); //Since this is loaded via JVBase, it's already running on init $this->registerDashboard(); $this->registerHooks(); } protected function registerDashboard():void { $dash = Registrar::forPost('dash', 'Dashboard', 'Dashboards'); $dash->setIcon('gauge') ->make([ 'show_in_admin_bar' => false, 'rewrite' => [ 'slug' => 'dash', 'with_front' => false, ], 'supports' => [ 'title', 'editor', 'custom-fields'], 'hierarchical' => true ])->setAll([ 'system' ]); } protected function registerHooks():void { add_action('template_redirect', [$this, 'handleRedirects']); add_action('template_include', [$this, 'dashboardTemplates']); add_action('admin_init', [$this, 'redirectFromAdmin']); add_action('wp_enqueue_scripts', [$this, 'dashboardScripts'], 50); add_filter('the_seo_framework_sitemap_exclude_ids', [$this, 'excludeDashboard'], 8, 1); } public function handleRedirects():void { if (!is_singular(BASE.'dash') && !is_post_type_archive(BASE.'dash') && !is_404()) { return; } if (!is_404()) { if (!is_user_logged_in()) { error_log('Redirecting to login - user not logged in'); $this->redirectToLogin(); } elseif (!isOurPeople() && !current_user_can('manage_options')) { $this->redirectToHome(); } else { $page = $this->getCurrentPageSlug(); if (array_key_exists($page, ['', 'dash'])) { return; } if (!array_key_exists($page, $this->pages)) { error_log('[DashboardManager]::handleRedirect could not find page for '.$page); return; } $permission = $this->pages[$page]->getPermission(); if (!empty($permission) && !current_user_can($permission)) { error_log('[DashboardManager]::handleRedirect User cannot manage '.$page); $this->redirectToDashboard(); } } } global $wp; if (str_starts_with($wp->request, 'dash/') || $wp->request === 'dash') { error_log('404 on dashboard URL, redirecting to dashboard home'); $this->redirectToDashboard(); } } public function dashboardTemplates(string $template):string { if (!is_singular(BASE.'dash') && !is_post_type_archive(BASE.'dash')) { return $template; } $page = $this->getCurrentPage(); if (!empty($page->getIcon())) { add_filter('jvbLoadingIcon', $page->getIcon()); } ob_start(); jvbInlineStyles('nav'); jvbInlineStyles('dash'); jvbInlineStyles('forms'); $this->renderHeader(); $page->render(); $this->renderFooter(); return ob_get_clean(); } protected function renderHeader():void { $page = $this->getCurrentPage(); ?> > <?= $page->getTitle() . ' | Dashboard' ?> pages as $page) { if (empty($page->getPermission()) || current_user_can($page->getPermission())) { echo ''; } } ?>
'core/site-logo', 'attrs' => [], ]); } ?>
outputSidebarNavigation(); ?> getCurrentPageSlug()); ?> addClass('sidebar left')->hasToggle()->defaultMenuClasses($menuClasses); $menu->defaultItemClasses($itemClasses); //Add the Main Dashboard first $dashboard = $menu->addItem('Dashboard', jvbDashIcon($this->pages['dash']->getIcon())) ->url($this->pages['dash']->getURL()); foreach ($this->sections as $section) { $pages = array_filter($this->pages, function($page) use ($section) { $canDo = empty($page->getPermission()) || current_user_can($page->getPermission()); return $page->getSection() === $section && $canDo; }); if (empty($pages)) { continue; } $icon = !empty($section['icon']??'') ? jvbDashIcon($section['icon']) : null; $section = $menu->addItem($section['title'], $icon) ->submenu($section['slug']) ->defaultMenuClasses($menuClasses) ->defaultItemClasses($itemClasses); foreach ($pages as $page) { $icon = empty($page->getIcon()) ? null : jvbDashIcon($page->getIcon()); $item = $section->addItem($page->getTitle(), $icon) ->url($page->getURL()); $registrar = Registrar::getInstance($page->getSlug()); if ($registrar && !empty($registrar->registrar->taxonomies)) { $itemMenu = $item->submenu($page->getSlug()); foreach ($registrar->registrar->taxonomies as $taxonomy) { $taxonomy = jvbNoBase($taxonomy); if (!array_key_exists($taxonomy, $this->pages)) { error_log('Could not add Taxonomy subpage for '.$taxonomy); continue; } $icon = empty($this->pages[$taxonomy]->getIcon()) ? null : jvbDashIcon($this->pages[$taxonomy]->getIcon()); $itemMenu->addItem($this->pages[$taxonomy]->getTitle(),$icon) ->url($this->pages[$taxonomy]->getURL()); } } } } $pages = $this->getUserAllowedPages()?:[]; //Dashboard //Referrals $dashboard = $menu->addItem('Dashboard',jvbDashIcon('door')) ->url($this->baseURL); // ->submenu('dashboard') // ->defaultMenuClasses($menuClasses) // ->defaultItemClasses($itemClasses); //notifications if (in_array('Notifications', $pages)) { $menu->addItem('Notifications',jvbDashIcon('bell')) ->url($this->baseURL.'/notifications'); } if (in_array('Referrals', $pages)) { $menu->addItem('Referrals', jvbDashIcon('hand-heart')) ->url($this->baseURL.'/referrals'); } if (in_array('Favourites', $pages)) { $menu->addItem('Favourites', jvbDashIcon('heart')) ->url($this->baseURL.'/favourites'); } //Content //content types $all = array_merge( Registrar::getRegistered('post'), Registrar::withFeature('is_content', 'term') ); $availableContent = []; // $availableContent = array_filter($pages, function($page, $key) use($all) { // return !is_numeric($key) && in_array($key, $all) && JVB()->roles()->checkRole($this->user, $key); // }, ARRAY_FILTER_USE_BOTH); if (!empty ($availableContent)){ $content = $menu->addItem('Your Content', jvbDashIcon('book-bookmark')) ->submenu('content') ->defaultMenuClasses($menuClasses) ->defaultItemClasses($itemClasses); foreach ($availableContent as $slug => $page) { $registrar = Registrar::getInstance($slug); $item = $content->addItem($page, $registrar->getIcon()) ->url($this->baseURL.'/'.$slug); if ($registrar->getType() === 'post') { $taxonomies = $registrar->registrar->taxonomies; if (!empty ($taxonomies)) { //TODO: If we add a dedicated 'create item' page, remove this from the empty check $itemMenu = $item->submenu($slug); foreach ($taxonomies as $s) { $taxRegistrar = Registrar::getInstance($s); if ($taxRegistrar) { $itemMenu->addItem($taxRegistrar->getPlural(), $taxRegistrar->getIcon()) ->url($this->baseURL.'/'.$s); } } } } } } //Taxonomies //Settings $settings = $menu->addItem('Settings', jvbDashIcon('faders')) ->submenu('settings') ->defaultItemClasses($itemClasses) ->defaultMenuClasses($menuClasses); //SEO if (in_array('SEO', $pages)) { $settings->addItem('SEO', jvbDashIcon('robot')) ->url($this->baseURL.'/seo'); } //Integrations if (in_array('Integrations', $pages)) { $settings->addItem('Integrations', jvbDashIcon('plugs-connected')) ->url($this->baseURL.'/integrations'); } //Account $account = $menu->addItem('Account', jvbDashIcon('user-circle')) ->url($this->baseURL.'/account') ->submenu('account') ->defaultMenuClasses($menuClasses) ->defaultItemClasses($itemClasses); $account->addItem('Reset Password', jvbDashIcon('password')) ->url($this->baseURL.'/reset-password'); //name + contact //reset password if (in_array('notifications', $pages)) { $account->addItem('Permissions', jvbDashIcon('keyhole')) ->url($this->baseURL.'/permissions'); } echo $menu->render(); } public function redirectFromAdmin():void { //Skip if already processing a redirect if (defined('DOING_AJAX') && DOING_AJAX) { return; } if (current_user_can('manage_options')) { return; } //Redirect to custom dashboard if (is_user_logged_in() && isOurPeople()) { $this->redirectToDashboard(); } } public function dashboardScripts():void { } public function excludeDashboard(array $IDs):array { $exclude = $this->cache->remember( 'dashboardIDs', function() { return get_posts([ 'post_type' => BASE.'dash', 'posts_per_page' => -1, 'fields' => 'ids', ]); }); if (!empty($exclude)) { $IDs = array_merge($IDs, $exclude); } return $IDs; } private function buildPages():void { $this->addPage('dash', 'Dashboard','door'); $this->buildContentPages(); $this->buildReferrals(); $this->buildMembership(); $this->buildFavourites(); $this->buildKarma(); $this->buildNotifications(); $this->buildIntegrations(); $this->buildSettingsPages(); $this->buildAccountPages(); } private function buildContentPages():void { $content = Registrar::getRegistered('post'); foreach ($content as $c) { $registrar = Registrar::getInstance($c); $page = $this->addPage($registrar->getPlural(), $c, $registrar->getIcon()); $page->setPermission(RoleManager::getPermissionName('edit', $c)); $page->setSection('content'); $this->pages[$c] = $page; } } private function buildSettingsPages():void { $seo = $this->addPage('SEO', 'seo', 'robot'); $seo->setSection('settings'); $seo->setPermission('manage_options'); $this->pages['seo'] = $seo; } private function buildAccountPages():void { if (Site::has('support')) { $page = $this->addPage('Support', 'support', 'question'); $page->setSection('support'); } $account = $this->addPage('Account', 'account', 'user-circle'); $account->setSection('account'); $accountID = $account->getID(); $password = $this->addPage('Reset Password', 'reset-password', 'password', $accountID); $password->setOrder(2); $password->setSection('account'); } private function buildReferrals():void { if (Site::has('referrals')) { $page = $this->addPage('Referrals', 'referrals', 'hand-heart'); } } private function buildMembership():void { $membership = Site::membership(); if ($membership) { if ($membership->has('can_invite')) { $page = $this->addPage('Invite', 'invite', ''); $page->setSection('notifications'); } if ($membership->has('term_approval')) { $page = $this->addPage('Approvals', 'approvals', 'check-circle'); $page->setSection('notifications'); } if ($membership->has('forum')) { $page = $this->addPage('Forum', 'forum', 'chats-teardrop'); } if ($membership->has('member_content')) { $page = $this->addPage('Metrics', 'metrics', 'chart-line'); } } } private function buildFavourites():void { if (Site::has('favourites')) { $page = $this->addPage('Favourites', 'favourites', 'heart'); //TODO: Lists, Share permissions } } private function buildKarma():void { if (!empty(Registrar::withFeature('karma'))) { $page = $this->addPage('Karmic', 'karmic', 'arrow-fat-up'); } } private function buildNotifications():void { if (Site::has('notifications')) { $page = $this->addPage('Notifications', 'notifications', 'bell'); $page->setSection('notifications'); $page = $this->addPage('Permissions', 'permissions', 'gear-six'); $page->setSection('notifications'); $page->setOrder(999); } } private function buildIntegrations():void { if (Site::hasAnyIntegration()) { $page = $this->addPage('Integrations', 'integrations', 'plugs-connected'); $page->setSection('settings'); $parent = $page->getID(); foreach (array_keys(Site::getIntegrations()) as $integration) { $integration = match($integration) { 'maps' => 'JVBase\integrations\GoogleMaps', 'square' => 'JVBase\integrations\Square', 'facebook' => 'JVBase\integrations\Facebook', 'helcim' => 'JVBase\integrations\Helcim', 'instagram' => 'JVBase\integrations\Instagram', 'bluesky' => 'JVBase\integrations\BlueSky', 'gmb' => 'JVBase\integrations\GoogleMyBusiness', 'cloudflare' => 'JVBase\integrations\Cloudflare', 'umami' => 'JVBase\integrations\Umami', 'postmark' => 'JVBase\integrations\PostMark', }; $title = $integration::title(); $icon = $integration::icon(); $page = $this->addPage($title, $title, $icon, $parent); } } } public function addPage(string $title, string $slug = '', string $icon = '', int $parent = 0):DashboardPage { $page = new DashboardPage($title, $slug, $icon, $parent); $this->pages[$page->getSlug()] = $page; return $page; } protected function buildSections():void { $sections = array_values(array_filter(array_unique(array_map(function ($page) { return $page->getSection(); }, $this->pages)))); foreach ($sections as $section) { $isLink = false; switch ($section) { case 'content': $title = 'Your Content'; $icon = 'book-bookmark'; break; case 'settings': $title = 'Settings'; $icon = 'faders'; break; case 'account': $title = 'Account'; $icon = 'user-circle'; break; case 'notifications': $title = 'Notifications'; $icon = 'bell'; break; case 'support': $title = 'Support'; $icon = 'question'; break; default: $mainPage = $this->getMainPage($section); if ($mainPage) { $title = $mainPage->getTitle(); $icon = $mainPage->getIcon(); $isLink = true; } else { error_log('[DashboardManager]::buildSections Could not create section for '.$section); return; } break; } if (!$isLink && $this->hasMainPage($section)) { $isLink = true; } $this->sections[$section] = new Section($title, $section, $icon); if ($isLink) { $this->sections[$section]->setIsLink(true); } } } protected function getSectionPages(string $section):array { return array_filter($this->pages, function($page) use ($section) { return $page->getSection() === $section; }); } protected function getMainPage(string $section):DashboardPage|false { $sectionPages = $this->getSectionPages($section); $mainPage = array_filter($sectionPages, function ($page) use ($section) { return $page->getSlug() === $section; }); return empty($mainPage) ? false : $mainPage[0]; } protected function hasMainPage(string $section):bool { return $this->getMainPage($section) !== false; } public function addSection(string $title, ?string $slug = null, string $icon = '', ?string $parent = null):void { $section = new Section($title, $slug, $icon, $parent); $this->sections[$section->getSlug()] = $section; } public function addPageToSection(string $slug, ?string $section = null):bool { if (!array_key_exists($slug, $this->pages)) { error_log('[DashboardManager]::addPageToSection Attempted to add page to section that doesn\'t exist: '.$slug); return false; } if (!is_null($section) && !array_key_exists($section, $this->sections)) { error_log('[DashboardManager]::addPageToSection Please configure section first for '.$section); return false; } $this->pages[$slug]->setSection($section); return true; } #[NoReturn]protected function redirectToLogin():void { wp_redirect(wp_login_url(get_home_url(null, '/dash'))); exit; } #[NoReturn]protected function redirectToDashboard():void { wp_redirect(get_home_url(null, '/dash')); exit; } #[NoReturn]protected function redirectToHome():void { wp_redirect(get_home_url()); exit; } protected function getCurrentPage():DashboardPage|false { $slug = $this->getCurrentPageSlug(); if (!array_key_exists($slug, $this->pages)) { error_log('[DashboardManager]::getCurrentPage Could not get configuration for '.$slug); return false; } return $this->pages[$slug]; } protected function getCurrentPageSlug():string { if (is_post_type_archive(BASE.'dash')) { return 'dash'; } global $post; if (!$post) { return ''; } return $post->post_name; } }