Core Web Vitals on a review site: LCP images and shifting tables

Review pages fail Core Web Vitals in two predictable places: the LCP image the browser finds too late, and the layout shift that tables, logos and banners cause after the page has painted.

By The PokaTheme team 6 min read

In this article
  1. The LCP element is nearly always an image, and usually a late one
  2. What WordPress does, and where it guesses wrong
  3. Layout shift: the comparison table
  4. Layout shift: banners, cookie bars and the age statement
  5. Sorting, filtering and load more
  6. Measure the page you ship, not the demo
  7. A checklist for a review template

A review page is one of the hardest pages on a WordPress site to make fast: a table of twenty operators, each with a logo, a rating and a button, a hero image above it, and around all of that a cookie bar, an age statement and whatever an affiliate network injects.

This post covers the two vitals review pages actually fail — Largest Contentful Paint, because the biggest element is nearly always an image the browser finds late, and Cumulative Layout Shift, because tables and banners move things after the page has painted — and what to change in a theme to fix each. Figures are from web.dev and make.wordpress.org; where we quote our own theme we say what was measured and on what.

The thresholds have not moved: LCP 2.5 s or less, Interaction to Next Paint 200 ms or less, CLS 0.1 or less, for at least 75% of page visits. That last part is the one people skip. These are field metrics from real Chrome users, reported in Search Console; Lighthouse is a lab test, good for finding a cause and useless as proof. The job is the slow quarter of visits — old phones on mobile data, loading your heaviest page.

The LCP element is nearly always an image, and usually a late one

Per the 2024 Web Almanac, quoted by web.dev, 73% of mobile pages have an image as their LCP element. Of those, 35% had URLs that were not discoverable in the initial HTML, and only 15% of eligible pages used fetchpriority. Among pages with poor LCP, image loading was delayed by 1,290 ms at the 75th percentile — not download time, but the browser not knowing the image exists yet.

web.dev splits LCP into four parts, with a guide to how the time should fall:

SubpartShare of LCP
Time to First Byte~40%
Resource load delay, before the image starts loadingunder 10%
Resource load duration, downloading it~40%
Element render delay, after it arrivesunder 10%

Load delay is what review pages blow, and three rules fix it:

  • Put src or srcset in the initial HTML — not data-src, not a CSS background, not injected by script. If it is referenced only from CSS, preload it with as="image".
  • Put fetchpriority="high" on the one image you expect to be the LCP element, and low on off-screen ones. Marking four images high makes the hint meaningless.
  • Never put loading="lazy" on it. It always adds load delay.

What WordPress does, and where it guesses wrong

Since 6.3, core adds fetchpriority="high" to the image it judges most likely to be the LCP element, and keeps loading="lazy" off images likely to be in the first viewport. Two filterable numbers drive that:

add_filter( 'wp_min_priority_img_pixels', 'my_min_pixels' );
add_filter( 'wp_omit_loading_attr_threshold', 'my_omit_threshold' );

The first is the minimum area for high priority, 50,000 pixels by default, so icons are skipped. The second is how many leading images escape lazy loading, raised from 1 to 3 in 6.3 for multi-column layouts. Both can miss on a review page: a 200 × 60 operator logo is 12,000 pixels, yet on a listicle with no hero the first logo in the table is a plausible LCP element.

Core’s guess is a default, not a measurement. Check which element Chrome reports on your own template before changing either filter.

The other way to lose this is in the theme, and ours did. PokaTheme renders operator logos with get_the_post_thumbnail(), which asks core for a full srcset and sizes and gets them — then every template printed the result through wp_kses_post(), whose allowed-tag list has no entry for srcset, sizes, decoding or fetchpriority. The sanitiser rebuilt each tag without them, at 183 call sites. They survive in v5; grep your own theme for the same pattern.

Layout shift: the comparison table

66% of pages have at least one image with no dimensions. On a review site that is usually the logo column, which is the worst place for it, because every unsized logo moves everything below the table.

  • Set width and height on every <img>, or reserve the box with aspect-ratio, keeping the same ratio across srcset candidates.
  • Logos come in mixed shapes: give the cell a fixed box and fit the logo inside it with object-fit: contain, so a tall badge and a wide wordmark occupy identical space.
  • Web fonts shift tables of names and numbers when they swap. font-display: optional avoids the swap; size-adjust and ascent-override bring the fallback close enough that it barely moves.
  • Animate with transform, not top or margin: pages animating layout-inducing properties are 15% less likely to have good CLS.

Fonts are a trade rather than a free win. Moving our font stylesheet off the render path bought about 1.2 s of LCP and cost 0.021 and 0.018 CLS on two content pages, against a 0.100 budget.

A gambling affiliate page has more late-arriving boxes than most: a cookie notice, an age statement, a responsible-gambling line and one or more ad slots, each inserted by a different script.

  • Reserve the space before the box arrives, with min-height, or aspect-ratio for a responsive slot. Where the size varies, reserve the smallest you expect.
  • Do not collapse that space when nothing loads — removing it shifts the page as much as inserting content does.
  • Or overlay it, out of the document flow. For a cookie bar or an age statement that is usually the right answer, and the same shift near the top of the page scores much worse than it would lower down.

CLS is the worst burst, not the total: the highest-scoring window of shifts less than a second apart, capped at five seconds. Fixing the worst offender beats tidying five small ones.

Sorting, filtering and load more

Shifts within 500 ms of a tap, click or keypress are flagged hadRecentInput and excluded, so a sortable table that re-renders promptly is free; one that waits on a fetch is not. Swap the rows inside a fixed-height container. Scrolling and dragging do not count as input, so a sticky header that resizes on scroll is counted in full.

Measure the page you ship, not the demo

Timings move with the machine: our harness measured one unchanged commit at 1.06 s or 2.75 s of first paint depending on whether the paint won a race with a font fetch. That is why our release gate counts page weight — uncompressed bytes and requests per page — rather than timings.

Our measured figures are 100 / 100 on mobile on our test pages, with LCP 1.5–1.9 s against a 2.5 s budget and CLS 0.002–0.004. Those are three seeded probe fixtures on a development rig, not a customer’s site with their images and plugins on it. Every seller’s number deserves that footnote, ours included — one of the questions we suggested asking before you buy.

A checklist for a review template

  1. In Chrome DevTools, note which element is reported as LCP, on the homepage, a review and a listicle.
  2. Confirm its URL is in the HTML source, carries fetchpriority="high" and does not carry loading="lazy".
  3. Grep the theme for wp_kses_post() around image output, and check srcset survives it.
  4. Give every logo, badge and screenshot explicit dimensions or an aspect-ratio box, and reserve height for every ad slot, cookie bar and age statement.
  5. Load the page at phone width with the cache cleared, then sort the table and use load more.
  6. Compare with field data in Search Console a month later, not with the Lighthouse run you did on the day.

The quickest way to see how a template behaves is to load a finished site at phone width: the five demos are complete sites rather than screenshots, and their tables are described in comparison tables and head-to-head pages. Theme-side settings are in the documentation. If your review pages are failing and you cannot tell whether it is the theme, the plugins or the ad script, get in touch — a free SEO audit starts with these numbers.

Written by the PokaTheme team

PokaTheme is designed and built by Redshift web development, a small team in Thessaloniki, Greece, making WordPress themes for affiliate sites for more than ten years.