Skip to content

Alt om WordPress, webutvikling — og mer til

⚡ Slik legger du til defer og async for WordPress-skript i function.php

⚡ Slik legger du til defer og async for WordPress-skript i function.php

Sider laster sakte, Google PageSpeed Insights viser oransje advarsler, og kunden spør: «hvorfor er nettstedet tregt?» Ni av ti ganger er rotårsaken at JavaScript blokkerer renderingen. Nettleseren treffer en <script>, stopper byggingen av DOM-en, laster og kjører skriptet, og først deretter fortsetter den. På et moderne nettsted med et dusin utvidelser blir denne forsinkelsen til sekunder.

WordPress hadde lenge ingen standard måte å kontrollere skriptinnlasting på. Utviklere danset rundt med workarounds: filtrering av script_loader_tag, patching av output via clean_url, eller til og med å skrive egne walkers for WP_Scripts. Men med lanseringen av WordPress 6.3 endret situasjonen seg radikalt, og nå har vi en ryddig, støttet måte å legge til defer eller async på ethvert skript uten et eneste hack.

Nedenfor finner du to fungerende metoder: den moderne, native tilnærmingen (WP 6.3+) og det velprøvde script_loader_tag-filteret (WP 4.1+). Begge er testet på reelle prosjekter, og begge bevarer integriteten til avhengighetskøen.

💡 Rask oversikt:

  • Forstå forskjellen mellom defer og async og når du skal bruke hvilken, dette avgjør om funksjonalitet ryker etter optimalisering
  • Bruk den native WordPress 6.3+-metoden via wp_enqueue_script() med strategy-parameteren, den reneste tilnærmingen som bevarer rekkefølgen på kjøring
  • Hvis nettstedet kjører en versjon under 6.3, bruk script_loader_tag-filteret med en array av handles, dette fungerer fra og med WordPress 4.1
  • For flere skripter, samle handles i en array og loop gjennom den, ett filter for alle skript i stedet for kopier og lim

Hva defer og async er og når du skal bruke dem

Når en nettleser møter en vanlig <script>-tagg, gjør den tre ting i rekkefølge: stopper parsing av HTML, laster skriptet, kjører det. Først deretter går den tilbake til HTML. På en side med fem skripter i <head> betyr dette at brukeren ser en hvit skjerm mens den siste kommentarutvidelsen laster, selv om selve innlegget kunne ha blitt rendret for lenge siden.

Attributtene defer og async løser dette problemet, men fungerer forskjellig:

Attributt

Når det lastes

Når det kjøres

Kjøringsrekkefølge

(ingen)

Blokkerer parsing umiddelbart

Umiddelbart etter lasting

I DOM-rekkefølge

defer

Parallelt med parsing

Etter at DOM er fullstendig lastet

I DOM-rekkefølge

async

Parallelt med parsing

Umiddelbart etter lasting

Den som laster først

Defer er arbeidshesten for de fleste scenarioer. Skriptet laster parallelt med HTML og kjøres først når DOM-en er fullstendig bygget. Rekkefølgen bevares: skript A vil kjøre før skript B, selv om B lastet raskere. Dette er kritisk for jQuery og alt som avhenger av det.

Async er et verktøy for uavhengige skripter. Analyse, annonser, sosiale medier-widgets: de trenger ikke DOM-en, de bryr seg ikke om rekkefølge, de trenger bare å kjøre så raskt som mulig. Men hvis du setter async på et skript som avhenger av jQuery, vil du sannsynligvis få $ is not defined.

Enkel regel: skript avhenger av andre skript eller av DOM-en → defer. Skript er fullstendig autonomt → async. Når du er i tvil, start alltid med defer.

Metode 1: Native WordPress 6.3+-tilnærming

Siden juli 2023 har en ny mekanisme fungert i WordPress-kjernen. Funksjonene wp_register_script() og wp_enqueue_script() fikk en overbelastet femte parameter $args, en array der du kan spesifisere lastestrategien. Ingen filtre, ingen strengmagi, ingen risiko for å ødelegge avhengighetsrekkefølgen.

Grunnleggende syntaks for defer:

1wp_enqueue_script(
2 'my-js-handle',
3 get_template_directory_uri() . '/js/my-script.js',
4 array('jquery'),
5 '1.0.0',
6 array(
7 'strategy' => 'defer',
8 'in_footer' => true,
9 )
10);

For async, samme mekanikk:

1wp_enqueue_script(
2 'google-analytics',
3 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX',
4 array(),
5 '1.0.0',
6 array(
7 'strategy' => 'async',
8 'in_footer' => false,
9 )
10);

Nøkkelen in_footer inne i arrayen fungerer på samme måte som den gamle boolske parameteren: true plasserer skriptet i footeren, false i <head>. For defer setter du typisk true (skriptet venter uansett på DOM, ingen vits i å laste det tidlig), for async det som fungerer.

