| | |
| | | <?php |
| | | namespace JVBase\managers\SEO; |
| | | |
| | | use JVBase\managers\CacheManager; |
| | | use JVBase\utility\Features; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\base\Site; |
| | | use WP_Post; |
| | | use WP_Term; |
| | | |
| | |
| | | */ |
| | | class BreadcrumbManager |
| | | { |
| | | private CacheManager $cache; |
| | | private Cache $cache; |
| | | private static ?self $instance = null; |
| | | |
| | | private function __construct() |
| | | { |
| | | $this->cache = CacheManager::for('breadcrumbs', MONTH_IN_SECONDS)->connectTo('all'); |
| | | $this->cache = Cache::for('breadcrumbs', MONTH_IN_SECONDS)->connect('post')->connect('taxonomy')->connect('user'); |
| | | $this->cache->flush(); |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | | } |
| | | } |
| | | |
| | | public static function getInstance(): self |
| | |
| | | break; |
| | | } |
| | | |
| | | $crumbs = $this->cache->get($key); |
| | | if ($crumbs !== false) { |
| | | return $crumbs; |
| | | } |
| | | |
| | | $crumbs = $this->buildCrumbs(); |
| | | $crumbs = apply_filters('jvbBreadcrumbs',$crumbs); |
| | | $this->cache->set($key, $crumbs); |
| | | |
| | | return $crumbs; |
| | | return $this->cache->remember( |
| | | $key, |
| | | function() { |
| | | $crumbs = $this->buildCrumbs(); |
| | | return apply_filters('jvbBreadcrumbs',$crumbs); |
| | | } |
| | | ); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | // Always start with home |
| | | $crumbs[] = [ |
| | | 'name' => 'Home', |
| | | 'name' => get_bloginfo('name'), |
| | | 'icon' => jvbIcon('house'), |
| | | 'url' => get_home_url(), |
| | | ]; |
| | |
| | | $crumbs = $this->addTaxonomyCrumbs($crumbs, $obj); |
| | | } elseif (is_singular()) { |
| | | $crumbs = $this->addArchiveCrumbs($crumbs, $obj); |
| | | $crumbs = $this->addSingularCrumbs($crumbs, $obj); |
| | | $hierarchy = $this->addSingularCrumbs($crumbs, $obj); |
| | | $crumbs = $crumbs + $hierarchy; |
| | | } elseif (is_post_type_archive() && !is_post_type_archive(BASE.'dash')) { |
| | | $crumbs = $this->addArchiveCrumbs($crumbs, $obj); |
| | | } |
| | |
| | | private function addTaxonomyCrumbs(array $crumbs, WP_Term $term): array |
| | | { |
| | | $tax = jvbNoBase($term->taxonomy); |
| | | $config = Features::getConfig($tax, 'term'); |
| | | |
| | | $registrar = Registrar::getInstance($tax); |
| | | // Add parent content archive if taxonomy is for single content type |
| | | if (count($config['for_content']) === 1) { |
| | | $contentConfig = JVB_CONTENT[$config['for_content'][0]]; |
| | | $crumbs[] = [ |
| | | 'name' => $contentConfig['breadcrumb'] ?? $contentConfig['plural'], |
| | | 'url' => get_post_type_archive_link(jvbCheckBase($config['for_content'][0])), |
| | | ]; |
| | | $crumbs[] = [ |
| | | 'name' => 'By ' . $config['singular'], |
| | | 'url' => false, |
| | | ]; |
| | | if ($registrar) { |
| | | if (count($registrar->registrar->for) === 1){ |
| | | $content = is_array($registrar->registrar->for) ? $registrar->registrar->for[0] : $registrar->registrar->for; |
| | | $contentRegistrar = Registrar::getInstance($content); |
| | | |
| | | $crumbs[] = [ |
| | | 'name' => $contentRegistrar->getConfig('breadcrumbs')['title']??$contentRegistrar->getPlural(), |
| | | 'url' => get_post_type_archive_link(jvbCheckBase($content)), |
| | | ]; |
| | | // $crumbs[] = [ |
| | | // 'name' => 'By ' . $registrar->getSingular(), |
| | | // 'url' => false, |
| | | // ]; |
| | | } |
| | | } |
| | | |
| | | |
| | | // Add directory if exists |
| | | if (Features::forTaxonomy($tax)->has('directory')) { |
| | | $directory = jvbDirectories($tax); |
| | | $crumbs[] = [ |
| | | 'name' => $directory['title'], |
| | | 'url' => $directory['url'] |
| | | ]; |
| | | if ($registrar && $registrar->hasFeature('directory')) { |
| | | $directory = JVB()->directories(); |
| | | if ($directory && !empty($directory->directories($tax))) { |
| | | $crumbs[] = [ |
| | | 'name' => $directory['title'], |
| | | 'url' => $directory['url'] |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | // Add term hierarchy |
| | | $crumbs = array_merge($crumbs, $this->buildTermHierarchy($term)); |
| | | |
| | | return $crumbs; |
| | | return array_merge($crumbs, $this->buildTermHierarchy($term)); |
| | | } |
| | | |
| | | /** |
| | |
| | | private function addSingularCrumbs(array $crumbs, WP_Post $post): array |
| | | { |
| | | // Add directory if exists |
| | | $directory = jvbDirectories(jvbNoBase($post->post_type)); |
| | | if (!empty($directory)) { |
| | | $crumbs[] = [ |
| | | 'name' => $directory['title'], |
| | | 'url' => $directory['url'] |
| | | ]; |
| | | $content = jvbNoBase($post->post_type); |
| | | $registrar = Registrar::getInstance($content); |
| | | $crumbConfig = false; |
| | | if ($registrar){ |
| | | $crumbConfig = $registrar->getConfig('breadcrumbs'); |
| | | } |
| | | |
| | | if($registrar && $registrar->hasFeature('show_directory')) { |
| | | $directory = JVB()->directories(); |
| | | if ($directory && !empty($directory->directories($content)??[])){ |
| | | $crumbs[] = [ |
| | | 'name' => $directory->directories($content)['title'], |
| | | 'url' =>$directory->directories($content)['url'] |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | // Handle directory posts specially |
| | | if (jvbIsDirectory()) { |
| | | if (JVB()->directories() && JVB()->directories()->isDirectory()) { |
| | | $pos = jvbGetDirectoryInfo(); |
| | | if (!empty($pos)) { |
| | | // Special case for map |
| | | if ($pos['title'] == 'Map') { |
| | | $crumbs[] = [ |
| | | 'name' => 'Tattoo Shops', |
| | | 'url' => jvbDirectories(BASE.'shop')['url'] |
| | | 'url' => JVB()->directories()->directories(BASE.'shop')['url'] |
| | | ]; |
| | | } |
| | | |
| | |
| | | ]; |
| | | } |
| | | } else { |
| | | |
| | | if ($registrar && !empty($crumbConfig['addCrumb'])) { |
| | | $crumbs = $this->addTaxToCrumbs($crumbs, $crumbConfig['addCrumb']); |
| | | } |
| | | // Add post hierarchy |
| | | $crumbs = array_merge($crumbs, $this->buildPostHierarchy($post)); |
| | | } |
| | |
| | | { |
| | | $type = is_singular() ? $obj->post_type : $obj->name; |
| | | $name = jvbNoBase($type); |
| | | if (array_key_exists($name, JVB_CONTENT)) { |
| | | |
| | | $registrar = Registrar::getInstance($name); |
| | | if (Site::has('is_directory') && $name === 'directory') { |
| | | $crumbs[] = [ |
| | | 'name' => JVB_CONTENT[$name]['breadcrumb'] ?? JVB_CONTENT[$name]['plural'], |
| | | 'name' => JVB()->directories()->referAs(true), |
| | | 'url' => get_post_type_archive_link($type) |
| | | ]; |
| | | } elseif (is_post_type_archive() && $registrar && $registrar->hasFeature('show_directory')) { |
| | | |
| | | $crumbs[] = [ |
| | | 'name' => $registrar->getConfig('breadcrumbs')['title'] ?? $registrar->getPlural(), |
| | | 'url' => get_post_type_archive_link($type) |
| | | ]; |
| | | } |
| | |
| | | { |
| | | $url = get_term_link($term->term_id); |
| | | array_unshift($crumbs, [ |
| | | 'name' => $term->name, |
| | | 'name' => html_entity_decode($term->name), |
| | | 'url' => $url, |
| | | 'id' => $term->term_id, |
| | | ]); |
| | |
| | | $items = []; |
| | | $position = 1; |
| | | |
| | | global $wp; |
| | | $current = home_url( add_query_arg( $_GET, $wp->request ) ); |
| | | foreach ($crumbs as $crumb) { |
| | | // Schema requires a URL |
| | | if ($crumb['url'] === false) { |
| | | $crumb['url'] = get_permalink(); |
| | | $crumb['url'] = $current; |
| | | } |
| | | |
| | | $items[] = [ |
| | | '@type' => 'ListItem', |
| | | 'position' => $position, |
| | | 'name' => $crumb['name'], |
| | | 'item' => $crumb['url'], |
| | | '@type' => 'ListItem', |
| | | '@id' => $crumb['url'], |
| | | 'position' => $position, |
| | | 'name' => $crumb['name'], |
| | | ]; |
| | | |
| | | $position++; |
| | |
| | | |
| | | return [ |
| | | '@type' => 'BreadcrumbList', |
| | | '@id' => get_permalink() . '/#breadcrumbs', |
| | | '@id' => $current . '/#breadcrumbs', |
| | | 'itemListElement' => $items |
| | | ]; |
| | | } |
| | |
| | | public function invalidateCache(?int $objectId = null): void |
| | | { |
| | | if ($objectId) { |
| | | $this->cache->delete($objectId); |
| | | $this->cache->forget($objectId); |
| | | } else { |
| | | $this->cache->clear(); |
| | | $this->cache->flush(); |
| | | } |
| | | } |
| | | |
| | | public function addTaxToCrumbs(array $crumbs, string|array $taxonomy):array |
| | | { |
| | | $ID = get_the_ID(); |
| | | $taxonomies = is_string($taxonomy) ? [$taxonomy] : $taxonomy; |
| | | foreach ($taxonomies as $tax) { |
| | | $taxonomy = jvbCheckBase($tax); |
| | | $terms = get_the_terms($ID, $taxonomy); |
| | | if ($terms && !is_wp_error($terms)) { |
| | | $term = $terms[0]; |
| | | $ancestors = get_ancestors($term->term_id, $taxonomy, 'taxonomy'); |
| | | $ancestors = array_reverse($ancestors); |
| | | foreach ($ancestors as $ancestor) { |
| | | $aTerm = get_term($ancestor, $taxonomy); |
| | | if ($aTerm && !is_wp_error($aTerm)) { |
| | | $crumbs[] = [ |
| | | 'name' => $aTerm->name, |
| | | 'url' => get_term_link($ancestor, $taxonomy) |
| | | ]; |
| | | } |
| | | } |
| | | $crumbs[] = [ |
| | | 'name' => html_entity_decode($term->name), |
| | | 'url' => get_term_link($term, $taxonomy) |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | return $crumbs; |
| | | } |
| | | } |