> */ private array $pages = array(); /** @var array> */ private array $header_items = array(); public static function instance(): Registry { return self::$instance ??= new self(); } /** * A native page: a sidebar item + a route under /app. * * @param array{title:string,path?:string,icon?:string,capability?:string,position?:int,render?:callable,script?:string,subroutes?:bool,nav?:bool|callable} $args 'subroutes' lets the page own deeper routes; 'nav' false (or a callable returning false) keeps it out of the sidebar. */ public function register_page( string $id, array $args ): void { $this->pages[ $id ] = array_merge( array( 'title' => $id, 'path' => '/' . $id, 'icon' => 'circle', 'capability' => 'read', 'position' => 50, 'render' => null, 'script' => '', 'subroutes' => false, 'nav' => true ), $args ); } /** @return array> */ public function pages(): array { $pages = $this->pages; uasort( $pages, static fn( $a, $b ) => $a['position'] <=> $b['position'] ); return $pages; } /** * The page for an /app route. A page registered with 'subroutes' => true also owns deeper * routes (tools/my-tool); the rest of the route comes back as 'sub'. */ public function page_for_route( string $route ): ?array { $route = trim( $route, '/' ); foreach ( $this->pages as $id => $page ) { if ( trim( (string) $page['path'], '/' ) === $route ) { return $page + array( 'id' => $id, 'sub' => '' ); } } foreach ( $this->pages as $id => $page ) { $base = trim( (string) $page['path'], '/' ); if ( ! empty( $page['subroutes'] ) && '' !== $base && str_starts_with( $route, $base . '/' ) ) { return $page + array( 'id' => $id, 'sub' => substr( $route, strlen( $base ) + 1 ) ); } } return null; } /** @var array> */ private array $notification_types = array(); /** @param array{label:string,icon?:string,description?:string} $args */ public function register_notification_type( string $type, array $args ): void { $this->notification_types[ sanitize_key( $type ) ] = array_merge( array( 'label' => $type, 'icon' => 'bell', 'description' => '' ), $args ); } /** @return array> */ public function notification_types(): array { return $this->notification_types; } /** @param array{icon:string,label:string,badge?:callable,url?:string,position?:int,capability?:string,toggle?:string,tab?:string} $args Set toggle 'flyout' + tab '' to open a flyout pane added via dashbread_flyout_tabs/panes. */ public function register_header_item( string $id, array $args ): void { $this->header_items[ $id ] = array_merge( array( 'icon' => 'circle', 'label' => $id, 'badge' => null, 'url' => '', 'position' => 50, 'capability' => 'read', 'toggle' => '' ), $args ); } /** @return array> */ public function header_items(): array { $items = $this->header_items; uasort( $items, static fn( $a, $b ) => $a['position'] <=> $b['position'] ); return $items; } }