From 56a9a1ccf764ff7a6af8f8a2292cb07443cb4aa7 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 28 May 2026 18:19:57 +0000
Subject: [PATCH] =New Gitbit setpu
---
inc/blocks/FeedBlock.php | 932 +++++++++++++++++++++++++++++++++-------------------------
1 files changed, 528 insertions(+), 404 deletions(-)
diff --git a/inc/blocks/FeedBlock.php b/inc/blocks/FeedBlock.php
index c6b1f0b..3ed2f38 100644
--- a/inc/blocks/FeedBlock.php
+++ b/inc/blocks/FeedBlock.php
@@ -5,6 +5,7 @@
use JVBase\registrar\Registrar;
use JVBase\base\Site;
use JVBase\forms\TaxonomySelector;
+use JVBase\ui\CRUDSkeleton;
use WP_Block;
if (!defined('ABSPATH')) {
@@ -17,13 +18,17 @@
protected array $config;
protected string $path = JVB_DIR.'/build/feed';
+ protected array $content = [];
+ protected array $taxonomies = [];
+ protected bool $isGallery = false;
+
public function __construct()
{
// Initialize cache with connections
$this->cache = Cache::for('feed_block', WEEK_IN_SECONDS);
-// if (JVB_TESTING) {
-// $this->cache->flush();
-// }
+ if (JVB_TESTING) {
+ $this->cache->flush();
+ }
add_action('init', [$this, 'registerBlock']);
}
@@ -35,385 +40,483 @@
]);
}
- protected function buildParams(array $attributes): array
- {
- if (!jvbCheck('inheritQuery', $attributes)) {
- return [
- 'title' => $attributes['title'],
- 'content' => $attributes['contentTypes'],
- 'taxonomies' => $this->getTaxonomies($attributes['contentTypes'])
- ];
- }
- $config = [
- 'is_gallery' => false,
- 'content' => '',
- 'taxonomies' => []
- ];
- $type = get_queried_object();
-
- if (is_post_type_archive() || is_singular()) {
- $content = is_singular() ? jvbNoBase($type->post_type) : jvbNoBase($type->name);
-
- $registrar = Registrar::getInstance($content)??false;
- if ($registrar) {
- $config = array_merge($config, $registrar->getConfig('feed'));
- } else {
- $config['content'] = $content;
- $config['icon'] = jvbDefaultIcon();
- }
- if (is_singular()) {
- $config['source'] = $type->ID;
- }
-
- $config['taxonomies'] = $this->getTaxonomies([$content]);
- } elseif (is_tax()) {
- $content = jvbNoBase($type->taxonomy);
- $registrar = Registrar::getInstance($content)??false;
- if ($registrar) {
- $config['content'] = $registrar->registrar->for;
- $config['context'] = $content;
- $config['taxonomies'] = $this->getTaxonomies($registrar->registrar->for);
- if (!empty($registrar->getConfig('feed'))){
- $config = array_merge($config, $registrar->getConfig('feed'));
- }
- }
- $config['source'] = $type->term_id;
- }
-
- if (!is_array($config['content'])) {
- $config['content'] = [$config['content']];
- }
-
- return $config;
- }
-
- /**
- * Get taxonomies for given content types
-
- */
- protected function getTaxonomies(array $content): array
- {
-
- $taxonomies = [];
-
- foreach ($content as $contentType) {
- $registrar = Registrar::getInstance($contentType);
- if (!$registrar) {
- continue;
- }
- $contentTaxonomies = $registrar->registrar->taxonomies;
- $contentTaxonomies = array_filter($contentTaxonomies, function($taxonomy) {
- return Registrar::getInstance($taxonomy)?->hasFeature('show_feed');
- });
- $taxonomies = array_merge($taxonomies, $contentTaxonomies);
- }
-
- return array_unique($taxonomies);
- }
-
- public function render(array $attributes, string $content, WP_Block $block)
- {
-
- $this->config = $this->buildParams($attributes);
- return $this->cache->remember(
- $this->cache->generateKey($this->config),
- function() {
- return $this->renderBlock();
- }
- );
- }
- protected function getContext():string|bool
- {
- return array_key_exists('context', $this->config)?$this->config['context']:false;
- }
- protected function getIDS():array|bool
- {
- return (array_key_exists('ids', $this->config) && !empty($this->config['ids'])) ? $this->config['ids'] : false;
- }
- protected function getClasses():array|bool
- {
- return array_key_exists('classes', $this->config) && !empty($this->config['classes']) ? $this->config['classes'] : false;
- }
- protected function getSource():string|bool
- {
- return array_key_exists('source', $this->config) ? $this->config['source'] : false;
- }
-
- protected function getIcon():string|bool
- {
- return array_key_exists('icon', $this->config) ? $this->config['icon'] : false;
- }
- protected function isGallery():bool
- {
- return (array_key_exists('is_gallery', $this->config) && $this->config['is_gallery']);
- }
- protected function getContent():array|bool
- {
- return (array_key_exists('content', $this->config) && !empty ($this->config['content'])) ? $this->config['content'] : false;
- }
-
- protected function renderBlock(): string
+ public function render(array $attributes): string
{
if (is_post_type_archive(BASE.'directory')) {
return '';
}
- $ids = ($this->getIDS()) ? ' id="'.implode(' ',$this->getIDS()).'"' : '';
- $classes = ($this->getClasses()) ? ' class="'.implode(' ',$this->getClasses()).'"' : '';
- $source = ($this->getSource()) ? ' data-source="'.$this->getSource().'"' : '';
- $context = ($this->getContext()) ? ' data-context="'.$this->getContext().'"' : '';
- $icons = ($this->getIcon()) ? ' data-icon="'.$this->getIcon().'"' : ' data-icon="'.jvbLogoIcon().'"';
- $gallery = $this->isGallery() ? ' data-gallery' : '';
- $content = ($this->getContent()) ? ' data-content="'.implode(',',$this->getContent()).'"' : '';
- ob_start();
- ?>
- <section<?= $ids.$classes ?> class="feed-block"<?= $content.$source.$context.$gallery.$icons ?>>
- <?php
- $this->renderFilters();
- $this->renderGrid();
- $this->renderLoader();
- $this->renderTemplates();
- echo TaxonomySelector::outputSelectorModal();
- ?>
- </section>
- <footer><button data-action="refresh" data-ignore><?=jvbIcon('arrows-clockwise')?><span>Hard Refresh</span></span></button></footer>
- <?php
- return ob_get_clean();
+ $this->determineContent($attributes);
+ if (empty($this->content)) {
+ return '';
+ }
+ $this->determineTaxonomies();
+ $classes = '';
+
+ return sprintf(
+ '<section class="feed-block%s" data-content="%s"%s>
+ %s%s%s%s%s
+ <footer>%s</footer>
+ </section>',
+ $classes,
+ $this->getContent(),
+ $this->isGallery ? ' data-gallery' : '',
+ $this->renderFiltersAndControls(),
+ $this->renderGrid(),
+ $this->renderTemplates(),
+ $this->renderLoader(),
+ TaxonomySelector::outputSelectorModal(),
+ $this->renderActions()
+ );
}
- protected function renderFilters(): void
+ protected function determineContent(array $attrs):void
{
- if (empty($this->config)) {
- return;
+ if (array_key_exists('inheritQuery', $attrs) && $attrs['inheritQuery'] === true) {
+ if (is_post_type_archive()) {
+ $obj = get_queried_object();
+ $this->content = [jvbNoBase($obj->name)];
+ return;
+ } elseif (!empty(Registrar::getProfileTypes()) && is_singular(Registrar::getProfileTypes())) {
+ global $post;
+ $author = $post->post_author;
+ $role = jvbUserRole($author);
+ $registrar = Registrar::getInstance($role);
+ if (!$registrar) {
+ return;
+ }
+ $this->content = $registrar->getCreatable();
+ return;
+ } elseif (is_tax()) {
+ $obj = get_queried_object();
+ $registrar = Registrar::getInstance($obj->taxonomy);
+ if (!$registrar) {
+ return;
+ }
+ if ($registrar->hasFeature('is_content')) {
+ //example: tattoo shop, etc TODO
+ return;
+ }
+ $this->content = array_map(function ($item) { return jvbNoBase($item); }, $registrar->registrar->for);
+ return;
+ }
}
+ // not inheriting, getting from config
+ $this->content = $attrs['contentTypes']??[];
+ }
+ protected function getContent():string
+ {
+ return implode(',', $this->content);
+ }
+ protected function determineTaxonomies():void
+ {
+ $taxonomies = [];
+ $ignore = [];
+ foreach ($this->content as $content) {
- $feedContent = $this->getFeedContent();
- $hasMany = count($this->getContent()) > 1;
- ?>
- <form class="filters" data-save="feed-<?=$this->getContext()?>">
- <?php if ($hasMany) {
- //If we have multiple content, only show the content first
- ?>
- <details class="col left">
- <summary class="row x-btw">
- <span class="label">SHOWING: </span>
- <?php
- $labels = [];
- foreach ($this->getContent() as $i => $type) :
-
- $checked = $i === 0 ? ' checked' : '';
- $label = $feedContent[$type]['plural'] ?? ucfirst($type);
- ?>
- <input type="radio"
- id="filter-<?= esc_attr($type) ?>"
- class="btn"
- name="content"
- data-filter="content"
- value="<?= esc_attr($type) ?>"
- <?= $checked ?>>
- <label for="filter-<?= esc_attr($type) ?>" title="Show <?= $label ?>" class="row">
- <?= jvbIcon($feedContent[$type]['icon']) ?>
- <span class="screen-reader-text"><?= $label ?></span>
- </label>
- <?php
- $labels['filter-'.$type] = $label;
- endforeach;
- ?>
- <ul class="filter-label">
- <?php
- $i = 0;
- foreach ($labels as $id => $label) {
- $active = $i === 0 ? ' class="active"' : '';
- ?>
- <li id="<?= $id ?>"<?= $active ?>>
- <?= $label ?>
- </li>
- <?php
- $i++;
+ $registrar = Registrar::getInstance($content);
+ if (!$registrar) continue;
+ $theTax = $registrar->registrar->taxonomies;
+ foreach ($theTax as $tax) {
+ if (!in_array($tax, $ignore) && !in_array($tax, $taxonomies)) {
+ $taxReg = Registrar::getInstance($tax);
+ if ($taxReg->hasFeature('show_feed')) {
+ $taxonomies[] = $tax;
+ } else {
+ $ignore[] = $tax;
}
- ?>
- </ul>
- <?php } ?>
-
-
- <?php if (Site::has('favourites') && is_user_logged_in()) : ?>
- <input type="checkbox" id="favourites" class="btn" name="favourites" value="on"
- data-filter="favourites">
- <label for="favourites" title="Show Favourites" class="row">
- <?= jvbIcon('heart').jvbIcon('heart', ['style' => 'fill']) ?>
- <span class="screen-reader-text">Show Favourites Only</span>
- </label>
- <?php endif; ?>
- <?php if ($hasMany) { ?>
- </summary>
- <?php }
- if (!empty ($this->config['taxonomies'])) {
- ?>
- <div class="filters">
- <div class="filter-group row left">
- <span class="label">FILTER BY:</span>
-
- <?php
- foreach ($this->config['taxonomies'] as $tax) :
- $registrar = Registrar::getInstance($tax)??false;
- if (!$registrar) continue;
-
- $contentForTax = $registrar->registrar->for;
- $hidden = empty($contentForTax) ? ' hidden' : '';
-
- $taxSelector = new TaxonomySelector(
- 'feed-'.$tax,
- $tax,
- [
- 'icon' => $registrar->getIcon()??jvbLogoIcon(),
- 'update' => '.selected-items-section .selected-items',
- 'types' => $contentForTax,
- 'autocomplete' => false,
- 'hidden' => $hidden,
- 'output' => 'minimal'
- ]
- );
- echo $taxSelector->render();
- endforeach;
- ?>
- </div>
- <div class="selected-items-section">
- <div class="selected-items row"></div>
- <div class="filter-actions row">
- <?= str_replace('class="toggle-text"', 'class="toggle-text" hidden', jvbRenderToggleTextField('match', 'Match', 'Filters', 'ALL', 'ANY', false, ['filter' => 'match'])) ?>
- <button type="button" class="clear-filters row" hidden>
- <?= jvbIcon('x') ?>
- Clear All Filters
- </button>
- </div>
- </div>
- </div>
- <?php } ?>
- <div class="row x-btw nowrap">
- <div class="order-by filter-group row left w-full">
- <span class="label">ORDER BY:</span>
- <?php
- //TODO: Get content types that can be sorted alphabetically
- ?>
- <input type="radio" id="order-title" class="btn" name="orderby" value="title" data-for="artist,shop" data-filter="orderby" hidden>
- <label for="order-title" title="Order by Name" class="row">
- <?= jvbIcon('alphabetical') ?>
- <span class="label">Name</span>
- </label>
-
- <input type="radio" id="order-date" class="btn" name="orderby" value="date" data-filter="orderby" checked>
- <label for="order-date" title="Order by Date Created" class="row">
- <?= jvbIcon('calendar', ['title' => 'Date']) ?>
- <span class="label">Date Created</span>
- </label>
-
- <input type="radio" id="order-modified" class="btn" name="orderby" value="modified" data-filter="orderby">
- <label for="order-modified" title="Order by Date Modified" class="row">
- <?= jvbIcon('clock-clockwise') ?>
- <span class="label">Date Modified</span>
- </label>
-
- <?php
- $custom = [];
- foreach ($this->getContent() as $content) {
- $registrar = Registrar::getInstance($content)??false;
-
- if ($registrar && !empty($registrar->config('feed')->getCustomOrder())) {
- $custom = array_merge_recursive($custom, $registrar->config('feed')->getCustomOrder());
- }
- }
- foreach ($custom as $slug => $conf) {
- ?>
- <input type="radio" id="order-<?=$slug?>" class="btn" name="orderby" value="<?=$slug?>" data-for="<?=$conf['for']?>" data-filter="orderby">
- <label for="order-<?=$slug?>" title="<?= $conf['label']?>" class="row">
- <?= jvbIcon($conf['icon']) ?>
- <span class="label"><?=$conf['label']?></span>
- </label>
- <?php
- }
- $custom = implode(',', array_keys($custom));
- ?>
- <input type="radio" id="order-random" class="btn" name="orderby" value="random" data-filter="orderby">
- <label for="order-random" title="Random Order" class="row">
- <?= jvbIcon('shuffle') ?>
- <span class="label">Random</span>
- </label>
-
- </div>
-
- <div class="order-direction filter-group row left w-full" data-for-order="date,modified,title<?= $custom === '' ? '' : ','.$custom?>">
- <span class="label">ORDER:</span>
- <input type="radio" id="order-desc" class="btn" name="order" value="desc" data-filter="order" checked>
- <label for="order-desc" title="Sort Descending (A-Z, 1-10)" class="row">
- <?= jvbIcon('sort-descending') ?>
- <span class="label" >DESC (A-Z)</span>
- </label>
-
- <input type="radio" id="order-asc" class="btn" name="order" value="asc" data-filter="order">
- <label for="order-asc" title="Sort Ascending (Z-A, 10-1)" class="row">
- <?= jvbIcon('sort-ascending') ?>
- <span class="label" >ASC (Z-A)</span>
- </label>
- </div>
- </div>
- <?php if ($hasMany) { ?>
- </details>
- <?php } ?>
- </form>
- <?php
- }
-
- protected function renderGrid(): void
- {
- ?>
- <div class="item-grid">
- <?php
- $total = count($this->getContent()) - 1;
- for ($i = 1; $i <= 36; $i++) {
- $rand = rand(0, $total);
- $config = Registrar::getInstance($this->getContent()[$rand]);
- $icon = jvbIcon($config->getIcon??jvbLogoIcon());
- ?>
- <div class="placeholder"><?=apply_filters('jvbFeedPlaceholder', $icon) ?></div>
- <?php
+ }
+ }
}
- ?>
- </div>
- <?php
- }
-
- protected function renderLoader(): void
- {
- ?>
- <button type="button" class="load-more">
- <?= jvbIcon('arrow-elbow-left-down') ?>
- Show Me More
- <?= jvbIcon('arrow-elbow-right-down') ?>
- </button>
-
- <?= jvbLoadingScreen() ?>
- <?php
- if (array_key_exists('is_gallery', $this->config)) {
- jvbRenderGallery();
- }
- }
-
- protected function renderTemplates(): void
- {
- if ($this->getContent()) {
- foreach ($this->getContent() as $content) {
- echo $this->getDefaultTemplate($content);
- }
+ $this->taxonomies = array_unique($taxonomies);
}
- echo '<template class="feedTerm"><button class="remove-term">'.jvbIcon(jvbDefaultIcon()).'<span></span>'.jvbIcon('x').'</button></template>';
- echo '<template class="emptyState">'.apply_filters('jvbFeedEmptyState', '<div class="empty-state">
- <h3>'.jvbIcon($this->getIcon()).'NOTHING HERE'.jvbIcon($this->getIcon()).'</h3>
+ protected function renderFiltersAndControls():string
+ {
+ return sprintf(
+ '<details class="all-filters col top left" data-ignore open>
+ <summary>Filters %s</summary>
+ %s%s%s%s%s
+ </details>
+ <button data-action="clear-filters" data-ignore hidden>%s<span>Clear Filters</span></span></button>',
+ $this->renderContentLabels(),
+ $this->renderSearch(),
+ $this->renderContent(),
+ $this->renderFilters(),
+ $this->renderOrderControls(),
+ $this->renderViewControls(),
+ jvbIcon('x')
+ );
+ }
+ protected function renderSearch():string
+ {
+ return sprintf(
+ '<div class="search row left nowrap">
+ <span class="label">Search:</span>
+ %s
+ </div>',
+ jvbSearch()
+ );
+ }
+ protected function renderContentLabels():string
+ {
+ $inside = '';
+ if (count($this->content) === 1) {
+ return '';
+ }
+ foreach ($this->content as $i => $type) {
+ $active = $i === 0 ? ' class="active"' : '';
+ $inside .= sprintf(
+ '<li id="filter-%s"%s>%s</li>',
+ $type,
+ $active,
+ Registrar::getInstance($type)->getPlural()??''
+ );
+ }
+ return sprintf(
+ '<ul class="filter-label">%s</ul>',
+ $inside
+ );
+ }
+ protected function renderContent():string
+ {
+ $favourites = '';
+ if (Site::has('favourites')) {
+ $favourites = sprintf(
+ '<input type="checkbox" id="favourites" class="btn" name="favourites" value="on" data-filter="favourites">
+ <label for="favourites" title="Show Favourites">%s%s<span class="screen-reader-text">Show Favourites Only</span></label>',
+ jvbIcon('heart'),
+ jvbIcon('heart', ['style' => 'fill'])
+ );
+ }
+ if (count($this->content) === 1) {
+ return empty($favourites)
+ ? sprintf(
+ '<input type="hidden" name="content" value="%s">',
+ implode(',', $this->content)
+ )
+ : sprintf(
+ '<div class="content row right">
+ <input type="hidden" name="content" value="%s">
+ %s
+ </div>',
+ implode(',', $this->content),
+ $favourites
+ );
+ }
+ $i = 0;
+ $content = implode('', array_map(function($type) use (&$i) {
+ $i++;
+ $registrar = Registrar::getInstance($type);
+ return sprintf(
+ '<input type="radio"
+ id="filter-%s"
+ class="btn"
+ name="content"
+ data-filter="content"
+ value="%s"%s>
+ <label for="filter-%s" title="Show %s">%s<span class="screen-reader-text">%s</span></label>',
+ $type,
+ $type,
+ $i === 0 ? ' checked' : '',
+ $type,
+ $registrar->getPlural(),
+ jvbIcon($registrar->getIcon()),
+ $registrar->getPlural()
+ );
+ }, $this->content));
+
+
+
+ return sprintf(
+ '<div class="content row left nowrap"><span class="label">Showing:</span>
+ %s%s
+ </div>',
+ $content,
+ $favourites
+ );
+ }
+
+ protected function renderFilters():string
+ {
+ if (empty ($this->taxonomies)) {
+ return '';
+ }
+ $inside = implode('', array_filter(array_map(function($tax) {
+ $registrar = Registrar::getInstance($tax);
+ if (!$registrar) return '';
+
+ $current = BASE.$this->content[0];
+ $contentFor = $registrar->registrar->for;
+ $hidden = in_array($current, $contentFor) ? '' : ' hidden';
+
+ $selector = new TaxonomySelector(
+ 'feed-'.$tax,
+ $tax,
+ [
+ 'icon' => $registrar->getIcon(),
+ 'update'=> '.selected-items-section .selected-items',
+ 'types' => $contentFor,
+ 'autocomplete' => false,
+ 'hidden' => $hidden,
+ 'output' => 'minimal',
+ 'search' => true
+ ]
+ );
+ return $selector->render();
+
+ }, $this->taxonomies)));
+ return sprintf(
+ '<div class="taxonomies row left">
+ <div class="row top nowrap">
+ <span class="label">Filter By:</span>
+ <div class="row left">%s</div>
+ </div>
+ <div class="selected-items-section">
+ <div class="selected-items row left"></div>
+ <div class="filter-actions row">
+ %s
+ <button type="button" class="clear-filters" hidden>
+ %s
+ <span>Clear All Filters</span>
+ </button>
+ </div>
+ </div>
+ </div>',
+ $inside,
+ str_replace('class="toggle-text"', 'class="toggle-text" hidden', jvbRenderToggleTextField('match', 'Match', 'Filters', 'ALL', 'ANY', false, ['filter' => 'match'])),
+ jvbIcon('x')
+ );
+ }
+
+ protected function renderOrderControls():string
+ {
+ $orderby = [
+ [
+ 'slug' => 'title',
+ 'icon' => 'alphabetical',
+ 'label' => 'Name'
+ ],
+ [
+ 'slug' => 'date',
+ 'icon' => 'calendar',
+ 'label' => 'Date Created',
+ ],
+ [
+ 'slug' => 'date_modified',
+ 'icon' => 'clock-clockwise',
+ 'label' => 'Date Modified'
+ ]
+ ];
+ $custom = $this->getCustomOrdering();
+ $orderby = $orderby + $custom;
+ $orderby[] = [
+ 'slug' => 'random',
+ 'icon' => 'shuffle',
+ 'label' => 'Randomly'
+ ];
+ $custom = implode(',', array_map(function($ord) {
+ return $ord['slug'];
+ }, $custom));
+
+ $i = 0;
+ $orderby = sprintf(
+ '<div class="orderby row left">
+ <span class="label">Order by:</span>%s
+ </div>',
+ implode('', array_map(function ($by) use (&$i){
+ $checked = $i === 0 ? ' checked' : '';
+ $i++;
+ return sprintf(
+ '<input type="radio" id="order-%s" class="btn" name="orderby" value="%s" data-filter="orderby"%s%s>
+ <label for="order-%s" title="Order %s">%s<span class="label">%s</span></label>',
+ $by['slug'],
+ $by['slug'],
+ $checked,
+ empty($by['for']??[]) ? '' : ' data-for="'.implode($by['for']).'"',
+ $by['slug'],
+ $by['slug'] === 'random' ? $by['label'] : 'by '.$by['label'],
+ jvbIcon($by['icon']),
+ $by['label']
+ );
+ }, $orderby))
+ );
+
+ $order = [
+ [
+ 'slug' => 'desc',
+ 'icon' => 'sort-descending',
+ 'label' => 'Descending (A-Z, 1-10)'
+ ],
+ [
+ 'slug' => 'asc',
+ 'icon' => 'sort-ascending',
+ 'label' => 'Ascending (Z-A, 10-1)'
+ ]
+ ];
+
+ $i = 0;
+ $order = sprintf(
+ '<div class="order-direction row left" data-for-order="date,date_modified,title%s">
+ <span class="label">Order:</span>
+ %s
+ </div>',
+ $custom === '' ? '' : ','.$custom,
+ implode('', array_map(function ($ord) use (&$i) {
+ $checked = $i=== 0 ? ' checked' : '';
+ $i++;
+ return sprintf(
+ '<input type="radio" id="order-%s" class="btn" name="order" value="%s" data-filter="order"%s>
+ <label for="order-%s" title="Sort %s">
+ %s
+ <span class="label">%s</span>
+ </label>',
+ $ord['slug'],
+ $ord['slug'],
+ $checked,
+ $ord['slug'],
+ $ord['label'],
+ jvbIcon($ord['icon']),
+ $ord['label']
+ );
+ }, $order))
+ );
+
+ return sprintf(
+ '<div class="ordering row left nowrap">%s%s</div>',
+ $orderby,
+ $order
+ );
+ }
+ protected function getCustomOrdering():array
+ {
+ $custom = [];
+ foreach ($this->content as $content) {
+ $registrar = Registrar::getInstance($content);
+ if (!$registrar || empty($registrar->config('feed')->getCustomOrder())) {
+ continue;
+ }
+ $custom = array_merge_recursive($custom, $registrar->config('feed')->getCustomOrder());
+ }
+ return $custom;
+ }
+ protected function renderViewControls():string
+ {
+ $views = [
+ 'grid' => ['slug' => 'grid', 'icon' => 'squares-four', 'label' => 'Grid View'],
+ 'list' => ['slug' => 'list', 'icon' => 'rows', 'label' => 'List View']
+ ];
+
+ $i = 0;
+ return sprintf(
+ '<div class="view row left nowrap"><span class="label">Switch View:</span>%s</div>',
+ implode('', array_map(function ($view) use (&$i) {
+ $checked = $i === 0 ? ' checked' : '';
+ $i++;
+ return sprintf(
+ '<input type="radio"
+ data-view="%s" value="%s" class="btn" name="view" id="view-%s"%s>
+ <label for="view-%s" title="%s">
+ %s<span class="label">%s</span>
+</label>',
+ $view['slug'],
+ $view['slug'],
+ $view['slug'],
+ $checked,
+ $view['slug'],
+ $view['label'],
+ jvbIcon($view['icon']),
+ $view['label'],
+ );
+ }, $views))
+ );
+ }
+
+ protected function renderGrid():string
+ {
+ $placeholders = '';
+ $total = count($this->content) - 1;
+ $icons = [];
+ $icon = apply_filters('jvbFeedPlaceholder', '');
+
+ for ($i=1; $i<=36; $i++) {
+ if (empty($icon)) {
+ $rand = $total === 0 ? $total : rand(0, $total);
+ $content = $this->content[$rand];
+ if (!in_array($content, $icons)) {
+ $icons[$content] = Registrar::getInstance($content)->getIcon();
+ }
+ $icon = jvbIcon($icons[$content]);
+ }
+
+ $placeholders .= sprintf(
+ '<div class="placeholder">%s</div>',
+ $icon
+ );
+ }
+
+ return sprintf(
+ '<div class="item-grid">%s</div>',
+ $placeholders
+ );
+ }
+
+ protected function renderLoader():string
+ {
+ return sprintf(
+ '<button type="button" class="load-more">%s<span>Show Me More</span>%s</button>
+ %s%s',
+ jvbIcon('arrow-elbow-left-down'),
+ jvbIcon('arrow-elbow-right-down'),
+ jvbLoadingScreen(),
+ $this->isGallery ? jvbRenderGallery(false) : '',
+ );
+ }
+
+ protected function renderTemplates():string
+ {
+
+ $templates = [];
+ foreach ($this->content as $content) {
+ $templates[] = $this->getDefaultTemplate($content);
+ }
+
+ $templates[] = sprintf(
+ '<template class="feedTerm"><button class="remove-term">%s<span></span>%s</button></template>',
+ jvbIcon(jvbDefaultIcon()),
+ jvbIcon('x')
+ );
+ $defaultEmptyState = sprintf(
+ '<div class="empty-state">
+ <h3>%sNOTHING HERE%s</h3>
<p>Try tweaking those filters a bit.</p>
- </div>', $this->config). '</template>';
- echo '<template class="placeholderTemplate"><div class="placeholder">'.apply_filters('jvbFeedPlaceholder', jvbIcon(jvbLogoIcon())).'</div></template>';
+ </div>',
+ jvbIcon(jvbDefaultIcon()),
+ jvbIcon(jvbDefaultIcon()),
+ );
+ $emptyState = apply_filters('jvbFeedEmptyState', $defaultEmptyState, $this->content);
+ $templates[] = sprintf(
+ '<template class="emptyState">%s</template>',
+ $emptyState
+ );
+
+ $placeholder = apply_filters('jvbFeedPlaceholder', jvbIcon(jvbLogoIcon()));
+ $templates[] = sprintf(
+ '<template class="placeholderTemplate"><div class="placeholder">%s</div></template>',
+ $placeholder
+ );
+
+ return implode('', $templates);
}
- protected function getFavouritesButton(string $content):string
+ protected function renderActions():string
+ {
+ return sprintf(
+ '<button data-action="refresh" data-ignore>%s<span>Hard Refresh</span></span></button>',
+ jvbIcon('arrows-clockwise')
+ );
+ }
+
+ public static function getFavouritesButton(string $content):string
{
$registrar = Registrar::getInstance($content);
if (!$registrar || !Site::has('favourites') || !$registrar->hasFeature('favouritable')) {
@@ -424,7 +527,7 @@
.jvbIcon('heart', ['style'=>'fill']).'
</button>';
}
- protected function getUpvotesButton(string $content):string
+ public static function getUpvotesButton(string $content):string
{
$registrar = Registrar::getInstance($content);
if (!Site::has('karma') || !$registrar || !$registrar->hasFeature('karma')){
@@ -444,39 +547,66 @@
}
protected function getDefaultTemplate(string $content): string
{
- $config = Registrar::getInstance($content)->getConfig('feed');
- $allFields = Registrar::getFieldsFor($content);
- $images = $config['images']??['post_thumbnail'];
- $fields = $config['fields']??['post_title','post_date','post_excerpt'];
- $fields = array_filter($fields, function($field) use($images) {
- return !in_array($field, $images);
- });
- $fields = array_filter($allFields, function($field) use($fields) {
- return in_array($field, $fields);
- }, ARRAY_FILTER_USE_KEY);
- $template = '<div class="feed item col '.$content.'">'.$this->getFavouritesButton($content).$this->getUpvotesButton($content);
+ $template = apply_filters('jvbFeedItem', '', $content);
+ if (empty($template)) {
+ $config = Registrar::getInstance($content)->getConfig('feed');
+ $allFields = Registrar::getFieldsFor($content);
+ $images = $config['images']??['post_thumbnail'];
+ $fields = $config['fields']??['post_title','post_date','post_excerpt'];
+ $fields = array_filter($fields, function($field) use($images) {
+ return !in_array($field, $images);
+ });
+ $fields = array_filter($allFields, function($field) use($fields) {
+ return in_array($field, $fields);
+ }, ARRAY_FILTER_USE_KEY);
- //Add all defined images, but allow for filtering
- $imageTemplate = '<a>';
- foreach ($images as $image) {
- $imageTemplate .= '<img data-field="'.$image.'" width="300px" height="300px" sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px" loading="lazy" decoding="async">';
+
+ $template = sprintf(
+ '<div class="feed item col %s">%s%s',
+ $content,
+ self::getFavouritesButton($content),
+ self::getUpvotesButton($content)
+ );
+
+ //Add all defined images, but allow for filtering
+ $imageTemplate = '<a>';
+ foreach ($images as $image) {
+ $imageTemplate .= sprintf(
+ '<img data-field="%s" width="300px" height="300px" sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px" loading="lazy" decoding="async">',
+ $image
+ );
+ }
+ $imageTemplate .= '</a>';
+
+ $template .= sprintf(
+ '<div class="images">%s</div>',
+ apply_filters('jvbFeedImages', $imageTemplate, $content, $images)
+ );
+
+ //Output default fields, but allow for filtering
+ $template .= sprintf(
+ '<details>
+ <summary>%s</summary>',
+ apply_filters('jvbFeedItemSummary', jvbIcon('dots-three'), $content)
+ );
+
+ $fieldsTemplate = '';
+ foreach ($fields as $fieldName => $config) {
+ $fieldsTemplate .= apply_filters('jvbFeedItemField', $this->defaultFieldTemplate($config['type'], $fieldName), $content, $fieldName, $config['type']);
+ }
+ $template .= sprintf(
+ '<div class="item-info">%s</div>',
+ apply_filters('jvbFeedItemFields', $fieldsTemplate, $content, $fields)
+ );
+ $template .= '</details></div>';
}
- $imageTemplate .= '</a>';
- $template .= '<div class="images">'.apply_filters('jvbFeedImages', $imageTemplate, $content, $images).'</div>';
- //Output default fields, but allow for filtering
- $template .= '<details>
- <summary>'.apply_filters('jvbFeedItemSummary', jvbIcon('dots-three'), $content).'</summary>';
- $fieldsTemplate = '';
-
- foreach ($fields as $fieldName => $config) {
- $fieldsTemplate .= apply_filters('jvbFeedItemField', $this->defaultFieldTemplate($config['type'], $fieldName), $content, $fieldName, $config['type']);
- }
- $template .= '<div class="item-info">'.apply_filters('jvbFeedItemFields', $fieldsTemplate, $content, $fields).'</div>';
- $template .= '</details></div>';
-
- return '<template class="feedItem'.ucfirst($content).'">'.apply_filters('jvbFeedItem', $template, $content).'</template>';
+ return sprintf(
+ '<template class="feedItem%s">%s</template>',
+ ucfirst($content),
+ $template
+ );
}
protected function defaultFieldTemplate(string $fieldType, string $fieldName):string
@@ -490,17 +620,11 @@
return '<time'.$data.'></time>';
}
return match($fieldType) {
+ 'date','datetime','time' => '<time'.$data.'></time>',
'upload' => '<img'.$data.' width="300px" height="300px" sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px" loading="lazy" decoding="async">',
'taxonomy' => '<ul'.$data.'><li><a><i></i></a></li></ul>',
default => '<p'.$data.'></p>',
};
}
- /**
- * Get feed content using Features instead of get_option
- * Returns array of slug => config for types that show in feed
- */
- public function getFeedContent(): array
- {
- return JVB()->routes('feed')->getFeedTypesConfig();
- }
+
}
--
Gitblit v1.10.0