PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.1
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.1
2.14.1 2.14.0 2.13.0 2.12.0 2.11.0 2.10.0 2.9.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 All 56 releases
← All changes | includes/diagnostics/class-foreign-schema-detector.php +33 -2 2.14.0 → 2.14.1 View file →
@@ -58,11 +58,12 @@
58 58 *
59 59 * `class` matches a token in the script tag's class attribute, which is the
60 60 * strongest signal available — the big four each tag their own block. `comment`
61 61 * matches the HTML comment wrapper a plugin prints around its head output,
62 - * for the ones that carry no class.
62 + * for the ones that carry no class. `id`, where present, matches the script
63 + * tag's id attribute exactly, for a plugin that labels its block that way.
63 64 *
64 - * @var array<string, array{name:string, class:string[], comment:string[]}>
65 + * @var array<string, array{name:string, class:string[], comment:string[], id?:string[]}>
65 66 */
66 67 private const SIGNATURES = [
67 68 'yoast' => [
68 69 'name' => 'Yoast SEO',
@@ -98,8 +99,16 @@
98 99 'name' => 'WooCommerce',
99 100 'class' => [],
100 101 'comment' => ['woocommerce json-ld'],
101 102 ],
103 + // SureRank tags its block by id, not class, and prints it outside
104 + // its "SureRank Meta Data" comment pair (#916).
105 + 'surerank' => [
106 + 'name' => 'SureRank',
107 + 'class' => [],
108 + 'comment' => [],
109 + 'id' => ['surerank-schema'],
110 + ],
102 111 ];
103 112
104 113 /**
105 114 * Schema types worth warning about when both sides publish one.
@@ -356,11 +365,16 @@
356 365 * @return array{slug:string, name:string, guess:bool}
357 366 */
358 367 private function attribute(array $block): array {
359 368 $classes = $this->class_tokens($block['tag']);
369 + $tag_id = $this->tag_id($block['tag']);
360 370 $comment = strtolower($block['preceding']);
361 371
362 372 foreach (self::SIGNATURES as $slug => $signature) {
373 + if ($tag_id !== '' && in_array($tag_id, $signature['id'] ?? [], true)) {
374 + return ['slug' => $slug, 'name' => $signature['name'], 'guess' => false];
375 + }
376 +
363 377 foreach ($signature['class'] as $class) {
364 378 if (in_array($class, $classes, true)) {
365 379 return ['slug' => $slug, 'name' => $signature['name'], 'guess' => false];
366 380 }
@@ -399,8 +413,25 @@
399 413 $names[$slug] = (string) ($plugin['name'] ?? $slug);
400 414 }
401 415
402 416 return $names;
417 + }
418 +
419 + /**
420 + * The id attribute of a script tag, lowercased.
421 + *
422 + * @since 2.15.0
423 + *
424 + * @param string $attributes Attribute text from the opening script tag.
425 + * @return string Id, or an empty string when the tag has none.
426 + */
427 + private function tag_id(string $attributes): string {
428 + // Whitespace before the name, so `data-id` is not read as `id`.
429 + if (!preg_match('#(?:^|\s)id\s*=\s*["\']([^"\']*)["\']#i', $attributes, $match)) {
430 + return '';
431 + }
432 +
433 + return strtolower(trim($match[1]));
403 434 }
404 435
405 436 /**
406 437 * Class tokens on a script tag.