Posting to WordPress without WordPress
Perhaps you’d like to post to your WordPress blog from an app that isn’t WordPress.
I know I do. I write most of my posts in an editor (javascript + php) I’ve worked on for over ten years. Someday I’ll clean it up and post it at GitHub so you can all have a laugh. Meanwhile, it intermittently loses its ability to post straight to my blog, so I have to copy and paste the text into the WP editor. But I fixed it again today. So, here’s a tutorial for people at my level of non-technicality. (I got huge help from a post at HurricaneSoftware. Thanks!)
First, make sure that the file xmlrpc.php is installed where you’ve installed your WordPress blog software. This file comes from WordPress itself, and it should be there automatically. Check the permissions; I think it should be 644 but I am terrible at permissions.
I run my homegrown editor from my Mac, using the Apache web server that MAMP supplies. That lets me write blog posts even when I’m not online. That means the directory from which I’m running my JavaScript and PHP is on my hard drive. I keep these files in /Applications/MAMP/htdocs/blogdraft/. (Blogdraft is the name of the folder in which my code resides.) To the web server, the address looks like this: /localhost/blogdraft/.
The operative part of this is your PHP file. Create an empty text file and name it, let’s say, postViaXmlrcp.php. For a first pass, it should look like this—and the brunt of this comes straight from HurricaneSoftware:
1 |
<?php |
2 |
// Modified from: |
3 |
// http://www.hurricanesoftwares.com/wordpress-xmlrpc-posting-content-from-outside-wordpress-admin-panel/ |
4 |
// Thanks!! |
|
|
5 |
require_once(“IXR_Library.php.inc”); |
6 |
$client->debug = true; //Set it to false in Production Environment |
7 |
$title=$_REQUEST[‘title’]; |
8 |
$body=$_REQUEST[‘body’]; |
9 |
$keywords=$_REQUEST[‘tags’]; |
10 |
$category=$_REQUEST[‘categoryArray’]; |
11 |
$customfields=null; |
|
|
12 |
$encoding = ini_get(“default_charset”); |
13 |
$title = htmlentities($title,ENT_QUOTES,$encoding); |
14 |
$keywords = htmlentities($keywords,ENT_QUOTES,$encoding); |
|
|
15 |
$content = array( |
16 |
‘title’=>$title, |
17 |
‘description’=>$body, |
18 |
‘mt_allow_comments’=>1, // 1 to allow comments |
19 |
‘mt_allow_pings’=>1, // 1 to allow trackbacks |
20 |
‘post_type’=>’post’, |
21 |
‘mt_keywords’=>$keywords, |
22 |
‘categories’=>$category, |
23 |
‘custom_fields’ => array($customfields) |
24 |
); |
|
|
25 |
// Create the client object |
26 |
$client = new IXR_Client(‘http://www.yourblog.com/myWP/xmlrpc.php’); |
27 |
$username = “your-WP-username”; |
28 |
$password = “your-WP-password”; |
|
|
29 |
$params = array(0,$username,$password,$content,true); // Last parameter is ‘true’ which means post immediately, to save as draft set it as ‘false’ |
|
|
30 |
// Run a query for PHP |
31 |
if (!$client->query(‘metaWeblog.newPost’, $params)) { |
32 |
die(‘Something went wrong – ‘.$client->getErrorCode().’ : ‘.$client->getErrorMessage()); |
33 |
} else { echo “Article Posted Successfully”; } |
34 |
?> |
This PHP script relies upon another one, so you have to load it. “Require_once” will do so, and it will remember that it has done so during a session so you won’t waste computer resources reloading it every time you run this script.
You can get this script here. Right click on that link and choose “Save file as…” or however your browser puts it. Put it in the same directory as your PHP script. Make sure you name it “IXR_Librabry.php.inc.” Set its permissions. (See above.) Then leave it alone.
7 |
$title=$_REQUEST[‘title’]; |
8 |
$body=$_REQUEST[‘body’]; |
9 |
$keywords=$_REQUEST[‘tags’]; |
10 |
$category=$_REQUEST[‘categoryArray’]; |
11 |
$customfields=null; |
These lines read data that you’ve sent from the JavaScript that we haven’t written yet. It assigns them to some pretty obviously-named PHP variables.
Notice that we’re doing nothing with the $customfields variable. That’s because I don’t know what to do with it. I would have just deleted that line, but it scares me. And yet fascinates me.
12 |
$encoding = ini_get(“default_charset”); |
13 |
$title = htmlentities($title,ENT_QUOTES,$encoding); |
14 |
$keywords = htmlentities($keywords,ENT_QUOTES,$encoding); |
htmlentities is a PHP function that makes sure that your HTML with all of its weird characters arrive without being translated into something more literal and wrong. Line 12 tells it which character encoding to use. I could have decided on one for you, but instead I’m just using whichever one you already use. We have already established I’m a coward, right?
15 |
$content = array( |
16 |
‘title’=>$title, |
17 |
‘description’=>$body, |
18 |
‘mt_allow_comments’=>1, // 1 to allow comments |
19 |
‘mt_allow_pings’=>1, // 1 to allow trackbacks |
20 |
‘post_type’=>’post’, |
21 |
‘mt_keywords’=>$keywords, |
22 |
‘categories’=>$category, |
23 |
‘custom_fields’ => array($customfields) |
24 |
); |
We are eventually going to be sending all of the content information to WordPress via XMLRPC. This section packs an array (“$content”) with the information XMLRPC needs, attached to the keywords it loves. If you want to argue about it, take it up with XMLRPC.
26 |
$client = new IXR_Client(‘http://www.yourblog.com/myWP/xmlrpc.php’); |
We now create a new client for the IXR script you downloaded. It wants to know where your xmlrpc.php file is, which should be where the rest of your WordPress files are folders are.
27 |
$username = “your-WP-username”; |
28 |
$password = “your-WP-password”; |
Fill in your WordPress username and password.
29 |
$params = array(0,$username,$password,$content,true); // Last parameter is ‘true’ which means post immediately, to save as draft set it as ‘false’ |
Now we’re making another array. This one includes the prior array ($content) as well as your username and password. And note the comment. Setting to “draft” is very useful when you’re playing around with these scripts.
31 |
if (!$client->query(‘metaWeblog.newPost’, $params)) { |
32 |
die(‘Something went wrong – ‘.$client->getErrorCode().’ : ‘.$client->getErrorMessage()); |
33 |
} else { echo “Article Posted Successfully”; } ?> |
This does the deed. No one knows how. If it fails, it’ll pop up the error messages and kill it before it spawns evil. Otherwise, it sends back the message that it posted successfully.
You can test this PHP script by running it in your browser. If you’re running a local web server, you’d enter something like this: /localhost/blogdraft/postViaXmlrcp.php. (That’s assuming you put it in a folder called “blogdraft,” of course.) Check with MAMP or whatever you’re using for your web server for details.
But running this as-is won’t work because it’s expecting the content to be sent to it from the JavaScript we still haven’t written. So, comment out lines #7-11, and insert something like these:
$title=”TEST TITLE”; |
|
$body=”<h1>Hello, world!</h1>” |
|
$keywords=”tag1,tag2″ |
|
$category=array(“cat1″,”cat2”); |
|
$customfields=null; |
Replace the categories (“cat1”, “cat2”) with the names of categories that you actually use. Also, change “true” to “false” in line #29 so you’ll just produce drafts, not actually publish anything yet.
Now when you run this PHP file in your browser ( /localhost/yourLocalFolder/postViaXmlrcp.php), if should create a draft post. Check via the “All posts” page at your WP administration page to see if the draft got created.
When it’s working, comment out the four lines immediately above and uncomment lines #7-11.
The JavaScript
I’m going to pretend that you have some HTML page that has a text box where you can enter the content of your post, a similar box for entering the title, one for entering tags separated by commas, and checkboxes that list the categories you use. I’ll also assume that you use jQuery. So, your HTML might look soomething like this:
1 |
<!DOCTYPE html> |
2 |
<html lang=”en”> |
3 |
<head> |
4 |
<meta charset=”utf-8″ /> |
5 |
<title>WordPress poster tester</title> |
6 |
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js”></script> |
|
|
7 |
<script> |
8 |
function postIt(){ |
9 |
// get the title |
10 |
var titlecontent = $(“#titlebox”).val(); |
11 |
// get the body of the post |
12 |
var bodycontent = $(“#contentbox”).val(); |
13 |
// get the tags |
14 |
var tagscontent = $(“#tagsbox”).val(); |
|
|
15 |
// create array of categories |
16 |
// get an array of all checkboxes in the div |
17 |
var checks = $(“#categories”).find(“input”); |
18 |
// create an empty array |
19 |
var cats = new Array(); |
20 |
// go through all the checkboxes |
21 |
for (var i=0; i < checks.length; i++){ |
22 |
// is this one checked? |
23 |
if ($(checks[i]).is(‘:checked’)){ |
24 |
// if so, then push its value into the array |
25 |
cats.push( $(checks[i]).val() ); |
26 |
} |
27 |
} |
28 |
// run the php |
29 |
$.ajax({ |
30 |
type: “POST”, |
31 |
url: “postViaXmlrcp.php”, |
32 |
dataType: JSON, |
33 |
data: {title: titlecontent, body : bodycontent, tags: tagscontent, categoryArray : cats}, |
34 |
error: function(e){ |
35 |
if (e.responseText.indexOf(“Successfully”) > -1){ |
36 |
alert(“Success! Post has been posted! Let the regrets begin!”); |
37 |
} |
38 |
else{ |
39 |
alert(‘Error posting blog via xmlrpc: ‘ + e.responseText); |
40 |
} |
41 |
} |
42 |
}) |
43 |
} |
44 |
</script> |
|
|
|
|
45 |
</head> |
46 |
<body> |
47 |
<textarea id=”titlebox”>test title</textarea> |
48 |
<textarea id=”contentbox”><h1>got some content here</h1></textarea> |
49 |
<textarea id=”tagsbox”>tag1, tag2</textarea> |
50 |
<div id=”categories”> |
51 |
<input value=”business” type=”checkbox” checked>Cats |
52 |
<input value=”dogs” type=”checkbox”>Dogs |
53 |
<input value=”philosophy” type=”checkbox”>Phenomenology |
54 |
</div> |
55 |
<input type=”button” value=”Post It!” onclick=”postIt()”> |
56 |
</body> |
57 |
</html> |
So, roughly, here’s what’s happening:
6 |
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js”></script> |
This loads jQuery from Google. Of course you could keep a local copy and include it that way.
8 |
function postIt(){ |
9 |
// get the title |
10 |
var titlecontent = $(“#titlebox”).val(); |
11 |
// get the body of the post |
12 |
var bodycontent = $(“#contentbox”).val(); |
13 |
// get the tags |
14 |
var tagscontent = $(“#tagsbox”).val(); |
The postIt function begins by using jQuery to fetch the values entered into the three text areas. (Just in case you don’t know jQuery, “$(“#titlebox”) gets the element with the ID of “titlebox.” And if you don’t want to use jQuery, you can get the same result with: var titlecontent = document.getElementById(‘titlebox’).value.
16 |
// get an array of all checkboxes in the div |
17 |
var checks = $(“#categories”).find(“input”); |
18 |
// create an empty array |
19 |
var cats = new Array(); |
20 |
// go through all the checkboxes |
21 |
for (var i=0; i < checks.length; i++){ |
22 |
// is this one checked? |
23 |
if ($(checks[i]).is(‘:checked’)){ |
24 |
// if so, then push its value into the array |
25 |
cats.push( $(checks[i]).val() ); |
26 |
} |
27 |
} |
Creating an array of categories takes a little more work. Line #17 creates an array (“checks”) of all of the checkboxes in the div with the id “categories.” Lines #21-27 look at each of the checkboxes in that array. If line #23 sees that a particular checkbox has in fact been checked, then it puts the value of that checkbox into the created on line #19. (You want the value to be exactly the same as the name of the category in your WordPress installation. Also, remember that the checkbox’s value is not necessarily the same as the text displayed to the user.)
29 |
$.ajax({ |
30 |
type: “POST”, |
31 |
url: “postViaXmlrcp.php”, |
32 |
dataType: JSON, |
33 |
data: {title: titlecontent, body : bodycontent, tags: tagscontent, categoryArray : cats}, |
34 |
error: function(e){ |
35 |
if (e.responseText.indexOf(“Successfully”) > -1){ |
36 |
alert(“Success! Post has been posted! Let the regrets begin!”); |
37 |
} |
38 |
else{ |
39 |
alert(‘Error posting blog via xmlrpc: ‘ + e.responseText); |
40 |
} |
41 |
} |
42 |
}) |
Now we call the PHP script that we created above. We do this via AJAX, using the jQuery syntax, which is much simpler than the native JavaScript way of doing it. Lines #30-40 specify the communication the JavaScript will have with the PHP file.
Line #30: The “POST” here has nothing to do with posting a blog post. It’s stating what sort of transaction we’re about to have with the PHP script.
Line #31: This is the path to the PHP file we’re going to run. If it’s in the same directory as this HTML file, you don’t have to monkey with a path name.
Line #32: We’re going to pass data to the PHP script in the JSON way of expressing data.
Line #33: This creates the JSON we’re going to send. It’s all within curly brackets. There are four phrases, separated by commas. Each phrase consists of a keyword (which you can think of as being like a variable) and a value. We are free to make up whatever keywords we want, so long as those are the keywords we use in the PHP file to fetch the data that they label; see lines #7-10 in the PHP script above.
Line #44: If there is an error in the PHP, it will send back some information. There is also an equivalent “success:” function available. But I’m doing something wrong, because even when the PHP works and the blog gets posted, I still get an error message. If you go back to Line #33 of the PHP, you’ll see that if the PHP succeeds, it sends the message “Article Posted Successfully.” For reasons I don’t understand, that message shows up in the “error:” function of the AJAX. So, I check the message. If it has the word “Successfully” in it, the script alerts the user that the post has been posted. If it does not, on line #39 it posts an error message.
That’s it. If it doesn’t work, it’s because you’re doing something wrong, starting with listening to me. Obviously I can’t help you since I don’t even know how this thing works.
Good luck!