diff --git a/includes/class-support.php b/includes/class-support.php index bfc9829..767999f 100644 --- a/includes/class-support.php +++ b/includes/class-support.php @@ -17,8 +17,8 @@ public function init(): void $this->uploadsInfo = \wp_upload_dir(); $this->fileCache = \get_transient('avif_local_support_file_cache') ?: []; add_filter('wp_get_attachment_image', [$this, 'wrapAttachment'], 10, 5); - add_filter('the_content', [$this, 'wrapContentImages']); - add_filter('post_thumbnail_html', [$this, 'wrapContentImages']); + add_filter('wp_content_img_tag', [$this, 'wrapContentImgTag'], 10, 3); + add_filter('post_thumbnail_html', [$this, 'wrapSingleImageHtml'], 10, 1); add_action('shutdown', [$this, 'saveCache']); } @@ -50,65 +50,112 @@ public function wrapAttachment(string $html, int $attachmentId, $size, bool $ico return $this->pictureMarkup($html, $avifSrc, $avifSrcset, $sizes); } - public function wrapContentImages(string $content): string + public function wrapContentImgTag(string $html, string $context, int $attachmentId): string { if (\is_admin() || \wp_doing_ajax() || (\defined('REST_REQUEST') && REST_REQUEST)) { - return $content; + return $html; } - if (!str_contains($content, 'uploadsInfo['baseurl'] ?? ''; - if (!$uploadsUrl) { - return $content; + if (!preg_match('/src=["\']([^"\']+)["\']/', $html, $srcMatch)) { + return $html; + } + $src = $srcMatch[1]; + if (!$this->isUploadsImage($src)) { + return $html; } - $pattern = sprintf( - '/]*?)src=["\'](%s[^"\']*\.(?:jpe?g|JPE?G))["\']([^>]*?)>/i', - preg_quote($uploadsUrl, '/') - ); - - $result = preg_replace_callback($pattern, function (array $matches): string { - $fullTag = $matches[0]; - $src = $matches[2]; - - $avifSrc = $this->avifUrlFor($src); - if (!$avifSrc) { - return $fullTag; - } + $avifSrc = $this->avifUrlFor($src); + if (!$avifSrc) { + return $html; + } - $avifSrcset = $avifSrc; - if (preg_match('/srcset=["\']([^"\']*)["\']/', $fullTag, $srcsetMatches)) { - $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); - if ($converted) { - $avifSrcset = $converted; - } + $avifSrcset = $avifSrc; + if (preg_match('/srcset=["\']([^"\']*)["\']/', $html, $srcsetMatches)) { + $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); + if ($converted) { + $avifSrcset = $converted; } + } - $sizes = ''; - if (preg_match('/sizes=["\']([^"\']*)["\']/', $fullTag, $sizesMatches)) { - $sizes = $sizesMatches[1]; - } + $sizes = ''; + if (preg_match('/sizes=["\']([^"\']*)["\']/', $html, $sizesMatches)) { + $sizes = $sizesMatches[1]; + } - return $this->pictureMarkup($fullTag, $avifSrc, $avifSrcset, $sizes); - }, $content); + return $this->pictureMarkup($html, $avifSrc, $avifSrcset, $sizes); + } - return $result !== null ? $result : $content; + public function wrapSingleImageHtml(string $html): string + { + if ($html === '' || str_contains($html, 'isUploadsImage($src)) { + return $html; + } + $avifSrc = $this->avifUrlFor($src); + if (!$avifSrc) { + return $html; + } + $avifSrcset = $avifSrc; + if (preg_match('/srcset=["\']([^"\']*)["\']/', $html, $srcsetMatches)) { + $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); + if ($converted) { + $avifSrcset = $converted; + } + } + $sizes = ''; + if (preg_match('/sizes=["\']([^"\']*)["\']/', $html, $sizesMatches)) { + $sizes = $sizesMatches[1]; + } + return $this->pictureMarkup($html, $avifSrc, $avifSrcset, $sizes); } private function avifUrlFor(string $jpegUrl): ?string { - if (!$this->isUploadsImage($jpegUrl) || !preg_match('/\.(jpe?g|JPE?G)$/', $jpegUrl)) { + if (!$this->isUploadsImage($jpegUrl)) { return null; } - $avifUrl = preg_replace('/\.(jpe?g|JPE?G)$/i', '.avif', $jpegUrl); - $relative = str_replace($this->uploadsInfo['baseurl'] ?? '', '', (string) $avifUrl); + + $queryString = ''; + $jpegUrlNoQuery = $jpegUrl; + $hashPos = strpos($jpegUrl, '#'); + $qPos = strpos($jpegUrl, '?'); + $cutPos = false; + if ($qPos !== false && $hashPos !== false) { + $cutPos = min($qPos, $hashPos); + } elseif ($qPos !== false) { + $cutPos = $qPos; + } elseif ($hashPos !== false) { + $cutPos = $hashPos; + } + if ($cutPos !== false) { + $queryString = substr($jpegUrl, (int) $cutPos); + $jpegUrlNoQuery = substr($jpegUrl, 0, (int) $cutPos); + } + + if (!preg_match('/\.(jpe?g|JPE?G)$/', $jpegUrlNoQuery)) { + return null; + } + + $avifNoQuery = preg_replace('/\.(jpe?g|JPE?G)$/i', '.avif', $jpegUrlNoQuery); + $relative = str_replace($this->uploadsInfo['baseurl'] ?? '', '', (string) $avifNoQuery); $avifLocal = ($this->uploadsInfo['basedir'] ?? '') . $relative; - return $this->avifExists($avifLocal) ? $avifUrl : null; + if (!$this->avifExists($avifLocal)) { + return null; + } + + return $avifNoQuery . $queryString; } private function isUploadsImage(string $src): bool