I am exploring how to build a theme where most of the pages are loaded using the Rest API. I can load the index page and from there make GET requests to get posts json data and after build its content in the current page. Basically a SPA, at least to some extent.
The problem comes when trying to load a single post and its scripts/styles. As an example, Gutenberg permits loading a script or/and a style for each registered block using the enqueue_block_assets
hook.
I am trying to figure out a way to get the registered styles and scripts url for a specific post. My idea is to register a rest route or a field that returns the url of each script/style. I can then attach each script/style to the DOM, after the single post json data has been mounted.
global $wp_scripts;
returns the registered scripts and also the enqueued ones in the current page load. So I could not find a way to get that info specifying the post id from outside the single page load flow.
How can I get the list of enqueued/registered scripts and styles url for any specific post id?
or
Is there a better approach?
1 Answer
I’m not familiar with Gutenberg, but as you mentioned it as an example, I assume you didn’t mean “only” Gutenberg.
The wp_enqeue_script()
or wp_enqueue_style()
functions do not accept arguments regarding posts or pages. The script are registered and rendered globally. If a script is output on certain posts only, then it has to be a native PHP conditional, which is not easy to determine.
One idea would be to include only a index.php
file in your theme, and add only wp_head()
and wp_footer()
in it. Then on each rest request, fetch the content of the real HTML page using wp_remote_get()
and run a preg_match_all()
to extract all the scripts from that page, and add it to your rest fields. It’s kind of messy, but reliable.
Don’t forget to cache the results in either a transient, or an object cache for increased performance.
Here’s a basic example about how to do so:
// Let's register a new field for returning the script srcs
add_action( 'rest_api_init', 'wpse320065_register_rest_field' );
function wpse320065_register_rest_field() {
register_rest_field(
'post',
'your-field-name',
[
'get_callback' => 'wpse320065_fetch_post_cont',
'schema' => null,
]
);
}
// Callback function to actually retrieve the data
function wpse320065_fetch_post_cont( $object ) {
// Get the id of the post object array
$post_id = $object['id'];
// Let's get the content of post number 123
$response = wp_remote_get( "http://example.com/?p={$post_id}" );
if ( is_array( $response ) ) {
$content = $response['body'];
// Extract the src attributes. You can also use preg_match_all
$document = new DOMDocument();
$document->loadHTML( $content );
// An empty array to store all the 'srcs'
$scripts_array = [];
// Store every script's source inside the array
foreach( $document->getElementsByTagName('script') as $script ) {
if( $script->hasAttribute('src') ) {
$scripts_array[] = $script->getAttribute('src');
}
}
}
return $scripts_array
}