cache = Cache::for('feed_block', WEEK_IN_SECONDS); if (JVB_TESTING) { $this->cache->flush(); } add_action('init', [$this, 'registerBlock']); } public function registerBlock() { register_block_type($this->path, [ 'render_callback' => [$this, 'render'] ]); } 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); $mainConfig = JVB_CONTENT[$content]??false; if ($mainConfig && array_key_exists('feed', $mainConfig) && array_key_exists('config', $mainConfig['feed'])){ $config = array_merge($config, $mainConfig['feed']['config']); } else { $config['content'] = $content; $config['icon'] = JVB_CONTENT[$content]['icon']??[jvbLogoIcon()]; } if (is_singular()) { $config['source'] = $type->ID; } $config['taxonomies'] = $this->getTaxonomies([$content]); } elseif (is_tax()) { $content = jvbNoBase($type->taxonomy); $mainConfig = JVB_TAXONOMY[$content]??false; if ($mainConfig) { $config['content'] = $mainConfig['for_content']; $config['context'] = $content; // ← ADD THIS $config['taxonomies'] = $this->getTaxonomies($mainConfig['for_content']); if (array_key_exists('feed', $mainConfig) && array_key_exists('config', $mainConfig['feed'])){ $config = array_merge($config, $mainConfig['feed']['config']); } } $config['source'] = $type->term_id; } if (!is_array($config['content'])) { $config['content'] = [$config['content']]; } return $config; } /** * Get taxonomies for given content types * Uses Checker instead of globals */ protected function getTaxonomies(array $content): array { $checker = Checker::getInstance(); $taxonomies = []; foreach ($content as $contentType) { $contentTaxonomies = $checker->getTaxonomiesForContent($contentType); $contentTaxonomies = array_filter($contentTaxonomies, function($taxonomy) { return array_key_exists('show_feed', JVB_TAXONOMY[$taxonomy]) && JVB_TAXONOMY[$taxonomy]['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 { 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(); ?> class="feed-block"> renderFilters(); $this->renderGrid(); $this->renderLoader(); $this->renderTemplates(); echo TaxonomySelector::outputSelectorModal(); ?> config)) { return; } $feedContent = $this->getFeedContent(); $hasMany = count($this->getContent()) > 1; ?>
SHOWING: getContent() as $i => $type) : $checked = $i === 0 ? ' checked' : ''; $label = $feedContent[$type]['plural'] ?? ucfirst($type); ?> >
    $label) { $active = $i === 0 ? ' class="active"' : ''; ?>
  • >
has('favourites') && is_user_logged_in()) : ?>
config['taxonomies'])) { ?>
FILTER BY: config['taxonomies'] as $tax) : $taxConfig = JVB_TAXONOMY[$tax] ?? null; if (!$taxConfig) continue; $contentForTax = $checker->getContentForTaxonomy($tax); $hidden = empty($contentForTax) ? ' hidden' : ''; $taxSelector = new TaxonomySelector( 'feed-'.$tax, $tax, [ 'icon' => $taxConfig['icon']??jvbLogoIcon(), 'update' => '.selected-items-section .selected-items', 'types' => $contentForTax, 'autocomplete' => false, 'hidden' => $hidden, 'output' => 'minimal' ] ); echo $taxSelector->render(); endforeach; ?>
'match'])) ?>
ORDER BY: getContent() as $content) { $config = JVB_CONTENT[$content]??JVB_TAXONOMY[$content]??JVB_USER[$content]??false; if ($config && array_key_exists('custom_order', $config)) { $custom = array_merge_recursive($custom, $config['custom_order']); } } foreach ($custom as $slug => $conf) { ?>
ORDER:
getContent()) - 1; for ($i = 1; $i <= 36; $i++) { $rand = rand(0, $total); $config = Features::getConfig($this->getContent()[$rand]); $icon = jvbIcon($config['icon']??jvbLogoIcon()); ?>
config)) { jvbRenderGallery(); } } protected function renderTemplates(): void { if ($this->getContent()) { foreach ($this->getContent() as $content) { echo $this->getDefaultTemplate($content); } } echo ''; echo ''; echo ''; } protected function getFavouritesButton(string $content):string { if (!Features::forSite()->has('favourites') && !Features::forContent($content)->has('favouritable')) { return ''; } return ''; } protected function getUpvotesButton(string $content):string { if (!Features::forSite()->has('karma') && !Features::forContent($content)->has('karma')){ return ''; } return '
'; } protected function getDefaultTemplate(string $content): string { $config = JVB_CONTENT[$content]??[]; $hasConfig = array_key_exists('feed', $config); $images = ($hasConfig && array_key_exists('images', $config['feed']) ? $config['feed']['images']:['post_thumbnail']); $images = (is_array($images)) ? $images : [$images]; $fields = ($hasConfig && array_key_exists('fields', $config['feed']) ? $config['feed']['fields']:['post_title', 'post_date']); $fields = array_filter($fields, function($field) use($images) { return !in_array($field, $images); }); $template = '
'.$this->getFavouritesButton($content).$this->getUpvotesButton($content); //Add all defined images, but allow for filtering $imageTemplate = ''; foreach ($images as $image) { $imageTemplate .= ''; } $imageTemplate .= ''; $template .= '
'.apply_filters('jvbFeedImages', $imageTemplate, $content, $images).'
'; //Output default fields, but allow for filtering $template .= '
'.apply_filters('jvbFeedItemSummary', jvbIcon('dots-three'), $content).''; $fieldsTemplate = ''; foreach ($fields as $fieldName) { $fieldType = JVB_CONTENT[$content][$fieldName]['type']??'text'; $fieldsTemplate .= apply_filters('jvbFeedItemField', $this->defaultFieldTemplate($fieldType, $fieldName), $content, $fieldName, $fieldType); } $template .= '
'.apply_filters('jvbFeedItemFields', $fieldsTemplate, $content, $fields).'
'; $template .= '
'; return ''; } protected function defaultFieldTemplate(string $fieldType, string $fieldName):string { $data = ' data-field="'.$fieldName.'"'; switch ($fieldName) { case 'post_title': return ''; case 'post_date': case 'post_modified': return ''; } return match($fieldType) { 'upload' => '', 'taxonomy' => '
  • ', default => '

    ', }; } /** * 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(); } }