cacheName = 'responses'; $this->cacheTtl = 1800; // 30 minutes parent::__construct(); $this->cache = Cache::for($this->cacheName, 'response', $this->cacheTtl); } public function registerRoutes(): void { register_rest_route($this->namespace, '/response', [ [ 'methods' => 'GET', 'callback' => [$this, 'getResponses'], 'permission_callback' => 'is_user_logged_in' ], [ 'methods' => 'POST', 'callback' => [$this, 'handleResponseActions'], 'permission_callback' => 'is_user_logged_in' ] ]); } /** * Get responses for an item */ public function getResponses(WP_REST_Request $request): WP_REST_Response { $params = $request->get_params(); if (!array_key_exists('item_id', $params)) { return $this->error('Missing item ID', 'missing_item_id'); } $item_id = absint($params['item_id']); $args = $this->buildQueryArgs($request); return $this->success(Responses::getInstance()->getAllItemResponses($item_id, $args)); } /** * Handle response actions (create/update/delete) */ public function handleResponseActions(WP_REST_Request $request): WP_REST_Response { $data = $request->get_params(); $user_id = get_current_user_id(); if (!$user_id) { return $this->unauthorized(); } $action = sanitize_text_field($data['action'] ?? ''); if (!in_array($action, ['create', 'delete', 'update'])) { return $this->error('Invalid action', 'invalid_action'); } // Validate required fields for create if ($action === 'create') { if (!isset($data['item_id'], $data['response'], $data['content'])) { return $this->error('Missing required fields', 'missing_fields'); } } $responses = Responses::getInstance(); $response = match($action) { 'create' => $responses->respondTo( absint($data['item_id']), sanitize_text_field($data['content']), $user_id, wp_kses_post($data['response']), isset($data['parent_id']) ? absint($data['parent_id']) : null ), 'update' => $responses->editResponse( absint($data['response_id']), wp_kses_post($data['response']??'') ), 'delete' => $responses->deleteResponse(absint($data['response_id'])) }; if ($response['success']) { return $this->success($response); } return $this->error($response['message']); } /** * Get responses with karma calculations */ public function getItemResponse(int $item_id, array $args = []): array|WP_Error { $responses = Responses::getInstance()->getAllItemResponses($item_id, $args); // Format responses $responses['items'] = array_map([$this, 'formatItem'], $responses); return $responses; } /** * Build query arguments from request */ protected function buildQueryArgs(WP_REST_Request $request): array { $page = max(1, (int) ($request->get_param('page') ?? 1)); $per_page = min(100, max(1, (int) ($request->get_param('per_page') ?? $this->perPage))); $args = [ 'page' => $page, 'per_page' => $per_page, 'orderby' => 'created_at', 'order' => 'DESC' ]; // Parent filter (null = top-level only) if ($request->has_param('parent_id')) { $parent_id = $request->get_param('parent_id'); $args['parent_id'] = $parent_id === '0' ? null : (int) $parent_id; } // Ordering if ($request->has_param('orderby')) { $orderby = $request->get_param('orderby'); $valid = ['created_at', 'updated_at', 'upvotes', 'downvotes', 'karmic_score']; if (in_array($orderby, $valid)) { $args['orderby'] = $orderby; } } if ($request->has_param('order')) { $order = strtoupper($request->get_param('order')); if (in_array($order, ['ASC', 'DESC'])) { $args['order'] = $order; } } return $args; } /** * Format response for API output */ protected function formatItem(array $response): array { // Handle deleted users if ($response['is_user_deleted']) { $response['user'] = [ 'id' => null, 'name' => '[deleted user]', 'is_deleted' => true ]; } else { $user = get_userdata($response['user_id']); $response['user'] = [ 'id' => $response['user_id'], 'name' => $user->display_name, 'url' => jvbUserProfileLink($response['user_id']), ]; } return $response; } }