PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.0
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 3.5.2 All 199 releases
betterdocs / includes / Abilities / Faq / CreateFAQGroup.php

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

236 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Create an FAQ group 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\AbilityError;
17 use WPDeveloper\BetterDocs\Abilities\Traits\ShapesFAQs;
18
19 /**
20 * Create an FAQ group — or hand back the one that already exists.
21 *
22 * **Find-or-create**, exactly as `bd-create-term` does it: a name that is taken
23 * comes back with `created: false` and the existing group's id, so "make sure
24 * these groups exist" is expressible as one repeatable call. Without it the
25 * second run of the same batch would fail on `term_exists` and an agent would
26 * have to guess whether that meant "already there" or "went wrong".
27 *
28 * The group's `status` is the FAQ Builder's enabled/disabled switch: a `draft`
29 * group and its questions do not render on the front end.
30 *
31 * @since 4.9.0
32 */
33 class CreateFAQGroup extends AbilityBase {
34
35 use ShapesFAQs;
36
37 /**
38 * @since 4.9.0
39 */
40 public function __construct() {
41 $this->id = 'betterdocs/create-faq-group';
42 $this->label = __( 'Create FAQ group', 'betterdocs' );
43 $this->description = __( 'Create a BetterDocs FAQ group (the FAQ Builder calls it a category). A name that already exists is returned as it is, with created:false, so the call is safe to repeat. FAQ groups are what bd-attach-faq puts on a doc.', 'betterdocs' );
44 $this->capability = 'edit_others_docs';
45 }
46
47 /**
48 * @since 4.9.0
49 *
50 * @return array
51 */
52 public function get_annotations() {
53 return [
54 'readonly' => false,
55 'destructive' => false,
56 'idempotent' => false,
57 'priority' => 2.0,
58 'openWorldHint' => false
59 ];
60 }
61
62 /**
63 * @since 4.9.0
64 *
65 * @return array
66 */
67 public function get_input_schema() {
68 return [
69 'type' => 'object',
70 'additionalProperties' => false,
71 'required' => [ 'title' ],
72 'properties' => [
73 'title' => [
74 'type' => 'string',
75 'description' => __( 'The group name, as a human would write it. Required. Capped at 200 characters, the WordPress term-name limit.', 'betterdocs' )
76 ],
77 'description' => [
78 'type' => 'string',
79 'description' => __( 'Optional description, shown by some FAQ layouts.', 'betterdocs' )
80 ],
81 'slug' => [
82 'type' => 'string',
83 'description' => __( 'URL slug. Derived from the name when omitted.', 'betterdocs' )
84 ],
85 'status' => array_merge(
86 self::group_status_schema(),
87 [ 'default' => 'publish' ]
88 )
89 ],
90 'default' => []
91 ];
92 }
93
94 /**
95 * @since 4.9.0
96 *
97 * @return array
98 */
99 public function get_output_schema() {
100 return [
101 'type' => 'object',
102 'properties' => array_merge(
103 self::group_shape_schema(),
104 [ 'created' => [ 'type' => 'boolean' ] ]
105 )
106 ];
107 }
108
109 /**
110 * @since 4.9.0
111 *
112 * @param array $input Validated input.
113 * @return array|\WP_Error
114 */
115 public function execute( $input ) {
116 $title = isset( $input['title'] ) ? trim( (string) $input['title'] ) : '';
117
118 if ( '' === $title ) {
119 return AbilityError::invalid_input( 'title', __( 'An FAQ group needs a name.', 'betterdocs' ) );
120 }
121
122 $existing = $this->find_group( $title, isset( $input['slug'] ) ? (string) $input['slug'] : '' );
123 $created = false;
124
125 if ( 0 === $existing ) {
126 $params = [ 'title' => $title ];
127
128 foreach ( [ 'description', 'slug' ] as $field ) {
129 if ( isset( $input[ $field ] ) ) {
130 $params[ $field ] = (string) $input[ $field ];
131 }
132 }
133
134 $existing = $this->create_group( $params );
135
136 if ( is_wp_error( $existing ) ) {
137 return $existing;
138 }
139
140 $created = true;
141 }
142
143 $status = $this->apply_group_status( (int) $existing, isset( $input['status'] ) ? (string) $input['status'] : 'publish', $created );
144
145 if ( is_wp_error( $status ) ) {
146 return $status;
147 }
148
149 $item = $this->group_item( (int) $existing );
150
151 if ( is_wp_error( $item ) ) {
152 return $item;
153 }
154
155 return array_merge( $this->group_shape( $item ), [ 'created' => $created ] );
156 }
157
158 /**
159 * The id of the group this title (or slug) already names, or 0.
160 *
161 * Checked before the write rather than after `term_exists` comes back,
162 * because `wp_insert_term()` reports the duplicate id in three different
163 * shapes depending on how it was reached; asking first is one lookup and one
164 * answer.
165 *
166 * @since 4.9.0
167 *
168 * @param string $title Group name.
169 * @param string $slug Requested slug, if any.
170 * @return int
171 */
172 protected function find_group( $title, $slug = '' ) {
173 $candidates = [ [ 'name', $title ], [ 'slug', sanitize_title( '' !== $slug ? $slug : $title ) ] ];
174
175 foreach ( $candidates as $candidate ) {
176 list( $field, $value ) = $candidate;
177
178 if ( '' === $value ) {
179 continue;
180 }
181
182 $term = get_term_by( $field, $value, self::GROUP_TAXONOMY );
183
184 if ( $term && ! is_wp_error( $term ) ) {
185 return (int) $term->term_id;
186 }
187 }
188
189 return 0;
190 }
191
192 /**
193 * Set the group's `status` term meta when it is not already what was asked
194 * for.
195 *
196 * A freshly created group is `1` (the `created_betterdocs_faq_category`
197 * hook stamps it), so `publish` on create writes nothing.
198 *
199 * @since 4.9.0
200 *
201 * @param int $term_id Group id.
202 * @param string $status `publish` or `draft`.
203 * @param bool $created Whether the group was just created.
204 * @return true|\WP_Error
205 */
206 protected function apply_group_status( $term_id, $status, $created ) {
207 $wanted = 'draft' === $status ? '0' : '1';
208
209 if ( ! $created ) {
210 $current = (string) get_term_meta( $term_id, 'status', true );
211
212 if ( $current === $wanted ) {
213 return true;
214 }
215 } elseif ( '1' === $wanted ) {
216 return true;
217 }
218
219 $result = $this->dispatch(
220 'POST',
221 '/faq/category_status',
222 [
223 'term_id' => $term_id,
224 'status' => $wanted
225 ],
226 self::FAQ_NS
227 );
228
229 if ( is_wp_error( $result ) ) {
230 return $this->map_faq_error( $result, __( 'change an FAQ group\'s status', 'betterdocs' ) );
231 }
232
233 return true;
234 }
235 }
236