From 46d9f9be4f634d94fc7742a043da7e69d2f6d023 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 10:14:03 +0100 Subject: [PATCH 01/33] chore: add server support checks - use global vars to detect for apache - check if mod rewrite is available - return object with server information --- src/class-tiny-server-capabilities.php | 110 +++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/class-tiny-server-capabilities.php diff --git a/src/class-tiny-server-capabilities.php b/src/class-tiny-server-capabilities.php new file mode 100644 index 00000000..6be8959e --- /dev/null +++ b/src/class-tiny-server-capabilities.php @@ -0,0 +1,110 @@ + self::get_server_type(), + 'is_apache' => self::is_apache(), + 'has_mod_rewrite' => self::has_mod_rewrite(), + 'uploads_writable' => self::uploads_htaccess_writable(), + 'htaccess_available' => self::is_apache() && self::has_mod_rewrite() && self::uploads_htaccess_writable(), + ); + } +} From d60d05ff143cd0ac87071d9d625d3bfea19e10d9 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 13:17:04 +0100 Subject: [PATCH 02/33] chore: import server capabilities in root plugin file --- tiny-compress-images.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 2efa12f6..e0d22d5c 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -18,6 +18,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-bulk-optimization.php'; require dirname( __FILE__ ) . '/src/class-tiny-image-size.php'; require dirname( __FILE__ ) . '/src/class-tiny-image.php'; +require dirname( __FILE__ ) . '/src/class-tiny-server-capabilities.php'; require dirname( __FILE__ ) . '/src/class-tiny-settings.php'; require dirname( __FILE__ ) . '/src/class-tiny-plugin.php'; require dirname( __FILE__ ) . '/src/class-tiny-notices.php'; From f8dc8e978c8ca660e936a1590fc10bf03e95f256 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 13:24:49 +0100 Subject: [PATCH 03/33] chore: refactor conversion settings into seperate views - not recommended to render html in a class - keep view rendering logic away from business logic --- src/class-tiny-settings.php | 115 ++++++++------------- src/views/settings-conversion-delivery.php | 37 +++++++ src/views/settings-conversion-enabled.php | 30 ++++++ src/views/settings-conversion-output.php | 52 ++++++++++ src/views/settings-conversion.php | 29 ++++++ src/views/settings.php | 34 +++--- 6 files changed, 207 insertions(+), 90 deletions(-) create mode 100644 src/views/settings-conversion-delivery.php create mode 100644 src/views/settings-conversion-enabled.php create mode 100644 src/views/settings-conversion-output.php create mode 100644 src/views/settings-conversion.php diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 19c33082..0957a3f7 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -416,6 +416,24 @@ private function get_convertto_mimetype() { return array( 'image/avif', 'image/webp' ); } + /** + * Retrieve the image delivery method. + * + * @return string The delivery method: 'picture' or 'htaccess'. Default is 'picture'. + */ + public function get_conversion_delivery_method() { + return self::get_convert_format_option( 'delivery_method', 'picture' ); + } + + /** + * Check if Apache with mod_rewrite is available. + * + * @return bool True if Apache with mod_rewrite is available, false otherwise + */ + public function is_apache_available() { + return Tiny_Server_Capabilities::is_apache() && Tiny_Server_Capabilities::has_mod_rewrite(); + } + private function setup_incomplete_checks() { if ( ! $this->get_api_key() ) { $this->notices->api_key_missing_notice(); @@ -980,89 +998,40 @@ public function compress_wr2x_images() { public function render_format_conversion() { - echo '
'; - - $convertopts_convert = self::get_prefixed_name( 'convert_format[convert]' ); - $convertopts_convert_id = self::get_prefixed_name( 'conversion_convert' ); - $convertopts_convert_checked = $this->get_conversion_enabled() ? - ' checked="checked"' : ''; - - echo '

'; - echo ''; - echo ''; - echo '

'; - - $convertopts_convert_to_name = self::get_prefixed_name( 'convert_format[convert_to]' ); - $convertopts_convert_subfields_classname = self::get_prefixed_name( 'convert_fields' ); - $convertopts_convert_to_id = self::get_prefixed_name( 'convert_convert_to' ); - $convertopts_convert_value = self::get_convert_format_option( 'convert_to', 'smallest' ); - $convertopts_convert_disabled = - self::get_conversion_enabled() ? '' : ' disabled="disabled"'; - echo sprintf( - '
', - $convertopts_convert_subfields_classname, - $convertopts_convert_to_id, - $convertopts_convert_disabled - ); - echo '

' . __( 'Conversion output', 'tiny-compress-images' ) . '

'; - self::render_convert_to_radiobutton( - $convertopts_convert_to_name, - sprintf( self::get_prefixed_name( 'convert_convert_to_%s' ), 'smallest' ), - 'smallest', - $convertopts_convert_value, - __( 'Convert to smallest file type (Recommended)', 'tiny-compress-images' ), - __( - 'We will calculate what is the best format for your image.', - 'tiny-compress-images' - ) - ); - self::render_convert_to_radiobutton( - $convertopts_convert_to_name, - sprintf( self::get_prefixed_name( 'convert_convert_to_%s' ), 'webp' ), - 'webp', - $convertopts_convert_value, - __( 'Convert to WebP', 'tiny-compress-images' ), - __( - 'WebP balances a small file size with good visual quality, - supporting transparency and animation.', - 'tiny-compress-images' - ) - ); - self::render_convert_to_radiobutton( - $convertopts_convert_to_name, - sprintf( self::get_prefixed_name( 'convert_convert_to_%s' ), 'avif' ), - 'avif', - $convertopts_convert_value, - __( 'Convert to AVIF', 'tiny-compress-images' ), - __( 'AVIF delivers even better compression and image quality than WebP. - Browser support is not as good as WebP.', 'tiny-compress-images' ) - ); - echo '
'; - echo '
'; + include( dirname( __FILE__ ) . '/views/settings-conversion.php' ); } - private static function render_convert_to_radiobutton( - $name, - $id, - $value, - $current, + private static function render_radiobutton( + $group_name, + $option_id, + $option_value, + $current_value, $label, $descr ) { - $checked = ($current === $value ? ' checked="checked"' : ''); + $checked = ($current_value === $option_value ? ' checked="checked"' : ''); echo '

'; - echo ''; - echo '

'; } + /** + * Render the delivery method settings view. + * Only displays if Apache with mod_rewrite is available. + */ + public function render_delivery_method() { + // Only show this section if Apache is available + if ( ! $this->is_apache_available() ) { + return; + } + + include( dirname( __FILE__ ) . '/views/delivery-method.php' ); + } + private static function get_convert_format_option( $option, $default_value ) { $setting = get_option( self::get_prefixed_name( 'convert_format' ) ); if ( isset( $setting[ $option ] ) && $setting[ $option ] ) { diff --git a/src/views/settings-conversion-delivery.php b/src/views/settings-conversion-delivery.php new file mode 100644 index 00000000..86b2c0ab --- /dev/null +++ b/src/views/settings-conversion-delivery.php @@ -0,0 +1,37 @@ + + +

+ + tags with multiple elements.' +); ?> + diff --git a/src/views/settings-conversion-enabled.php b/src/views/settings-conversion-enabled.php new file mode 100644 index 00000000..dae6f61e --- /dev/null +++ b/src/views/settings-conversion-enabled.php @@ -0,0 +1,30 @@ +get_conversion_enabled() ? + ' checked="checked"' : ''; +?> + +
+

+ /> + +

+
diff --git a/src/views/settings-conversion-output.php b/src/views/settings-conversion-output.php new file mode 100644 index 00000000..cd321eeb --- /dev/null +++ b/src/views/settings-conversion-output.php @@ -0,0 +1,52 @@ + +

+ + + + + + diff --git a/src/views/settings-conversion.php b/src/views/settings-conversion.php new file mode 100644 index 00000000..f26e4ef4 --- /dev/null +++ b/src/views/settings-conversion.php @@ -0,0 +1,29 @@ + + +
+ + +
> + +
+
diff --git a/src/views/settings.php b/src/views/settings.php index 07946ac1..41438cca 100644 --- a/src/views/settings.php +++ b/src/views/settings.php @@ -36,23 +36,23 @@ - - - -

-

- -

- render_format_conversion(); ?> - - - - + + + +

+

+ +

