PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.11.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.11.0
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/admin/importers/class-yoast-exporter.php +60 -0 2.7.0 → 2.11.0 View file →
@@ -155,8 +155,9 @@
155 155 'twitter_title' => $this->convert_template_variables($meta['_yoast_wpseo_twitter-title'] ?? '', $post_id),
156 156 'twitter_description' => $this->convert_template_variables($meta['_yoast_wpseo_twitter-description'] ?? '', $post_id),
157 157 'twitter_image' => $meta['_yoast_wpseo_twitter-image'] ?? '',
158 158 'primary_category' => (int) ($meta['_yoast_wpseo_primary_category'] ?? 0),
159 + 'product_identifier' => $this->extract_product_identifier($meta),
159 160 'schema_type' => $meta['_yoast_wpseo_schema_page_type'] ?? '',
160 161 // Yoast "cornerstone content" maps to ThinkRank pillar content.
161 162 'pillar_content' => (int) ($meta['_yoast_wpseo_is_cornerstone'] ?? 0),
162 163 ],
@@ -549,8 +550,15 @@
549 550 '%%modified%%' => '%modified%',
550 551 '%%name%%' => '%author%',
551 552 '%%category%%' => '%category%',
552 553 '%%primary_category%%' => '%category%',
554 + // WooCommerce SEO product variables. Stripped rather than mapped
555 + // until #715, so a product description template imported as "Buy
556 + // %title% for" with the price and stock gone.
557 + '%%wc_price%%' => '%price%',
558 + '%%wc_sku%%' => '%sku%',
559 + '%%wc_shortdesc%%' => '%short_description%',
560 + '%%wc_brand%%' => '%brand%',
553 561 ];
554 562
555 563 $template = str_replace(array_keys($map), array_values($map), $template);
556 564
@@ -788,8 +796,22 @@
788 796 // Math tokens wrapped in Yoast's double-percent syntax — tokens Yoast
789 797 // itself cannot resolve either. Map them rather than stripping them,
790 798 // or the format silently loses its search term / term name.
791 799 '%%search_query%%' => '%search_term%',
800 + // NOT the WooCommerce product variables, deliberately. This
801 + // converter writes Site Identity title formats, and those are
802 + // resolved by SEO_Manager::process_title_template() against its own
803 + // vocabulary — %site_title%, %separator%, %search_term% and the
804 + // rest — which has no %price%/%sku%/%brand% and, unlike
805 + // Pattern_Resolver, does not strip what it cannot resolve. Mapping
806 + // them here published "Search pennant - %price% - Media Wipe" in a
807 + // live <title>: a silent loss traded for the literal leak #715 is
808 + // about. The formats this feeds are the homepage, search, archive,
809 + // author, category and tag titles, where there is no one product
810 + // for a price to belong to either way, so the strip below is the
811 + // right answer. The per-post converter keeps them, because
812 + // Pattern_Resolver does resolve them: see
813 + // convert_template_pattern().
792 814 ];
793 815 if ($context_token !== '') {
794 816 $map['%%title%%'] = $context_token;
795 817 $map['%%term_title%%'] = $context_token;
@@ -992,6 +1014,44 @@
992 1014 }
993 1015 }
994 1016
995 1017 return $settings;
1018 + }
1019 +
1020 + /**
1021 + * A product's identifier from Yoast WooCommerce SEO.
1022 + *
1023 + * Yoast stores every identifier type in one serialised map keyed by type
1024 + * (`gtin8`, `gtin12`, `gtin13`, `gtin14`, `isbn`, `mpn`) rather than in a
1025 + * field per type. ThinkRank Pro holds a single identifier, so the first
1026 + * non-empty one wins, in the order Google prefers: a GTIN identifies the
1027 + * product itself, an MPN only identifies it within one manufacturer, and
1028 + * an ISBN applies to books alone.
1029 + *
1030 + * @since 2.10.1
1031 + *
1032 + * @param array $meta Post meta for the product.
1033 + * @return string Identifier, or '' when the product has none.
1034 + */
1035 + private function extract_product_identifier(array $meta): string {
1036 + $raw = $meta['wpseo_global_identifier_values'] ?? '';
1037 +
1038 + if (is_string($raw) && '' !== $raw) {
1039 + $decoded = maybe_unserialize($raw);
1040 + $raw = is_array($decoded) ? $decoded : [];
1041 + }
1042 +
1043 + if (!is_array($raw) || empty($raw)) {
1044 + return '';
1045 + }
1046 +
1047 + foreach (['gtin13', 'gtin14', 'gtin12', 'gtin8', 'mpn', 'isbn'] as $type) {
1048 + $value = trim((string) ($raw[$type] ?? ''));
1049 +
1050 + if ('' !== $value) {
1051 + return $value;
1052 + }
1053 + }
1054 +
1055 + return '';
996 1056 }
997 1057 }