google-sheetsgoogle-apps-scriptgoogle-slides

Append a hyperlink from another column in sheets to a slide deck via appscript


I'm starting with this script:

    function getDataFromSheet() {
  var presentationId = "presentationId";
  var sheetUrl = "sheetURL";
  var spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
  var sheets = spreadsheet.getSheets();
  var presentation = SlidesApp.openById(presentationId);

  sheets.forEach(function(sheet) {
    var data = sheet.getRange("A1:B" + sheet.getLastRow()).getValues();
    data.forEach(function(row) {
      var variable = row[0];  
      var value = row[1];
      if (variable !== "") {
        var slides = presentation.getSlides();
        slides.forEach(function(slide) {
          slide.replaceAllText(variable, value);
        });
      }
    });
  });
}

I'm creating 1 unique variable in column A and it's value in column B. It is replacing everything in my deck as intended. I'd like to also have a URL in column C, so that, when the script finds the variable in column A, within the slide deck, it will replace the text with the value from column B, and also append a hyperlink from column C, if there is a value in column C.

Edit:

I got this far with AI, it is successfully replacing the value on the slide deck, but the hyperlink is being appended to the shape, i.e the textbox around the value, I'd like it to hyperlink the text itself.

function getDataFromSheet() {
  var presentationId = "presentationID";
  var sheetUrl = sheetURL";
  var spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
  var sheets = spreadsheet.getSheets();
  var presentation = SlidesApp.openById(presentationId);

  sheets.forEach(function(sheet) {
    // Expand range to column C to get the URL
    var data = sheet.getRange("A1:C" + sheet.getLastRow()).getValues();
    data.forEach(function(row) {
      var variable = row[0];  
      var value = row[1];
      var url = row[2]; // URL from column C
      
      if (variable !== "") {
        var slides = presentation.getSlides();
        slides.forEach(function(slide) {
          // Replace text first
          slide.replaceAllText(variable, value);
          
          // If URL is provided, add hyperlink
          if (url) {
            // Ensure URL starts with http:// or https://
            var formattedUrl = url.startsWith('http') ? url : 'https://' + url;
            
            // Get all page elements
            var pageElements = slide.getPageElements();
            
            pageElements.forEach(function(element) {
              // Check if it's a shape
              if (element.getPageElementType() === SlidesApp.PageElementType.SHAPE) {
                var shape = element.asShape();
                var textRange = shape.getText();
                
                // Check if the shape contains the replaced text
                if (textRange.asString().indexOf(value) !== -1) {
                  // Add hyperlink to the shape
                  shape.setLinkUrl(formattedUrl);
                }
              }
            });
          }
        });
      }
    });
  });
}

