Search code examples
google-apps-scriptexport-to-pdfgoogle-slides-api

Exported Google Slides presentation does not include recent changes


I have written some code to automatically add in a user's name to a template Google Slides file. This template is essentially a certificate, and I'm trying to automate the generation of said certificate for each user.

Unfortunately, when I try to convert the Slides file to a PDF, it converts the slide without the user's name - e.g. basically just the template file is exported. It's definitely pulling in the correct file id, but still not working. The only problem I can think of is that the presentation hasn't saved the changes by the time the code gets the blob data from DriveApp.

function buildCertificate() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1'),
      rows = sheet.getDataRange().getValues(),
      template = DriveApp.getFileById('some file id'),
      destination = DriveApp.getFolderById('some folder id'),
      i = 1;

  while (i < rows.length) {
    if (rows[i][3] != 'Y') {
      var file = template.makeCopy(rows[i][0] + ' ' + rows[i][1], destination),
      id = file.getId(),
      slide = SlidesApp.openById(id).getSlides()[0],
      shape = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 60, 207, 600, 110),
      textRange = shape.getText(),
      textStyle = textRange.getTextStyle();

      textRange.setText([rows[i][0] + ' ' + rows[i][1]]);
      textStyle.setFontSize(40);
      textStyle.setForegroundColor('#F9B300');

      var paragraphStyle = textRange.getParagraphs()[0].getRange().getParagraphStyle();
      paragraphStyle.setParagraphAlignment(SlidesApp.ParagraphAlignment.CENTER);

      var theBlob = DriveApp.getFileById(id).getBlob().getAs('application/pdf').setName('test'),
      newFile = DriveApp.getFolderById("some folder id").createFile(theBlob);
    }

    sheet.getRange(i + 1, 4).setValue('Y');
    i++;
  } 
}

Solution

  • Per the Apps Script SlidesApp documentation, you can force any pending writes to the Slides Presentation by closing it with saveAndClose(). Closing of open presentations is automatically performed when the script execution ends, but for use cases such as yours, this automatic flush occurs too late to be useful:

    saveAndClose():

    saves the current Presentation. Causes pending updates to be flushed and applied.

    The saveAndClose() method is automatically invoked at the end of script execution for each open Presentation, even if the script execution terminated with an error.

    A closed Presentation cannot be edited. Use one of the open methods on SlidesApp to reopen a given presentation for editing.

    The presentation your code uses is bound in your variable slide, so altering your loop structure to close this prior to your DriveApp code will ensure the Blob data reflects the latest changes.

    while (i < rows.length) {
      if (rows[i][3] != 'Y') {
        var file = template.makeCopy(rows[i][0] + ' ' + rows[i][1], destination),
            id = file.getId(),
            presentation = SlidesApp.openById(id),
            slide = presentation.getSlides()[0],
            shape = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 60, 207, 600, 110),
            textRange = shape.getText(),
            textStyle = textRange.getTextStyle();
    
        textRange.setText([rows[i][0] + ' ' + rows[i][1]]);
        textStyle.setFontSize(40);
        textStyle.setForegroundColor('#F9B300');
    
        var paragraphStyle = textRange.getParagraphs()[0].getRange().getParagraphStyle();
        paragraphStyle.setParagraphAlignment(SlidesApp.ParagraphAlignment.CENTER);
    
        // Flush the changes we've made to the instantiated template presentation.
        presentation.saveAndClose();
    
        // Reopen the file with DriveApp -- could perhaps use the existing `file` reference, e.g.:
        // var theBlob = file.getAs(MimeType.PDF).setName('test');
        var theBlob = DriveApp.getFileById(id).getAs(MimeType.PDF).setName('test');
        // Create the PDF in the desired Drive folder.
        DriveApp.getFolderById("some folder id").createFile(theBlob);
      }
    
      sheet.getRange(i + 1, 4).setValue('Y');
      i++;
    }