4

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?

  • Have you tried to list about the global $GLOBALS['wp_styles']->do_items(); for styles. This should only list all styles, there are still loaded on the current page? That's should also work for the $wp_scripts . – bueltge Nov 30 '18 at 14:44
  • @bueltge thanks for the suggestion. The problem, as far as I understand, is that the global is set on the page load, so if I'm loading post 123, then I'll get the list for this post when calling the method. But if Im outside, let's say in an index page, calling it would give me the list for the current index page. – Alvaro Nov 30 '18 at 15:36
2
+50

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

}
  • Thanks for the answer. I suspected about the HTML, but didn't know about wp_remote_get. Could you please elaborate on how to apply it inside the rest route/field from the template file? I'm not sure how would I do so to get, lets say, post with id 123. – Alvaro Nov 28 '18 at 20:53
  • You're welcome. I have updated my answer for you. – Jack Johansson Nov 29 '18 at 0:35
  • Thank you very much. This solution works but I had some issues with wp_remote_get response until I could find how to properly set it. Which makes me wonder there might be similar/other issues with other servers. – Alvaro Nov 30 '18 at 15:33
  • You're welcome. The wp_remote_get() function is simply a wrapper, you can use the native curl command of PHP, if you're having trouble using the former. – Jack Johansson Dec 1 '18 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.