| @@ -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) { |