| | |
| | | <?php |
| | | namespace JVBase\rest\routes; |
| | | |
| | | use JVBase\managers\Cache; |
| | | use JVBase\rest\RestRouteManager; |
| | | use JVBase\meta\Meta; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\rest\Rest; |
| | | use JVBase\integrations\Umami; |
| | | use JVBase\meta\MetaManager; |
| | | use JVBase\managers\TaxonomyRelationships; |
| | | use JVBase\utility\Checker; |
| | | use JVBase\utility\Features; |
| | | use JVBase\rest\Route; |
| | | use JVBase\base\Site; |
| | | use WP_Query; |
| | | use WP_Post; |
| | | use WP_Term; |
| | |
| | | exit; // Exit if accessed directly |
| | | } |
| | | |
| | | class FeedRoutes extends RestRouteManager |
| | | class FeedRoutes extends Rest |
| | | { |
| | | protected int $per_page = 36; |
| | | protected ?Umami $tracker = null; |
| | | protected ?Checker $checker = null; |
| | | |
| | | protected ?array $fields = null; |
| | | protected ?array $timelineSharedFields = null; |
| | | protected ?array $timelineUniqueFields = null; |
| | | |
| | | public function __construct() |
| | | { |
| | | $this->cache_name = 'feed'; |
| | | $this->cache_ttl = 86400; |
| | | $this->cacheName = 'feed'; |
| | | $this->cacheTtl = 86400; |
| | | parent::__construct(); |
| | | $this->cache |
| | | ->connect('post') |
| | | ->connect('taxonomy') |
| | | ->connect('user'); |
| | | ->connect('post', true) |
| | | ->connect('taxonomy', true) |
| | | ->connect('user', true); |
| | | |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | |
| | | |
| | | public function init():void |
| | | { |
| | | $this->checker = Checker::getInstance(); |
| | | |
| | | if (Features::hasIntegration('umami')) { |
| | | if (Site::hasIntegration('umami')) { |
| | | $this->tracker = JVB()->connect('umami'); |
| | | } |
| | | } |
| | |
| | | */ |
| | | public function registerRoutes(): void |
| | | { |
| | | register_rest_route($this->namespace, '/feed', [ |
| | | 'methods' => ['GET', 'POST'], |
| | | 'callback' => [$this, 'handleFeedRequest'], |
| | | 'permission_callback' => [$this, 'checkPermission'], |
| | | ]); |
| | | Route::for('feed') |
| | | ->get([$this, 'handleFeedRequest']) |
| | | ->args([ |
| | | 'content' => 'string', |
| | | 'page' => 'integer|default:1|min:1', |
| | | 'taxonomy' => 'string', |
| | | 'match' => 'string|enum:all,any|default:all', |
| | | 'orderby' => 'string', |
| | | 'order' => 'string|enum:ASC,DESC', |
| | | 'date-filter' => 'string', |
| | | 'dateFrom' => 'string', |
| | | 'dateTo' => 'string', |
| | | 'context' => 'string', |
| | | 'source' => 'string', |
| | | 'favourites' => 'boolean', |
| | | 'user' => 'integer', |
| | | 'highlight' => 'string', |
| | | ]) |
| | | ->auth('public') |
| | | ->rateLimit(30, 60) |
| | | ->post([$this, 'handleFeedRequest']) |
| | | ->args([ |
| | | 'content' => 'string', |
| | | 'page' => 'integer|default:1|min:1', |
| | | 'taxonomy' => 'string', |
| | | 'match' => 'string|enum:all,any|default:all', |
| | | 'orderby' => 'string', |
| | | 'order' => 'string|enum:ASC,DESC', |
| | | 'date-filter' => 'string', |
| | | 'dateFrom' => 'string', |
| | | 'dateTo' => 'string', |
| | | 'context' => 'string', |
| | | 'source' => 'string', |
| | | 'favourites' => 'boolean', |
| | | 'user' => 'integer', |
| | | 'highlight' => 'string', |
| | | ]) |
| | | ->auth('public') |
| | | ->rateLimit(30) |
| | | ->register(); |
| | | |
| | | register_rest_route($this->namespace, 'feed/types', [ |
| | | 'permission_callback' => [$this, 'checkPermission'], |
| | | 'methods' => 'GET', |
| | | 'callback' => [$this, 'getFeedTypes'] |
| | | ]); |
| | | // Feed types endpoint |
| | | Route::for('feed/types') |
| | | ->get([$this, 'getFeedTypes']) |
| | | ->auth('public') |
| | | ->rateLimit() |
| | | ->register(); |
| | | } |
| | | |
| | | /** |
| | |
| | | return $this->cache->remember( |
| | | $postID, |
| | | function() use ($postID, $type, $metaType, $post, $skip) { |
| | | $config = null; |
| | | $registrar = null; |
| | | switch ($metaType) { |
| | | case 'post': |
| | | $config = JVB_CONTENT[$type]; |
| | | if (!$skip && array_key_exists('is_timeline', $config) && $config['is_timeline']) { |
| | | $registrar = Registrar::getInstance($type); |
| | | $meta = Meta::forPost($postID); |
| | | if (!$skip && $registrar->isTimeline()) { |
| | | return $this->formatTimeline($postID, $post); |
| | | } |
| | | break; |
| | | case 'term': |
| | | $config = JVB_TAXONOMY[$type]; |
| | | |
| | | $meta = Meta::forTerm($postID); |
| | | $registrar = Registrar::getInstance($type); |
| | | break; |
| | | case 'user': |
| | | $meta = Meta::forUser($postID); |
| | | $registrar = Registrar::getInstance($type); |
| | | break; |
| | | } |
| | | if (!$config) { |
| | | if (!$registrar) { |
| | | return []; |
| | | } |
| | | $fields = $config['fields']; |
| | | $fields = $registrar->getFields(); |
| | | |
| | | //Allow custom filtering for public fields |
| | | if (array_key_exists('feed', $config) && array_key_exists('fields', $config['feed'])) { |
| | | $fields = array_filter($fields, function($field) use ($config) { |
| | | return in_array($field, $config['feed']['fields']); |
| | | if (!empty($registrar->getConfig('feed')['fields'])) { |
| | | $fields = array_filter($fields, function($field) use ($registrar) { |
| | | return in_array($field, $registrar->getConfig('feed')['fields']); |
| | | }, ARRAY_FILTER_USE_KEY); |
| | | } |
| | | |
| | | $meta = new MetaManager($postID, $metaType); |
| | | $values = $meta->getAll(array_keys($fields)); |
| | | |
| | | $out = [ |
| | |
| | | |
| | | $out['id'] = $postID; |
| | | $out['content'] = $type; |
| | | $out['icon'] = $config['icon']??jvbDefaultIcon(); |
| | | $out['icon'] = $registrar->getIcon()??jvbDefaultIcon(); |
| | | if ($out['icon'] === '') { |
| | | $out['icon'] = jvbDefaultIcon(); |
| | | } |
| | | |
| | | if ($this->tracker) { |
| | | $args = ($metaType === 'post') ? ['owner_id' => $post->post_author] : []; |
| | |
| | | |
| | | switch ($metaType) { |
| | | case 'term': |
| | | $owner = (in_array($type, jvbContentTaxonomies()) ? $meta->getValue('owner') : null); |
| | | |
| | | $owner = $registrar->hasFeature('is_content') ? $meta->get('owner') : null; |
| | | if (!is_null($owner)) { |
| | | $out['user_id'] = $owner; |
| | | } |
| | |
| | | |
| | | protected function initTimelineFields(string $content):void |
| | | { |
| | | $content = jvbNoBase($content); |
| | | if (!Features::forContent($content)->has('is_timeline')){ |
| | | $registrar = Registrar::getInstance($content); |
| | | if (!$registrar || !$registrar->hasFeature('is_timeline')){ |
| | | return; |
| | | } |
| | | $config = Features::getConfig($content); |
| | | $this->fields = $config['fields']; |
| | | $this->fields = $registrar->getFields(); |
| | | |
| | | $this->timelineSharedFields = array_keys(array_filter($this->fields, function ($field) { |
| | | if (!array_key_exists('for_all', $field) || $field['for_all'] === false){ |
| | |
| | | } |
| | | $item = $this->formatItem($postID, 'post', true); |
| | | //Step 1: Get the fields that apply to all posts |
| | | $mainMeta = new MetaManager($post->ID, 'post'); |
| | | $mainMeta = Meta::forPost($post->ID); |
| | | $item['fields'] = $mainMeta->getAll($this->timelineSharedFields); |
| | | |
| | | //Step 2: Get the fields for each individual posts |
| | |
| | | $subFields = []; |
| | | $images = []; |
| | | foreach ($children as $child) { |
| | | $meta = new MetaManager($child, 'post'); |
| | | $meta = Meta::forPost($child); |
| | | $f = $meta->getAll($this->timelineUniqueFields); |
| | | $f = ['id' => $child] + $f; |
| | | $subFields[] = $f; |
| | |
| | | if (empty($value)) { |
| | | continue; |
| | | } |
| | | if (!array_key_exists($key, JVB_TAXONOMY)) { |
| | | |
| | | $registrar = Registrar::getInstance($key); |
| | | if (!$registrar || $registrar->registrar->public === false){ |
| | | continue; |
| | | } |
| | | |
| | | $taxConfig = JVB_TAXONOMY[$key]; |
| | | if (isset($taxConfig['public']) && $taxConfig['public'] === false) { |
| | | continue; |
| | | } |
| | | $terms = array_map('absint', explode(',', $value)); |
| | | $terms = array_filter($terms); // Remove 0 values |
| | | |
| | |
| | | protected function getAuthorData(WP_Post $post) |
| | | { |
| | | $author = $post->post_author; |
| | | $userLink = get_user_meta($author, BASE.'link', true); |
| | | $userLink = get_user_meta($author, BASE.'profile_link', true); |
| | | return $this->cache->remember( |
| | | $userLink, |
| | | function () use ($userLink, $author) { |
| | | $label = jvbUserRole($author); |
| | | if (array_key_exists($label, JVB_USER)) { |
| | | $label = JVB_USER[$label]['label']; |
| | | $registrar = Registrar::getInstance($label); |
| | | if ($registrar) { |
| | | $label = $registrar->getSingular(); |
| | | } else { |
| | | $label = 'Artist'; |
| | | } |
| | |
| | | |
| | | protected function getTaxonomies(int $postID, string $content): array |
| | | { |
| | | $taxonomies = jvbTaxonomiesForContent($content); |
| | | $registrar = Registrar::getInstance($content)??false; |
| | | $taxonomies = $registrar->registrar->taxonomies; |
| | | $out = []; |
| | | foreach ($taxonomies as $tax) { |
| | | $terms = get_the_terms($postID, $tax); |
| | | $t = []; |
| | | if ($terms && !is_wp_error($terms)) { |
| | | $config = jvbNoBase($tax); |
| | | $config = Registrar::getInstance($tax); |
| | | $out[] = [ |
| | | 'icon' => $config, |
| | | 'title' => JVB_TAXONOMY[$config]['plural'], |
| | | 'icon' => $config->getIcon(), |
| | | 'title' => $config->getPlural(), |
| | | 'terms' => array_map(function ($term) use ($tax, $postID, $content) { |
| | | $item = $this->cache->remember( |
| | | $term->term_id, |
| | |
| | | $data = $request->get_params(); |
| | | $args = [ |
| | | 'post_type' => (array_key_exists($data['content'], $this->buildFeedTypesConfig())) ? |
| | | BASE . $data['content'] : |
| | | BASE . array_key_first(JVB_CONTENT), |
| | | jvbCheckBase($data['content']) : null, |
| | | 'paged' => intval($data['page'] ?? 1), |
| | | 'posts_per_page' => $this->per_page, |
| | | ]; |
| | |
| | | return $this->applyFavouritesFilter($args, $data); |
| | | } |
| | | |
| | | // protected function applyTaxonomyFilters(array $args, array $data): array |
| | | // { |
| | | // if (!array_key_exists('taxonomy', $data) || empty($data['taxonomy'])) { |
| | | // return $args; |
| | | // } |
| | | // |
| | | // $taxonomyFilters = $data['taxonomy']; |
| | | // |
| | | // // Validate taxonomies exist and sanitize |
| | | // $validFilters = []; |
| | | // foreach ($taxonomyFilters as $taxonomy => $terms) { |
| | | // if (!taxonomy_exists(jvbCheckBase($taxonomy))) { |
| | | // continue; |
| | | // } |
| | | // |
| | | // $validFilters[] = [ |
| | | // 'taxonomy' => jvbCheckBase($taxonomy), |
| | | // 'field' => 'term_id', |
| | | // 'terms' => array_map('absint', (array)$terms), |
| | | // 'operator' => 'IN' |
| | | // ]; |
| | | // } |
| | | // |
| | | // if (empty($validFilters)) { |
| | | // return $args; |
| | | // } |
| | | // |
| | | // // Determine relation based on match filter |
| | | // $relation = ($data['match'] ?? 'all') === 'all' ? 'AND' : 'OR'; |
| | | // |
| | | // $args['tax_query'] = array_merge( |
| | | // ['relation' => $relation], |
| | | // $validFilters |
| | | // ); |
| | | // |
| | | // return $args; |
| | | // } |
| | | |
| | | /** |
| | | * @param WP_REST_Request $request |
| | | * |
| | |
| | | $args['highlight'] = $highlight; |
| | | } |
| | | $cached['items'] = $this->processHighlightedItem($cached['items'], $args); |
| | | $response = new WP_REST_Response($cached); |
| | | $response = $this->success($cached); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | // Fetch and format items |
| | | $items = $this->fetchFeedItems($args); |
| | | |
| | | $ttl = (str_contains($args['orderby'], 'RAND')) ? 300 : $this->cache_ttl; |
| | | $ttl = (str_contains($args['orderby'], 'RAND')) ? 300 : $this->cacheTtl; |
| | | $this->cache->set($key, $items, $ttl); |
| | | |
| | | if ($request->get_param('highlight')) { |
| | |
| | | } |
| | | |
| | | $items['items'] = $this->processHighlightedItem($items['items'], $args); |
| | | $response = new WP_REST_Response($items); |
| | | $response = $this->success($items); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | /** |
| | | * Build cache context from query args |
| | | * Extracts content types and parameters needed for proper cache checking |
| | | * |
| | | * @param array $args Built WP_Query arguments |
| | | * @param WP_REST_Request $request Original request |
| | | * @return array Cache context with content_types and additional_params |
| | | */ |
| | | protected function buildCacheContext(array $args, WP_REST_Request $request): array |
| | | { |
| | | // Extract content types from post_type in args |
| | | $post_types = is_array($args['post_type']) |
| | | ? $args['post_type'] |
| | | : [$args['post_type']]; |
| | | |
| | | $content_types = array_map('jvbNoBase', $post_types); |
| | | $content_types[] = 'feed'; // Always include base feed type |
| | | |
| | | // Build additional params for ETag uniqueness |
| | | $additional_params = [ |
| | | 'order' => $args['orderby'] ?? 'date', |
| | | 'direction' => $args['order'] ?? 'DESC', |
| | | 'page' => $args['paged'] ?? 1, |
| | | ]; |
| | | |
| | | if ($request->get_param('favourites')) { |
| | | $additional_params['user'] = (int)$request->get_param('user'); |
| | | } |
| | | |
| | | // Include author filter if present (from context or favourites) |
| | | if (!empty($args['author'])) { |
| | | $additional_params['author'] = $args['author']; |
| | | } |
| | | |
| | | if (!empty($args['author__in'])) { |
| | | $additional_params['author__in'] = $args['author__in']; |
| | | } |
| | | |
| | | // Include taxonomy filters if present |
| | | if (!empty($args['tax_query'])) { |
| | | $tax_filters = []; |
| | | foreach ($args['tax_query'] as $key => $query) { |
| | | if ($key === 'relation' || !is_array($query)) { |
| | | continue; |
| | | } |
| | | |
| | | $taxonomy = jvbNoBase($query['taxonomy'] ?? ''); |
| | | if ($taxonomy) { |
| | | $tax_filters[$taxonomy] = $query['terms'] ?? []; |
| | | // Also add taxonomy to content_types for timestamp checking |
| | | $content_types[] = $taxonomy; |
| | | } |
| | | } |
| | | if (!empty($tax_filters)) { |
| | | $additional_params['taxonomies'] = $tax_filters; |
| | | } |
| | | } |
| | | |
| | | // Include date filters if present |
| | | if (!empty($args['date_query'])) { |
| | | $additional_params['date_filter'] = md5(serialize($args['date_query'])); |
| | | } |
| | | |
| | | // Include meta queries if present |
| | | if (!empty($args['meta_query'])) { |
| | | $additional_params['meta_filter'] = md5(serialize($args['meta_query'])); |
| | | } |
| | | |
| | | return [ |
| | | 'content_types' => array_unique($content_types), |
| | | 'additional_params' => $additional_params |
| | | ]; |
| | | } |
| | | |
| | | /** |
| | | * @param array $args Formatted Args for WP_Query |
| | | * @param array $items Formatted Args for WP_Query |
| | | * @param array $data parsed Request Data |
| | | * |
| | | * @return array|null |
| | |
| | | // Extract key and value |
| | | $key = array_keys($data['highlight'])[0] ?? false; |
| | | $value = array_values($data['highlight'])[0] ?? false; |
| | | error_log('Highlighted item: ' . $key); |
| | | error_log('Highlighted item: ' . $value); |
| | | error_log('No Single Content Types: ' . print_r(jvbNoSingleContentTypes(), true)); |
| | | error_log('Page: ' . print_r($data['paged'], true)); |
| | | if (in_array($key, jvbNoSingleContentTypes()) && $value && $data['paged'] === 1) { |
| | | error_log('Formatted Highlighted item: ' . print_r($this->formatItem($value), true)); |
| | | error_log('Items: ' . print_r($items, true)); |
| | | if ($key && $data['paged'] === 1) { |
| | | array_unshift($items, $this->formatItem($value)); |
| | | error_log('Items after unshift: ' . print_r($items, true)); |
| | | } |
| | | return $items; |
| | | } |
| | |
| | | return $args; |
| | | } |
| | | |
| | | $registrar = Registrar::getInstance($context['type']); |
| | | switch (true) { |
| | | case contentIsJVBUserType($context['type']): |
| | | case $registrar->hasFeature('profile_link'): |
| | | $args['author'] = (int)get_post_meta($context['id'], BASE . 'link', true); |
| | | break; |
| | | case taxIsJVBContentTax($context['type']): |
| | | case $registrar->getType() === 'term' && $registrar->hasFeature('is_content'): |
| | | $args['post_type'] = is_array($args['post_type']) |
| | | ? $args['post_type'] |
| | | : explode(',', $args['post_type']); |
| | | |
| | | // Check if filtering global feed content |
| | | $globalFeedTypes = array_map('jvbCheckBase', |
| | | array_keys(Features::getTypesWithFeature('show_feed', 'content')) |
| | | ); |
| | | if (in_array(jvbNoBase($context['type']), Registrar::getFeatured('is_content', 'term'))) { |
| | | // Global: show posts from any content type with this taxonomy |
| | | $for_content = Registrar::getInstance($context['type'])->registrar->for ?? []; |
| | | |
| | | if (array_intersect($args['post_type'], $globalFeedTypes)) { |
| | | $artists = jvbGetContentUsers($context['id']); |
| | | if (!empty($artists)) { |
| | | $args['author__in'] = $artists; |
| | | } |
| | | } else { |
| | | $args['tax_query'] = [ |
| | | 'relation' => 'AND', |
| | | [ |
| | | 'taxonomy' => BASE . $context['type'], |
| | | 'terms' => $context['id'], |
| | | ] |
| | | ]; |
| | | // Convert to full post types with BASE prefix |
| | | $post_types = array_map(fn($type) => jvbCheckBase($type), $for_content); |
| | | |
| | | // Filter to only show_feed content types |
| | | $show_feed_types = Registrar::getFeatured('show_feed', 'post'); |
| | | $args['post_type'] = array_intersect( |
| | | $post_types, |
| | | array_map(fn($type) => jvbCheckBase($type), $show_feed_types) |
| | | ); |
| | | } |
| | | break; |
| | | case taxonomy_exists(jvbCheckBase($context['type'])): |
| | | $args['tax_query'] = [ |
| | | 'relation' => 'AND', |
| | | [ |
| | | 'taxonomy' => BASE . $context['type'], |
| | | 'terms' => $context['id'], |
| | | ] |
| | | |
| | | // Add term to tax query |
| | | $args['tax_query'][] = [ |
| | | 'taxonomy' => jvbCheckBase($context['type']), |
| | | 'field' => 'term_id', |
| | | 'terms' => [(int)$context['id']], |
| | | ]; |
| | | break; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | |
| | | * |
| | | * @return array |
| | | */ |
| | | protected function applyFavouritesFilter(array $args, array $filters): array |
| | | protected function applyFavouritesFilter(array $args, array $data): array |
| | | { |
| | | if (!array_key_exists('favourites', $filters)) { |
| | | if (empty($data['favourites']) || empty($data['user'])) { |
| | | return $args; |
| | | } |
| | | global $wpdb; |
| | | |
| | | // Get post types for the current filter |
| | | $post_types = is_array($args['post_type']) |
| | | ? $args['post_type'] |
| | | : [$args['post_type']]; |
| | | $user_id = (int)$data['user']; |
| | | $content = jvbNoBase($args['post_type']); |
| | | |
| | | $favourites_table = $wpdb->prefix . BASE . 'favourites'; |
| | | $placeholders = implode(',', array_fill(0, count($post_types), '%s')); |
| | | $favourited_ids = $wpdb->get_col($wpdb->prepare( |
| | | "SELECT target_id FROM {$favourites_table} |
| | | WHERE user_id = %d AND type IN ($placeholders)", |
| | | array_merge( |
| | | [get_current_user_id()], |
| | | $post_types |
| | | ) |
| | | )); |
| | | // Get user's favourites for this content type |
| | | $fav_key = BASE . 'favourites_' . $content; |
| | | $favourites = get_user_meta($user_id, $fav_key, true); |
| | | |
| | | if (empty($favourited_ids)) { |
| | | // Force empty results |
| | | if (empty($favourites)) { |
| | | // No favourites - return empty result |
| | | $args['post__in'] = [0]; // Will return no results |
| | | return $args; |
| | | } |
| | | |
| | | $fav_ids = array_filter(array_map('intval', explode(',', $favourites))); |
| | | |
| | | if (empty($fav_ids)) { |
| | | $args['post__in'] = [0]; |
| | | return $args; |
| | | } |
| | | |
| | | $args['post__in'] = isset($args['post__in']) |
| | | ? array_intersect($args['post__in'], $favourited_ids) |
| | | : $favourited_ids; |
| | | $args['post__in'] = $fav_ids; |
| | | $args['orderby'] = 'post__in'; // Preserve favourite order |
| | | |
| | | return $args; |
| | | } |
| | |
| | | { |
| | | $postType = is_array($args['post_type']) ? $args['post_type'][0] : $args['post_type']; |
| | | $slug = jvbNoBase($postType); |
| | | |
| | | if (Features::forContent($slug)->has('is_timeline')) { |
| | | $registrar = Registrar::getInstance($slug); |
| | | if ($registrar && $registrar->hasFeature('is_timeline')) { |
| | | $args['post_parent'] = 0; |
| | | } |
| | | if (in_array($slug, Features::getTypesWithFeature('is_content', 'taxonomy'))) { |
| | | if ($registrar && $registrar->hasFeature('is_content')) { |
| | | return $this->handleContentTaxonomies($args); |
| | | } |
| | | $args['fields'] = 'ids'; |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get custom table fields for a taxonomy |
| | | * @param string $taxonomy Taxonomy type |
| | | * @return array Field definitions |
| | | */ |
| | | protected function getCustomTableFields(string $taxonomy): array |
| | | { |
| | | return jvbContentTaxonomiesTableFields($taxonomy)['fields'] ?? []; |
| | | } |
| | | |
| | | /** |
| | | * Get available feed types (for block editor) |
| | |
| | | public function getFeedTypes(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | // Check HTTP cache |
| | | $cache_check = $this->checkHeaders($request, ['feed_types']); |
| | | $cache_check = $this->checkHeaders($request, 'feed_types'); |
| | | if ($cache_check) { |
| | | return $cache_check; |
| | | } |
| | | |
| | | $feedTypes = $this->buildFeedTypesConfig(); |
| | | |
| | | $response = new WP_REST_Response($feedTypes); |
| | | $response = $this->success($feedTypes); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | |
| | | */ |
| | | protected function buildFeedTypesConfig(): array |
| | | { |
| | | if (!$this->checker) { |
| | | $this->checker = Checker::getInstance(); |
| | | } |
| | | return $this->cache->remember( |
| | | 'contentTypes', |
| | | function () { |
| | | $config = []; |
| | | |
| | | // Get content types with show_feed |
| | | $contentTypes = Features::getTypesWithFeature('show_feed', 'content'); |
| | | $contentTypes = Registrar::getFeatured('show_feed', 'post'); |
| | | foreach ($contentTypes as $slug) { |
| | | $this->cache->tag('content:'.$slug); |
| | | $contentConfig = JVB_CONTENT[$slug] ?? null; |
| | | if (!$contentConfig) continue; |
| | | $registrar = Registrar::getInstance($slug); |
| | | if (!$registrar) continue; |
| | | |
| | | $config[$slug] = [ |
| | | 'type' => 'content', |
| | | 'singular' => $contentConfig['singular'] ?? ucfirst($slug), |
| | | 'plural' => $contentConfig['plural'] ?? ucfirst($slug) . 's', |
| | | 'icon' => $slug, |
| | | 'taxonomies' => $this->checker->getTaxonomiesForContent($slug), |
| | | 'singular' => $registrar->getSingular(), |
| | | 'plural' => $registrar->getPlural(), |
| | | 'icon' => $registrar->getIcon(), |
| | | 'taxonomies' => $registrar->registrar->taxonomies, |
| | | ]; |
| | | } |
| | | |
| | | // Get taxonomies with show_feed (content taxonomies) |
| | | $taxonomies = Features::getTypesWithFeature('show_feed', 'taxonomy'); |
| | | $taxonomies = Registrar::getFeatured('show_feed', 'term'); |
| | | foreach ($taxonomies as $slug) { |
| | | $taxConfig = JVB_TAXONOMY[$slug] ?? null; |
| | | if (!$taxConfig || !($taxConfig['is_content'] ?? false)) { |
| | | $registrar = Registrar::getInstance($slug); |
| | | if (!$registrar || !($registrar->hasFeature('is_content') ?? false)) { |
| | | continue; |
| | | } |
| | | |
| | |
| | | |
| | | $config[$slug] = [ |
| | | 'type' => 'taxonomy', |
| | | 'singular' => $taxConfig['singular'] ?? ucfirst($slug), |
| | | 'plural' => $taxConfig['plural'] ?? ucfirst($slug) . 's', |
| | | 'icon' => $slug, |
| | | 'singular' => $registrar->getSingular(), |
| | | 'plural' => $registrar->getPlural(), |
| | | 'icon' => $registrar->getIcon(), |
| | | 'taxonomies' => [], // Content taxonomies don't have sub-taxonomies |
| | | 'for_content' => $taxConfig['for_content'] ?? [], |
| | | 'for_content' => $registrar->registrar->for ?? [] |
| | | ]; |
| | | } |
| | | |