PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.5.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.5.5
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 / Migration.php

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

160 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- one-shot data/schema migrations; caching unwanted.
3 namespace WPDeveloper\BetterDocs\Core;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use WP_Query;
10 use WPDeveloper\BetterDocs\Utils\Base;
11 use WPDeveloper\BetterDocs\Utils\Database;
12 use WPDeveloper\BetterDocs\Dependencies\DI\Container;
13
14 class Migration extends Base {
15 /**
16 * Database
17 * @var Database
18 */
19 private $database;
20 private $settings;
21 private $container;
22
23 public function __construct( Container $container ) {
24 $this->container = $container;
25 $this->database = $container->get( Database::class );
26 $this->settings = $container->get( Settings::class );
27 }
28
29 public function init( $version ) {
30 if ( $version > 250 ) {
31 for ( $_version = 250; $_version <= $version; $_version++ ) {
32 if ( method_exists( $this, "v$_version" ) ) {
33 call_user_func( [ $this, "v$_version" ] );
34 }
35 }
36 }
37
38 $this->search_migration();
39 $this->fix_search_table_collation();
40
41 /**
42 * Settings Migration
43 */
44 $this->settings->migration( $version );
45 }
46
47 public function search_migration() {
48 global $wpdb;
49 if ( ! $this->database->get( 'betterdocs_search_data_migration', false ) ) {
50 $search_data = $this->database->get( 'betterdocs_search_data' );
51 if ( ! empty( $search_data ) ) {
52 $search_data_arr = unserialize( $search_data );
53 foreach ( $search_data_arr as $key => $value ) {
54 $args = [
55 'post_type' => 'docs',
56 'post_status' => 'publish',
57 'posts_per_page' => -1,
58 'suppress_filters' => true, // phpcs:ignore WordPressVIPMinimum.Hooks.PreGetPosts.PreGetPosts,WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- migration must run on raw posts without language filters.
59 's' => $key
60 ];
61
62 $loop = new WP_Query( $args );
63 if ( $loop->have_posts() ) {
64 $count = $value;
65 $not_found_count = 0;
66 } else {
67 $count = 0;
68 $not_found_count = $value;
69 }
70
71 // Use BINARY comparison to avoid collation mismatch errors
72 $keyword = $wpdb->get_var(
73 $wpdb->prepare(
74 "
75 SELECT keyword
76 FROM {$wpdb->prefix}betterdocs_search_keyword
77 WHERE BINARY keyword = %s",
78 $key
79 )
80 );
81
82 if ( $keyword == null ) {
83 $insert = $wpdb->query(
84 $wpdb->prepare(
85 "INSERT INTO {$wpdb->prefix}betterdocs_search_keyword
86 ( keyword )
87 VALUES ( %s )",
88 [
89 $key
90 ]
91 )
92 );
93
94 if ( $insert ) {
95 $wpdb->query(
96 $wpdb->prepare(
97 "INSERT INTO {$wpdb->prefix}betterdocs_search_log
98 (keyword_id, count, not_found_count, created_at)
99 VALUES (%d, %d, %d, %s)",
100 [
101 $wpdb->insert_id,
102 $count,
103 $not_found_count,
104 gmdate( 'Y-m-d' )
105 ]
106 )
107 );
108 }
109 }
110 }
111
112 $this->database->save( 'betterdocs_search_data_migration', '1.0' );
113 }
114 }
115 }
116
117 /**
118 * Fix collation issues in search tables
119 * Converts tables to proper UTF-8 charset and collation to prevent
120 * "Illegal mix of collations" errors when searching with non-Latin characters
121 *
122 * @since 1.0.2
123 * @return void
124 */
125 public function fix_search_table_collation() {
126 global $wpdb;
127
128 // Check if migration already ran
129 if ( $this->database->get( 'betterdocs_search_collation_fixed', false ) ) {
130 return;
131 }
132
133 // Get the WordPress default charset and collation; restrict to a safe identifier
134 // alphabet because they're interpolated into ALTER TABLE statements below.
135 $charset = preg_replace( '/[^A-Za-z0-9_]/', '', $wpdb->charset ? $wpdb->charset : 'utf8mb4' );
136 $collate = preg_replace( '/[^A-Za-z0-9_]/', '', $wpdb->collate ? $wpdb->collate : 'utf8mb4_unicode_520_ci' );
137
138 // Fix search_keyword table
139 $search_keyword_table = $wpdb->prefix . 'betterdocs_search_keyword';
140 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- one-shot collation migration; identifiers come from $wpdb only.
141 if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $search_keyword_table ) ) === $search_keyword_table ) {
142 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter
143 $wpdb->query( "ALTER TABLE `{$search_keyword_table}` CONVERT TO CHARACTER SET {$charset} COLLATE {$collate}" );
144 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter
145 $wpdb->query( "ALTER TABLE `{$search_keyword_table}` MODIFY keyword TEXT CHARACTER SET {$charset} COLLATE {$collate} NOT NULL" );
146 }
147
148 // Fix search_log table
149 $search_log_table = $wpdb->prefix . 'betterdocs_search_log';
150 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange
151 if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $search_log_table ) ) === $search_log_table ) {
152 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter
153 $wpdb->query( "ALTER TABLE `{$search_log_table}` CONVERT TO CHARACTER SET {$charset} COLLATE {$collate}" );
154 }
155
156 // Mark migration as complete
157 $this->database->save( 'betterdocs_search_collation_fixed', '1.0' );
158 }
159 }
160