<?php
|
namespace JVBase\managers;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
use WP_Block;
|
use WP_Query;
|
|
class DirectoryManager
|
{
|
protected array $directories;
|
protected static string $type = BASE.'for_type';
|
protected static string $slug = BASE.'for_type_slug';
|
protected CacheManager $cache;
|
|
public function __construct()
|
{
|
$this->directories = jvbGlobalDirectoryInfo();
|
if (empty(jvbGlobalDirectories())) {
|
return;
|
}
|
$this->cache = new CacheManager('directory', WEEK_IN_SECONDS);
|
|
add_action('init', [$this, 'registerDirectories']);
|
jvb_register_do_once('directories_registered', [$this, 'activate']);
|
|
add_action('render_block', [$this, 'renderBlock'], 99, 3);
|
}
|
|
public function registerDirectories()
|
{
|
$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')
|
));
|
}
|
|
public function activate()
|
{
|
$created = [];
|
$directories = [];
|
|
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(2, '/directory/'.$slug),
|
'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(2, '/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(2, '/directory/map'),
|
'page' => 'Map',
|
'type' => 'term',
|
];
|
}
|
}
|
|
if (!empty($created)) {
|
update_option(BASE.'directory_ids', $created);
|
}
|
if (!empty($directories)) {
|
update_option(BASE.'directory_list', $directories);
|
}
|
}
|
|
public static function getConfig(int $ID):array
|
{
|
$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 [];
|
}
|
|
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'
|
];
|
}
|
|
protected 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;
|
}
|
|
private function renderArchive(): string
|
{
|
return $this->cache->remember(
|
'archive',
|
function() {
|
$cache = '<h1>Directory of Directories</h1>
|
<p>You like lists? We\'ve got \'em!</p>
|
<section class="directories item-grid">';
|
foreach ($this->directories as $slug => $directory) {
|
$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>';
|
if (!empty($directory['description'])) {
|
$cache .= '<div class="description">';
|
foreach ($directory['description'] as $description) {
|
$cache .= '<p>'.$description.'</p>';
|
}
|
$cache .= '</div>';
|
}
|
$cache .= '</div>';
|
}
|
$cache .= '</section>';
|
return $cache;
|
}
|
);
|
}
|
|
protected function renderIndex(string $current = '', bool $open = false):string
|
{
|
$cache = $this->cache->remember(
|
'index',
|
function() {
|
$cache = '<nav class="directory"><ul>';
|
foreach (jvbDirectories() as $slug => $directory) {
|
$cache .= '<li id="'.$slug.'">
|
<a href="'.$directory['url'].'">'.
|
jvbIcon(str_replace('-grouped', '', $slug)).$directory['title'].'
|
</a>
|
</li>';
|
}
|
$cache .= '</ul></nav>';
|
return $cache;
|
}
|
);
|
if ($current !== '' && array_key_exists($current, jvbDirectories())) {
|
$open = ($open) ? ' open' : '';
|
$cache = '<details'.$open.'><summary class="row btw">Other Directories:</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 '';
|
}
|
return $this->cache->remember(
|
$slug,
|
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);
|
|
$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'
|
]);
|
|
if ($get->have_posts()) {
|
while ( $get->have_posts() ) {
|
$get->the_post();
|
$extra = [];
|
foreach ( $data['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,
|
];
|
|
}
|
$list = $this->alphabetizeMe(
|
$list,
|
get_the_title(),
|
get_the_permalink(),
|
get_the_ID(),
|
$extra
|
);
|
}
|
}
|
}
|
wp_reset_postdata();
|
break;
|
case 'tax':
|
$get = get_terms([
|
'taxonomy' => jvbCheckBase($slug),
|
'hide_empty' => true,
|
'orderby' => 'name',
|
'order' => 'ASC',
|
]);
|
|
if ($get && !is_wp_error($get)) {
|
$extra = false;
|
foreach ($get as $term) {
|
|
$list = $this->alphabetizeMe(
|
$list,
|
$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;
|
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->renderLettersList($list, $slug);
|
}
|
$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() {
|
$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 btw"><a href="'.get_term_link($term->term_id, $term->taxonomy).'" title="See more '.$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 .= '</li>';
|
}
|
$out .= '</ul>';
|
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>';
|
}
|
|
$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 a-start btw"><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>';
|
}
|
$out .= '<li class="row btw">
|
<a href="'.$item['url'].'" title="More about '.$item['name'].'">
|
'.$item['name'].'</a>'.$extra.
|
'</li>';
|
|
}
|
$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;
|
}
|
|
|
// 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;
|
}
|
|
// 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;
|
}
|
}
|
|
new DirectoryManager();
|
|
function jvbDirectoryConfig():array
|
{
|
$ID = get_the_ID();
|
if ($ID) {
|
return DirectoryManager::getConfig($ID);
|
}
|
return [];
|
}
|