PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.13.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.13.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 1.26.0 1.25.0 All 54 releases
← All changes | includes/frontend/class-seo-manager.php +46 -4 2.9.0 → 2.13.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 }
@@ -2740,8 +2752,22 @@
2740 2752 if ($archive_description) {
2741 2753 return $archive_description;
2742 2754 }
2743 2755
2756 + // The blog-index homepage's own description (Site Identity
2757 + // homepage_description, #897), in the same vocabulary as its title. A
2758 + // static front page is a page, and its description is set on it.
2759 + if (is_front_page() && is_home() && $this->site_identity_data && $this->site_identity_data['enabled']) {
2760 + $identity = $this->site_identity_manager->get_settings('site');
2761 + $template = trim((string) ($identity['homepage_description'] ?? ''));
2762 + if ($template !== '') {
2763 + $homepage_description = trim($this->process_title_template($template, $this->get_title_placeholders()));
2764 + if ($homepage_description !== '') {
2765 + return $homepage_description;
2766 + }
2767 + }
2768 + }
2769 +
2744 2770 // Third priority: Site Identity default meta description
2745 2771 if ($this->site_identity_data && $this->site_identity_data['enabled']) {
2746 2772 $settings = $this->site_identity_manager->get_settings('site');
2747 2773 $default_description = $settings['default_meta_description'] ?? '';
@@ -2954,10 +2980,22 @@
2954 2980 $context_type,
2955 2981 $context_id
2956 2982 );
2957 2983
2984 + // A deployed node is a snapshot from Deploy time and outranks
2985 + // the automatic node, so page and article types would publish
2986 + // a frozen excerpt instead of the description the head
2987 + // resolves. Give them the live one, as the automatic node has.
2988 + $context_post = get_post($context_id);
2989 +
2958 2990 foreach ($page_specific_schemas as $schema_type => $schema_info) {
2959 - Schema_Graph::instance()->add_primary($schema_info['data'], (string) $schema_type, 'schema_manager');
2991 + $node = $schema_info['data'];
2992 +
2993 + if ($this->global_seo_schema && $context_post instanceof \WP_Post) {
2994 + $node = $this->global_seo_schema->refresh_deployed_description($node, (string) $schema_type, $context_post);
2995 + }
2996 +
2997 + Schema_Graph::instance()->add_primary($node, (string) $schema_type, 'schema_manager');
2960 2998 }
2961 2999 $has_schema_manager_output = true;
2962 3000 }
2963 3001 }
@@ -3015,8 +3053,12 @@
3015 3053 'url' => home_url('/'),
3016 3054 ];
3017 3055
3018 3056 $description = !empty($settings['site_description']) ? $settings['site_description'] : get_bloginfo('description');
3057 + // The tagline is stored esc_html()'d by sanitize_option(), so a site
3058 + // called "Fish & Chips" published `&amp;` literally in its WebSite
3059 + // node; nothing decodes JSON-LD downstream.
3060 + $description = \ThinkRank\Core\Seo_Text::normalize_schema_text((string) $description);
3019 3061 if (!empty($description)) {
3020 3062 $schema['description'] = $description;
3021 3063 }
3022 3064