$server,
'is_nginx' => $is_ng,
'exists' => $exists,
'writable' => $write,
'supported' => ! $is_ng && $exists,
'active' => $browser_active,
'page_cache_active' => $page_cache_active,
'webp_active' => $webp_active,
);
}
/**
* Build Apache / LiteSpeed static asset caching & deflate rules.
*/
public static function get_rules() {
return array(
'',
' ExpiresActive On',
' ExpiresDefault "access plus 1 month"',
' ExpiresByType text/html "access plus 0 seconds"',
' ExpiresByType text/xml "access plus 0 seconds"',
' ExpiresByType application/xml "access plus 0 seconds"',
' ExpiresByType application/json "access plus 0 seconds"',
' ExpiresByType text/css "access plus 1 year"',
' ExpiresByType text/javascript "access plus 1 year"',
' ExpiresByType application/javascript "access plus 1 year"',
' ExpiresByType application/x-javascript "access plus 1 year"',
' ExpiresByType image/jpeg "access plus 1 year"',
' ExpiresByType image/png "access plus 1 year"',
' ExpiresByType image/gif "access plus 1 year"',
' ExpiresByType image/webp "access plus 1 year"',
' ExpiresByType image/avif "access plus 1 year"',
' ExpiresByType image/svg+xml "access plus 1 year"',
' ExpiresByType image/x-icon "access plus 1 year"',
' ExpiresByType font/woff2 "access plus 1 year"',
' ExpiresByType font/woff "access plus 1 year"',
' ExpiresByType font/ttf "access plus 1 year"',
' ExpiresByType font/otf "access plus 1 year"',
' ExpiresByType application/font-woff2 "access plus 1 year"',
' ExpiresByType application/font-woff "access plus 1 year"',
'',
'',
' ',
' Header set Cache-Control "public, max-age=31536000"',
' ',
' Header append Vary Accept-Encoding',
'',
'',
' AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml font/ttf font/otf',
'',
);
}
/**
* Build Zero-PHP Direct Disk Page Cache mod_rewrite block (must precede # BEGIN WordPress).
*/
public static function build_page_cache_block( $options = null ) {
if ( ! is_array( $options ) ) {
$options = get_option( 'aio_options', array() );
}
$upload_dir = wp_upload_dir();
$norm_abspath = trailingslashit( wp_normalize_path( ABSPATH ) );
$norm_cache = trailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . 'aio-cache';
if ( strpos( $norm_cache, $norm_abspath ) !== 0 ) {
return '';
}
$rel_cache = ltrim( substr( $norm_cache, strlen( $norm_abspath ) ), '/' );
$home_sub = trim( (string) wp_parse_url( home_url(), PHP_URL_PATH ), '/' );
$uri_base = $home_sub !== '' ? '/' . preg_replace( '/[^A-Za-z0-9\/_.-]/', '', $home_sub ) : '';
$ignore_tracking = ! isset( $options['optCacheIgnoreTracking'] ) || ! empty( $options['optCacheIgnoreTracking'] );
$qs_cond = $ignore_tracking
? ' RewriteCond %{QUERY_STRING} ^(?:&*(?:utm_(?:source|medium|campaign|term|content|id)|fbclid|gclid|dclid|msclkid|ttclid|twclid|yclid|zarsrc|_ga|_gl|mc_cid|mc_eid)=[^&]*)*$ [NC]'
: ' RewriteCond %{QUERY_STRING} ^$';
$cookies = array(
'wordpress_logged_in_',
'wp-postpass_',
'woocommerce_items_in_cart',
'wp_woocommerce_session_',
'aio_maint_bypass',
'comment_author_',
);
if ( ! empty( $options['optCacheExcludeCookies'] ) ) {
foreach ( preg_split( '/[\r\n]+/', (string) $options['optCacheExcludeCookies'] ) as $c ) {
$clean_c = preg_replace( '/[^A-Za-z0-9_-]/', '', trim( $c ) );
if ( $clean_c !== '' ) {
$cookies[] = $clean_c;
}
}
}
$cookie_cond = ' RewriteCond %{HTTP_COOKIE} !(' . implode( '|', array_unique( $cookies ) ) . ') [NC]';
$uri_exclude_lines = array();
if ( ! empty( $options['optCacheExcludeUrls'] ) ) {
foreach ( preg_split( '/[\r\n]+/', (string) $options['optCacheExcludeUrls'] ) as $u ) {
$clean_u = preg_replace( '/[^A-Za-z0-9\/_.-]/', '', trim( $u ) );
if ( $clean_u !== '' ) {
$uri_exclude_lines[] = ' RewriteCond %{REQUEST_URI} !' . preg_quote( $clean_u, '#' ) . ' [NC]';
}
}
}
$common_conds = array_merge(
array(
' RewriteCond %{REQUEST_METHOD} ^GET$',
$qs_cond,
$cookie_cond,
),
$uri_exclude_lines
);
$lines = array(
'# BEGIN ' . self::PAGE_CACHE_MARKER,
'',
' RewriteEngine On',
' # Serve pre-compressed HTTPS .html.gz directly from disk (0ms PHP)',
' RewriteCond %{HTTPS} =on [OR]',
' RewriteCond %{HTTP:X-Forwarded-Proto} =https',
);
$lines = array_merge(
$lines,
$common_conds,
array(
' RewriteCond %{HTTP:Accept-Encoding} gzip [NC]',
' RewriteCond "' . $norm_cache . '/https-%{HTTP_HOST}' . $uri_base . '/$1/index.html.gz" -f',
' RewriteRule ^(.*?)/?$ ' . $rel_cache . '/https-%{HTTP_HOST}' . $uri_base . '/$1/index.html.gz [L,E=AIO_HIT:SERVER-GZIP]',
'',
' # Serve pre-compressed HTTP .html.gz directly from disk (0ms PHP)',
' RewriteCond %{HTTPS} !=on',
' RewriteCond %{HTTP:X-Forwarded-Proto} !=https',
),
$common_conds,
array(
' RewriteCond %{HTTP:Accept-Encoding} gzip [NC]',
' RewriteCond "' . $norm_cache . '/http-%{HTTP_HOST}' . $uri_base . '/$1/index.html.gz" -f',
' RewriteRule ^(.*?)/?$ ' . $rel_cache . '/http-%{HTTP_HOST}' . $uri_base . '/$1/index.html.gz [L,E=AIO_HIT:SERVER-GZIP]',
'',
' # Serve static HTTPS .html directly from disk',
' RewriteCond %{HTTPS} =on [OR]',
' RewriteCond %{HTTP:X-Forwarded-Proto} =https',
),
$common_conds,
array(
' RewriteCond "' . $norm_cache . '/https-%{HTTP_HOST}' . $uri_base . '/$1/index.html" -f',
' RewriteRule ^(.*?)/?$ ' . $rel_cache . '/https-%{HTTP_HOST}' . $uri_base . '/$1/index.html [L,E=AIO_HIT:SERVER]',
'',
' # Serve static HTTP .html directly from disk',
' RewriteCond %{HTTPS} !=on',
' RewriteCond %{HTTP:X-Forwarded-Proto} !=https',
),
$common_conds,
array(
' RewriteCond "' . $norm_cache . '/http-%{HTTP_HOST}' . $uri_base . '/$1/index.html" -f',
' RewriteRule ^(.*?)/?$ ' . $rel_cache . '/http-%{HTTP_HOST}' . $uri_base . '/$1/index.html [L,E=AIO_HIT:SERVER]',
'',
'',
' Header set X-AIO-Cache "HIT-SERVER-GZIP" env=REDIRECT_AIO_HIT',
' Header set X-AIO-Cache "HIT-SERVER-GZIP" env=AIO_HIT',
'',
'# END ' . self::PAGE_CACHE_MARKER,
)
);
return implode( "\n", $lines );
}
/**
* Build transparent WebP delivery mod_rewrite block for uploads directory.
* Works even when original .jpg/.png files were removed after WebP conversion!
*/
public static function build_webp_block() {
$upload_dir = wp_upload_dir();
$norm_abspath = trailingslashit( wp_normalize_path( ABSPATH ) );
$norm_uploads = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) );
if ( strpos( $norm_uploads, $norm_abspath ) !== 0 ) {
return '';
}
$rel_uploads = ltrim( substr( $norm_uploads, strlen( $norm_abspath ) ), '/' );
$rel_uploads_rx = str_replace( '.', '\.', $rel_uploads );
$lines = array(
'# BEGIN ' . self::WEBP_MARKER,
'',
' RewriteEngine On',
' RewriteCond %{DOCUMENT_ROOT}/' . $rel_uploads . '/$1.webp -f [OR]',
' RewriteCond "' . $norm_uploads . '/$1.webp" -f',
' RewriteRule ^' . $rel_uploads_rx . '/(.+)\.(?:jpe?g|png)$ ' . $rel_uploads . '/$1.webp [T=image/webp,E=AIO_WEBP:1,L]',
'',
' # Prevent missing static media in uploads from booting WordPress / MySQL 404 queries',
' RewriteCond %{REQUEST_FILENAME} !-f',
' RewriteRule ^' . $rel_uploads_rx . '/.+\.(?:jpe?g|png|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|css|js)$ - [R=404,L]',
'',
'',
' Header append Vary Accept env=REDIRECT_AIO_WEBP',
' Header append Vary Accept env=AIO_WEBP',
'',
'',
' AddType image/webp .webp',
'',
'# END ' . self::WEBP_MARKER,
);
return implode( "\n", $lines );
}
/**
* Prepend or remove # BEGIN AIO Tools Page Cache block above # BEGIN WordPress in .htaccess.
*/
public static function sync_page_cache( $enabled, $options = null ) {
$path = self::get_htaccess_path();
if ( ! file_exists( $path ) || ! is_readable( $path ) || ! is_writable( $path ) ) {
return false;
}
$server = isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
if ( stripos( $server, 'nginx' ) !== false ) {
return false;
}
$contents = (string) @file_get_contents( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
$pattern = '/# BEGIN ' . preg_quote( self::PAGE_CACHE_MARKER, '/' ) . '.*?# END ' . preg_quote( self::PAGE_CACHE_MARKER, '/' ) . '\r?\n*/s';
$cleaned = preg_replace( $pattern, '', $contents );
if ( ! is_string( $cleaned ) ) {
return false;
}
if ( $enabled ) {
$block = self::build_page_cache_block( $options );
if ( $block !== '' ) {
$cleaned = $block . "\n\n" . ltrim( $cleaned );
}
}
if ( $cleaned === $contents ) {
return true;
}
return (bool) @file_put_contents( $path, $cleaned, LOCK_EX ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
}
/**
* Prepend or remove # BEGIN AIO Tools WebP Delivery block above # BEGIN WordPress in .htaccess.
*/
public static function sync_webp_rewrite( $enabled ) {
$path = self::get_htaccess_path();
if ( ! file_exists( $path ) || ! is_readable( $path ) || ! is_writable( $path ) ) {
return false;
}
$server = isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
if ( stripos( $server, 'nginx' ) !== false ) {
return false;
}
$contents = (string) @file_get_contents( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
$pattern = '/# BEGIN ' . preg_quote( self::WEBP_MARKER, '/' ) . '.*?# END ' . preg_quote( self::WEBP_MARKER, '/' ) . '\r?\n*/s';
$cleaned = preg_replace( $pattern, '', $contents );
if ( ! is_string( $cleaned ) ) {
return false;
}
if ( $enabled ) {
$block = self::build_webp_block();
if ( $block !== '' ) {
// Place right before # BEGIN WordPress if present, otherwise prepend
if ( strpos( $cleaned, '# BEGIN WordPress' ) !== false ) {
$cleaned = str_replace( '# BEGIN WordPress', $block . "\n\n# BEGIN WordPress", $cleaned );
} else {
$cleaned = $block . "\n\n" . ltrim( $cleaned );
}
}
}
if ( $cleaned === $contents ) {
return true;
}
return (bool) @file_put_contents( $path, $cleaned, LOCK_EX ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
}
/**
* Synchronize Browser Cache & Static Gzip rules with plugin setting.
*
* @param bool $enabled Whether browser cache rules should be present.
* @return bool
*/
public static function sync( $enabled ) {
$path = self::get_htaccess_path();
if ( ! file_exists( $path ) || ! is_writable( $path ) ) {
return false;
}
if ( ! function_exists( 'insert_with_markers' ) && file_exists( ABSPATH . 'wp-admin/includes/misc.php' ) ) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
if ( ! function_exists( 'insert_with_markers' ) ) {
return false;
}
$lines = $enabled ? self::get_rules() : array();
return (bool) insert_with_markers( $path, self::MARKER, $lines );
}
/**
* Generate a copy-paste Nginx server {} block snippet for Zero-PHP Page Cache & WebP delivery.
*/
public static function get_nginx_config_snippet() {
$upload_dir = wp_upload_dir();
$uploads_url = (string) wp_parse_url( $upload_dir['baseurl'], PHP_URL_PATH );
$rel_uploads = '/' . trim( $uploads_url !== '' ? $uploads_url : '/wp-content/uploads', '/' );
$rel_cache = $rel_uploads . '/aio-cache';
$lines = array(
'# === AIO Tools Zero-PHP Nginx Page Cache & WebP Rules ===',
'set $aio_cache_bypass 0;',
'if ($request_method != GET) { set $aio_cache_bypass 1; }',
'if ($query_string !~* "^(?:&*(?:utm_(?:source|medium|campaign|term|content|id)|fbclid|gclid|dclid|msclkid|ttclid|twclid|yclid|zarsrc|_ga|_gl|mc_cid|mc_eid)=[^&]*)*$") {',
' set $aio_cache_bypass 1;',
'}',
'if ($http_cookie ~* "(wordpress_logged_in_|wp-postpass_|woocommerce_items_in_cart|wp_woocommerce_session_|aio_maint_bypass|comment_author_)") {',
' set $aio_cache_bypass 1;',
'}',
'set $aio_cache_uri $uri;',
'if ($aio_cache_bypass = 1) { set $aio_cache_uri "/__aio_bypass__"; }',
'',
'# 1. Zero-PHP Full-Page Cache (serves pre-compressed .html.gz via gzip_static)',
'location / {',
' gzip_static on;',
' add_header X-AIO-Cache "HIT-NGINX" always;',
' try_files ' . $rel_cache . '/$scheme-$host$aio_cache_uri/index.html $uri $uri/ /index.php?$args;',
'}',
'',
'# 2. Transparent WebP Delivery & 1-Year Static Browser Cache',
'location ~* ^(' . $rel_uploads . '/.+)\.(?:jpe?g|png)$ {',
' add_header Vary Accept;',
' expires 365d;',
' try_files $1.webp $uri =404;',
'}',
'location ~* \.(?:css|js|webp|avif|gif|svg|ico|woff2?|ttf|otf)$ {',
' expires 365d;',
' add_header Cache-Control "public, max-age=31536000, immutable";',
'}',
);
return implode( "\n", $lines );
}
/**
* Remove all AIO Tools Page Cache, WebP Delivery, and Browser Cache rules from root .htaccess.
*/
public static function remove() {
self::sync_page_cache( false );
self::sync_webp_rewrite( false );
return self::sync( false );
}
}