How to post content to a WordPress blog from the command line

WordPress is a great publishing system, but managing it manually can be a very time consuming process. This is especially true when you want to upload lots of posts, or if you would like to write content in your preferred, full-blown text editor and then have it “magically” appear online.

WordPress takes care of these needs allowing remote posting via email or the WordPress XML-RPC interface (if you enable the WordPress, Movable Type, MetaWeblog and Blogger XML-RPC checkbox in goinig to Settings > Writing > Remote Publishing). The first method is explained here and in other places, but requires setting up a dedicated email account. For several reasons I preferred not to do it that way, so I looked at the other system.

PHP scripts for this purpose are here and here. The first uses the cURL capabilities of PHP to send the data over SSL. The second uses IXR, the Incutio XML-RPC Library for PHP, to “incorporate both client and server classes, as it is designed to hide as much of the workings of XML-RPC from the user as possible”.

Both those scripts work, and the second can also be used to edit existing posts or get lists of the latest published articles. However I was looking for something that didn’t require PHP (personal preference, really). Eventually, I found the WordPress-CLI utility by Leo Charre and have already used it successfully to upload hundreds of posts to several of my WordPress websites (see bottom of this page for examples). Here’s how I did it.

WordPress-CLI installs like any other Perl Module, see the instructions in the README file. In order for it to work, however, I also had to download and install from CPAN the Perl Modules Getopt-Std-Strict-1.01 and LEOCHARRE-Debug-1.03.

Once everything is installed, you’ll have in your path a script called wordpress-upload-post. Run it at the command prompt or in a script, giving as options the name of the HTML file containing the post, plus its required publication date, title and category, as well as your user name and password, and you’ll have your post online.

To make things faster, I use wordpress-upload-post inside this script:


  #! /bin/bash
  # usage: post2wp.sh postfile blogname
  # postfile: text file containing post content in txt2tags format
  # blogname: name of blog

  POST=$1
  BLOGNAME=$2

  HTML=/tmp/tmp_wordpress_post.html
  ACCOUNTS_DIR= "$HOME/.blog_accounts"

  #########################################################################
  #extract title, category and publication date of the post
  TITLE=`grep '%TITLE: ' $POST | cut -c9-`
  CATEGORY=`grep '%CATEGORY: ' $POST | cut -c12-`
  DATE=`grep '%DATE: ' $POST | cut -c8-`

  YEAR=`echo $DATE | cut -c1-4`
  MONTH=`echo $DATE | cut -c5-6`
  DAY=`echo $DATE | cut -c7-8`
  HOUR=`echo $DATE | cut -c9-10`
  MIN=`echo $DATE | cut -c11-12`
  DATE="$HOUR:$MIN $YEAR/$MONTH/$DAY"

  rm -f $HTML.tmp*
  txt2tags -t xhtml --no-headers -i $POST -o $HTML

  ###########################################################################
  # source blog parameters: user name, password, XML_RPC url

  if [ -e $ACCOUNTS_DIR/$BLOGNAME ]
  then
    source $ACCOUNTS_DIR/$BLOGNAME
  else
    echo "Error! $BLOGNAME account file doesn't exist!"
    exit
  fi

  ###########################################################################
  # upload post to blog
  WP_OPTS="-D '$DATE' -t '$TITLE'  -c '$CATEGORY'  -u $USER -p '$PW' -x $XMLRPC_URL"
  WP_CMD="wordpress-upload-post $WP_OPTS $HTML"
  eval $WP_CMD
  exit


I use txt2tags as source format for most things I publish online. It is a very simple ASCII markup format, that I customize adding to each article to be published on WordPress comments like these:


  %TITLE: Is it OK for a School or Charity to accept software donations?
  %CATEGORY: Digiworld
  %DATE: 200707010900


The script extracts these variables from the source text and reformats them in the way required by wordpress-upload-post.

