| | |
| | | exit; |
| | | } |
| | | |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\base\Site; |
| | | use WP_Block; |
| | | use WP_Query; |
| | | |
| | | class DirectoryManager |
| | | { |
| | | protected array $directories; |
| | | protected array $directoryPageIDs; |
| | | protected array $directoryList; |
| | | protected int $perPage; |
| | | protected static string $type = BASE.'for_type'; |
| | | protected static string $slug = BASE.'for_type_slug'; |
| | | protected CacheManager $cache; |
| | | protected Cache $cache; |
| | | |
| | | public function __construct() |
| | | public function __construct($perPage = 100) |
| | | { |
| | | $this->directories = jvbGlobalDirectoryInfo(); |
| | | if (empty(jvbGlobalDirectories())) { |
| | | $this->directories = $this->getDirectories(); |
| | | if (empty($this->directories)) { |
| | | return; |
| | | } |
| | | $this->cache = CacheManager::for('directory', WEEK_IN_SECONDS); |
| | | $this->perPage = $perPage; |
| | | $this->cache = Cache::for('directory', WEEK_IN_SECONDS); |
| | | $this->cache->connect('post', true) |
| | | ->connect('taxonomy', true) |
| | | ->connect('user', true); |
| | | |
| | | add_action('init', [$this, 'registerDirectories']); |
| | | jvb_register_do_once('directories_registered', [$this, 'activate']); |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | | } |
| | | |
| | | add_action('render_block', [$this, 'renderBlock'], 99, 3); |
| | | jvb_register_do_once('buildDirectories', [$this, 'activate']); |
| | | add_action('init', [$this, 'registerDirectories']); |
| | | add_filter('render_block', [$this, 'renderBlock'], 998, 3); |
| | | } |
| | | |
| | | public function registerDirectories() |
| | | public function registerDirectories():void |
| | | { |
| | | $plural = 'Directories'; |
| | | $singular = 'Directory'; |
| | | register_post_type(BASE.'directory', array( |
| | | 'labels' => [ |
| | | 'name' => $plural, |
| | | 'singular_name' => $singular, |
| | | 'menu_name' => $plural, |
| | | 'add_new' => "Add New {$singular}", |
| | | 'add_new_item' => "Add New {$singular}", |
| | | 'edit_item' => "Edit {$singular}", |
| | | 'new_item' => "New {$singular}", |
| | | 'view_item' => "View {$singular}", |
| | | 'search_items' => "Search {$plural}", |
| | | 'not_found' => "No {$plural} found", |
| | | 'not_found_in_trash' => "No {$plural} found in Trash" |
| | | ], |
| | | 'menu_icon' => jvbCSSIcon('asc'), |
| | | 'public' => true, |
| | | 'publicly_queryable' => true, |
| | | 'show_in_menu' => true, |
| | | 'show_in_admin_bar' => false, |
| | | 'has_archive' => true, |
| | | 'rewrite' => array( |
| | | 'slug' => 'directory', |
| | | 'with_front' => false |
| | | ), |
| | | 'capability_type' => 'post', |
| | | 'supports' => array('title', 'editor', 'content', 'excerpt', 'custom-fields') |
| | | )); |
| | | |
| | | $singular = Site::getDirectorySingular()??'Directory'; |
| | | $plural = Site::getDirectoryPlural()??'Directories'; |
| | | $config = [ |
| | | 'labels' => [ |
| | | 'name' => $plural, |
| | | 'singular_name' => $singular, |
| | | 'menu_name' => $plural, |
| | | 'name_admin_bar' => $singular, |
| | | 'add_new' => "Add New", |
| | | 'add_new_item' => "Add New {$singular}", |
| | | 'new_item' => "New {$singular}", |
| | | 'edit_item' => "Edit {$singular}", |
| | | 'view_item' => "View {$singular}", |
| | | 'all_items' => "All {$plural}", |
| | | 'search_items' => "Search {$plural}", |
| | | 'parent_item_colon' => "Parent {$plural}:", |
| | | 'not_found' => "No {$plural} found.", |
| | | 'not_found_in_trash' => "No {$plural} found in Trash.", |
| | | ], |
| | | 'public' => true, |
| | | 'menu_icon' => jvbCSSIcon('list-dashes'), |
| | | 'publicly_queryable' => true, |
| | | 'show_in_menu' => true, |
| | | 'show_in_admin_bar' => false, |
| | | 'has_archive' => true, |
| | | 'hierarchical' => true, |
| | | 'rewrite' => [ |
| | | 'slug' => sanitize_title(strtolower($plural)), |
| | | 'with_front' => false, |
| | | ], |
| | | 'capability_type' => 'post', |
| | | 'show_in_rest' => true, |
| | | 'supports'=>['title', 'author', 'thumbnail', 'editor', 'revisions', 'custom-fields', 'excerpt', 'content'] |
| | | ]; |
| | | |
| | | register_post_type(BASE.'directory', $config); |
| | | } |
| | | |
| | | public function activate() |
| | | public function getDirectories():array |
| | | { |
| | | $directories = get_option(BASE.'directories'); |
| | | |
| | | if (!$directories) { |
| | | $directories = []; |
| | | //content |
| | | |
| | | $content = Registrar::getFeatured('show_directory', 'post'); |
| | | if(!empty($content)) { |
| | | foreach ($content as $key) { |
| | | $directories[$key] = 'content'; |
| | | } |
| | | } |
| | | |
| | | $taxonomies = Registrar::getFeatured('show_directory', 'term'); |
| | | if(!empty($taxonomies)) { |
| | | foreach ($taxonomies as $key) { |
| | | $directories[$key] = 'taxonomy'; |
| | | } |
| | | } |
| | | |
| | | $users = Registrar::getFeatured('show_directory', 'user'); |
| | | if(!empty($users)) { |
| | | foreach ($users as $key) { |
| | | $directories[$key] = 'user'; |
| | | } |
| | | } |
| | | |
| | | update_option(BASE.'directories', $directories); |
| | | } |
| | | return $directories; |
| | | } |
| | | |
| | | public function activate():void |
| | | { |
| | | // $tmp = new self(); |
| | | // $this->registerDirectories(); |
| | | |
| | | $created = []; |
| | | $directories = []; |
| | | $this->getDirectories(); |
| | | foreach($this->directories as $directory => $type) { |
| | | $registrar = Registrar::getInstance($directory); |
| | | if (!$registrar){ |
| | | error_log('Could not find registrar for making directory for '.$directory); |
| | | continue; |
| | | } |
| | | |
| | | foreach (jvbGlobalDirectories() as $directory => $type) { |
| | | switch ($type) { |
| | | case 'content': |
| | | $config = JVB_CONTENT; |
| | | break; |
| | | case 'tax': |
| | | $config = JVB_TAXONOMY; |
| | | break; |
| | | case 'user': |
| | | $config = JVB_USER; |
| | | break; |
| | | } |
| | | $title = $config[$directory]['directory']??$config[$directory]['plural']; |
| | | $excerpt = implode(' ', $config[$directory]['description']??[]); |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_title'=> $title, |
| | | 'post_status'=> 'publish', |
| | | 'post_excerpt' => $excerpt, |
| | | 'slug' => sanitize_title($title) |
| | | ]); |
| | | if (!is_wp_error($ID)) { |
| | | add_post_meta($ID, self::$type, $type); |
| | | add_post_meta($ID, self::$slug, $directory); |
| | | $created[$directory] = (int)$ID; |
| | | $slug = sanitize_title($title); |
| | | $directories[$directory] = [ |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_home_url(null, '/directory/'.$slug), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | | 'extra' => $config[$directory]['directory_extra'] ??[], |
| | | ]; |
| | | } |
| | | $config = $registrar->getConfig('directory'); |
| | | $title = $config['title']; |
| | | //Bail early if we've already created the page |
| | | $existing = new WP_Query([ |
| | | 'post_type' => BASE.'directory', |
| | | 'name' => sanitize_title($title), |
| | | 'posts_per_page' => 1, |
| | | ]); |
| | | if ($existing->have_posts()) { |
| | | $existing = $existing->posts[0]; |
| | | $created[$directory] = $existing->ID; |
| | | $directories[$directory] = [ |
| | | 'slug' => $existing->post_name, |
| | | 'title' => $existing->post_title, |
| | | 'ID' => $existing->ID, |
| | | 'url' => get_the_permalink($existing->ID), |
| | | 'page' => $existing->post_title, |
| | | 'description'=> $existing->post_excerpt, |
| | | 'type' => $type, |
| | | 'extra' => $config[$directory]['directory_extra']??[], |
| | | ]; |
| | | continue; |
| | | } |
| | | |
| | | $excerpt = implode(' ', $config['description']??[]); |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_title' => $title, |
| | | 'post_status' => 'publish', |
| | | 'post_excerpt' => $excerpt, |
| | | 'post_name' => sanitize_title($title) |
| | | ]); |
| | | if (!is_wp_error($ID)) { |
| | | add_post_meta($ID, self::$type, $type); |
| | | add_post_meta($ID, self::$slug, $directory); |
| | | $created[$directory] = (int)$ID; |
| | | $slug = sanitize_title($title); |
| | | $directories[$directory] = [ |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_the_permalink($ID), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | | 'extra' => $config[$directory]['directory_extra'] ??[], |
| | | ]; |
| | | } |
| | | if ($config['isGrouped']) { |
| | | $title = $title.', but Grouped'; |
| | | $slug = sanitize_title($title).'-grouped'; |
| | | $excerpt = $config['groupedDescription']??'Too many options? This is grouped by type.'; |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_title' => $title, |
| | | 'post_status' => 'publish', |
| | | 'post_excerpt' => $excerpt, |
| | | 'slug' => $slug, |
| | | ]); |
| | | if (!is_wp_error($ID)) { |
| | | add_post_meta($ID, self::$type, $type); |
| | | add_post_meta($ID, self::$slug, $directory.'-grouped'); |
| | | add_post_meta($ID, BASE.'grouped_directory', 'yup'); |
| | | $created[$directory.'-grouped'] = (int)$ID; |
| | | $directories[$directory.'-grouped'] = [ |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_the_permalink($ID), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | | 'extra' => $config[$directory]['directory_extra'] ??[], |
| | | ]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (jvbCheck('isGrouped', $config[$directory])) { |
| | | $title = $title. ', but Grouped'; |
| | | $excerpt = 'Too many options in the list? This is grouped by type, nested deep, man.'; |
| | | $slug = sanitize_title(str_replace(', but', '', $title)); |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_title'=> $title, |
| | | 'post_status'=> 'publish', |
| | | 'post_excerpt' => $excerpt, |
| | | 'slug' => $slug |
| | | ]); |
| | | if (!is_wp_error($ID)) { |
| | | add_post_meta($ID, self::$type, $type); |
| | | add_post_meta($ID, self::$slug, $directory.'-grouped'); |
| | | add_post_meta($ID, BASE.'grouped_directory', 'yup'); |
| | | $created[$directory.'-grouped'] = (int)$ID; |
| | | $directories[$directory.'-grouped'] = [ |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_home_url(null, '/directory/'.$slug), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | | 'extra' => $config[$directory]['directory_extra'] ??[], |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | } |
| | | if (jvbCheck('has_map', JVB_SITE)) { |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_title' => 'Map', |
| | | 'post_status'=> 'publish', |
| | | 'slug' => 'map', |
| | | ]); |
| | | if (!is_wp_error($ID)) { |
| | | add_post_meta($ID, self::$type, 'map'); |
| | | $created['map'] = (int)$ID; |
| | | $directories['map'] = [ |
| | | 'slug' => 'map', |
| | | 'title' => 'Map', |
| | | 'ID' => $ID, |
| | | 'url' => get_home_url(null, '/directory/map'), |
| | | 'page' => 'Map', |
| | | 'type' => 'term', |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | // if (Site::has('has_map')) { |
| | | // $ID = wp_insert_post([ |
| | | // 'post_type' => BASE.'directory', |
| | | // 'post_title' => 'Map', |
| | | // 'post_status'=> 'publish', |
| | | // 'slug' => 'map', |
| | | // ]); |
| | | // if (!is_wp_error($ID)) { |
| | | // add_post_meta($ID, self::$type, 'map'); |
| | | // $created['map'] = (int)$ID; |
| | | // $directories['map'] = [ |
| | | // 'slug' => 'map', |
| | | // 'title' => 'Map', |
| | | // 'ID' => $ID, |
| | | // 'url' => get_the_permalink($ID), |
| | | // 'page' => 'Map', |
| | | // 'type' => 'term', |
| | | // ]; |
| | | // } |
| | | // } |
| | | if (!empty($created)) { |
| | | update_option(BASE.'directory_ids', $created); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | public static function getConfig(int $ID):array |
| | | protected function buildDirectoryList():array |
| | | { |
| | | $saved = get_option(BASE.'directory_list', []); |
| | | |
| | | if (empty($saved)) { |
| | | $all = new WP_Query([ |
| | | 'post_type' => BASE.'directory', |
| | | 'post_status' => 'publish', |
| | | 'posts_per_page' => -1, |
| | | ]); |
| | | foreach($all->posts as $post) { |
| | | $config = Registrar::getInstance($post->post_name)->getConfig('directory')??false; |
| | | |
| | | $saved[$post->post_name] = [ |
| | | 'slug' => $post->post_name, |
| | | 'title' => $post->post_title, |
| | | 'ID' => $post->ID, |
| | | 'url' => get_the_permalink($post->ID), |
| | | 'page' => $post->post_title, |
| | | 'description' => ($config) ?$config['description'] :'', |
| | | 'type' => get_post_meta($post->ID, self::$type,true), |
| | | 'extra' => ($config) ?$config['directory_extra'] : [], |
| | | ]; |
| | | } |
| | | update_option(BASE.'directory_list', $saved); |
| | | wp_reset_postdata(); |
| | | } |
| | | return $saved; |
| | | } |
| | | |
| | | public function getDirectoryPageIDs():array |
| | | { |
| | | if (empty($this->directoryPageIDs)) { |
| | | $this->directoryPageIDs = get_option(BASE.'directory_ids', []); |
| | | } |
| | | return $this->directoryPageIDs; |
| | | } |
| | | public function getDirectoryList():array |
| | | { |
| | | if (empty($this->directoryList)) { |
| | | $this->directoryList = $this->buildDirectoryList(); |
| | | } |
| | | return $this->directoryList; |
| | | } |
| | | |
| | | public static function getConfig(int $ID):Registrar|false |
| | | { |
| | | $type = get_post_meta($ID, self::$type, true); |
| | | $slug = get_post_meta($ID, self::$slug, true); |
| | | switch ($type) { |
| | | case 'content': |
| | | return JVB_CONTENT[$slug]; |
| | | case 'taxonomy': |
| | | return JVB_TAXONOMY[$slug]; |
| | | case 'user': |
| | | return JVB_USER[$slug]; |
| | | } |
| | | return []; |
| | | } |
| | | return Registrar::getInstance($slug); |
| | | } |
| | | |
| | | public function letters():array |
| | | { |
| | |
| | | ]; |
| | | } |
| | | |
| | | protected function alphabetizeMe( |
| | | public function alphabetizeMe( |
| | | array $list, |
| | | string $name = '', |
| | | string $url = '', |
| | |
| | | return $list; |
| | | } |
| | | |
| | | public function directories(string $search = 'all'):array |
| | | { |
| | | $directories = $this->getDirectoryList(); |
| | | if ($search === 'all') { |
| | | return $directories; |
| | | } |
| | | return $directories[$search]??[]; |
| | | } |
| | | |
| | | public function isDirectory():bool |
| | | { |
| | | return (is_post_type_archive(BASE.'directory') || is_singular(BASE.'directory')); |
| | | } |
| | | |
| | | private function renderArchive(): string |
| | | { |
| | | $this->getDirectoryList(); |
| | | return $this->cache->remember( |
| | | 'archive', |
| | | function() { |
| | | $cache = '<h1>Directory of Directories</h1> |
| | | $cache = '<h1>'.$this->referAs().' of '.$this->referAs(true).'</h1> |
| | | <p>You like lists? We\'ve got \'em!</p> |
| | | <section class="directories item-grid">'; |
| | | foreach ($this->directories as $slug => $directory) { |
| | | <ul class="directories">'; |
| | | foreach ($this->directoryList as $slug => $directory) { |
| | | $config = Registrar::getInstance($slug); |
| | | $aOpen = '<a href="'.$directory['url'].'" title="See our list of '.$directory['title'].'">'; |
| | | $aClose = '</a>'; |
| | | $cache .= '<div class="directory col start"> |
| | | '.$aOpen.jvbIcon($slug).$aClose. |
| | | '<h2>'.$aOpen.$directory['title'].$aClose.'</h2>'; |
| | | $cache .= '<li class="directory col left"> |
| | | '. $aOpen.jvbIcon($config->getIcon() !== '' ? $config->getIcon() :'list-dashes').$directory['title'].$aClose; |
| | | if (!empty($directory['description'])) { |
| | | $cache .= '<div class="description">'; |
| | | foreach ($directory['description'] as $description) { |
| | |
| | | } |
| | | $cache .= '</div>'; |
| | | } |
| | | $cache .= '</div>'; |
| | | $cache .= '</li>'; |
| | | } |
| | | $cache .= '</section>'; |
| | | $cache .= '</ul>'; |
| | | return $cache; |
| | | } |
| | | ); |
| | |
| | | $cache = $this->cache->remember( |
| | | 'index', |
| | | function() { |
| | | $cache = '<nav class="directory"><ul>'; |
| | | foreach (jvbDirectories() as $slug => $directory) { |
| | | $cache = '<nav class="directory condensed"><ul>'; |
| | | foreach ($this->getDirectoryList() as $slug => $directory) { |
| | | $actualSlug = str_replace('-grouped', '', $slug); |
| | | $config = Registrar::getInstance($actualSlug); |
| | | $icon = $config->getIcon() !== '' ? jvbIcon($config->getIcon()) : ''; |
| | | $cache .= '<li id="'.$slug.'"> |
| | | <a href="'.$directory['url'].'">'. |
| | | jvbIcon(str_replace('-grouped', '', $slug)).$directory['title'].' |
| | | <a href="'.$directory['url'].'" class="'.$actualSlug.'">'. |
| | | $icon.$directory['title'].' |
| | | </a> |
| | | </li>'; |
| | | } |
| | |
| | | return $cache; |
| | | } |
| | | ); |
| | | if ($current !== '' && array_key_exists($current, jvbDirectories())) { |
| | | if ($current !== '' && array_key_exists($current, $this->directories())) { |
| | | $open = ($open) ? ' open' : ''; |
| | | $cache = '<details'.$open.'><summary class="row btw">Other Directories:</summary>'. |
| | | $cache = '<details'.$open.'><summary class="row x-btw">Other '.$this->referAs(true).':</summary>'. |
| | | str_replace('id="'.$current.'"', 'id="'.$current.'" class="current"', $cache) |
| | | .'</details>'; |
| | | } |
| | | return $cache; |
| | | } |
| | | |
| | | private function renderDirectory():string |
| | | { |
| | | private function renderDirectory(): string |
| | | { |
| | | $slug = get_post_meta(get_the_ID(), self::$slug, true); |
| | | if ($slug === '') { |
| | | return ''; |
| | | } |
| | | |
| | | $slug = get_post_meta(get_the_ID(), self::$slug, true); |
| | | if ($slug === '') { |
| | | return ''; |
| | | } |
| | | return $this->cache->remember( |
| | | $slug, |
| | | function() use ($slug) { |
| | | $out = '<h1>'.$this->directories[$slug]['title'].'</h1>'; |
| | | $out .= '<div class="description">'; |
| | | $type = $this->directories[$slug]; |
| | | $registrar = Registrar::getInstance($slug); |
| | | $config = $registrar->getConfig('directory'); |
| | | |
| | | foreach ($this->directories[$slug]['description']??[] as $p) { |
| | | $out .= '<p>'.$p.'</p>'; |
| | | } |
| | | $out .= '</div>'; |
| | | $out .= $this->renderIndex($slug); |
| | | $paged = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1; |
| | | |
| | | $data = $this->directories[$slug]; |
| | | $list = []; |
| | | switch ($data['type']) { |
| | | case 'content': |
| | | $get = new WP_Query([ |
| | | 'post_type' => jvbCheckBase($slug), |
| | | 'posts_per_page' => -1, |
| | | 'orderby' => 'title', |
| | | 'order' => 'ASC' |
| | | ]); |
| | | $cacheKey = $slug . '_page_' . $paged; |
| | | |
| | | return $this->cache->remember( |
| | | $cacheKey, |
| | | function() use ($slug, $type, $registrar, $config, $paged) { |
| | | $out = '<h1>' . $this->directoryTitle($registrar) . '</h1>'; |
| | | $out .= '<div class="description">'; |
| | | foreach ($config['description'] ?? [] as $p) { |
| | | $out .= '<p>' . $p . '</p>'; |
| | | } |
| | | $out .= '</div>'; |
| | | $out .= $this->renderIndex($slug); |
| | | |
| | | $list = []; |
| | | $query = null; |
| | | |
| | | switch ($type) { |
| | | case 'content': |
| | | $args = [ |
| | | 'post_type' => jvbCheckBase($slug), |
| | | 'posts_per_page' => $this->perPage, |
| | | 'paged' => $paged, |
| | | 'orderby' => 'title', |
| | | 'order' => 'ASC' |
| | | ]; |
| | | |
| | | |
| | | if ($registrar->hasFeature('is_timeline')) { |
| | | $args['post_parent'] = 0; |
| | | } |
| | | |
| | | $get = new WP_Query($args); |
| | | |
| | | $hasExtra = $registrar->hasFeature('directory_extra'); |
| | | if ($get->have_posts()) { |
| | | while ( $get->have_posts() ) { |
| | | $get->the_post(); |
| | | $extra = []; |
| | | foreach ( $data['extra'] as $item ) { |
| | | $item = jvbCheckBase( $item ); |
| | | if ($hasExtra) { |
| | | foreach ($config['directory_extra'] as $item ) { |
| | | $item = jvbCheckBase( $item ); |
| | | |
| | | $terms = get_the_terms( get_the_ID(), jvbCheckBase( $item ) ); |
| | | if ( $terms && ! is_wp_error( $terms ) ) { |
| | | $term = $terms[0]; |
| | | $extra[] = [ |
| | | 'name' => (get_term_meta( $term->term_id, BASE . 'singular', true ) !== '') ? get_term_meta( $term->term_id, BASE . 'singular', true ) : $term->name, |
| | | 'url' => get_term_link( $term->term_id, $item ), |
| | | 'id' => $term->term_id, |
| | | 'type' => $item, |
| | | ]; |
| | | $terms = get_the_terms( get_the_ID(), jvbCheckBase( $item ) ); |
| | | if ( $terms && ! is_wp_error( $terms ) ) { |
| | | $term = $terms[0]; |
| | | $extra[] = [ |
| | | 'name' => (get_term_meta( $term->term_id, BASE . 'singular', true ) !== '') ? get_term_meta( $term->term_id, BASE . 'singular', true ) : html_entity_decode($term->name), |
| | | 'url' => get_term_link( $term->term_id, $item ), |
| | | 'id' => $term->term_id, |
| | | 'type' => $item, |
| | | ]; |
| | | |
| | | } |
| | | } |
| | | $list = $this->alphabetizeMe( |
| | | $list, |
| | | get_the_title(), |
| | | get_the_permalink(), |
| | | get_the_ID(), |
| | | $extra |
| | | ); |
| | | } |
| | | $list = $this->alphabetizeMe( |
| | | $list, |
| | | get_the_title(), |
| | | get_the_permalink(), |
| | | get_the_ID(), |
| | | $extra |
| | | ); |
| | | } |
| | | } |
| | | wp_reset_postdata(); |
| | | break; |
| | | case 'tax': |
| | | case 'taxonomy': |
| | | // For taxonomy, we need to manually paginate |
| | | $offset = ($paged - 1) * $this->perPage; |
| | | $get = get_terms([ |
| | | 'taxonomy' => jvbCheckBase($slug), |
| | | 'hide_empty' => true, |
| | | 'orderby' => 'name', |
| | | 'order' => 'ASC', |
| | | 'taxonomy' => jvbCheckBase($slug), |
| | | 'hide_empty' => true, |
| | | 'orderby' => 'name', |
| | | 'order' => 'ASC', |
| | | 'number' => $this->perPage, |
| | | 'offset' => $offset, |
| | | ]); |
| | | |
| | | // Get total for pagination |
| | | $total_terms = wp_count_terms([ |
| | | 'taxonomy' => jvbCheckBase($slug), |
| | | 'hide_empty' => true, |
| | | ]); |
| | | |
| | | if ($get && !is_wp_error($get)) { |
| | | $extra = false; |
| | | $extra = []; |
| | | foreach ($get as $term) { |
| | | |
| | | $list = $this->alphabetizeMe( |
| | | $list, |
| | | $term->name, |
| | | html_entity_decode($term->name), |
| | | get_term_link( $term->term_id, jvbCheckBase( $slug ) ), |
| | | $term->term_id, |
| | | $extra |
| | |
| | | ]); |
| | | |
| | | break; |
| | | default: |
| | | $list = []; |
| | | break; |
| | | } |
| | | |
| | | $out .= '<section class="directory-list '.$slug.'">'; |
| | | if (empty($list)) { |
| | | $out .= '<h2>Nothing here.</h2><p>We don\'t have anything here yet.</p>'; |
| | | } else { |
| | | $out .= $this->renderLettersIndex($list); |
| | | $out .= $this->renderLettersIndex($list, $type, $slug); |
| | | $out .= $this->renderLettersList($list, $slug); |
| | | |
| | | if ($type === 'content' && $query) { |
| | | $out .= $this->renderPagination($query); |
| | | } elseif ($type === 'taxonomy' && is_numeric($total_terms)) { |
| | | $out .= $this->renderTaxonomyPagination($total_terms, $paged); |
| | | } |
| | | } |
| | | $out .= '</section>'; |
| | | |
| | |
| | | } |
| | | return $this->cache->remember( |
| | | $slug.'_group', |
| | | function() { |
| | | function() use ($slug){ |
| | | $out = '<h1>'.$this->directories[$slug]['title'].'</h1>'; |
| | | $out .= '<div class="description">'; |
| | | |
| | |
| | | $children =$this->renderListChunk($taxonomy, $term->term_id); |
| | | $out .= '<li>'; |
| | | if ($children !== '') { |
| | | $out .= '<details class="term"><summary class="row btw"><a href="'.get_term_link($term->term_id, $term->taxonomy).'" title="See more '.$term->name.'">'.$term->name.'</a></summary>'; |
| | | $out .= '<details class="term"><summary class="row x-btw"><a href="'.get_term_link($term->term_id, $term->taxonomy).'" title="See more '.html_entity_decode($term->name).'">'.$term->name.'</a></summary>'; |
| | | $out .= $children; |
| | | $out .= '</details>'; |
| | | } else { |
| | | $out .= '<a href="'.get_term_link($term->term_id, $term->taxonomy).'" title="See more '.$term->name.'">'.$term->name.'</a>'; |
| | | $out .= '<a href="'.get_term_link($term->term_id, $term->taxonomy).'" title="See more '.$term->name.'">'.html_entity_decode($term->name).'</a>'; |
| | | } |
| | | $out .= '</li>'; |
| | | } |
| | |
| | | return $out; |
| | | } |
| | | |
| | | public function renderLettersIndex(array $list):string |
| | | { |
| | | $out = '<nav class="letters on-this-page"><ul>'; |
| | | foreach ($this->letters() as $l) { |
| | | $aOpen = $aClose = $class = ''; |
| | | if (array_key_exists($l, $list)) { |
| | | $aOpen = '<a href="#starts-with-'.$l.'">'; |
| | | $aClose = '</a>'; |
| | | $class = ' class="has"'; |
| | | } |
| | | $out .= '<li'.$class.'>'.$aOpen.strtoupper($l).$aClose.'</li>'; |
| | | } |
| | | public function renderLettersIndex(array $list, string $type = '', string $slug = ''): string |
| | | { |
| | | $letters_on_page = array_keys($list); |
| | | $letterPageMap = []; |
| | | |
| | | $out .= '</ul></nav>'; |
| | | if ($type !== '' && $slug !== '') { |
| | | $letterPageMap = $this->getLetterPageMap($type, $slug); |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | $out = '<nav class="letters on-this-page"><ul>'; |
| | | |
| | | foreach ($this->letters() as $l) { |
| | | $aOpen = $aClose = $class = ''; |
| | | |
| | | if (array_key_exists($l, $list)) { |
| | | // Letter is on current page - link to anchor |
| | | $aOpen = '<a href="#starts-with-' . $l . '">'; |
| | | $aClose = '</a>'; |
| | | $class = ' class="has current-page"'; |
| | | } elseif (isset($letterPageMap[$l])) { |
| | | // Letter exists but on different page - link to that page with GET param |
| | | $page = $letterPageMap[$l]['page']; |
| | | $url = add_query_arg('page', $page, get_permalink()) . '#starts-with-' . $l; |
| | | $aOpen = '<a href="' . $url . '" title="Go to page ' . $page . '">'; |
| | | $aClose = '</a>'; |
| | | $class = ' class="has other-page"'; |
| | | } |
| | | |
| | | $out .= '<li' . $class . '>' . $aOpen . strtoupper($l) . $aClose . '</li>'; |
| | | } |
| | | |
| | | $out .= '</ul></nav>'; |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | public function renderLettersList(array $list, string $type):string |
| | | { |
| | |
| | | |
| | | $out = '<ul class="list-none">'; |
| | | foreach ($list as $letter => $items) { |
| | | $out .= '<li id="starts-with-'.$letter.'" class="row a-start btw"><h3>'.strtoupper($letter).'</h3><ul>'; |
| | | $out .= '<li id="starts-with-'.$letter.'" class="row top x-btw nowrap"><h3>'.strtoupper($letter).'</h3><ul>'; |
| | | foreach ($items as $item) { |
| | | $extra = ''; |
| | | if (!empty($item['extra'])) { |
| | |
| | | } |
| | | $extra .= '</span>'; |
| | | } |
| | | $out .= '<li class="row btw"> |
| | | |
| | | $item_html = apply_filters('jvb_directory_render_item', '', $item, $type, $extra); |
| | | |
| | | if (empty($item_html)) { |
| | | $item_html = '<li class="row x-btw"> |
| | | <a href="'.$item['url'].'" title="More about '.$item['name'].'"> |
| | | '.$item['name'].'</a>'.$extra. |
| | | '</li>'; |
| | | '.$item['name'].'</a>'.$extra.' |
| | | </li>'; |
| | | } |
| | | $out .= $item_html; |
| | | |
| | | } |
| | | $out .= '</ul></li>'; |
| | |
| | | return $content; |
| | | } |
| | | |
| | | |
| | | error_log('Still working on directory manager...'); |
| | | // For archive page |
| | | if (is_post_type_archive(BASE.'directory') && $block['blockName'] === 'core/group') { |
| | | return ($block['attrs']['tagName']??false === 'main') ? '<main>'.$this->renderArchive().'</main>' : $content; |
| | | return ($block['attrs']['tagName']??'' === 'main') ? '<main>'.$this->renderArchive().'</main>' : $content; |
| | | } |
| | | |
| | | // For single directory posts |
| | | if ($block['blockName'] === 'core/group') { |
| | | |
| | | switch (get_post_meta(get_the_ID(), BASE.'grouped_directory', true)) { |
| | | case '': |
| | | return '<main>' . $this->renderDirectory() . '</main>'; |
| | |
| | | |
| | | return $content; |
| | | } |
| | | |
| | | protected function directoryTitle(Registrar $registrar):string |
| | | { |
| | | $config = $registrar->getConfig('directory'); |
| | | return $config['title']?: $registrar->getPlural(); |
| | | } |
| | | |
| | | public function referAs($plural = false):string |
| | | { |
| | | return ($plural) ? Site::getDirectoryPlural()??'Directories' : Site::getDirectorySingular()??'Directory'; |
| | | } |
| | | |
| | | /***************************************************** |
| | | * PAGINATION HELPERS |
| | | ****************************************************/ |
| | | protected function renderPagination(WP_Query $query): string |
| | | { |
| | | if ($query->max_num_pages <= 1) { |
| | | return ''; |
| | | } |
| | | |
| | | $current = max(1, isset($_GET['page']) ? (int)$_GET['page'] : 1); |
| | | |
| | | $pagination = paginate_links([ |
| | | 'base' => add_query_arg('page', '%#%'), |
| | | 'format' => '', |
| | | 'current' => $current, |
| | | 'total' => $query->max_num_pages, |
| | | 'type' => 'array', |
| | | 'prev_text' => jvbIcon('arrow-square-left'), |
| | | 'next_text' => jvbIcon('arrow-square-right'), |
| | | ]); |
| | | |
| | | if (!$pagination) { |
| | | return ''; |
| | | } |
| | | |
| | | $out = '<nav class="directory-pagination" aria-label="Directory pagination"><ul class="pagination">'; |
| | | foreach ($pagination as $page) { |
| | | $out .= '<li>' . $page . '</li>'; |
| | | } |
| | | $out .= '</ul></nav>'; |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | protected function renderTaxonomyPagination(int $total, int $paged): string |
| | | { |
| | | $max_pages = ceil($total / $this->perPage); |
| | | |
| | | if ($max_pages <= 1) { |
| | | return ''; |
| | | } |
| | | |
| | | $current = max(1, isset($_GET['page']) ? (int)$_GET['page'] : 1); |
| | | |
| | | $pagination = paginate_links([ |
| | | 'base' => add_query_arg('page', '%#%'), |
| | | 'format' => '', |
| | | 'current' => $current, |
| | | 'total' => $max_pages, |
| | | 'type' => 'array', |
| | | 'prev_text' => jvbIcon('arrow-square-left'), |
| | | 'next_text' => jvbIcon('arrow-square-right'), |
| | | ]); |
| | | |
| | | if (!$pagination) { |
| | | return ''; |
| | | } |
| | | |
| | | $out = '<nav class="directory-pagination" aria-label="Directory pagination"><ul class="pagination">'; |
| | | foreach ($pagination as $page) { |
| | | $out .= '<li>' . $page . '</li>'; |
| | | } |
| | | $out .= '</ul></nav>'; |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | protected function getLetterRanges(array $letters): array |
| | | { |
| | | if (empty($letters)) { |
| | | return []; |
| | | } |
| | | |
| | | sort($letters); |
| | | $ranges = []; |
| | | $start = $letters[0]; |
| | | $prev = $letters[0]; |
| | | |
| | | foreach (array_slice($letters, 1) as $letter) { |
| | | // Check if letters are consecutive |
| | | if (ord($letter) !== ord($prev) + 1) { |
| | | $ranges[] = ['start' => $start, 'end' => $prev]; |
| | | $start = $letter; |
| | | } |
| | | $prev = $letter; |
| | | } |
| | | |
| | | // Add final range |
| | | $ranges[] = ['start' => $start, 'end' => $prev]; |
| | | |
| | | return $ranges; |
| | | } |
| | | protected function getLetterPageMap(string $type, string $slug): array |
| | | { |
| | | return $this->cache->remember( |
| | | $slug . '_letter_page_map', |
| | | function() use ($type, $slug) { |
| | | $titles = []; |
| | | $registrar = Registrar::getInstance($slug); |
| | | switch ($type) { |
| | | case 'content': |
| | | global $wpdb; |
| | | $post_type = jvbCheckBase($slug); |
| | | |
| | | $where = $wpdb->prepare("post_type = %s AND post_status = 'publish'", $post_type); |
| | | if ($registrar && $registrar->hasFeature('is_timeline')) { |
| | | $where .= " AND post_parent = 0"; |
| | | } |
| | | |
| | | $titles = $wpdb->get_col( |
| | | "SELECT post_title |
| | | FROM {$wpdb->posts} |
| | | WHERE {$where} |
| | | ORDER BY post_title" |
| | | ); |
| | | break; |
| | | |
| | | case 'taxonomy': |
| | | global $wpdb; |
| | | $taxonomy = jvbCheckBase($slug); |
| | | |
| | | $titles = $wpdb->get_col($wpdb->prepare( |
| | | "SELECT t.name |
| | | FROM {$wpdb->terms} t |
| | | INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id |
| | | WHERE tt.taxonomy = %s AND tt.count > 0 |
| | | ORDER BY t.name ASC", |
| | | $taxonomy |
| | | )); |
| | | break; |
| | | |
| | | case 'user': |
| | | $users = get_users([ |
| | | 'role' => jvbCheckBase($slug), |
| | | 'orderby' => 'display_name', |
| | | 'order' => 'ASC', |
| | | 'fields' => 'display_name', |
| | | ]); |
| | | $titles = array_column($users, 'display_name'); |
| | | break; |
| | | } |
| | | |
| | | return $this->calculateLetterPages($titles); |
| | | } |
| | | ); |
| | | } |
| | | |
| | | protected function calculateLetterPages(array $titles): array |
| | | { |
| | | $letterCounts = []; |
| | | |
| | | // Count items per letter |
| | | foreach ($titles as $title) { |
| | | $letter = strtolower(mb_substr($title, 0, 1)); |
| | | if (!isset($letterCounts[$letter])) { |
| | | $letterCounts[$letter] = 0; |
| | | } |
| | | $letterCounts[$letter]++; |
| | | } |
| | | |
| | | // Calculate which page each letter starts on |
| | | $letterPages = []; |
| | | $runningTotal = 0; |
| | | |
| | | foreach ($this->letters() as $letter) { |
| | | if (!isset($letterCounts[$letter])) { |
| | | continue; |
| | | } |
| | | |
| | | $count = $letterCounts[$letter]; |
| | | $startPosition = $runningTotal + 1; |
| | | $startPage = (int)ceil($startPosition / $this->perPage); |
| | | |
| | | $letterPages[$letter] = [ |
| | | 'page' => $startPage, |
| | | 'count' => $count, |
| | | 'start_position' => $startPosition, |
| | | ]; |
| | | |
| | | $runningTotal += $count; |
| | | } |
| | | |
| | | return $letterPages; |
| | | } |
| | | } |
| | | |
| | | new DirectoryManager(); |
| | | |
| | | function jvbDirectoryConfig():array |
| | | { |
| | | $ID = get_the_ID(); |
| | | if ($ID) { |
| | | return DirectoryManager::getConfig($ID); |
| | | } |
| | | return []; |
| | | } |
| | | |