jQuery’yi Footer’a Taşıma: Sayfa Hızı Optimizasyonu

WordPress sitenizin yavaş yüklendiğinden şikayet eden ziyaretçileriniz var mı? Google PageSpeed Insights sürekli kötü skorlar mı gösteriyor? Büyük ihtimalle sorun jQuery’nin bölümünde yüklenmesinden kaynaklanıyor. Bu yazıda jQuery’yi footer’a taşımanın ne anlama geldiğini, nasıl yapıldığını ve hangi durumlarda dikkatli olmak gerektiğini gerçek dünya örnekleriyle ele alacağız.

jQuery Neden Sayfa Hızını Etkiler?

Tarayıcılar bir HTML sayfasını yukarıdan aşağıya doğru okur. bölümünde karşılaştığı JavaScript dosyalarını indirip çalıştırana kadar sayfanın geri kalanını işlemeyi durdurur. Buna render-blocking (oluşturmayı engelleyen) kaynak denir.

jQuery, WordPress’in neredeyse her kurulumunda varsayılan olarak bölümüne yüklenir. Bu dosya küçük değil; minified versiyonu bile yaklaşık 87 KB civarında. Yavaş bağlantılarda bu dosyanın inmesi için kullanıcılar boş bir ekrana bakmak zorunda kalır.

Peki çözüm ne? jQuery’yi ve ona bağımlı scriptleri sayfanın en altına, yani etiketinden hemen önce yüklemek. Böylece HTML içeriği önce işlenir, kullanıcı sayfayı görür, sonra scriptler yüklenir.

WordPress’te Script Yükleme Mantığı

WordPress’te scriptler wp_enqueue_script() fonksiyonu ile yüklenir. Bu fonksiyonun son parametresi $in_footer değeridir. true olarak ayarlandığında script footer’a taşınır.

wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );

Parametreleri açıklayalım:

  • $handle: Scriptin benzersiz adı (örneğin jquery)
  • $src: Script dosyasının URL’si
  • $deps: Bağımlılıklar dizisi
  • $ver: Versiyon numarası
  • $in_footer: true olursa footer’a yüklenir

WordPress’in kendi jQuery kaydı wp_default_scripts() fonksiyonu içinde yapılır ve varsayılan olarak footer parametresi false yani head’e yüklenir. Bunu değiştirmek için functions.php dosyasına müdahale etmemiz gerekir.

Temel jQuery Footer Taşıma Kodu

En basit yöntemle başlayalım. Bu kod, jQuery’yi dequeue edip footer’da tekrar enqueue eder:

function move_jquery_to_footer() {
    if ( !is_admin() ) {
        wp_dequeue_script( 'jquery' );
        wp_enqueue_script( 'jquery', includes_url( '/js/jquery/jquery.min.js' ), array(), null, true );
    }
}
add_action( 'wp_enqueue_scripts', 'move_jquery_to_footer', 99 );

Buradaki is_admin() kontrolü çok önemli. Admin panelinde jQuery’yi footer’a taşırsanız WordPress yönetim ekranı çalışmaz hale gelir. Bu yüzden sadece frontend için bu işlemi yapıyoruz.

99 öncelik değeri de kritik; diğer temaların ve eklentilerin jQuery’yi enqueue etmesinden sonra bizim fonksiyonumuzun çalışmasını sağlar.

jQuery Migrate ile Birlikte Taşıma

Modern WordPress kurulumlarında jQuery ile birlikte jquery-migrate scripti de yüklenir. Eski jQuery sözdizimini kullanan eklentiler için bu gereklidir. Her ikisini de birlikte taşımak daha güvenli olur:

function move_jquery_and_migrate_to_footer() {
    if ( !is_admin() ) {
        // jQuery'yi footer'a taşı
        wp_dequeue_script( 'jquery' );
        wp_dequeue_script( 'jquery-core' );
        wp_dequeue_script( 'jquery-migrate' );
        
        wp_enqueue_script( 'jquery-core', '/wp-includes/js/jquery/jquery.min.js', array(), null, true );
        wp_enqueue_script( 'jquery-migrate', '/wp-includes/js/jquery/jquery-migrate.min.js', array( 'jquery-core' ), null, true );
        wp_enqueue_script( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), null, true );
    }
}
add_action( 'wp_enqueue_scripts', 'move_jquery_and_migrate_to_footer', 99 );

Bu yaklaşımda önce her iki scripti de kuyruğdan çıkarıyoruz, sonra doğru bağımlılık sırasıyla footer’a yeniden ekliyoruz. jquery handle’ı aslında bir “alias” olduğu için false source ile tanımlanması yeterli.

Login Sayfasını Hariç Tutma

