From 46d681c6b825d21b3f698d793c4e630c687d90ad Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 21 May 2026 21:41:53 +0000
Subject: [PATCH] =Major CustomBlocks.php overhaul, expanding block support and customization from the editor. theme.json should now be updated on new themes to set brand colours, etc. Also note: major change to .col vs .row alignment: simplifying it to .top .bottom vs the confusion of the differences for .col/.row .start and .a-start
---
inc/managers/DirectoryManager.php | 854 ++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 609 insertions(+), 245 deletions(-)
diff --git a/inc/managers/DirectoryManager.php b/inc/managers/DirectoryManager.php
index a8b7a43..c81010d 100644
--- a/inc/managers/DirectoryManager.php
+++ b/inc/managers/DirectoryManager.php
@@ -5,157 +5,229 @@
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('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 = 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.'dash',
+ '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);
@@ -165,20 +237,55 @@
}
}
- 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
{
@@ -212,7 +319,7 @@
];
}
- protected function alphabetizeMe(
+ public function alphabetizeMe(
array $list,
string $name = '',
string $url = '',
@@ -239,20 +346,35 @@
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) {
@@ -260,9 +382,9 @@
}
$cache .= '</div>';
}
- $cache .= '</div>';
+ $cache .= '</li>';
}
- $cache .= '</section>';
+ $cache .= '</ul>';
return $cache;
}
);
@@ -273,11 +395,14 @@
$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>';
}
@@ -285,90 +410,119 @@
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
@@ -384,17 +538,20 @@
]);
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>';
@@ -412,7 +569,7 @@
}
return $this->cache->remember(
$slug.'_group',
- function() {
+ function() use ($slug){
$out = '<h1>'.$this->directories[$slug]['title'].'</h1>';
$out .= '<div class="description">';
@@ -456,11 +613,11 @@
$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>';
}
@@ -468,23 +625,41 @@
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
{
@@ -493,7 +668,7 @@
$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'])) {
@@ -504,10 +679,16 @@
}
$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>';
@@ -525,15 +706,14 @@
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>';
@@ -544,16 +724,200 @@
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 [];
-}
-
--
Gitblit v1.10.0