<?php
|
namespace JVBase\managers;
|
|
if (!defined('ABSPATH')) {
|
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 Cache $cache;
|
|
public function __construct($perPage = 100)
|
{
|
$this->directories = $this->getDirectories();
|
if (empty($this->directories)) {
|
return;
|
}
|
$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();
|
}
|
|
jvb_register_do_once('buildDirectories', [$this, 'activate']);
|
add_action('init', [$this, 'registerDirectories']);
|
add_filter('render_block', [$this, 'renderBlock'], 998, 3);
|
}
|
|
public function registerDirectories():void
|
{
|
|
$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 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;
|
}
|
|
$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 (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);
|
}
|
if (!empty($directories)) {
|
update_option(BASE.'directory_list', $directories);
|
}
|
}
|
|
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
|
{
|
$slug = get_post_meta($ID, self::$slug, true);
|
return Registrar::getInstance($slug);
|
}
|
|
public function letters():array
|
{
|
return [
|
'a',
|
'b',
|
'c',
|
'd',
|
'e',
|
'f',
|
'g',
|
'h',
|
'i',
|
'j',
|
'k',
|
'l',
|
'm',
|
'n',
|
'o',
|
'p',
|
'q',
|
'r',
|
's',
|
't',
|
'u',
|
'v',
|
'w',
|
'x',
|
'y',
|
'z'
|
];
|
}
|
|
public function alphabetizeMe(
|
array $list,
|
string $name = '',
|
string $url = '',
|
string $ID = '',
|
$extra = false
|
):array {
|
if ($name == '') {
|
$name = get_the_title();
|
}
|
if ($url == '') {
|
$url = get_the_permalink();
|
}
|
if ($ID == '') {
|
$ID = get_the_ID();
|
}
|
|
$first = strtolower(mb_substr($name, 0, 1));
|
$list[$first][] = array(
|
'name' => $name,
|
'url' => $url,
|
'id' => $ID,
|
'extra' => $extra,
|
);
|
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>'.$this->referAs().' of '.$this->referAs(true).'</h1>
|
<p>You like lists? We\'ve got \'em!</p>
|
<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 .= '<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 .= '<p>'.$description.'</p>';
|
}
|
$cache .= '</div>';
|
}
|
$cache .= '</li>';
|
}
|
$cache .= '</ul>';
|
return $cache;
|
}
|
);
|
}
|
|
protected function renderIndex(string $current = '', bool $open = false):string
|
{
|
$cache = $this->cache->remember(
|
'index',
|
function() {
|
$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'].'" class="'.$actualSlug.'">'.
|
$icon.$directory['title'].'
|
</a>
|
</li>';
|
}
|
$cache .= '</ul></nav>';
|
return $cache;
|
}
|
);
|
if ($current !== '' && array_key_exists($current, $this->directories())) {
|
$open = ($open) ? ' open' : '';
|
$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
|
{
|
$slug = get_post_meta(get_the_ID(), self::$slug, true);
|
if ($slug === '') {
|
return '';
|
}
|
|
$type = $this->directories[$slug];
|
$registrar = Registrar::getInstance($slug);
|
$config = $registrar->getConfig('directory');
|
|
$paged = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
|
$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 = [];
|
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 ) : 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
|
);
|
}
|
}
|
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',
|
'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 = [];
|
foreach ($get as $term) {
|
|
$list = $this->alphabetizeMe(
|
$list,
|
html_entity_decode($term->name),
|
get_term_link( $term->term_id, jvbCheckBase( $slug ) ),
|
$term->term_id,
|
$extra
|
);
|
}
|
}
|
break;
|
case 'user':
|
$get = get_users([
|
'role' => jvbCheckBase($slug),
|
'orderby' => 'display_name',
|
'order' => 'ASC',
|
]);
|
|
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, $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>';
|
|
$out .= $this->renderIndex($slug, true);
|
return $out;
|
}
|
);
|
}
|
|
private function renderGroupedDirectory():string
|
{
|
$slug = get_post_meta(get_the_ID(), self::$slug, true);
|
if ($slug === '') {
|
return '';
|
}
|
return $this->cache->remember(
|
$slug.'_group',
|
function() use ($slug){
|
$out = '<h1>'.$this->directories[$slug]['title'].'</h1>';
|
$out .= '<div class="description">';
|
|
foreach ($this->directories[$slug]['description']??[] as $p) {
|
$out .= '<p>'.$p.'</p>';
|
}
|
$out .= '</div>';
|
$out .= $this->renderIndex($slug);
|
|
|
$taxonomy = str_replace('-grouped', '', $slug);
|
$tax = jvbCheckBase($taxonomy);
|
$list = $this->renderListChunk($tax, 0);
|
if ($list !== '') {
|
$out .= '<section class="directory-list '.$taxonomy.' grouped">'.$list.'</section>';
|
} else {
|
$out .= '<h2>Nothing here.</h2><p>We don\'t have anything here yet.</p>';
|
}
|
|
$out .= $this->renderIndex($slug, true);
|
return $out;
|
}
|
);
|
}
|
|
protected function renderListChunk(string $taxonomy, int $parent):string
|
{
|
$get = get_terms([
|
'taxonomy' => jvbCheckBase(str_replace('-grouped', '', $taxonomy)),
|
'hide_empty' => true,
|
'orderby' => 'name',
|
'order' => 'ASC',
|
'parent' => $parent
|
]);
|
|
if (!$get || is_wp_error($get)) {
|
return '';
|
}
|
$out = '<ul class="grouped-directory">';
|
foreach ($get as $term) {
|
$children =$this->renderListChunk($taxonomy, $term->term_id);
|
$out .= '<li>';
|
if ($children !== '') {
|
$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.'">'.html_entity_decode($term->name).'</a>';
|
}
|
$out .= '</li>';
|
}
|
$out .= '</ul>';
|
return $out;
|
}
|
|
public function renderLettersIndex(array $list, string $type = '', string $slug = ''): string
|
{
|
$letters_on_page = array_keys($list);
|
$letterPageMap = [];
|
|
if ($type !== '' && $slug !== '') {
|
$letterPageMap = $this->getLetterPageMap($type, $slug);
|
}
|
|
$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
|
{
|
|
$umami = JVB()->connect('umami');
|
|
$out = '<ul class="list-none">';
|
foreach ($list as $letter => $items) {
|
$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>';
|
foreach ($item['extra'] as $ext) {
|
$umamiType = ($ext['type'] === BASE.'shop') ? 'click_shop' : 'click_taxonomy';
|
$extra .= '<a href="'.$ext['url'].'"'.$umami->trackContentClick($item['id'],$umamiType, ['source_type' => 'directory']).'>'.$ext['name'].'</a>';
|
}
|
$extra .= '</span>';
|
}
|
|
$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>';
|
}
|
$out .= $item_html;
|
|
}
|
$out .= '</ul></li>';
|
}
|
$out .= '</ul>';
|
return $out;
|
}
|
|
public function renderBlock(string $content, array $block, WP_Block $instance)
|
{
|
if (!is_post_type_archive(BASE.'directory') && !is_singular(BASE.'directory')) {
|
return $content;
|
}
|
if ($block['blockName'] !== 'core/post-content' && ($block['blockName'] !== 'core/group')) {
|
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']??'' === '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>';
|
case 'yup':
|
return '<main>' . $this->renderGroupedDirectory() . '</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;
|
}
|
}
|