PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.7.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.7.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 1.10.0 All 48 releases
← All changes | includes/frontend/template-functions.php +50 -43 1.30.02.7.0 View file →
@@ -232,26 +232,53 @@
232 232 if (!$seo_manager) {
233 233 return;
234 234 }
235 235
236 - // Lightweight breadcrumb check — query the DB directly to avoid loading
237 - // the full Site_Identity_Manager (115KB) on every frontend page
238 - global $wpdb;
239 - $table = $wpdb->prefix . 'thinkrank_seo_settings';
236 + // Both checks below read the site_identity settings category. Loading the
237 + // full Site_Identity_Manager (115KB) on every front-end page to get them
238 + // would be worse, but the two ad-hoc queries that replaced it did not share
239 + // the object cache the manager populates on `wp` — so the category was
240 + // fetched twice per request, uncached, on top of the manager's own read
241 + // (#402).
242 + //
243 + // Read that cache entry directly. Abstract_SEO_Manager caches the merged
244 + // settings under this key on every get_settings('site') call, and `wp` runs
245 + // before wp_enqueue_scripts, so on a normal front-end render this is a hit
246 + // and costs nothing. The fallback is one query for the whole category
247 + // rather than two for parts of it.
248 + $identity = wp_cache_get('seo_settings_site_identity_site_0', 'thinkrank_seo');
240 249
241 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Lightweight frontend check avoids loading heavy manager class
242 - $breadcrumbs_enabled = $wpdb->get_var(
243 - $wpdb->prepare(
244 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses WordPress prefix, safe to interpolate
245 - "SELECT setting_value FROM `{$table}` WHERE context_type = %s AND context_id = %d AND setting_category = %s AND setting_key = %s AND is_active = 1",
246 - 'site',
247 - 0,
248 - 'site_identity',
249 - 'breadcrumbs_enabled'
250 - )
251 - );
250 + if (!is_array($identity)) {
251 + global $wpdb;
252 + $table = $wpdb->prefix . 'thinkrank_seo_settings';
252 253
253 - if ($breadcrumbs_enabled) {
254 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Lightweight frontend check avoids loading heavy manager class
255 + $rows = $wpdb->get_results(
256 + $wpdb->prepare(
257 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses WordPress prefix, safe to interpolate
258 + "SELECT setting_key, setting_value FROM `{$table}` WHERE context_type = %s AND context_id = %d AND setting_category = %s AND is_active = 1",
259 + 'site',
260 + 0,
261 + 'site_identity'
262 + ),
263 + ARRAY_A
264 + );
265 +
266 + $identity = [];
267 + foreach ((array) $rows as $row) {
268 + $identity[$row['setting_key']] = $row['setting_value'];
269 + }
270 +
271 + // Deliberately not written back to the object cache: the manager caches
272 + // the values *merged with its defaults* under this key, and seeding it
273 + // with raw rows would hand every later reader a partial record.
274 + }
275 +
276 + $identity_value = static function (string $key) use ($identity): string {
277 + return isset($identity[$key]) ? trim((string) $identity[$key]) : '';
278 + };
279 +
280 + if (!empty($identity['breadcrumbs_enabled'])) {
254 281 wp_enqueue_style(
255 282 'thinkrank-breadcrumbs',
256 283 THINKRANK_PLUGIN_URL . 'static/css/breadcrumbs.css',
257 284 [],
@@ -258,35 +285,15 @@
258 285 THINKRANK_VERSION
259 286 );
260 287 }
261 288
262 - // Lightweight hero check — only load hero CSS when the hero will actually
263 - // render. Mirrors the render gate in SEO_Manager::generate_hero_html():
264 - // a title, a subtitle, or a COMPLETE CTA (both text and URL). A CTA with
265 - // text but no URL renders nothing, so it must not pull in the stylesheet.
266 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Lightweight frontend check avoids loading heavy manager class
267 - $hero_fields = $wpdb->get_results(
268 - $wpdb->prepare(
269 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses WordPress prefix, safe to interpolate
270 - "SELECT setting_key, setting_value FROM `{$table}` WHERE context_type = %s AND context_id = %d AND setting_category = %s AND setting_key IN (%s, %s, %s, %s) AND is_active = 1",
271 - 'site',
272 - 0,
273 - 'site_identity',
274 - 'hero_title',
275 - 'hero_subtitle',
276 - 'hero_cta_text',
277 - 'hero_cta_url'
278 - ),
279 - OBJECT_K
280 - );
281 -
282 - $hero_value = static function ($key) use ($hero_fields) {
283 - return isset($hero_fields[$key]) ? trim((string) $hero_fields[$key]->setting_value) : '';
284 - };
285 -
286 - $hero_renders = '' !== $hero_value('hero_title')
287 - || '' !== $hero_value('hero_subtitle')
288 - || ('' !== $hero_value('hero_cta_text') && '' !== $hero_value('hero_cta_url'));
289 + // Hero check — only load hero CSS when the hero will actually render.
290 + // Mirrors the render gate in SEO_Manager::generate_hero_html(): a title, a
291 + // subtitle, or a COMPLETE CTA (both text and URL). A CTA with text but no
292 + // URL renders nothing, so it must not pull in the stylesheet.
293 + $hero_renders = '' !== $identity_value('hero_title')
294 + || '' !== $identity_value('hero_subtitle')
295 + || ('' !== $identity_value('hero_cta_text') && '' !== $identity_value('hero_cta_url'));
289 296
290 297 if ($hero_renders) {
291 298 wp_enqueue_style(
292 299 'thinkrank-hero',