Note: I have no idea what I'm talking about, but it's working, so here we go!
Update July 24, 2020: I changed the XMLRPC library to one that supports httr
and added some additional notes at the bottom.
This is an R Markdown document I created using RStudio, an open source IDE for working with R.
One of our clients uses R Markdown as part of their workflow for creating and publishing rich reports with charts and data in HTML. For a while they've been working with the ever so available tools: copy and paste. This seems to work well for the most part, but the images generated as part of the document are included inline and the WordPress editor removes some of that image data during the process of saving after pasting. (I'm pretty sure this is something that used to work, but I haven't gone back and verified yet.)
Our client found a great blog post explaining how to post from R Markdown to WordPress and asked us if that was an option with their site. While I generally have a knee-jerk reaction to publishing with XML-RPC, I don't really have a reason why it shouldn't work. So I checked it out!
Here's the quick version:
- Download and install the R binary from one of the many CRAN mirrors.
- Download and install RStudio.
- Open RStudio.
- Create a new R Markdown file.
From what I can tell, there are three important panes in the RStudio window.
- The file pane used to edit the R Markdown document.
- The Console pane used to issue commands in R syntax to manipulate the document and its configuration.
- The Help/Viewer pane on the right displays help information or a preview of the document upon request.
The file pane has an “Knit” menu that provides options for publishing the document to HTML, PDF, or a Word document. Additional configuration is required to “knit” to WordPress.
In the console, I typed these commands:
install.packages( "knitr" ) install.packages( "devtools" ) devtools::install_github(c("josephguillaume/XMLRPC","duncantl/RWordPress"))
This installs the packages required to publish over XML-RPC with commands that WordPress understands.
The josephguillaume/XMLRPC package is a fork of the duncantl/XMLRPC package and uses httr instead of RCurl to make HTTP requests. I believe this is an improvement, though I'm not familiar with the differences.
Once those are setup, an XML-RPC configuration needs to be set. Note the lowercase P in each command.
options(WordpressURL = c("https://yourdomain.com/xmlrpc.php")) options(WordpressLogin = c( "username" = "password" ))
One minor word of caution: when I find myself publishing via XML-RPC or anything else that requires a plaintext username and password, I add separate user account to my site with a lower set of capabilities and then manually adjust the author information once the post is properly published.
Now we're ready to publish. The RWordPress package provides the knit2wp
command. If you type ?knit2wp
in the console pane, information appears in the help pane explaining how to manipulate the command to create a new post, edit a post, and assign categories and tags.
To publish this post as a draft on my site, I used:
knit2wp('testpost.Rmd', title='Publishing to WordPress with RStudio', publish = FALSE )
After I published the first version and made some changes, I used the following to edit the post:
knit2wp('testpost.Rmd', title='Publishing to WordPress with RStudio', action=c("editPost"), postid = 13616, publish = FALSE )
And here we are. This is pretty cool!
Caveats
Data URI Images and unfiltered HTML
Note that images generated through RStudio (maybe RMarkdown in general?) are added to content as Data URIs and will not be uploaded to the WordPress media library. This also poses an issue if the user publishing a content is not allowed to push unfiltered HTML. WordPress will strip that data URI as a security precaution when the post content is saved. On single site WordPress, you'll need to be at least an Editor. On multisite WordPress, you'll need to be super administrator.
Ongoing use
If you're familiar with R, this may be obvious, but it wasn't to me! When you start RStudio again after exiting, you can use the library()
command to reload required packages:
library('knitr') library('devtools') library('RWordPress') library('XMLRPC') options(WordpressURL = c("https://yourdomain.com/xmlrpc.php")) options(WordpressLogin = c( "username" = "password" ))
I'm sure there's a way to maintain a persistent state, but I haven't looked. 🙂
Why R Markdown?
I'm done with the overview, but I'm including this section as an example. The framework for it was provided by RStudio when I first created the document.
From what I can tell, the cars
variable is already provided as a dataset. When I type cars
in the console pane, I get a list of numbers populating speed and distance columns. If I type summary(cars)
in the console, I see the a version of the table listed below, which this markdown document says to embed:
## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu.:19.0 3rd Qu.: 56.00 ## Max. :25.0 Max. :120.00
And I can plot that same data into a graph with plot(cars)
:
How cool!
I seem to be having some trouble parsing the html to xml. Any suggestions where I might start to debug the messages below?
...
output file: report.md
Entity 'raquo' not defined
Entity 'raquo' not defined
xmlParseEntityRef: no name
EntityRef: expecting ';'
xmlParseEntityRef: no name
xmlParseEntityRef: no name
xmlParseEntityRef: no name
xmlParseEntityRef: no name
error parsing attribute name
attributes construct error
Couldn't find end of Start Tag i.length line 102
xmlParseEntityRef: no name
EntityRef: expecting ';'
xmlParseEntityRef: no name
xmlParseEntityRef: no name
xmlParseEntityRef: no name
EntityRef: expecting ';'
xmlParseEntityRef: no name
xmlParseEntityRef: no name
xmlParseEntityRef: no name
EntityRef: expecting ';'
xmlParseEntityRef: no name
EntityRef: expecting ';'
xmlParseEntityRef: no name
xmlParseEntityRef: no name
Opening and ending tag mismatch: link line 6 and head
Entity 'hellip' not defined
Opening and ending tag mismatch: input line 204 and label
Opening and ending tag mismatch: input line 206 and form
Opening and ending tag mismatch: label line 202 and div
Opening and ending tag mismatch: form line 201 and header
Entity 'rarr' not defined
Entity 'rarr' not defined
Entity 'rarr' not defined
Namespace prefix xlink for href on use is not defined
Namespace prefix xlink for href on use is not defined
Namespace prefix xlink for href on use is not defined
Namespace prefix xlink for href on use is not defined
Namespace prefix xlink for href on use is not defined
Opening and ending tag mismatch: br line 600 and p
Opening and ending tag mismatch: img line 602 and a
Opening and ending tag mismatch: img line 602 and a
Opening and ending tag mismatch: img line 602 and a
Opening and ending tag mismatch: img line 602 and a
Opening and ending tag mismatch: a line 602 and div
Opening and ending tag mismatch: a line 602 and div
Opening and ending tag mismatch: a line 602 and div
expected '>'
Opening and ending tag mismatch: br line 599 and div
Entity 'copy' not defined
attributes construct error
Couldn't find end of Start Tag a line 609
Opening and ending tag mismatch: div line 609 and a
Opening and ending tag mismatch: footer line 607 and div
Opening and ending tag mismatch: p line 599 and div
Opening and ending tag mismatch: img line 599 and footer
Opening and ending tag mismatch: aside line 586 and body
Opening and ending tag mismatch: div line 327 and html
Premature end of data in tag div line 223
Premature end of data in tag div line 222
Premature end of data in tag div line 195
Premature end of data in tag header line 194
Premature end of data in tag div line 191
Premature end of data in tag body line 186
Premature end of data in tag meta line 5
Premature end of data in tag meta line 4
Premature end of data in tag head line 3
Premature end of data in tag html line 2
Error in (function (cond) :
error in evaluating the argument 'node' in selecting a method for function 'convertToR': 1: Entity 'raquo' not defined
2: Entity 'raquo' not defined
3: xmlParseEntityRef: no name
4: EntityRef: expecting ';'
5: xmlParseEntityRef: no name
6: xmlParseEntityRef: no name
7: xmlParseEntityRef: no name
8: xmlParseEntityRef: no name
9: error parsing attribute name
10: attributes construct error
11: Couldn't find end of Start Tag i.length line 102
12: xmlParseEntityRef: no name
13: EntityRef: expecting ';'
14: xmlParseEntityRef: no name
15: xmlParseEntityRef: no name
16: xmlParseEntityRef: no name
17: EntityRef: expecting ';'
18: xmlParseEntityRef: no name
19: xmlParseEntityRef: no name
20: xmlParseEntityRef: no name
21: EntityRef: expecting ';'
22: xmlParseEntityRef: no name
23: EntityRef: expecting ';'
24: xmlParseEntityRef: no name
25: xmlParseEntityRef: no name
26: Opening and ending tag mismatch: link line 6 and head
27: Entity 'hellip' not defined
28: Opening and ending tag mism
In addition: Warning message:
attributes are not identical across measure variables;
they will be dropped
>
Hey I found a small problem in RWordPress
Re: Error: faultCode: 403 faultString: Incorrect username or password.
Because,
We said,
options(WordPressURL = "https://XXXX.com/xmlrpc.php")
However, this URL was not passed to any function under RWordPress correctly on my computer. This is because .server = getServerURL() is not working in any function.
To fix this, I have to manually change .server = getServerURL() to .server = getOption("WordPressURL")
The option keys are case sensitive, so setting `WordPressURL` will not work, but `WordpressURL` will.
I hope that's the issue, otherwise I have no idea! :)
This is great .
Can you share the R version and Rstudio version? I have been trying, but couldn't.
Hi Ram - I'm using RStudio version 1.3.1004 for macOS and R version 4.0.0.
I'm about to update the post with a reference to a different XMLRPC client that uses httr instead of RCurl. The person I'm working with on this was having trouble connecting via RCurl at all, but httr works fine.