render_layout_open('Compatibility', 'compatibility', 'Check compatibility status with popular plugins, page builders, and caching solutions.'); ?>
render_compatibility_sections(); ?>

Host Blocking Test

Verify if this site can reach services.

Test Configuration

Test connectivity by running both GET and POST requests. Results appear below.

render_last_automatic_check(); ?>
render_troubleshooting_section(); ?>

🚫 Excluded URLs

Manage URLs where should not run. Add URL patterns to exclude specific pages from processing.

Add New Excluded URL

Enter the URL or pattern you want to exclude from .

How the URL should be matched against the pattern.

Excluded URLs

Loading excluded URLs...

render_layout_close(); } /** * Show the result of the last automatic host blocking check. * * Reads the stored result only — it never triggers a probe, so opening this page * costs nothing extra. The automatic check runs ~10 minutes after activation and * weekly after that; the button above re-runs the same probe on demand. */ private function render_last_automatic_check(): void { if (!class_exists('Metasync_Host_Blocking_Check')) { return; } $checker = Metasync_Host_Blocking_Check::get_instance(); $result = $checker->get_last_result(); echo '

'; if ($result === null) { if (!$checker->site_is_publicly_reachable()) { echo esc_html__('Automatic checks are skipped on local and private-network sites, because our services cannot call this site back. Use the button above to test manually.', 'metasync'); } else { echo esc_html__('The automatic check has not run yet. It runs about 10 minutes after activation, then weekly.', 'metasync'); } echo '

'; return; } $blocked = []; if ($result['get_blocked']) { $blocked[] = 'GET'; } if ($result['post_blocked']) { $blocked[] = 'POST'; } if (empty($blocked)) { printf( /* translators: %s: date/time of the last automatic check */ esc_html__('Last automatic check: %s — no blocking detected.', 'metasync'), esc_html($result['checked_at']) ); } else { printf( /* translators: 1: date/time of the last automatic check, 2: blocked HTTP methods */ esc_html__('Last automatic check: %1$s — %2$s requests were blocked. Re-run the test above after changing any firewall or security settings.', 'metasync'), esc_html($result['checked_at']), esc_html(implode(' and ', $blocked)) ); } echo '

'; } public function render_compatibility_sections() { ?>
render_compatibility_section( $this->get_page_builders_compatibility(), 'admin-page', 'Page Builders', 'Elementor, Divi, Gutenberg, Oxygen, Bricks' ); ?> render_compatibility_section( $this->get_themes_compatibility(), 'art', 'Themes', 'Astra, GeneratePress, OceanWP and more' ); ?> render_compatibility_section( $this->get_seo_plugins_compatibility(), 'search', 'SEO Plugins', 'Yoast, Rank Math, AIOSEO and others' ); ?> render_compatibility_section( $this->get_cache_plugins_compatibility(), 'performance', 'Cache & Performance', 'WP Rocket, LiteSpeed, W3 Total Cache and more' ); ?> render_compatibility_section( $this->get_cdn_compatibility(), 'networking', 'CDN & Hosting', 'Cloudflare, Fastly, Bunny CDN, Kinsta, Flywheel' ); ?>
$i['is_installed'] && $i['is_active'] ) ); $total = count( $items ); $subtitle = $active_count > 0 ? $active_count . ' of ' . $total . ' active' : ( $description ?: $total . ' checked' ); ?>
Active Installed Not installed
'Title tag disappears when Yoast SEO is active', 'cause' => 'Yoast SEO takes ownership of the tag. ' . $plugin_name . ' filters may conflict if both try to modify the document title at the same priority.', 'fix' => 'Go to ' . $plugin_name . ' → Settings → Compatibility and make sure "Yoast SEO title handoff" is enabled. This lets Yoast own the title while ' . $plugin_name . ' passes its optimised title through Yoast.', ], [ 'title' => $otto_name . ' changes not appearing after cache flush', 'cause' => 'Some cache plugins (WP Rocket, Kinsta) serve stale HTML even after a purge if cache warm-up races with the write.', 'fix' => 'Increase the cache warm-up timeout in ' . $plugin_name . ' → Settings → Advanced, or disable "Immediate Warm-up" and let the cache rebuild organically.', ], [ 'title' => 'SEO meta not showing for Oxygen Builder pages', 'cause' => 'Oxygen replaces the standard WordPress template, bypassing some meta output hooks.', 'fix' => $plugin_name . ' automatically handles Oxygen compatibility — no setting required. If meta is still missing, ensure ' . $plugin_name . ' is up to date and try clearing any server-side or CDN cache.', ], [ 'title' => 'Schema markup injected on every page instead of the target page only', 'cause' => 'A known bug in versions prior to 2.5.20 where schema was registered globally.', 'fix' => 'Update to the latest version. Go to Settings → Schema Markup and re-save your configuration.', ], [ 'title' => 'Sitemap returns 404', 'cause' => 'Permalink flush needed after activation or after a WordPress update.', 'fix' => 'Go to Settings → Permalinks in WordPress admin and click "Save Changes" (no actual change needed — this flushes rewrite rules).', ], [ 'title' => 'Cloudflare / CDN caching stale SEO meta', 'cause' => 'CDN caches the full HTML response including meta tags. After updating SEO meta, the CDN may serve old content.', 'fix' => 'Purge the CDN cache for the affected URL via your CDN dashboard, or enable automatic purge integration in ' . $plugin_name . ' → Settings → Cache.', ], ]; ?> <div id="ms-comp-troubleshooting" class="dashboard-card" style="margin-top: 20px;"> <div style="display:flex; align-items:center; gap:10px; margin-bottom:6px;"> <span class="dashicons dashicons-sos" style="font-size:24px;width:24px;height:24px;color:var(--dashboard-accent);"></span> <div> <h2 style="margin:0;">Troubleshooting</h2> <p style="color:var(--dashboard-text-secondary); margin:4px 0 0 0;">Common issues and how to fix them.</p> </div> </div> <div style="margin-top:16px; display:flex; flex-direction:column; gap:8px;"> <?php foreach ( $issues as $i => $issue ): ?> <details style="border:1px solid var(--dashboard-border); border-radius:8px; overflow:hidden;"> <summary style="cursor:pointer; padding:14px 16px; list-style:none; display:flex; align-items:center; justify-content:space-between; gap:12px; background:var(--dashboard-bg); font-weight:600; font-size:14px; color:var(--dashboard-text-primary);"> <span style="display:flex; align-items:center; gap:10px;"> <span class="dashicons dashicons-warning" style="font-size:16px;width:16px;height:16px;color:#f59e0b;flex-shrink:0;"></span> <?php echo esc_html( $issue['title'] ); ?> </span> <span class="dashicons dashicons-arrow-down-alt2" style="font-size:14px;width:14px;height:14px;color:var(--dashboard-text-secondary);flex-shrink:0;transition:transform .2s;"></span> </summary> <div style="padding:16px; background:var(--dashboard-card-bg); border-top:1px solid var(--dashboard-border);"> <p style="margin:0 0 10px 0; color:var(--dashboard-text-secondary); font-size:13px;"> <strong style="color:var(--dashboard-text-primary);">Cause:</strong> <?php echo esc_html( $issue['cause'] ); ?> </p> <p style="margin:0; color:var(--dashboard-text-secondary); font-size:13px;"> <strong style="color:var(--dashboard-text-primary);">Fix:</strong> <?php echo esc_html( $issue['fix'] ); ?> </p> </div> </details> <?php endforeach; ?> </div> </div> <script> document.querySelectorAll('#ms-comp-troubleshooting details').forEach(function(el) { el.addEventListener('toggle', function() { var arrow = el.querySelector('.dashicons-arrow-down-alt2'); if (arrow) arrow.style.transform = el.open ? 'rotate(180deg)' : ''; }); }); </script> <?php } /** * Render Lock Section button for protected tabs. * * @param string $tab The tab identifier (general, whitelabel, advanced) */ public function render_lock_button($tab) { ?> <button type="button" class="metasync-lock-btn" data-tab="<?php echo esc_attr($tab); ?>" style="background: #dc3545; color: white; border: none; padding: 10px 20px; border-radius: 6px; font-size: 14px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; transition: all 0.3s ease;" onmouseover="this.style.background='#c82333'" onmouseout="this.style.background='#dc3545'" onfocus="this.style.background='#c82333'" onblur="this.style.background='#dc3545'" aria-label="Lock this section and require password for access"> <span class="dashicons dashicons-lock" style="font-size:16px;width:16px;height:16px;" aria-hidden="true"></span> Lock Section </button> <?php } public function get_page_builders_compatibility() { $builders = [ 'elementor' => [ 'name' => 'Elementor', 'plugin_files' => [ 'elementor/elementor.php', 'elementor-pro/elementor-pro.php' ], 'supported' => true, 'version' => '3.31.5', ], 'gutenberg' => [ 'name' => 'WordPress Block Editor', 'plugin_files' => [ 'gutenberg/gutenberg.php' ], 'supported' => true, 'is_core' => true, 'version' => get_bloginfo( 'version' ), ], 'divi' => [ 'name' => 'Divi Builder', 'plugin_files' => [ 'divi-builder/divi-builder.php' ], 'theme_name' => 'Divi', 'supported' => true, 'version' => '', ], 'oxygen' => [ 'name' => 'Oxygen Builder', 'plugin_files' => [ 'oxygen/functions.php' ], 'supported' => true, 'version' => '4.9', 'note' => 'Enable Oxygen Compatibility in Settings for correct meta output.', ], 'bricks' => [ 'name' => 'Bricks Builder', 'plugin_files' => [ 'bricks/bricks.php' ], 'theme_name' => 'Bricks', 'supported' => true, 'version' => '1.11', ], ]; $result = []; foreach ($builders as $key => $builder) { $is_core = isset($builder['is_core']) && $builder['is_core']; // The array key is the theme directory slug; pass it (not the display name) // so wp_get_theme() can resolve the theme on case-sensitive filesystems. $theme_slug = isset($builder['theme_name']) ? $key : null; $plugin_status = $this->get_plugin_status($builder['plugin_files'], $is_core, $theme_slug); if ($builder['supported']) { $status = 'supported'; $status_text = 'Supported'; } else { $status = 'coming-soon'; $status_text = 'Coming Soon'; } $result[] = [ 'name' => $builder['name'], 'version' => $builder['version'], 'status' => $status, 'status_text' => $status_text, 'is_installed' => $plugin_status['is_installed'], 'is_active' => $plugin_status['is_active'], 'note' => $builder['note'] ?? '', 'logo' => $this->get_plugin_logo( $key, 'page_builder' ), ]; } return $result; } public function get_seo_plugins_compatibility() { $plugins = [ 'yoast' => [ 'name' => 'Yoast SEO', 'plugin_files' => [ 'wordpress-seo/wp-seo.php', 'wordpress-seo-premium/wp-seo-premium.php' ], 'supported' => true, 'version' => '25.9.0' ], 'rankmath' => [ 'name' => 'Rank Math', 'plugin_files' => [ 'seo-by-rank-math/rank-math.php', 'seo-by-rank-math-pro/rank-math-pro.php' ], 'supported' => true, 'version' => '1.0.253.0' ], 'aioseo' => [ 'name' => 'All in One SEO', 'plugin_files' => [ 'all-in-one-seo-pack/all_in_one_seo_pack.php', 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php' ], 'supported' => true, 'version' => '4.8.7' ] ]; $result = []; foreach ($plugins as $key => $plugin) { $plugin_status = $this->get_plugin_status($plugin['plugin_files']); if ($plugin['supported']) { $status = 'supported'; $status_text = 'Supported'; } else { $status = 'coming-soon'; $status_text = 'Coming Soon'; } $result[] = [ 'name' => $plugin['name'], 'version' => $plugin['version'], 'status' => $status, 'status_text' => $status_text, 'is_installed' => $plugin_status['is_installed'], 'is_active' => $plugin_status['is_active'], 'note' => $plugin['note'] ?? '', 'logo' => $this->get_plugin_logo( $key, 'seo' ), ]; } return $result; } public function get_themes_compatibility() { $themes = [ 'astra' => [ 'name' => 'Astra', 'theme_name' => 'Astra', 'plugin_files' => [], 'supported' => true, 'version' => '4.8', 'note' => 'Full compatibility including title tag and schema support.', ], 'generatepress' => [ 'name' => 'GeneratePress', 'theme_name' => 'GeneratePress', 'plugin_files' => [], 'supported' => true, 'version' => '3.5', ], 'oceanwp' => [ 'name' => 'OceanWP', 'theme_name' => 'OceanWP', 'plugin_files' => [], 'supported' => true, 'version' => '3.5', ], 'hello-elementor' => [ 'name' => 'Hello Elementor', 'theme_name' => 'Hello Elementor', 'plugin_files' => [], 'supported' => true, 'version' => '3.1', ], 'kadence' => [ 'name' => 'Kadence', 'theme_name' => 'Kadence', 'plugin_files' => [], 'supported' => true, 'version' => '1.2', ], ]; $result = []; foreach ( $themes as $key => $theme ) { // The array key is the theme directory slug; pass it (not the display name) // so wp_get_theme() can resolve the theme on case-sensitive filesystems. $status = $this->get_plugin_status( $theme['plugin_files'], false, $key ); $result[] = [ 'name' => $theme['name'], 'version' => $theme['version'], 'status' => 'supported', 'status_text' => 'Supported', 'is_installed' => $status['is_installed'], 'is_active' => $status['is_active'], 'note' => $theme['note'] ?? '', 'logo' => $this->get_plugin_logo( $key, 'theme' ), ]; } return $result; } public function get_cache_plugins_compatibility() { $plugins = [ 'wp-rocket' => [ 'name' => 'WP Rocket', 'plugin_files' => [ 'wp-rocket/wp-rocket.php' ], 'supported' => true, 'version' => '3.16', 'note' => 'Automatic cache purge on OTTO update.', ], 'litespeed-cache' => [ 'name' => 'LiteSpeed Cache', 'plugin_files' => [ 'litespeed-cache/litespeed-cache.php' ], 'supported' => true, 'version' => '7.5.0.1', ], 'w3-total-cache' => [ 'name' => 'W3 Total Cache', 'plugin_files' => [ 'w3-total-cache/w3-total-cache.php' ], 'supported' => true, 'version' => '2.7', ], 'sg-cachepress' => [ 'name' => 'SiteGround Optimizer', 'plugin_files' => [ 'sg-cachepress/sg-cachepress.php' ], 'supported' => true, 'version' => '7.6', ], 'hummingbird-performance' => [ 'name' => 'Hummingbird', 'plugin_files' => [ 'hummingbird-performance/wp-hummingbird.php' ], 'supported' => true, 'version' => '3.9', ], 'autoptimize' => [ 'name' => 'Autoptimize', 'plugin_files' => [ 'autoptimize/autoptimize.php' ], 'supported' => true, 'version' => '3.1', ], 'comet-cache' => [ 'name' => 'Comet Cache', 'plugin_files' => [ 'comet-cache/comet-cache.php' ], 'supported' => true, 'version' => '17.6', ], 'cache-enabler' => [ 'name' => 'Cache Enabler', 'plugin_files' => [ 'cache-enabler/cache-enabler.php' ], 'supported' => true, 'version' => '1.8', ], 'breeze' => [ 'name' => 'Breeze (Cloudways)', 'plugin_files' => [ 'breeze/breeze.php' ], 'supported' => true, 'version' => '2.1', ], ]; $result = []; foreach ($plugins as $key => $plugin) { $plugin_status = $this->get_plugin_status($plugin['plugin_files']); if ($plugin['supported']) { $status = 'supported'; $status_text = 'Supported'; } else { $status = 'coming-soon'; $status_text = 'Coming Soon'; } $result[] = [ 'name' => $plugin['name'], 'version' => $plugin['version'], 'status' => $status, 'status_text' => $status_text, 'is_installed' => $plugin_status['is_installed'], 'is_active' => $plugin_status['is_active'], 'note' => $plugin['note'] ?? '', 'logo' => $this->get_plugin_logo( $key, 'cache' ), ]; } return $result; } public function get_cdn_compatibility() { $providers = [ 'cloudflare' => [ 'name' => 'Cloudflare', 'plugin_files' => [ 'cloudflare/cloudflare.php' ], 'supported' => true, 'version' => '', 'note' => 'Cache purge supported. Ensure HTML caching is disabled or bypass rules set for admin.', ], 'fastly' => [ 'name' => 'Fastly', 'plugin_files' => [ 'fastly/fastly.php' ], 'supported' => true, 'version' => '', 'note' => 'Edge cache purge triggered on OTTO update.', ], 'bunnycdn' => [ 'name' => 'Bunny CDN', 'plugin_files' => [ 'bunnycdn/bunnycdn.php', 'bunny-cdn/bunny-cdn.php' ], 'supported' => true, 'version' => '', ], 'kinsta-mu-plugins' => [ 'name' => 'Kinsta (Managed Hosting)', 'plugin_files' => [ 'kinsta-mu-plugins/kinsta-mu-plugins.php' ], 'supported' => true, 'version' => '', 'note' => 'Kinsta Varnish/Nginx cache purged per-URL on OTTO update.', ], 'flywheel' => [ 'name' => 'Flywheel / Local', 'plugin_files' => [ 'flywheel-common/plugin.php' ], 'supported' => true, 'version' => '', 'note' => 'Varnish cache purge supported.', ], ]; $result = []; foreach ( $providers as $key => $provider ) { $status = $this->get_plugin_status( $provider['plugin_files'] ); $result[] = [ 'name' => $provider['name'], 'version' => $provider['version'], 'status' => 'supported', 'status_text' => 'Supported', 'is_installed' => $status['is_installed'], 'is_active' => $status['is_active'], 'note' => $provider['note'] ?? '', 'logo' => $this->get_plugin_logo( $key, 'cdn' ), ]; } return $result; } /** * @deprecated Use get_plugin_status() instead */ public function is_plugin_installed($plugin_file) { if (!function_exists('is_plugin_active')) { include_once(ABSPATH . 'wp-admin/includes/plugin.php'); } return is_plugin_active($plugin_file); } /** * Get detailed plugin status (installed and/or active). * * @param array $plugin_files Array of plugin file paths to check * @param bool $is_core Whether this is a WordPress core feature * @param string $theme_slug Optional theme directory slug to check (e.g. 'hello-elementor', * 'astra'). Must be the directory slug, not the display name, * because wp_get_theme() resolves themes by directory slug. * @return array ['is_installed' => bool, 'is_active' => bool, 'active_version' => string|null] */ public function get_plugin_status($plugin_files, $is_core = false, $theme_slug = null) { if ($is_core) { return [ 'is_installed' => true, 'is_active' => true, 'active_version' => 'core' ]; } if ($theme_slug) { $current_theme = wp_get_theme(); $is_theme_active = (strtolower($current_theme->get('Name')) === strtolower($theme_slug) || strtolower($current_theme->get_stylesheet()) === strtolower($theme_slug)); // An active theme is by definition installed. Fall back to a directory // lookup for themes that are installed but not currently active. $theme_exists = $is_theme_active || wp_get_theme($theme_slug)->exists(); if ($theme_exists) { return [ 'is_installed' => true, 'is_active' => $is_theme_active, 'active_version' => $is_theme_active ? 'theme' : null ]; } } if (!function_exists('is_plugin_active')) { include_once(ABSPATH . 'wp-admin/includes/plugin.php'); } if (!function_exists('get_plugins')) { include_once(ABSPATH . 'wp-admin/includes/plugin.php'); } if (!is_array($plugin_files)) { $plugin_files = [$plugin_files]; } $is_installed = false; $is_active = false; $active_version = null; foreach ($plugin_files as $plugin_file) { $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file; if (file_exists($plugin_path)) { $is_installed = true; if (is_plugin_active($plugin_file)) { $is_active = true; $active_version = strpos($plugin_file, 'pro') !== false || strpos($plugin_file, 'premium') !== false ? 'premium' : 'free'; break; } } } return [ 'is_installed' => $is_installed, 'is_active' => $is_active, 'active_version' => $active_version ]; } public function get_plugin_logo($plugin_key, $type) { // Compatibility icons are bundled locally; loading images from external // servers (wp.org, vendor sites, CDNs) counts as offloaded content and // is disallowed for wordpress.org releases. $assets = plugins_url('assets/images/compat/', dirname(__DIR__) . '/metasync.php'); $logos = [ 'page_builder' => [ 'elementor' => $assets . 'elementor.svg', 'gutenberg' => $assets . 'gutenberg.svg', 'divi' => $assets . 'divi.svg', 'oxygen' => $assets . 'oxygen.svg', 'bricks' => $assets . 'bricks.svg', ], 'theme' => [ 'astra' => $assets . 'astra.svg', 'generatepress' => $assets . 'generatepress.svg', 'oceanwp' => $assets . 'oceanwp.svg', 'hello-elementor' => $assets . 'hello-elementor.svg', 'kadence' => $assets . 'kadence.svg', ], 'seo' => [ 'yoast' => $assets . 'yoast.svg', 'rankmath' => $assets . 'rankmath.svg', 'aioseo' => $assets . 'aioseo.svg', ], 'cache' => [ 'wp-rocket' => $assets . 'wp-rocket.svg', 'litespeed-cache' => $assets . 'litespeed-cache.svg', 'w3-total-cache' => $assets . 'w3-total-cache.svg', 'sg-cachepress' => $assets . 'sg-cachepress.svg', 'hummingbird-performance' => $assets . 'hummingbird-performance.svg', 'autoptimize' => $assets . 'autoptimize.svg', ], 'cdn' => [ 'cloudflare' => $assets . 'cloudflare.svg', 'fastly' => $assets . 'fastly.svg', ], ]; return isset($logos[$type][$plugin_key]) ? $logos[$type][$plugin_key] : ''; } }