rewriter — tüm sunucularda çalışır (fallback) * * Mantık: görseller .jpg/.png olarak HTML'de durur, sunucu veya PHP * WebP destekleyen tarayıcılara şeffaf olarak .webp gönderir. * Böylece hem orijinal hem WebP korunabilir, eski tarayıcılar kırılmaz. */ class ERDO_WebP_Server { const HTACCESS_MARKER = 'Erdo WebP'; /* ------------------------------------------------------------------ KURULUM / KALDIRMA ------------------------------------------------------------------ */ public static function init() { if ( ! get_option( 'erdo_serve_webp' ) ) { return; } $method = get_option( 'erdo_webp_serve_method', 'picture' ); if ( 'htaccess' === $method && self::is_apache() ) { // .htaccess zaten yazılmış, ek PHP işlemi yok. return; } // PHP picture rewriter — front-end filtreler add_filter( 'the_content', array( __CLASS__, 'rewrite_html' ), 99 ); add_filter( 'post_thumbnail_html', array( __CLASS__, 'rewrite_html' ), 99 ); add_filter( 'wp_get_attachment_image',array( __CLASS__, 'rewrite_html' ), 99 ); } /* ------------------------------------------------------------------ SUNUCU TESPİTİ ------------------------------------------------------------------ */ public static function is_apache() { $software = sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ?? '' ) ); return stripos( $software, 'apache' ) !== false; } public static function is_nginx() { $software = sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ?? '' ) ); return stripos( $software, 'nginx' ) !== false; } /* ------------------------------------------------------------------ .HTACCESS KURULUM / KALDIRMA ------------------------------------------------------------------ */ public static function write_htaccess_rules() { $upload_dir = wp_upload_dir(); $htaccess = trailingslashit( $upload_dir['basedir'] ) . '.htaccess'; $rules = "\n# BEGIN " . self::HTACCESS_MARKER . "\n" . "\n" . " RewriteEngine On\n" . " RewriteCond %{HTTP_ACCEPT} image/webp\n" . " RewriteCond %{REQUEST_FILENAME} \\.(jpe?g|png|gif)$\n" . " RewriteCond %{REQUEST_FILENAME}\\.webp -f\n" . " RewriteRule ^ %{REQUEST_URI}.webp [L,T=image/webp]\n" . "\n" . "\n" . " \n" . " Header append Vary Accept\n" . " \n" . "\n" . "# END " . self::HTACCESS_MARKER . "\n"; $existing = file_exists( $htaccess ) ? file_get_contents( $htaccess ) : ''; // phpcs:ignore WordPress.WP.AlternativeFunctions if ( strpos( $existing, '# BEGIN ' . self::HTACCESS_MARKER ) !== false ) { // Zaten var — güncelle $pattern = '/# BEGIN ' . preg_quote( self::HTACCESS_MARKER, '/' ) . '.*?# END ' . preg_quote( self::HTACCESS_MARKER, '/' ) . '\n?/s'; $existing = preg_replace( $pattern, '', $existing ); } file_put_contents( $htaccess, $existing . $rules ); // phpcs:ignore WordPress.WP.AlternativeFunctions } public static function remove_htaccess_rules() { $upload_dir = wp_upload_dir(); $htaccess = trailingslashit( $upload_dir['basedir'] ) . '.htaccess'; if ( ! file_exists( $htaccess ) ) { return; } $content = file_get_contents( $htaccess ); // phpcs:ignore WordPress.WP.AlternativeFunctions $pattern = '/# BEGIN ' . preg_quote( self::HTACCESS_MARKER, '/' ) . '.*?# END ' . preg_quote( self::HTACCESS_MARKER, '/' ) . '\n?/s'; $content = preg_replace( $pattern, '', $content ); file_put_contents( $htaccess, $content ); // phpcs:ignore WordPress.WP.AlternativeFunctions } /* ------------------------------------------------------------------ NGINX KURAL METNİ ------------------------------------------------------------------ */ public static function get_nginx_config() { $upload_path = str_replace( ABSPATH, '/', wp_upload_dir()['basedir'] ); return "# Nginx sunucunuzun site konfigürasyonuna ekleyin:\n" . "location ~* ^" . $upload_path . ".*\\.(jpe?g|png|gif)$ {\n" . " add_header Vary Accept;\n" . " try_files \$uri.webp \$uri =404;\n" . "}"; } /* ------------------------------------------------------------------ PHP REWRITER ------------------------------------------------------------------ */ /** * HTML içindeki etiketlerini, eğer .webp karşılığı diskte mevcutsa * ile sarar. */ public static function rewrite_html( $html ) { if ( empty( $html ) || is_admin() ) { return $html; } return preg_replace_callback( '/]+)>/i', array( __CLASS__, 'replace_img_tag' ), $html ); } private static function replace_img_tag( $matches ) { $attrs = $matches[1]; $orig_tag = $matches[0]; // src özelliğini al if ( ! preg_match( '/\bsrc=["\']([^"\']+)["\']/', $attrs, $src_m ) ) { return $orig_tag; } $src = $src_m[1]; // Sadece uploads dizinindeki görseller $upload_dir = wp_upload_dir(); if ( strpos( $src, $upload_dir['baseurl'] ) === false ) { return $orig_tag; } // .jpg/.png/.gif uzantılı mı? if ( ! preg_match( '/\.(jpe?g|png|gif)(\?.*)?$/i', $src, $ext_m ) ) { return $orig_tag; } // WebP karşılığı URL ve yolu hesapla $src_clean = strtok( $src, '?' ); $webp_url = preg_replace( '/\.(jpe?g|png|gif)$/i', '.webp', $src_clean ); $webp_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $webp_url ); if ( ! file_exists( $webp_path ) ) { return $orig_tag; } // srcset varsa onu da dönüştür $srcset_html = ''; if ( preg_match( '/\bsrcset=["\']([^"\']+)["\']/', $attrs, $ss_m ) ) { $webp_srcset = preg_replace( '/\.(jpe?g|png|gif)/i', '.webp', $ss_m[1] ); $srcset_html = ' srcset="' . esc_attr( $webp_srcset ) . '"'; } return '' . '' . $orig_tag . ''; } /* ------------------------------------------------------------------ .HTACCESS DURUMU ------------------------------------------------------------------ */ public static function htaccess_has_rules() { $upload_dir = wp_upload_dir(); $htaccess = trailingslashit( $upload_dir['basedir'] ) . '.htaccess'; if ( ! file_exists( $htaccess ) ) { return false; } return strpos( file_get_contents( $htaccess ), '# BEGIN ' . self::HTACCESS_MARKER ) !== false; // phpcs:ignore WordPress.WP.AlternativeFunctions } }