WordPress login sayfası da frontend sayılır ama burada jQuery’nin head’de olması bazı durumlarda önemlidir. Login formundaki bazı güvenlik eklentileri head’deki scriptlere bağımlı çalışır:

function move_jquery_to_footer_safe() {
    // Admin paneli ve login sayfasını atla
    if ( is_admin() ) {
        return;
    }
    
    // Login, register ve lost password sayfalarını atla
    if ( in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ) ) ) {
        return;
    }
    
    wp_dequeue_script( 'jquery' );
    wp_dequeue_script( 'jquery-core' );
    wp_dequeue_script( 'jquery-migrate' );
    
    wp_enqueue_script( 'jquery-core', includes_url( 'js/jquery/jquery.min.js' ), array(), null, true );
    wp_enqueue_script( 'jquery-migrate', includes_url( 'js/jquery/jquery-migrate.min.js' ), array( 'jquery-core' ), null, true );
    wp_enqueue_script( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), null, true );
}
add_action( 'wp_enqueue_scripts', 'move_jquery_to_footer_safe', 99 );

WooCommerce ile Uyumluluk

WooCommerce kendi jQuery bağımlı scriptlerini yönetir ve bunların bir kısmı head’de kalması gerekebilir. Özellikle checkout sayfasında jQuery’nin geç yüklenmesi ödeme formlarının bozulmasına neden olabilir.

WooCommerce sayfalarını hariç tutan gelişmiş bir versiyon:

function move_jquery_to_footer_woocommerce() {
    if ( is_admin() ) {
        return;
    }
    
    // WooCommerce kritik sayfalarını atla
    if ( function_exists( 'is_woocommerce' ) ) {
        if ( is_checkout() || is_cart() || is_account_page() ) {
            return;
        }
    }
    
    // Login sayfasını atla
    if ( in_array( $GLOBALS['pagenow'], array( 'wp-login.php' ) ) ) {
        return;
    }
    
    global $wp_scripts;
    
    // jQuery ve bağımlılarını footer'a taşı
    if ( isset( $wp_scripts->registered['jquery'] ) ) {
        $wp_scripts->registered['jquery']->extra['group'] = 1;
    }
    if ( isset( $wp_scripts->registered['jquery-core'] ) ) {
        $wp_scripts->registered['jquery-core']->extra['group'] = 1;
    }
    if ( isset( $wp_scripts->registered['jquery-migrate'] ) ) {
        $wp_scripts->registered['jquery-migrate']->extra['group'] = 1;
    }
}
add_action( 'wp_enqueue_scripts', 'move_jquery_to_footer_woocommerce', 9999 );

Bu yöntemde extra['group'] = 1 kullanıyoruz. WordPress scriptleri için group 0 head, group 1 footer anlamına gelir. Bu yaklaşım daha temiz çünkü dequeue/enqueue döngüsüne girmeden direkt gruba atıyoruz.

Script Bağımlılıklarını Otomatik Footer’a Taşıma

Gerçek dünya senaryolarında sadece jQuery değil, jQuery’ye bağımlı onlarca script olabilir. Bunların hepsini manuel taşımak yerine otomatik bir çözüm daha pratik:

function move_all_jquery_deps_to_footer() {
    if ( is_admin() ) {
        return;
    }
    
    global $wp_scripts;
    
    // Tum enqueue edilmis scriptleri kontrol et
    foreach ( $wp_scripts->queue as $handle ) {
        // jQuery'ye bagimli olan tum scriptleri bul
        if ( isset( $wp_scripts->registered[$handle] ) ) {
            $script = $wp_scripts->registered[$handle];
            
            // Bu script jQuery'ye bagimli mi?
            if ( in_array( 'jquery', (array) $script->deps ) || 
                 in_array( 'jquery-core', (array) $script->deps ) ) {
                // Footer'a tasıyoruz
                $script->extra['group'] = 1;
            }
        }
    }
    
    // Ana jQuery'yi de footer'a al
    if ( isset( $wp_scripts->registered['jquery'] ) ) {
        $wp_scripts->registered['jquery']->extra['group'] = 1;
    }
    if ( isset( $wp_scripts->registered['jquery-core'] ) ) {
        $wp_scripts->registered['jquery-core']->extra['group'] = 1;
    }
}
add_action( 'wp_print_scripts', 'move_all_jquery_deps_to_footer', 9999 );

Bu fonksiyon wp_print_scripts hook’unu kullanır, çünkü bu aşamada tüm scriptler zaten kuyruğa alınmış olur ve hepsini bir arada işleyebiliriz.

Sayfa Bazlı Kontrol ile Gelişmiş Yapı

Production ortamında en güvenli yaklaşım, belirli sayfa tiplerinde bu optimizasyonu devreye almak:

