Command Line Blogging – WordPress

I am using command line most of the time because of the nature of my work. Normally, when I discovered new techniques to do things, solved a problem or had a cool idea, I would write them down on my exercise book. It soon became clear that I needed something more concrete as copying lines of code isn’t fun (and they were very disorganised). I was also thinking of a way to share my ideas with the world…

How about posting them in a blog! Sounds good, But I don’t want to be alt-tabbing, copying and pasting between firefox and the terminal. Most importantly, I don’t like the idea of people seeing me blogging during working hours. Looks like I have to investigate how to do it in command line then.

I know that there are some command line blogging tools out there but what I need is the ability to post articles in WordPress (because I am using it) using the command line. After some googling, I knew that that is possible using command line php and xmlrpc. WordPress supports xmlrpc. Time to rock.

This point onwards is all WordPress related. Anyone interested can download a copy of WordPress from http://www.wordpress.com. What I will be doing here is to come up with a simple php script to post articles in wordpress blogs.

Investigation

In xmlrpc.php, line 133 – 166 tells us what API WordPress supports.

133 // Blogger API
134 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
135 'blogger.getUserInfo' => 'this:blogger_getUserInfo',
136 'blogger.getPost' => 'this:blogger_getPost',
137 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
138 'blogger.getTemplate' => 'this:blogger_getTemplate',
139 'blogger.setTemplate' => 'this:blogger_setTemplate',
140 'blogger.newPost' => 'this:blogger_newPost',
141 'blogger.editPost' => 'this:blogger_editPost',
142 'blogger.deletePost' => 'this:blogger_deletePost',
143
144 // MetaWeblog API (with MT extensions to structs)
145 'metaWeblog.newPost' => 'this:mw_newPost',
146 'metaWeblog.editPost' => 'this:mw_editPost',
147 'metaWeblog.getPost' => 'this:mw_getPost',
148 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
149 'metaWeblog.getCategories' => 'this:mw_getCategories',
150 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
151
152 // MetaWeblog API aliases for Blogger API
153 // see http://www.xmlrpc.com/stories/storyReader$2460
154 'metaWeblog.deletePost' => 'this:blogger_deletePost',
155 'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
156 'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
157 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
158
159 // MovableType API
160 'mt.getCategoryList' => 'this:mt_getCategoryList',
161 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
162 'mt.getPostCategories' => 'this:mt_getPostCategories',
163 'mt.setPostCategories' => 'this:mt_setPostCategories',
164 'mt.supportedMethods' => 'this:mt_supportedMethods',
165 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
166 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
167 'mt.publishPost' => 'this:mt_publishPost',

The name of the function tells a lot. I had a quick look at the functions and MetaWeblog API seems to be quite promising as it supports a wide range of options. The part that I am interested is the function mw_newPost.

