ForgeWP

The Sharp Image Optimization Pipeline

How ForgeWP generates build-time WebP variants, caches image work, and handles eligible image preloads.

In traditional WordPress sites, image optimization is often handled by heavy runtime PHP plugins (like Smush or Imagify) or third-party cloud SaaS proxies. These plugins compress images dynamically on the server or charge monthly fees for CDN bandwidth.

ForgeWP includes a build-time Sharp pipeline that runs during pnpm export. It processes eligible local raster assets and can download external images when optimize="build" is explicitly requested.


1. Traditional WordPress vs. ForgeWP Image Pipelines

Flowchart
Rendering diagram...

By pre-processing images at compile time:

  • No Build-Time Image Processing on WordPress: Eligible theme assets are processed during export rather than recompressed for each page request.
  • Static Asset Delivery: Generated files live in the exported theme and are served like other theme assets.
  • No Monthly SaaS Subscriptions: Image compression happens on your development machine before deployment.

2. Next-Gen WebP Variants & Responsive Breakpoints

When you run pnpm export, the compiler scans all static image imports and local graphics referenced by <WpImage>:

  1. WebP Generation: Creates WebP variants for eligible local raster assets. Source dimensions and configured quality determine the output; compare generated variants to choose the right balance for your images.
  2. Standard Candidate Widths: The optimizer considers these default widths and skips any larger than the source image:
TYPESCRIPT
1export const DEFAULT_RESPONSIVE_WIDTHS = [480, 768, 1024, 1440, 1920]
  1. No Upscaling: ForgeWP does not enlarge a source image. It also includes the original width when it is not already one of the candidate widths.
Compiler Output inside .forgewp/out/my-theme/assets/images/
hero-banner-480w.webp       # Generated if the source is at least 480px wide
hero-banner-768w.webp       # Generated if the source is at least 768px wide
hero-banner-1024w.webp      # Generated if the source is at least 1024px wide
hero-banner-1200w.webp      # Original width may be added as a candidate

The compiler attaches generated variants as srcset candidates to matching local static images rendered through <WpImage> or a standard <img>. It also emits sizes and intrinsic dimensions when they are not already supplied. The original image remains the fallback src; the browser chooses a suitable WebP candidate from srcset. For WordPress Media Library images, wp_get_attachment_image() uses WordPress's registered image sizes and responsive attributes.


3. Responsive Breakpoints & the sizes Prop

To ensure mobile devices don't download oversized desktop images, use the sizes prop on <WpImage>:

src/components/CardGrid.tsx
1import { WpImage } from "@forgewp/react"
2
3export function ArticleCard({ post }: { post: any }) {
4  return (
5    <div className="flex flex-col rounded-2xl border border-border bg-card p-4">
6      <WpImage
7        field="featuredImage"
8        size="large"
9        // 100vw on mobile, 50vw on tablet, 33vw on desktop
10        sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
11        className="h-48 w-full rounded-xl object-cover"
12        alt={post.title}
13      />
14      <h3 className="mt-4 font-bold text-foreground">{post.title}</h3>
15    </div>
16  )
17}

For a WordPress attachment rendered through field="featuredImage" or id={...}, WordPress can use its registered sizes and responsive srcset. For a local static image, the export attaches generated variants automatically when the image is found in the asset graph; a provided sizes value overrides the pipeline's default.


4. Preventing Cumulative Layout Shift (CLS) with Blur Placeholders

Cumulative Layout Shift (CLS) occurs when an image loads without reserved layout space. Provide intrinsic dimensions or give the image wrapper a stable aspect ratio:

src/components/MediaBanner.tsx
1<WpImage
2  src="/assets/banner.png"
3  width={1200}
4  height={675}
5  className="w-full object-cover"
6/>

The browser can reserve space from the intrinsic dimensions. If you use a wrapper with aspect-video, make the image fill that wrapper with CSS.

Blur Placeholder API Status

WpImage exposes placeholder="blur" and blurDataURL props for client rendering. Sharp records a generated blur value in asset metadata, but the current PHP markup processor does not inject that value into exported <WpImage> output. Do not rely on automatic blur-up placeholders in the exported theme. A supplied blur data URL also does not replace image dimensions or a stable layout box.


5. Persistent SHA-256 Build Caching

Image processing can slow down builds if every asset is re-encoded on each export. ForgeWP includes an automated image cache:

  • Location: .forgewp/cache/images/manifest.json
  • Cache Key: A deterministic SHA-256 hash computed from the source image buffer and requested widths, quality, and public URL prefix.
  • Instant Incremental Builds: When you run pnpm export, already-optimized images are retrieved from cache in milliseconds. Only new or modified assets trigger Sharp encoding.

6. Preloading Above-the-Fold Media (priority={true})

For your page's primary Hero or Largest Contentful Paint (LCP) element, apply priority={true}:

src/app/page.tsx
1<WpImage
2  src="/assets/hero-desktop.jpg"
3  size="full"
4  priority={true}
5  alt="Main Website Hero"
6  className="h-125 w-full object-cover"
7/>

When priority={true} is enabled, the compiler marks the image with high fetch priority and eager loading. For a statically resolved image source, export also generates a preload tag whose responsive candidates match the rendered image's srcset:

Generated HTML <head>
1<link
2  rel="preload"
3  as="image"
4  imagesrcset="<?php echo esc_url( get_theme_file_uri( 'assets/images/hero-desktop-480w.webp' ) ); ?> 480w, …"
5  imagesizes="(max-width: 1024px) 100vw, 50vw"
6  fetchpriority="high"
7/>

Browsers use this hint to prioritize loading. Inspect the generated HTML and measure the page to tune preload behavior.


Common Questions & FAQs

Does the build-time Sharp pipeline optimize images uploaded by clients in the WordPress Media Library?

No. The Sharp pipeline specifically optimizes theme assets and static graphics bundled inside your theme repository at build time. Images uploaded dynamically by content editors in the WordPress admin are managed by WordPress core's media system (wp_get_attachment_image), which generates responsive sub-sizes upon upload. ForgeWP's <WpImage> bridges both worlds seamlessly.

Do I need to install libvips or C++ build tools on my development machine?

No! Sharp includes pre-compiled native binaries for macOS (Apple Silicon and Intel), Linux, and Windows x64. When you install ForgeWP dependencies via pnpm install, the appropriate native platform binary is fetched automatically.


Section Summary

You now have a complete, production-grade understanding of media handling in ForgeWP:

  1. The <WpImage> Primitive connects your React components to WordPress featured images, attachment IDs, and responsive sizes.
  2. Local Assets & Icons separates root public/ files from bundled src/assets/, with automatic theme URI resolution and zero-runtime <WpIcon> vector glyphs.
  3. The Sharp Pipeline generates cached WebP variants for eligible raster assets. Check the asset report and exported markup to confirm how each image is served.

Next Section: Components & Registry

Now that you can style layouts and render responsive media, discover how to install and author modular UI primitives with the ForgeWP Component Registry!

Proceed to The Component Registry.