PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.6
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.6
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / redirections / class-metasync-redirection-database.php

class-metasync-redirection-database.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.6, at redirections/class-metasync-redirection-database.php

372 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The database operations for the redirections.
5 *
6 * @since 1.0.0
7 * @package Metasync
8 * @subpackage Metasync/redirections
9 * @author Engineering Team <[email protected]>
10 */
11 if (!class_exists('Metasync_Redirection_Database')) {
12 class Metasync_Redirection_Database
13 {
14 public static $table_name = "metasync_redirections";
15
16 private function get_table_name()
17 {
18 global $wpdb;
19 return $wpdb->prefix . self::$table_name;
20 }
21
22 /**
23 * Ensure table structure is up to date
24 */
25 private function ensure_table_structure()
26 {
27 global $wpdb;
28 $table_name = $this->get_table_name();
29
30 // Check if table exists
31 if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) {
32 // Table doesn't exist, run full migration
33 require_once dirname(__FILE__, 2) . '/database/class-db-migrations.php';
34 MetaSync_DBMigration::activation();
35 return;
36 }
37
38 // Check if required columns exist
39 $columns = $wpdb->get_col("DESCRIBE {$table_name}");
40
41 $required_columns = [
42 'pattern_type' => "ALTER TABLE {$table_name} ADD COLUMN pattern_type ENUM('exact', 'contain', 'start', 'end', 'regex') NOT NULL DEFAULT 'exact' AFTER status",
43 'regex_pattern' => "ALTER TABLE {$table_name} ADD COLUMN regex_pattern TEXT NULL AFTER pattern_type",
44 'description' => "ALTER TABLE {$table_name} ADD COLUMN description TEXT NULL AFTER regex_pattern",
45 'created_at' => "ALTER TABLE {$table_name} ADD COLUMN created_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER description",
46 'updated_at' => "ALTER TABLE {$table_name} ADD COLUMN updated_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER created_at",
47 'last_accessed_at' => "ALTER TABLE {$table_name} ADD COLUMN last_accessed_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER updated_at"
48 ];
49
50 foreach ($required_columns as $column => $sql) {
51 if (!in_array($column, $columns)) {
52 $wpdb->query($sql);
53 }
54 }
55
56 // Check and add indexes
57 $indexes = $wpdb->get_results("SHOW INDEX FROM {$table_name}");
58 $index_names = array_column($indexes, 'Key_name');
59
60 $required_indexes = [
61 'pattern_type' => "ALTER TABLE {$table_name} ADD KEY pattern_type (pattern_type)",
62 'created_at' => "ALTER TABLE {$table_name} ADD KEY created_at (created_at)",
63 'status_created' => "ALTER TABLE {$table_name} ADD KEY status_created (status, created_at)"
64 ];
65
66 foreach ($required_indexes as $index => $sql) {
67 if (!in_array($index, $index_names)) {
68 $wpdb->query($sql);
69 }
70 }
71
72 // Set default pattern_type for existing records
73 $wpdb->query("UPDATE {$table_name} SET pattern_type = 'exact' WHERE pattern_type IS NULL OR pattern_type = ''");
74 }
75
76 /**
77 * Manually trigger table structure update
78 * Can be called from admin or via AJAX if needed
79 */
80 public function force_table_update()
81 {
82 $this->ensure_table_structure();
83 return true;
84 }
85
86 public function getAllRecords()
87 {
88 global $wpdb;
89 $tableName = $this->get_table_name();
90 return $wpdb->get_results(" SELECT * FROM `$tableName` ");
91 }
92
93 public function getAllActiveRecords()
94 {
95 global $wpdb;
96 $tableName = $this->get_table_name();
97
98 // Check cache first
99 $cache_key = 'metasync_active_redirections';
100 $cached_redirections = wp_cache_get($cache_key, 'metasync');
101
102 if ($cached_redirections !== false) {
103 return $cached_redirections;
104 }
105
106 $redirections = $wpdb->get_results($wpdb->prepare("SELECT * FROM `$tableName` WHERE status = %s ORDER BY created_at DESC", 'active'));
107
108 // Cache for 1 hour
109 wp_cache_set($cache_key, $redirections, 'metasync', HOUR_IN_SECONDS);
110
111 return $redirections;
112 }
113
114 /**
115 * Find a single redirection by ID
116 * @param int $id The redirection ID
117 * @return object|null The redirection record or null if not found
118 */
119 public function find($id)
120 {
121 global $wpdb;
122 $tableName = $this->get_table_name();
123 return $wpdb->get_row($wpdb->prepare("SELECT * FROM `$tableName` WHERE id = %d", intval($id)));
124 }
125
126 /**
127 * Add a record.
128 * @param array $args Values to insert.
129 */
130 public function add($args)
131 {
132 global $wpdb;
133
134 // Ensure table structure is up to date
135 $this->ensure_table_structure();
136
137 $args = wp_parse_args(
138 $args,
139 [
140 'sources_from' => [],
141 'url_redirect_to' => site_url(),
142 'http_code' => 301,
143 'hits_count' => 0,
144 'status' => 'active',
145 'pattern_type' => 'exact',
146 'regex_pattern' => null,
147 'description' => '',
148 'created_at' => current_time('mysql'),
149 'updated_at' => current_time('mysql'),
150 ]
151 );
152
153 // Serialize sources_from if array (rest of codebase uses serialized format)
154 if ( is_array( $args['sources_from'] ) ) {
155 $sources = $args['sources_from'];
156 $args['sources_from'] = serialize( array_combine( array_values( $sources ), array_fill( 0, count( $sources ), 'exact' ) ) ?: [] );
157 }
158
159 $result = $wpdb->insert( $this->get_table_name(), $args );
160
161 // Clear cache after adding
162 $this->clear_cache();
163
164 return $result !== false ? (int) $wpdb->insert_id : false;
165 }
166
167 /**
168 * Update a record.
169 * @param array $args Values to update.
170 * @param string $id
171 */
172 public function update($args, $id)
173 {
174 global $wpdb;
175
176 // Ensure table structure is up to date
177 $this->ensure_table_structure();
178
179 $tableName = $this->get_table_name();
180 $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM `$tableName` WHERE `id` = %s ", $id));
181 if (!$row) return;
182
183 $args['updated_at'] = current_time('mysql');
184 $wpdb->update($tableName, $args, ['id' => $id]);
185
186 // Clear cache after updating
187 $this->clear_cache();
188 }
189
190 /**
191 * Get total number of rows in the DB table).
192 */
193 public function get_count()
194 {
195 global $wpdb;
196 $tableName = $this->get_table_name();
197 return (int) $wpdb->get_var("SELECT COUNT(*) FROM `$tableName`");
198 }
199
200 /**
201 * Delete a redirection record.
202 */
203 public function delete($items)
204 {
205 global $wpdb;
206 $tableName = $this->get_table_name();
207 if (!is_array($items) || empty($items)) return;
208 $ids = implode(',', array_fill(0, count($items), '%d'));
209 $wpdb->query($wpdb->prepare(
210 "
211 DELETE FROM `$tableName`
212 WHERE `id` IN ($ids) ",
213 $items
214 ));
215
216 // Clear cache after deleting
217 $this->clear_cache();
218 }
219
220 /**
221 * activate a redirection record.
222 */
223 public function update_status($items, $status)
224 {
225 global $wpdb;
226 $tableName = $this->get_table_name();
227 if (!is_array($items) || empty($items)) return;
228 $ids = implode(', ', array_fill(0, count($items), '%d'));
229 $set_status = $wpdb->prepare(
230 "
231 UPDATE `$tableName`
232 SET `status` = %s, `updated_at` = %s",
233 $status,
234 current_time('mysql')
235 );
236 $where = $wpdb->prepare(
237 "
238 WHERE `id` IN ( $ids )",
239 $items
240 );
241 $query = "{$set_status}{$where}";
242 $wpdb->query($query);
243
244 // Clear cache after updating status
245 $this->clear_cache();
246 }
247
248 /**
249 * Update if URL is matched and hit.
250 * @param object $row Record to update.
251 */
252 public function update_counter($row)
253 {
254 global $wpdb;
255 $update_data = [
256 'last_accessed_at' => current_time('mysql'),
257 'hits_count' => absint($row->hits_count) + 1,
258 ];
259 $wpdb->update($this->get_table_name(), $update_data, ['id' => $row->id]);
260 }
261
262 /**
263 * Clear redirection cache
264 */
265 public function clear_cache()
266 {
267 wp_cache_delete('metasync_active_redirections', 'metasync');
268 }
269
270 /**
271 * Search redirections with filters
272 * @param array $filters Search filters
273 */
274 public function search_redirections($filters = [])
275 {
276 global $wpdb;
277 $tableName = $this->get_table_name();
278
279 $where_conditions = ['1=1'];
280 $where_values = [];
281
282 if (!empty($filters['search'])) {
283 $where_conditions[] = "(sources_from LIKE %s OR url_redirect_to LIKE %s OR description LIKE %s)";
284 $search_term = '%' . $wpdb->esc_like($filters['search']) . '%';
285 $where_values[] = $search_term;
286 $where_values[] = $search_term;
287 $where_values[] = $search_term;
288 }
289
290 if (!empty($filters['status'])) {
291 $where_conditions[] = "status = %s";
292 $where_values[] = $filters['status'];
293 }
294
295 if (!empty($filters['pattern_type'])) {
296 $where_conditions[] = "pattern_type = %s";
297 $where_values[] = $filters['pattern_type'];
298 }
299
300 if (!empty($filters['http_code'])) {
301 $where_conditions[] = "http_code = %d";
302 $where_values[] = intval($filters['http_code']);
303 }
304
305 $where_clause = implode(' AND ', $where_conditions);
306 $order_by = !empty($filters['order_by']) ? sanitize_sql_orderby($filters['order_by']) : 'created_at';
307 $order = !empty($filters['order']) && strtoupper($filters['order']) === 'ASC' ? 'ASC' : 'DESC';
308
309 // Add pagination support
310 $limit_clause = '';
311 if (isset($filters['per_page']) && isset($filters['offset'])) {
312 $limit_clause = " LIMIT %d OFFSET %d";
313 $where_values[] = intval($filters['per_page']);
314 $where_values[] = intval($filters['offset']);
315 }
316
317 $query = "SELECT * FROM `$tableName` WHERE $where_clause ORDER BY $order_by $order" . $limit_clause;
318
319 if (!empty($where_values)) {
320 return $wpdb->get_results($wpdb->prepare($query, $where_values));
321 } else {
322 return $wpdb->get_results($query);
323 }
324 }
325
326 /**
327 * Count total redirections with filters (for pagination)
328 * @param array $filters Search filters
329 */
330 public function count_redirections($filters = [])
331 {
332 global $wpdb;
333 $tableName = $this->get_table_name();
334
335 $where_conditions = ['1=1'];
336 $where_values = [];
337
338 if (!empty($filters['search'])) {
339 $where_conditions[] = "(sources_from LIKE %s OR url_redirect_to LIKE %s OR description LIKE %s)";
340 $search_term = '%' . $wpdb->esc_like($filters['search']) . '%';
341 $where_values[] = $search_term;
342 $where_values[] = $search_term;
343 $where_values[] = $search_term;
344 }
345
346 if (!empty($filters['status'])) {
347 $where_conditions[] = "status = %s";
348 $where_values[] = $filters['status'];
349 }
350
351 if (!empty($filters['pattern_type'])) {
352 $where_conditions[] = "pattern_type = %s";
353 $where_values[] = $filters['pattern_type'];
354 }
355
356 if (!empty($filters['http_code'])) {
357 $where_conditions[] = "http_code = %d";
358 $where_values[] = intval($filters['http_code']);
359 }
360
361 $where_clause = implode(' AND ', $where_conditions);
362 $query = "SELECT COUNT(*) FROM `$tableName` WHERE $where_clause";
363
364 if (!empty($where_values)) {
365 return $wpdb->get_var($wpdb->prepare($query, $where_values));
366 } else {
367 return $wpdb->get_var($query);
368 }
369 }
370 }
371 }
372