PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.1
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 / REST / Settings.php

Settings.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.1, at includes/REST/Settings.php

367 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\REST;
4
5 use WP_Query;
6 use WP_REST_Request;
7 use WPDeveloper\BetterDocs\Admin\CSVExporter;
8 use WPDeveloper\BetterDocs\Admin\Importer\Parsers\CSV_Parser;
9 use WPDeveloper\BetterDocs\Admin\Importer\WPImport;
10 use WPDeveloper\BetterDocs\Admin\ReportEmail;
11 use WPDeveloper\BetterDocs\Admin\XMLExporter;
12 use WPDeveloper\BetterDocs\Core\BaseAPI;
13 use WPDeveloper\BetterDocs\Dependencies\DI\DependencyException;
14 use WPDeveloper\BetterDocs\Dependencies\DI\NotFoundException;
15 use WPDeveloper\BetterDocsChatbot\Core\AIChatbot;
16 use WPDeveloper\BetterDocs\Core\Settings as CoreSettings;
17 use WPDeveloper\BetterDocs\Utils\Helper;
18
19 class Settings extends BaseAPI {
20
21 public function permission_check(): bool {
22 return current_user_can( 'edit_docs_settings' );
23 }
24
25 public function register() {
26 $this->get( 'settings', [ $this, 'get_settings' ] );
27 $this->post( 'dark-mode', [ $this, 'dark_mode' ] );
28 $this->post( 'settings', [ $this, 'save_settings' ] );
29 $this->post( 'plugin_insights', [ $this, 'plugin_insights' ] );
30 $this->post( 'create-sample-docs', [$this, 'sample_docs'] );
31 $this->post( 'reporting-test', [ $this, 'test_reporting' ] );
32 $this->post( 'export-docs', [ $this, 'export_docs' ] );
33 $this->post( 'export-settings', [ $this, 'export_settings' ] );
34 $this->post( 'import-docs', [ $this, 'import_docs' ] );
35 $this->post( 'import-settings', [ $this, 'import_settings' ] );
36 $this->post( 'parse-xml', [ $this, 'parse_xml' ] );
37 $this->post( 'parse-csv', [ $this, 'parse_csv' ] );
38 $this->post( 'migrate', [ $this, 'migrate_plugins' ] );
39 $this->post( 'helpscout-migration', [$this, 'helpscout_migration'] );
40 $this->post( 'dashboard-mode', [$this, 'dashboard_mode'] );
41 }
42
43 public function dashboard_mode( WP_REST_Request $request ) {
44 $mode = $request->get_param( 'dashboard_mode' );
45 return update_option( 'dashboard_mode', $mode );
46 }
47
48 public function dark_mode( WP_REST_Request $request ): bool {
49 $dark_mode = rest_sanitize_boolean( $request->get_param( 'mode' ) );
50
51 if ( betterdocs()->settings->save( 'dark_mode', $dark_mode ) ) {
52 return true;
53 }
54
55 return false;
56 }
57
58 public function sample_docs( WP_REST_Request $request ) {
59 $action = $request->get_param( 'action' );
60
61 if ( $action == 'create-dummy-data' ) {
62 $file = BETTERDOCS_ABSPATH . 'assets/static/admin/images/BetterDocs-sample-data.csv';
63 $args = [
64 'fetch_attachments' => true,
65 'action' => '',
66 'existing_slug' => '',
67 'file_type' => 'text/csv'
68 ];
69 $wp_import_object = new WPImport( $file, $args );
70 return $wp_import_object->run();
71 }
72 }
73
74 public function export_docs( WP_REST_Request $request ) {
75 $data = $request->get_params();
76 $args = [
77 'include_post_featured_image_as_attachment' => true,
78 'status' => 'publish',
79 'content' => $data['export_type'],
80 'selected_docs' => $data['export_docs'],
81 'include_faq' => $data['enable_export_faq'],
82 ];
83
84 if ( $data['export_type'] == 'docs' && $data['export_docs'][0] != 'all' ) {
85 $args['post__in'] = $data['export_docs'];
86 }
87
88 if ( $data['export_type'] == 'doc_category' || $data['export_type'] == 'knowledge_base' ) {
89 $args['content'] = 'docs';
90 }
91
92 if ( $data['export_type'] == 'doc_category' && $data['export_categories'][0] != 'all' ) {
93 $args['category_terms'] = $data['export_categories'];
94 } else if ( $data['export_type'] == 'knowledge_base' && $data['export_kbs'][0] != 'all' ) {
95 $args['kb_terms'] = $data['export_kbs'];
96 }
97
98 if ( $data['export_type'] == 'glossaries' && $data['export_glossaries'][0] != 'all' ) {
99 $args['glossary_terms'] = $data['export_glossaries'];
100 unset( $args['selected_docs'] );
101 }
102
103 if ( $data['file_type'] == 'xml' ) {
104 $exporter = new XMLExporter( $args );
105 } else if ( $data['file_type'] == 'csv' ) {
106 $exporter = new CSVExporter( $args );
107 }
108
109 /**
110 * @var XMLExporter|CSVExporter $exporter
111 */
112
113 return $exporter->run();
114 }
115
116 public function export_settings( WP_REST_Request $request ): array {
117 $betterdocs_settings = get_option( 'betterdocs_settings' );
118 $json_str = json_encode( $betterdocs_settings, JSON_PRETTY_PRINT );
119 $file_name = 'betterdocs-settings.json';
120
121 return [
122 'success' => true,
123 'data' => [
124 'filename' => $file_name,
125 'filetype' => 'text/json',
126 'download' => $json_str,
127 ]
128 ];
129 }
130
131 public function import_settings( WP_REST_Request $request ): array {
132 $settings = $request->get_param( 'settings' );
133 // Decode the JSON data into a PHP array
134 $settings = json_decode( $settings, true );
135 $saved = update_option( 'betterdocs_settings', $settings );
136
137 if ( ! $saved ) {
138 return [
139 'status' => 'failed'
140 ];
141 }
142
143 return [
144 'status' => 'success'
145 ];
146 }
147
148 public function import_docs( WP_REST_Request $request ): array {
149 $existing_slug = $request->get_param( 'existing_slug' );
150 $action = $request->get_param( 'action' );
151
152 $files = $request->get_file_params();
153
154 $file = $files['file']['tmp_name'];
155
156 $args = [
157 'fetch_attachments' => true,
158 'existing_slug' => $existing_slug,
159 'action' => $action,
160 'file_type' => $files['file']['type'],
161 // The original upload name (with its extension) is the reliable
162 // signal for choosing the parser; the browser-reported MIME on
163 // $files['file']['type'] is not.
164 'file_name' => isset( $files['file']['name'] ) ? $files['file']['name'] : ''
165 ];
166
167 $wp_importer = new WPImport( $file, $args );
168
169 return $wp_importer->run();
170 }
171
172 public function parse_xml( WP_REST_Request $request ): array {
173 $data = $request->get_params();
174 $existing_post_slugs = $this->get_existing_slugs( $data['posts'] );
175
176 // Output the array of existing post slugs
177 return [
178 'status' => 'success',
179 'data' => $existing_post_slugs,
180 ];
181 }
182
183 public function parse_csv( WP_REST_Request $request ): array {
184 $files = $request->get_file_params();
185
186 $file = $files['file']['tmp_name'];
187
188 $parser = new CSV_Parser();
189 $parsed = $parser->parse( $file );
190
191 $existing_post_slugs = [];
192
193 if ( isset( $parsed['posts'] ) && is_array( $parsed['posts'] ) ) {
194 $post_names = array_map(
195 function ( $post ) {
196 return $post['post_name'];
197 },
198 $parsed['posts']
199 );
200
201 $existing_post_slugs = $this->get_existing_slugs( $post_names );
202 }
203
204 return [
205 'status' => 'success',
206 'data' => $existing_post_slugs,
207 ];
208 }
209
210 public function migrate_plugins( WP_REST_Request $request ): array {
211 betterdocs()->kbmigration->migrate();
212
213 return [
214 'status' => 'success'
215 ];
216 }
217
218 public function helpscout_migration( WP_REST_Request $request ) {
219 $api_key = $request->get_param( 'helpscout_api_key' );
220 $collection_id = $request->get_param( 'helpscout_collection_id' );
221
222 if ( ! $api_key || ! $collection_id ) {
223 return [
224 'status' => 'error',
225 'message' => esc_html__( 'Please provide both API Key and Collection ID', 'betterdocs' )
226 ];
227 }
228
229 $api_endpoint = 'https://docsapi.helpscout.net/v1/collections/' . $collection_id . '/articles?pageSize=1';
230
231 $headers = array(
232 'Authorization' => 'Basic ' . base64_encode( $api_key . ':X' ),
233 'Content-Type' => 'application/json',
234 );
235
236 $initial_response = wp_remote_get( $api_endpoint, array( 'headers' => $headers ) );
237
238 if ( $initial_response['response']['code'] == '404' || $initial_response['response']['code'] == 401 ) {
239 return [
240 'status' => 'error',
241 'message' => esc_html__( 'Unauthorized API Key or Collection ID', 'betterdocs' )
242 ];
243 }
244
245 // Enqueue migration task
246 betterdocs()->backgroundProccessor->push_to_queue(
247 array(
248 'headers' => $headers,
249 'initial_response' => $initial_response,
250 'api_key' => $api_key,
251 'collection_id' => $collection_id
252 )
253 )->save();
254
255 // Start processing the queue
256 betterdocs()->backgroundProccessor->dispatch();
257
258 return [
259 'status' => 'success',
260 'message' => esc_html__( 'Migration process has started in the background.', 'betterdocs' )
261 ];
262 }
263
264 public function get_existing_slugs( $slugs ) {
265 // Initialize the array for existing post slugs
266 $existing_post_slugs = [];
267
268 // Initialize the query arguments
269 $args = [
270 'post_type' => [ 'docs', 'betterdocs_faq' ], // Change 'post' to your custom post type if applicable
271 'post_status' => 'publish',
272 'posts_per_page' => -1, // Retrieve all posts
273 'fields' => 'ids', // Retrieve only post IDs to reduce memory usage
274 ];
275
276 // Create a new instance of WP_Query
277 $query = new WP_Query( $args );
278
279 // Get an array of post slugs from the query
280 $all_post_slugs = array_map(
281 function ( $post_id ) {
282 return get_post_field( 'post_name', $post_id );
283 },
284 $query->posts
285 );
286
287 // Restore original post data
288 wp_reset_postdata();
289
290 // Find the intersection of the two arrays to get existing post slugs
291 return array_intersect( $slugs, $all_post_slugs );
292 }
293
294 public function insights(): bool {
295 return true;
296 }
297
298 public function get_settings(): array {
299 $settings = betterdocs()->settings->get_all( true );
300
301 // Never hand raw API keys back over REST. The route is already gated to
302 // `edit_docs_settings` (see permission_check() above), but get_all( true ) returned
303 // UNMASKED values, so an authorized admin still received every key in full — the admin
304 // UI only ever needs the masked form. Mask for managers, and strip entirely for anyone
305 // else as defense-in-depth should that capability gate ever loosen. Mirrors the
306 // admin-page localizer (Core\Settings::enqueue()) so the masked-key save round-trip
307 // stays consistent.
308 $sensitive_api_keys = CoreSettings::sensitive_api_key_fields();
309 $can_manage = current_user_can( 'edit_docs_settings' );
310 foreach ( $sensitive_api_keys as $api_key_field ) {
311 if ( ! isset( $settings[ $api_key_field ] ) ) {
312 continue;
313 }
314 if ( ! $can_manage ) {
315 unset( $settings[ $api_key_field ] );
316 continue;
317 }
318 if ( ! empty( $settings[ $api_key_field ] ) ) {
319 $settings[ $api_key_field ] = Helper::mask_api_key( $settings[ $api_key_field ] );
320 }
321 }
322
323 return $settings;
324 }
325
326 public function save_settings( WP_REST_Request $request ) {
327 $result = betterdocs()->settings->save_settings( $request->get_params() );
328 if ( is_wp_error( $result ) ) {
329 return $this->error( $result->get_error_code(), $result->get_error_message(), 400 );
330 }
331 if ( $result ) {
332 return $this->success( __( 'Settings Saved!', 'betterdocs' ) );
333 }
334
335 return $this->error( 'nothing_changed', __( 'There are no changes to be saved.', 'betterdocs' ), 200 );
336 }
337
338 /**
339 * @throws NotFoundException
340 * @throws DependencyException
341 */
342 public function test_reporting( $request ) {
343 return $this->container->get( ReportEmail::class )->test_email_report( $request );
344 }
345
346 public function do_wizard_tracking(): bool {
347 $insights = betterdocs()->admin->plugin_insights( true );
348 // Get our data
349 $insights->schedule_tracking();
350 $insights->set_is_tracking_allowed( true, 'betterdocs' );
351 if ( $insights->do_tracking( true ) ) {
352 $insights->update_block_notice( 'betterdocs' );
353 }
354 if ( ! isset( $_COOKIE['betterdocs_insights_allowed'] ) ) {
355 setcookie( 'betterdocs_insights_allowed', true, time() + ( 30 * 24 * 60 * 60 ), '/' );
356 }
357 return true;
358 }
359
360 public function plugin_insights( $request ) {
361 if ( $this->do_wizard_tracking() ) {
362 wp_send_json_success( 'done' );
363 }
364 wp_send_json_error( 'Something went wrong.' );
365 }
366 }
367