Skip to content

Performance

This page explains the performance strategy for Naluma WordPress --- the layered approach combining CDN delivery, image optimization, script management, resource hints, and speculative loading. Each layer addresses a different bottleneck in the page load waterfall.

Performance Philosophy

Medical information sites have a specific performance profile: content-heavy pages with images, long-form text, and third-party analytics scripts. The audience includes patients on mobile devices, often in situations where they are anxious and impatient. Core Web Vitals (LCP, CLS, INP) directly affect both search ranking and user experience.

The strategy is:

  1. Serve from the edge. Kinsta CDN + Cloudflare puts cached content close to users.
  2. Optimize the heaviest assets. Images are the largest payload on content pages.
  3. Defer what is not critical. Analytics and consent scripts should not block rendering.
  4. Hint at what comes next. Resource hints and speculation rules prepare the browser for likely navigations.
  5. Let WordPress handle the orchestration. Performance Lab modules integrate natively with WordPress core rather than adding another abstraction layer.

CDN and Hosting

Kinsta's managed hosting provides several performance features at the infrastructure level:

Kinsta CDN (Cloudflare-backed). All static assets and cached pages are served from Cloudflare's edge network. This reduces time-to-first-byte (TTFB) for geographically distributed users.

Automatic WebP conversion via Cloudflare Polish. Cloudflare automatically converts JPEG and PNG images to WebP format when the browser supports it. This is a CDN-level transformation --- no WordPress plugin is needed for WebP delivery. The webp-uploads Performance Lab module fills the remaining gap by generating WebP versions at upload time, which is important for the REST API (the Flutter app requests images directly, not through the CDN).

Server-level caching. Kinsta manages full-page caching at the Nginx level. The kinsta-mu-plugins package provides cache purging integration with WordPress --- when content is updated, the relevant cached pages are automatically invalidated.

Server-level cron. WordPress's built-in wp-cron.php is unreliable because it piggybacks on visitor requests. Kinsta provides a true server-level cron job that fires on schedule regardless of traffic. This is why DISABLE_WP_CRON is set to true in config/application.php:

Config::define('DISABLE_WP_CRON', true);

Why disable WP-Cron?

wp-cron.php runs on every page load and checks if any scheduled tasks are due. On a low-traffic site, tasks may run late; on a high-traffic site, concurrent cron runs can cause race conditions. Kinsta's server-level cron eliminates both problems while also removing the overhead of cron checks from every page request.

Performance Lab Modules

The WordPress Performance Lab project develops performance features as standalone plugins before they graduate into WordPress core. Naluma uses 11 modules, each addressing a specific performance concern:

Image Optimization

Module Purpose Core Web Vital
auto-sizes Adds sizes="auto" to lazy-loaded images, letting the browser calculate the correct size based on layout rather than using a static sizes attribute LCP, CLS
dominant-color-images Extracts the dominant color of each image at upload time and uses it as a CSS placeholder background while the image loads CLS
image-prioritizer Detects above-the-fold images and adds fetchpriority="high" while ensuring below-the-fold images are lazy-loaded LCP
webp-uploads Generates WebP versions of uploaded images alongside the original format LCP

These four modules form a comprehensive image pipeline:

graph LR
    Upload["Image Upload"] --> WebP["webp-uploads<br/>Generate WebP"]
    Upload --> DomColor["dominant-color-images<br/>Extract placeholder color"]
    WebP --> Render["Page Render"]
    DomColor --> Render
    Render --> AutoSizes["auto-sizes<br/>Correct sizes attribute"]
    Render --> Priority["image-prioritizer<br/>fetchpriority for ATF images"]

CDN handles the rest

Cloudflare Polish provides an additional optimization layer on top of these plugins. Images that webp-uploads already converted serve directly as WebP; images that were not converted (e.g., uploaded before the plugin was active) get converted at the CDN edge.

Script and Resource Optimization

Module Purpose Core Web Vital
optimization-detective Collects real-user metrics about element visibility and layout to inform other modules' decisions LCP, CLS
embed-optimizer Lazy-loads third-party embeds (YouTube, Twitter, etc.) and replaces them with lightweight placeholders until interaction LCP, INP
performant-translations Loads translations using a performance-optimized format (PHP files instead of .mo binary), reducing memory usage and load time on multilingual sites TTFB
web-worker-offloading Moves non-critical JavaScript execution to a Web Worker, keeping the main thread free for user interaction INP
Module Purpose Core Web Vital
speculation-rules Injects the Speculation Rules API to prefetch or prerender pages the user is likely to navigate to next LCP (next page)
view-transitions Enables the View Transitions API for smooth animated page transitions between navigations Perceived perf
nocache-bfcache Ensures no-cache pages are excluded from bfcache (back/forward cache), preventing stale content display Correctness