function smart_jquery_footer_loader() {
    if ( is_admin() ) {
        return;
    }
    
    // Login sayfasi
    if ( in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ) ) ) {
        return;
    }
    
    // WooCommerce kritik sayfalari
    $woo_critical_pages = false;
    if ( function_exists( 'is_woocommerce' ) ) {
        $woo_critical_pages = is_checkout() || is_cart() || is_account_page() || is_wc_endpoint_url();
    }
    
    if ( $woo_critical_pages ) {
        return;
    }
    
    // AJAX isteklerinde atla
    if ( wp_doing_ajax() ) {
        return;
    }
    
    global $wp_scripts;
    
    $jquery_handles = array( 'jquery', 'jquery-core', 'jquery-migrate' );
    
    foreach ( $jquery_handles as $handle ) {
        if ( isset( $wp_scripts->registered[$handle] ) ) {
            $wp_scripts->registered[$handle]->extra['group'] = 1;
            
            // Eger src yoksa (alias ise) bunu da ayarla
            if ( !$wp_scripts->registered[$handle]->src ) {
                continue;
            }
        }
    }
    
    // jQuery'ye bagli scriptleri de tasıyalim
    foreach ( $wp_scripts->queue as $handle ) {
        if ( !isset( $wp_scripts->registered[$handle] ) ) {
            continue;
        }
        
        $deps = (array) $wp_scripts->registered[$handle]->deps;
        
        if ( array_intersect( $deps, $jquery_handles ) ) {
            $wp_scripts->registered[$handle]->extra['group'] = 1;
        }
    }
}
add_action( 'wp_print_scripts', 'smart_jquery_footer_loader', 9999 );

Inline Script Sorununu Çözme

jQuery footer’a taşındığında head’deki inline bloklarında jQuery kullanan kodlar hata verir. Bu çok yaygın bir problem. Örneğin tema dosyalarında şöyle kodlar görebilirsiniz:

// Yanlis yaklasim - inline script head'de jQuery'yi bekler
add_action( 'wp_head', function() {
    echo '<script>jQuery(document).ready(function($) { ... });</script>';
});

Bunun yerine bu inline scriptleri de footer’a taşımalısınız:

// Dogru yaklasim - inline scripti footer'a ekle
function add_custom_inline_script() {
    if ( is_admin() ) {
        return;
    }
    
    // Once bir handle enqueue et
    wp_enqueue_script( 'my-custom-inline', '', array( 'jquery' ), '', true );
    
    // Sonra inline scripti buna bagla
    $inline_script = "
        jQuery(document).ready(function($) {
            console.log('jQuery footer da calisiyor!');
            // Buraya kodlarinizi ekleyin
        });
    ";
    
    wp_add_inline_script( 'jquery-core', $inline_script );
}
add_action( 'wp_enqueue_scripts', 'add_custom_inline_script' );

wp_add_inline_script() fonksiyonu, scripti bağlı olduğu handle ile birlikte aynı konuma (footer veya head) yerleştirir. Bu yüzden inline scriptleriniz için bu yöntemi kullanmak çok daha güvenli.

Test ve Doğrulama

Kodu ekledikten sonra düzgün çalışıp çalışmadığını test etmek için birkaç yöntem:

Tarayıcı DevTools ile kontrol:

# Chrome DevTools'ta Network sekmesinde
# jquery.min.js dosyasini bulduktan sonra
# Initiator sutununa bakin - burasi head mi footer mu kontrolu icin

# Ayrica Elements sekmesinde Ctrl+F ile arama yapabilirsiniz
# <head> icerisinde jquery arayin - olmamali
# </body> oncesinde jquery arayin - olmali

PageSpeed Insights skoru karşılaştırması: Kodu eklemeden önce ve sonra PageSpeed Insights testini çalıştırın. “Eliminate render-blocking resources” uyarısında jQuery’nin kaybolması gerekiyor.

Konsol hata kontrolü:

# Tarayici konsolunda su hatalar varsa bagintilar bozulmus demektir:
# "jQuery is not defined"
# "$ is not a function"
# "Cannot read property of undefined"

# Bu hatalari gorurseniz ilgili sayfayi istisnalara ekleyin

Gerçek Dünya Senaryosu: E-Ticaret Sitesi

Bir WooCommerce müşterisi düşünün. 47 eklenti kurulu, PageSpeed skoru mobilde 34. Sorunların büyük çoğunluğu render-blocking kaynaklar. Yapılan adımlar:

  • Önce tüm sayfalar audit edildi, hangi sayfalarda hangi scriptlerin kritik olduğu listelendi
  • Anasayfa, blog, ürün listeleme sayfaları için jQuery footer’a taşındı
  • Sepet, ödeme ve hesap sayfaları hariç tutuldu
  • jQuery’ye bağımlı 12 eklentinin scripti de otomatik olarak footer’a taşındı
  • Tema’nın head’deki inline scriptleri wp_add_inline_script ile footer’a alındı