Solution

  • Unfortunately, I do not know your current Google Slide. So, this answer is my guess.

    In this answer, it supposes that the Spreadsheet and the Slide are as follows.

    Spreadsheet

    enter image description here

    Slide

    enter image description here

    And, about I'd like to also have a URL in column C, so that, when the script finds the variable in column A, within the slide deck, it will replace the text with the value from column B, and also append a hyperlink from column C, if there is a value in column C., I supposed that you might want to set the link to the replaced text.

    When my guess was correct, how about the following modified script?

    Modified script:

    Please set your presentationId and sheetUrl.

    function getDataFromSheet() {
      var presentationId = "presentationId";
      var sheetUrl = "sheetURL";
      var spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
      var sheets = spreadsheet.getSheets();
      var presentation = SlidesApp.openById(presentationId);
    
    
      // I modified the below script.
      var values = sheets.reduce((ar, sheet) => {
        var v = sheet.getRange("A1:C" + sheet.getLastRow()).getRichTextValues();
        v.forEach(([a, b, c]) => {
          var variable = a.getText().trim();
          if (variable) {
            ar.push([variable, b.getText().trim(), c.getLinkUrl()]);
          }
        });
        return ar;
      }, []);
      var replaceWithLink_ = text => {
        values.forEach(([a, b, c]) => {
          var f = text.find(a.replace(/([(){}])/g, "\\$1"));
          if (f.length > 0) {
            f.forEach(ff => {
              const text = ff.setText(b);
              if (c) {
                text.getTextStyle().setLinkUrl(c);
              }
            });
          }
        });
      }
      var forTable = table => {
        for (var r = 0; r < table.getNumRows(); r++) {
          for (var c = 0; c < table.getNumColumns(); c++) {
            if (table.getCell(r, c).getMergeState() != SlidesApp.CellMergeState.MERGED) {
              replaceWithLink_(table.getCell(r, c).getText());
            }
          }
        }
      }
      var forGroup = g => {
        g.getChildren().forEach(c => {
          var type = c.getPageElementType();
          if (type == SlidesApp.PageElementType.SHAPE) {
            replaceWithLink_(c.asShape().getText());
          } else if (type == SlidesApp.PageElementType.TABLE) {
            forTable(p.asTable());
          } else if (type == SlidesApp.PageElementType.GROUP) {
            forGroup(c.asGroup());
          }
        });
      }
      presentation.getSlides().forEach(slide => {
        slide.getPageElements().forEach(p => {
          var type = p.getPageElementType();
          if (type == SlidesApp.PageElementType.SHAPE) {
            replaceWithLink_(p.asShape().getText());
          } else if (type == SlidesApp.PageElementType.TABLE) {
            forTable(p.asTable());
          } else if (type == SlidesApp.PageElementType.GROUP) {
            slide.getGroups().forEach(forGroup);
          }
        });
      });
    }
    

    When this script is run for the above Spreadsheet and Slide, the result Slide is as follows. The texts on each slide are replaced by the values of column "B" and set the hyperlinks of column "C" to the replaced text.

    enter image description here

    Note:

    As additional information, the following sample script might also be able to be used. This is from this post (Author: me).

    /**
     * ### Description
     * Replace all texts in all slides in a Google Slide by giving the text styles.
     *
     * @param {SlidesApp.Presentation} presentation Class Presentation object
     * @param {Object} replaceObj Object for replacing texts.
     * @return {void}
     */
    function findReplaceAllText_(presentation, replaceObj) {
      const replaceWithLink_ = text => {
        replaceObj.forEach(({ replaceText, containsText, style }) => {
          const f = text.find(replaceText);
          if (f.length > 0) {
            f.forEach(ff => {
              const text = ff.setText(containsText);
              if (style) {
                Object.entries(style).forEach(([k, v]) =>
                  text.getTextStyle()[`set${k.replace(/^./, ([a]) => a.toUpperCase())}`](v)
                );
              }
            });
          }
        });
      }
      const forTable = table => {
        for (let r = 0; r < table.getNumRows(); r++) {
          for (let c = 0; c < table.getNumColumns(); c++) {
        if (table.getCell(r, c).getMergeState() != SlidesApp.CellMergeState.MERGED) {
          replaceWithLink_(table.getCell(r, c).getText());
        }
          }
        }
      }
      const forGroup = g => {
        g.getChildren().forEach(c => {
          const type = c.getPageElementType();
          if (type == SlidesApp.PageElementType.SHAPE) {
            replaceWithLink_(c.asShape().getText());
          } else if (type == SlidesApp.PageElementType.TABLE) {
            forTable(p.asTable());
          } else if (type == SlidesApp.PageElementType.GROUP) {
            forGroup(c.asGroup());
          }
        });
      }
      presentation.getSlides().forEach(slide => {
        slide.getPageElements().forEach(p => {
          const type = p.getPageElementType();
          if (type == SlidesApp.PageElementType.SHAPE) {
            replaceWithLink_(p.asShape().getText());
          } else if (type == SlidesApp.PageElementType.TABLE) {
            forTable(p.asTable());
          } else if (type == SlidesApp.PageElementType.GROUP) {
            slide.getGroups().forEach(forGroup);
          }
        });
      });
    }
    
    // Please run this function.
    function main() {
      const presentationId = "###"; // Please set your presentation ID.
      const spreadsheetId = "###"; // Please set your spreadsheet ID.
    
      var replaceObj = SpreadsheetApp.openById(spreadsheetId).getSheets().reduce((ar, sheet) => {
        var v = sheet.getRange("A1:C" + sheet.getLastRow()).getRichTextValues();
        v.forEach(([a, b, c]) => {
          var replaceText = a.getText().trim().replace(/([(){}])/g, "\\$1");
          if (replaceText) {
            var obj = { replaceText, containsText: b.getText().trim() };
            var linkUrl = c.getLinkUrl();
            if (linkUrl) {
              obj.style = { linkUrl };
            }
            ar.push(obj);
          }
        });
        return ar;
      }, []);
      const presentation = SlidesApp.openById(presentationId);
      findReplaceAllText_(presentation, replaceObj);
    }