Hovedfordelen med den native metoden er at kjernen selv sjekker avhengighetstreet. Hvis skript A med defer avhenger av skript B, og B er registrert uten strategi (blokkerende), vil ikke WordPress ødelegge nettstedet ditt: det vil automatisk nedgradere skript A sin strategi til blokkerende. Når du bruker script_loader_tag mangler du denne beskyttelsen, filteret setter bare inn attributtet uten å se på avhengigheter.

Viktig: $args-arrayen dukket opp i WordPress 6.3. Hvis et tema eller en utvidelse må fungere på lavere versjoner, bruk metode 2 eller legg til en sjekk:

1if ( version_compare( $GLOBALS['wp_version'], '6.3', '>=' ) ) {
2 // native method
3} else {
4 // script_loader_tag filter
5}

Metode 2: script_loader_tag-filter (WordPress 4.1+)

Hvis nettstedet kjører en versjon under 6.3 eller du trenger å opprettholde bakoverkompatibilitet, bruk det velprøvde script_loader_tag-filteret. Det har eksistert siden WordPress 4.1 og fungerer fortsatt feilfritt.

Filteret utløses rett før <script>-taggen sendes ut til HTML, du mottar den ferdige tagg-strengen, skript-handlen og filbanen, og kan erstatte src med defer="defer" src eller async="async" src.

Enkelt skript med defer:

1function add_defer_to_my_script($tag, $handle) {
2 if ( 'my-js-handle' !== $handle ) {
3 return $tag;
4 }
5 return str_replace( ' src', ' defer="defer" src', $tag );
6}
7add_filter('script_loader_tag', 'add_defer_to_my_script', 10, 2);

Koden plasseres i det aktive temaets functions.php eller, mer korrekt, i en separat snippet-utvidelse som Code Snippets eller WPCode. Hvis du legger den i et child-temas functions.php, vil skriptene bli blokkerende igjen når du bytter tema, og du vil ikke merke det umiddelbart.

Skript-handlen er den første parameteren du sendte til wp_register_script() eller wp_enqueue_script(). Dette er det som vises i if-betingelsen. Ikke gjett handlen, åpne kildekoden til utvidelsen eller temaet og finn kallet til wp_enqueue_script.

Defer og async for flere skript

Å legge til ett filter per skript er en vei til oppblåst functions.php og kopier-og-lim-feil. Den riktige løsningen: en array med handles og ett filter med en loop.

1function add_defer_to_scripts($tag, $handle) {
2 $scripts_to_defer = array(
3 'my-js-handle',
4 'another-handle',
5 'third-party-lib',
6 );
7
8 foreach ( $scripts_to_defer as $defer_script ) {
9 if ( $defer_script === $handle ) {
10 return str_replace( ' src', ' defer="defer" src', $tag );
11 }
12 }
13 return $tag;
14}
15add_filter('script_loader_tag', 'add_defer_to_scripts', 10, 2);

For async er det bare attributtet og array-navnet som endres:

1function add_async_to_scripts($tag, $handle) {
2 $scripts_to_async = array(
3 'google-tag-manager',
4 'facebook-pixel',
5 'hotjar',
6 );
7
8 foreach ( $scripts_to_async as $async_script ) {
9 if ( $async_script === $handle ) {
10 return str_replace( ' src', ' async="async" src', $tag );
11 }
12 }
13 return $tag;
14}
15add_filter('script_loader_tag', 'add_async_to_scripts', 10, 2);

Begge filtrene kan hektes på samtidig, defer på dine skript, async på tredjeparts trackere. De fungerer uavhengig og kommer ikke i konflikt.

Praktisk eksempel: Google Maps API

Google Maps er en klassisk kandidat for defer. Kartet er typisk i footeren på kontaktsiden, skriptet henter 100+ KB, og brukeren trenger ikke kartet med en gang. Dessuten avhenger ikke selve API-et av andre sideskripter, et ideelt tilfelle.

Koble til og defer:

1// theme's functions.php
2function enqueue_google_maps() {
3 if ( ! is_page('contacts') ) {
4 return;
5 }
6
7 wp_enqueue_script(
8 'google-maps-api',
9 'https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY',
10 array(),
11 null,
12 array(
13 'strategy' => 'defer',
14 'in_footer' => true,
15 )
16 );
17}
18add_action('wp_enqueue_scripts', 'enqueue_google_maps');

Samme resultat via script_loader_tag:

1function add_defer_to_google_maps($tag, $handle) {
2 if ( 'google-maps-api' !== $handle ) {
3 return $tag;
4 }
5 return str_replace( ' src', ' defer="defer" src', $tag );
6}
7add_filter('script_loader_tag', 'add_defer_to_google_maps', 10, 2);

Etter at du har installert en av variantene, sjekk definitivt kartet på kontaktsiden. Åpne nettleserkonsollen (F12), forsikre deg om at det ikke er noen JavaScript-feil, og at kartet ble rendret korrekt. Hvis du får en feil som initMap is not a function, betyr det at initialiseringsskriptet ditt også må merkes som defer og plasseres strengt etter API-tilkoblingen.