Sonuç: Mobil PageSpeed skoru 34’ten 71’e çıktı. Sunucu tarafında herhangi bir değişiklik yapılmadı, sadece functions.php düzenlendi.

Olası Sorunlar ve Çözümleri

Sorun 1: Slider veya carousel çalışmıyor

Bazı slider eklentileri jQuery’nin head’de olmasını bekler. Bu durumda ilgili eklentinin scriptini de footer’a taşıyan kodu kontrol edin veya slider eklentisinin ayarlarında script pozisyonunu değiştirin.

Sorun 2: Contact Form 7 veya benzeri form eklentileri hata veriyor

CF7 genellikle jQuery bağımlıdır ve versiyona göre sorun çıkarabilir. CF7’nin kendi scriptlerini dequeue edip footer’da tekrar enqueue etmeyi deneyin:

function fix_cf7_jquery_footer() {
    if ( !is_admin() ) {
        wp_dequeue_script( 'contact-form-7' );
        wp_enqueue_script( 
            'contact-form-7', 
            plugins_url( 'contact-form-7/includes/js/scripts.js' ), 
            array( 'jquery' ), 
            '5.8', 
            true  // footer
        );
    }
}
add_action( 'wp_enqueue_scripts', 'fix_cf7_jquery_footer', 99 );

Sorun 3: Admin bar bozuluyor

is_admin() kontrolü admin bar’ı kapsamaz. Admin bar frontend’de de gösterilir. is_admin_bar_showing() kontrolü ekleyin:

function move_jquery_footer_safe_v2() {
    // Hem admin paneli hem admin bar kontrolu
    if ( is_admin() ) {
        return;
    }
    
    // Admin bar gorununuyorsa dikkatli ol
    // Cok kritik sayfalarda atla
    if ( is_customize_preview() ) {
        return;
    }
    
    // ... geri kalan kod
}

Sorun 4: Caching eklentisi çakışması

W3 Total Cache veya WP Super Cache kullanıyorsanız, bu eklentiler de script optimizasyonu yapar. İkisi aynı anda çalışırsa çakışma olabilir. Ya caching eklentisinin JS optimizasyonunu kapatın ya da sadece birini kullanın.

Child Theme’de Güvenli Uygulama

Bu kodu direkt ana tema’nın functions.php dosyasına eklemek yerine child theme kullanmak daha doğru bir yaklaşım. Ana tema güncellendiğinde kodlarınız silinmez:

// child-theme/functions.php icine ekleyin

if ( !function_exists( 'mytheme_move_jquery_footer' ) ) {
    function mytheme_move_jquery_footer() {
        if ( is_admin() || is_customize_preview() ) {
            return;
        }
        
        if ( in_array( $GLOBALS['pagenow'], array( 'wp-login.php' ) ) ) {
            return;
        }
        
        global $wp_scripts;
        
        foreach ( array( 'jquery', 'jquery-core', 'jquery-migrate' ) as $handle ) {
            if ( isset( $wp_scripts->registered[$handle] ) ) {
                $wp_scripts->registered[$handle]->extra['group'] = 1;
            }
        }
    }
}
add_action( 'wp_print_scripts', 'mytheme_move_jquery_footer', 9999 );

function_exists() kontrolü, bu fonksiyonun başka bir yerde tanımlanmış olması durumunda çakışmayı önler.

Sonuç

jQuery’yi footer’a taşımak kulağa basit gelen ama dikkat gerektiren bir optimizasyon. Doğru yapıldığında PageSpeed skorlarında ciddi iyileşme sağlar, yanlış yapıldığında sitenizi kullanılamaz hale getirebilir.

Önemli noktalara bir daha değinelim:

  • Her zaman is_admin() kontrolü yapın
  • WooCommerce checkout ve cart sayfalarını hariç tutun
  • Login sayfasını hariç tutmayı unutmayın
  • Inline scriptleri wp_add_inline_script() ile taşıyın
  • Caching eklentisiyle çakışma olup olmadığını kontrol edin
  • Değişikliği staging ortamında test edip sonra production’a alın

Bu optimizasyonu yaparken her zaman önce yedek alın ve değişikliği staging ortamında deneyin. Production’da test etmek, ziyaretçilerinizi kobay olarak kullanmak anlamına gelir ki bu hiç profesyonelce değil. Sabırlı olun, site bazlı test edin ve sonuçları PageSpeed Insights veya GTmetrix ile ölçün.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir