PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.2
4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 All 200 releases
betterdocs / includes / Abilities / Faq / ListFAQs.php

ListFAQs.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.2, at includes/Abilities/Faq/ListFAQs.php

196 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * List FAQs ability.
4 *
5 * @package BetterDocs
6 * @since 4.9.0
7 */
8
9 namespace WPDeveloper\BetterDocs\Abilities\Faq;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 use WPDeveloper\BetterDocs\Abilities\AbilityBase;
16 use WPDeveloper\BetterDocs\Abilities\Traits\ShapesFAQs;
17
18 /**
19 * Read the questions: all of them, or one group's, with their answers.
20 *
21 * `group_name` here is **find-only** — a name that matches nothing is a
22 * `not_found`, never a new group. A filter that created what it was looking for
23 * would answer "no results" and litter the taxonomy at the same time (the same
24 * rule `bd-list-docs` follows for categories and tags).
25 *
26 * `status` defaults to `any`, because an agent asked to fix a draft answer has
27 * to be able to see it.
28 *
29 * @since 4.9.0
30 */
31 class ListFAQs extends AbilityBase {
32
33 use ShapesFAQs;
34
35 /**
36 * @since 4.9.0
37 */
38 public function __construct() {
39 $this->id = 'betterdocs/list-faqs';
40 $this->label = __( 'List FAQs', 'betterdocs' );
41 $this->description = __( 'List BetterDocs FAQs with their questions, answers and groups. Filter by group, search text or status. Naming a group that does not exist is an error here, not an invitation to create it.', 'betterdocs' );
42 $this->capability = 'edit_others_docs';
43 }
44
45 /**
46 * @since 4.9.0
47 *
48 * @return array
49 */
50 public function get_annotations() {
51 return [
52 'readonly' => true,
53 'destructive' => false,
54 'idempotent' => true,
55 'priority' => 1.5,
56 'openWorldHint' => false
57 ];
58 }
59
60 /**
61 * @since 4.9.0
62 *
63 * @return array
64 */
65 public function get_input_schema() {
66 return [
67 'type' => 'object',
68 'additionalProperties' => false,
69 'properties' => [
70 'group_id' => [
71 'type' => 'integer',
72 'description' => __( 'Only FAQs in this group, by id.', 'betterdocs' )
73 ],
74 'group_name' => [
75 'type' => 'string',
76 'description' => __( 'Only FAQs in this group, by name or slug. The group must already exist. Send group_id or group_name, not both.', 'betterdocs' )
77 ],
78 'search' => [
79 'type' => 'string',
80 'description' => __( 'Free-text search over questions and answers.', 'betterdocs' )
81 ],
82 'status' => [
83 'type' => 'string',
84 'enum' => [ 'any', 'publish', 'draft', 'pending', 'private', 'future', 'trash' ],
85 'default' => 'any',
86 'description' => __( 'Post status to list. Defaults to any, which is everything except trashed FAQs.', 'betterdocs' )
87 ],
88 'page' => [
89 'type' => 'integer',
90 'minimum' => 1,
91 'default' => 1
92 ],
93 'per_page' => [
94 'type' => 'integer',
95 'minimum' => 1,
96 'maximum' => 100,
97 'default' => 20,
98 'description' => __( 'FAQs per page, 1–100. Answers are returned in full, so keep this small.', 'betterdocs' )
99 ]
100 ],
101 'default' => []
102 ];
103 }
104
105 /**
106 * @since 4.9.0
107 *
108 * @return array
109 */
110 public function get_output_schema() {
111 return [
112 'type' => 'object',
113 'properties' => [
114 'items' => [
115 'type' => 'array',
116 'items' => [
117 'type' => 'object',
118 'properties' => self::faq_shape_schema()
119 ]
120 ],
121 'total' => [ 'type' => 'integer' ],
122 'total_pages' => [ 'type' => 'integer' ],
123 'page' => [ 'type' => 'integer' ],
124 'per_page' => [ 'type' => 'integer' ]
125 ]
126 ];
127 }
128
129 /**
130 * @since 4.9.0
131 *
132 * @param array $input Validated input.
133 * @return array|\WP_Error
134 */
135 public function execute( $input ) {
136 $page = isset( $input['page'] ) ? max( 1, (int) $input['page'] ) : 1;
137 $per_page = isset( $input['per_page'] ) ? (int) $input['per_page'] : 20;
138
139 // Find-only: a listing must never create the group it was asked about.
140 $group = $this->group_ref_input( $input, false );
141
142 if ( is_wp_error( $group ) ) {
143 return $group;
144 }
145
146 $params = [
147 // Edit context, for `content.raw`: the answer an agent should read
148 // and rewrite is the stored HTML, not the filtered render. Every
149 // caller holds `edit_others_docs`, which is what the posts
150 // controller asks for here.
151 'context' => 'edit',
152 'status' => isset( $input['status'] ) ? (string) $input['status'] : 'any',
153 'page' => $page,
154 'per_page' => $per_page,
155 'orderby' => 'date',
156 'order' => 'desc'
157 ];
158
159 if ( null !== $group ) {
160 $params[ self::GROUP_TAXONOMY ] = [ (int) $group ];
161 }
162
163 if ( isset( $input['search'] ) && '' !== (string) $input['search'] ) {
164 $params['search'] = (string) $input['search'];
165 }
166
167 $response = $this->dispatch_response( 'GET', '/' . self::FAQ_POST_TYPE, $params, 'wp/v2' );
168
169 if ( $response->is_error() ) {
170 $error = $response->as_error();
171
172 // A page past the last one is an empty page, not an upstream fault.
173 if ( $this->is_page_out_of_range( $error ) ) {
174 return $this->empty_page( '/' . self::FAQ_POST_TYPE, $params, $page, $per_page, 'wp/v2' );
175 }
176
177 return $this->map_faq_error( $error, __( 'list FAQs', 'betterdocs' ) );
178 }
179
180 $headers = $response->get_headers();
181 $items = [];
182
183 foreach ( (array) $response->get_data() as $post ) {
184 $items[] = $this->faq_shape( (array) $post );
185 }
186
187 return [
188 'items' => $items,
189 'total' => isset( $headers['X-WP-Total'] ) ? (int) $headers['X-WP-Total'] : count( $items ),
190 'total_pages' => isset( $headers['X-WP-TotalPages'] ) ? (int) $headers['X-WP-TotalPages'] : 1,
191 'page' => $page,
192 'per_page' => $per_page
193 ];
194 }
195 }
196