Next, it converts the article from the ASCII markup to HTML calling the txt2tags Python Script. Password, user name and the URL of the wordpress blog to use to upload the HTML post are in a separate file ($ACCOUNTS_DIR/$BLOGNAME) that has this format:


  USER='your user name'
  PW='your password'
  XMLRPC_URL='http://your.blog.home.page/xmlrpc.php'


and is read right after generating the HTML version of the post. The last part of the script, “upload post to blog” concatenates all the parameters in one option string WP_OPTS, build the publishing command WP_CMD and evaluates, thus publishing your post online. Enjoy! Of course, if you only post once in a while you won’t save much time, but if you ever need, as I did, to post lots of stuff, try this!

What’s missing

wordpress-upload-post and this script work great (see bottom of page), but they aren’t perfect. The biggest limit right now of WordPress-CLI is that you can’t specify WordPress tags or, if you have a multilingual blog, the language of the current post. I’d also like to use it to add comments to existing posts, but that’s not essential really. I discussed these things with Leo. His answer is that “some of these things simply won’t work. For example- adding tags- because xmlrpc.php does not implement a call to add a tag. I’ve made some hacks to be able to do so- but this works on a local/server level. [also] I can’t recall right now if they have a comment call”. Leo also asked me to forward to all readers of this page this invitation:

  I'd be open to actually share in maintenance of things like WordPress::XMLRPC and a WordPress::CLI revised version. If you want to do this level of changes/additions, we could set up a branch off some cvs server... and... implement bugzilla on some server- to keep track of changes and todos.

Another thing I’d like to figure out is a way to upload images to WordPress so that they are associated to that post and get thumbnails. If that were possible, it would be easy to figure out in advance the right URLs for both the images and their thumbnails, and add them to the txt2tags source. As it is today, in the rare cases where I need to upload with this script a post that does have images, I add them in a second moment by hand. Suggestions?

How I’ve used this script

If you are curious to what real posts written in txt2tags format, then converted to HTML and automatically uploaded to a WordPress blog look like, and don’t mind a bit of self-promotion, have a look at the following links. I have already used the script above to:

How to create stacked area graphs with Gnuplot

Gnuplot is a really great plotting utility, that can be used either interactively or automatically, from inside scripts of all sorts. However, sometimes it can be quite difficult to use simply because there are lots of documentation, but it is hard to figure out exactly what piece of documentation you should read and where it is.

This is a big problem, because the way you plot data, that is which Gnuplot options you set, can make a huge difference in the readability of the plot. For example, I had this ASCII file called initial_data.dat, that lists the number of daily visitors to four different websites I follow (the complete file used for this article is downloadable from the link at the end of this page):


  20110101 2481 89 896 98
  20110102 2341 83 1341 762
  20110103 560 208 1795 890
  20110104 936 409 1665 419
  20110105 534 562 937 341
  20110106 171 728 953 612
  20110107 200 199 1297 569
  20110108 521 557 990 295
  20110109 1592 227 535 466
  20110110 1363 211 21 299
  20110111 437 222 110 302
  ...


The file format is very simple: the first column is the date, then there are four space-separated columns, one for each website. However, if you tell gnuplot to plot those numbers as simple lines with these commands (the plot command here is wrapped around for readability, but it must stay all on one line!):



  set terminal png size 1400, 600
  set output "with_lines.png"
  set key center top
  set style fill solid
  set xdata time
  set timefmt "%Y%m%d"
  set format x "%b %d"
  set ytics 300
  set y2tics 300 border
  set xlabel "Website traffic from 20110101 to 20110322"

  set style line 1 linetype 1 pointtype 0 linewidth 1 linecolor 6
  set style line 2 linetype 2 pointtype 0 linewidth 1 linecolor 7
  set style line 3 linetype 3 pointtype 0 linewidth 1 linecolor 8
  set style line 4 linetype 4 pointtype 0 linewidth 1 linecolor 9
  plot ["20110101":"20110131"][:] 'initial_data.dat' using 1:5 t   
                                  "Website 4" w lines linestyle 4, 
   'initial_data.dat' using 1:4 t "Website 3" w lines linestyle 3, 
   'initial_data.dat' using 1:3 t "Website 2" w lines linestyle 2, 
   'initial_data.dat' using 1:2 t "Website 1" w lines linestyle 1


