From 40f0ab61a698d1ae6f1893530ace15eeaf4bb4bc Mon Sep 17 00:00:00 2001 From: Gael Robin Date: Fri, 5 Jan 2024 06:21:48 +0100 Subject: [PATCH 1/4] Add AVIF rewrites rules --- classes/Avif/RewriteRules/Apache.php | 60 ++++++ classes/Avif/RewriteRules/Display.php | 252 ++++++++++++++++++++++++++ classes/Avif/RewriteRules/Nginx.php | 49 +++++ 3 files changed, 361 insertions(+) create mode 100644 classes/Avif/RewriteRules/Apache.php create mode 100644 classes/Avif/RewriteRules/Display.php create mode 100644 classes/Avif/RewriteRules/Nginx.php diff --git a/classes/Avif/RewriteRules/Apache.php b/classes/Avif/RewriteRules/Apache.php new file mode 100644 index 000000000..16fe87c4e --- /dev/null +++ b/classes/Avif/RewriteRules/Apache.php @@ -0,0 +1,60 @@ +get_extensions_pattern(); + $home_root = wp_parse_url( home_url( '/' ) ); + $home_root = $home_root['path']; + + return trim( ' + + # Vary: Accept for all the requests to jpeg, png, and gif. + SetEnvIf Request_URI "\.(' . $extensions . ')$" REQUEST_image + + + + RewriteEngine On + RewriteBase ' . $home_root . ' + + # Check if browser supports AVIF images. + # Update the MIME type accordingly. + RewriteCond %{HTTP_ACCEPT} image/avif + + # Check if AVIF replacement image exists. + RewriteCond %{REQUEST_FILENAME}.avif -f + + # Serve AVIF image instead. + RewriteRule (.+)\.(' . $extensions . ')$ $1.$2.avif [T=image/avif,NC] + + + + # Update the MIME type accordingly. + Header append Vary Accept env=REQUEST_image +' ); + } +} diff --git a/classes/Avif/RewriteRules/Display.php b/classes/Avif/RewriteRules/Display.php new file mode 100644 index 000000000..b88ca2e04 --- /dev/null +++ b/classes/Avif/RewriteRules/Display.php @@ -0,0 +1,252 @@ +validate_values_on_update() for why we use 'convert_to_avif' here. + $is_enabled = ! empty($values['display_avif']) && ! empty($values['convert_to_avif']); + + // Which method? + $old_value = get_imagify_option('display_avif_method'); + $new_value = ! empty($values['display_avif_method']) ? $values['display_avif_method'] : ''; + + // Decide when to add or remove rules. + $is_rewrite = self::OPTION_VALUE === $new_value; + $was_rewrite = self::OPTION_VALUE === $old_value; + $add_or_remove = false; + + if ($is_enabled && $is_rewrite && (!$was_enabled || !$was_rewrite)) { + // Display AVIF & use rewrite method, but only if one of the values changed: add rules. + $add_or_remove = 'add'; + } elseif ($was_enabled && $was_rewrite && (!$is_enabled || !$is_rewrite)) { + // Was displaying AVIF & was using rewrite method, but only if one of the values changed: remove rules. + $add_or_remove = 'remove'; + } else { + return $values; + } + + if ($is_apache) { + $rules = new Apache(); + } elseif ($is_nginx) { + $rules = new Nginx(); + } else { + return $values; + } + + if ('add' === $add_or_remove) { + // Add the rewrite rules. + $result = $rules->add(); + } else { + // Remove the rewrite rules. + $result = $rules->remove(); + } + + if (!is_wp_error($result)) { + return $values; + } + + // Display an error message. + if (is_multisite() && strpos(wp_get_referer(), network_admin_url('/')) === 0) { + Notices::get_instance()->add_network_temporary_notice($result->get_error_message()); + } else { + Notices::get_instance()->add_site_temporary_notice($result->get_error_message()); + } + + return $values; + } + + /** + * If the conf file is not writable, add a warning. + * + * @since 1.9 + */ + public function maybe_add_avif_info() { + global $is_nginx; + + $conf = $this->get_server_conf(); + + if (!$conf) { + return; + } + + $writable = $conf->is_file_writable(); + + if (is_wp_error($writable)) { + $rules = $conf->get_new_contents(); + + if (!$rules) { + // Uh? + return; + } + + printf( + /* translators: %s is a file name. */ + esc_html__('If you choose to use rewrite rules, you will have to add the following lines manually to the %s file:', 'imagify'), + '' . $this->get_file_path(true) . '' + ); + + echo '
' . esc_html($rules) . '
'; + } elseif ($is_nginx) { + printf( + /* translators: %s is a file name. */ + esc_html__('If you choose to use rewrite rules, the file %s will be created and must be included into the server’s configuration file (then restart the server).', 'imagify'), + '' . $this->get_file_path(true) . '' + ); + } + } + + /** + * Add rules on plugin activation. + * + * @since 1.9 + */ + public function activate() { + $conf = $this->get_server_conf(); + + if (!$conf) { + return; + } + if (!get_imagify_option('display_avif')) { + return; + } + if (self::OPTION_VALUE !== get_imagify_option('display_avif_method')) { + return; + } + if (is_wp_error($conf->is_file_writable())) { + return; + } + + $conf->add(); + } + + /** + * Remove rules on plugin deactivation. + * + * @since 1.9 + */ + public function deactivate() { + $conf = $this->get_server_conf(); + + if (!$conf) { + return; + } + if (!get_imagify_option('display_avif')) { + return; + } + if (self::OPTION_VALUE !== get_imagify_option('display_avif_method')) { + return; + } + + $file_path = $conf->get_file_path(); + $filesystem = \Imagify_Filesystem::get_instance(); + + if (!$filesystem->exists($file_path)) { + return; + } + if (!$filesystem->is_writable($file_path)) { + return; + } + + $conf->remove(); + } + + /** + * Get the path to the directory conf file. + * + * @since 1.9 + * + * @param bool $relative True to get a path relative to the site’s root. + * @return string|bool The file path. False on failure. + */ + public function get_file_path($relative = false) { + if (!$this->get_server_conf()) { + return false; + } + + $file_path = $this->get_server_conf()->get_file_path(); + + if ($relative) { + return \Imagify_Filesystem::get_instance()->make_path_relative($file_path); + } + + return $file_path; + } + + /** + * Get the server conf instance. + * + * @since 1.9 + * + * @return \Imagify\WriteFile\WriteFileInterface + */ + protected function get_server_conf() { + global $is_apache, $is_iis7, $is_nginx; + + if (isset($this->server_conf)) { + return $this->server_conf; + } + + if ($is_apache) { + $this->server_conf = new Apache(); + } elseif ($is_iis7) { + $this->server_conf = new IIS(); + } elseif ($is_nginx) { + $this->server_conf = new Nginx(); + } else { + $this->server_conf = false; + } + + return $this->server_conf; + } +} diff --git a/classes/Avif/RewriteRules/Nginx.php b/classes/Avif/RewriteRules/Nginx.php new file mode 100644 index 000000000..d22a17e6f --- /dev/null +++ b/classes/Avif/RewriteRules/Nginx.php @@ -0,0 +1,49 @@ +get_extensions_pattern(); + $home_root = wp_parse_url( home_url( '/' ) ); + $home_root = $home_root['path']; + + return trim( ' +location ~* ^(' . $home_root . '.+)\.(' . $extensions . ')$ { + add_header Vary Accept; + + if ($http_accept ~* "avif"){ + set $imavif A; + } + if (-f $request_filename.avif) { + set $imavif "${imavif}B"; + } + if ($imavif = AB) { + rewrite ^(.*) $1.avif; + } +}' ); + } +} From b86ac781e0c389c495303def2baf2a0f88c84df1 Mon Sep 17 00:00:00 2001 From: Gael Robin Date: Fri, 5 Jan 2024 06:42:38 +0100 Subject: [PATCH 2/4] fix phpcs --- classes/Avif/RewriteRules/Display.php | 112 +++++++++++--------------- 1 file changed, 46 insertions(+), 66 deletions(-) diff --git a/classes/Avif/RewriteRules/Display.php b/classes/Avif/RewriteRules/Display.php index b88ca2e04..1228e8842 100644 --- a/classes/Avif/RewriteRules/Display.php +++ b/classes/Avif/RewriteRules/Display.php @@ -7,8 +7,6 @@ /** * Display AVIF images on the site with rewrite rules. - * - * @since 1.9 // Update this version number accordingly */ class Display { use InstanceGetterTrait; @@ -24,67 +22,61 @@ class Display { * Option value. * * @var string - * @since 1.9 // Update this version number accordingly */ - const OPTION_VALUE = 'rewrite_avif'; // Adjust accordingly + const OPTION_VALUE = 'rewrite_avif'; /** * Init. - * - * @since 1.9 // Update this version number accordingly */ public function init() { - add_filter('imagify_settings_on_save', [$this, 'maybe_add_rewrite_rules']); - add_action('imagify_settings_avif_info', [$this, 'maybe_add_avif_info']); - add_action('imagify_activation', [$this, 'activate']); - add_action('imagify_deactivation', [$this, 'deactivate']); - // Add your additional initialization logic here, similar to the Display class. + add_filter( 'imagify_settings_on_save', [ $this, 'maybe_add_rewrite_rules' ] ); + add_action( 'imagify_settings_avif_info', [ $this, 'maybe_add_avif_info' ] ); + add_action( 'imagify_activation', [ $this, 'activate' ] ); + add_action( 'imagify_deactivation', [ $this, 'deactivate' ] ); } /** * If display AVIF images via rewrite rules, add the rules to the .htaccess/etc file. * - * @since 1.9 - * * @param array $values The option values. * @return array */ - public function maybe_add_rewrite_rules($values) { - global $is_apache, $is_iis7, $is_nginx; + public function maybe_add_rewrite_rules( $values ) { + global $is_apache, $is_nginx; // Display AVIF? - $was_enabled = (bool) get_imagify_option('display_avif'); + $was_enabled = (bool) get_imagify_option( 'display_avif' ); // See \Imagify_Options->validate_values_on_update() for why we use 'convert_to_avif' here. - $is_enabled = ! empty($values['display_avif']) && ! empty($values['convert_to_avif']); + $is_enabled = ! empty( $values['display_avif'] ) && ! empty( $values['convert_to_avif'] ); // Which method? - $old_value = get_imagify_option('display_avif_method'); - $new_value = ! empty($values['display_avif_method']) ? $values['display_avif_method'] : ''; + $old_value = get_imagify_option( 'display_avif_method' ); + $new_value = ! empty( $values['display_avif_method'] ) ? $values['display_avif_method'] : ''; // Decide when to add or remove rules. $is_rewrite = self::OPTION_VALUE === $new_value; $was_rewrite = self::OPTION_VALUE === $old_value; $add_or_remove = false; - if ($is_enabled && $is_rewrite && (!$was_enabled || !$was_rewrite)) { + if ( $is_enabled && $is_rewrite && ( ! $was_enabled || ! $was_rewrite ) ) { // Display AVIF & use rewrite method, but only if one of the values changed: add rules. $add_or_remove = 'add'; - } elseif ($was_enabled && $was_rewrite && (!$is_enabled || !$is_rewrite)) { + } elseif ( $was_enabled && $was_rewrite && ( ! $is_enabled || ! $is_rewrite ) ) { // Was displaying AVIF & was using rewrite method, but only if one of the values changed: remove rules. $add_or_remove = 'remove'; } else { return $values; } - if ($is_apache) { + if ( $is_apache ) { $rules = new Apache(); - } elseif ($is_nginx) { + } elseif ( $is_nginx ) { $rules = new Nginx(); } else { return $values; } - if ('add' === $add_or_remove) { + if ( 'add' === $add_or_remove ) { // Add the rewrite rules. $result = $rules->add(); } else { @@ -92,15 +84,15 @@ public function maybe_add_rewrite_rules($values) { $result = $rules->remove(); } - if (!is_wp_error($result)) { + if ( ! is_wp_error( $result ) ) { return $values; } // Display an error message. - if (is_multisite() && strpos(wp_get_referer(), network_admin_url('/')) === 0) { - Notices::get_instance()->add_network_temporary_notice($result->get_error_message()); + if ( is_multisite() && strpos( wp_get_referer(), network_admin_url( '/' ) ) === 0 ) { + Notices::get_instance()->add_network_temporary_notice( $result->get_error_message() ); } else { - Notices::get_instance()->add_site_temporary_notice($result->get_error_message()); + Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() ); } return $values; @@ -108,62 +100,58 @@ public function maybe_add_rewrite_rules($values) { /** * If the conf file is not writable, add a warning. - * - * @since 1.9 */ public function maybe_add_avif_info() { global $is_nginx; $conf = $this->get_server_conf(); - if (!$conf) { + if ( ! $conf ) { return; } $writable = $conf->is_file_writable(); - if (is_wp_error($writable)) { + if ( is_wp_error( $writable ) ) { $rules = $conf->get_new_contents(); - if (!$rules) { + if ( ! $rules ) { // Uh? return; } printf( /* translators: %s is a file name. */ - esc_html__('If you choose to use rewrite rules, you will have to add the following lines manually to the %s file:', 'imagify'), - '' . $this->get_file_path(true) . '' + esc_html__( 'If you choose to use rewrite rules, you will have to add the following lines manually to the %s file:', 'imagify' ), + '' . $this->get_file_path( true ) . '' ); - echo '
' . esc_html($rules) . '
'; - } elseif ($is_nginx) { + echo '
' . esc_html( $rules ) . '
'; + } elseif ( $is_nginx ) { printf( /* translators: %s is a file name. */ - esc_html__('If you choose to use rewrite rules, the file %s will be created and must be included into the server’s configuration file (then restart the server).', 'imagify'), - '' . $this->get_file_path(true) . '' + esc_html__( 'If you choose to use rewrite rules, the file %s will be created and must be included into the server’s configuration file (then restart the server).', 'imagify' ), + '' . $this->get_file_path( true ) . '' ); } } /** * Add rules on plugin activation. - * - * @since 1.9 */ public function activate() { $conf = $this->get_server_conf(); - if (!$conf) { + if ( ! $conf ) { return; } - if (!get_imagify_option('display_avif')) { + if ( ! get_imagify_option( 'display_avif' ) ) { return; } - if (self::OPTION_VALUE !== get_imagify_option('display_avif_method')) { + if ( self::OPTION_VALUE !== get_imagify_option( 'display_avif_method' ) ) { return; } - if (is_wp_error($conf->is_file_writable())) { + if ( is_wp_error( $conf->is_file_writable() ) ) { return; } @@ -172,29 +160,27 @@ public function activate() { /** * Remove rules on plugin deactivation. - * - * @since 1.9 */ public function deactivate() { $conf = $this->get_server_conf(); - if (!$conf) { + if ( ! $conf ) { return; } - if (!get_imagify_option('display_avif')) { + if ( ! get_imagify_option( 'display_avif' ) ) { return; } - if (self::OPTION_VALUE !== get_imagify_option('display_avif_method')) { + if ( self::OPTION_VALUE !== get_imagify_option( 'display_avif_method' ) ) { return; } $file_path = $conf->get_file_path(); $filesystem = \Imagify_Filesystem::get_instance(); - if (!$filesystem->exists($file_path)) { + if ( ! $filesystem->exists( $file_path ) ) { return; } - if (!$filesystem->is_writable($file_path)) { + if ( ! $filesystem->is_writable( $file_path ) ) { return; } @@ -204,20 +190,18 @@ public function deactivate() { /** * Get the path to the directory conf file. * - * @since 1.9 - * * @param bool $relative True to get a path relative to the site’s root. * @return string|bool The file path. False on failure. */ - public function get_file_path($relative = false) { - if (!$this->get_server_conf()) { + public function get_file_path( $relative = false ) { + if ( ! $this->get_server_conf() ) { return false; } $file_path = $this->get_server_conf()->get_file_path(); - if ($relative) { - return \Imagify_Filesystem::get_instance()->make_path_relative($file_path); + if ( $relative ) { + return \Imagify_Filesystem::get_instance()->make_path_relative( $file_path ); } return $file_path; @@ -226,22 +210,18 @@ public function get_file_path($relative = false) { /** * Get the server conf instance. * - * @since 1.9 - * * @return \Imagify\WriteFile\WriteFileInterface */ protected function get_server_conf() { - global $is_apache, $is_iis7, $is_nginx; + global $is_apache, $is_nginx; - if (isset($this->server_conf)) { + if ( isset( $this->server_conf ) ) { return $this->server_conf; } - if ($is_apache) { + if ( $is_apache ) { $this->server_conf = new Apache(); - } elseif ($is_iis7) { - $this->server_conf = new IIS(); - } elseif ($is_nginx) { + } elseif ( $is_nginx ) { $this->server_conf = new Nginx(); } else { $this->server_conf = false; From 25f9b78feb2441c140c141f1cbe21e537a18b7db Mon Sep 17 00:00:00 2001 From: Gael Robin Date: Mon, 8 Jan 2024 13:48:45 +0100 Subject: [PATCH 3/4] Comply feedback --- classes/Avif/RewriteRules/Apache.php | 7 ++----- classes/Avif/RewriteRules/Nginx.php | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/classes/Avif/RewriteRules/Apache.php b/classes/Avif/RewriteRules/Apache.php index 16fe87c4e..605966b64 100644 --- a/classes/Avif/RewriteRules/Apache.php +++ b/classes/Avif/RewriteRules/Apache.php @@ -1,20 +1,18 @@ Date: Wed, 17 Jan 2024 05:08:51 +0100 Subject: [PATCH 4/4] Comply feedback --- classes/Avif/RewriteRules/Display.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/classes/Avif/RewriteRules/Display.php b/classes/Avif/RewriteRules/Display.php index 1228e8842..883166942 100644 --- a/classes/Avif/RewriteRules/Display.php +++ b/classes/Avif/RewriteRules/Display.php @@ -45,14 +45,13 @@ public function maybe_add_rewrite_rules( $values ) { global $is_apache, $is_nginx; // Display AVIF? - $was_enabled = (bool) get_imagify_option( 'display_avif' ); + $was_enabled = (bool) get_imagify_option( 'display_next_gen_method' ); // See \Imagify_Options->validate_values_on_update() for why we use 'convert_to_avif' here. - $is_enabled = ! empty( $values['display_avif'] ) && ! empty( $values['convert_to_avif'] ); + $is_enabled = ! empty( $values['display_next_gen_method'] ) && ! empty( $values['convert_to_next_gen'] ); // Which method? - $old_value = get_imagify_option( 'display_avif_method' ); - $new_value = ! empty( $values['display_avif_method'] ) ? $values['display_avif_method'] : ''; - + $old_value = get_imagify_option( 'display_next_gen_method' ); + $new_value = ! empty( $values['display_next_gen_method'] ) ? $values['display_next_gen_method'] : ''; // Decide when to add or remove rules. $is_rewrite = self::OPTION_VALUE === $new_value; $was_rewrite = self::OPTION_VALUE === $old_value; @@ -145,10 +144,10 @@ public function activate() { if ( ! $conf ) { return; } - if ( ! get_imagify_option( 'display_avif' ) ) { + if ( ! get_imagify_option( 'display_next_gen' ) ) { return; } - if ( self::OPTION_VALUE !== get_imagify_option( 'display_avif_method' ) ) { + if ( self::OPTION_VALUE !== get_imagify_option( 'display_next_gen_method' ) ) { return; } if ( is_wp_error( $conf->is_file_writable() ) ) { @@ -167,10 +166,10 @@ public function deactivate() { if ( ! $conf ) { return; } - if ( ! get_imagify_option( 'display_avif' ) ) { + if ( ! get_imagify_option( 'display_next_gen' ) ) { return; } - if ( self::OPTION_VALUE !== get_imagify_option( 'display_avif_method' ) ) { + if ( self::OPTION_VALUE !== get_imagify_option( 'display_next_gen_method' ) ) { return; }