'GET', 'permission_callback' => static fn (): bool => current_user_can('edit_pcwp_events'), 'callback' => function (\WP_REST_Request $request): \WP_REST_Response { $type = $request['type'] === 'pcwp_organizer' ? 'pcwp_organizer' : 'pcwp_venue'; $posts = get_posts(['post_type' => $type, 'post_status' => ['publish', 'draft'], 's' => sanitize_text_field((string) $request['search']), 'posts_per_page' => 30, 'orderby' => 'title', 'order' => 'ASC']); $include = array_slice(array_filter(array_map('absint', explode(',', (string) $request['include']))), 0, 200); if ($include !== []) { $posts = array_merge($posts, get_posts(['post_type' => $type, 'post_status' => ['publish', 'draft'], 'include' => $include, 'numberposts' => count($include)])); } $rows = []; foreach ($posts as $post) { if (current_user_can('read_post', $post->ID)) { $rows[$post->ID] = ['id' => $post->ID, 'name' => $post->post_title]; } } return new \WP_REST_Response(array_values($rows)); }], ['methods' => 'POST', 'permission_callback' => static fn (\WP_REST_Request $request): bool => current_user_can('edit_pcwp_events') && current_user_can('edit_posts') && \ProCalendarWP\Infrastructure\Capabilities::canCreatePosts($request['type'] === 'pcwp_organizer' ? 'pcwp_organizer' : 'pcwp_venue'), 'callback' => function (\WP_REST_Request $request): \WP_REST_Response|\WP_Error { $name = sanitize_text_field((string) $request['name']); if ($name === '' || mb_strlen($name) > 200) { return new \WP_Error('pcwp_entity_name', __('Enter a name up to 200 characters.', 'proeventswp'), ['status' => 400]); } $id = wp_insert_post(['post_type' => $request['type'] === 'pcwp_organizer' ? 'pcwp_organizer' : 'pcwp_venue', 'post_title' => $name, 'post_status' => 'draft'], true); return is_wp_error($id) ? $id : new \WP_REST_Response(['id' => $id, 'name' => $name], 201); }], ]); foreach (['venues' => 'pcwp_venue', 'organizers' => 'pcwp_organizer'] as $resource => $postType) { register_rest_route('pro-calendar-wp/v1', '/' . $resource, [ 'methods' => \WP_REST_Server::READABLE, 'callback' => fn (\WP_REST_Request $request): \WP_REST_Response => $this->posts($request, $postType), 'permission_callback' => '__return_true', 'args' => ['search' => ['type' => 'string'], 'page' => ['type' => 'integer', 'minimum' => 1, 'default' => 1], 'per_page' => ['type' => 'integer', 'minimum' => 1, 'maximum' => 100, 'default' => 20]], ]); register_rest_route('pro-calendar-wp/v1', '/' . $resource . '/(?P\d+)', [ 'methods' => \WP_REST_Server::READABLE, 'callback' => fn (\WP_REST_Request $request): \WP_REST_Response|\WP_Error => $this->post((int) $request['id'], $postType), 'permission_callback' => '__return_true', ]); } foreach (['categories' => 'pcwp_event_category', 'tags' => 'pcwp_event_tag'] as $resource => $taxonomy) { register_rest_route('pro-calendar-wp/v1', '/' . $resource, [ 'methods' => \WP_REST_Server::READABLE, 'callback' => fn (): \WP_REST_Response => $this->terms($taxonomy), 'permission_callback' => '__return_true', ]); } } private function posts(\WP_REST_Request $request, string $postType): \WP_REST_Response { $query = new \WP_Query([ 'post_type' => $postType, 'post_status' => 'publish', 'has_password' => false, 's' => sanitize_text_field((string) $request['search']), 'paged' => max(1, (int) $request['page']), 'posts_per_page' => min(100, max(1, (int) $request['per_page'])), ]); $response = new \WP_REST_Response(array_map([$this, 'postData'], $query->posts)); $response->header('X-WP-Total', (string) $query->found_posts); $response->header('X-WP-TotalPages', (string) $query->max_num_pages); return $response; } private function post(int $id, string $postType): \WP_REST_Response|\WP_Error { $post = get_post($id); if (! $post instanceof \WP_Post || $post->post_type !== $postType || $post->post_status !== 'publish' || $post->post_password !== '') { return new \WP_Error('pcwp_entity_not_found', __('Resource not found.', 'proeventswp'), ['status' => 404]); } return new \WP_REST_Response($this->postData($post)); } /** @return array */ private function postData(\WP_Post $post): array { return [ 'id' => $post->ID, 'title' => get_the_title($post), 'description' => apply_filters('the_content', $post->post_content), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WordPress core content-rendering hook. 'excerpt' => $post->post_excerpt, 'link' => get_permalink($post), 'image' => get_the_post_thumbnail_url($post, 'large') ?: null, 'location' => $post->post_type === 'pcwp_venue' ? \ProCalendarWP\Maps\Location::publicData($post->ID) : null, ]; } private function terms(string $taxonomy): \WP_REST_Response { $terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]); if (is_wp_error($terms)) { return new \WP_REST_Response([]); } return new \WP_REST_Response(array_map(static fn (\WP_Term $term): array => [ 'id' => $term->term_id, 'name' => $term->name, 'slug' => $term->slug, 'description' => $term->description, 'count' => $term->count, 'link' => get_term_link($term), ], $terms)); } }