with_lines you’ll get the diagram on the left, that isn’t really informative: the lines continuously overlap, so it’s hard to see quickly which website had the highest traffic on each day. It’s even harder to see the total amount of traffic on each day. The solution is to stack the graphs, that is to use each line as the foundation on which to draw the others. In other words, instead of drawing four lines, one for each website, I wanted to draw:

  • traffic for website 1 using the numbers in the second columns, as they are in the data file
  • traffic for website 2 //summing its numbers in column 3 with the corresponding numbers in column 2
  • traffic for website 3 //summing its numbers in column 4 with the corresponding numbers in column 2 and 3
  • traffic for website 4 //summing its numbers in column 5 with the corresponding numbers in column 2, 3 and 4

It is possible to do this kind of stuff directly in Gnuplot, by calling utilities like sed or awk directly from within the Gnuplot command file as explained in this page. However, in my opinion it is much better and cleaner to do stuff like this before calling gnuplot, with an auxiliary script in Perl, Python or whatever strikes your fancy. The reason is that in this way you can pre-process the numbers in much more flexible, and self-documenting ways that Gnuplot is capable of: another way to say this is that it is better to keep number calculation and number plotting completely separate. For example, I also run an expanded version of the script below that calculates and stacks on the fly the moving averages over one month of the traffic to each website.

In this case, using a separate script to “stack” the data is also quick. All I had to do to rearrange the numbers as described above was to feed the data file to another script and save the result as another data file:

cat initial_data.dat | perl stack_data.pl > stacked_data.dat

Stack_data.pl is the simple Perl script below:


  #! /usr/bin/perl

  use strict;
  my $I;
    while (<>) {                            # read the data file from Standard Input
      chomp;
      my @FIELDS = split ' ', $_;           # put each column in a different
      my $DATE = shift @FIELDS;             # field of the @FIELDS array
      print "$DATE ";
      my $LINE_TOTAL = 0;
      for ($I = 0; $I <= $#FIELDS; $I++) {  # re-print the data, but making of
         $LINE_TOTAL += $FIELDS[$I];        # each column the sum of all the ones
         print " $LINE_TOTAL";              # preceeding it
      }
      print "n";                           # print the new numbers to Standard Output
   }


stacked_lines Here is what you get when plotting the stacked_data.dat file with the same style of the initial graph, that is with the same “plot” command. That is much better but, in my opinion, it wasn’t good enough yet. Personally, I think filled areas are more informative in cases like this. The way to obtain them is to use another style in the plot command. Replace the last line of the Gnuplot instruction file with this one (on ONE line!):


  plot ["20110101":"20110131"][:]
  'initial_data.dat' using 1:5 t "Website 4" w filledcurves x1 linestyle 4,
  'initial_data.dat' using 1:4 t "Website 3" w filledcurves x1 linestyle 3,
  'initial_data.dat' using 1:3 t "Website 2" w filledcurves x1 linestyle 2,
  'initial_data.dat' using 1:2 t "Website 1" w filledcurves x1 linestyle 1


with_filledcurves and this is what the plot will look like. Nicer, uh? Please note that the order in which each column is read and plotted in the command above is important. When Gnuplot draws a new line or area, it does it over what it has already drawn or paint. With lines (second diagram in this page) it makes no practical difference. With areas, instead, it’s esential to paint them in the right order. This means that you must plot first the highest area (“Website 4″ in our example) that is the one that is the sum of all the original columns. Then comes the one that is the sum of only the first three columns etc…