From c28612dec5dc34fd64ed11e72b07426bcdb20506 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 11 Aug 2025 16:43:06 +0000 Subject: [PATCH 1/2] Improve AVIF image conversion with better handling of query strings and picture tags Co-authored-by: dingoes-51.slots --- includes/class-support.php | 102 +++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/includes/class-support.php b/includes/class-support.php index bfc9829..c566c82 100644 --- a/includes/class-support.php +++ b/includes/class-support.php @@ -58,9 +58,6 @@ public function wrapContentImages(string $content): string if (!str_contains($content, 'uploadsInfo['baseurl'] ?? ''; if (!$uploadsUrl) { @@ -68,47 +65,98 @@ public function wrapContentImages(string $content): string } $pattern = sprintf( - '/]*?)src=["\'](%s[^"\']*\.(?:jpe?g|JPE?G))["\']([^>]*?)>/i', + '/]*?)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; - } + if (!preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) { + return $content; + } - $avifSrcset = $avifSrc; - if (preg_match('/srcset=["\']([^"\']*)["\']/', $fullTag, $srcsetMatches)) { - $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); - if ($converted) { - $avifSrcset = $converted; + $lastPos = 0; + $out = ''; + $total = count($matches[0]); + for ($i = 0; $i < $total; $i++) { + $fullTag = $matches[0][$i][0]; + $start = $matches[0][$i][1]; + $length = strlen($fullTag); + $src = $matches[2][$i][0]; + + // Determine if this is inside an existing + $insidePicture = false; + $before = substr($content, 0, $start); + $lastPictureStart = strripos($before, '', $lastPictureStart); + if ($closingPos === false || $closingPos > $start) { + $insidePicture = true; } } - $sizes = ''; - if (preg_match('/sizes=["\']([^"\']*)["\']/', $fullTag, $sizesMatches)) { - $sizes = $sizesMatches[1]; + $replacement = $fullTag; + if (!$insidePicture) { + $avifSrc = $this->avifUrlFor($src); + if ($avifSrc) { + $avifSrcset = $avifSrc; + if (preg_match('/srcset=["\']([^"\']*)["\']/', $fullTag, $srcsetMatches)) { + $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); + if ($converted) { + $avifSrcset = $converted; + } + } + + $sizes = ''; + if (preg_match('/sizes=["\']([^"\']*)["\']/', $fullTag, $sizesMatches)) { + $sizes = $sizesMatches[1]; + } + + $replacement = $this->pictureMarkup($fullTag, $avifSrc, $avifSrcset, $sizes); + } } - return $this->pictureMarkup($fullTag, $avifSrc, $avifSrcset, $sizes); - }, $content); + $out .= substr($content, $lastPos, $start - $lastPos) . $replacement; + $lastPos = $start + $length; + } + $out .= substr($content, $lastPos); - return $result !== null ? $result : $content; + return $out; } private function avifUrlFor(string $jpegUrl): ?string { - if (!$this->isUploadsImage($jpegUrl) || !preg_match('/\.(jpe?g|JPE?G)$/', $jpegUrl)) { + if (!$this->isUploadsImage($jpegUrl)) { + return null; + } + + $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; } - $avifUrl = preg_replace('/\.(jpe?g|JPE?G)$/i', '.avif', $jpegUrl); - $relative = str_replace($this->uploadsInfo['baseurl'] ?? '', '', (string) $avifUrl); + + $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 From 9cc1340baac628299b65d20b2b62320964874895 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 11 Aug 2025 19:37:37 +0000 Subject: [PATCH 2/2] Refactor image wrapping methods for better AVIF conversion handling Co-authored-by: dingoes-51.slots --- includes/class-support.php | 123 ++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/includes/class-support.php b/includes/class-support.php index c566c82..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,76 +50,75 @@ 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 ($html === '' || !str_contains($html, 'uploadsInfo['baseurl'] ?? ''; - if (!$uploadsUrl) { - return $content; - } - - $pattern = sprintf( - '/]*?)src=["\'](%s[^"\']*?\.(?:jpe?g|JPE?G)(?:\?[^"\']*)?)["\']([^>]*?)>/i', - preg_quote($uploadsUrl, '/') - ); - - if (!preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) { - return $content; - } - - $lastPos = 0; - $out = ''; - $total = count($matches[0]); - for ($i = 0; $i < $total; $i++) { - $fullTag = $matches[0][$i][0]; - $start = $matches[0][$i][1]; - $length = strlen($fullTag); - $src = $matches[2][$i][0]; - - // Determine if this is inside an existing - $insidePicture = false; - $before = substr($content, 0, $start); - $lastPictureStart = strripos($before, '', $lastPictureStart); - if ($closingPos === false || $closingPos > $start) { - $insidePicture = true; - } - } + if (!preg_match('/src=["\']([^"\']+)["\']/', $html, $srcMatch)) { + return $html; + } + $src = $srcMatch[1]; + if (!$this->isUploadsImage($src)) { + return $html; + } + + $avifSrc = $this->avifUrlFor($src); + if (!$avifSrc) { + return $html; + } - $replacement = $fullTag; - if (!$insidePicture) { - $avifSrc = $this->avifUrlFor($src); - if ($avifSrc) { - $avifSrcset = $avifSrc; - if (preg_match('/srcset=["\']([^"\']*)["\']/', $fullTag, $srcsetMatches)) { - $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); - if ($converted) { - $avifSrcset = $converted; - } - } - - $sizes = ''; - if (preg_match('/sizes=["\']([^"\']*)["\']/', $fullTag, $sizesMatches)) { - $sizes = $sizesMatches[1]; - } - - $replacement = $this->pictureMarkup($fullTag, $avifSrc, $avifSrcset, $sizes); - } + $avifSrcset = $avifSrc; + if (preg_match('/srcset=["\']([^"\']*)["\']/', $html, $srcsetMatches)) { + $converted = $this->convertSrcsetToAvif($srcsetMatches[1]); + if ($converted) { + $avifSrcset = $converted; } + } - $out .= substr($content, $lastPos, $start - $lastPos) . $replacement; - $lastPos = $start + $length; + $sizes = ''; + if (preg_match('/sizes=["\']([^"\']*)["\']/', $html, $sizesMatches)) { + $sizes = $sizesMatches[1]; } - $out .= substr($content, $lastPos); - return $out; + return $this->pictureMarkup($html, $avifSrc, $avifSrcset, $sizes); + } + + 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