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:
trueolursa 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_scriptile 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.