Hvordan verifisere at defer og async fungerer

Etter implementering kommer verifisering. Uten den vet du ikke om optimaliseringen fungerte eller bare ligger som død kode.

Åpne sidekilden (Ctrl+U) og finn skriptene dine. <script>-taggen skal ha attributtene:

1<script defer="defer" src="/wp-content/themes/my-theme/js/my-script.js"></script>

Hvis det ikke er noen attributter, sjekk om handlen i filteret samsvarer med den faktiske skript-handlen. Vanlig feil: i wp_enqueue_script er handlen my-plugin-frontend, men i filteret er den my_plugin_frontend. Bindestrek versus understrek, og filteret hopper stille over skriptet.

Siste finpuss, Google PageSpeed Insights eller Lighthouse i Audits-fanen i utviklerverktøyene. Seksjonen «Eliminate render-blocking resources» skal vise forbedring. Den spesifikke gevinsten avhenger av antall og størrelse på skript, men for et typisk WordPress-nettsted med 5-7 utvidelser er en 40-60% reduksjon i blokkerende JavaScript et oppnåelig resultat.

⁉️🤔 Ofte stilte spørsmål

Kan jeg bruke både defer og async på ett skript?

Nei. Hvis du spesifiserer begge attributtene samtidig, vil nettleseren ignorere defer og kjøre skriptet som async. Denne oppførselen er bakt inn i HTML-spesifikasjonen, async har alltid prioritet. Velg én basert på om kjøringsrekkefølge er viktig.

Hva gjør jeg hvis skriptet sluttet å fungere etter at jeg la til defer?

Mest sannsynlig forventer skriptet at DOM-en ikke er bygget ennå og prøver å manipulere elementer som ikke eksisterer på kjøretidspunktet. Erstatt defer med standard blokkerende lasting for det spesifikke skriptet. Eller pakk skriptkoden inn i DOMContentLoaded, da kan det fungere med defer uten feil. Det andre alternativet er å foretrekke: du beholder optimaliseringen og fikser kompatibiliteten.

Hva er forskjellen mellom defer og å flytte skriptet til footeren via wp_enqueue_script med $in_footer = true?

$in_footer = true flytter bare <script>-taggen fra <head> til slutten av <body>. Skriptet blokkerer fortsatt rendering, bare senere. defer laster parallelt med HTML-parsing og kjøres strengt etter at DOM-en er bygget. Kombinert bruk (in_footer => true + strategy => 'defer') gir maksimal effekt: skriptet i footeren forsinker ikke første render, og defer garanterer at det heller ikke vil blokkere endelig rendering.

Bør jeg oppdatere WordPress til 6.3 bare for den native metoden?

Hvis nettstedet er på versjon 6.2 eller eldre, er det verdt å oppdatere ikke bare for strategy. WordPress 6.3 lukket dusinvis av sårbarheter og ga ytelsesforbedringer i kjernen. Men hvis en oppdatering er umulig av en eller annen grunn, fungerer script_loader_tag-filteret helt pålitelig fra versjon 4.1, utgitt i 2014. Du taper ingenting på å bruke det.

Hva med jQuery, defer eller la det være som det er?

jQuery bør lastes med defer hvis alle avhengige skripter også er merket defer. Problemet er at WordPress-utvidelser ekstremt sjelden håndterer attributter for skriptene sine. Hvis du setter defer på jQuery mens en kontaktskjema-utvidelse kobler til sitt skript uten attributter, vil nettleseren kjøre utvidelsen før jQuery og skjemaet vil ryke. Praktisk råd: start med defer for dine egne temaskripter. Ikke rør jQuery før du har testet hver eneste utvidelse på nettstedet.

Hva du bør bruke på et produksjonsnettsted i 2026

Hvis serveren kjører WordPress 6.3 eller nyere, kun den native metoden. Ren kode, beskyttelse mot avhengighetskonflikter, kjernestøtte. Start med defer for alle temaskripter og kritisk viktige utvidelser; reserver async for analyse og tredjeparts widgets.

Hvis versjonen er under 6.3, bruk script_loader_tag-filteret med en array av handles. Det har fungert i et tiår, ingenting å ødelegge. Det eneste det ikke kan gjøre er å automatisk sjekke avhengighetstreet, så legg til skripter i arrayen ett om gangen og sjekk nettstedet etter hvert.

Og viktigst av alt: ingen metode erstatter revisjon av selve skriptene. Hvis en galleriutvidelse kobler til 15 filer bare for å vise tre bilder, vil verken defer eller async hjelpe radikalt. Lastoptimalisering starter med spørsmålet «er dette skriptet i det hele tatt nødvendig», og først deretter, «hvordan skal det lastes».

🔗 Offisiell WordPress 6.3-dokumentasjon, Script Loading Strategies