PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.8
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.8
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 2.6.4 2.6.3 2.5.23 All 138 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.8, at redirections/class-metasync-redirection-database.php

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