0

I am using officer to generate a weekly PowerPoint deck for my management. They have provided me with a template they wish to use. I have automated the whole process apart from one part which is causing me some difficulty i was hoping someone could help with

The first slide in the template for them is a very nice cover slide but contains a text box with the Week number the report is to address so for example Report Week 5. I wish to change this every week i run the report. The next iteration would be Report Week 6. The name of the text box is called TextField 26 when i press ALT+F10 in windows

I have tried numerous solutions from here, here and here

I just cant seem to reference the slide itself within the template. I have seen the response on GITHUB related to a similar question where the advice was to remove the old shape and re-add it. I would be happy to do this but again I am unable to reference the title slide.

I would really appreciate anyone's insight to this

Thank you very much for your time

John Smith
  • 2,448
  • 7
  • 54
  • 78
  • If you are on a windows computer, I highly recomend looking into the `RDCOMClient` package. It basically allows you to do everything you would normally do through Microsoft applications like Outlook, word, powerpoint, excel, etc. The only disadvantage is that it is not always obvious how to access certain methods and functions. For that you could explore the object model in the following [web page](https://learn.microsoft.com/en-us/office/vba/api/overview/powerpoint). From what it sounds like, you would want to just execute a "find and replace" method. – Justin Landis Feb 13 '20 at 18:07

2 Answers2

1

To go off my comment, I wrote a function that should work. Unfortunately the RDCOMClient package does require you to be on a windows computer to work

devtools::install_github("omegahat/RDCOMClient")
library(RDCOMClient)

ReplaceTextInObject <- function(path, Find, Replace, SlideNum = NULL){
  ppApp <- COMCreate("powerpoint.application")
  #Requires absolute paths from C drive
  path <- normalizePath(c("C://Users",path), winslash = "\\")[2] 
  ppoint <- ppApp[["Presentations"]]$Open(path, WithWindow = F)
  slides <- 1:ppoint$Slides()$Count()
  #if SlideNum is NULL - loop through each slide
  if(!is.null(SlideNum)&&
     all(SlideNum%%1)==0&&
     all(SlideNum<=ppoint$Slides()$Count())){
    slides <- SlideNum
  } else{
    stop("m must be either an integer or NULL")
  } 

  for(j in slides){
    Slide <- ppoint$Slides(j)
    n <- Slide$Shapes()$Range()$Count() # Total number of shape objects on slide
    #if there are shapes with text - attempt find and replace
    if(n>0){
      for(i in 1:n){
        if(Slide$Shapes(i)$HasTextFrame()==-1&&
           Slide$Shapes(i)$TextFrame()$HasText()==-1){
             Slide$Shapes(i)$TextFrame()$TextRange()$Replace(FindWhat = Find,
                                                             ReplaceWhat = Replace)
        }
      }
    }
  }

  ppoint$Save()
  ppoint$Close()
  rm(Slide, ppoint, ppApp)
}

This function will take a slide number then look through all the objects in the slide. If the object (or shape as VBA has them listed in the documentation) can contain text and has text, then we attempt the find and replace function in that shape object.

If you knew the exact shape index, then you don't need to bother with a loop, but this will do most of the heavy lifting for you. So if the text field is really unique in your template, this should solve your problem.

Justin Landis
  • 1,981
  • 7
  • 9
  • Thank you @Justin Landis this is exactly what i need. It has def pointed me in the right direction. I need to wait an hour to give you the points :) – John Smith Feb 14 '20 at 09:47
  • No problem @JohnSmith. The worst part of `RDCOMClient` is figuring out how to access the methods and properties. Additionally if you code carelessly it can fail with a non-informative error message. I edited the function to be more robust and able to take a range of Slide numbers in order to do the find and replace. I originally started using `RDCOMClient` over `officer` because their find and replace text functions do not always work because text (at least in word documents) were not always on the same nodelist. Not something I completely understood but it had to do with xml code. – Justin Landis Feb 14 '20 at 15:18
1

I think you would have this placeholder in the template rather than in an existing slide would make things easier to manage. However, if you are using a powerpoint where the first slide contain an empty shape named "TextField 26", the officer code would be:

enter image description here

library(officer)
doc <- read_pptx("update_shape_text.pptx")
doc <- ph_add_text(doc, str = "Report Week 5", ph_label = "TextField 26") 
print(doc, "result.pptx")

Note I can't attach update_shape_text.pptx so I used a github issue so that you can get the files. https://github.com/davidgohel/flextable/issues/189

David Gohel
  • 9,180
  • 2
  • 16
  • 34
  • Hi @David Gohel, thank you very much for your explanation. If i add several slides to the presentation template, i get the error: `Error in xpath_search(x$node, x$doc, xpath = xpath, nsMap = ns, num_results = 1) : Expecting a single string value: [type=character; extent=0].`. This is probably in relation to my misunderstanding on how the `pos` field is working – John Smith Feb 17 '20 at 10:25
  • I am sorry, I am not able to help without any reproducible code. Best would be to create a new post and let people reproduce exactly your code so that they can help you without trying to guess :) – David Gohel Feb 17 '20 at 10:38