Wordpress Görselleri Webp. çevirme eklentisi önerisi
8
●172
- 29-08-2026, 18:43:15çevirmede bir sınır varmı hocamWxTimer adlı üyeden alıntı: mesajı görüntüle
- 29-08-2026, 18:43:50https://saerasoft.com/caesium/
buradaki ücretsiz programı kullanıyorum. Çok fazla görseliniz yoksa hepsini indirip toplu halde program ile webp formatına çevirip tek tek ilgili konularda güncelleyebilirsiniz. Sonraki süreçte de 1 dakika vakit ayırıp önceden görselinizi webp formatına çevirip öyle sitenizdeki yazıya ekleyebilirsiniz. - 29-08-2026, 18:44:097gb görselleri 3 4gb düşürdüğünü hatırlıyorum hocam öyle anlatayım size her optimizasyon yaptığımız sitede kullanırız. Hiçbir sorun yaşamadık bu zamana kadarAlpagu adlı üyeden alıntı: mesajı görüntüle
- 29-08-2026, 18:45:14hocam sınır derken şöyle diyim wordpress 1 görseli evirip çevirip 8 tane çogaltıyor . şimdilik 1000'e yakın görsel var şuan için. ileride daha fazla olur diye düşünüyorum görsel çevirmede sınırlımıdır.WxTimer adlı üyeden alıntı: mesajı görüntüle
- 29-08-2026, 18:51:23Alpagu adlı üyeden alıntı: mesajı görüntüle
<?php /** * Plugin Name: WD WebP Dönüştürücü * Plugin URI: https://webdanismani.com * Description: WordPress & WooCommerce'e yüklenen tüm JPEG/PNG görselleri otomatik olarak WebP formatına dönüştürür. Mevcut medya kütüphanesi için toplu dönüştürme aracı içerir. * Version: 1.0.0 * Author: Web Danışmanı * Author URI: https://webdanismani.com * License: GPL-2.0-or-later * Text Domain: wd-webp * Requires at least: 5.8 * Requires PHP: 7.4 */ if ( ! defined( 'ABSPATH' ) ) { exit; } final class WD_WebP_Converter { const OPTION = 'wd_webp_settings'; private static $instance = null; public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } private function __construct() { // Yükleme anında dönüştürme (medya kütüphanesi, WooCommerce, REST, sideload — hepsi bu iki filtreden geçer) add_filter( 'wp_handle_upload', array( $this, 'convert_on_upload' ) ); add_filter( 'wp_handle_sideload', array( $this, 'convert_on_upload' ) ); // Yönetim add_action( 'admin_menu', array( $this, 'admin_menu' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); add_action( 'wp_ajax_wd_webp_bulk', array( $this, 'ajax_bulk' ) ); add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'action_links' ) ); register_uninstall_hook( __FILE__, array( 'WD_WebP_Converter', 'uninstall' ) ); } public static function uninstall() { delete_option( self::OPTION ); delete_post_meta_by_key( '_wd_webp_failed' ); } /* ------------------------------------------------------------------ * Ayarlar * ---------------------------------------------------------------- */ public function settings() { $defaults = array( 'enabled' => 1, 'quality' => 82, 'convert_jpeg' => 1, 'convert_png' => 1, 'keep_original' => 0, ); return wp_parse_args( (array) get_option( self::OPTION, array() ), $defaults ); } public function register_settings() { register_setting( 'wd_webp', self::OPTION, array( 'sanitize_callback' => array( $this, 'sanitize_settings' ) ) ); } public function sanitize_settings( $in ) { $in = (array) $in; return array( 'enabled' => empty( $in['enabled'] ) ? 0 : 1, 'quality' => max( 1, min( 100, (int) ( isset( $in['quality'] ) ? $in['quality'] : 82 ) ) ), 'convert_jpeg' => empty( $in['convert_jpeg'] ) ? 0 : 1, 'convert_png' => empty( $in['convert_png'] ) ? 0 : 1, 'keep_original' => empty( $in['keep_original'] ) ? 0 : 1, ); } public function action_links( $links ) { array_unshift( $links, '<a href="' . esc_url( admin_url( 'options-general.php?page=wd-webp' ) ) . '">Ayarlar</a>' ); return $links; } /* ------------------------------------------------------------------ * Sunucu yetenekleri * ---------------------------------------------------------------- */ private function imagick_webp() { if ( ! class_exists( 'Imagick' ) ) { return false; } try { return count( Imagick::queryFormats( 'WEBP' ) ) > 0; } catch ( Exception $e ) { return false; } } private function gd_webp() { if ( ! function_exists( 'imagewebp' ) || ! function_exists( 'gd_info' ) ) { return false; } $gd = gd_info(); return ! empty( $gd['WebP Support'] ); } private function webp_supported() { return $this->imagick_webp() || $this->gd_webp(); } /* ------------------------------------------------------------------ * Yükleme anında dönüştürme * ---------------------------------------------------------------- */ public function convert_on_upload( $upload ) { $s = $this->settings(); if ( empty( $s['enabled'] ) ) { return $upload; } if ( ! is_array( $upload ) || empty( $upload['file'] ) || empty( $upload['type'] ) || ! empty( $upload['error'] ) ) { return $upload; } $allowed = array(); if ( ! empty( $s['convert_jpeg'] ) ) { $allowed[] = 'image/jpeg'; } if ( ! empty( $s['convert_png'] ) ) { $allowed[] = 'image/png'; } if ( ! in_array( $upload['type'], $allowed, true ) ) { return $upload; } // Sunucu WebP üretemiyorsa veya WP küçük boyutları WebP'den oluşturamayacaksa dokunma if ( ! $this->webp_supported() || ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { return $upload; } $file = wp_normalize_path( $upload['file'] ); $webp = $this->unique_webp_path( $file ); if ( ! $this->convert_image( $file, $webp, (int) $s['quality'] ) ) { return $upload; // dönüştürülemezse orijinal akış devam eder } // Nadiren WebP daha büyük çıkabilir; o zaman vazgeç if ( filesize( $webp ) >= filesize( $file ) ) { @unlink( $webp ); return $upload; } if ( empty( $s['keep_original'] ) ) { @unlink( $file ); } $upload['url'] = str_replace( wp_basename( $upload['file'] ), wp_basename( $webp ), $upload['url'] ); $upload['file'] = $webp; $upload['type'] = 'image/webp'; return $upload; } /* ------------------------------------------------------------------ * Çekirdek dönüştürücü (Imagick öncelikli, GD yedek) * ---------------------------------------------------------------- */ private function convert_image( $source, $dest, $quality ) { $quality = max( 1, min( 100, (int) $quality ) ); $info = @getimagesize( $source ); if ( ! $info || empty( $info['mime'] ) ) { return false; } $mime = $info['mime']; if ( ! in_array( $mime, array( 'image/jpeg', 'image/png' ), true ) ) { return false; } // 1) Imagick if ( $this->imagick_webp() ) { try { $im = new Imagick( $source ); // EXIF yönünü piksellere uygula (telefon fotoğrafları yan dönmesin) switch ( $im->getImageOrientation() ) { case Imagick::ORIENTATION_BOTTOMRIGHT: $im->rotateImage( '#000', 180 ); break; case Imagick::ORIENTATION_RIGHTTOP: $im->rotateImage( '#000', 90 ); break; case Imagick::ORIENTATION_LEFTBOTTOM: $im->rotateImage( '#000', -90 ); break; } $im->setImageOrientation( Imagick::ORIENTATION_TOPLEFT ); // Renk profili varsa sRGB'ye çevirip metadata'yı temizle (dosya küçülür, renk kaymaz) if ( method_exists( $im, 'transformImageColorspace' ) && Imagick::COLORSPACE_SRGB !== $im->getImageColorspace() ) { $im->transformImageColorspace( Imagick::COLORSPACE_SRGB ); } $im->stripImage(); $im->setImageFormat( 'webp' ); $im->setImageCompressionQuality( $quality ); $ok = $im->writeImage( $dest ); $im->clear(); $im->destroy(); if ( $ok && file_exists( $dest ) && filesize( $dest ) > 0 ) { return true; } } catch ( Exception $e ) { // GD'ye düş } } // 2) GD if ( $this->gd_webp() ) { $img = false; if ( 'image/jpeg' === $mime ) { $img = @imagecreatefromjpeg( $source ); if ( $img && function_exists( 'exif_read_data' ) ) { $exif = @exif_read_data( $source ); if ( ! empty( $exif['Orientation'] ) ) { $deg = 0; switch ( (int) $exif['Orientation'] ) { case 3: $deg = 180; break; case 6: $deg = -90; break; case 8: $deg = 90; break; } if ( $deg ) { $rot = imagerotate( $img, $deg, 0 ); if ( $rot ) { imagedestroy( $img ); $img = $rot; } } } } } elseif ( 'image/png' === $mime ) { $img = @imagecreatefrompng( $source ); if ( $img ) { imagepalettetotruecolor( $img ); // palet PNG'ler imagewebp'te patlar imagealphablending( $img, false ); imagesavealpha( $img, true ); // şeffaflık korunur } } if ( ! $img ) { return false; } $ok = imagewebp( $img, $dest, $quality ); imagedestroy( $img ); return $ok && file_exists( $dest ) && filesize( $dest ) > 0; } return false; } private function unique_webp_path( $file ) { $dir = dirname( $file ); $name = preg_replace( '/\.[^.\/\\\\]+$/', '', wp_basename( $file ) ) . '.webp'; if ( file_exists( trailingslashit( $dir ) . $name ) ) { $name = wp_unique_filename( $dir, $name ); } return trailingslashit( $dir ) . $name; } /* ------------------------------------------------------------------ * Toplu dönüştürme (mevcut medya kütüphanesi) * ---------------------------------------------------------------- */ private function count_remaining() { $q = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => array( 'image/jpeg', 'image/png' ), 'posts_per_page' => 1, 'fields' => 'ids', 'meta_query' => array( array( 'key' => '_wd_webp_failed', 'compare' => 'NOT EXISTS', ), ), ) ); return (int) $q->found_posts; } public function ajax_bulk() { if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => 'Yetkiniz yok.' ), 403 ); } check_ajax_referer( 'wd_webp_bulk' ); $mode = isset( $_POST['mode'] ) ? sanitize_key( $_POST['mode'] ) : 'status'; if ( 'reset_failed' === $mode ) { delete_post_meta_by_key( '_wd_webp_failed' ); wp_send_json_success( array( 'message' => 'Başarısız işaretleri temizlendi, tekrar denenebilir.' ) ); } if ( 'status' === $mode ) { wp_send_json_success( array( 'remaining' => $this->count_remaining(), 'webp' => $this->webp_supported(), ) ); } // mode === run if ( ! $this->webp_supported() ) { wp_send_json_error( array( 'message' => 'Sunucuda WebP desteği yok (GD webp veya Imagick gerekli).' ) ); } @set_time_limit( 120 ); if ( function_exists( 'wp_raise_memory_limit' ) ) { wp_raise_memory_limit( 'image' ); } $s = $this->settings(); $ids = get_posts( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => array( 'image/jpeg', 'image/png' ), 'posts_per_page' => 4, 'orderby' => 'ID', 'order' => 'ASC', 'fields' => 'ids', 'meta_query' => array( array( 'key' => '_wd_webp_failed', 'compare' => 'NOT EXISTS', ), ), ) ); $log = array(); $done = 0; $failed = 0; foreach ( $ids as $id ) { $result = $this->convert_attachment( (int) $id, (int) $s['quality'], ! empty( $s['keep_original'] ) ); if ( is_wp_error( $result ) ) { update_post_meta( $id, '_wd_webp_failed', $result->get_error_message() ); $failed++; $log[] = sprintf( '#%d HATA: %s', $id, $result->get_error_message() ); } else { $done++; $log[] = sprintf( '#%d dönüştürüldü (%d dosya).', $id, $result ); } } wp_send_json_success( array( 'processed' => count( $ids ), 'done' => $done, 'failed' => $failed, 'remaining' => $this->count_remaining(), 'log' => $log, ) ); } /** * Bir eki tüm boyutlarıyla WebP'ye çevirir, metadata + içerik URL'lerini günceller. * * @return int|WP_Error Dönüştürülen dosya sayısı ya da hata. */ private function convert_attachment( $id, $quality, $keep_original ) { $file = get_attached_file( $id ); if ( ! $file || ! file_exists( $file ) ) { return new WP_Error( 'missing_file', 'Dosya diskte bulunamadı' ); } $file = wp_normalize_path( $file ); $mime = get_post_mime_type( $id ); if ( ! in_array( $mime, array( 'image/jpeg', 'image/png' ), true ) ) { return new WP_Error( 'bad_mime', 'Desteklenmeyen tür: ' . $mime ); } $meta = wp_get_attachment_metadata( $id ); if ( ! is_array( $meta ) ) { $meta = array(); } $dir = trailingslashit( dirname( $file ) ); $uploads = wp_get_upload_dir(); $basedir = wp_normalize_path( $uploads['basedir'] ); $baseurl = $uploads['baseurl']; $map = array(); // eski disk yolu => yeni disk yolu // 1) Ana dosya (büyük görsel ölçeklendiyse bu "-scaled" dosyasıdır) $new_main = $this->unique_webp_path( $file ); if ( ! $this->convert_image( $file, $new_main, $quality ) ) { return new WP_Error( 'convert_failed', 'Ana dosya dönüştürülemedi' ); } $map[ $file ] = $new_main; // 2) Ölçeklenmemiş orijinal (varsa) if ( ! empty( $meta['original_image'] ) ) { $orig = $dir . $meta['original_image']; if ( file_exists( $orig ) && ! isset( $map[ $orig ] ) ) { $new_orig = $this->unique_webp_path( $orig ); if ( $this->convert_image( $orig, $new_orig, $quality ) ) { $map[ $orig ] = $new_orig; $meta['original_image'] = wp_basename( $new_orig ); } } } // 3) Ara boyutlar (thumbnail, medium, woocommerce_thumbnail vb.) if ( ! empty( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) { foreach ( $meta['sizes'] as $size => $data ) { if ( empty( $data['file'] ) ) { continue; } $p = $dir . $data['file']; // Aynı dosyayı paylaşan boyutlar tekrar dönüştürülmesin if ( isset( $map[ $p ] ) ) { $meta['sizes'][ $size ]['file'] = wp_basename( $map[ $p ] ); $meta['sizes'][ $size ]['mime-type'] = 'image/webp'; continue; } if ( ! file_exists( $p ) ) { continue; } $np = $this->unique_webp_path( $p ); if ( $this->convert_image( $p, $np, $quality ) ) { $map[ $p ] = $np; $meta['sizes'][ $size ]['file'] = wp_basename( $np ); $meta['sizes'][ $size ]['mime-type'] = 'image/webp'; if ( isset( $meta['sizes'][ $size ]['filesize'] ) ) { $meta['sizes'][ $size ]['filesize'] = (int) filesize( $np ); } } } } // 4) Ek kaydını güncelle update_attached_file( $id, $new_main ); $meta['file'] = ltrim( str_replace( $basedir, '', $new_main ), '/' ); if ( isset( $meta['filesize'] ) ) { $meta['filesize'] = (int) filesize( $new_main ); } wp_update_attachment_metadata( $id, $meta ); $new_main_url = str_replace( $basedir, $baseurl, $new_main ); wp_update_post( array( 'ID' => $id, 'post_mime_type' => 'image/webp', 'guid' => $new_main_url, ) ); // 5) Yazı/ürün içeriklerindeki eski URL'leri değiştir + eski dosyaları sil global $wpdb; foreach ( $map as $old_path => $new_path ) { $old_url = str_replace( $basedir, $baseurl, $old_path ); $new_url = str_replace( $basedir, $baseurl, $new_path ); if ( $old_url !== $new_url ) { $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $old_url, $new_url ) ); } if ( ! $keep_original ) { @unlink( $old_path ); } } clean_post_cache( $id ); return count( $map ); } /* ------------------------------------------------------------------ * Yönetim sayfası * ---------------------------------------------------------------- */ public function admin_menu() { add_options_page( 'WebP Dönüştürücü', 'WebP Dönüştürücü', 'manage_options', 'wd-webp', array( $this, 'render_page' ) ); } public function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $s = $this->settings(); $imagick_ok = $this->imagick_webp(); $gd_ok = $this->gd_webp(); $remaining = $this->count_remaining(); ?> <div class="wrap"> <h1>WD WebP Dönüştürücü</h1> <p> Sunucu desteği: <strong style="color:<?php echo $imagick_ok ? '#00a32a' : '#d63638'; ?>">Imagick <?php echo $imagick_ok ? '✓' : '✗'; ?></strong> | <strong style="color:<?php echo $gd_ok ? '#00a32a' : '#d63638'; ?>">GD WebP <?php echo $gd_ok ? '✓' : '✗'; ?></strong> </p> <?php if ( ! $imagick_ok && ! $gd_ok ) : ?> <div class="notice notice-error"><p><strong>Sunucunuzda WebP desteği yok.</strong> Hosting sağlayıcınızdan GD'nin WebP desteğiyle derlenmesini veya Imagick kurulmasını isteyin. Eklenti bu durumda hiçbir şey yapmaz.</p></div> <?php endif; ?> <form method="post" action="options.php"> <?php settings_fields( 'wd_webp' ); ?> <table class="form-table" role="presentation"> <tr> <th scope="row">Otomatik dönüştürme</th> <td> <label> <input type="checkbox" name="<?php echo esc_attr( self::OPTION ); ?>[enabled]" value="1" <?php checked( $s['enabled'], 1 ); ?>> Yüklenen görselleri otomatik olarak WebP'ye dönüştür </label> </td> </tr> <tr> <th scope="row">Dönüştürülecek türler</th> <td> <label><input type="checkbox" name="<?php echo esc_attr( self::OPTION ); ?>[convert_jpeg]" value="1" <?php checked( $s['convert_jpeg'], 1 ); ?>> JPEG</label><br> <label><input type="checkbox" name="<?php echo esc_attr( self::OPTION ); ?>[convert_png]" value="1" <?php checked( $s['convert_png'], 1 ); ?>> PNG (şeffaflık korunur)</label> <p class="description">GIF ve SVG dosyalarına dokunulmaz.</p> </td> </tr> <tr> <th scope="row"><label for="wd-webp-quality">Kalite</label></th> <td> <input type="number" id="wd-webp-quality" name="<?php echo esc_attr( self::OPTION ); ?>[quality]" value="<?php echo esc_attr( $s['quality'] ); ?>" min="1" max="100" step="1" class="small-text"> / 100 <p class="description">Önerilen: 75–85. Değer düştükçe dosya küçülür, kalite azalır.</p> </td> </tr> <tr> <th scope="row">Orijinal dosya</th> <td> <label> <input type="checkbox" name="<?php echo esc_attr( self::OPTION ); ?>[keep_original]" value="1" <?php checked( $s['keep_original'], 1 ); ?>> Orijinal JPEG/PNG dosyasını diskte tut (yedek olarak; medya kütüphanesinde görünmez) </label> </td> </tr> </table> <?php submit_button( 'Ayarları Kaydet' ); ?> </form> <hr> <h2>Mevcut Görselleri Toplu Dönüştür</h2> <p>Medya kütüphanesindeki dönüştürülebilir görsel sayısı: <strong id="wd-webp-remaining"><?php echo esc_html( $remaining ); ?></strong></p> <p class="description"><strong>Uyarı:</strong> Başlamadan önce mutlaka dosya + veritabanı yedeği alın. Tüm boyutlar (küçük görseller dahil) dönüştürülür, ek kayıtları ve yazı/ürün içeriklerindeki görsel adresleri güncellenir, eski dosyalar (ayara göre) silinir.</p> <p> <button type="button" class="button button-primary" id="wd-webp-start">Toplu Dönüştürmeyi Başlat</button> <button type="button" class="button" id="wd-webp-stop" disabled>Durdur</button> <button type="button" class="button" id="wd-webp-reset">Başarısızları Sıfırla</button> </p> <div style="max-width:640px;background:#dcdcde;border-radius:3px;height:22px;overflow:hidden;margin-bottom:6px;"> <div id="wd-webp-bar" style="height:100%;width:0;background:#2271b1;transition:width .3s;"></div> </div> <p id="wd-webp-pct" style="margin-top:0;"></p> <pre id="wd-webp-log" style="max-width:640px;height:220px;overflow:auto;background:#1d2327;color:#9ec2e6;padding:10px;font-size:12px;"></pre> </div> <script> (function () { var nonce = '<?php echo esc_js( wp_create_nonce( 'wd_webp_bulk' ) ); ?>'; var running = false; var total = 0; var done = 0; function el( id ) { return document.getElementById( id ); } function post( mode ) { var body = new URLSearchParams( { action: 'wd_webp_bulk', mode: mode, _wpnonce: nonce } ); return fetch( ajaxurl, { method: 'POST', credentials: 'same-origin', body: body } ) .then( function ( r ) { return r.json(); } ); } function log( lines ) { var box = el( 'wd-webp-log' ); ( lines || [] ).forEach( function ( l ) { box.textContent += l + '\n'; } ); box.scrollTop = box.scrollHeight; } function setProgress() { var pct = total > 0 ? Math.round( ( done / total ) * 100 ) : 100; el( 'wd-webp-bar' ).style.width = pct + '%'; el( 'wd-webp-pct' ).textContent = done + ' / ' + total + ' (%' + pct + ')'; } function toggle() { el( 'wd-webp-start' ).disabled = running; el( 'wd-webp-stop' ).disabled = ! running; } function step() { if ( ! running ) { return; } post( 'run' ).then( function ( res ) { if ( ! res || ! res.success ) { log( [ 'HATA: ' + ( res && res.data && res.data.message ? res.data.message : 'İstek başarısız oldu.' ) ] ); running = false; toggle(); return; } done += res.data.processed; log( res.data.log ); setProgress(); el( 'wd-webp-remaining' ).textContent = res.data.remaining; if ( res.data.remaining > 0 && res.data.processed > 0 ) { step(); } else { log( [ '--- Tamamlandı ---' ] ); running = false; toggle(); } } ).catch( function ( e ) { log( [ 'HATA: ' + e ] ); running = false; toggle(); } ); } el( 'wd-webp-start' ).addEventListener( 'click', function () { post( 'status' ).then( function ( res ) { if ( ! res || ! res.success ) { return; } if ( ! res.data.webp ) { log( [ 'Sunucuda WebP desteği yok.' ] ); return; } total = res.data.remaining; done = 0; el( 'wd-webp-log' ).textContent = ''; if ( total < 1 ) { log( [ 'Dönüştürülecek görsel yok.' ] ); return; } running = true; toggle(); setProgress(); step(); } ); } ); el( 'wd-webp-stop' ).addEventListener( 'click', function () { running = false; toggle(); log( [ 'Durduruldu. Kaldığı yerden tekrar başlatabilirsiniz.' ] ); } ); el( 'wd-webp-reset' ).addEventListener( 'click', function () { post( 'reset_failed' ).then( function ( res ) { log( [ res && res.success ? res.data.message : 'Sıfırlama başarısız.' ] ); post( 'status' ).then( function ( r2 ) { if ( r2 && r2.success ) { el( 'wd-webp-remaining' ).textContent = r2.data.remaining; } } ); } ); } ); })(); </script> <?php } } WD_WebP_Converter::instance();Ücretsiz kullanabilirsiniz.