PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
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
← All changes | includes/class-metasync-admin-ajax.php +42 -45 2.6.25 → 2.7.1 View file →
@@ -57,9 +57,9 @@
57 57 $replacement = array('owner' => $owner, 'time' => time());
58 58 global $wpdb;
59 59 if (isset($wpdb) && is_object($wpdb) && method_exists($wpdb, 'query') && method_exists($wpdb, 'prepare')) {
60 60 $serialize = function ($value) { return function_exists('maybe_serialize') ? maybe_serialize($value) : serialize($value); };
61 - $wpdb->query($wpdb->prepare(
61 + $wpdb->query($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- atomic compare-and-swap on option rows — the WHERE-guarded UPDATE/DELETE is the lock primitive
62 62 "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value = %s",
63 63 $serialize($replacement), $key, $serialize($held)
64 64 ));
65 65 if (function_exists('wp_cache_delete')) wp_cache_delete($key, 'options');
@@ -79,9 +79,9 @@
79 79 if (is_array($held) && isset($held['owner']) && hash_equals((string) $held['owner'], (string) $owner)) {
80 80 global $wpdb;
81 81 if (isset($wpdb) && is_object($wpdb) && method_exists($wpdb, 'query') && method_exists($wpdb, 'prepare')) {
82 82 $serialized = function_exists('maybe_serialize') ? maybe_serialize($held) : serialize($held);
83 - $wpdb->query($wpdb->prepare(
83 + $wpdb->query($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- atomic compare-and-swap on option rows — the WHERE-guarded UPDATE/DELETE is the lock primitive
84 84 "DELETE FROM {$wpdb->options} WHERE option_name = %s AND option_value = %s",
85 85 $key,
86 86 $serialized
87 87 ));
@@ -127,9 +127,9 @@
127 127 public function ajax_import_external_data()
128 128 {
129 129 $execution_time = Metasync_Settings_Fields::instance()->get_execution_setting('max_execution_time');
130 130 if (function_exists('set_time_limit')) {
131 - @set_time_limit($execution_time);
131 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
132 132 }
133 133
134 134 Metasync_Settings_Fields::instance()->apply_memory_limit();
135 135
@@ -138,10 +138,10 @@
138 138 if (!Metasync::current_user_has_plugin_access()) {
139 139 wp_send_json_error(['message' => 'Insufficient permissions.']);
140 140 }
141 141
142 - $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : '';
143 - $plugin = isset($_POST['plugin']) ? sanitize_text_field($_POST['plugin']) : '';
142 + $type = isset($_POST['type']) ? sanitize_text_field(wp_unslash($_POST['type'])) : '';
143 + $plugin = isset($_POST['plugin']) ? sanitize_text_field(wp_unslash($_POST['plugin'])) : '';
144 144 $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
145 145
146 146 if (empty($type) || empty($plugin)) {
147 147 wp_send_json_error(['message' => 'Missing required parameters.']);
@@ -179,9 +179,9 @@
179 179 public function ajax_import_seo_metadata()
180 180 {
181 181 $execution_time = Metasync_Settings_Fields::instance()->get_execution_setting('max_execution_time');
182 182 if (function_exists('set_time_limit')) {
183 - @set_time_limit($execution_time);
183 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
184 184 }
185 185
186 186 Metasync_Settings_Fields::instance()->apply_memory_limit();
187 187
@@ -190,9 +190,9 @@
190 190 if (!Metasync::current_user_has_plugin_access()) {
191 191 wp_send_json_error(['message' => 'Insufficient permissions.']);
192 192 }
193 193
194 - $plugin = isset($_POST['plugin']) ? sanitize_text_field($_POST['plugin']) : '';
194 + $plugin = isset($_POST['plugin']) ? sanitize_text_field(wp_unslash($_POST['plugin'])) : '';
195 195 $import_titles = isset($_POST['import_titles']) ? (bool) intval($_POST['import_titles']) : true;
196 196 $import_descriptions = isset($_POST['import_descriptions']) ? (bool) intval($_POST['import_descriptions']) : true;
197 197 $import_social_text = isset($_POST['import_social_text']) ? (bool) intval($_POST['import_social_text']) : true;
198 198 $import_social_images = isset($_POST['import_social_images']) ? (bool) intval($_POST['import_social_images']) : true;
@@ -563,10 +563,10 @@
563 563 if (!Metasync::current_user_has_plugin_access()) {
564 564 wp_die('Insufficient permissions');
565 565 }
566 566
567 - $uri = sanitize_text_field($_POST['uri']);
568 - $redirect_url = sanitize_url($_POST['redirect_url']);
567 + $uri = sanitize_text_field(wp_unslash($_POST['uri']));
568 + $redirect_url = sanitize_url(wp_unslash($_POST['redirect_url']));
569 569
570 570 if (empty($uri) || empty($redirect_url)) {
571 571 wp_send_json_error('Missing required parameters');
572 572 }
@@ -635,9 +635,9 @@
635 635 try {
636 636 delete_expired_transients(true);
637 637 $cleanup_stats['expired_transients'] = 'cleaned_by_wordpress';
638 638
639 - $plugin_transients = $wpdb->get_results(
639 + $plugin_transients = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient enumeration/cleanup on the options table — no API to scan or bulk-delete transient rows
640 640 "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_metasync_%'",
641 641 ARRAY_A
642 642 );
643 643
@@ -646,9 +646,9 @@
646 646 delete_transient($transient_name);
647 647 $cleanup_stats['plugin_transients']++;
648 648 }
649 649
650 - $rate_limit_transients = $wpdb->get_results(
650 + $rate_limit_transients = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient enumeration/cleanup on the options table — no API to scan or bulk-delete transient rows
651 651 "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_sa_connect_rate_limit_%'",
652 652 ARRAY_A
653 653 );
654 654
@@ -657,9 +657,9 @@
657 657 delete_transient($transient_name);
658 658 $cleanup_stats['rate_limit_transients']++;
659 659 }
660 660
661 - $telemetry_transients = $wpdb->get_results(
661 + $telemetry_transients = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient enumeration/cleanup on the options table — no API to scan or bulk-delete transient rows
662 662 "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_metasync_telemetry_%'",
663 663 ARRAY_A
664 664 );
665 665
@@ -668,9 +668,9 @@
668 668 delete_transient($transient_name);
669 669 $cleanup_stats['telemetry_transients']++;
670 670 }
671 671
672 - $sa_connect_success_transients = $wpdb->get_results(
672 + $sa_connect_success_transients = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient enumeration/cleanup on the options table — no API to scan or bulk-delete transient rows
673 673 "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_metasync_sa_connect_success_%'",
674 674 ARRAY_A
675 675 );
676 676
@@ -681,14 +681,12 @@
681 681 }
682 682
683 683 $cleanup_stats['execution_time'] = round((microtime(true) - $cleanup_stats['start_time']) * 1000, 2);
684 684 $cleanup_stats['next_run'] = wp_next_scheduled('metasync_cleanup_transients') ?
685 - date('Y-m-d H:i:s T', wp_next_scheduled('metasync_cleanup_transients')) : 'N/A';
685 + gmdate('Y-m-d H:i:s T', wp_next_scheduled('metasync_cleanup_transients')) : 'N/A';
686 686
687 - error_log('MetaSync: Transient cleanup completed - ' . json_encode($cleanup_stats));
688 -
689 687 } catch (Exception $e) {
690 - error_log('MetaSync: Transient cleanup failed - ' . $e->getMessage());
688 + error_log('MetaSync: Transient cleanup failed - ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
691 689 }
692 690 }
693 691
694 692 public function ajax_submit_issue_report()
@@ -818,9 +816,9 @@
818 816 # Check if Sentry feedback function exists
819 817 if (!function_exists('metasync_sentry_capture_feedback')) {
820 818 # Log warning if function doesn't exist
821 819 if (defined('WP_DEBUG') && WP_DEBUG) {
822 - error_log('MetaSync: Sentry feedback function not available for report submission.');
820 + error_log('MetaSync: Sentry feedback function not available for report submission.'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
823 821 }
824 822 } else {
825 823 $feedback_data = array(
826 824 'message' => $issue_message,
@@ -847,13 +845,11 @@
847 845 ));
848 846 } else {
849 847 # Fallback: Log locally if Sentry fails or is unavailable
850 848 if (defined('WP_DEBUG') && WP_DEBUG) {
851 - error_log(sprintf(
852 - 'MetaSync Client Report (Fallback): UUID: %s | Title: %s | Message: %s | Severity: %s',
849 + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
850 + 'MetaSync Client Report (Fallback): UUID: %s | Severity: %s',
853 851 $project_uuid,
854 - $issue_title,
855 - $issue_message,
856 852 $issue_severity
857 853 ));
858 854 }
859 855
@@ -867,9 +863,9 @@
867 863
868 864 } catch (Exception $e) {
869 865 # Log the error securely (only in debug mode)
870 866 if (defined('WP_DEBUG') && WP_DEBUG) {
871 - error_log(sprintf(
867 + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
872 868 'MetaSync Report Submission Error: %s in %s on line %d',
873 869 $e->getMessage(),
874 870 $e->getFile(),
875 871 $e->getLine()
@@ -1012,9 +1008,9 @@
1012 1008 if ($rate_owner !== '') {
1013 1009 $this->release_recovery_lock($rate_owner);
1014 1010 }
1015 1011 if (defined('WP_DEBUG') && WP_DEBUG) {
1016 - error_log(sprintf(
1012 + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
1017 1013 'MetaSync Password Recovery Error: %s in %s on line %d',
1018 1014 $e->getMessage(),
1019 1015 $e->getFile(),
1020 1016 $e->getLine()
@@ -1162,9 +1158,9 @@
1162 1158
1163 1159 } catch (Exception $e) {
1164 1160 # Log error if debug is enabled
1165 1161 if (defined('WP_DEBUG') && WP_DEBUG) {
1166 - error_log('MetaSync Theme Save Error: ' . $e->getMessage());
1162 + error_log('MetaSync Theme Save Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
1167 1163 }
1168 1164
1169 1165 wp_send_json_error(array('message' => 'Failed to save theme preference.'));
1170 1166 }
@@ -1305,9 +1301,9 @@
1305 1301 wp_mkdir_p($temp_dir);
1306 1302 }
1307 1303
1308 1304 # Generate unique filename
1309 - $timestamp = date('Y-m-d_H-i-s');
1305 + $timestamp = gmdate('Y-m-d_H-i-s');
1310 1306 $zip_filename = 'metasync-whitelabel-plugin-' . $timestamp . '.zip';
1311 1307 $json_filename = 'whitelabel-settings.json';
1312 1308 $zip_path = $temp_dir . '/' . $zip_filename;
1313 1309
@@ -1368,14 +1364,14 @@
1368 1364 header('Pragma: no-cache');
1369 1365 header('Expires: 0');
1370 1366
1371 1367 # Output file and clean up
1372 - readfile($zip_path);
1373 - unlink($zip_path);
1368 + readfile($zip_path); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- streams a large file to output without loading it into memory
1369 + wp_delete_file($zip_path);
1374 1370
1375 1371 # Clean up temp directory if empty
1376 1372 if (is_dir($temp_dir) && count(scandir($temp_dir)) == 2) {
1377 - rmdir($temp_dir);
1373 + rmdir($temp_dir); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- WP_Filesystem would prompt for FTP credentials on non-direct hosts
1378 1374 }
1379 1375
1380 1376 # Exit to prevent WordPress from adding anything to the response
1381 1377 exit;
@@ -1382,12 +1378,12 @@
1382 1378
1383 1379 } catch (Exception $e) {
1384 1380 # Log error if debug is enabled
1385 1381 if (defined('WP_DEBUG') && WP_DEBUG) {
1386 - error_log('MetaSync Whitelabel Export Error: ' . $e->getMessage());
1382 + error_log('MetaSync Whitelabel Export Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
1387 1383 }
1388 1384
1389 - wp_die('Failed to export whitelabel settings: ' . $e->getMessage());
1385 + wp_die(esc_html__('Failed to export whitelabel settings.', 'metasync'));
1390 1386 }
1391 1387 }
1392 1388
1393 1389 private static function add_directory_to_zip($zip, $dir, $zip_path = '', $exclude_patterns = array())
@@ -1432,10 +1428,10 @@
1432 1428 public function render_html_pages_dashboard_widget()
1433 1429 {
1434 1430 global $wpdb;
1435 1431
1436 - $query = "
1437 - SELECT p.ID, p.post_title, p.post_modified, p.post_type
1432 + $html_pages = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin dashboard widget join over posts+postmeta — aggregate view, no WordPress API for the join
1433 + "SELECT p.ID, p.post_title, p.post_modified, p.post_type
1438 1434 FROM {$wpdb->posts} p
1439 1435 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
1440 1436 WHERE p.post_status = 'publish'
1441 1437 AND p.post_type IN ('post', 'page')
@@ -1442,11 +1438,10 @@
1442 1438 AND (pm.meta_key = '_metasync_raw_html_enabled' OR pm.meta_key = '_metasync_custom_css')
1443 1439 GROUP BY p.ID
1444 1440 ORDER BY p.post_modified DESC
1445 1441 LIMIT 10
1446 - ";
1447 -
1448 - $html_pages = $wpdb->get_results($query);
1442 + "
1443 + );
1449 1444 $total_count = count($html_pages);
1450 1445
1451 1446 $label = $this->get_html_source_label();
1452 1447
@@ -1453,13 +1448,14 @@
1453 1448 if (empty($html_pages)) {
1454 1449 echo '<div class="metasync-dashboard-widget-empty">';
1455 1450 echo '<span class="dashicons dashicons-admin-page" style="font-size: 48px; opacity: 0.3; display: block; margin: 20px auto;"></span>';
1456 1451 echo '<p style="text-align: center; color: #666;">';
1452 + /* translators: %s: HTML source label. */
1457 1453 echo sprintf(__('No pages created with %s yet.', 'metasync'), '<strong>' . esc_html($label) . '</strong>');
1458 1454 echo '</p>';
1459 1455 echo '<p style="text-align: center;">';
1460 - echo '<a href="' . admin_url('admin.php?page=' . Metasync_Admin::$page_slug) . '" class="button button-primary">';
1461 - echo __('Get Started', 'metasync');
1456 + echo '<a href="' . esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug)) . '" class="button button-primary">';
1457 + echo esc_html__('Get Started', 'metasync');
1462 1458 echo '</a>';
1463 1459 echo '</p>';
1464 1460 echo '</div>';
1465 1461 return;
@@ -1468,15 +1464,15 @@
1468 1464 echo '<div class="metasync-dashboard-widget">';
1469 1465
1470 1466 echo '<div class="metasync-widget-stats">';
1471 1467 echo '<div class="metasync-stat-box">';
1472 - echo '<span class="metasync-stat-number">' . $total_count . '</span>';
1473 - echo '<span class="metasync-stat-label">' . __('AI-Generated Pages', 'metasync') . '</span>';
1468 + echo '<span class="metasync-stat-number">' . esc_html((string) $total_count) . '</span>';
1469 + echo '<span class="metasync-stat-label">' . esc_html__('AI-Generated Pages', 'metasync') . '</span>';
1474 1470 echo '</div>';
1475 1471 echo '</div>';
1476 1472
1477 1473 echo '<div class="metasync-widget-list">';
1478 - echo '<h4>' . __('Recent Pages', 'metasync') . '</h4>';
1474 + echo '<h4>' . esc_html__('Recent Pages', 'metasync') . '</h4>';
1479 1475 echo '<ul>';
1480 1476
1481 1477 foreach ($html_pages as $page) {
1482 1478 $edit_link = get_edit_post_link($page->ID);
@@ -1489,11 +1485,12 @@
1489 1485 echo '<a href="' . esc_url($edit_link) . '" class="metasync-page-title">';
1490 1486 echo esc_html($page->post_title ?: __('(no title)', 'metasync'));
1491 1487 echo '</a>';
1492 1488 echo '<span class="metasync-page-meta">';
1493 - echo sprintf(__('Updated %s ago', 'metasync'), $time_ago);
1489 + /* translators: %s: human-readable time difference. */
1490 + echo esc_html(sprintf(__('Updated %s ago', 'metasync'), $time_ago));
1494 1491 echo ' • ';
1495 - echo '<a href="' . esc_url($view_link) . '" target="_blank">' . __('View', 'metasync') . '</a>';
1492 + echo '<a href="' . esc_url($view_link) . '" target="_blank">' . esc_html__('View', 'metasync') . '</a>';
1496 1493 echo '</span>';
1497 1494 echo '</div>';
1498 1495 echo '</li>';
1499 1496 }
@@ -1501,10 +1498,10 @@
1501 1498 echo '</ul>';
1502 1499 echo '</div>';
1503 1500
1504 1501 echo '<div class="metasync-widget-footer">';
1505 - echo '<a href="' . admin_url('edit.php?post_type=page') . '">';
1506 - echo __('View All Pages', 'metasync') . ' →';
1502 + echo '<a href="' . esc_url(admin_url("edit.php?post_type=page")) . '">';
1503 + echo esc_html__('View All Pages', 'metasync') . ' →';
1507 1504 echo '</a>';
1508 1505 echo '</div>';
1509 1506
1510 1507 echo '</div>';