Phase 6: WebP image conversion - Converter for Media plugin with Nginx rewrite rules
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
use WebpConverter\Settings\Option\SupportedExtensionsOption;
|
||||
|
||||
/**
|
||||
* Supports method of loading images using rewrites from .htaccess file.
|
||||
*/
|
||||
class HtaccessBypassingLoader extends HtaccessLoader {
|
||||
|
||||
const LOADER_TYPE = 'htaccess_bypassing';
|
||||
const FILENAME_SUFFIX = '-optimized';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_type(): string {
|
||||
return self::LOADER_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_admin_hooks() {
|
||||
add_filter( 'webpc_debug_image_url', [ $this, 'update_image_urls' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_front_end_hooks() {
|
||||
add_action( 'init', [ $this, 'start_buffering' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function start_buffering() {
|
||||
if ( ! ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || ( ! is_admin() && ! is_network_admin() ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start(
|
||||
function ( $buffer ) {
|
||||
return $this->update_image_urls( $buffer );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces URLs to source images in output buffer.
|
||||
*
|
||||
* @param string $buffer Contents of output buffer.
|
||||
*
|
||||
* @return string Contents of output buffer.
|
||||
* @internal
|
||||
*/
|
||||
public function update_image_urls( string $buffer ): string {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
$extensions = implode( '|', $settings[ SupportedExtensionsOption::OPTION_NAME ] );
|
||||
if ( ! $extensions ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$path_dir_uploads = apply_filters( 'webpc_dir_name', '', 'uploads' );
|
||||
return preg_replace_callback(
|
||||
'/((?:\/' . str_replace( '/', '\\/', $path_dir_uploads ) . '\/)(?:.*?))\.(' . $extensions . ')/',
|
||||
function ( $matches ) {
|
||||
return str_replace( self::FILENAME_SUFFIX, '', $matches[1] ) . self::FILENAME_SUFFIX . '.' . $matches[2];
|
||||
},
|
||||
$buffer
|
||||
) ?: $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_rules_to_wp_content( array $settings ): array {
|
||||
return [
|
||||
$this->get_suffix_redirect_rules( $settings ),
|
||||
$this->get_mod_rewrite_rules( $settings ),
|
||||
$this->get_mod_headers_rules( $settings ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates redirects for suffixed URLs.
|
||||
*
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
private function get_suffix_redirect_rules( array $settings ): string {
|
||||
$content = '';
|
||||
$extensions = implode( '|', $settings[ SupportedExtensionsOption::OPTION_NAME ] ) ?: '.+';
|
||||
|
||||
$content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
|
||||
$content .= ' RewriteEngine On' . PHP_EOL;
|
||||
$content .= ' RewriteCond %{REQUEST_FILENAME} !-f' . PHP_EOL;
|
||||
$content .= ' RewriteRule ^(.+)' . self::FILENAME_SUFFIX . '\.(' . $extensions . ')$ $1.$2 [NC]' . PHP_EOL;
|
||||
$content .= '</IfModule>';
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
use WebpConverter\Service\CloudflareConfigurator;
|
||||
use WebpConverter\Service\EnvDetector;
|
||||
use WebpConverter\Service\OptionsAccessManager;
|
||||
use WebpConverter\Service\PathsGenerator;
|
||||
use WebpConverter\Settings\Option\CloudflareApiTokenOption;
|
||||
use WebpConverter\Settings\Option\CloudflareZoneIdOption;
|
||||
use WebpConverter\Settings\Option\ExtraFeaturesOption;
|
||||
use WebpConverter\Settings\Option\HtaccessRewriteOutputOption;
|
||||
use WebpConverter\Settings\Option\HtaccessRewritePathOption;
|
||||
use WebpConverter\Settings\Option\HtaccessRewriteRootOption;
|
||||
use WebpConverter\Settings\Option\RewriteInheritanceOption;
|
||||
use WebpConverter\Settings\Option\SupportedExtensionsOption;
|
||||
|
||||
/**
|
||||
* Supports method of loading images using rewrites from .htaccess file.
|
||||
*/
|
||||
class HtaccessLoader extends LoaderAbstract {
|
||||
|
||||
const LOADER_TYPE = 'htaccess';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_type(): string {
|
||||
return self::LOADER_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_admin_hooks() {
|
||||
add_filter( 'webpc_htaccess_rewrite_root', [ $this, 'modify_document_root_path' ], 0 );
|
||||
add_filter( 'webpc_htaccess_rewrite_output', [ $this, 'modify_output_root_path' ], 0, 2 );
|
||||
add_filter( 'webpc_htaccess_rewrite_root', [ $this, 'overwrite_htaccess_rewrite_root' ] );
|
||||
add_filter( 'webpc_htaccess_rewrite_path', [ $this, 'overwrite_htaccess_rewrite_path' ] );
|
||||
add_filter( 'webpc_htaccess_rewrite_output', [ $this, 'overwrite_htaccess_rewrite_output' ] );
|
||||
add_filter( 'webpc_debug_image_url', [ $this, 'update_image_urls_to_bunny_cdn' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_front_end_hooks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function activate_loader( bool $is_debug = false ) {
|
||||
$settings = ( ! $is_debug ) ? $this->plugin_data->get_plugin_settings() : $this->plugin_data->get_plugin_settings_debug();
|
||||
|
||||
$this->deactivate_loader();
|
||||
|
||||
$this->add_rewrite_rules_to_wp_content( true, $settings );
|
||||
$this->add_rewrite_rules_to_uploads( true, $settings );
|
||||
$this->add_rewrite_rules_to_uploads_webp( true, $settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deactivate_loader() {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
|
||||
$this->add_rewrite_rules_to_wp_content( false, $settings );
|
||||
$this->add_rewrite_rules_to_uploads( false, $settings );
|
||||
$this->add_rewrite_rules_to_uploads_webp( false, $settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $original_path .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function modify_document_root_path( string $original_path ): string {
|
||||
if ( isset( $_SERVER['SERVER_ADMIN'] ) && strpos( $_SERVER['SERVER_ADMIN'], '.home.pl' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
|
||||
return '%{DOCUMENT_ROOT}' . str_replace( '//', '/', ABSPATH );
|
||||
}
|
||||
|
||||
return $original_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $output_path .
|
||||
* @param string $root_path .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function modify_output_root_path( string $output_path, string $root_path ): string {
|
||||
if ( $output_path === $root_path ) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return $output_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function overwrite_htaccess_rewrite_root( string $path ): string {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
$terms = [
|
||||
'ABSPATH' => ABSPATH,
|
||||
];
|
||||
|
||||
return ( $settings[ HtaccessRewriteRootOption::OPTION_NAME ] !== '' )
|
||||
? str_replace( array_keys( $terms ), array_values( $terms ), $settings[ HtaccessRewriteRootOption::OPTION_NAME ] )
|
||||
: $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function overwrite_htaccess_rewrite_path( string $path ): string {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
|
||||
return ( $settings[ HtaccessRewritePathOption::OPTION_NAME ] !== '' ) ? $settings[ HtaccessRewritePathOption::OPTION_NAME ] : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function overwrite_htaccess_rewrite_output( string $path ): string {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
|
||||
return ( $settings[ HtaccessRewriteOutputOption::OPTION_NAME ] !== '' ) ? $settings[ HtaccessRewriteOutputOption::OPTION_NAME ] : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url .
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function update_image_urls_to_bunny_cdn( string $url ): string {
|
||||
if ( ! class_exists( '\BunnyCDN' ) || ! EnvDetector::is_cdn_bunny() ) {
|
||||
return $url;
|
||||
}
|
||||
$options = \BunnyCDN::getOptions();
|
||||
|
||||
return str_replace( $options['site_url'], ( is_ssl() ? 'https://' : 'http://' ) . $options['cdn_domain_name'], $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves rules to .htaccess file in /wp-content directory.
|
||||
*
|
||||
* @param bool $is_active Is loader active?
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_rewrite_rules_to_wp_content( bool $is_active, array $settings ) {
|
||||
$path = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) );
|
||||
if ( ! $is_active ) {
|
||||
$this->save_rewrites_in_htaccesss( $path );
|
||||
return;
|
||||
}
|
||||
|
||||
$content = $this->add_comments_to_rules( $this->get_rules_to_wp_content( $settings ) );
|
||||
|
||||
$content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
|
||||
$this->save_rewrites_in_htaccesss( $path, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_rules_to_wp_content( array $settings ): array {
|
||||
return [
|
||||
$this->get_mod_rewrite_rules( $settings ),
|
||||
$this->get_mod_headers_rules( $settings ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves rules to .htaccess file in /uploads directory.
|
||||
*
|
||||
* @param bool $is_active Is loader active?
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_rewrite_rules_to_uploads( bool $is_active, array $settings ) {
|
||||
$path = apply_filters( 'webpc_dir_path', '', 'uploads' );
|
||||
if ( ! $is_active ) {
|
||||
$this->save_rewrites_in_htaccesss( $path );
|
||||
return;
|
||||
}
|
||||
|
||||
$path_parts = explode( '/', apply_filters( 'webpc_dir_name', '', 'uploads' ) );
|
||||
$content = $this->add_comments_to_rules(
|
||||
[
|
||||
$this->get_mod_rewrite_rules( $settings, end( $path_parts ) ),
|
||||
]
|
||||
);
|
||||
|
||||
$content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
|
||||
$this->save_rewrites_in_htaccesss( $path, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves rules to .htaccess file in /uploads-webpc directory.
|
||||
*
|
||||
* @param bool $is_active Is loader active?
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_rewrite_rules_to_uploads_webp( bool $is_active, array $settings ) {
|
||||
$path = apply_filters( 'webpc_dir_path', '', 'webp' );
|
||||
if ( ! $is_active ) {
|
||||
$this->save_rewrites_in_htaccesss( $path );
|
||||
return;
|
||||
}
|
||||
|
||||
$content = $this->add_comments_to_rules(
|
||||
[
|
||||
$this->get_mod_mime_rules( $settings ),
|
||||
$this->get_mod_expires_rules(),
|
||||
]
|
||||
);
|
||||
|
||||
$content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
|
||||
$this->save_rewrites_in_htaccesss( $path, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates rules for rewriting source images to output images.
|
||||
*
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
* @param string|null $output_path_suffix Location of .htaccess file.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
protected function get_mod_rewrite_rules( array $settings, ?string $output_path_suffix = null ): string {
|
||||
$content = '';
|
||||
if ( ! $settings[ SupportedExtensionsOption::OPTION_NAME ] ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$document_root = PathsGenerator::get_rewrite_root();
|
||||
$root_suffix = PathsGenerator::get_rewrite_path();
|
||||
$root_suffix_output = apply_filters( 'webpc_htaccess_rewrite_output', $root_suffix, $document_root );
|
||||
$output_path = apply_filters( 'webpc_dir_name', '', 'webp' );
|
||||
if ( $output_path_suffix !== null ) {
|
||||
$output_path .= '/' . $output_path_suffix;
|
||||
}
|
||||
|
||||
$content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
|
||||
$content .= ' RewriteEngine On' . PHP_EOL;
|
||||
if ( apply_filters( 'webpc_htaccess_mod_rewrite_inherit', ! $settings[ RewriteInheritanceOption::OPTION_NAME ] ) === true ) {
|
||||
$content .= ' RewriteOptions Inherit' . PHP_EOL;
|
||||
}
|
||||
|
||||
$content .= PHP_EOL;
|
||||
$content .= ' ' . apply_filters( 'webpc_htaccess_original_cond', 'RewriteCond %{QUERY_STRING} original$' ) . PHP_EOL;
|
||||
$content .= ' RewriteCond %{REQUEST_FILENAME} -f' . PHP_EOL;
|
||||
$content .= ' RewriteRule . - [L]' . PHP_EOL;
|
||||
|
||||
foreach ( $this->format_factory->get_mime_types() as $format => $mime_type ) {
|
||||
$content .= PHP_EOL;
|
||||
foreach ( $settings[ SupportedExtensionsOption::OPTION_NAME ] as $ext ) {
|
||||
if ( $format === $ext ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content .= " RewriteCond %{HTTP_ACCEPT} {$mime_type}" . PHP_EOL;
|
||||
if ( in_array( ExtraFeaturesOption::OPTION_VALUE_ONLY_SMALLER, $settings[ ExtraFeaturesOption::OPTION_NAME ] ) ) {
|
||||
$content .= " RewriteCond %{REQUEST_FILENAME} -f" . PHP_EOL;
|
||||
}
|
||||
|
||||
if ( $document_root === '%{DOCUMENT_ROOT}/' ) {
|
||||
$content .= " RewriteCond %{DOCUMENT_ROOT}/{$output_path}/$1.{$ext}.{$format} -f" . PHP_EOL;
|
||||
} elseif ( strpos( $document_root, '%{DOCUMENT_ROOT}' ) !== false ) {
|
||||
$content .= " RewriteCond {$document_root}{$output_path}/$1.{$ext}.{$format} -f [OR]" . PHP_EOL;
|
||||
$content .= " RewriteCond %{DOCUMENT_ROOT}/{$output_path}/$1.{$ext}.{$format} -f" . PHP_EOL;
|
||||
} else {
|
||||
$content .= " RewriteCond {$document_root}{$output_path}/$1.{$ext}.{$format} -f [OR]" . PHP_EOL;
|
||||
$content .= " RewriteCond %{DOCUMENT_ROOT}{$root_suffix}{$output_path}/$1.{$ext}.{$format} -f" . PHP_EOL;
|
||||
}
|
||||
|
||||
if ( apply_filters( 'webpc_htaccess_mod_rewrite_referer', false ) === true ) {
|
||||
$content .= " RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} ^([^@]*)@@https?://\\1/.*" . PHP_EOL;
|
||||
}
|
||||
$content .= " RewriteRule (.+)\.{$ext}$ {$root_suffix_output}{$output_path}/$1.{$ext}.{$format} [NC,T={$mime_type},L]" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$content .= '</IfModule>' . PHP_EOL;
|
||||
|
||||
return apply_filters( 'webpc_htaccess_mod_rewrite', trim( $content ), $output_path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates rules for mod_headers.
|
||||
*
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
protected function get_mod_headers_rules( array $settings ): string {
|
||||
$content = '';
|
||||
$extensions = implode( '|', $settings[ SupportedExtensionsOption::OPTION_NAME ] );
|
||||
|
||||
$cache_control = true;
|
||||
if ( $settings[ CloudflareZoneIdOption::OPTION_NAME ] && $settings[ CloudflareApiTokenOption::OPTION_NAME ]
|
||||
&& OptionsAccessManager::get_option( CloudflareConfigurator::REQUEST_CACHE_CONFIG_OPTION ) === 'yes' ) {
|
||||
$cache_control = false;
|
||||
} elseif ( EnvDetector::is_cdn_bunny() ) {
|
||||
$cache_control = false;
|
||||
}
|
||||
|
||||
$content .= '<IfModule mod_headers.c>' . PHP_EOL;
|
||||
if ( $extensions ) {
|
||||
$content .= ' <FilesMatch "(?i)\.(' . $extensions . ')(\.(webp|avif))?$">' . PHP_EOL;
|
||||
}
|
||||
if ( apply_filters( 'webpc_htaccess_cache_control_private', $cache_control ) ) {
|
||||
$content .= ' Header always set Cache-Control "private"' . PHP_EOL;
|
||||
$content .= ' Header always set X-LiteSpeed-Cache-Control "no-cache"' . PHP_EOL;
|
||||
}
|
||||
$content .= ' Header append Vary "Accept"' . PHP_EOL;
|
||||
if ( $extensions ) {
|
||||
$content .= ' </FilesMatch>' . PHP_EOL;
|
||||
}
|
||||
$content .= '</IfModule>';
|
||||
|
||||
return apply_filters( 'webpc_htaccess_mod_headers', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates rules for mod_expires.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
private function get_mod_expires_rules(): string {
|
||||
$content = '';
|
||||
|
||||
$content .= '<IfModule mod_expires.c>' . PHP_EOL;
|
||||
$content .= ' ExpiresActive On' . PHP_EOL;
|
||||
foreach ( $this->format_factory->get_mime_types() as $format => $mime_type ) {
|
||||
$content .= " ExpiresByType {$mime_type} \"access plus 1 year\"" . PHP_EOL;
|
||||
}
|
||||
$content .= '</IfModule>';
|
||||
|
||||
return apply_filters( 'webpc_htaccess_mod_expires', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates rules that add support for output formats.
|
||||
*
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
private function get_mod_mime_rules( array $settings ): string {
|
||||
$content = '';
|
||||
if ( ! $settings[ SupportedExtensionsOption::OPTION_NAME ] ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$content .= '<IfModule mod_mime.c>' . PHP_EOL;
|
||||
foreach ( $this->format_factory->get_mime_types() as $format => $mime_type ) {
|
||||
$content .= " AddType {$mime_type} .{$format}" . PHP_EOL;
|
||||
}
|
||||
$content .= '</IfModule>';
|
||||
|
||||
return apply_filters( 'webpc_htaccess_mod_mime', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds comments before and after rules for .htaccess file.
|
||||
*
|
||||
* @param string[] $rules Rules for .htaccess file.
|
||||
*
|
||||
* @return string Rules for .htaccess file.
|
||||
*/
|
||||
private function add_comments_to_rules( array $rules ): string {
|
||||
if ( ! $rules ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$rows = [];
|
||||
$rows[] = '';
|
||||
$rows[] = '# BEGIN Converter for Media';
|
||||
$rows[] = '# ! --- DO NOT EDIT PREVIOUS LINE --- !';
|
||||
$rows = array_merge( $rows, array_filter( $rules ) );
|
||||
$rows[] = '# ! --- DO NOT EDIT NEXT LINE --- !';
|
||||
$rows[] = '# END Converter for Media';
|
||||
$rows[] = '';
|
||||
|
||||
return implode( PHP_EOL, $rows );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves rules to .htaccess file in selected location.
|
||||
*
|
||||
* @param string $path_dir Location of .htaccess file.
|
||||
* @param string $rules Rules for .htaccess file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_rewrites_in_htaccesss( string $path_dir, string $rules = '' ) {
|
||||
$path_file = $path_dir . '/.htaccess';
|
||||
|
||||
$code = ( is_readable( $path_file ) ) ? file_get_contents( $path_file ) ?: '' : '';
|
||||
$code = preg_replace(
|
||||
'/((:?[\r\n|\r|\n]?)# BEGIN (Converter for Media|WebP Converter)(.*?)# END (Converter for Media|WebP Converter)(:?(:?[\r\n|\r|\n]+)?))/s',
|
||||
'',
|
||||
$code
|
||||
);
|
||||
if ( $rules && $code ) {
|
||||
$code = PHP_EOL . $code;
|
||||
}
|
||||
$code = $rules . $code;
|
||||
|
||||
if ( is_writable( $path_dir ) ) {
|
||||
file_put_contents( $path_file, $code );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
use WebpConverter\Conversion\Format\FormatFactory;
|
||||
use WebpConverter\PluginData;
|
||||
use WebpConverter\PluginInfo;
|
||||
use WebpConverter\Settings\Option\LoaderTypeOption;
|
||||
|
||||
/**
|
||||
* Abstract class for class that supports method of loading images.
|
||||
*/
|
||||
abstract class LoaderAbstract implements LoaderInterface {
|
||||
|
||||
const ACTION_NAME = 'webpc_refresh_loader';
|
||||
|
||||
/**
|
||||
* @var PluginInfo
|
||||
*/
|
||||
protected $plugin_info;
|
||||
|
||||
/**
|
||||
* @var PluginData
|
||||
*/
|
||||
protected $plugin_data;
|
||||
|
||||
/**
|
||||
* @var FormatFactory
|
||||
*/
|
||||
protected $format_factory;
|
||||
|
||||
public function __construct( PluginInfo $plugin_info, PluginData $plugin_data, FormatFactory $format_factory ) {
|
||||
$this->plugin_info = $plugin_info;
|
||||
$this->plugin_data = $plugin_data;
|
||||
$this->format_factory = $format_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function is_active_loader(): bool {
|
||||
$settings = $this->plugin_data->get_plugin_settings();
|
||||
return ( $settings[ LoaderTypeOption::OPTION_NAME ] === $this->get_type() );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_admin_hooks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_front_end_hooks() {
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
use WebpConverter\HookableInterface;
|
||||
|
||||
/**
|
||||
* Adds integration with active method of loading images.
|
||||
*/
|
||||
class LoaderIntegrator implements HookableInterface {
|
||||
|
||||
/**
|
||||
* Object of image loader method.
|
||||
*
|
||||
* @var LoaderInterface
|
||||
*/
|
||||
private $loader;
|
||||
|
||||
public function __construct( LoaderInterface $loader ) {
|
||||
$this->loader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_hooks() {
|
||||
add_action( LoaderAbstract::ACTION_NAME, [ $this, 'refresh_active_loader' ], 20, 2 );
|
||||
add_action( LoaderAbstract::ACTION_NAME, [ $this, 'refresh_inactive_loader' ] );
|
||||
add_action( 'webpc_settings_page_loaded', [ $this, 'load_admin_actions' ], 0 );
|
||||
add_action( 'init', [ $this, 'load_front_end_actions' ], 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $is_active .
|
||||
* @param bool $is_debug .
|
||||
*
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function refresh_active_loader( bool $is_active, bool $is_debug = false ) {
|
||||
if ( $is_active && $this->loader->is_active_loader() ) {
|
||||
$this->loader->activate_loader( $is_debug );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $is_active .
|
||||
*
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function refresh_inactive_loader( bool $is_active ) {
|
||||
if ( ! $is_active || ! $this->loader->is_active_loader() ) {
|
||||
$this->loader->deactivate_loader();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function load_admin_actions() {
|
||||
if ( $this->loader->is_active_loader() ) {
|
||||
$this->loader->init_admin_hooks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function load_front_end_actions() {
|
||||
if ( $this->loader->is_active_loader() && ( apply_filters( 'webpc_server_errors', [], true ) === [] ) ) {
|
||||
$this->loader->init_front_end_hooks();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
/**
|
||||
* Interface for class that supports method of loading images.
|
||||
*/
|
||||
interface LoaderInterface {
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_type(): string;
|
||||
|
||||
/**
|
||||
* Returns status if loader is active.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active_loader(): bool;
|
||||
|
||||
/**
|
||||
* Integrates with WordPress hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init_admin_hooks();
|
||||
|
||||
/**
|
||||
* Integrates with WordPress hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init_front_end_hooks();
|
||||
|
||||
/**
|
||||
* Initializes actions for activating loader.
|
||||
*
|
||||
* @param bool $is_debug Is debugging?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate_loader( bool $is_debug = false );
|
||||
|
||||
/**
|
||||
* Initializes actions for deactivating loader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate_loader();
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace WebpConverter\Loader;
|
||||
|
||||
use WebpConverter\Settings\Option\OutputFormatsOption;
|
||||
use WebpConverter\Settings\Option\SupportedDirectoriesOption;
|
||||
use WebpConverter\Settings\Option\SupportedExtensionsOption;
|
||||
|
||||
/**
|
||||
* Supports method of loading images using .php file as Pass Thru.
|
||||
*/
|
||||
class PassthruLoader extends LoaderAbstract {
|
||||
|
||||
const LOADER_TYPE = 'passthru';
|
||||
const PATH_LOADER = '/webpc-passthru.php';
|
||||
const LOADER_SOURCE = '/includes/passthru.php';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_type(): string {
|
||||
return self::LOADER_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_admin_hooks() {
|
||||
add_filter( 'webpc_debug_image_url', [ $this, 'update_image_urls' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init_front_end_hooks() {
|
||||
add_action( 'init', [ $this, 'start_buffering' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function activate_loader( bool $is_debug = false ) {
|
||||
$settings = ( ! $is_debug ) ? $this->plugin_data->get_plugin_settings() : $this->plugin_data->get_plugin_settings_debug();
|
||||
$path_source = $this->plugin_info->get_plugin_directory_path() . self::LOADER_SOURCE;
|
||||
$source_code = ( is_readable( $path_source ) ) ? file_get_contents( $path_source ) ?: '' : '';
|
||||
if ( ! $source_code ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path_dir_uploads = apply_filters( 'webpc_dir_name', '', 'uploads' );
|
||||
$path_dir_webp = apply_filters( 'webpc_dir_name', '', 'webp' );
|
||||
$upload_suffix = implode( '/', array_diff( explode( '/', $path_dir_uploads ), explode( '/', $path_dir_webp ) ) );
|
||||
$mime_types = $this->format_factory->get_mime_types( $settings[ OutputFormatsOption::OPTION_NAME ] );
|
||||
|
||||
$source_code = preg_replace(
|
||||
'/(PATH_UPLOADS(?:\s+)= \')(\')/',
|
||||
'$1/' . $path_dir_uploads . '/$2',
|
||||
$source_code
|
||||
);
|
||||
$source_code = preg_replace(
|
||||
'/(PATH_UPLOADS_WEBP(?:\s+)= \')(\')/',
|
||||
'$1/' . $path_dir_webp . '/' . $upload_suffix . '/$2',
|
||||
$source_code ?: ''
|
||||
);
|
||||
$source_code = preg_replace(
|
||||
'/(MIME_TYPES(?:\s+)= \')(\')/',
|
||||
'$1' . json_encode( $mime_types ) . '$2',
|
||||
$source_code ?: ''
|
||||
);
|
||||
|
||||
$dir_output = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) );
|
||||
if ( is_writable( $dir_output ) ) {
|
||||
file_put_contents( $dir_output . self::PATH_LOADER, $source_code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deactivate_loader() {
|
||||
$dir_output = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) ) . self::PATH_LOADER;
|
||||
if ( is_writable( $dir_output ) ) {
|
||||
unlink( $dir_output );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function start_buffering() {
|
||||
if ( ! ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || ( ! is_admin() && ! is_network_admin() ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start(
|
||||
function ( $buffer ) {
|
||||
return $this->update_image_urls( $buffer );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces URLs to source images in output buffer.
|
||||
*
|
||||
* @param string $buffer Contents of output buffer.
|
||||
* @param bool $is_debug Is debugging?
|
||||
*
|
||||
* @return string Contents of output buffer.
|
||||
* @internal
|
||||
*/
|
||||
public function update_image_urls( string $buffer, bool $is_debug = false ): string {
|
||||
$settings = ( ! $is_debug ) ? $this->plugin_data->get_plugin_settings() : $this->plugin_data->get_plugin_settings_debug();
|
||||
$extensions = implode( '|', $settings[ SupportedExtensionsOption::OPTION_NAME ] );
|
||||
if ( ! $extensions ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$source_dir = $this->get_loader_url();
|
||||
$allowed_dirs = $this->get_allowed_dirs( $settings );
|
||||
if ( ! $source_dir || ! $allowed_dirs ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$dir_paths = str_replace( '/', '\\/', implode( '|', $allowed_dirs ) );
|
||||
$has_nocache = apply_filters( 'webpc_passthru_url_nocache', true );
|
||||
|
||||
return preg_replace(
|
||||
'/(https?:\/\/(?:[^\s()"\']+)(?:' . $dir_paths . ')(?:[^\s()"\']+)\.(?:' . $extensions . '))/',
|
||||
$source_dir . '?src=$1' . ( ( $has_nocache ) ? '&nocache=1' : '' ),
|
||||
$buffer
|
||||
) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns URL for Passthru loader.
|
||||
*
|
||||
* @return string|null URL of source PHP file.
|
||||
*/
|
||||
public static function get_loader_url() {
|
||||
if ( ! $source_dir = dirname( apply_filters( 'webpc_dir_url', '', 'uploads' ) ) ) {
|
||||
return null;
|
||||
}
|
||||
return $source_dir . self::PATH_LOADER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of directories for which redirection from source images to output images.
|
||||
*
|
||||
* @param mixed[] $settings Plugin settings.
|
||||
*
|
||||
* @return string[] List of directories names.
|
||||
*/
|
||||
private function get_allowed_dirs( array $settings ): array {
|
||||
$dirs = [];
|
||||
foreach ( $settings[ SupportedDirectoriesOption::OPTION_NAME ] as $dir ) {
|
||||
$dirs[] = apply_filters( 'webpc_dir_name', '', $dir );
|
||||
}
|
||||
return array_filter( $dirs );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user