PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
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-compatibility-checker.php +73 -31 2.6.25 → 2.7.2 View file →
@@ -38,8 +38,36 @@
38 38
39 39 <div class="dashboard-card">
40 40 <?php $this->render_compatibility_sections(); ?>
41 41 </div>
42 +
43 + <?php
44 + # Plugin-compatibility toggles. Registered under the
45 + # <page_slug>_compatibility settings page only while the relevant
46 + # plugin is active, so the card self-hides when neither plugin is
47 + # present. Saves through options.php with a hidden active_tab so
48 + # the General-tab sanitizer blocks stay inert.
49 + $has_compat_fields = defined('WP_ROCKET_VERSION')
50 + || class_exists('WP_Rocket')
51 + || class_exists('SiteGround_Optimizer\Parser\Parser')
52 + || defined('SiteGround_Optimizer\VERSION')
53 + || class_exists('bookingpress_spam_protection');
54 + if ($has_compat_fields) :
55 + settings_errors();
56 + ?>
57 + <div class="dashboard-card" style="margin-top: 20px;">
58 + <h2 style="margin: 0 0 4px 0;">Plugin Compatibility Settings</h2>
59 + <p style="color: var(--dashboard-text-secondary); margin: 0 0 20px 0;">Control how <?php echo esc_html(Metasync::get_effective_plugin_name()); ?> interacts with detected plugins. Each setting appears only while its plugin is active.</p>
60 + <form method="post" action="options.php">
61 + <input type="hidden" name="active_tab" value="compatibility" />
62 + <?php
63 + settings_fields(Metasync_Admin::option_group);
64 + do_settings_sections(Metasync_Admin::$page_slug . '_compatibility');
65 + submit_button();
66 + ?>
67 + </form>
68 + </div>
69 + <?php endif; ?>
42 70
43 71 <!-- Section: Host Blocking Test -->
44 72 <div id="ms-comp-host-test" class="dashboard-card" style="margin-top: 20px;">
45 73 <details open>
@@ -134,9 +162,9 @@
134 162 $.ajax({
135 163 url: ajaxUrl,
136 164 type: 'POST',
137 165 dataType: 'json',
138 - data: { action: action, nonce: '<?php echo wp_create_nonce("metasync_nonce"); ?>' },
166 + data: { action: action, nonce: '<?php echo esc_attr(wp_create_nonce("metasync_nonce")); ?>' },
139 167 timeout: 35000,
140 168 success: function(response, textStatus, xhr) {
141 169 try {
142 170 if (response && response.success && response.data) {
@@ -205,22 +233,22 @@
205 233 var blockedClass = inconclusive ? 'inconclusive' : (result.blocked ? 'blocked' : 'allowed');
206 234
207 235 html += '<div class="test-result-item ' + statusClass + '">';
208 236 html += '<div class="test-result-header">';
209 - html += '<h4>' + statusIcon + ' ' + result.method + ' Request - ' + blockedStatus + '</h4>';
237 + html += '<h4>' + statusIcon + ' ' + escapeHtml(result.method) + ' Request - ' + blockedStatus + '</h4>';
210 238 html += '<span class="test-status ' + blockedClass + '">' + blockedStatus + '</span>';
211 239 html += '</div>';
212 240
213 241 html += '<div class="test-result-details">';
214 - html += '<p><strong>Response Time:</strong> ' + result.response_time + '</p>';
215 - html += '<p><strong>Status:</strong> ' + result.status + '</p>';
242 + html += '<p><strong>Response Time:</strong> ' + escapeHtml(result.response_time) + '</p>';
243 + html += '<p><strong>Status:</strong> ' + escapeHtml(result.status) + '</p>';
216 244
217 245 if (result.status_code) {
218 - html += '<p><strong>HTTP Status Code:</strong> <span class="status-code">' + result.status_code + '</span></p>';
246 + html += '<p><strong>HTTP Status Code:</strong> <span class="status-code">' + escapeHtml(result.status_code) + '</span></p>';
219 247 }
220 248
221 249 if (result.error) {
222 - html += '<p><strong>Error:</strong> <span class="error-message">' + result.error + '</span></p>';
250 + html += '<p><strong>Error:</strong> <span class="error-message">' + escapeHtml(result.error) + '</span></p>';
223 251 }
224 252
225 253 if (result.body) {
226 254 html += '<p><strong>Response Body:</strong></p>';
@@ -230,9 +258,9 @@
230 258 if (result.headers && Object.keys(result.headers).length > 0) {
231 259 html += '<p><strong>Response Headers:</strong></p>';
232 260 html += '<pre class="response-headers">';
233 261 Object.keys(result.headers).forEach(function(key) {
234 - html += key + ': ' + result.headers[key] + '\n';
262 + html += escapeHtml(key) + ': ' + escapeHtml(result.headers[key]) + '\n';
235 263 });
236 264 html += '</pre>';
237 265 }
238 266
@@ -245,9 +273,9 @@
245 273 html += '<p><strong>Parsed Response:</strong></p>';
246 274 html += '<pre class="parsed-response">' + escapeHtml(JSON.stringify(result.parsed_response, null, 2)) + '</pre>';
247 275 }
248 276
249 - html += '<p><strong>Details:</strong> ' + result.details + '</p>';
277 + html += '<p><strong>Details:</strong> ' + escapeHtml(result.details) + '</p>';
250 278 html += '</div>';
251 279 html += '</div>';
252 280 });
253 281
@@ -262,9 +290,9 @@
262 290 '>': '&gt;',
263 291 '"': '&quot;',
264 292 "'": '&#039;'
265 293 };
266 - return text.replace(/[&<>"']/g, function(m) { return map[m]; });
294 + return String(text).replace(/[&<>"']/g, function(m) { return map[m]; });
267 295 }
268 296
269 297 setTimeout(function() {
270 298 var btnBoth = $('#test-both-requests');
@@ -507,8 +535,10 @@
507 535 color: #646970 !important;
508 536 opacity: 0.7;
509 537 }
510 538
539 + /* Equal width so badges of different lengths (Exact, Contains,
540 + etc.) render at the same size for a visually balanced column. */
511 541 .otto-pattern-type-badge {
512 542 display: inline-block;
513 543 padding: 3px 8px;
514 544 border-radius: 3px;
@@ -515,8 +545,11 @@
515 545 font-size: 11px;
516 546 font-weight: 600;
517 547 text-transform: uppercase;
518 548 letter-spacing: 0.5px;
549 + min-width: 90px;
550 + text-align: center;
551 + box-sizing: border-box;
519 552 }
520 553
521 554 /* Badge text is 11px uppercase, i.e. normal-size text: the darker
522 555 foreground steps keep every pair at or above the 4.5:1 AA bar
@@ -616,11 +649,15 @@
616 649 border: 1px solid #dcdcde;
617 650 }
618 651
619 652 #otto-excluded-urls-table-container .otto-delete-url,
620 - #otto-excluded-urls-table-container .otto-recheck-url {
653 + #otto-excluded-urls-table-container .otto-recheck-url,
654 + #otto-excluded-urls-table-container .otto-recheck-disabled {
621 655 padding: 4px 10px;
622 656 font-size: 12px;
657 + box-sizing: border-box;
658 + height: 26px;
659 + line-height: 1;
623 660 }
624 661
625 662 #otto-excluded-urls-table-container .otto-delete-url {
626 663 background: #dc3545 !important;
@@ -1349,39 +1386,44 @@
1349 1386 }
1350 1387
1351 1388 public function get_plugin_logo($plugin_key, $type)
1352 1389 {
1390 + // Compatibility icons are bundled locally; loading images from external
1391 + // servers (wp.org, vendor sites, CDNs) counts as offloaded content and
1392 + // is disallowed for wordpress.org releases.
1393 + $assets = plugins_url('assets/images/compat/', dirname(__DIR__) . '/metasync.php');
1394 +
1353 1395 $logos = [
1354 1396 'page_builder' => [
1355 - 'elementor' => 'https://ps.w.org/elementor/assets/icon-256x256.gif',
1356 - 'gutenberg' => 'https://i0.wp.com/wordpress.org/files/2023/02/wmark.png',
1357 - 'divi' => 'https://www.elegantthemes.com/images/logo.svg',
1358 - 'oxygen' => 'https://oxygenbuilder.com/wp-content/uploads/2021/09/oxygen-logo-icon.png',
1359 - 'bricks' => 'https://bricksbuilder.io/wp-content/uploads/2021/05/bricks-icon.svg',
1397 + 'elementor' => $assets . 'elementor.svg',
1398 + 'gutenberg' => $assets . 'gutenberg.svg',
1399 + 'divi' => $assets . 'divi.svg',
1400 + 'oxygen' => $assets . 'oxygen.svg',
1401 + 'bricks' => $assets . 'bricks.svg',
1360 1402 ],
1361 1403 'theme' => [
1362 - 'astra' => 'https://ps.w.org/astra/assets/icon-128x128.png',
1363 - 'generatepress' => 'https://ps.w.org/generatepress/assets/icon-128x128.png',
1364 - 'oceanwp' => 'https://ps.w.org/ocean-extra/assets/icon-128x128.png',
1365 - 'hello-elementor' => 'https://ps.w.org/hello-elementor/assets/icon-128x128.png',
1366 - 'kadence' => 'https://ps.w.org/kadence-blocks/assets/icon-128x128.png',
1404 + 'astra' => $assets . 'astra.svg',
1405 + 'generatepress' => $assets . 'generatepress.svg',
1406 + 'oceanwp' => $assets . 'oceanwp.svg',
1407 + 'hello-elementor' => $assets . 'hello-elementor.svg',
1408 + 'kadence' => $assets . 'kadence.svg',
1367 1409 ],
1368 1410 'seo' => [
1369 - 'yoast' => 'https://ps.w.org/wordpress-seo/assets/icon-128x128.gif',
1370 - 'rankmath' => 'https://ps.w.org/seo-by-rank-math/assets/icon-128x128.png',
1371 - 'aioseo' => 'https://ps.w.org/all-in-one-seo-pack/assets/icon-128x128.png',
1411 + 'yoast' => $assets . 'yoast.svg',
1412 + 'rankmath' => $assets . 'rankmath.svg',
1413 + 'aioseo' => $assets . 'aioseo.svg',
1372 1414 ],
1373 1415 'cache' => [
1374 - 'wp-rocket' => 'https://ps.w.org/rocket-lazy-load/assets/icon-128x128.png',
1375 - 'litespeed-cache' => 'https://ps.w.org/litespeed-cache/assets/icon-128x128.png',
1376 - 'w3-total-cache' => 'https://ps.w.org/w3-total-cache/assets/icon-128x128.png',
1377 - 'sg-cachepress' => 'https://ps.w.org/sg-cachepress/assets/icon-128x128.png',
1378 - 'hummingbird-performance' => 'https://ps.w.org/hummingbird-performance/assets/icon-128x128.png',
1379 - 'autoptimize' => 'https://ps.w.org/autoptimize/assets/icon-128x128.png',
1416 + 'wp-rocket' => $assets . 'wp-rocket.svg',
1417 + 'litespeed-cache' => $assets . 'litespeed-cache.svg',
1418 + 'w3-total-cache' => $assets . 'w3-total-cache.svg',
1419 + 'sg-cachepress' => $assets . 'sg-cachepress.svg',
1420 + 'hummingbird-performance' => $assets . 'hummingbird-performance.svg',
1421 + 'autoptimize' => $assets . 'autoptimize.svg',
1380 1422 ],
1381 1423 'cdn' => [
1382 - 'cloudflare' => 'https://ps.w.org/cloudflare/assets/icon-128x128.png',
1383 - 'fastly' => 'https://ps.w.org/purgely/assets/icon-128x128.png',
1424 + 'cloudflare' => $assets . 'cloudflare.svg',
1425 + 'fastly' => $assets . 'fastly.svg',
1384 1426 ],
1385 1427 ];
1386 1428
1387 1429 return isset($logos[$type][$plugin_key]) ? $logos[$type][$plugin_key] : '';