'; echo '❌ Error: Transient Cache class not found.'; echo '

'; return; } $cache_count = Metasync_Otto_Transient_Cache::get_cache_count(); ?>

Clear All Cache Plugins

Clear all cache plugins to ensure changes are visible immediately.

get_active_cache_plugins(); if (!empty($active_cache_plugins)) { echo '

Active Cache Plugins Detected:

'; echo ''; } else { echo '

ℹ️ No cache plugins detected.

'; } } catch (Exception $e) { error_log('MetaSync Cache Status Error: ' . $e->getMessage()); echo '

⚠️ An error occurred while retrieving cache plugin status.

'; } } else { echo '

⚠️ Cache Purge class not loaded.

'; } ?>

This will clear cache from WP Rocket, LiteSpeed, W3 Total Cache, and all other detected cache plugins.

0) { echo '

'; echo '✅ Success! Cleared cache for ' . intval( $cleared ) . ' plugin(s)'; if ($plugins) { echo ': ' . esc_html($plugins); } echo '

'; } else { echo '

'; echo 'ℹ️ No cache plugins found to clear. WordPress object cache was cleared.'; echo '

'; } if ($failed > 0) { echo '

'; echo '⚠️ Failed to clear ' . intval( $failed ) . ' plugin(s).'; echo '

'; } } if (isset($_GET['cache_error']) && $_GET['cache_error'] == '1') { $message = isset($_GET['message']) ? urldecode(sanitize_text_field($_GET['message'])) : ''; if (empty($message)) { $message = 'An unknown error occurred while clearing cache. Please check error logs for details.'; } echo '

'; echo '❌ Error clearing cache: ' . esc_html($message); echo '

'; } ?>
true, 'kinsta_enabled' => true); $hosting_settings = wp_parse_args(get_option('metasync_hosting_cache_options', array()), $hosting_defaults); $wpe_detected = class_exists('WpeCommon'); $kinsta_detected = class_exists('KinstaCache'); ?>

Hosting Cache Integration

Use your hosting provider's native API to purge the entire site cache in one click. These options are independent of cache plugins and target the server-level cache layer.

WP Engine Kinsta
Enable Native Cache Purge

Triggers a full-site cache purge using the native WP Engine and/or Kinsta APIs (based on toggles above).

'; echo '✅ Success! Purged hosting cache on: ' . esc_html($hc_cleared); echo '

'; } if ($hc_failed) { echo '

'; echo '❌ Failed to purge: ' . esc_html($hc_failed); echo '

'; } if ($hc_not_detected && !$hc_cleared && !$hc_failed) { echo '

'; echo 'ℹ️ No enabled hosting providers were detected on this server (' . esc_html($hc_not_detected) . ').'; echo '

'; } } ?>

Transient Cache

Manage suggestions cache. Clearing cache will force fresh API calls on next page load.

Current Cache Status: cached entries

'; if (!empty($url)) { echo '✅ Success! Cleared cache for URL: ' . esc_html($url) . ' (' . intval( $cleared_count ) . ' entries)'; } else { echo '✅ Success! Cleared entire transient cache (' . intval( $cleared_count ) . ' entries)'; } echo '

'; } if (isset($_GET['otto_cache_error']) && $_GET['otto_cache_error'] == '1') { $message = isset($_GET['message']) ? urldecode(sanitize_text_field($_GET['message'])) : 'An unknown error occurred.'; echo '

'; echo '❌ Error: ' . esc_html($message); echo '

'; } ?>
Clear Entire Transient Cache

This will clear all transient cache entries (suggestions, locks, stale cache, rate limits).

Clear Cache by URL

