| | |
| | | exit; |
| | | } |
| | | |
| | | use JVBase\registry\PostTypeRegistrar; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\utility\Features; |
| | | use WP_Block; |
| | | use WP_Query; |
| | |
| | | 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 = $this->getDirectories(); |
| | | $this->directories = $this->getDirectories(); |
| | | if (empty($this->directories)) { |
| | | return; |
| | | } |
| | | $this->cache = CacheManager::for('directory', WEEK_IN_SECONDS); |
| | | foreach(['content','taxonomy','user'] as $key) { |
| | | if (array_key_exists($key, $this->directories)) { |
| | | $this->cache->connectTo($key); |
| | | } |
| | | $this->perPage = $perPage; |
| | | $this->cache = Cache::for('directory', WEEK_IN_SECONDS); |
| | | $this->cache->connect('post', true) |
| | | ->connect('taxonomy', true) |
| | | ->connect('user', true); |
| | | |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | | } |
| | | |
| | | add_action('init', [$this, 'registerDirectories']); |
| | | jvb_register_do_once('directories_registered', [$this, 'activate']); |
| | | |
| | | add_action('init', [$this, 'registerDirectories']); |
| | | add_action('render_block', [$this, 'renderBlock'], 99999, 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('sort-ascending'), |
| | | '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 = (array_key_exists('directory_label', JVB_SITE)) ? JVB_SITE['directory_label'][0] : 'Directory'; |
| | | $plural = (array_key_exists('directory_label', JVB_SITE)) ? JVB_SITE['directory_label'][1] : '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 getDirectories():array |
| | |
| | | |
| | | } |
| | | |
| | | public function activate() |
| | | public static function activate() |
| | | { |
| | | $tmp = new self(); |
| | | $tmp->registerDirectories(); |
| | | |
| | | $created = []; |
| | | $directories = []; |
| | | |
| | | foreach($this->directories as $directory => $type) { |
| | | $config = $this->getConfigFromType($directory); |
| | | $title = $config['directory']??$config['plural']; |
| | | foreach($tmp->directories as $directory => $type) { |
| | | $config = $tmp->getConfigFromType($directory); |
| | | $title = $tmp->directoryTitle($config); |
| | | $excerpt = implode(' ', $config['description']??[]); |
| | | $ID = wp_insert_post([ |
| | | 'post_type' => BASE.'directory', |
| | |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_home_url(null, '/directory/'.$slug), |
| | | 'url' => get_the_permalink($ID), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | |
| | | 'slug' => $slug, |
| | | 'title' => $title, |
| | | 'ID' => $ID, |
| | | 'url' => get_home_url(null, '/directory/'.$slug), |
| | | 'url' => get_the_permalink($ID), |
| | | 'page' => $title, |
| | | 'description' =>$config[$directory]['description']??[], |
| | | 'type' => $type, |
| | |
| | | } |
| | | } |
| | | |
| | | if (Features::forSite()->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_home_url(null, '/directory/map'), |
| | | 'page' => 'Map', |
| | | 'type' => 'term', |
| | | ]; |
| | | } |
| | | } |
| | | // if (Features::forSite()->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); |
| | |
| | | } |
| | | } |
| | | |
| | | 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) { |
| | | $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' => $this->getConfigFromType($post->post_name)['description']??'', |
| | | 'type' => get_post_meta($post->ID, self::$type,true), |
| | | 'extra' => $this->getConfigFromType($post->post_name)['directory_extra']??[], |
| | | ]; |
| | | } |
| | | update_option(BASE.'directory_list', $saved); |
| | | wp_reset_postdata(); |
| | | } |
| | | return $saved; |
| | | } |
| | | |
| | | public function getDirectoryPageIDs():array |
| | | { |
| | | if (empty($this->directoryPageIDs)) { |
| | |
| | | public function getDirectoryList():array |
| | | { |
| | | if (empty($this->directoryList)) { |
| | | $this->directoryList = get_option(BASE.'directory_list', []); |
| | | $this->directoryList = $this->buildDirectoryList(); |
| | | } |
| | | return $this->directoryList; |
| | | } |
| | |
| | | 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">'; |
| | | <ul class="directories">'; |
| | | foreach ($this->directoryList as $slug => $directory) { |
| | | $config = $this->getConfigFromType($slug); |
| | | $aOpen = '<a href="'.$directory['url'].'" title="See our list of '.$directory['title'].'">'; |
| | | $aClose = '</a>'; |
| | | $cache .= '<div class="directory col start"> |
| | | '.$aOpen.jvbIcon($config['icon']).$aClose. |
| | | '<h2>'.$aOpen.$directory['title'].$aClose.'</h2>'; |
| | | $cache .= '<li class="directory col start"> |
| | | '. $aOpen.jvbIcon(array_key_exists('icon', $config) ? $config['icon']:'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; |
| | | } |
| | | ); |
| | |
| | | ); |
| | | 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 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 ''; |
| | | } |
| | | $this->directories(); |
| | | return $this->cache->remember( |
| | | $slug, |
| | | function() use ($slug) { |
| | | $config = $this->getConfigFromType($slug); |
| | | $out = '<h1>'.$config['directory'].'</h1>'; |
| | | $out .= '<div class="description">'; |
| | | $type = $this->directories[$slug]; |
| | | $config = $this->getConfigFromType($slug); |
| | | |
| | | foreach ($config[$slug]['description']??[] as $p) { |
| | | $out .= '<p>'.$p.'</p>'; |
| | | } |
| | | $out .= '</div>'; |
| | | $out .= $this->renderIndex($slug); |
| | | $paged = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1; |
| | | |
| | | $type = $this->directories[$slug]; |
| | | $list = []; |
| | | switch ($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, $config, $paged) { |
| | | $out = '<h1>' . $this->directoryTitle($config) . '</h1>'; |
| | | $out .= '<div class="description">'; |
| | | foreach ($config[$slug]['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 (Features::forContent($slug)->has('is_timeline')) { |
| | | $args['post_parent'] = 0; |
| | | } |
| | | |
| | | $get = new WP_Query($args); |
| | | |
| | | $hasExtra = Features::forContent($slug)->has('directory_extra'); |
| | | if ($get->have_posts()) { |
| | |
| | | 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, |
| | | '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, |
| | |
| | | wp_reset_postdata(); |
| | | break; |
| | | 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)) { |
| | |
| | | |
| | | $list = $this->alphabetizeMe( |
| | | $list, |
| | | $term->name, |
| | | html_entity_decode($term->name), |
| | | get_term_link( $term->term_id, jvbCheckBase( $slug ) ), |
| | | $term->term_id, |
| | | $extra |
| | |
| | | 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>'; |
| | | |
| | |
| | | $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 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 |
| | | { |
| | |
| | | } |
| | | $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 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; |
| | | } |
| | | |
| | | protected function directoryTitle(array $config):string |
| | | { |
| | | return array_key_exists('directory', $config) ? $config['directory'] : $config['plural']; |
| | | } |
| | | |
| | | public function referAs($plural = false):string |
| | | { |
| | | if (!empty(JVB_SITE) && array_key_exists('directory_label', JVB_SITE)) { |
| | | return ($plural) ? JVB_SITE['directory_label'][1] : JVB_SITE['directory_label'][0]; |
| | | } |
| | | return ($plural) ? 'Directories' : '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 = []; |
| | | |
| | | switch ($type) { |
| | | case 'content': |
| | | global $wpdb; |
| | | $post_type = jvbCheckBase($slug); |
| | | |
| | | $where = $wpdb->prepare("post_type = %s AND post_status = 'publish'", $post_type); |
| | | if (Features::forContent($slug)->has('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; |
| | | } |
| | | } |