Speculation Rules deserves special attention. Instead of prefetching every link on the page (wasteful), the Speculation Rules API uses browser-level heuristics to predict which links the user will click and prerenders them in advance. When the user does click, the page appears to load instantly because it was already rendered in the background.

Flying Scripts: Deferred JavaScript

The Flying Scripts plugin complements the Performance Lab modules by providing fine-grained control over when third-party scripts execute. It delays specified scripts until user interaction (mouse movement, scroll, keypress, or touch), preventing them from blocking the initial page render.

This is particularly important for:

  • Google Tag Manager (GTM) --- a substantial JavaScript bundle that is not needed until the user interacts with the page
  • PostHog analytics --- similarly non-critical for initial rendering
  • Complianz consent manager --- the consent banner needs to appear quickly, but the full consent logic can load after interaction

The result is a faster Largest Contentful Paint (LCP) because the browser's main thread is not occupied parsing and executing analytics scripts during the critical rendering path.

Resource Hints (performance-hints.php)

The performance-hints.php mu-plugin adds two types of resource hints to the <head> of every frontend page:

Preconnect

<link rel="preconnect" href="https://www.googletagmanager.com">

Preconnect tells the browser to establish a TCP connection, perform the TLS handshake, and resolve DNS for the specified origin before the script tag that actually loads it is parsed. This saves 100--300ms of connection setup time when the script eventually loads.

Google Tag Manager is preconnected because it loads on every page (even if deferred by Flying Scripts, the connection setup happens early so the script loads faster when triggered).

DNS Prefetch

<link rel="dns-prefetch" href="https://eu-assets.i.posthog.com">

DNS prefetch is a lighter hint --- it only resolves the domain name, without establishing a connection. This is used for PostHog's asset CDN because it is consent-gated: the full connection may never happen if the user does not accept analytics cookies. DNS resolution is cheap enough to do speculatively without wasting resources.

Why two different hint types?

Preconnect is more aggressive (DNS + TCP + TLS) and should be reserved for origins that will definitely be contacted. DNS prefetch is lighter and appropriate for origins that may be contacted depending on user behavior or consent status. Using preconnect for consent-gated origins wastes connection resources on users who decline cookies.

The hints are only output on frontend pages (is_admin() check prevents them from appearing in the admin dashboard).

How the Layers Interact

A typical page load for a Naluma article illustrates how these layers work together:

sequenceDiagram
    participant User
    participant CDN as Kinsta CDN
    participant WP as WordPress
    participant Browser

    User->>CDN: Request /tinnitus-behandlung/
    CDN->>CDN: Cache hit? Return cached page
    CDN-->>Browser: HTML (with resource hints)

    Note over Browser: Parse HTML
    Browser->>CDN: Preconnect to GTM origin
    Browser->>CDN: DNS prefetch for PostHog
    Browser->>CDN: Load CSS (critical path)

    Note over Browser: Render first paint

    Browser->>CDN: Load hero image (fetchpriority=high)
    Note over Browser: dominant-color placeholder shown
    CDN-->>Browser: WebP image from cache
    Note over Browser: LCP complete

    Note over Browser: Lazy-load below-fold images (auto-sizes)

    User->>Browser: First interaction (scroll/click)
    Browser->>CDN: Load GTM (deferred by Flying Scripts)
    Browser->>CDN: Load PostHog (if consent given)

    Note over Browser: speculation-rules prefetches next likely page
    User->>Browser: Click internal link
    Note over Browser: Instant navigation (prerendered)

The key insight is that performance is not a single optimization but a pipeline where each layer handles a different phase of the page lifecycle:

  1. Infrastructure (CDN, caching) minimizes server response time
  2. Image optimization (Performance Lab modules) minimizes the largest content element
  3. Script deferral (Flying Scripts) keeps the main thread free during rendering
  4. Resource hints (performance-hints.php) parallelizes network setup
  5. Speculation rules make the next navigation fast, not just the current one

This layered approach means no single plugin failure degrades performance catastrophically --- each layer provides independent value.