| @@ -124,8 +124,45 @@ | ||
| 124 | 124 | */ |
| 125 | 125 | private const REFRESH_TIMEOUT = 10; |
| 126 | 126 | |
| 127 | 127 | /** |
| 128 | + * Transient prefix for the cached dashboard payload, suffixed with the | |
| 129 | + * date range ("30d"). Carries the plugin prefix so uninstall's | |
| 130 | + * `_transient_thinkrank_%` sweep removes it; the payload holds up to | |
| 131 | + * 1,000 of the site's search queries (#918). | |
| 132 | + * | |
| 133 | + * @since 2.14.2 | |
| 134 | + * @var string | |
| 135 | + */ | |
| 136 | + public const DASHBOARD_CACHE_PREFIX = 'thinkrank_analytics_dashboard_v5_'; | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * Transient prefix for the cached SEO opportunities payload, suffixed | |
| 140 | + * with the date range. Prefixed for the same reason as the dashboard's. | |
| 141 | + * | |
| 142 | + * @since 2.14.2 | |
| 143 | + * @var string | |
| 144 | + */ | |
| 145 | + public const OPPORTUNITIES_CACHE_PREFIX = 'thinkrank_seo_opportunities_'; | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * Every date range the dashboard cache is written under: the three the | |
| 149 | + * UI offers plus the doubled previous-period ranges used for trends. | |
| 150 | + * | |
| 151 | + * @since 2.14.2 | |
| 152 | + * @var string[] | |
| 153 | + */ | |
| 154 | + public const CACHED_DASHBOARD_RANGES = ['7d', '30d', '90d', '14d', '60d', '180d']; | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * Every date range the opportunities cache is written under. | |
| 158 | + * | |
| 159 | + * @since 2.14.2 | |
| 160 | + * @var string[] | |
| 161 | + */ | |
| 162 | + public const CACHED_OPPORTUNITY_RANGES = ['7d', '30d', '90d']; | |
| 163 | + | |
| 164 | + /** | |
| 128 | 165 | * Constructor |
| 129 | 166 | * |
| 130 | 167 | * @param Settings_Manager|null $settings_manager Settings manager instance |
| 131 | 168 | */ |
| @@ -677,9 +714,9 @@ | ||
| 677 | 714 | * |
| 678 | 715 | * @throws \Exception On failure. |
| 679 | 716 | */ |
| 680 | 717 | public function get_dashboard_data(string $date_range = '30d'): array { |
| 681 | - $cache_key = "analytics_dashboard_v5_{$date_range}"; | |
| 718 | + $cache_key = self::DASHBOARD_CACHE_PREFIX . $date_range; | |
| 682 | 719 | $cached_data = get_transient($cache_key); |
| 683 | 720 | |
| 684 | 721 | if ($cached_data !== false) { |
| 685 | 722 | // Core Web Vitals are cached separately with a much shorter |
| @@ -970,9 +1007,9 @@ | ||
| 970 | 1007 | * @param string $date_range Date range for analysis |
| 971 | 1008 | * @return array SEO opportunities |
| 972 | 1009 | */ |
| 973 | 1010 | public function get_seo_opportunities(string $date_range = '30d'): array { |
| 974 | - $cache_key = "seo_opportunities_{$date_range}"; | |
| 1011 | + $cache_key = self::OPPORTUNITIES_CACHE_PREFIX . $date_range; | |
| 975 | 1012 | $cached_data = get_transient($cache_key); |
| 976 | 1013 | |
| 977 | 1014 | if ($cached_data !== false) { |
| 978 | 1015 | return $cached_data; |
| @@ -1086,8 +1123,27 @@ | ||
| 1086 | 1123 | } |
| 1087 | 1124 | } |
| 1088 | 1125 | |
| 1089 | 1126 | /** |
| 1127 | + * Every transient the dashboard and opportunities caches are written | |
| 1128 | + * under. One list, so "Refresh data", the settings save and any later | |
| 1129 | + * caller clear the same keys the readers use. | |
| 1130 | + * | |
| 1131 | + * @since 2.14.2 | |
| 1132 | + * @return string[] | |
| 1133 | + */ | |
| 1134 | + public static function dashboard_cache_keys(): array { | |
| 1135 | + $keys = []; | |
| 1136 | + foreach (self::CACHED_DASHBOARD_RANGES as $range) { | |
| 1137 | + $keys[] = self::DASHBOARD_CACHE_PREFIX . $range; | |
| 1138 | + } | |
| 1139 | + foreach (self::CACHED_OPPORTUNITY_RANGES as $range) { | |
| 1140 | + $keys[] = self::OPPORTUNITIES_CACHE_PREFIX . $range; | |
| 1141 | + } | |
| 1142 | + return $keys; | |
| 1143 | + } | |
| 1144 | + | |
| 1145 | + /** | |
| 1090 | 1146 | * Force refresh of all cached data |
| 1091 | 1147 | * |
| 1092 | 1148 | * @return array Refresh results |
| 1093 | 1149 | */ |
| @@ -1094,21 +1150,12 @@ | ||
| 1094 | 1150 | public function refresh_data(): array { |
| 1095 | 1151 | // Clear all analytics-related transients, including the previous-period |
| 1096 | 1152 | // ranges used for trend comparison (14d/60d/180d) and the separately |
| 1097 | 1153 | // cached Core Web Vitals payload. |
| 1098 | - $cache_keys = [ | |
| 1099 | - 'analytics_dashboard_v5_7d', | |
| 1100 | - 'analytics_dashboard_v5_30d', | |
| 1101 | - 'analytics_dashboard_v5_90d', | |
| 1102 | - 'analytics_dashboard_v5_14d', | |
| 1103 | - 'analytics_dashboard_v5_60d', | |
| 1104 | - 'analytics_dashboard_v5_180d', | |
| 1105 | - 'seo_opportunities_7d', | |
| 1106 | - 'seo_opportunities_30d', | |
| 1107 | - 'seo_opportunities_90d', | |
| 1108 | - 'indexing_status', | |
| 1109 | - 'thinkrank_dashboard_cwv' | |
| 1110 | - ]; | |
| 1154 | + $cache_keys = array_merge( | |
| 1155 | + self::dashboard_cache_keys(), | |
| 1156 | + ['indexing_status', 'thinkrank_dashboard_cwv'] | |
| 1157 | + ); | |
| 1111 | 1158 | |
| 1112 | 1159 | // Also clear PageSpeed-derived caches. Their keys are md5-derived from |
| 1113 | 1160 | // URL + device, so compute them for the URL/device combinations the |
| 1114 | 1161 | // plugin actually tests. |