<?php
|
namespace JVBase\rest\routes;
|
|
use JVBase\rest\RestRouteManager;
|
use JVBase\meta\MetaManager;
|
use JVBase\managers\NewsRelationships;
|
use WP_Query;
|
use WP_Error;
|
use WP_REST_Request;
|
use WP_REST_Response;
|
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
|
class NewsRoutes extends RestRouteManager
|
{
|
protected int $per_page;
|
protected bool|object $manager = false;
|
public function __construct()
|
{
|
$this->cache_name = 'news';
|
parent::__construct();
|
$this->action = 'dash-';
|
$this->per_page = 20;
|
|
add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
|
}
|
|
/**
|
* Registers news routes
|
* @return void
|
*/
|
public function registerRoutes():void
|
{
|
register_rest_route($this->namespace, '/news', [
|
[
|
'methods' => 'GET',
|
'callback' => [$this, 'getNews'],
|
'permission_callback' => [$this, 'checkPermission']
|
],
|
[
|
'methods' => 'POST',
|
'callback' => [$this, 'handleNewsOperation'],
|
'permission_callback' => [$this, 'checkPermission']
|
]
|
]);
|
}
|
|
/**
|
* @param WP_REST_Request $request
|
*
|
* @return WP_REST_Response
|
*/
|
public function handleNewsOperation(WP_REST_Request $request):WP_REST_Response
|
{
|
$queue = JVB()->queue();
|
$data = $request->get_params();
|
$user = $data['user'];
|
$operationID = $data['id'];
|
|
unset($data['user']);
|
unset($data['id']);
|
$queue->queueOperation(
|
'new_news',
|
$user,
|
$data,
|
[
|
'operation_id' => 'u'.$user.'_'.$operationID,
|
'priority' => 'high',
|
'notification' => true,
|
]
|
);
|
|
return new WP_REST_Response([
|
'success' => true,
|
'message' => 'Queued for processing.'
|
]);
|
}
|
|
/**
|
* @param WP_REST_Request $request
|
*
|
* @return WP_REST_Response
|
*/
|
public function getNews(WP_REST_Request $request):WP_REST_Response
|
{
|
$args = $this->buildQueryArgs($request);
|
$key = $this->cache->generateKey($args);
|
$cache = $this->cache->get($key);
|
if ($cache) {
|
return new WP_REST_Response($cache);
|
}
|
$args['post_type'] = BASE.'news';
|
|
$query = new WP_Query($args);
|
$items = array_map([$this, 'formatItem'], $query->posts);
|
|
$results = [
|
'items' => $items,
|
'has_more' => $query->max_num_pages > $args['paged'],
|
'total_items' => $query->found_posts,
|
'total_pages' => $query->max_num_pages
|
];
|
|
$this->cache->set($key, $results);
|
|
return new WP_REST_Response($results);
|
}
|
|
/**
|
* @param WP_REST_Request $request
|
*
|
* @return array
|
*/
|
protected function buildQueryArgs(WP_REST_Request $request):array
|
{
|
$data = $request->get_params();
|
|
$page = intval($request->get_param('page') ?? 1);
|
$args = [
|
'paged' => $page,
|
'post_status' => 'publish'
|
];
|
|
$args = $this->applyTaxonomyFilters($args, $data);
|
$args = $this->applyOrderFilters($args, $data);
|
$args = $this->applyDateFilters($args, $data);
|
return $this->applyWatchedFilter($args, $data);
|
}
|
|
/**
|
* @return void
|
*/
|
protected function checkRelationshipManager():void
|
{
|
if (!$this->manager) {
|
$this->manager = new NewsRelationships();
|
}
|
}
|
|
/**
|
* @param array $args
|
* @param array $data
|
*
|
* @return array
|
*/
|
protected function applyTaxonomyFilters(array $args, array $data):array
|
{
|
if (array_key_exists('shop', $data)) {
|
$this->checkRelationshipManager();
|
$shop = (int) $data['shop'];
|
$artists = $this->manager->getShopArtistsWithNews($shop);
|
$args['author__in'] = $artists;
|
}
|
if (array_key_exists('type', $data)) {
|
$args['tax_query'] = [[
|
'taxonomy' => BASE.'ntype',
|
'terms' => (int) $data['type'],
|
]];
|
}
|
if (array_key_exists('artist', $data)) {
|
$artist_ids = array_map('intval', (array)$data['artist']);
|
$args['author__in'] = $artist_ids;
|
}
|
|
return $args;
|
}
|
|
/**
|
* @param array $args
|
* @param array $data
|
*
|
* @return array
|
*/
|
protected function applyOrderFilters(array $args, array $data):array
|
{
|
if (array_key_exists('orderby', $data) && $data['orderby'] === 'random') {
|
// Handle random ordering
|
$current_seed = jvbGetRandomSeed();
|
$args['orderby'] = 'RAND(' . $current_seed . ')';
|
unset($args['order']);
|
} else {
|
// Standard ordering
|
if (in_array($data['orderby'], ['date', 'title', 'name'])) {
|
$args['orderby'] = $data['orderby'];
|
} else {
|
switch ($data['orderby']) {
|
case 'popularity':
|
$args['meta_key'] = BASE.'upvotes';
|
$args['orderby'] = 'meta_value_num';
|
break;
|
case 'karma':
|
$args['meta_key'] = BASE.'karma';
|
$args['orderby'] = 'meta_value_num';
|
break;
|
default:
|
$args['orderby'] = 'date';
|
}
|
}
|
$args['order'] = (in_array($data['order'], ['ASC', 'DESC'])) ? $data['order'] : 'DESC';
|
}
|
|
return $args;
|
}
|
|
/**
|
* @param array $args
|
* @param array $data
|
*
|
* @return array
|
*/
|
protected function applyDateFilters(array $args, array $data):array
|
{
|
if (!array_key_exists('date-filter', $data) && !array_key_exists('dateFrom', $data)) {
|
return $args;
|
}
|
if (array_key_exists('dateFrom', $data)) {
|
$dateFrom = strtotime($data['dateFrom']);
|
$dateTo = strtotime($data['dateTo']);
|
if ($dateFrom !== false && $dateTo !== false) {
|
$args['date_query'] = [
|
[
|
'after' => date("c", $dateFrom),
|
'before' => date("c", $dateTo),
|
'inclusive' => true,
|
]
|
];
|
}
|
} else {
|
switch ($data['date-filter']) {
|
case 'today':
|
$args['date_query'] = [['after' => '1 day ago']];
|
break;
|
case 'week':
|
$args['date_query'] = [['after' => '1 week ago']];
|
break;
|
case 'month':
|
$args['date_query'] = [['after' => '1 month ago']];
|
break;
|
case 'year':
|
$args['date_query'] = [['after' => '1 year ago']];
|
break;
|
}
|
}
|
return $args;
|
}
|
|
/**
|
* @param array $args
|
* @param array $data
|
*
|
* @return array
|
*/
|
protected function applyWatchedFilter(array $args, array $data):array
|
{
|
if (!array_key_exists('watched', $data)) {
|
return $args;
|
}
|
|
global $wpdb;
|
|
$favourites_table = $wpdb->prefix . BASE . 'favourites';
|
$post_types = [BASE.'news'];
|
$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
|
)
|
));
|
|
if (empty($favourited_ids)) {
|
$favourited_ids = [0];
|
}
|
|
$args['post__in'] = isset($args['post__in'])
|
? array_intersect($args['post__in'], $favourited_ids)
|
: $favourited_ids;
|
|
|
return $args;
|
}
|
|
|
/**
|
* @param int|object $post
|
*
|
* @return array
|
*/
|
public function formatItem(int|object $post):array
|
{
|
if (is_int($post)) {
|
$post = get_post($post);
|
if (!$post || is_wp_error($post)) {
|
return [];
|
}
|
}
|
|
$artist = jvbContentFromUser($post->post_author);
|
$upvotes = (int) get_post_meta($post->ID, BASE.'upvotes', true);
|
$downvotes = (int) get_post_meta($post->ID, BASE.'downvotes', true);
|
$comments = JVB()->routes('comments')->getItemResponse($post->ID, BASE.'news');
|
|
return [
|
'id' => $post->ID,
|
'title' => $post->post_title,
|
'tldr' => $post->post_excerpt,
|
'post_content' => $post->post_content,
|
'content' => 'news',
|
'date' => $post->post_date,
|
'artist' => [
|
'id' => $artist['id'],
|
'name' => $artist['name'],
|
'url' => $artist['url']
|
],
|
'shop' => $artist['shop'],
|
'upvotes' => $upvotes,
|
'downvotes' => $downvotes,
|
'comments' => $comments,
|
'type' => $artist['type'],
|
];
|
}
|
|
/**
|
* @param WP_Error|array $result
|
* @param object $operation
|
* @param array $data
|
*
|
* @return WP_Error|array
|
*/
|
public function processOperation(WP_Error|array $result, object $operation, array $data):array|WP_Error
|
{
|
if ($operation->type != 'new_news') {
|
return $result;
|
}
|
|
$user_id = $operation->user_id;
|
|
$title = sanitize_text_field($data['post_title']);
|
$tldr = sanitize_textarea_field($data['post_excerpt']);
|
|
$content = wp_kses_post($data['post_content']);
|
unset($data['post_title']);
|
unset($data['post_excerpt']);
|
unset($data['post_content']);
|
$result = [];
|
|
$ID = wp_insert_post([
|
'post_type' => BASE.'news',
|
'post_author' => $user_id,
|
'post_title' => $title,
|
'post_excerpt' => $tldr,
|
'post_content' => $content,
|
'post_status' => 'publish'
|
]);
|
$result['post_id'] = ($ID && !is_wp_error($ID));
|
|
$type = get_term((int) $data['type'], BASE.'ntype');
|
if ($type && !is_wp_error($type)) {
|
$terms = wp_set_post_terms($ID, $type, BASE.'ntype');
|
$result['term_update'] = ($terms && !is_wp_error($terms));
|
}
|
unset($data['type']);
|
|
if ($ID) {
|
$meta = new MetaManager($ID, 'post');
|
foreach ($data as $key => $value) {
|
$m = $meta->updateValue($key, $value);
|
$result[$key] = $m;
|
}
|
}
|
|
$this->cache->flush();
|
|
return [
|
'success' => true,
|
'result' => $result
|
];
|
}
|
}
|