1365 /* MetaWeblog API functions
1366 * specs on wherever Dave Winer wants them to be
1367 */
1368
1369 /* metaweblog.newPost creates a post */
1370 function mw_newPost($args) {
1371 $this->escape($args);
1372
1373 $blog_ID = (int) $args[0]; // we will support this in the near future
1374 $user_login = $args[1];
1375 $user_pass = $args[2];
1376 $content_struct = $args[3];
1377 $publish = $args[4];
1378
1379 if (!$this->login_pass_ok($user_login, $user_pass)) {
1380 return $this->error;
1381 }
1382 $user = set_current_user(0, $user_login);
1383
1384 do_action('xmlrpc_call', 'metaWeblog.newPost');

So we need to pass an array containing 5 elements to the function, namely $blog_ID (not implemented yet), $user_login, $user_pass, $content_struct and $publish. Looking at the code further, I know that $content_struct contains another array and there are a few elements within $content_struct that I am interested for now: title, categories, mt_keywords. With all these information at hand, I can start building my script.

Check Requirements

I am going to use php built-in xml-rpc function. So my php has to support xml-rpc.


[username@web ~]$ cd /etc/php.d
[username@web php.d]$ ls
dbase.ini  mysqli.ini  pdo.ini        pdo_sqlite.ini
gd.ini     mysql.ini   pdo_mysql.ini  
[username@web php]$ cd /usr/lib/php/modules/
[username@web modules]$ ls
dbase.so  mysqli.so  pdo_mysql.so  pdo_sqlite.so
gd.so     mysql.so   pdo.so        phpcups.so

ok, looks like xmlrpc is not installed. I need to install it.

[username@web modules]$ yum install php-xmlrpc

Actual PHP Code

Now we have what we need. Time to code:

#!/usr/bin/php -q
$v) {
echo "[$k. $v] ";
}
echo "\n\neg. ".basename($_SERVER['argv'][0])." -t \"blog title\" -c 1,3,4 -k \"php,linux\" -p 0\n";
exit(1);
}
$options = getopt("c:k:t:p:");
if (empty($options)) {
displayHelp();
}
// convert categories to array
$cat = explode(',',$options['c']);
$catList = getCategories();
$categories = array();
foreach ($cat as $v) {
$categories[] = $catList[$v];
}
// convert tags to array
$tag = explode(',',$options['k']);
$title = $options['t'];
$publish = ($options['p']) ? $options['p'] : 1;
$stdin = file_get_contents("php://stdin", "r");
// posting blog
$params = array();
$contruct_params = array(
'title'=>$title,
'description'=>"$stdin",
'mt_allow_comments'=>1,
'mt_allow_pings'=>1,
'mt_keywords'=> $tag,
'categories'=> $categories
);
$request_params = array(
'1',
$username,
$passwd,
$contruct_params,
$publish
);
$request = xmlrpc_encode_request("metaWeblog.newPost", $request_params);
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: text/xml",
'content' => $request
)));
$file = file_get_contents($url, false, $context);
$response = xmlrpc_decode($file);
if (xmlrpc_is_fault($response)) {
echo $response['faultString'];
exit(1);
}
else {
echo "article posted successfully";
exit(0);
}
?>

anyone interested in the code can get it here

As you can see, the script is a quick draft. There are a few things that I can improve on it. First of all, I can do more work on validating the input arguments or making getopt work better. Then, instead of hardcoding the categories, I can retreive all categories using the function ‘metaWeblog.getCategories’. I can also ping technorati after every post. There is a good possibility of expanding the script and create a class that make use of other API functions, like ‘metaWeblog.getPost’ and ‘metaWeblog.deletePost’… and lastly, the command line can be more user friendly with more interactive prompts. The possibilities are limitless.

Time to test

I call the script ‘postblog’ and put in under my bin directory, ie ~/bin. Then display the help to see the category options.


[user@web ~]# postblog
Usage: postblog -t [title] -c [categoriesNo] -k [tags] -p [publish]
category choice: [0. Blog] [1. Think Linux] [2. Think Network Monitoring] [3. Think Networking] [4. Think Technology] [5. Think PHP] [6. Think Regular Expression] [7. Think SEO] [8. Think Software] [9. Think SQL] [10. Other Interest]
eg. postblog -t "blog title" -c 1,3,4 -k "php,linux" -p 0

I wrote my blog in vim and save the file as ‘myblog’. To publish the article in wordpress under the ‘Blog ‘, ‘Think Linux’ category with blogging and technology tags,


[user@web ~]# cat myblog | postblog -t "Command Line Blogging" -c 0,1 -k blogging,technology
[user@web ~]# article posted successfully

Yay, it works!

What’s Next

Perhaps a bash version of the script or further improvements on the php current script.

Author: bpeh

Bernard Peh is a great passioner of web technologies and one of the co-founder of Sitecritic.net Website Design and Reviews. He works with experienced web designers and developers everyday, developing and designing commercial websites. He specialises mainly in SEO and PHP programming.

1 thought on “Command Line Blogging – WordPress”

Comments are closed.