Når en WordPress-side føles treg, er første refleks ofte å bytte hosting. Det er sjelden det riktige første steget. De fleste flaskehalsene sitter i PHP-bootstrap, MySQL-spørringer, autoload-data og front-end-ressurser du kan måle og fikse uten å bytte maskin.
Denne guiden er en praktisk ytelsesgjennomgang for utviklere og tekniske redaktører: hvordan du måler TTFB, leser Query Monitor, rydder wp_options, skriver sunnere WP_Query, vurderer Redis/object cache, og kobler arbeidet til LCP, INP og CLS. Offisiell WordPress-veiledning for samme lag finnes under performance optimization.
Hosting vs kode: hva problemet egentlig er
Hosting påvirker CPU, I/O, PHP-FPM-workers og avstand til brukeren. Kode påvirker hvor mye arbeid hver HTTP-forespørsel gjør før første byte forlater serveren.
Bytt hosting når:
- en nesten tom PHP-side (uten page cache) fortsatt har dårlig TTFB etter at du har fjernet åpenbare plugins og autoload-søppel
- CPU-throttling eller disk-I/O er synlig under reell samtidighet
- opprinnelsesserveren ligger geografisk feil for hovedmålgruppen, og edge/page cache ikke dekker dynamiske maler
Ikke bytt hosting når:
- Query Monitor viser titalls dupliserte spørringer eller trege
SELECTmotwp_postmeta - autoload i
wp_optionser oppblåst etter år med plugin-tester - LCP kollapser på et hero-bilde uten dimensjoner eller moderne format
- INP er dårlig fordi page builder-skript og chat-widgets kjører på hovedtråden
På norske butikkfronter ser jeg ofte at forsiden «ser grei ut» i et lab-kjøring fra et CDN-nært sted, mens produktsider med Vipps- og Klarna-widgets lastet synkront i headeren er det som faktisk rammer feltedata. Mål den malen kundene bruker, ikke bare forsiden.
Mål TTFB før du endrer noe
Time to First Byte er tiden fra forespørselen sendes til første byte av responsen mottas. I WordPress er TTFB den beste tidlige indikatoren på backend-helse: DNS, TLS, PHP-bootstrap, SQL og eventuell page cache.
Mål fra terminalen med curl, slik at du skiller DNS, TCP, TLS og serverarbeid:
curl -o /dev/null -s -w "DNS: %{time_namelookup}s | Connect: %{time_connect}s | TLS: %{time_appconnect}s | TTFB: %{time_starttransfer}s | Total: %{time_total}s\n" https://eksempel.no/Tolking i praksis (uten fabrikkerte «bransjesnitt»):
- lav TTFB på cachede HTML-sider er forventet når page/edge cache treffer
- høy TTFB på en cache-miss eller innlogget sesjon peker mot PHP/MySQL
- høy
time_namelookupeller TLS-tid er nettverks-/sertifikatlag, ikke WordPress-kode
Sammenlign tre URL-er: forside, én tung arkiv-/produktside, og wp-login.php (eller en annen autentisert mal). Forskjellen mellom cache-hit og cache-miss forteller mer enn ett enkelt lab-tall.
Chrome DevTools → Network → dokumentets Timing-panel gir samme historie visuelt. Noter TTFB før og etter hver endring. Uten baseline optimaliserer du i blinde.
Query Monitor: profilér, ikke gjett
Query Monitor er det vanligste gratis verktøyet for å se hva WordPress faktisk gjør på staging. Aktiver den bare i utviklings-/stagingmiljø, ikke som permanent produksjonspanel for anonyme besøkende. På produksjon kan den eksponere SQL, stier og brukermeta for innloggede redaktører - hold den bak staging eller en IP-begrenset kopi.
Etter aktivering, last den trege malen og les:
- antall SQL-spørringer for den aktuelle forespørselen
- spørringer merket som trege (lang varighet)
- duplikater mot
wp_posts,wp_postmetaellerwp_options - HTTP API-kall (
wp_remote_get/wp_remote_post) som blokkerer render - komponenten som trigget spørringen (tema, plugin, mu-plugin)
- PHP-feil og hooks som kjører uventet tidlig i bootstrap
Typiske funn på eldre norske bedriftssider:
- samme
WP_Querykjørt i header, widget og shortcode - meta-oppslag i løkke uten
update_post_meta_cache/ fornuftig batching - cron eller security-scan-plugins som treffer eksterne API-er under front-end-render
- oversettelses- eller SEO-plugins som laster store option-arrays på hver forespørsel
Fiks rekkefølge: fjern eller erstatt den dyreste komponenten først, mål på nytt, deretter neste. En cache-plugin oppå mange dårlige spørringer skjuler problemet til cache-missen treffer. Ta gjerne et skjermbilde eller eksporter spørringslisten før du deaktiverer noe, slik at du kan sammenligne neste baseline.
Når du profiler WooCommerce-maler, last både katalog, enkeltprodukt og handlekurv. De tre malene har ulike hook-sett; en «rask» forside sier lite om checkout-stien.
Autoload i wp_options
WordPress henter rader med autoload = 'yes' tidlig i bootstrap, på nesten hver forespørsel - også REST og mange admin-ajax-kall. Etter år med installerte og slettede plugins kan autoload-massen bli stor nok til at PHP bruker mer tid på deserialisering enn på å bygge HTML.
Sjekk total størrelse:
SELECT ROUND(SUM(LENGTH(option_value)) / 1024, 2) AS autoload_kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto', 'auto-on');Finn de største radene:
SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto', 'auto-on')
ORDER BY bytes DESC
LIMIT 20;Med WP-CLI (når du har shell-tilgang):
wp option list --autoload=on --format=tablePraktiske regler:
- slett foreldreløse rader fra plugins som ikke lenger finnes
- sett store, sjelden brukte options til ikke-autoload når API-et tillater det (
autoloadiadd_option/update_option) - ikke skru av autoload på kjernerader du ikke forstår; ta backup først
Autoload-rydding senker ofte TTFB på cache-miss mer enn nok en «speed»-plugin.
no_found_rows og sunnere WP_Query
Standard WP_Query kjører en ekstra SQL_CALC_FOUND_ROWS / count-logikk for paginering. Når du bare trenger N innlegg og ikke trenger totalt antall sider, slå det av:
$query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => 5,
'post_status' => 'publish',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
)
);Bruk update_post_meta_cache og update_post_term_cache bare når malen faktisk trenger meta/termer for alle treff. For en enkel «siste fem tittel-lenker»-widget er de unødvendige.
Persistente resultater hører hjemme i object cache, ikke i å kjøre samme spørring på hver sidevisning:
function wpp_get_latest_post_ids() {
$cache_key = 'wpp_latest_post_ids_v1';
$cached = wp_cache_get( $cache_key, 'wpp' );
if ( false !== $cached ) {
return $cached;
}
$query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => 5,
'fields' => 'ids',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
)
);
$ids = $query->posts;
wp_cache_set( $cache_key, $ids, 'wpp', HOUR_IN_SECONDS );
return $ids;
}Uten persistent backend (Redis/Memcached) er wp_cache_* per-forespørsel. Det hjelper fortsatt mot duplikater innen samme request, men ikke på tvers av besøkende.
Redis og object cache
WordPress object cache lagrer objekter i minnet via WP_Object_Cache. Uten drop-in er den ikke-persistent. Med Redis eller Memcached overlever data mellom forespørsler og reduserer gjentatte oppslag i wp_options, transients og genererte resultater.
Når object cache lønner seg:
- Query Monitor viser høy DB-tid selv etter autoload-rydding
- mange samtidige innloggede brukere (redaksjon, WooCommerce-kontoer)
- dynamiske maler som ikke kan full-page-caches trygt (handlekurv, checkout, personaliserte dashboards)
Når det er overkill:
- lavtrafikk bedriftsside med sunn page cache og få plugins
- hosting uten Redis/Memcached tilgjengelig og uten vilje til å drifte det
WordPress-dokumentasjonen under performance optimization dekker caching-lagene. Installer en vedlikeholdt object-cache-drop-in som matcher hostens Redis-tilkobling, verifiser med wp cache type (WP-CLI) eller Query Monitor, og sørg for at cache invalideres ved publisering og lagerendringer.
Page cache og object cache er komplementære: page cache sparer hele HTML-genereringen for anonyme GET-er; object cache reduserer kostnad når PHP likevel må kjøre.
Driftsdetaljer som ofte glemmes: bruk et eget Redis-databaseindeks eller nøkkelprefiks per miljø (staging vs produksjon), overvåk minnebruk så eviction ikke tømmer viktige nøkler midt i rush, og test at SAVE_POST / WooCommerce-lageroppdateringer faktisk tømmer relevante grupper. En «varm» cache som serverer gamle lagerstatuser er verre enn en treg, korrekt side.
Core Web Vitals i kortform
Feltedata for rangering og brukeropplevelse går via Core Web Vitals. Tre metrikker du må koble til WordPress-arbeidet:
| Metrikk | Hva den måler | Typisk WordPress-årsak |
|---|---|---|
| LCP | når største innholdselement males | treg TTFB, hero uten width/height, blokkerende CSS, tungt bilde |
| INP | responstid på interaksjoner | page builder-JS, jQuery-plugins, chat, filtrering i katalog |
| CLS | layoutskift | bilder uten dimensjoner, sene webfonter, innsatte banners |
INP erstattet FID. Artikler som bare snakker om FID er utdaterte.
Arbeidsrekkefølge som matcher målingene:
- Senk TTFB (autoload, SQL, cache) - det mater LCP.
- Fiks LCP-elementet (format, størrelse, prioritet, CDN for media).
- Kutt hovedtråd-JS for INP på de malene brukerne klikker.
- Sett eksplisitte dimensjoner og stabile plassholdere for CLS.
Lab (Lighthouse/PageSpeed) er nyttig for reproduserbare endringer. Feltedata (CrUX / Search Console) er det som teller for «god» / «trenger forbedring» i Google. Mål mobil for Norge når det er markedssegmentet ditt.
Bilder, skript og plugins uten magi
Etter backend-hygiene:
- lever hero og produktbilder i moderne formater (WebP/AVIF der støttet), med
srcset/sizes - last ikke Google Fonts synkront fra tredjepart hvis du kan self-hoste med
font-display: swap - unngå to «speed»-plugins som begge minifiserer og deferred den samme køen
- deaktiver plugins som ikke er i den kritiske forretningsstien; mål spørringsantall etter hver deaktivering
- last betalings- og fraktwidgets bare på handlekurv/checkout når det er mulig, ikke globalt i
wp_head
Output-komprimering (gzip/Brotli) hører hjemme i webserver eller CDN, ikke som en tilfeldig ob_gzhandler i temaet hvis hosten allerede komprimerer. Dobbel komprimering gir sjelden gevinst og kan skape feil.
Et praktisk plugin-audit-mønster: klon staging, deaktiver alt utenom WooCommerce/tema (eller tilsvarende kjerne), mål TTFB og spørringsantall, aktiver tilbake én forretningskritisk plugin om gangen. Behold bare det som flytter en forretningsmetrikk - ikke det som «kan være nyttig senere». To overlappende bildekomprimeringsplugins og to sikkerhetsskannere er et klassisk norsk SMB-oppsett etter år med byråbytter; rydding der gir ofte mer enn nyere maskinvare.
En arbeidssekvens for én diagnostikksyklus
- Ta TTFB-baseline med
curlpå forside, tung mal og innlogget/dynamisk mal. - Kjør Query Monitor på staging for den tunge malen; skriv ned topp fem spørringer og HTTP-kall.
- Mål autoload-KB; fjern eller deaktiver autoload på åpenbart døde store rader.
- Legg til
no_found_rows(og tynnere cache-flagg) der paginering ikke trengs. - Vurder Redis hvis DB-tid fortsatt dominerer etter steg 3-4.
- Koble LCP/INP/CLS til konkrete front-end-endringer; verifiser i lab, følg feltedata over tid.
Relatert lesning internt: SEO- og GEO-optimalisering. Eksternt: TTFB, LCP, INP, CLS og WordPress performance optimization.
Oppsummering
Treg WordPress er sjelden «bare hosting». Start med målt TTFB, les Query Monitor, rydd autoload, skriv tynnere spørringer med no_found_rows, legg til persistent object cache når PHP fortsatt må kjøre, og knytt front-end-arbeidet til LCP, INP og CLS. Hostingbytte kommer etter at koden og cache-lagene er ærlige - ikke før.






