PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.3
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.3
2.14.3 2.14.2 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 All 58 releases
← All changes | includes/seo/class-schema-builder.php +64 -24 2.13.0 → 2.14.3 View file →
@@ -463,8 +463,54 @@
463 463 return '';
464 464 }
465 465
466 466 /**
467 + * The WebSite SearchAction for the sitelinks search box, or null when the
468 + * site switched it off.
469 + *
470 + * Reads the Website tab's two settings. website_enable_search absent (or
471 + * null) means not configured, which stays on; any other value is read as
472 + * a boolean, so the '' a switched-off toggle is stored as turns it off.
473 + *
474 + * website_search_url is used as the urlTemplate when it is an http(s) URL,
475 + * or a site path, and carries the {search_term_string} placeholder that
476 + * query-input names. Without the placeholder the template cannot take a
477 + * query, so the default WordPress search URL is used instead, as it is
478 + * when the field is empty.
479 + *
480 + * @since 2.15.0
481 + *
482 + * @param array $settings Schema settings or site_data.
483 + * @return array|null SearchAction node, or null when switched off.
484 + */
485 + public static function website_search_action(array $settings): ?array {
486 + $enabled = $settings['website_enable_search'] ?? null;
487 + if (null !== $enabled && empty($enabled)) {
488 + return null;
489 + }
490 +
491 + $url_template = home_url('/?s={search_term_string}');
492 +
493 + $custom = trim((string) ($settings['website_search_url'] ?? ''));
494 + if ('' !== $custom && false !== strpos($custom, '{search_term_string}')) {
495 + if (\ThinkRank\Core\Url_Validator::is_http_url($custom)) {
496 + $url_template = $custom;
497 + } elseif (\ThinkRank\Core\Url_Validator::is_http_url_or_path($custom)) {
498 + $url_template = home_url($custom);
499 + }
500 + }
501 +
502 + return [
503 + '@type' => 'SearchAction',
504 + 'target' => [
505 + '@type' => 'EntryPoint',
506 + 'urlTemplate' => $url_template
507 + ],
508 + 'query-input' => 'required name=search_term_string'
509 + ];
510 + }
511 +
512 + /**
467 513 * Populate Organization schema
468 514 * PRESERVED: Exact same method logic from original Schema_Generator
469 515 *
470 516 * @since 1.0.0
@@ -493,11 +539,18 @@
493 539 $data['url'] ?? null,
494 540 home_url()
495 541 );
496 542
497 - // Logo from user configuration or theme customizer
498 - if (!empty($data['site_data']['organization_logo'])) {
499 - $schema['logo'] = $this->format_image_schema($data['site_data']['organization_logo']);
543 + // Logo: the Schema Manager's Organization logo, then the Site Identity
544 + // logo (the one WebSite.publisher and LocalBusiness already use, so the
545 + // same entity carries the same logo everywhere), then the theme's
546 + // custom logo. With none of them, logo is left out (#1010).
547 + $logo_url = $this->first_non_empty(
548 + $data['site_data']['organization_logo'] ?? null,
549 + $data['site_data']['logo_url'] ?? null
550 + );
551 + if ('' !== $logo_url) {
552 + $schema['logo'] = $this->format_image_schema($logo_url);
500 553 } else {
501 554 // Fallback to WordPress custom logo
502 555 $custom_logo_id = get_theme_mod('custom_logo');
503 556 if ($custom_logo_id) {
@@ -924,9 +977,9 @@
924 977 'organization_social_telegram'
925 978 ];
926 979
927 980 foreach ($social_fields as $field) {
928 - if (!empty($settings[$field]) && filter_var($settings[$field], FILTER_VALIDATE_URL)) {
981 + if (!empty($settings[$field]) && \ThinkRank\Core\Url_Validator::is_valid($settings[$field])) {
929 982 $social_profiles[] = $settings[$field];
930 983 }
931 984 }
932 985
@@ -1130,22 +1183,14 @@
1130 1183 }
1131 1184
1132 1185 $schema['publisher'] = $publisher;
1133 1186
1134 - // Search action for sitelinks search box (optional but recommended)
1135 - if ($data['site_data']['website_enable_search'] ?? true) {
1136 - $search_url = $this->first_non_empty(
1137 - $data['site_data']['website_search_url'] ?? '',
1138 - home_url('/?s={search_term_string}')
1139 - );
1140 - $schema['potentialAction'] = [
1141 - '@type' => 'SearchAction',
1142 - 'target' => [
1143 - '@type' => 'EntryPoint',
1144 - 'urlTemplate' => $search_url
1145 - ],
1146 - 'query-input' => 'required name=search_term_string'
1147 - ];
1187 + // Search action for sitelinks search box (optional but recommended).
1188 + // Shared with the live fallback in SEO_Manager so the deployed and
1189 + // live WebSite nodes read the switch and the URL the same way (#1009).
1190 + $search_action = self::website_search_action($data['site_data'] ?? []);
1191 + if (null !== $search_action) {
1192 + $schema['potentialAction'] = $search_action;
1148 1193 }
1149 1194
1150 1195 // Social media profiles (sameAs)
1151 1196 $social_profiles = $this->get_social_profiles();
@@ -1598,14 +1643,9 @@
1598 1643 $social_profiles,
1599 1644 static function ($url) {
1600 1645 return is_string($url)
1601 1646 && '' !== trim($url)
1602 - && filter_var($url, FILTER_VALIDATE_URL)
1603 - && in_array(
1604 - strtolower((string) wp_parse_url($url, PHP_URL_SCHEME)),
1605 - ['http', 'https'],
1606 - true
1607 - );
1647 + && \ThinkRank\Core\Url_Validator::is_http_url($url);
1608 1648 }
1609 1649 )));
1610 1650
1611 1651 if (!empty($social_profiles)) {