Enter a specific URL to clear its cached suggestions. Use the full URL including protocol (e.g., https://example.com/page/).

Enter the full URL of the page whose cache you want to clear.

get_page_slug() . '&tab=advanced'); if (class_exists('Metasync_Cache_Purge')) { try { $cache_purge = Metasync_Cache_Purge::get_instance(); $results = $cache_purge->clear_all_caches('manual_admin'); $cleared_count = count($results['cleared']); $failed_count = count($results['failed']); $redirect_url .= '&cache_cleared=1&cleared=' . $cleared_count . '&failed=' . $failed_count; if (!empty($results['cleared'])) { $redirect_url .= '&plugins=' . urlencode(implode(',', $results['cleared'])); } } catch (Exception $e) { error_log('MetaSync Cache Clear Error: ' . $e->getMessage()); $redirect_url .= '&cache_error=1&message=' . urlencode('An error occurred while clearing the cache. Please try again.'); } } else { $redirect_url .= '&cache_error=1&message=' . urlencode('Cache Purge class not available'); } wp_safe_redirect($redirect_url); exit; } /** * WordPress standard handler for clearing OTTO cache (admin_post hook) */ public function handle_clear_otto_cache_all() { if (!isset($_POST['clear_otto_cache_nonce']) || !wp_verify_nonce($_POST['clear_otto_cache_nonce'], 'metasync_clear_otto_cache_nonce')) { wp_die('Security check failed'); } if (!Metasync::current_user_has_plugin_access()) { wp_die('You do not have permission to perform this action'); } $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced'); if (class_exists('Metasync_Otto_Transient_Cache')) { try { $result = Metasync_Otto_Transient_Cache::clear_all_transients(); $redirect_url .= '&otto_cache_cleared=1&count=' . $result['cleared_count']; } catch (Exception $e) { error_log('MetaSync OTTO Cache Clear Error: ' . $e->getMessage()); $redirect_url .= '&otto_cache_error=1&message=' . urlencode('An error occurred while clearing the OTTO cache. Please try again.'); } } else { $redirect_url .= '&otto_cache_error=1&message=' . urlencode('Transient Cache class not found'); } delete_transient('metasync_otto_js_detected'); wp_safe_redirect($redirect_url); exit; } /** * WordPress standard handler for clearing OTTO cache by URL (admin_post hook) */ public function handle_clear_otto_cache_url() { if (!isset($_POST['clear_otto_cache_nonce']) || !wp_verify_nonce($_POST['clear_otto_cache_nonce'], 'metasync_clear_otto_cache_nonce')) { wp_die('Security check failed'); } if (!Metasync::current_user_has_plugin_access()) { wp_die('You do not have permission to perform this action'); } $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced'); $url = isset($_POST['otto_cache_url']) ? trim($_POST['otto_cache_url']) : ''; if (empty($url)) { wp_safe_redirect($redirect_url . '&otto_cache_error=1&message=' . urlencode('URL is required')); exit; } if (!filter_var($url, FILTER_VALIDATE_URL)) { wp_safe_redirect($redirect_url . '&otto_cache_error=1&message=' . urlencode('Invalid URL format')); exit; } if (class_exists('Metasync_Otto_Transient_Cache')) { try { $result = Metasync_Otto_Transient_Cache::clear_url_transient($url); if ($result['success']) { $redirect_url .= '&otto_cache_cleared=1&count=' . $result['cleared_count'] . '&url=' . urlencode($url); } else { $redirect_url .= '&otto_cache_error=1&message=' . urlencode($result['message']); } } catch (Exception $e) { error_log('MetaSync OTTO Cache Clear Error: ' . $e->getMessage()); $redirect_url .= '&otto_cache_error=1&message=' . urlencode('An error occurred while clearing the OTTO cache for this URL. Please try again.'); } } else { $redirect_url .= '&otto_cache_error=1&message=' . urlencode('Transient Cache class not found'); } delete_transient('metasync_otto_js_detected'); wp_safe_redirect($redirect_url); exit; } // ------------------------------------------------------------------ // AJAX handlers – excluded URLs // ------------------------------------------------------------------ /** * AJAX handler to add excluded URL for OTTO */ public function ajax_otto_add_excluded_url() { if (!Metasync::current_user_has_plugin_access()) { wp_send_json_error(['message' => 'Insufficient permissions']); return; } if (!check_ajax_referer('metasync_otto_excluded_urls', 'nonce', false)) { wp_send_json_error(['message' => 'Invalid security token']); return; } $url_pattern = isset($_POST['url_pattern']) ? sanitize_text_field($_POST['url_pattern']) : ''; $pattern_type = isset($_POST['pattern_type']) ? sanitize_text_field($_POST['pattern_type']) : 'exact'; $description = isset($_POST['description']) ? sanitize_textarea_field($_POST['description']) : ''; if (empty($url_pattern)) { wp_send_json_error(['message' => 'URL pattern is required']); return; } $valid_types = ['exact', 'contain', 'start', 'end', 'regex']; if (!in_array($pattern_type, $valid_types)) { wp_send_json_error(['message' => 'Invalid pattern type']); return; } if ($pattern_type === 'regex') { // Limit pattern length to prevent ReDoS via catastrophic backtracking if (strlen($url_pattern) > 500) { wp_send_json_error(['message' => 'Regular expression pattern is too long (max 500 characters)']); return; } // Reject patterns with nested quantifiers that could cause ReDoS $raw = preg_replace('/^\S(.*)\S[a-zA-Z]*$/', '$1', $url_pattern); if (preg_match('/(\([^)]*[+*][^)]*\))[+*?{]|(\[[^\]]*\])[+*][+*?{]/', $raw)) { wp_send_json_error(['message' => 'Pattern contains potentially unsafe nested quantifiers']); return; } $test_pattern = $url_pattern; $delimiter_chars = ['/', '#', '~', '%', '@']; $has_valid_delimiters = false; if (strlen($test_pattern) >= 2) { $first_char = $test_pattern[0]; if (in_array($first_char, $delimiter_chars)) { $last_pos = strrpos($test_pattern, $first_char); if ($last_pos > 0) { $has_valid_delimiters = true; } } } if (!$has_valid_delimiters) { $test_pattern = '/' . $test_pattern . '/'; } if (!Metasync_Regex_Validator::is_valid($test_pattern)) { wp_send_json_error(['message' => 'Invalid regular expression pattern']); return; } } require_once plugin_dir_path(dirname(__FILE__)) . 'otto/class-metasync-otto-excluded-urls-database.php'; $db = new Metasync_Otto_Excluded_URLs_Database(); $result = $db->add([ 'url_pattern' => $url_pattern, 'pattern_type' => $pattern_type, 'description' => $description, 'status' => 'active', ]); if ($result === 'duplicate') { wp_send_json_error([ 'message' => 'This URL pattern already exists in the exclusion list', 'code' => 'duplicate' ]); return; } if ($result === 'reactivated') { $db->clear_cache(); if ($pattern_type === 'exact') { try { if (class_exists('Metasync_Cache_Purge')) { $cache_purge = Metasync_Cache_Purge::get_instance(); $cache_purge->clear_url_cache($url_pattern); } wp_cache_flush(); } catch (Exception $e) { error_log('MetaSync: Failed to clear cache for reactivated URL: ' . $e->getMessage()); } } wp_send_json_success([ 'message' => 'Previously inactive URL pattern has been reactivated. Cache cleared.', ]); return; } if ($result === true) { $db->clear_cache(); if ($pattern_type === 'exact') { try { if (class_exists('Metasync_Cache_Purge')) { $cache_purge = Metasync_Cache_Purge::get_instance(); $cache_purge->clear_url_cache($url_pattern); } wp_cache_flush(); } catch (Exception $e) { error_log('MetaSync: Failed to clear cache for excluded URL: ' . $e->getMessage()); } } wp_send_json_success([ 'message' => sprintf('URL excluded from %s successfully. Cache cleared.', Metasync::get_whitelabel_otto_name()), ]); } else { wp_send_json_error(['message' => 'Failed to add excluded URL']); } } /** * AJAX handler to delete excluded URL for OTTO */ public function ajax_otto_delete_excluded_url() { if (!Metasync::current_user_has_plugin_access()) { wp_send_json_error(['message' => 'Insufficient permissions']); return; } if (!check_ajax_referer('metasync_otto_excluded_urls', 'nonce', false)) { wp_send_json_error(['message' => 'Invalid security token']); return; } $id = isset($_POST['id']) ? intval($_POST['id']) : 0; if ($id <= 0) { wp_send_json_error(['message' => 'Invalid ID']); return; } require_once plugin_dir_path(dirname(__FILE__)) . 'otto/class-metasync-otto-excluded-urls-database.php'; $db = new Metasync_Otto_Excluded_URLs_Database(); $result = $db->delete([$id]); if ($result) { wp_send_json_success([ 'message' => 'Excluded URL deleted successfully', ]); } else { wp_send_json_error(['message' => 'Failed to delete excluded URL']); } } /** * AJAX handler to recheck if an excluded URL is now available */ public function ajax_otto_recheck_excluded_url() { if (!Metasync::current_user_has_plugin_access()) { wp_send_json_error(['message' => 'Insufficient permissions']); return; } if (!check_ajax_referer('metasync_otto_excluded_urls', 'nonce', false)) { wp_send_json_error(['message' => 'Invalid security token']); return; } $id = isset($_POST['id']) ? intval($_POST['id']) : 0; if ($id <= 0) { wp_send_json_error(['message' => 'Invalid ID']); return; } require_once plugin_dir_path(dirname(__FILE__)) . 'otto/class-metasync-otto-excluded-urls-database.php'; require_once plugin_dir_path(dirname(__FILE__)) . 'otto/otto_pixel.php'; $db = new Metasync_Otto_Excluded_URLs_Database(); $row = $db->get_record_by_id($id); if (!$row || empty($row->url_pattern)) { wp_send_json_error(['message' => 'Excluded URL not found']); return; } $url = trim($row->url_pattern); $available = metasync_otto_is_url_available($url); wp_send_json_success([ 'available' => $available, 'url' => $url, ]); } /** * AJAX handler to get excluded URLs with pagination */ public function ajax_otto_get_excluded_urls() { if (!Metasync::current_user_has_plugin_access()) { wp_send_json_error(['message' => 'Insufficient permissions']); return; } if (!check_ajax_referer('metasync_otto_excluded_urls', 'nonce', false)) { wp_send_json_error(['message' => 'Invalid security token']); return; } $page = isset($_POST['page']) ? intval($_POST['page']) : 1; $per_page = isset($_POST['per_page']) ? intval($_POST['per_page']) : 10; if ($page < 1) { $page = 1; } if ($per_page < 1 || $per_page > 100) { $per_page = 10; } require_once plugin_dir_path(dirname(__FILE__)) . 'otto/class-metasync-otto-excluded-urls-database.php'; $db = new Metasync_Otto_Excluded_URLs_Database(); $records = $db->get_paginated_records($per_page, $page); $total_count = $db->get_total_count(); $total_pages = ceil($total_count / $per_page); wp_send_json_success([ 'records' => $records, 'pagination' => [ 'current_page' => $page, 'per_page' => $per_page, 'total_count' => $total_count, 'total_pages' => $total_pages, ], ]); } }