google-apps-scriptgoogle-docsflysystem-google-drive

Get Header and Footer from template Google Doc, and apply to all docs in a Google Drive folder


I need help applying a header and footer that contains tables, paragraphs, and images (branding content/letterhead) across all Google docs in a Google drive folder.

GOALS:

  1. Get/Copy header from source document that contains tables, paragraphs, and images.
  2. Paste/Apply/Replace header copied in 1 to all documents in a Google drive folder
  3. Do same for Footer.
  4. Don't require programatic "appending" to existing footers.

I wish there was a way to do CSS or something similar for templates that could be applied to a batch of google docs... but I believe scripting is the only way.

This is adding on to this post: Find and Replace text in entire Google Drive folder, headers, footers, google docs using a script

function replaceHeaderAndFooter() {
  
 const headerToCopyandPaste = DocumentApp.openById("<SourceDocID>").getHeader().getTables().toString();  // ID contains source header
 const footerToCopyandPaste = DocumentApp.openById("<SourceDocID>").getHeader().copy();  // ID contains source footer
  
  
  var files = DriveApp.getFolderById("<FolderID>").getFiles();  //ID contains folder that has Google Docs that will have Header and Footer Replaced
  while (files.hasNext()) {
    var file = files.next();
    var doc = DocumentApp.openById(file.getId());
    
  var headerSectionToBeReplaced = doc.getHeader()
  var footerSectionToBeReplaced = doc.getFooter()
    
  headerSectionToBeReplaced.clear();
footerSectionToBeReplaced.clear();

 headerSectionToBeReplaced.appendTable(headerToCopyandPaste); //This does not work
 footerSectionToBeReplaced = footerToCopyandPaste    // This does not work
    
  }
}

Solution

  • I believe your goal and situation as follows.

    In order to achieve your goal, in this sample script, I would like to propose the following flow.

    Flow:

    1. Retrieve Google Document files from the specific folder.
      • In this case, the Document files are retrieved from just under the specific folder without checking the subfolders.
      • Because from your replying comments, although there are hundreds number of Google Document files you want to use, you will run the script for every several Documents.
    2. Copy the header from the template Document to the destination Document.
    3. Copy the footer from the template Document to the destination Document.

    IMPORTANT:

    As an important point, in the current stage, unfortunately, it seems that when the header and footer retrieved by getHeader() and getFooter() of Google Document service cannot identify whether the check of 1st page header is enabled and disabled. So in this sample script, the headers and footers both with and without the check of the 1st page header are overwritten.

    Sample script:

    Please copy and paste the following script to the script editor, and set the values of templateDocumentId and folderId, and then, run main().

    function getObjs(dstDoc, key) {
      if (!dstDoc.getHeader()) dstDoc.addHeader();  // Added
      if (!dstDoc.getFooter()) dstDoc.addFooter();  // Added
    
      var dd = dstDoc.getHeader().getParent();
      var cc = dd.getNumChildren();
      const objs = [];
      for (let i = 0; i < cc; i++) {
        if (dd.getChild(i).getType() == DocumentApp.ElementType[key == "header" ? "HEADER_SECTION" : "FOOTER_SECTION"]) {
          objs.push(dd.getChild(i)[key == "header" ? "asHeaderSection" : "asFooterSection"]());
        }
      }
      return objs;
    }
    
    function copyFooter(tempDoc, dstDoc) {
      getObjs(dstDoc, "footer").forEach(dstFooter => {
        dstFooter.clear();
        const d = tempDoc.getFooter();
        const c = d.getNumChildren();
        for (let i = 0; i < c; i++) {
          const child = d.getChild(i);
          const type = child.getType();
          if (type == DocumentApp.ElementType.PARAGRAPH) {
            dstFooter.insertParagraph(i, child.copy().asParagraph());
          } if (type == DocumentApp.ElementType.TABLE) {
            dstFooter.insertTable(i, child.copy().asTable());
          }
        }
      });
    }
    
    function copyHeader(tempDoc, dstDoc) {
      getObjs(dstDoc, "header").forEach(dstHeader => {
        dstHeader.clear();
        const d = tempDoc.getHeader();
        const c = d.getNumChildren();
        for (let i = 0; i < c; i++) {
          const child = d.getChild(i);
          const type = child.getType();
          if (type == DocumentApp.ElementType.PARAGRAPH) {
            dstHeader.insertParagraph(i, child.copy().asParagraph());
          } if (type == DocumentApp.ElementType.TABLE) {
            const table = child.copy().asTable();
            let imgObj = [];
            for (let r = 0, rows = table.getNumRows(); r < rows; r++) {
              const row = table.getRow(r);
              for (let c = 0, cols = row.getNumCells(); c < cols; c++) {
                const cell = row.getCell(c);
                for (let ce = 0, cc = cell.getNumChildren(); ce < cc; ce++) {
                  if (cell.getChild(ce).getType() == DocumentApp.ElementType.PARAGRAPH) {
                    const cp = cell.getChild(ce).asParagraph();
                    for (let cee = 0, cpn = cp.getNumChildren(); cee < cpn; cee++) {
                      const ceec = cp.getChild(cee);
                      if (ceec.getType() == DocumentApp.ElementType.INLINE_IMAGE) {
                        const img = ceec.asInlineImage();
                        imgObj.push({child: cee, img: img, row: r, col: c, blob: img.getBlob(), width: img.getWidth(), height: img.getHeight()});
                        ceec.removeFromParent();
                      }
                    }
                  }
                }
    
              }
            }
            const dstTable = dstHeader.insertTable(i, table);
            if (imgObj.length > 0) {
              imgObj.forEach(({row, col, child, blob, width, height}) => dstTable.getCell(row, col).insertImage(child, blob).setWidth(width).setHeight(height));
            }
          }
        }
      });
    }
    
    // Please run this function.
    function main() {
      const templateDocumentId = "###";  // Please set the template Document ID.
      const folderId = "###";  // Please set the folder ID.
    
      const tempDoc = DocumentApp.openById(templateDocumentId);
      const docs = DriveApp.getFolderById(folderId).getFilesByType(MimeType.GOOGLE_DOCS);
      while (docs.hasNext()) {
        const docId = docs.next().getId();
        const dstDoc = DocumentApp.openById(docId);
        copyHeader(tempDoc, dstDoc);
        copyFooter(tempDoc, dstDoc);
      }
    }
    

    Note:

    References: