PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.8.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.8.0
2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 All 49 releases
← All changes | includes/seo/class-schema-cache-manager.php +26 -14 1.0.02.8.0 View file →
@@ -136,14 +136,26 @@
136 136 */
137 137 public function clear_all(): bool {
138 138 global $wpdb;
139 139
140 - // Clear memory cache (if using object cache)
141 - wp_cache_flush_group(self::CACHE_GROUP);
140 + // Clear memory cache (if using object cache).
141 + //
142 + // wp_cache_flush_group() is WordPress 6.1+, and the plugin header
143 + // declares "Requires at least: 6.0" — on 6.0 this was a fatal
144 + // "call to undefined function" on every schema settings save, since
145 + // save_settings() reaches here via invalidate_all_cache(). Fall back to
146 + // a full flush rather than skipping: a no-op would leave stale schema
147 + // served until the database rows expire, which is worse than a coarse
148 + // flush. Deactivator already guards the same call this way.
149 + if (function_exists('wp_cache_flush_group')) {
150 + wp_cache_flush_group(self::CACHE_GROUP);
151 + } else {
152 + wp_cache_flush();
153 + }
142 154
143 155 // Clear database cache
144 156 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
145 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Table name is properly constructed from controlled prefix, cache clearing requires direct database access
157 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is properly constructed from controlled prefix, cache clearing requires direct database access
146 158 $result = $wpdb->query($wpdb->prepare("DELETE FROM {$table_name} WHERE cache_key LIKE %s", 'schema_%'));
147 159
148 160 return $result !== false;
149 161 }
@@ -160,12 +172,12 @@
160 172
161 173 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
162 174 $current_time = time();
163 175
164 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache cleanup requires direct database access
176 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Cache cleanup requires direct database access
165 177 $result = $wpdb->query(
166 178 $wpdb->prepare(
167 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is properly constructed from controlled prefix
179 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is properly constructed from controlled prefix
168 180 "DELETE FROM {$table_name} WHERE cache_key LIKE %s AND expires_at < %d",
169 181 'schema_%',
170 182 $current_time
171 183 )
@@ -207,9 +219,9 @@
207 219 public function generate_schema_generation_key(string $schema_type, array $data, array $options = []): string {
208 220 $key_data = [
209 221 'operation' => 'schema_generation',
210 222 'schema_type' => $schema_type,
211 - 'data_hash' => md5(serialize($data)),
223 + 'data_hash' => md5(wp_json_encode($data)),
212 224 'options' => $options,
213 225 'version' => THINKRANK_VERSION,
214 226 ];
215 227
@@ -229,9 +241,9 @@
229 241 public function generate_validation_key(array $schema_data, string $schema_type, array $options = []): string {
230 242 $key_data = [
231 243 'operation' => 'schema_validation',
232 244 'schema_type' => $schema_type,
233 - 'schema_hash' => md5(serialize($schema_data)),
245 + 'schema_hash' => md5(wp_json_encode($schema_data)),
234 246 'options' => $options,
235 247 'version' => THINKRANK_VERSION,
236 248 ];
237 249
@@ -288,12 +300,12 @@
288 300
289 301 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
290 302 $current_time = time();
291 303
292 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache retrieval requires direct database access
304 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Cache retrieval requires direct database access
293 305 $cached_row = $wpdb->get_row(
294 306 $wpdb->prepare(
295 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is properly constructed from controlled prefix
307 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is properly constructed from controlled prefix
296 308 "SELECT cache_data, expires_at FROM {$table_name}
297 309 WHERE cache_key = %s AND expires_at > %d",
298 310 $cache_key,
299 311 $current_time
@@ -321,9 +333,9 @@
321 333 global $wpdb;
322 334
323 335 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
324 336
325 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache storage requires direct database access
337 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Cache storage requires direct database access
326 338 $result = $wpdb->replace(
327 339 $table_name,
328 340 [
329 341 'cache_key' => $cache_key,
@@ -349,9 +361,9 @@
349 361 global $wpdb;
350 362
351 363 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
352 364
353 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache deletion requires direct database access
365 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Cache deletion requires direct database access
354 366 $result = $wpdb->delete(
355 367 $table_name,
356 368 ['cache_key' => $cache_key],
357 369 ['%s']
@@ -372,14 +384,14 @@
372 384
373 385 $table_name = $wpdb->prefix . 'thinkrank_ai_cache';
374 386 $current_time = time();
375 387
376 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Table name is properly constructed from controlled prefix, cache stats require direct database access
388 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is properly constructed from controlled prefix, cache stats require direct database access
377 389 $total_entries = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table_name} WHERE cache_key LIKE %s", 'schema_%'));
378 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache stats require direct database access
390 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Cache stats require direct database access
379 391 $expired_entries = $wpdb->get_var(
380 392 $wpdb->prepare(
381 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is properly constructed from controlled prefix
393 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is properly constructed from controlled prefix
382 394 "SELECT COUNT(*) FROM {$table_name} WHERE cache_key LIKE %s AND expires_at < %d",
383 395 'schema_%',
384 396 $current_time
385 397 )