+ render_format_conversion(); ?> + + + + render_resize() ?> From ce741e25d08a154263c8a8a13524c6fb8e447d8a Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 13:27:12 +0100 Subject: [PATCH 04/33] fix: echo enabled check --- src/views/settings-conversion-enabled.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/settings-conversion-enabled.php b/src/views/settings-conversion-enabled.php index dae6f61e..82197f8e 100644 --- a/src/views/settings-conversion-enabled.php +++ b/src/views/settings-conversion-enabled.php @@ -22,7 +22,7 @@ id="" name="" value="on" - /> + /> From 31c82e2fa6fd45a9b30975b813c26a94217407ea Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 13:27:26 +0100 Subject: [PATCH 05/33] fix: use correct value from convert_format options --- src/views/settings-conversion-delivery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/settings-conversion-delivery.php b/src/views/settings-conversion-delivery.php index 86b2c0ab..1725281f 100644 --- a/src/views/settings-conversion-delivery.php +++ b/src/views/settings-conversion-delivery.php @@ -9,7 +9,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } -$tinify_delivery_name = self::get_prefixed_name( 'convert_delivery' ); +$tinify_delivery_name = self::get_prefixed_name( 'convert_format[delivery_method]' ); $tinify_delivery_option_picture = self::get_prefixed_name( 'convert_delivery_picture' ); $tinify_delivery_option_htaccess = self::get_prefixed_name( 'convert_delivery_htaccess' ); From f6eaf254fd9711eedf470e59dd94c723e7314f22 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 22 Dec 2025 13:28:23 +0100 Subject: [PATCH 06/33] chore: format phpcs --- src/class-tiny-server-capabilities.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/class-tiny-server-capabilities.php b/src/class-tiny-server-capabilities.php index 6be8959e..c370b7bc 100644 --- a/src/class-tiny-server-capabilities.php +++ b/src/class-tiny-server-capabilities.php @@ -96,7 +96,8 @@ public static function uploads_htaccess_writable() { /** * Get a detailed capabilities object. * - * @return array Array with properties: server, is_apache, has_mod_rewrite, uploads_writable, htaccess_available + * @return array Array with properties: server, is_apache, has_mod_rewrite, + * uploads_writable, htaccess_available */ public static function get_capabilities() { return array( @@ -104,7 +105,9 @@ public static function get_capabilities() { 'is_apache' => self::is_apache(), 'has_mod_rewrite' => self::has_mod_rewrite(), 'uploads_writable' => self::uploads_htaccess_writable(), - 'htaccess_available' => self::is_apache() && self::has_mod_rewrite() && self::uploads_htaccess_writable(), + 'htaccess_available' => self::is_apache() && + self::has_mod_rewrite() && + self::uploads_htaccess_writable(), ); } } From 2413f118caea3377e6fbafde4070dbdea1312b1b Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 1 Jan 2026 18:10:58 +0100 Subject: [PATCH 07/33] chore: add apache rewriter for webp and avif --- src/class-tiny-apache-rewrite.php | 162 ++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/class-tiny-apache-rewrite.php diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php new file mode 100644 index 00000000..632fc1d6 --- /dev/null +++ b/src/class-tiny-apache-rewrite.php @@ -0,0 +1,162 @@ +', + 'RewriteEngine On', + 'RewriteOptions Inherit', + ); + + $rules = array_merge($rules, self::get_avif_rules()); + $rules = array_merge($rules, self::get_webp_rules()); + + $rules[] = ''; + + $rules[] = ''; + $rules[] = 'Header append Vary Accept'; + $rules[] = ''; + $rules[] = 'Header set Cache-Control "max-age=31536000, public"'; + $rules[] = ''; + $rules[] = ''; + + $rules[] = ''; + $rules[] = 'AddType image/webp .webp'; + $rules[] = 'AddType image/avif .avif'; + $rules[] = ''; + + return implode("\n", $rules); + } + + /** + * Generate AVIF rewrite rules. + * + * @return array[] AVIF rewrite rules + */ + private static function get_avif_rules() + { + $rules = array(); + + // AVIF rule 1: Try file with original extension appended (image.jpg.avif) + $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; + $rules[] = 'RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.avif -f'; + $rules[] = 'RewriteRule ^(.+)$ $1.avif [T=image/avif,L]'; + + // AVIF rule 2: Try file with extension replaced (image.avif) + $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; + $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\\.(?:jpe?g|png|gif)$'; + $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.avif -f'; + $rules[] = 'RewriteRule (.+)\\.(?:jpe?g|png|gif)$ $1.avif [T=image/avif,L]'; + + return $rules; + } + + /** + * Generate WebP rewrite rules. + * + * @return array[] WebP rewrite rules + */ + private static function get_webp_rules() + { + $rules = array(); + + // WebP rule 1: Try file with original extension appended (image.jpg.webp) + // Check for Chrome browser or explicit Accept header + $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp [OR]'; + $rules[] = 'RewriteCond %{HTTP_USER_AGENT} Chrome'; + $rules[] = 'RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.webp -f'; + $rules[] = 'RewriteRule ^(.+)$ $1.webp [T=image/webp,L]'; + + // WebP rule 2: Try file with extension replaced (image.webp) + $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp [OR]'; + $rules[] = 'RewriteCond %{HTTP_USER_AGENT} Chrome'; + $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\\.(?:jpe?g|png|gif)$'; + $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.webp -f'; + $rules[] = 'RewriteRule (.+)\\.(?:jpe?g|png|gif)$ $1.webp [T=image/webp,L]'; + + return $rules; + } + + /** + * Install rewrite rules to .htaccess files. + * + * @return bool True on success, false otherwise + */ + public static function install() + { + if (! function_exists('insert_with_markers')) { + require_once ABSPATH . 'wp-admin/includes/misc.php'; + } + + $rules = self::get_rewrite_rules(); + + // Write to uploads directory + $upload_dir = wp_upload_dir(); + if (isset($upload_dir['basedir']) && is_writable($upload_dir['basedir'])) { + $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; + insert_with_markers($htaccess_file, self::MARKER, $rules); + } + + // Write to root directory + if (is_writable(get_home_path())) { + $htaccess_file = get_home_path() . '.htaccess'; + insert_with_markers($htaccess_file, self::MARKER, $rules); + } + + return true; + } + + /** + * Remove rewrite rules from .htaccess files. + * + * @return bool True on success, false otherwise + */ + public static function uninstall() + { + if (! function_exists('insert_with_markers')) { + require_once ABSPATH . 'wp-admin/includes/misc.php'; + } + + // Remove from uploads directory + $upload_dir = wp_upload_dir(); + if (isset($upload_dir['basedir']) && file_exists($upload_dir['basedir'] . '/.htaccess')) { + $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; + insert_with_markers($htaccess_file, self::MARKER, ''); + } + + // Remove from root directory + if (file_exists(get_home_path() . '.htaccess')) { + $htaccess_file = get_home_path() . '.htaccess'; + insert_with_markers($htaccess_file, self::MARKER, ''); + } + + return true; + } +} From 34905ceebcbafddf31441831c308f0f2334036b5 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Jan 2026 09:27:46 +0100 Subject: [PATCH 08/33] refactor: simplify Apache rewrite rules and rename methods Remove redundant rewrite rules that append file extensions (image.jpg.avif). Keep only the extension replacement rules (image.avif). - Rename install() to install_rules() and uninstall() to uninstall_rules() - Remove duplicate AVIF and WebP rules that check for appended extensions - Update MARKER constant to match plugin name - Remove redundant comments and empty lines --- src/class-tiny-apache-rewrite.php | 36 +++---------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 632fc1d6..e6a2108a 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -20,7 +20,7 @@ class Tiny_Apache_Rewrite extends Tiny_WP_Base { - const MARKER = 'tinify_modern_images'; + const MARKER = 'tiny-compress-images'; /** * Generate .htaccess rewrite rules for serving WebP and AVIF images. @@ -63,18 +63,10 @@ public static function get_rewrite_rules() private static function get_avif_rules() { $rules = array(); - - // AVIF rule 1: Try file with original extension appended (image.jpg.avif) - $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; - $rules[] = 'RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.avif -f'; - $rules[] = 'RewriteRule ^(.+)$ $1.avif [T=image/avif,L]'; - - // AVIF rule 2: Try file with extension replaced (image.avif) $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.avif -f'; $rules[] = 'RewriteRule (.+)\\.(?:jpe?g|png|gif)$ $1.avif [T=image/avif,L]'; - return $rules; } @@ -86,21 +78,11 @@ private static function get_avif_rules() private static function get_webp_rules() { $rules = array(); - - // WebP rule 1: Try file with original extension appended (image.jpg.webp) - // Check for Chrome browser or explicit Accept header - $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp [OR]'; - $rules[] = 'RewriteCond %{HTTP_USER_AGENT} Chrome'; - $rules[] = 'RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.webp -f'; - $rules[] = 'RewriteRule ^(.+)$ $1.webp [T=image/webp,L]'; - - // WebP rule 2: Try file with extension replaced (image.webp) $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp [OR]'; $rules[] = 'RewriteCond %{HTTP_USER_AGENT} Chrome'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.webp -f'; $rules[] = 'RewriteRule (.+)\\.(?:jpe?g|png|gif)$ $1.webp [T=image/webp,L]'; - return $rules; } @@ -109,22 +91,16 @@ private static function get_webp_rules() * * @return bool True on success, false otherwise */ - public static function install() + public static function install_rules() { - if (! function_exists('insert_with_markers')) { - require_once ABSPATH . 'wp-admin/includes/misc.php'; - } - $rules = self::get_rewrite_rules(); - // Write to uploads directory $upload_dir = wp_upload_dir(); if (isset($upload_dir['basedir']) && is_writable($upload_dir['basedir'])) { $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; insert_with_markers($htaccess_file, self::MARKER, $rules); } - // Write to root directory if (is_writable(get_home_path())) { $htaccess_file = get_home_path() . '.htaccess'; insert_with_markers($htaccess_file, self::MARKER, $rules); @@ -138,20 +114,14 @@ public static function install() * * @return bool True on success, false otherwise */ - public static function uninstall() + public static function uninstall_rules() { - if (! function_exists('insert_with_markers')) { - require_once ABSPATH . 'wp-admin/includes/misc.php'; - } - - // Remove from uploads directory $upload_dir = wp_upload_dir(); if (isset($upload_dir['basedir']) && file_exists($upload_dir['basedir'] . '/.htaccess')) { $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; insert_with_markers($htaccess_file, self::MARKER, ''); } - // Remove from root directory if (file_exists(get_home_path() . '.htaccess')) { $htaccess_file = get_home_path() . '.htaccess'; insert_with_markers($htaccess_file, self::MARKER, ''); From 3752cefa9ed4975c932e9be026066f57bbb4550b Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Jan 2026 09:33:18 +0100 Subject: [PATCH 09/33] test: add delivery method option to conversion settings utility Add delivery parameter to setConversionSettings helper to configure picture tag or htaccess delivery methods in integration tests. --- test/integration/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/integration/utils.ts b/test/integration/utils.ts index 5bcfbc7c..f89c5786 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -202,7 +202,7 @@ export async function deactivatePlugin(page: Page, pluginSlug: string) { await plugin.getByLabel('Deactivate').click(); } -export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif' }) { +export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif' , delivery: 'picture' | 'htaccess' }) { await page.goto('/wp-admin/options-general.php?page=tinify'); if (settings.convert) { @@ -223,6 +223,12 @@ export async function setConversionSettings(page: Page, settings: { convert: boo await page.locator('#tinypng_conversion_convert').uncheck(); } + if (settings.delivery === 'htaccess') { + await page.getByTestId('tinypng_convert_delivery_picture').check(); + } else { + await page.getByTestId('tinypng_convert_delivery_htaccess').check(); + } + await page.locator('#submit').click(); } From 4061361485377e4d061437825f94f39623c044ce Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Jan 2026 09:35:53 +0100 Subject: [PATCH 10/33] test: add data-testid attribute to radio button inputs Add data-testid attribute to radio input elements to improve test selector reliability in integration tests. --- src/class-tiny-settings.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 0957a3f7..f1172d84 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -1011,7 +1011,8 @@ private static function render_radiobutton( ) { $checked = ($current_value === $option_value ? ' checked="checked"' : ''); echo '

'; - echo ''; echo '

`, + }, + WPVersion + ); + const imageResponsePromise = page.waitForResponse(response => + // img is still jpg, but expect content type to be avif + response.url().includes('input-example.jpg') && response.status() === 200 + ); + + await page.goto(`/?p=${postID}`); + + const imgResponse = await imageResponsePromise; + const contentType = await imgResponse.headerValue('content-type'); + expect(contentType).toBe('image/avif'); + }); }); diff --git a/tiny-compress-images.php b/tiny-compress-images.php index e0d22d5c..2d15adf9 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -24,6 +24,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-notices.php'; require dirname( __FILE__ ) . '/src/class-tiny-cli.php'; require dirname( __FILE__ ) . '/src/class-tiny-picture.php'; +require dirname( __FILE__ ) . '/src/class-tiny-apache-rewrite.php'; require dirname( __FILE__ ) . '/src/compatibility/wpml/class-tiny-wpml.php'; require dirname( __FILE__ ) . '/src/compatibility/as3cf/class-tiny-as3cf.php'; From 4680f5c69666368ec68e8fd7dfdc992ff7ce9768 Mon Sep 17 00:00:00 2001 From: Sertii <36940685+Sreini@users.noreply.github.com> Date: Mon, 16 Feb 2026 07:34:38 +0100 Subject: [PATCH 12/33] release: 3.6.10 --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 565e7c67..aa6e9ea1 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://tinypng.com/ Tags: compress images, compression, image size, page speed, performance Requires at least: 4.0 Tested up to: 6.9 -Stable tag: 3.6.9 +Stable tag: 3.6.10 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From e195502a938ddbc2941ae91ed1a8dddc2b0e47df Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 16 Feb 2026 09:11:54 +0100 Subject: [PATCH 13/33] Format --- src/class-tiny-apache-rewrite.php | 64 ++++++++++------------ src/class-tiny-plugin.php | 2 +- src/class-tiny-server-capabilities.php | 8 +-- src/class-tiny-settings.php | 4 +- src/views/settings-conversion-delivery.php | 8 ++- src/views/settings-conversion-enabled.php | 4 +- src/views/settings-conversion-output.php | 5 +- src/views/settings-conversion.php | 10 ++-- src/views/settings.php | 6 +- 9 files changed, 54 insertions(+), 57 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 5b80cc92..d579389e 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -17,49 +17,48 @@ * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n*/ -class Tiny_Apache_Rewrite -{ +class Tiny_Apache_Rewrite { + const MARKER = 'tiny-compress-images'; /** * Initialize Apache Rewrite for converted images. * - install rules * - adds hook to add or remove the rules - * + * * @return void */ public static function init() { - add_action('update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3); + add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); } /** * Installs or uninstalls the htaccess rules * hooked into `update_option_tinypng_convert_format` * https://developer.wordpress.org/reference/hooks/update_option_option/ - * + * * * @param mixed $old_value * @param mixed $value * @param string $option * @return void */ - public static function toggle_rules( $old_value, $value, $option) { - $old_delivery = isset($old_value['delivery_method']) ? $old_value['delivery_method'] : null; - $new_delivery = isset($value['delivery_method']) ? $value['delivery_method'] : null; + public static function toggle_rules( $old_value, $value, $option ) { + $old_delivery = isset( $old_value['delivery_method'] ) ? $old_value['delivery_method'] : null; + $new_delivery = isset( $value['delivery_method'] ) ? $value['delivery_method'] : null; if ( $old_delivery === $new_delivery ) { return; } - if ($old_delivery === 'htaccess' && ($new_delivery === 'picture' || $new_delivery === null)) { + if ( $old_delivery === 'htaccess' && ( $new_delivery === 'picture' || $new_delivery === null ) ) { self::uninstall_rules(); return; } - if (($old_delivery === 'picture' || $old_delivery === null) && $new_delivery === 'htaccess' ) { + if ( ( $old_delivery === 'picture' || $old_delivery === null ) && $new_delivery === 'htaccess' ) { self::install_rules(); return; } - } /** @@ -67,16 +66,15 @@ public static function toggle_rules( $old_value, $value, $option) { * * @return string The .htaccess rules */ - private static function get_rewrite_rules() - { + private static function get_rewrite_rules() { $rules = array( '', 'RewriteEngine On', 'RewriteOptions Inherit', ); - $rules = array_merge($rules, self::get_avif_rules()); - $rules = array_merge($rules, self::get_webp_rules()); + $rules = array_merge( $rules, self::get_avif_rules() ); + $rules = array_merge( $rules, self::get_webp_rules() ); $rules[] = ''; @@ -92,7 +90,7 @@ private static function get_rewrite_rules() $rules[] = 'AddType image/avif .avif'; $rules[] = ''; - return implode("\n", $rules); + return implode( "\n", $rules ); } /** @@ -100,9 +98,8 @@ private static function get_rewrite_rules() * * @return array[] AVIF rewrite rules */ - private static function get_avif_rules() - { - $rules = array(); + private static function get_avif_rules() { + $rules = array(); $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.avif -f'; @@ -115,14 +112,13 @@ private static function get_avif_rules() * * @return array[] WebP rewrite rules */ - private static function get_webp_rules() - { - $rules = array(); + private static function get_webp_rules() { + $rules = array(); $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.webp -f'; $rules[] = 'RewriteRule (.+)\.(?:jpe?g|png|gif)$ $1.webp [T=image/webp,L]'; - + return $rules; } @@ -131,19 +127,18 @@ private static function get_webp_rules() * * @return bool True on success, false otherwise */ - private static function install_rules() - { + private static function install_rules() { $rules = self::get_rewrite_rules(); $upload_dir = wp_upload_dir(); - if (isset($upload_dir['basedir']) && is_writable($upload_dir['basedir'])) { + if ( isset( $upload_dir['basedir'] ) && is_writable( $upload_dir['basedir'] ) ) { $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; - insert_with_markers($htaccess_file, self::MARKER, $rules); + insert_with_markers( $htaccess_file, self::MARKER, $rules ); } - if (is_writable(get_home_path())) { + if ( is_writable( get_home_path() ) ) { $htaccess_file = get_home_path() . '.htaccess'; - insert_with_markers($htaccess_file, self::MARKER, $rules); + insert_with_markers( $htaccess_file, self::MARKER, $rules ); } return true; @@ -154,17 +149,16 @@ private static function install_rules() * * @return bool True on success, false otherwise */ - public static function uninstall_rules() - { + public static function uninstall_rules() { $upload_dir = wp_upload_dir(); - if (isset($upload_dir['basedir']) && file_exists($upload_dir['basedir'] . '/.htaccess')) { + if ( isset( $upload_dir['basedir'] ) && file_exists( $upload_dir['basedir'] . '/.htaccess' ) ) { $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; - insert_with_markers($htaccess_file, self::MARKER, ''); + insert_with_markers( $htaccess_file, self::MARKER, '' ); } - if (file_exists(get_home_path() . '.htaccess')) { + if ( file_exists( get_home_path() . '.htaccess' ) ) { $htaccess_file = get_home_path() . '.htaccess'; - insert_with_markers($htaccess_file, self::MARKER, ''); + insert_with_markers( $htaccess_file, self::MARKER, '' ); } return true; diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 2a0697fe..f5f334d7 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -82,7 +82,7 @@ public function init() { * * @since 3.7.0 */ - if ($delivery_method === 'picture' && apply_filters( 'tiny_replace_with_picture', true ) ) { + if ( $delivery_method === 'picture' && apply_filters( 'tiny_replace_with_picture', true ) ) { new Tiny_Picture( ABSPATH, array( get_site_url() ) ); } } diff --git a/src/class-tiny-server-capabilities.php b/src/class-tiny-server-capabilities.php index c370b7bc..85d9b254 100644 --- a/src/class-tiny-server-capabilities.php +++ b/src/class-tiny-server-capabilities.php @@ -101,10 +101,10 @@ public static function uploads_htaccess_writable() { */ public static function get_capabilities() { return array( - 'server' => self::get_server_type(), - 'is_apache' => self::is_apache(), - 'has_mod_rewrite' => self::has_mod_rewrite(), - 'uploads_writable' => self::uploads_htaccess_writable(), + 'server' => self::get_server_type(), + 'is_apache' => self::is_apache(), + 'has_mod_rewrite' => self::has_mod_rewrite(), + 'uploads_writable' => self::uploads_htaccess_writable(), 'htaccess_available' => self::is_apache() && self::has_mod_rewrite() && self::uploads_htaccess_writable(), diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 4976cd3e..92b8e671 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -1031,7 +1031,7 @@ public function compress_wr2x_images() { public function render_format_conversion() { - include( dirname( __FILE__ ) . '/views/settings-conversion.php' ); + include __DIR__ . '/views/settings-conversion.php'; } /** @@ -1044,7 +1044,7 @@ public function render_delivery_method() { return; } - include( dirname( __FILE__ ) . '/views/delivery-method.php' ); + include __DIR__ . '/views/delivery-method.php'; } private static function get_convert_format_option( $option, $default_value ) { diff --git a/src/views/settings-conversion-delivery.php b/src/views/settings-conversion-delivery.php index 1725281f..969b07f9 100644 --- a/src/views/settings-conversion-delivery.php +++ b/src/views/settings-conversion-delivery.php @@ -11,7 +11,7 @@ } $tinify_delivery_name = self::get_prefixed_name( 'convert_format[delivery_method]' ); -$tinify_delivery_option_picture = self::get_prefixed_name( 'convert_delivery_picture' ); +$tinify_delivery_option_picture = self::get_prefixed_name( 'convert_delivery_picture' ); $tinify_delivery_option_htaccess = self::get_prefixed_name( 'convert_delivery_htaccess' ); $tinify_delivery_value = self::get_conversion_delivery_method(); @@ -19,14 +19,16 @@

- tags with multiple elements.' -); ?> +); +?> get_conversion_enabled() ? ' checked="checked"' : ''; ?> diff --git a/src/views/settings-conversion-output.php b/src/views/settings-conversion-output.php index cd321eeb..95bbf125 100644 --- a/src/views/settings-conversion-output.php +++ b/src/views/settings-conversion-output.php @@ -10,11 +10,12 @@ exit; // Exit if accessed directly. } $convertopts_convert_to_name = self::get_prefixed_name( 'convert_format[convert_to]' ); -$convertopts_convert_value = self::get_convert_format_option( 'convert_to', 'smallest' ); +$convertopts_convert_value = self::get_convert_format_option( 'convert_to', 'smallest' ); ?>

-
- +
>
diff --git a/src/views/settings.php b/src/views/settings.php index 861a75eb..1f70b2a6 100644 --- a/src/views/settings.php +++ b/src/views/settings.php @@ -37,9 +37,9 @@ - + -

+

- + render_resize(); ?> From 864f3a3f4c25d469a041d79db5ab0f521c9ad3ea Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 16 Feb 2026 09:29:02 +0100 Subject: [PATCH 14/33] chore: readd radio button --- src/class-tiny-settings.php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 92b8e671..a00ab69c 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -1031,7 +1031,26 @@ public function compress_wr2x_images() { public function render_format_conversion() { - include __DIR__ . '/views/settings-conversion.php'; + include( dirname( __FILE__ ) . '/views/settings-conversion.php' ); + } + + private static function render_radiobutton( + $group_name, + $option_id, + $option_value, + $current_value, + $label, + $descr + ) { + $checked = ($current_value === $option_value ? ' checked="checked"' : ''); + echo '

'; + echo ''; + echo ''; + echo '

'; } /** @@ -1044,7 +1063,7 @@ public function render_delivery_method() { return; } - include __DIR__ . '/views/delivery-method.php'; + include( dirname( __FILE__ ) . '/views/delivery-method.php' ); } private static function get_convert_format_option( $option, $default_value ) { From c83f338b1e95f7fcb7d13ddf5a83f2967a8b9189 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 16 Feb 2026 10:22:46 +0100 Subject: [PATCH 15/33] add conversio class to initialize picture or apache --- src/class-tiny-apache-rewrite.php | 4 +- src/class-tiny-conversion.php | 71 ++++++++++++++++++++++++++ src/class-tiny-plugin.php | 15 +----- src/class-tiny-server-capabilities.php | 5 +- tiny-compress-images.php | 3 +- 5 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 src/class-tiny-conversion.php diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index d579389e..697d55b0 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -17,7 +17,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n*/ -class Tiny_Apache_Rewrite { +class Tiny_Apache_Rewrite extends Tiny_WP_Base { const MARKER = 'tiny-compress-images'; @@ -28,7 +28,7 @@ class Tiny_Apache_Rewrite { * * @return void */ - public static function init() { + public function init() { add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); } diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php new file mode 100644 index 00000000..004f69de --- /dev/null +++ b/src/class-tiny-conversion.php @@ -0,0 +1,71 @@ +$settings = $settings; + } + + /** + * Invoked in init hook from Tiny_WP_Base + */ + public function init() + { + if ($this->settings->get_conversion_enabled()) { + return; + } + + $this->enable_conversion(); + } + + /** + * Will check wether conversion needs to be enabled + * and which form of delivery should be applied. + * + * @return void + */ + function enable_conversion() + { + $delivery_method = $this->settings->get_conversion_delivery_method(); + + /** + * Controls wether the page should replace with elements + * converted sources. + * + * @since 3.7.0 + */ + if ($delivery_method === 'picture' && apply_filters('tiny_replace_with_picture', true)) { + new Tiny_Picture(ABSPATH, array(get_site_url())); + } else { + new Tiny_Apache_Rewrite(); + } + } +} diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index f5f334d7..79550eae 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -40,6 +40,7 @@ public static function version() { public function __construct() { parent::__construct(); $this->settings = new Tiny_Settings(); + new Tiny_Conversion($this->settings); } public function set_compressor( $compressor ) { @@ -72,20 +73,6 @@ public function init() { dirname( plugin_basename( __FILE__ ) ) . '/languages' ); - /** isolate conversion and move this to a seperate class */ - Tiny_Apache_Rewrite::init(); - if ( $this->settings->get_conversion_enabled() ) { - $delivery_method = $this->settings->get_conversion_delivery_method(); - /** - * Controls wether the page should replace with elements - * converted sources. - * - * @since 3.7.0 - */ - if ( $delivery_method === 'picture' && apply_filters( 'tiny_replace_with_picture', true ) ) { - new Tiny_Picture( ABSPATH, array( get_site_url() ) ); - } - } $this->tiny_compatibility(); } diff --git a/src/class-tiny-server-capabilities.php b/src/class-tiny-server-capabilities.php index 85d9b254..4f0438eb 100644 --- a/src/class-tiny-server-capabilities.php +++ b/src/class-tiny-server-capabilities.php @@ -18,7 +18,10 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -class Tiny_Server_Capabilities extends Tiny_WP_Base { +/** + * class responsible for checking and managing server capabilities + */ +class Tiny_Server_Capabilities { /** * Detect the web server software using WordPress globals. diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 936d4435..5670af40 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -2,7 +2,7 @@ /** * Plugin Name: TinyPNG - JPEG, PNG & WebP image compression * Description: Speed up your website. Optimize your JPEG, PNG, and WebP images automatically with TinyPNG. - * Version: 3.6.9 + * Version: 3.6.10 * Author: TinyPNG * Author URI: https://tinypng.com * Text Domain: tiny-compress-images @@ -25,6 +25,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-plugin.php'; require dirname( __FILE__ ) . '/src/class-tiny-notices.php'; require dirname( __FILE__ ) . '/src/class-tiny-cli.php'; +require dirname( __FILE__ ) . '/src/class-tiny-conversion.php'; require dirname( __FILE__ ) . '/src/class-tiny-picture.php'; require dirname( __FILE__ ) . '/src/class-tiny-apache-rewrite.php'; require dirname( __FILE__ ) . '/src/compatibility/wpml/class-tiny-wpml.php'; From 76f4232d7fc8564f933aacfb262e830c2a6e03bc Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 17 Feb 2026 16:22:19 +0100 Subject: [PATCH 16/33] test and docs --- src/class-tiny-apache-rewrite.php | 17 ++++- src/class-tiny-conversion.php | 93 +++++++++++++------------- test/unit/Tiny_Apache_Rewrite_Test.php | 39 +++++++++++ 3 files changed, 101 insertions(+), 48 deletions(-) create mode 100644 test/unit/Tiny_Apache_Rewrite_Test.php diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 697d55b0..d4d5d85e 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -17,18 +17,31 @@ * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n*/ +/** + * Tiny_Apache_Rewrite + * class responsible for the apache rules for image delivery. + * - toggling the rules when saving settings + * - inserting/removing rules from htaccess + * + * We are only updating rules when: + * - updating the option convert_format + * - (un)installing the plug-in + */ class Tiny_Apache_Rewrite extends Tiny_WP_Base { + /** + * seperator when rules are inserted + * @var string + */ const MARKER = 'tiny-compress-images'; /** * Initialize Apache Rewrite for converted images. * - install rules * - adds hook to add or remove the rules - * * @return void */ - public function init() { + function __construct() { add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); } diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php index 004f69de..e421a76e 100644 --- a/src/class-tiny-conversion.php +++ b/src/class-tiny-conversion.php @@ -18,54 +18,55 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -class Tiny_Conversion extends Tiny_WP_Base -{ - /** - * @var Tiny_Settings - */ - private $settings; +class Tiny_Conversion extends Tiny_WP_Base { - /** - * @param $settings Tiny_Settings - */ - public function __construct($settings) - { - return parent::__construct(); - $this->$settings = $settings; - } + /** + * @var Tiny_Settings plug-in settings + */ + private $settings; - /** - * Invoked in init hook from Tiny_WP_Base - */ - public function init() - { - if ($this->settings->get_conversion_enabled()) { - return; - } + /** + * @param Tiny_Settings $settings + */ + public function __construct( $settings ) { + parent::__construct(); + $this->settings = $settings; + } - $this->enable_conversion(); - } + /** + * Invoked in init hook from Tiny_WP_Base + */ + public function init() { + if ( ! $this->settings->get_conversion_enabled() ) { + return; + } - /** - * Will check wether conversion needs to be enabled - * and which form of delivery should be applied. - * - * @return void - */ - function enable_conversion() - { - $delivery_method = $this->settings->get_conversion_delivery_method(); - - /** - * Controls wether the page should replace with elements - * converted sources. - * - * @since 3.7.0 - */ - if ($delivery_method === 'picture' && apply_filters('tiny_replace_with_picture', true)) { - new Tiny_Picture(ABSPATH, array(get_site_url())); - } else { - new Tiny_Apache_Rewrite(); - } - } + $delivery_method = $this->settings->get_conversion_delivery_method(); + + $this->init_image_delivery( $delivery_method ); + } + + /** + * Initializes the method of delivery for optimised images + * + * @param string $delivery_method 'picture' or 'htaccess' + * @return void + */ + private function init_image_delivery( $delivery_method ) { + /** + * Controls wether the page should replace with elements + * converted sources. + * + * @since 3.7.0 + */ + if ( $delivery_method === 'htaccess' && Tiny_Server_Capabilities::is_apache() ) { + new Tiny_Apache_Rewrite(); + return; + } + + if ( apply_filters( 'tiny_replace_with_picture', $delivery_method === 'picture' ) ) { + new Tiny_Picture( ABSPATH, array( get_site_url() ) ); + return; + } + } } diff --git a/test/unit/Tiny_Apache_Rewrite_Test.php b/test/unit/Tiny_Apache_Rewrite_Test.php new file mode 100644 index 00000000..b52e65d2 --- /dev/null +++ b/test/unit/Tiny_Apache_Rewrite_Test.php @@ -0,0 +1,39 @@ +shouldReceive('is_apache')->andReturn(true); + + $mock_settings = $this->createMock(Tiny_Settings::class); + $mock_settings->method('get_conversion_enabled')->willReturn(true); + $mock_settings->method('get_conversion_delivery_method')->willReturn('htaccess'); + + new Tiny_Conversion($mock_settings); + + $this->wp->init(); + + WordPressStubs::assertHook('update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules'); + } + + /** + * assert that when the plugin is uninstalled, the htaccess rules are removed + */ + function test_plugin_uninstalled_removed_rules() { + + } + + /** + * assert that when the plugin is installed, convert is enabled and delivery is apache, then + * htaccess rules will be installed. + */ + function test_plugin_install_add_rules() {} +} From 913b4f3983b720bb7ec800920fd4c6a39afb36bb Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 09:01:17 +0100 Subject: [PATCH 17/33] Uninstal rules on uninstall --- uninstall.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 uninstall.php diff --git a/uninstall.php b/uninstall.php new file mode 100644 index 00000000..79745b95 --- /dev/null +++ b/uninstall.php @@ -0,0 +1,14 @@ + Date: Wed, 18 Feb 2026 09:01:29 +0100 Subject: [PATCH 18/33] format --- src/class-tiny-plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 79550eae..2236332d 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -40,7 +40,7 @@ public static function version() { public function __construct() { parent::__construct(); $this->settings = new Tiny_Settings(); - new Tiny_Conversion($this->settings); + new Tiny_Conversion( $this->settings ); } public function set_compressor( $compressor ) { From 8f9c83994797cb60d737344a099485c007f672e8 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 09:01:43 +0100 Subject: [PATCH 19/33] format --- src/class-tiny-settings.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index a00ab69c..7be76aa9 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -1031,7 +1031,7 @@ public function compress_wr2x_images() { public function render_format_conversion() { - include( dirname( __FILE__ ) . '/views/settings-conversion.php' ); + include __DIR__ . '/views/settings-conversion.php'; } private static function render_radiobutton( @@ -1042,7 +1042,7 @@ private static function render_radiobutton( $label, $descr ) { - $checked = ($current_value === $option_value ? ' checked="checked"' : ''); + $checked = ( $current_value === $option_value ? ' checked="checked"' : '' ); echo '

'; echo 'createMock(Tiny_Settings::class); $mock_settings->method('get_conversion_enabled')->willReturn(true); @@ -488,20 +486,13 @@ public function test_conversion_enabled_and_not_filtered() $settings_prop->setAccessible(true); $settings_prop->setValue($tiny_plugin, $mock_settings); - // Init plugin $tiny_plugin->init(); - $template_redirect_registered = false; - foreach ($this->wp->getCalls('add_action') as $call) { - if ($call[0] === 'template_redirect') { - $template_redirect_registered = true; - break; - } - } + $tiny_picture = new Tiny_Picture( $mock_settings ); - $this->assertTrue( - $template_redirect_registered, - 'Expected Tiny_Picture to hook into template_redirect.' - ); + // hook is registered on init + $this->wp->init(); + + WordPressStubs::assertHook('template_redirect', array($tiny_picture, 'on_template_redirect')); } } diff --git a/test/unit/Tiny_Apache_Rewrite_Test.php b/test/unit/Tiny_Apache_Rewrite_Test.php index b52e65d2..9a1fdaf6 100644 --- a/test/unit/Tiny_Apache_Rewrite_Test.php +++ b/test/unit/Tiny_Apache_Rewrite_Test.php @@ -12,7 +12,7 @@ function test_plugin_init_will_add_hook() { $mock_capabilities = Mockery::mock('alias:Tiny_Server_Capabilities'); $mock_capabilities->shouldReceive('is_apache')->andReturn(true); - + $mock_settings = $this->createMock(Tiny_Settings::class); $mock_settings->method('get_conversion_enabled')->willReturn(true); $mock_settings->method('get_conversion_delivery_method')->willReturn('htaccess'); @@ -25,15 +25,104 @@ function test_plugin_init_will_add_hook() } /** - * assert that when the plugin is uninstalled, the htaccess rules are removed + * uninstall_rules removes htaccess rules from upload directory. + * - creates a htaccess file in uploads directory + * - run uninstall_rules + * - validate if rules are removed + */ + function test_uninstall_rules_removes_upload_dir_htaccess() + { + $upload_dir = $this->vfs->url() . '/wp-content/uploads'; + $htaccess_file = $upload_dir . '/.htaccess'; + + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0755, true); + } + + $htaccess_content = "# BEGIN tiny-compress-images\nRewriteEngine On\n# END tiny-compress-images"; + file_put_contents($htaccess_file, $htaccess_content); + + $this->assertTrue(file_exists($htaccess_file), 'htaccess should exist before uninstall'); + + Tiny_Apache_Rewrite::uninstall_rules(); + + $contents = file_get_contents($htaccess_file); + $this->assertStringNotContainsString('tiny-compress-images', $contents, 'htaccess should not contain tinify anymore'); + } + + /** + * uninstall_rules removes htaccess rules from upload directory. + * - creates a htaccess file in uploads directory + * - run uninstall_rules + * - validate if rules are removed + */ + function test_uninstall_rules_removes_home_dir_htaccess() + { + $home_path = $this->vfs->url() . '/'; + $htaccess_file = $home_path . '.htaccess'; + + $this->wp->stub('get_home_path', function () use ($home_path) { + return $home_path; + }); + + file_put_contents($htaccess_file, "# BEGIN tiny-compress-images\nRewriteEngine On\n# END tiny-compress-images"); + + $this->assertTrue(file_exists($htaccess_file), 'htaccess should exist before uninstall'); + + Tiny_Apache_Rewrite::uninstall_rules(); + + $contents = file_get_contents($htaccess_file); + $this->assertStringNotContainsString('tiny-compress-images', $contents, 'htaccess should not contain plugin markers after uninstall'); + } + + /** + * Test that uninstall_rules handles non-existent upload directory htaccess gracefully. */ - function test_plugin_uninstalled_removed_rules() { - + function test_uninstall_rules_handles_missing_upload_htaccess() + { + $upload_dir = $this->vfs->url() . '/wp-content/uploads'; + $htaccess_file = $upload_dir . '/.htaccess'; + + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0755, true); + } + + // Ensure file doesn't exist + if (file_exists($htaccess_file)) { + unlink($htaccess_file); + } + + $this->assertFalse(file_exists($htaccess_file), 'htaccess should not exist'); + + // Should not throw error + $result = Tiny_Apache_Rewrite::uninstall_rules(); + + $this->assertTrue($result, 'uninstall_rules should return true even when file does not exist'); } /** - * assert that when the plugin is installed, convert is enabled and delivery is apache, then - * htaccess rules will be installed. + * Test that uninstall_rules handles non-existent home directory htaccess gracefully. */ - function test_plugin_install_add_rules() {} + function test_uninstall_rules_handles_missing_home_htaccess() + { + $home_path = $this->vfs->url() . '/'; + $htaccess_file = $home_path . '.htaccess'; + + // Mock get_home_path to return our virtual filesystem path + $this->wp->stub('get_home_path', function () use ($home_path) { + return $home_path; + }); + + // Ensure file doesn't exist + if (file_exists($htaccess_file)) { + unlink($htaccess_file); + } + + $this->assertFalse(file_exists($htaccess_file), 'htaccess should not exist'); + + // Should not throw error + $result = Tiny_Apache_Rewrite::uninstall_rules(); + + $this->assertTrue($result, 'uninstall_rules should return true even when file does not exist'); + } } From f81e1bf3a380c5c117564c5f418fcebad08695b9 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 10:20:26 +0100 Subject: [PATCH 21/33] Remove cache and only vary accept when it is an image --- src/class-tiny-apache-rewrite.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index e0ca38c6..612e580b 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -92,9 +92,8 @@ private static function get_rewrite_rules() { $rules[] = ''; $rules[] = ''; - $rules[] = 'Header append Vary Accept'; - $rules[] = ''; - $rules[] = 'Header set Cache-Control "max-age=31536000, public"'; + $rules[] = ''; + $rules[] = 'Header append Vary Accept'; $rules[] = ''; $rules[] = ''; From 9e3b4ec617379c8152ef48317769352f8eca4d2b Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 10:28:42 +0100 Subject: [PATCH 22/33] only write into uploads dir --- src/class-tiny-apache-rewrite.php | 19 ++-------- src/class-tiny-server-capabilities.php | 2 +- test/helpers/wordpress.php | 3 -- test/unit/Tiny_Apache_Rewrite_Test.php | 51 -------------------------- 4 files changed, 5 insertions(+), 70 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 612e580b..e447d465 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -80,11 +80,10 @@ public static function toggle_rules( $old_value, $value, $option ) { * @return string The .htaccess rules */ private static function get_rewrite_rules() { - $rules = array( - '', - 'RewriteEngine On', - 'RewriteOptions Inherit', - ); + $rules = array(); + $rules[] = ''; + $rules[] = 'RewriteEngine On'; + $rules[] = 'RewriteOptions Inherit'; $rules = array_merge( $rules, self::get_avif_rules() ); $rules = array_merge( $rules, self::get_webp_rules() ); @@ -148,11 +147,6 @@ private static function install_rules() { insert_with_markers( $htaccess_file, self::MARKER, $rules ); } - if ( is_writable( get_home_path() ) ) { - $htaccess_file = get_home_path() . '.htaccess'; - insert_with_markers( $htaccess_file, self::MARKER, $rules ); - } - return true; } @@ -168,11 +162,6 @@ public static function uninstall_rules() { insert_with_markers( $htaccess_file, self::MARKER, '' ); } - if ( file_exists( get_home_path() . '.htaccess' ) ) { - $htaccess_file = get_home_path() . '.htaccess'; - insert_with_markers( $htaccess_file, self::MARKER, '' ); - } - return true; } } diff --git a/src/class-tiny-server-capabilities.php b/src/class-tiny-server-capabilities.php index 4f0438eb..3655679f 100644 --- a/src/class-tiny-server-capabilities.php +++ b/src/class-tiny-server-capabilities.php @@ -76,7 +76,7 @@ public static function has_mod_rewrite() { } if ( function_exists( 'insert_with_markers' ) ) { - $htaccess = get_home_path() . '.htaccess'; + $htaccess = wp_upload_dir() . '.htaccess'; return is_writable( dirname( $htaccess ) ); } diff --git a/test/helpers/wordpress.php b/test/helpers/wordpress.php index d395f220..3123e40f 100644 --- a/test/helpers/wordpress.php +++ b/test/helpers/wordpress.php @@ -103,7 +103,6 @@ public function __construct($vfs) $this->addMethod('wp_send_json_error'); $this->addMethod('get_temp_dir'); $this->addMethod('esc_attr'); - $this->addMethod('get_home_path'); $this->addMethod('insert_with_markers'); $this->defaults(); $this->create_filesystem(); @@ -202,8 +201,6 @@ public function call($method, $args) return array('basedir' => $this->vfs->url() . '/' . self::UPLOAD_DIR, 'baseurl' => '/' . self::UPLOAD_DIR); } elseif ('is_admin' === $method) { return true; - } elseif ('get_home_path' === $method) { - return $this->vfs->url() . '/'; } elseif ('insert_with_markers' === $method) { return call_user_func_array(array($mocks, $method), $args); } elseif (method_exists($mocks, $method)) { diff --git a/test/unit/Tiny_Apache_Rewrite_Test.php b/test/unit/Tiny_Apache_Rewrite_Test.php index 9a1fdaf6..7ce052d1 100644 --- a/test/unit/Tiny_Apache_Rewrite_Test.php +++ b/test/unit/Tiny_Apache_Rewrite_Test.php @@ -50,31 +50,6 @@ function test_uninstall_rules_removes_upload_dir_htaccess() $this->assertStringNotContainsString('tiny-compress-images', $contents, 'htaccess should not contain tinify anymore'); } - /** - * uninstall_rules removes htaccess rules from upload directory. - * - creates a htaccess file in uploads directory - * - run uninstall_rules - * - validate if rules are removed - */ - function test_uninstall_rules_removes_home_dir_htaccess() - { - $home_path = $this->vfs->url() . '/'; - $htaccess_file = $home_path . '.htaccess'; - - $this->wp->stub('get_home_path', function () use ($home_path) { - return $home_path; - }); - - file_put_contents($htaccess_file, "# BEGIN tiny-compress-images\nRewriteEngine On\n# END tiny-compress-images"); - - $this->assertTrue(file_exists($htaccess_file), 'htaccess should exist before uninstall'); - - Tiny_Apache_Rewrite::uninstall_rules(); - - $contents = file_get_contents($htaccess_file); - $this->assertStringNotContainsString('tiny-compress-images', $contents, 'htaccess should not contain plugin markers after uninstall'); - } - /** * Test that uninstall_rules handles non-existent upload directory htaccess gracefully. */ @@ -99,30 +74,4 @@ function test_uninstall_rules_handles_missing_upload_htaccess() $this->assertTrue($result, 'uninstall_rules should return true even when file does not exist'); } - - /** - * Test that uninstall_rules handles non-existent home directory htaccess gracefully. - */ - function test_uninstall_rules_handles_missing_home_htaccess() - { - $home_path = $this->vfs->url() . '/'; - $htaccess_file = $home_path . '.htaccess'; - - // Mock get_home_path to return our virtual filesystem path - $this->wp->stub('get_home_path', function () use ($home_path) { - return $home_path; - }); - - // Ensure file doesn't exist - if (file_exists($htaccess_file)) { - unlink($htaccess_file); - } - - $this->assertFalse(file_exists($htaccess_file), 'htaccess should not exist'); - - // Should not throw error - $result = Tiny_Apache_Rewrite::uninstall_rules(); - - $this->assertTrue($result, 'uninstall_rules should return true even when file does not exist'); - } } From e053543e4be99ad829c363ba8f6e01e4ba463c3d Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 10:30:55 +0100 Subject: [PATCH 23/33] typo --- src/views/settings-conversion-delivery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/settings-conversion-delivery.php b/src/views/settings-conversion-delivery.php index 969b07f9..e120c5e7 100644 --- a/src/views/settings-conversion-delivery.php +++ b/src/views/settings-conversion-delivery.php @@ -35,5 +35,5 @@ 'htaccess', $tinify_delivery_value, 'Server rules', - 'Adds htaccess rules to delivery the optimized image.' + 'Adds htaccess rules to deliver the optimized image.' ); ?> From cbaf5963f2b7796e3a576f9e9cbb608e0b47c039 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 11:30:31 +0100 Subject: [PATCH 24/33] add query parameter for original bypass --- src/class-tiny-apache-rewrite.php | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index e447d465..f87acf81 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -35,16 +35,6 @@ class Tiny_Apache_Rewrite extends Tiny_WP_Base { */ const MARKER = 'tiny-compress-images'; - /** - * Initialize Apache Rewrite for converted images. - * - install rules - * - adds hook to add or remove the rules - * @return void - */ - function __construct() { - add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); - } - /** * Installs or uninstalls the htaccess rules * hooked into `update_option_tinypng_convert_format` @@ -61,15 +51,18 @@ public static function toggle_rules( $old_value, $value, $option ) { $new_delivery = isset( $value['delivery_method'] ) ? $value['delivery_method'] : null; if ( $old_delivery === $new_delivery ) { + Tiny_Logger::debug('image delivery method has not changed'); return; } if ( $old_delivery === 'htaccess' && ( $new_delivery === 'picture' || $new_delivery === null ) ) { self::uninstall_rules(); + Tiny_Logger::debug('uninstalled image delivery rules'); return; } if ( ( $old_delivery === 'picture' || $old_delivery === null ) && $new_delivery === 'htaccess' ) { self::install_rules(); + Tiny_Logger::debug('installed image delivery rules'); return; } } @@ -114,6 +107,7 @@ private static function get_avif_rules() { $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/avif'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.avif -f'; + $rules[] = 'RewriteCond %{QUERY_STRING} !type=original'; $rules[] = 'RewriteRule (.+)\.(?:jpe?g|png|gif)$ $1.avif [T=image/avif,L]'; return $rules; } @@ -128,6 +122,7 @@ private static function get_webp_rules() { $rules[] = 'RewriteCond %{HTTP_ACCEPT} image/webp'; $rules[] = 'RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png|gif)$'; $rules[] = 'RewriteCond %{DOCUMENT_ROOT}/%1.webp -f'; + $rules[] = 'RewriteCond %{QUERY_STRING} !type=original'; $rules[] = 'RewriteRule (.+)\.(?:jpe?g|png|gif)$ $1.webp [T=image/webp,L]'; return $rules; From a49dd8f6dd842813633ca8100b63e852ec2ce298 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 11:30:44 +0100 Subject: [PATCH 25/33] Move hook to init --- src/class-tiny-conversion.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php index 8fec8c85..917894fa 100644 --- a/src/class-tiny-conversion.php +++ b/src/class-tiny-conversion.php @@ -38,7 +38,9 @@ public function __construct( $settings ) { /** * will check if conversion is enabled, - * if true, will enable the delivery method + * if true: + * - will enable the delivery method + * - will add hook to toggle rules * * hooked into `init` */ @@ -47,6 +49,7 @@ public function init() { return; } + add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); $delivery_method = $this->settings->get_conversion_delivery_method(); $this->init_image_delivery( $delivery_method ); From 9d433f452feae5bcb1f2ebf966e0d261bfb12515 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 11:54:36 +0100 Subject: [PATCH 26/33] Format --- src/class-tiny-apache-rewrite.php | 10 +++++----- src/class-tiny-conversion.php | 6 +++--- src/class-tiny-logger.php | 8 ++++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index f87acf81..980e8610 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -51,18 +51,18 @@ public static function toggle_rules( $old_value, $value, $option ) { $new_delivery = isset( $value['delivery_method'] ) ? $value['delivery_method'] : null; if ( $old_delivery === $new_delivery ) { - Tiny_Logger::debug('image delivery method has not changed'); + Tiny_Logger::debug( 'image delivery method has not changed' ); return; } if ( $old_delivery === 'htaccess' && ( $new_delivery === 'picture' || $new_delivery === null ) ) { self::uninstall_rules(); - Tiny_Logger::debug('uninstalled image delivery rules'); + Tiny_Logger::debug( 'uninstalled image delivery rules' ); return; } if ( ( $old_delivery === 'picture' || $old_delivery === null ) && $new_delivery === 'htaccess' ) { self::install_rules(); - Tiny_Logger::debug('installed image delivery rules'); + Tiny_Logger::debug( 'installed image delivery rules' ); return; } } @@ -73,7 +73,7 @@ public static function toggle_rules( $old_value, $value, $option ) { * @return string The .htaccess rules */ private static function get_rewrite_rules() { - $rules = array(); + $rules = array(); $rules[] = ''; $rules[] = 'RewriteEngine On'; $rules[] = 'RewriteOptions Inherit'; @@ -85,7 +85,7 @@ private static function get_rewrite_rules() { $rules[] = ''; $rules[] = ''; - $rules[] = 'Header append Vary Accept'; + $rules[] = 'Header append Vary Accept'; $rules[] = ''; $rules[] = ''; diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php index 917894fa..9c711727 100644 --- a/src/class-tiny-conversion.php +++ b/src/class-tiny-conversion.php @@ -38,11 +38,11 @@ public function __construct( $settings ) { /** * will check if conversion is enabled, - * if true: + * if true: * - will enable the delivery method * - will add hook to toggle rules - * - * hooked into `init` + * + * hooked into `init` */ public function init() { if ( ! $this->settings->get_conversion_enabled() ) { diff --git a/src/class-tiny-logger.php b/src/class-tiny-logger.php index 2111d39f..aa168dbf 100644 --- a/src/class-tiny-logger.php +++ b/src/class-tiny-logger.php @@ -112,8 +112,12 @@ public function get_log_file_path() { */ public static function on_save_log_enabled( $log_enabled, $old, $option ) { $instance = self::get_instance(); - $instance->log_enabled = 'on' === $log_enabled; - if ( $instance->get_log_enabled() ) { + $was_enabled = 'on' === $old; + $is_now_enabled = 'on' === $log_enabled; + $instance->log_enabled = $is_now_enabled; + + // Only clear logs when logging is being turned on (from off to on). + if ( ! $was_enabled && $is_now_enabled ) { self::clear_logs(); } From 4c03162e026b86d670f43a6b246033265c20a1c2 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 11:57:17 +0100 Subject: [PATCH 27/33] fix style --- src/class-tiny-conversion.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php index 9c711727..956ecd3c 100644 --- a/src/class-tiny-conversion.php +++ b/src/class-tiny-conversion.php @@ -49,7 +49,13 @@ public function init() { return; } - add_action( 'update_option_tinypng_convert_format', 'Tiny_Apache_Rewrite::toggle_rules', 20, 3 ); + add_action( + 'update_option_tinypng_convert_format', + 'Tiny_Apache_Rewrite::toggle_rules', + 20, + 3 + ); + $delivery_method = $this->settings->get_conversion_delivery_method(); $this->init_image_delivery( $delivery_method ); @@ -68,12 +74,12 @@ private function init_image_delivery( $delivery_method ) { * * @since 3.7.0 */ - if ( $delivery_method === 'htaccess' && Tiny_Server_Capabilities::is_apache() ) { + if ( 'htaccess' === $delivery_method && Tiny_Server_Capabilities::is_apache() ) { new Tiny_Apache_Rewrite(); return; } - if ( apply_filters( 'tiny_replace_with_picture', $delivery_method === 'picture' ) ) { + if ( apply_filters( 'tiny_replace_with_picture', 'picture' === $delivery_method ) ) { new Tiny_Picture( ABSPATH, array( get_site_url() ) ); return; } From bac9e7b0e221fd8ff9edfe2c5e3b663e22392d42 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 12:17:11 +0100 Subject: [PATCH 28/33] Lint --- src/class-tiny-apache-rewrite.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 980e8610..897aedbe 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -51,20 +51,20 @@ public static function toggle_rules( $old_value, $value, $option ) { $new_delivery = isset( $value['delivery_method'] ) ? $value['delivery_method'] : null; if ( $old_delivery === $new_delivery ) { - Tiny_Logger::debug( 'image delivery method has not changed' ); return; } - if ( $old_delivery === 'htaccess' && ( $new_delivery === 'picture' || $new_delivery === null ) ) { - self::uninstall_rules(); - Tiny_Logger::debug( 'uninstalled image delivery rules' ); - return; - } - if ( ( $old_delivery === 'picture' || $old_delivery === null ) && $new_delivery === 'htaccess' ) { + if ( 'htaccess' === $new_delivery ) { self::install_rules(); - Tiny_Logger::debug( 'installed image delivery rules' ); + Tiny_Logger::debug( 'Installed image delivery rules' ); return; } + + // We only uninstall if we were previously using htaccess + if ( 'htaccess' === $old_delivery ) { + self::uninstall_rules(); + Tiny_Logger::debug( 'Uninstalled image delivery rules' ); + } } /** From 1cf893d00f7d358df92432c7f1d85a770c32dcd5 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 12:18:53 +0100 Subject: [PATCH 29/33] format --- src/class-tiny-apache-rewrite.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-apache-rewrite.php b/src/class-tiny-apache-rewrite.php index 897aedbe..cf64a873 100644 --- a/src/class-tiny-apache-rewrite.php +++ b/src/class-tiny-apache-rewrite.php @@ -47,8 +47,10 @@ class Tiny_Apache_Rewrite extends Tiny_WP_Base { * @return void */ public static function toggle_rules( $old_value, $value, $option ) { - $old_delivery = isset( $old_value['delivery_method'] ) ? $old_value['delivery_method'] : null; - $new_delivery = isset( $value['delivery_method'] ) ? $value['delivery_method'] : null; + $old_delivery = isset( $old_value['delivery_method'] ) ? + $old_value['delivery_method'] : null; + $new_delivery = isset( $value['delivery_method'] ) ? + $value['delivery_method'] : null; if ( $old_delivery === $new_delivery ) { return; @@ -152,7 +154,9 @@ private static function install_rules() { */ public static function uninstall_rules() { $upload_dir = wp_upload_dir(); - if ( isset( $upload_dir['basedir'] ) && file_exists( $upload_dir['basedir'] . '/.htaccess' ) ) { + if ( + file_exists( $upload_dir['basedir'] . '/.htaccess' ) + ) { $htaccess_file = $upload_dir['basedir'] . '/.htaccess'; insert_with_markers( $htaccess_file, self::MARKER, '' ); } From f2a0a919d30a763bc779c0f5f49908c8a9537223 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 14:56:18 +0100 Subject: [PATCH 30/33] Only apply convertion settings when conversion is enabled --- test/integration/utils.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/integration/utils.ts b/test/integration/utils.ts index 13ee19e1..21c78a88 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -214,7 +214,7 @@ export async function deactivatePlugin(page: Page, pluginSlug: string) { await plugin.getByLabel('Deactivate').click(); } -export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif' , delivery: 'picture' | 'htaccess' }) { +export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif'; delivery: 'picture' | 'htaccess' }) { await page.goto('/wp-admin/options-general.php?page=tinify'); if (settings.convert) { @@ -231,14 +231,14 @@ export async function setConversionSettings(page: Page, settings: { convert: boo default: await page.locator('#tinypng_convert_convert_to_smallest').check(); } - } else { - await page.locator('#tinypng_conversion_convert').uncheck(); - } - if (settings.delivery === 'htaccess') { - await page.getByTestId('tinypng_convert_delivery_picture').check(); + if (settings.delivery === 'htaccess') { + await page.getByTestId('tinypng_convert_delivery_picture').check(); + } else { + await page.getByTestId('tinypng_convert_delivery_htaccess').check(); + } } else { - await page.getByTestId('tinypng_convert_delivery_htaccess').check(); + await page.locator('#tinypng_conversion_convert').uncheck(); } await page.locator('#submit').click(); From 795b9391a63dcbc1c96bfd10d85406a1a985dc1b Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 15:01:20 +0100 Subject: [PATCH 31/33] check delivery method incorrect --- test/integration/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/utils.ts b/test/integration/utils.ts index 21c78a88..01640e24 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -233,9 +233,9 @@ export async function setConversionSettings(page: Page, settings: { convert: boo } if (settings.delivery === 'htaccess') { - await page.getByTestId('tinypng_convert_delivery_picture').check(); - } else { await page.getByTestId('tinypng_convert_delivery_htaccess').check(); + } else { + await page.getByTestId('tinypng_convert_delivery_picture').check(); } } else { await page.locator('#tinypng_conversion_convert').uncheck(); From a25c9a652b4496869fef8ce4487018a8bae5d281 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 18 Feb 2026 16:24:24 +0100 Subject: [PATCH 32/33] Resolve integration tests --- src/class-tiny-conversion.php | 2 +- test/integration/conversion.spec.ts | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/class-tiny-conversion.php b/src/class-tiny-conversion.php index 956ecd3c..6cd319b6 100644 --- a/src/class-tiny-conversion.php +++ b/src/class-tiny-conversion.php @@ -80,7 +80,7 @@ private function init_image_delivery( $delivery_method ) { } if ( apply_filters( 'tiny_replace_with_picture', 'picture' === $delivery_method ) ) { - new Tiny_Picture( ABSPATH, array( get_site_url() ) ); + new Tiny_Picture( $this->settings, ABSPATH, array( get_site_url() ) ); return; } } diff --git a/test/integration/conversion.spec.ts b/test/integration/conversion.spec.ts index a401c3ff..13670f48 100644 --- a/test/integration/conversion.spec.ts +++ b/test/integration/conversion.spec.ts @@ -85,15 +85,21 @@ test.describe('conversion', () => { }, WPVersion ); - const imageResponsePromise = page.waitForResponse(response => - // img is still jpg, but expect content type to be avif - response.url().includes('input-example.jpg') && response.status() === 200 - ); + + const imageResponsePromise = page.waitForResponse((response) => response.url().includes('input-example.jpg'), { timeout: 10000 }); await page.goto(`/?p=${postID}`); - const imgResponse = await imageResponsePromise; - const contentType = await imgResponse.headerValue('content-type'); - expect(contentType).toBe('image/avif'); + await imageResponsePromise; + + const response = await page.request.get(media, { + headers: { + Accept: 'image/avif,image/webp,*/*', // browser automatically add this + }, + }); + const buffer = await response.body(); + const signature = buffer.toString('ascii', 0, 16); + + expect(signature).toContain('ftypavif'); }); }); From e94a2d3bf3b137d0ed9e0241247e6e93d6007f2b Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 19 Feb 2026 14:50:23 +0100 Subject: [PATCH 33/33] chore: revert logger changes from conversion branch The logger fix has been moved to the separate diagnostic-logging branch --- src/class-tiny-logger.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/class-tiny-logger.php b/src/class-tiny-logger.php index aa168dbf..2111d39f 100644 --- a/src/class-tiny-logger.php +++ b/src/class-tiny-logger.php @@ -112,12 +112,8 @@ public function get_log_file_path() { */ public static function on_save_log_enabled( $log_enabled, $old, $option ) { $instance = self::get_instance(); - $was_enabled = 'on' === $old; - $is_now_enabled = 'on' === $log_enabled; - $instance->log_enabled = $is_now_enabled; - - // Only clear logs when logging is being turned on (from off to on). - if ( ! $was_enabled && $is_now_enabled ) { + $instance->log_enabled = 'on' === $log_enabled; + if ( $instance->get_log_enabled() ) { self::clear_logs(); }