Media Pipeline
Why It Exists
ReactWP can describe route media in PHP, download it before or after a reveal, cache same-origin responses, and render the final media element into a React placeholder.
This is useful when image, video, or audio timing is part of the transition design. It is optional: normal <img>, <video>, and <audio> elements still work when the loader does not need to own them.
The Three Asset Maps
The bootstrap payload exposes:
assets.criticalFontsassets.criticalMediasassets.noCriticalMedias
Register them in PHP with:
rwp_critical_fontsrwp_critical_mediasrwp_no_critical_medias
Every map is grouped. The loader always includes all, then adds the comma-separated groups declared by the current route's mediaGroups value.
For a route with mediaGroups: "about, shared", the loader resolves all, about, and shared.
Critical vs Deferred
Critical media is downloaded and rendered before the route finishes its critical reveal. Use it for the first visible image or media that must be present when the transition enters.
Deferred media starts separately and renders after the critical phase. Deferred groups download in parallel, but each group can render as soon as its own work is ready. One slow group does not hold every deferred image.
Registering an Image
add_filter('rwp_critical_medias', function($medias){
$medias['home'][] = [
'type' => 'image',
'src' => get_stylesheet_directory_uri() . '/assets/images/hero.jpg',
'target' => '#home-hero .img',
'alt' => 'Project exterior',
'className' => 'hero-image',
'sources' => [
[
'src' => get_stylesheet_directory_uri() . '/assets/images/hero-mobile.jpg',
'media' => '(max-width: 767px)'
]
]
];
return $medias;
});
An entry can use:
type:image,video, oraudiosrc: primary source URLtargetortargets: selector, element, or list of targetssources: responsive image sources or media source children- DOM properties such as
alt,className,poster,muted,loop,controls,autoplay, andplaysInline
For images with sources, ReactWP builds a <picture>. For video and audio it builds source children before starting display playback behavior.
React Placeholders
The shipped Image, Video, and Audio components render the target structure expected by the loader.
import Image from '../components/Image';
const Hero = () => (
<section id="home-hero">
<Image className="hero-media" />
</section>
);
Image creates .img-container > .inner-img > .img. Point the PHP media entry at the inner .img slot, not at a selector shared by unrelated items.
Targets are resolved when display begins, after the route component has mounted. If a target does not exist, the download still settles and the loader skips that replacement instead of blocking navigation forever.
ACF Media Groups
ReactWP registers a media_groups route field for pages, posts, users, taxonomies, and any additional post types selected in Site settings.
The route resolver sends that value as route.mediaGroups. This field selects existing code-defined groups; it does not create the media entries by itself.
Dynamic Lists and Carousels
For a CMS-driven list whose length changes, normal JSX media is often the clearer choice. Loader targets are best when the selector is stable and one media entry has one unambiguous destination.
Avoid targeting :nth-child() positions in filtered or reordered lists. React can reuse positions while the content identity changes. Use stable item IDs in selectors, or render the item image directly from its data.
Caching
Same-origin media requests can be stored in the versioned Cache Storage managed by Cache.js. ReactWP may render a blob URL created from that response and revoke old blob URLs when they are replaced.
Cross-origin responses depend on the remote server's CORS behavior and may not be writable to Cache Storage. The loader still falls back to a normal fetch path when cache operations are unavailable.
See Cache and Invalidation for generation changes and manual invalidation.
Debugging the Lifecycle
Observe the current route through:
window.loader.route
Wait for one deferred group with:
await window.loader.noCriticalDisplayGroups.home
The complete promise list is documented in Loader.