PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.2
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.2
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 1.28.0 All 57 releases
← All changes | includes/seo/class-social-meta-manager.php +66 -21 2.11.0 → 2.14.2 View file →
@@ -523,12 +523,29 @@
523 523 $validation['valid'] = false;
524 524 }
525 525 }
526 526
527 + // The default Open Graph and Twitter images are checked in the field
528 + // details above only while their feature is switched on, but they are
529 + // stored (and shown in the admin preview's src) either way.
530 + $flagged = [];
531 + foreach ($field_details as $field) {
532 + if ('error' === ($field['status'] ?? '')) {
533 + $flagged[] = $field['field'] ?? '';
534 + }
535 + }
536 + foreach (['default_og_image' => 'Default Open Graph image', 'default_twitter_image' => 'Default Twitter Card image'] as $key => $label) {
537 + if (!empty($settings[$key]) && !in_array($key, $flagged, true)
538 + && !\ThinkRank\Core\Url_Validator::is_http_url($settings[$key])) {
539 + $validation['errors'][] = $label . ' must be an http or https URL.';
540 + $validation['valid'] = false;
541 + }
542 + }
543 +
527 544 // Validate default image
528 545 if (isset($settings['default_image']) && !empty($settings['default_image'])) {
529 - if (!filter_var($settings['default_image'], FILTER_VALIDATE_URL)) {
530 - $validation['errors'][] = 'default_image must be a valid URL';
546 + if (!\ThinkRank\Core\Url_Validator::is_http_url($settings['default_image'])) {
547 + $validation['errors'][] = 'default_image must be an http or https URL';
531 548 $validation['valid'] = false;
532 549 } else {
533 550 // Check image dimensions and format
534 551 $image_validation = $this->validate_social_image($settings['default_image']);
@@ -766,9 +783,12 @@
766 783 }
767 784
768 785 // Default Image validation
769 786 if (!empty($settings['default_og_image'])) {
770 - if (filter_var($settings['default_og_image'], FILTER_VALIDATE_URL)) {
787 + // http(s) only, and refused rather than warned about: the
788 + // value becomes og:image and the admin preview's src, and a
789 + // javascript: URL passed is_valid().
790 + if (\ThinkRank\Core\Url_Validator::is_http_url($settings['default_og_image'])) {
771 791 $field_details[] = [
772 792 'field' => 'default_og_image',
773 793 'label' => 'Default Open Graph image is configured.',
774 794 'status' => 'valid',
@@ -776,11 +796,11 @@
776 796 ];
777 797 } else {
778 798 $field_details[] = [
779 799 'field' => 'default_og_image',
780 - 'label' => 'Default Open Graph image URL appears invalid.',
781 - 'status' => 'warning',
782 - 'icon' => '⚠'
800 + 'label' => 'Default Open Graph image must be an http or https URL.',
801 + 'status' => 'error',
802 + 'icon' => '✗'
783 803 ];
784 804 }
785 805 } else {
786 806 $field_details[] = [
@@ -900,9 +920,9 @@
900 920 }
901 921
902 922 // Default Twitter Image validation
903 923 if (!empty($settings['default_twitter_image'])) {
904 - if (filter_var($settings['default_twitter_image'], FILTER_VALIDATE_URL)) {
924 + if (\ThinkRank\Core\Url_Validator::is_http_url($settings['default_twitter_image'])) {
905 925 $field_details[] = [
906 926 'field' => 'default_twitter_image',
907 927 'label' => 'Default Twitter Card image is configured.',
908 928 'status' => 'valid',
@@ -910,11 +930,11 @@
910 930 ];
911 931 } else {
912 932 $field_details[] = [
913 933 'field' => 'default_twitter_image',
914 - 'label' => 'Default Twitter Card image URL appears invalid.',
915 - 'status' => 'warning',
916 - 'icon' => '⚠'
934 + 'label' => 'Default Twitter Card image must be an http or https URL.',
935 + 'status' => 'error',
936 + 'icon' => '✗'
917 937 ];
918 938 }
919 939 } else {
920 940 $field_details[] = [
@@ -1533,9 +1553,21 @@
1533 1553 $data['title'] = $fallback_title;
1534 1554 } else {
1535 1555 $data['title'] = $blogname;
1536 1556 }
1537 - $data['description'] = $settings['og_description'] ?? get_bloginfo('description');
1557 + // Same rule as the title above: the shipped default (the tagline)
1558 + // is not a choice, so the homepage's meta description wins over
1559 + // it. Without this an imported or hand-set homepage description
1560 + // printed as the meta description while og:/twitter:description
1561 + // kept the tagline (#897).
1562 + $og_description = (string) ($settings['og_description'] ?? '');
1563 + if ($og_description !== '' && $og_description !== get_bloginfo('description')) {
1564 + $data['description'] = $og_description;
1565 + } elseif ($fallback_description !== null && $fallback_description !== '') {
1566 + $data['description'] = $fallback_description;
1567 + } else {
1568 + $data['description'] = get_bloginfo('description');
1569 + }
1538 1570 // Use home_url('/') so og:url matches the homepage canonical
1539 1571 // (class-seo-manager.php) and the WebSite schema, which both include
1540 1572 // the trailing slash. A bare home_url() would key a different URL in
1541 1573 // social caches than the canonical.
@@ -1842,8 +1874,12 @@
1842 1874 $image_id = get_post_thumbnail_id($post);
1843 1875 if ($image_id) {
1844 1876 $image_data = wp_get_attachment_image_src($image_id, 'large');
1845 1877 if (!empty($image_data[0])) {
1878 + // The ID is in hand here and gone once this returns a
1879 + // bare URL; say so rather than have the tag builders look
1880 + // it up again, twice, with a URL core cannot match (#847).
1881 + Attachment_Lookup::remember((string) $image_data[0], (int) $image_id);
1846 1882 return $image_data[0];
1847 1883 }
1848 1884 }
1849 1885 }
@@ -1890,8 +1926,12 @@
1890 1926 $image_id = get_post_thumbnail_id($post);
1891 1927 if ($image_id) {
1892 1928 $image_data = wp_get_attachment_image_src($image_id, 'large');
1893 1929 if (!empty($image_data[0])) {
1930 + // The ID is in hand here and gone once this returns a
1931 + // bare URL; say so rather than have the tag builders look
1932 + // it up again, twice, with a URL core cannot match (#847).
1933 + Attachment_Lookup::remember((string) $image_data[0], (int) $image_id);
1894 1934 return $image_data[0];
1895 1935 }
1896 1936 }
1897 1937 }
@@ -2184,21 +2224,23 @@
2184 2224 if (empty($image_url)) {
2185 2225 return $image_data;
2186 2226 }
2187 2227
2188 - // Get image metadata
2189 - $attachment_id = attachment_url_to_postid($image_url);
2228 + // Get image metadata. The dimensions are those of the file this URL
2229 + // names — usually a generated size — not of the original upload, so
2230 + // the width and height published beside it describe the same image.
2231 + $attachment_id = Attachment_Lookup::id_from_url($image_url);
2190 2232 if ($attachment_id) {
2191 2233 $image_meta = wp_get_attachment_metadata($attachment_id);
2192 2234 $image_alt = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
2193 - $mime_type = get_post_mime_type($attachment_id);
2235 + $image_file = Attachment_Lookup::describe($attachment_id, $image_url);
2194 2236
2195 2237 if ($image_meta && isset($image_meta['width'], $image_meta['height'])) {
2196 - $width = (int) $image_meta['width'];
2197 - $height = (int) $image_meta['height'];
2238 + $width = $image_file['width'];
2239 + $height = $image_file['height'];
2198 2240
2199 2241 $image_data['alt'] = $image_alt ?: '';
2200 - $image_data['type'] = $mime_type ?: '';
2242 + $image_data['type'] = $image_file['type'];
2201 2243
2202 2244 // SVGs and other vector uploads store 0x0 metadata. Dimension
2203 2245 // checks are meaningless there and dividing by 0 is fatal.
2204 2246 if ($width > 0 && $height > 0) {
@@ -2250,8 +2292,9 @@
2250 2292 $custom_logo_id = get_theme_mod('custom_logo');
2251 2293 if ($custom_logo_id) {
2252 2294 $logo_data = wp_get_attachment_image_src($custom_logo_id, 'large');
2253 2295 if ($logo_data) {
2296 + Attachment_Lookup::remember((string) $logo_data[0], (int) $custom_logo_id);
2254 2297 return $logo_data[0];
2255 2298 }
2256 2299 }
2257 2300
@@ -2259,8 +2302,9 @@
2259 2302 $site_icon_id = get_option('site_icon');
2260 2303 if ($site_icon_id) {
2261 2304 $icon_data = wp_get_attachment_image_src($site_icon_id, 'large');
2262 2305 if ($icon_data) {
2306 + Attachment_Lookup::remember((string) $icon_data[0], (int) $site_icon_id);
2263 2307 return $icon_data[0];
2264 2308 }
2265 2309 }
2266 2310
@@ -3011,19 +3055,20 @@
3011 3055 return $validation;
3012 3056 }
3013 3057
3014 3058 // Check if URL is valid
3015 - if (!filter_var($image_url, FILTER_VALIDATE_URL)) {
3059 + if (!\ThinkRank\Core\Url_Validator::is_http_url($image_url)) {
3016 3060 $validation['warnings'][] = 'Invalid image URL';
3017 3061 return $validation;
3018 3062 }
3019 3063
3020 3064 // Get image metadata if it's a local attachment
3021 - $attachment_id = attachment_url_to_postid($image_url);
3065 + $attachment_id = Attachment_Lookup::id_from_url($image_url);
3022 3066 if ($attachment_id) {
3023 3067 $image_meta = wp_get_attachment_metadata($attachment_id);
3024 - $meta_width = isset($image_meta['width']) ? (int) $image_meta['width'] : 0;
3025 - $meta_height = isset($image_meta['height']) ? (int) $image_meta['height'] : 0;
3068 + $image_file = Attachment_Lookup::describe($attachment_id, $image_url);
3069 + $meta_width = $image_file['width'];
3070 + $meta_height = $image_file['height'];
3026 3071
3027 3072 // SVGs and other vector uploads store 0x0 metadata — skip the
3028 3073 // dimension/ratio checks instead of dividing by 0.
3029 3074 if ($image_meta && $meta_width > 0 && $meta_height > 0) {