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

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

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