PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.8.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.8.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 / Core / KBMigration.php

KBMigration.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.8.1, at includes/Core/KBMigration.php

560 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPDeveloper\BetterDocs\Core;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8
9 use WP_Query;
10 use WPDeveloper\BetterDocs\Utils\Base;
11 use WPDeveloper\BetterDocs\Utils\Helper;
12 use WPDeveloper\BetterDocs\Admin\Builder\Rules;
13
14 class KBMigration extends Base {
15 public $existing_plugins;
16 public $migrated_plugins;
17 public $active = 'helpscout';
18
19 public function __construct() {
20 $this->existing_plugins = $this->knowledge_base_plugins();
21 $this->migrated_plugins = $this->get_migrated_plugins();
22
23 add_filter( 'betterdocs_settings_tabs', [ $this, 'migration_settings' ], 10, 1 );
24 if ( ! $this->existing_plugins || ( $this->existing_plugins && in_array( $this->existing_plugins[0][0], $this->migrated_plugins ) ) ) {
25 return;
26 }
27 $this->active = 'kb-migration';
28 //add_filter( 'admin_notices', [ $this, 'migration_notice' ], 10, 1 );
29 add_filter( 'betterdocs_migration_tab_sections', [ $this, 'kb_migration_settings' ], 10, 1 );
30 }
31
32 public function migration_notice() {
33 $screen = get_current_screen()->id;
34 if ( $screen === 'betterdocs_page_betterdocs-setup' ) {
35 return;
36 }
37 ?>
38 <div class="notice notice-success is-dismissible">
39 <?php
40 printf(
41 '<p>%s<a class="button button-primary betterdocs-migration-notice" href="%s">%s</a><a class="button" href="#">%s</a><a class="button" href="#">%s</a></p>',
42 esc_html(
43 sprintf(
44 /* translators: %1$s and %2$s are the name of the existing plugin. */
45 __(
46 'Whoops! You are already using %1$s on your website. To migrate your %2$s data to BetterDocs, click here ',
47 'betterdocs'
48 ),
49 '<strong>' . esc_html( $this->existing_plugins[0][1] ) . '</strong>',
50 '<strong>' . esc_html( $this->existing_plugins[0][1] ) . '</strong>'
51 )
52 ),
53 esc_url( admin_url( 'admin.php?page=betterdocs-settings#migration' ) ),
54 esc_html__( 'Start Migration', 'betterdocs' ),
55 esc_html__( 'Maybe Later', 'betterdocs' ),
56 esc_html__( 'Never Show Again', 'betterdocs' )
57 );
58 ?>
59 </div>
60 <?php
61 }
62
63
64 public function migration_settings( $args ) {
65 /**
66 * License Tab
67 */
68 $args['tab-migration'] = apply_filters(
69 'betterdocs_settings_tab_migration',
70 [
71 'id' => 'tab-migration',
72 'name' => 'tab-migration',
73 'classes' => 'tab-migration',
74 'label' => __( 'Migration', 'betterdocs' ),
75 'priority' => 80,
76 'fields' => [
77 'sections-migration' => [
78 'name' => 'sections-migration',
79 'type' => 'section',
80 'label' => __( 'Migration', 'betterdocs' ),
81 'priority' => 30,
82 'fields' => [
83 'all-migration' => [
84 'id' => 'all-tab-migration',
85 'name' => 'all-tab-migration',
86 'label' => __( 'Migration Settings', 'betterdocs' ),
87 'classes' => 'tab-layout',
88 'type' => 'tab',
89 'active' => $this->active,
90 'completionTrack' => true,
91 'sidebar' => false,
92 'save' => false,
93 'title' => false,
94 'config' => [
95 'active' => $this->active,
96 'sidebar' => false,
97 'title' => false
98 ],
99 'submit' => [
100 'show' => false
101 ],
102 'step' => [
103 'show' => false
104 ],
105 'priority' => 20,
106 'fields' => apply_filters(
107 'betterdocs_migration_tab_sections',
108 [
109 'helpscout' => [
110 'id' => 'helpscout',
111 'name' => 'helpscout',
112 'type' => 'section',
113 'label' => __( 'Help Scout', 'betterdocs' ),
114 'priority' => 2,
115 'fields' => [
116 'helpscout_api_key' => [
117 'name' => 'helpscout_api_key',
118 'type' => 'text',
119 'label' => __( 'Docs API Key', 'betterdocs' ),
120 'label_subtitle' => sprintf(
121 /* translators: %s is a URL to the Help Scout migration documentation. */
122 __( 'Check out this <a target="_blank" href="%s">documentation</a> to retrieve your Help Scout Docs API Key.', 'betterdocs' ),
123 esc_url( 'https://betterdocs.co/docs/help-scout-migration-feature-with-betterdocs/' )
124 ),
125 'default' => '',
126 'priority' => 1,
127 ],
128 'helpscout_collection_id' => [
129 'name' => 'helpscout_collection_id',
130 'type' => 'text',
131 'label' => __( 'Collection ID', 'betterdocs' ),
132 'label_subtitle' => sprintf(
133 /* translators: %s is a URL to the Help Scout migration documentation. */
134 __( 'Check out this <a target="_blank" href="%s">documentation</a> to retrieve your Help Scout Collection ID.', 'betterdocs' ),
135 esc_url( 'https://betterdocs.co/docs/help-scout-migration-feature-with-betterdocs/' )
136 ),
137 'default' => '',
138 'priority' => 2,
139 ],
140 'helpscout_action' => apply_filters(
141 'betterdocs_helpscout_migration_action',
142 [
143 'name' => 'helpscout_action',
144 'text' => [
145 'normal' => __( 'Migrate Help Scout Docs', 'betterdocs' ),
146 'saved' => __( 'Migrate Help Scout Docs', 'betterdocs' ),
147 'loading' => __( 'Migrating...', 'betterdocs' ),
148 ],
149 'type' => 'button',
150 'priority' => 3,
151 'ajax' => [
152 'on' => 'click',
153 'api' => '/betterdocs/v1/helpscout-migration',
154 'data' => [
155 'helpscout_api_key' => '@helpscout_api_key',
156 'helpscout_collection_id' => '@helpscout_collection_id'
157 ],
158 'swal' => [
159 'text' => __( 'Migration process has started in the background.', 'betterdocs' ),
160 'icon' => 'success',
161 'autoClose' => 2000
162 ]
163 ]
164 ]
165 )
166 ]
167 ]
168 ]
169 )
170 ]
171 ]
172 ]
173 ]
174 ]
175 );
176
177 return $args;
178 }
179
180 public function kb_migration_settings( $args ) {
181 /**
182 * License Tab
183 */
184 $args['kb-migration'] = [
185 'id' => 'kb-migration',
186 'name' => 'kb-migration',
187 'type' => 'section',
188 'label' => $this->existing_plugins[0][1],
189 'priority' => 1,
190 'fields' => [
191 'kb-migration-section' => [
192 'name' => 'kb-migration-section',
193 'classes' => 'kb-migration-section',
194 'type' => 'section',
195 'priority' => 0,
196 'save' => false,
197 'fields' => apply_filters(
198 'betterdocs_migration_fields',
199 [
200 'migration_header' => [
201 'name' => 'migration_header',
202 'type' => 'header',
203 'title' => __( 'Migration', 'betterdocs' ),
204 'direction' => 'column',
205 'description' => sprintf(
206 /* translators: %1$s is the name of the existing knowledge base plugin. */
207 __( 'We found that there is another Knowledge Base plugin, %1$s, installed on this website. To migrate your knowledge base to BetterDocs from %2$s, click the "Start Migration" button and all the documentation will be migrated to BetterDocs.', 'betterdocs' ),
208 esc_html( $this->existing_plugins[0][1] ),
209 esc_html( $this->existing_plugins[0][1] )
210 ),
211 'icon' => '<img src="' . betterdocs()->assets->icon( 'icons/migration.svg', true ) . '"/>',
212 'priority' => 1,
213 ],
214 'migration_action' => [
215 'name' => 'migration_action',
216 'type' => 'button',
217 'text' => [
218 'normal' => __( 'Start Migration', 'betterdocs' ),
219 'saved' => __( 'Migrated', 'betterdocs' ),
220 'loading' => __( 'Migrating...', 'betterdocs' ),
221 ],
222 'ajax' => [
223 'on' => 'click',
224 'api' => '/betterdocs/v1/migrate',
225 'data' => [
226 'existing_plugins' => $this->existing_plugins[0][1],
227 ],
228 'swal' => [
229 'text' => __( 'Migration completed successfully.', 'betterdocs' ),
230 'icon' => 'success',
231 'autoClose' => 1000
232 ],
233 'reload' => admin_url( 'admin.php?page=betterdocs-settings' ),
234 ],
235 'priority' => 2,
236 ]
237 ]
238 )
239 ]
240 ]
241 ];
242
243 return $args;
244 }
245
246 public function migrate() {
247 $existing_plugins = $this->knowledge_base_plugins();
248 $existing_plugins_data = $this->existing_plugins_data( $existing_plugins[0][0] );
249 if ( isset( $existing_plugins_data['name'] ) && isset( $existing_plugins_data['url'] ) ) {
250 if ( $existing_plugins_data['name'] === 'echo-knowledge-base' ) {
251 $this->eco_knowledgebase_migration();
252 } elseif ( $existing_plugins_data['name'] === 'pressapps-knowledge-base' ) {
253 $this->pressapps_migration();
254 } elseif ( $existing_plugins_data['name'] === 'wedocs' ) {
255 $this->wedocs_migration();
256 }
257 $this->update_option( $existing_plugins_data['name'] );
258 deactivate_plugins( $existing_plugins_data['url'] );
259 }
260 }
261
262 public function knowledge_base_plugins() {
263 $plugins = [];
264
265 if ( Helper::is_plugin_active( 'wedocs/wedocs.php' ) ) {
266 $plugins[] = [ 'wedocs', 'weDocs' ];
267 }
268 if ( Helper::is_plugin_active( 'bsf-docs/bsf-docs.php' ) ) {
269 $plugins[] = [ 'bsf-docs', 'BSF docs' ];
270 }
271 if ( Helper::is_plugin_active( 'documentor-lite/documentor-lite.php' ) ) {
272 $plugins[] = [ 'documentor-lite', 'Documentor' ];
273 }
274 if ( Helper::is_plugin_active( 'echo-knowledge-base/echo-knowledge-base.php' ) ) {
275 $plugins[] = [ 'echo-knowledge-base', 'Echo Knowledge Base' ];
276 }
277 if ( Helper::is_plugin_active( 'pressapps-knowledge-base/pressapps-knowledge-base.php' ) ) {
278 $plugins[] = [ 'pressapps-knowledge-base', 'PressApps Knowledge Base' ];
279 }
280
281 return $plugins;
282 }
283
284 public function insert_terms_hierarchically( $existing_term, $new_term, $parentId = 0 ) {
285 $into = [];
286 $cats = get_terms(
287 [
288 'taxonomy' => $existing_term,
289 'hide_empty' => false
290 ]
291 );
292 if ( $cats ) {
293 foreach ( $cats as $i => $cat ) {
294 if ( $cat->parent == $parentId ) {
295 $into[ $cat->term_id ] = $cat;
296 unset( $cats[ $i ] );
297 $doc_parent_term = term_exists( $cat->name, $new_term );
298 wp_insert_term(
299 $cat->name,
300 $new_term,
301 [
302 'alias_of' => $cat->slug,
303 'description' => $cat->description,
304 'slug' => $cat->slug,
305 'parent' => $cat->parent
306 ]
307 );
308 }
309 }
310 if ( $cats ) {
311 foreach ( $cats as $i => $cat ) {
312 $get_existing_term = get_term_by( 'id', $cat->parent, $existing_term );
313 $doc_parent_term = term_exists( $get_existing_term->name, $new_term );
314 wp_insert_term(
315 $cat->name,
316 $new_term,
317 [
318 'alias_of' => $cat->slug,
319 'description' => $cat->description,
320 'slug' => $cat->slug,
321 'parent' => $doc_parent_term['term_id']
322 ]
323 );
324 }
325 }
326 }
327 }
328
329 public function insert_posts( $existing_post, $existing_cat, $existing_tag ) {
330 $args = [
331 'post_type' => $existing_post,
332 'post_status' => 'any',
333 'posts_per_page' => -1,
334 ];
335 $postslist = get_posts( $args );
336 if ( $postslist ) {
337 foreach ( $postslist as $post ) {
338 // Check if a post with the same title exists using WP_Query
339 $query_args = [
340 'post_type' => 'docs',
341 'post_status' => 'any',
342 'title' => $post->post_title,
343 'posts_per_page' => 1,
344 'fields' => 'ids',
345 ];
346 $existing_doc = new WP_Query( $query_args );
347
348 if ( ! $existing_doc->have_posts() ) {
349 $post_args = [
350 'post_type' => 'docs',
351 'post_title' => $post->post_title,
352 'post_content' => $post->post_content,
353 'post_status' => $post->post_status,
354 'post_author' => $post->post_author,
355 'post_date' => $post->post_date,
356 'post_date_gmt' => $post->post_date_gmt,
357 'post_excerpt' => $post->post_excerpt,
358 'comment_status' => $post->comment_status,
359 'ping_status' => $post->ping_status,
360 'post_password' => $post->post_password,
361 'post_name' => $post->post_name,
362 'to_ping' => $post->to_ping,
363 'pinged' => $post->pinged,
364 'post_modified' => $post->post_modified,
365 'post_modified_gmt' => $post->post_modified_gmt,
366 'post_content_filtered' => $post->post_content_filtered,
367 'post_parent' => $post->post_parent,
368 'post_mime_type' => $post->post_mime_type,
369 'comment_count' => $post->comment_count,
370 'filter' => $post->filter,
371 ];
372 // Insert the post into the database
373 $result = wp_insert_post( $post_args );
374 if ( $result && ! is_wp_error( $result ) ) {
375 $cat_list = wp_get_post_terms( $post->ID, $existing_cat, [ 'fields' => 'all' ] );
376 if ( $cat_list ) {
377 $post_id = $result;
378 wp_set_object_terms( $post_id, [ $cat_list[0]->name ], 'doc_category', false );
379 }
380 $tag_list = wp_get_post_terms( $post->ID, $existing_tag, [ 'fields' => 'all' ] );
381 if ( $tag_list ) {
382 $post_id = $result;
383 wp_set_object_terms( $post_id, [ $tag_list[0]->name ], 'doc_tag', false );
384 }
385 }
386 }
387
388 // Reset post data after query
389 wp_reset_postdata();
390 }
391 }
392 }
393
394 public function existing_plugins_data( $plugins ) {
395 $plugins_data = [];
396 if ( $plugins === 'wedocs' ) {
397 $plugins_data['name'] = 'wedocs';
398 $plugins_data['url'] = 'wedocs/wedocs.php';
399 }
400 if ( $plugins === 'bsf-docs' ) {
401 $plugins_data['name'] = 'bsf-docs';
402 $plugins_data['url'] = 'bsf-docs/bsf-docs.php';
403 }
404 if ( $plugins === 'documentor-lite' ) {
405 $plugins_data['name'] = 'documentor-lite';
406 $plugins_data['url'] = 'documentor-lite/documentor-lite.php';
407 }
408 if ( $plugins === 'echo-knowledge-base' ) {
409 $plugins_data['name'] = 'echo-knowledge-base';
410 $plugins_data['url'] = 'echo-knowledge-base/echo-knowledge-base.php';
411 }
412 if ( $plugins === 'pressapps-knowledge-base' ) {
413 $plugins_data['name'] = 'pressapps-knowledge-base';
414 $plugins_data['url'] = 'pressapps-knowledge-base/pressapps-knowledge-base.php';
415 }
416 return $plugins_data;
417 }
418
419 public function eco_knowledgebase_migration() {
420 $this->insert_terms_hierarchically( 'epkb_post_type_1_category', 'doc_category' );
421 $this->insert_terms_hierarchically( 'epkb_post_type_1_tag', 'doc_tag' );
422 $this->insert_posts( 'epkb_post_type_1', 'epkb_post_type_1_category', 'epkb_post_type_1_tag' );
423 }
424
425 public function pressapps_migration() {
426 $this->insert_terms_hierarchically( 'knowledgebase_category', 'doc_category' );
427 $this->insert_terms_hierarchically( 'knowledgebase_tags', 'doc_tag' );
428 $this->insert_posts( 'knowledgebase', 'knowledgebase_category', 'knowledgebase_tags' );
429 }
430
431 public function wedocs_migration() {
432 // Step 1: Get posts with no parent (main posts)
433 $args_step1 = array(
434 'post_type' => 'docs',
435 'post_status' => 'publish',
436 'posts_per_page' => -1,
437 'post_parent' => 0,
438 );
439
440 $posts_step1 = get_posts( $args_step1 );
441
442 // Multidimensional array to store posts
443 $nested_posts = array();
444
445 // First Dimension key: 'multiple_kb'
446 foreach ( $posts_step1 as $post_step1 ) {
447 $nested_posts['multiple_kb'][ $post_step1->ID ] = array(
448 'post' => $post_step1,
449 'doc_category' => array(), // Initialize the second dimension
450 );
451
452 // Step 2: 'doc_category'
453 $args_step2 = array(
454 'post_type' => 'docs',
455 'post_status' => 'publish',
456 'posts_per_page' => -1,
457 'post_parent' => $post_step1->ID,
458 );
459
460 $posts_step2 = get_posts( $args_step2 );
461
462 foreach ( $posts_step2 as $post_step2 ) {
463 $nested_posts['multiple_kb'][ $post_step1->ID ]['doc_category'][ $post_step2->ID ] = array(
464 'post' => $post_step2,
465 'docs' => array(), // Initialize the third dimension
466 );
467
468 // Step 3: 'docs'
469 $args_step3 = array(
470 'post_type' => 'docs', // Replace with your actual post type
471 'post_status' => 'publish',
472 'posts_per_page' => -1,
473 'post_parent' => $post_step2->ID,
474 );
475
476 $posts_step3 = get_posts( $args_step3 );
477
478 foreach ( $posts_step3 as $post_step3 ) {
479 $nested_posts['multiple_kb'][ $post_step1->ID ]['doc_category'][ $post_step2->ID ]['docs'][ $post_step3->ID ] = array(
480 'post' => $post_step3,
481 );
482 // Continue with additional dimensions if needed
483 }
484 }
485 }
486
487 // Now, $nested_posts contains the posts organized in a multidimensional array with the specified key names
488
489 foreach ( $nested_posts['multiple_kb'] as $multiple_kb_id => $multiple_kb_data ) {
490 // Step 1: Insert posts as terms under 'knowledge_base'
491 $knowledge_base_id = wp_insert_term( $multiple_kb_data['post']->post_title, 'knowledge_base' );
492
493 if ( ! is_wp_error( $knowledge_base_id ) ) {
494 wp_delete_post( $multiple_kb_data['post']->ID, true );
495 $knowledge_base_term = get_term( $knowledge_base_id['term_id'], 'knowledge_base' );
496 }
497
498 foreach ( $multiple_kb_data['doc_category'] as $doc_category_id => $doc_category_data ) {
499
500 // Step 2: Insert posts as terms under 'doc_category' and set term meta
501 $doc_category_id = wp_insert_term( $doc_category_data['post']->post_title, 'doc_category' );
502
503 if ( ! is_wp_error( $doc_category_id ) ) {
504 $doc_category_term = get_term( $doc_category_id['term_id'], 'doc_category' );
505 wp_delete_post( $doc_category_data['post']->ID, true );
506 $doc_category_kb = rest_sanitize_array( array( $knowledge_base_term->slug ) );
507 // Set term meta for 'knowledge_base_doc_category'
508 update_term_meta( $doc_category_id['term_id'], 'doc_category_knowledge_base', $doc_category_kb );
509 }
510
511 foreach ( $doc_category_data['docs'] as $docs_id => $docs_data ) {
512 wp_set_post_terms( $docs_data['post']->ID, array( $knowledge_base_term->term_id ), 'knowledge_base' );
513 wp_set_post_terms( $docs_data['post']->ID, array( $doc_category_term->term_id ), 'doc_category' );
514 // // Step 3: Update posts to assign correct parent terms
515 // wp_update_post(array(
516 // 'ID' => $docs_data['post']->ID,
517 // 'post_parent' => 0,
518 // ));
519 }
520 }
521 }
522 }
523
524 /**
525 * Updates the 'betterdocs_migration' option with migrated knowledge base plugin names.
526 *
527 * This function checks if the option exists and is a serialized array. If the option exists,
528 * it unserializes the current value, merges it with the new values, serializes the merged array,
529 * and updates the option. If the option doesn't exist or is not a serialized array, it creates
530 * a new option with the serialized format.
531 *
532 * @param string $kb_name The name of the knowledge base to be added or updated.
533 *
534 * @return void
535 */
536 public function update_option( $kb_name ) {
537 $existing_value = get_option( 'betterdocs_migration' );
538 $new_values = array( $kb_name );
539
540 if ( $existing_value !== false && is_serialized( $existing_value ) ) {
541 $existing_values_array = unserialize( $existing_value );
542 $merged_values = array_merge( $existing_values_array, $new_values );
543
544 update_option( 'betterdocs_migration', serialize( $merged_values ) );
545 } else {
546 update_option( 'betterdocs_migration', serialize( $new_values ) );
547 }
548 }
549
550 public function get_migrated_plugins() {
551 $existing_value = get_option( 'betterdocs_migration' );
552
553 if ( $existing_value ) {
554 return unserialize( $existing_value );
555 }
556
557 return [];
558 }
559 }
560