On many websites, you can have content embedded from other sites and one way that most external sites will offer will be to include a script that’s hosted on their website.

But if all that script does is including some remote content there are better ways to get that, that will provide customizations and performance.

For example, the website Goodreads offers such an embed JS with a list of the latest books you read, and you must include the script where you want the content to be shown. But that has a long list of drawbacks: the script uses the old API document.write, is a script and can’t be loaded in AMP, the scripts write very old style HTML with tags like center, attributes like border which again is not valid AMP, then also that script will be loaded for every request, so you’ll have one additional request.

We have two methods to improve this process and the second one is even better than the first one. The first way is to use our server to fetch the script content then use a JS script to modify the content so that is valid and modern.

The second way is to use only the server to fetch and change the content and insert it from time to time.

First Method

In this example we use WordPress on the server side so we make a REST endpoint that only fetches the content:

//...

add_action('rest_api_init', 'change_rest_post' );
function change_rest_post(){
    register_rest_route( 'a309/v1', '/gr-widget', array(
    'methods' => 'GET',
    'callback' => 'a309_get_gr_widget',
    'permission_callback' => '__return_true',
  ) );
   
}

function a309_get_gr_widget(){
    echo file_get_contents("https://www.goodreads.com/review/custom_widget/52338687.Andrei's%20bookshelf:%20read?cover_position=left&cover_size=small&num_books=5&order=d&shelf=read&show_author=1&show_cover=1&show_rating=1&show_review=1&show_tags=1&show_title=1&sort=date_added&widget_bg_color=FFFFFF&widget_bg_transparent=true&widget_border_width=none&widget_id=1613506906&widget_text_color=000000&widget_title_size=medium&widget_width=medium");
}
//...

So practically is just an echo of the script contents.

Then is our JS we can have something like:

(async () => {
   const grFurl = `${window.location.origin}/wp-json/a309/v1/gr-widget`;
   const response = await fetch(grFurl,{ mode: 'cors',  headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    } });
   if(response.ok){
       const widgetId = 'gr_custom_widget_1613506906';
       const respTxt = await response.text();
       let widgetHTML = respTxt.match(/=([^]+)widget_div =/gm)[0];
       if(widgetHTML){        
       widgetHTML = widgetHTML.replace('  var widget_div =','');
       widgetHTML = widgetHTML.substring(3).slice(0, -2).trim();
       widgetHTML = widgetHTML.replace(/\\\//gm, '/').replace(/\\n/gm, '');
       widgetHTML = widgetHTML.replace(/\\"/gm, '"').replace(/<center>.*?<\/center>/gm, '').replace(/border="0"/gm, '').replace(/\\'/gm,`'`);
        
       document.getElementById(widgetId).innerHTML = widgetHTML;
   }
   } 
})();

And that’s it with the note that probably better regexes can be written.

Second Method

In the second method will just write a function that will updated our content and will put it in the cron:

//...
add_filter( 'cron_schedules', 'three_days_add_cron_interval' );
function three_days_add_cron_interval( $schedules ) { 
    $schedules['three_days'] = array(
        'interval' => 259200,
        'display'  => esc_html__( 'Every 3 Days' ), );
    return $schedules;
}

if ( ! wp_next_scheduled( 'a309_update_good_reads' ) ) {
    wp_schedule_event( time(), 'three_days', 'a309_update_good_reads' );
}
add_action( 'a309_update_good_reads', 'a309_update_good_reads' );


 function a309_update_good_reads () {
     $option = get_option('widget_custom_html');
     if($option){
     $widgetArrId = 2;
     $goodReadsJs = file_get_contents("https://www.goodreads.com/review/custom_widget/52338687.Andrei's%20bookshelf:%20read?cover_position=left&cover_size=small&num_books=5&order=d&shelf=read&show_author=1&show_cover=1&show_rating=1&show_review=1&show_tags=1&show_title=1&sort=date_added&widget_bg_color=FFFFFF&widget_bg_transparent=true&widget_border_width=none&widget_id=1613506906&widget_text_color=000000&widget_title_size=medium&widget_width=medium");

     preg_match ( '/=[^~]+widget_div =/ms' , $goodReadsJs , $mArr);
     $iRep = str_replace('  var widget_div =' , '' , $mArr[0]);
     $iRep = preg_replace ( '|\\\/|m' , '/' , $iRep);
     $iRep = preg_replace ( '|\\\\n|m' , '' , $iRep);
     $iRep = preg_replace ( '/\\\\"/m' , '"' , $iRep);
     $iRep = preg_replace ( '/<center>[^\x07]+center>/m' , '' , $iRep);
     $iRep = preg_replace ( '/border="0"/m' , '' , $iRep);
     $iRep = preg_replace ( "/\\\\'/m" , "'" , $iRep);
     $iRep = preg_replace ( "/<noscript>[^\x07]+noscript>/m" , "" , $iRep);
     $iRep = preg_replace ( '|<br[^\x07]+<|m' , '<' , $iRep);
     preg_match ( '|<div class="gr[^\x07]+$|m' , $iRep , $mArr);
     $option[$widgetArrId]['content'] = substr($mArr[0], 0, -2);
     
     update_option('widget_custom_html', $option);
 
     }
  }
 //...

In this example there’s a hardcoded id 2, which is the id of your widget_custom_html, also again the regex could be simplified but this one under 1k steps so I think is pretty usable.

You can skip adding a new interval to WP Cron, in the above cause is just because I wanted a 3 days interval which is not included in the default intervals.

You should disable the WordPress cron and just add wp-cron to crontab, this is recommended for anything that uses WP cron because that way your cron will run more efficiently and not at the same time with a user request.