'object', 'properties' => array_merge([ 'post_type' => ['type' => 'string', 'description' => 'Inhaltstyp, z. B. page oder post.'], 'status' => [ 'type' => 'array', 'items' => ['type' => 'string', 'enum' => self::STATUSES], 'description' => 'Standard: alle außer Papierkorb.', ], 'search' => ['type' => 'string'], 'taxonomy' => [ 'type' => 'object', 'properties' => [ 'taxonomy' => ['type' => 'string'], 'terms' => ['type' => 'array', 'minItems' => 1, 'items' => ['type' => ['integer', 'string']]], ], 'required' => ['taxonomy', 'terms'], 'additionalProperties' => false, ], 'field' => [ 'type' => 'object', 'properties' => [ 'key' => ['type' => 'string'], 'value' => ['type' => ['string', 'number', 'boolean']], 'compare' => ['type' => 'string', 'enum' => ['=', '!=', 'LIKE', 'EXISTS', 'NOT EXISTS']], ], 'required' => ['key'], 'additionalProperties' => false, ], 'date_after' => ['type' => 'string', 'pattern' => self::DATE_PATTERN], 'date_before' => ['type' => 'string', 'pattern' => self::DATE_PATTERN], 'parent' => ['type' => 'integer', 'minimum' => 0], 'orderby' => ['type' => 'string', 'enum' => ['date', 'modified', 'title', 'menu_order']], 'order' => ['type' => 'string', 'enum' => ['asc', 'desc']], ], Cursor::inputProperties()), 'required' => ['post_type'], 'additionalProperties' => false, ]; } public function outputSchema(): ?array { return [ 'type' => 'object', 'properties' => [ 'items' => ['type' => 'array', 'items' => PostPresenter::summarySchema()], 'next_cursor' => ['type' => ['string', 'null']], ], 'required' => ['items', 'next_cursor'], ]; } public function annotations(): array { return ['readonly' => true, 'destructive' => false, 'idempotent' => true]; } public function isDirect(): bool { return true; } public function permission(array $input): bool|WP_Error { $type = PostGuard::postType($input['post_type'] ?? null, $this->schema, 'edit_posts'); return $type instanceof WP_Error ? $type : true; } public function execute(array $input): mixed { $offset = Cursor::decode(isset($input['cursor']) ? (string) $input['cursor'] : null); if ($offset === null) { return Cursor::invalid(); } $limit = Cursor::limit($input['limit'] ?? null); $posts = get_posts(array_merge($this->queryArgs($input), [ 'posts_per_page' => $limit + 1, 'offset' => $offset, ])); $page = Cursor::page(array_values($posts), $limit, $offset); $items = []; foreach ($page['items'] as $post) { if ($post instanceof WP_Post && current_user_can('edit_post', (int) $post->ID)) { $items[] = $this->presenter->summary($post); } } return ['items' => $items, 'next_cursor' => $page['next_cursor']]; } /** * @param array $input * @return array */ private function queryArgs(array $input): array { $args = [ 'post_type' => (string) $input['post_type'], 'post_status' => $input['status'] ?? self::STATUSES, 'orderby' => (string) ($input['orderby'] ?? 'date'), 'order' => strtoupper((string) ($input['order'] ?? 'desc')), 'no_found_rows' => true, 'ignore_sticky_posts' => true, 'suppress_filters' => false, ]; if (isset($input['search']) && $input['search'] !== '') { $args['s'] = (string) $input['search']; } if (isset($input['parent'])) { $args['post_parent'] = (int) $input['parent']; } if (isset($input['taxonomy']) && is_array($input['taxonomy'])) { $args['tax_query'] = $this->taxQuery($input['taxonomy']); } if (isset($input['field']) && is_array($input['field'])) { $compare = (string) ($input['field']['compare'] ?? '='); $clause = ['key' => (string) $input['field']['key'], 'compare' => $compare]; if (! in_array($compare, ['EXISTS', 'NOT EXISTS'], true)) { $clause['value'] = $input['field']['value'] ?? ''; } $args['meta_query'] = [$clause]; } $date = []; if (isset($input['date_after'])) { $date['after'] = (string) $input['date_after']; } if (isset($input['date_before'])) { $date['before'] = (string) $input['date_before']; } if ($date !== []) { $args['date_query'] = [array_merge($date, ['inclusive' => true])]; } return $args; } /** * @param array $filter * @return array */ private function taxQuery(array $filter): array { $taxonomy = (string) $filter['taxonomy']; $terms = (array) $filter['terms']; $ids = array_values(array_filter($terms, 'is_int')); $slugs = array_values(array_filter($terms, 'is_string')); $clauses = []; if ($ids !== []) { $clauses[] = ['taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $ids]; } if ($slugs !== []) { $clauses[] = ['taxonomy' => $taxonomy, 'field' => 'slug', 'terms' => $slugs]; } return count($clauses) > 1 ? array_merge(['relation' => 'OR'], $clauses) : $clauses; } }