Patching site html

If you have a fairly large Google Site, and you make mistakes like we all do, at some point you'll need to do a mass update to all the pages. It happened to me yesterday. I host a gadget on most of my pages see (Displaying analytics data on site pages), which I had accidentally deleted a while ago. I host it on Drive, so when I deleted it, I actually only moved it to my trash. 

When you host something on Drive, it takes the url https://googledrive.com/host/fileid , so it actually still continues to work from the trash bin. Yesterday I thought it was time to clean out my trash so I permanently deleted everything, including the hosted gadget - so every page on this site started showing an error where the missing gadget used to be.

Luckily I had the source for the gadget on GitHub, so I could easily recreate it, but the problem with using Drive as a host  is that the fileid is a oneoff thing - meaning that I cannot just create another file with the same id.

So I was faced with either manually editing each of 700+ pages on this site and reinserting a new gadget, or patching up the existing gadget with the new fileid.

Here's a snippet to do it. 

DANGER and IMPORTANT - make sure you do lots of checking on what will be changed before actually doing the setHtmlContent() . This could mess up your site if you replace the wrong thing with the wrong thing. NOTE also that some deprecated gadgets will stop working when rewritten. For example , those old Adsense gadgets that Google deprecated on Sites. If your page gets rewritten and you still have some of them on your site - they will disappear forever. If you have gadgets on your site, test thoroughly that they will not be screwed up by rewriting the html before running.


All I had to do was set the old fileId

var searchRx = /0B92ExLh4POiZT081dWl6WjdwbFk/g;

And the new one

var replaceWith = "0B92ExLh4POiZb19Qc3hidFgzS2M";


Always worth giving it a trial run first by setting this to false

var actuallyDoIt = true;



function patch() {
  
  // set this to true to actually do the update as opposed to just reporing it
  var actuallyDoIt = false;
  
  // this is the site i'm working with
  var site = SitesApp.getSite("mcpher.com", "share");
  
  // get all the pages on the site
  var pages = getPages(site);
  
  // get all the pages that contain the search term in their html
  var searchRx = /0B92ExLh4POiZT081dWl6WjdwbFk/g;
  var workingPages = pages.reduce (function (p,c) {
    var html = c.getHtmlContent();
    // if its a target page then select it and avoid getting the html again later
    if (html.search (searchRx , html) >=0) {
      p.push ({html:html, page:c});
    }
    return p;
  },[]);
  
  
  //now we'll update these pages with the replacement value
  var replaceWith = "0B92ExLh4POiZb19Qc3hidFgzS2M";
  workingPages.forEach (function (d,i) {
    Logger.log (""+i+" "+(actuallyDoIt ? "updating " : "would have updated ") + d.page.getUrl());
    
    // REMEMBER TO DO LOTS OF LOGGING AND CHECKING HERE BEFORE SETTING ACTUALLYDOIT TO TRUE
    if (actuallyDoIt) {
      d.page.setHtmlContent ( d.html.replace (searchRx, replaceWith) );
    }
  });
  
}

/**
 * get all the pages on my site - into a heirach object
 * @param {Site} site the site
 * @param {number} optMax max number of pages to go for
 * @param {string} optQuery a search query (unfortunately this doesnt search html)
 * @param {number} optStart you can start later - useful for restarting if you run out of execution time
 * @return {Array.Page} all the pages on the site
 **/
function getPages(site,optMax,optQuery,optStart) {
  
  var chunk,pages = [], options = {};
  do {
    options.start= pages.length + (optStart || 0);
    if (optMax) options.max =  optMax - pages.length ;
    if (optQuery) options.search = optQuery;
    chunk = cUseful.rateLimitExpBackoff( function (){
      return site.getAllDescendants(options);
    });
    cUseful.arrayAppend(pages, chunk);
  }
  while (chunk.length && (!optMax || pages.length < optMax));
  
  return pages;
}  




For this snippet you'll need my cUseful library. You can find the details below or get it from github.

https://script.google.com/macros/s/AKfycbwZ2Hht93wTNzvRmYINYF7obaOHciBXWcP_wAiEtyGq70_x3cI/exec?list=cUseful


For more like this, see  Google Apps Scripts snippets. Why not join our forum,follow the blog or follow me on twitter to ensure you get updates when they are available. 

You want to learn Google Apps Script?

Learning Apps Script, (and transitioning from VBA) are covered comprehensively in my my book, Going Gas - from VBA to Apps script, available All formats are available now from O'Reilly,Amazon and all good bookshops. You can also read a preview on O'Reilly

If you prefer Video style learning I also have two courses available. also published by O'Reilly.
Google Apps Script for Developers and Google Apps Script for Beginners.




Comments