Head and SEO
Role
ReactWP supports two head-rendering moments:
- the initial WordPress page render through
wp_head - client-side navigation through the route payload returned by the REST endpoint
If you want a custom tag to exist in both cases, it must be generated through the rwp_wp_head filter.
The rwp_wp_head Filter
The filter signature is:
add_filter('rwp_wp_head', function($wp_heads, $context = []){
// ...
return $wp_heads;
}, 10, 2);
$wp_heads is an associative array of HTML strings keyed however you want.
Example:
add_filter('rwp_wp_head', function($wp_heads, $context = []){
$wp_heads['potato'] = '<meta name="potato" content="He is a vegetable.">';
return $wp_heads;
}, 10, 2);
Why The Second Parameter Matters
On a direct page load, WordPress is rendering the page normally, so conditional tags like is_front_page() work as expected.
During a React navigation, the head payload is built from the route resolver through the REST endpoint. In that context, conditional tags such as is_front_page() are not reliable enough to drive your logic.
That is why ReactWP also passes a second argument: $context.
$context Shape
ReactWP currently passes these keys:
sourceobjectroute
source
source tells you where the filter is being executed.
Possible values:
wp_headroute
object
object is the current WordPress object when one is available.
Examples:
WP_PostWP_TermWP_Usernull
route
route is the normalized ReactWP route payload when the filter is executed from the route resolver.
This is the same kind of payload the frontend uses during client-side navigation.
Useful values include:
$context['route']['path']$context['route']['template']$context['route']['pageName']$context['route']['is404']$context['route']['seo']
Front Page Example
This is the recommended pattern when a tag must work on both direct loads and React navigation:
add_filter('rwp_wp_head', function($wp_heads, $context = []){
$is_front = false;
if(($context['source'] ?? null) === 'wp_head'){
$is_front = is_front_page();
} elseif(($context['source'] ?? null) === 'route'){
$is_front = (($context['route']['path'] ?? null) === '/');
}
if($is_front){
$wp_heads['potato'] = '<meta name="vegetable" content="he-is">';
}
return $wp_heads;
}, 10, 2);
Initial Render vs React Navigation
ReactWP uses the same filter in two places:
- the SEO render layer during
wp_head - the route resolver when building
route.head
That means:
- direct load: the tag is printed by PHP
- client-side navigation: the tag is sent in the route payload and synced by the frontend runtime
If you only rely on a WordPress conditional without using $context, the tag may work on direct loads but fail after clicking through the React app.
Frontend Sync
The frontend reads route.head and updates the document head after navigation.
The relevant files are:
src/themes/reactwp/js/inc/useDocumentMeta.jssrc/mu-plugins/plugins/reactwp/template/inc/runtime/RouteResolver.phpsrc/plugins/reactwp-seo/template/inc/render.php
If route.head is present, ReactWP syncs those tags directly. If not, it falls back to a smaller SEO sync based on route.seo.