PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.12.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.12.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 1.26.0 1.25.0 trunk All 53 releases
← All changes | includes/frontend/class-seo-manager.php +32 -4 2.9.0 → 2.12.0 View file →
@@ -377,8 +377,16 @@
377 377 }
378 378
379 379 // Initialize Global SEO Schema Output and store reference
380 380 $this->global_seo_schema = new Global_SEO_Schema_Output();
381 + // Let schema reuse the description this class already resolves, so the
382 + // JSON-LD and the meta/og/twitter tags cannot disagree about what the
383 + // page is (#766). Passed as a callback rather than a value: schema is
384 + // built during wp_head, by which point the request context this
385 + // resolution depends on is set, and it must not be captured earlier.
386 + $this->global_seo_schema->set_description_resolver(
387 + fn (): string => (string) $this->get_meta_description()
388 + );
381 389 $this->global_seo_schema->init();
382 390 }
383 391
384 392 /**
@@ -1791,12 +1799,16 @@
1791 1799 // Get image dimensions and alt text
1792 1800 $image_id = get_post_thumbnail_id($this->current_post_id);
1793 1801 $image_meta = wp_get_attachment_metadata($image_id);
1794 1802 if ($image_meta) {
1803 + // The `large` file being published, not the original it
1804 + // was generated from: the metadata's own width and height
1805 + // describe an image this tag does not point at (#847).
1806 + $image_file = \ThinkRank\SEO\Attachment_Lookup::describe((int) $image_id, (string) $image_url);
1795 1807 // SVGs (and other vector uploads) report 0x0 — emitting
1796 1808 // those as og:image dimensions is invalid, so skip them.
1797 - $og_width = isset($image_meta['width']) ? (int) $image_meta['width'] : 0;
1798 - $og_height = isset($image_meta['height']) ? (int) $image_meta['height'] : 0;
1809 + $og_width = $image_file['width'];
1810 + $og_height = $image_file['height'];
1799 1811 if ($og_width > 0 && $og_height > 0) {
1800 1812 echo "<meta property=\"og:image:width\" content=\"" . esc_attr($og_width) . "\" />\n";
1801 1813 echo "<meta property=\"og:image:height\" content=\"" . esc_attr($og_height) . "\" />\n";
1802 1814 }
@@ -1801,9 +1813,9 @@
1801 1813 echo "<meta property=\"og:image:height\" content=\"" . esc_attr($og_height) . "\" />\n";
1802 1814 }
1803 1815 // Derive the real mime type instead of hardcoding image/jpeg,
1804 1816 // which mislabels PNG/WebP featured images.
1805 - $image_mime = get_post_mime_type($image_id);
1817 + $image_mime = $image_file['type'];
1806 1818 if ($image_mime) {
1807 1819 echo "<meta property=\"og:image:type\" content=\"" . esc_attr($image_mime) . "\" />\n";
1808 1820 }
1809 1821 }
@@ -2954,10 +2966,22 @@
2954 2966 $context_type,
2955 2967 $context_id
2956 2968 );
2957 2969
2970 + // A deployed node is a snapshot from Deploy time and outranks
2971 + // the automatic node, so page and article types would publish
2972 + // a frozen excerpt instead of the description the head
2973 + // resolves. Give them the live one, as the automatic node has.
2974 + $context_post = get_post($context_id);
2975 +
2958 2976 foreach ($page_specific_schemas as $schema_type => $schema_info) {
2959 - Schema_Graph::instance()->add_primary($schema_info['data'], (string) $schema_type, 'schema_manager');
2977 + $node = $schema_info['data'];
2978 +
2979 + if ($this->global_seo_schema && $context_post instanceof \WP_Post) {
2980 + $node = $this->global_seo_schema->refresh_deployed_description($node, (string) $schema_type, $context_post);
2981 + }
2982 +
2983 + Schema_Graph::instance()->add_primary($node, (string) $schema_type, 'schema_manager');
2960 2984 }
2961 2985 $has_schema_manager_output = true;
2962 2986 }
2963 2987 }
@@ -3015,8 +3039,12 @@
3015 3039 'url' => home_url('/'),
3016 3040 ];
3017 3041
3018 3042 $description = !empty($settings['site_description']) ? $settings['site_description'] : get_bloginfo('description');
3043 + // The tagline is stored esc_html()'d by sanitize_option(), so a site
3044 + // called "Fish & Chips" published `&amp;` literally in its WebSite
3045 + // node; nothing decodes JSON-LD downstream.
3046 + $description = \ThinkRank\Core\Seo_Text::normalize_schema_text((string) $description);
3019 3047 if (!empty($description)) {
3020 3048 $schema['description'] = $description;
3021 3049 }
3022 3050