PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.5.23
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.5.23
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.5.23, at redirections/class-metasync-redirection-database.php

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