Joho the Blogtutorial Archives - Joho the Blog

November 11, 2015

Unlocking Keynote's hidden frames

For some reason, Apple Keynote continues to ship with many more frames than it lets you use. (Frames are called Picture Frames when you click on the Border dropdown menu in the Format panel.) You can get Keynote to list these hidden frames if you’re willing to mess around with a file that might break Keynote.

Please nod your head to indicate that you’ve read and understood the above warning.

The first thing to do is to find the hidden files. For Keynote 6.6 (the latest version), they’re here:

/Applications/Keynote.app/Contents/Resources/Frames/

To get there you have to select Keynote in your Applications folder and right-click on it, or do what you have to in order to get the popup menu. Choose “Show Package Contents” and navigate to the Frames folder.

Screen capture of frames UI

In that folder is a file named FrameInspectorLayoutInfo.plist. Make a copy of it as a backup and put it some place safe.

Nod your head to indicate that you have done that. I mean it.

Open the original of that file in a text editor of your choice. (If you’re comfortable editing plists in Xcode, use that. It’s easier.) This is an XML file that lists all the frames that will show up when you choose Picture Frame from the Border dropdown. (To see them, you have to click the tiny triangle to the right of the thumbnail view Keynote provides of the Picture Frame you’ve chosen.)

You can see the available frames in the Frames folder in Finder where you found the file you’re currently editing. To add a frame, you add it to the list called “Asset Scales” that is the first half of the file, and you add it again to the list called “Display Order” that is the second half. But you add it differently in each.

Asset Scales expects an entry of this form:

<key>Spiralbook Creme</key>
<real>0.59999999999999998</real>

Please note that I DO NOT KNOW WHAT THAT SECOND LINE MEANS. So I’ve just been copy-pasting it and replacing the name of the frame. It does not work for some frames (e.g., Venetian 3), which results in a blank spot in the menu of available frames…but if you click on that blank space, for some of them you get the frame anyway. In the sample file I’m providing, I have not included any frames with that problem. (Asset Scales probably specifies how to display the thumbnail version of the frame. It just doesn’t work for all of them, and I don’t know why.)

The Display Order list does what it sounds like: it controls the order of the layout of the thumbnails you can choose from. It does not have to be the same as the order of the frames in the Asset Scales list. It expects entries in this form:

<string>Spiralbook Creme</string>

Make a typo and you’ll have a blank spot where a thumbnail is supposed to be, and that blank spot won’t do anything.

Now save the file; it will likely ask you for permission first. Reload Keynote. Enjoy your new frames.

I’m posting a version of the replacement file here. I’ve only added about half of the frames so far because I’m lazy. I’ll add more over time.

Nod your head if you agree not to blame me for screwing up your Mac.

2 Comments »

October 5, 2015

Enabling JavaScript to read files on your drive via Dropbox: A “Where I went wrong” puzzle.

Ermahgerd, this was so much harder than I thought it would be. In fact, what follows is best approached as a puzzler in which your task is to find the earliest place where I’ve gone horribly wrong. The winning comment will be of the form, “You’re such an idiot! All you had to do was____!” Second place, because less satisfying but no less humiliating, will be comments of the form, “OMFG, why are you writing this? How can you get the simplest thing wrong???”

I know. Forgive me.


So, let’s say you’re writing, oh, an outliner for your own personal use because the one you’ve been using for seven years or so no longer supports Dropbox: If you save an OmniOutliner file to a Dropbox folder, it only gets one of the sub-files. You poke around with alternatives but none of have exactly the set of minimal features you want. (Dave Winer’s Fargo gets damn close to my peculiarities, and it saves outlines in Dropbox…but in only one special folder. I’m picky. And I was looking for a programming project.) So, you decide to write your own. Sure, it’ll be under-featured, and it’ll break. But it’ll be yours.


It’s going to run in a browser because you can’t find any other way to write an app for your Mac except Objective C and Swift, both of which require three days of tutorials and a hundred pushups to get to “Hello, world.” So, you’re using JavaScript and jQuery, JavaScript’s smarter older brother. (Hi, Andy.) And PHP.


Now, you can try as hard as you want, but “The browser is going to insist on protecting you from accessing files on anyone’s hard drive, even your own”the browser is going to insist on protecting you from being able to access files on anyone’s hard drive, even your own, because otherwise Malefactors are going to install apps that will suck your brains out through your smallest aperture and take your credit card numbers with it. For real.

I tried many of the things the Internet recommends to circumvent this well-meaning rule. I wouldn’t have even tried, but I’m running my outliner on my local hard drive, using the Apache2 web server that comes with MAMP. So, I understand why there’s a wall around the files that are not part of what the web server considers to be its home, but those files are mind. So close, yet so far.

I tried figuring out how to set up a virtual directory, but the initial efforts failed and monkeying with apache files scares me. Likewise for changing the server’s document root.

I put a symbolic link to my Dropbox folder into the JavaScript project’s folder (actually in the “php” sub-folder), and was able to write a file into it via PHP. But I couldn’t figure out a way to read the Dropbox folder, which means that if I wanted to switch from loading an outline from

/Dropbox/blogposts/2015/October

to

/Dropbox/Bad_Ideas/Recipes_For_Disaster


I’d have to type in the entire pathname. No directory browsing for you!

(To create a symbolic link, in your Mac terminal type: “ln -s /Users/YOUR_NAME/Dropbox”. )


So, I had a brainstorm. I use outlines in almost everything I do, but virtually everything I do is in Dropbox. “Dropbox.com has a perfect mirror of my files and folder structure. ”Dropbox.com therefore has a perfect mirror of my files and folder structure. Perhaps Dropbox has an API that would let me browse its mirror of my local disk.


It does! With lots of documentation, almost none of which I understand! I’m sure it’s terrific for people who know what they’re doing, but won’t someone please think of the people who need a For Dummies book to read a For Dummies book?


What I’d like to do is to browse the file structure at Dropbox.com so I can identify the file I want to open, and have Dropbox.com tell me via its API what that file’s path is. Then I could use PHP or even JavaScript (I think) to directly open that file on my own disk via the Dropbox symbolic link in my PHP folder. Right?


Guess what the Dropbox.com API doesn’t tell you. Which is too bad because I want to use the same info later to save a file to a pathname inside that symbolic link.

But Dropbox does make it easy for you to drop a magic button into your HTML that will launch a Dropbox mini-file-browser. The version called the “Chooser” downloads files. The version called “Saver” uploads them. Just what I need.


Sort of. What I’d really like to do is:


  • Browse my Dropbox folders using the Chooser.

  • Click to download my chosen file.


  • Read the content of that file into my app, so I can display the outline contained within.



“As a matter of principle, I want to be able to have a user choose it, and read the contents programmatically. Thus did I lose, oh, two days of my life.”As a matter of principle, I want to be able to have a user choose it, and read the contents programmatically. Thus did I lose, oh, two days of my life.


I will not bore you with the many ways I tried to do this basic thing. I am sure that someone is going to read this and give me the one line of code I need. Instead, here is the complex way I managed to accomplish this basic task.

Register your app

First, you have to register your app with Dropbox in order to get a key that will let you access their API. This is relatively simple to do. Go to their App Console, and click on the “Create App” button. When asked, say you want to use the Dropbox API, not the Dropox for Business API, unless you have a business account with Dropbox. It will ask if you want to access a particular folder or all of the user’s folders. It will ask you to give your app a name; it has to be unique among all apps registered there.

On the next page, the fourth line is your app key. Copy it. Click on the “app secret” and copy it too. For OAuth redirect, use “localhost” if you’re hosting your app locally. Or put in the URL of where you’re hosting if it’s going to be out on the Web. Likewise for “Chooser/Saver domains.”

Now, into your HTML file place the line:

<script type=”text/javascript” src=”https://www.dropbox.com/static/api/2/dropins.js” id=”dropboxjs” data-app-key=”YOUR_KEY”></script>

Obviously, insert your Dropbox key (see above) appropriately.

Ok, let’s create the app.

The app


Into your HTML document create an empty div where the Dropbox button will go:

1

<div id=”DBbutton”></div>


In the header of your HTML document make sure you’ve included jQuery:

1

<script src=”https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js”></script>


Of course, if you prefer to download your own copy of jQuery instead of using Google’s, go ahead. But at this point so much of what I do goes through Google that avoiding using it for jQuery seems foolish.

Also in your header, after the jQuery line, place the following:

1

<script type=”text/javascript” src=”./js/Your_File_Name.js”></script>

Create a subfolder in the directory where your HTML file is and name it “js”. Using your favorite text editor create a file called whatever you want to call it, with a “js” extension. Obviously make sure that the file’s name is exactly the one in the line above. That .js file is where you’ll put your JavaScript…although in this example I’m including it all in the HTML file itself because all I’m going to do is going to occur in the script that loads immediately after the file loads. So never mind.

Here’s the rest of what should go into the head section of your HTML file.

1

<script type=”text/javascript”>

 

2

$(document).ready(function(){

3

var opts= {

4

success: function(files) {

5

var filename = files[0].link;

6

filename = filename.replace(“dl=0″,”dl=1”);

7

//alert(filename);

8

$.ajax({

9

url: “./php/downloadDropboxContents.php”,

10

data: “src=” + filename,

11

success: function(cont){

12

//alert(cont);

13

},

14

error: function(e){

15

alert(e.responseText);

16

}

17

});

18

},

19

extensions: [“.txt”,”.opml”],

20

multiselect: false,

21

linkType: “download”

22

};

23

var button = Dropbox.createChooseButton(opts);

24

document.getElementById(“DBbutton”).appendChild(button);

25

});

26

</script>


Line 2 is a very handy jQuery function that gets executed after the entire page has been downloaded into the browser. That means all the bits and pieces are there before the code in the function is executed.


In this case, the code is going to create a Dropbox button for the user to press. The options for that button are expressed in lines 2-22. Let’s start with the last lines.


Line 19 lists the extensions I want to let users (= me) select for download. There are only two: files that end with .txt and ones that end with .opml. OPML is the standard format for outlines. (Thank you, Dave Winer.)

Line 20 says that I don’t want users to be able to open more than one file at a time.


On line 21 we specify that we want Dropbox to give us back the downloaded file. The alternative is “preview,” which will provide a preview.


By the way, note that each option line ends with a comma, except for the last one. This whole option statement is actually a JSON set of key:value pairs, each delimited by a comma. In some cases, as in Dreaded Line 4, the values are multi-line and complex. Nevertheless, they’re still just values of the keyword to the left of the colon.


But I’m just putting off talking about the “success” option, lines 4-18, that set what happens if the download operation is successful.


Line 4 creates a function that will get passed an array of downloaded files, which unimaginatively I am capturing in the variable “files.”


Line 5 gets the link to the first file in the array. The array is files[]. The appended “.link” gets the URL to the Dropbox file, but it’s a funky link that, alas, doesn’t express the pathname, but some seemingly arbitrary set of characters. For example:

https://www.dropbox.com/s/smwhasdgztdiw5gbn/A%20History%20of%20the%20Philosophy%20of%20Time.%20txt?dl=0



If you were instead to say “files[0].name”, you’d get the file’s name (“A History of the Philosophy of Time.txt”). And if you say “.path” you — damn their eyes — get an error. Aargh. This could have been so much easier! Anyway.


“Line 6 is something I discovered on my own, i.e., I didn’t read the documentation carefully enough.”Line 6 is something I discovered on my own, i.e., I didn’t read the documentation carefully enough. Notice the “dl=0” at the end of the file link above. I’m going to guess the “dl” stands for “download.” If you leave it at 0, you get the user interface. But — aha! — if you replace it with 1, it downloads the actual damn file into your normal download folder, which defaults on the Mac to the Download folder. So, line 6 does the search and replace. (If line 7 weren’t commented out, it’d pop up the file link.)


So now we have a link that will download the file. Excellent!


Lines 8-17 use that URL to actually download it and read it. This requires (i.e., it’s the only way I know how to do it) executing a PHP script. For that we use AJAX, which JavaScript makes hard but jQuery makes easy.


Line 9 points to the PHP file. It lives in a folder called “php.” The “./” is redundant — it says “that folder is in the current directory” but I’m superstitious. We’ll write the PHP file soon.


Line 10 is the dumb way of saying what data we’re going to pass into the PHP script. We’re using the variable “src” and we’re passing the path to the downloadable Dropbox file. The better way to express this data would be to use JSON, but I never remember whether you put the key in quotes or not, so I’d rather do it this way (which in essence simply writes out the appendage to the basic PHP’s script URL) than look it up. But, I just did look it up, and, no, you don’t quote the keys. So line 10 should really be:

data: {src : filename},

but I’m too lazy to do that.

Now in line 11 we get to what we do with the results of the PHP script’s processing of the content it’s going to receive. The commented-out line would post the content into a dialogue box so you can confirm you got it, but what I really want to do is turn the content of that file into a outline displayed by my app. So, my real line 12 will be something like “displayOutline(cont)”, a function that I’ll stick elsewhere in my JavaScript. But that’s not what we’re here to talk about.


Lines 14-6 get invoked if the PHP fails. It displays a human-readable version of the error code. You’ll also want to be looking at your console’s error log. If you’re using MAMP, look at php_error.log, which you’ll find in MAMP/logs.


At line 23, we’re outside of the options declaration. Line 23 uses Dropbox to create a Chooser button that when pressed will pop up the Chooser with the right options set. “With luck, when you load it, you’ll see a Dropbox button sitting there.”


The button exists but not on your page. For that to happen, you need line 24 to tell your page to find the div with the id of “DBbutton” and to insert the button into it as a new last element. (Since there are no elements in that div, the button becomes its only element.)


All this happens before your page becomes visible. With luck, when you load it, you’ll see a Dropbox button sitting there.


Now onto the PHP.

The PHP

Create a folder named “php” in the same directory as your HTML file. In it create a file called “downloadDropboxContents.php”.


Here it is:

1

<?php

 

2

$src = $_REQUEST[‘src’]; // url

3

$filename = basename($src); // get the file’s name

4

error_log(“SRC; $src – FILENAME: $filename”);

5

$dir=”Downloads”; // set the folder to download into

6

// create the pathname for the downloaded file

7

$downloads = $dir . “/” . $filename; // md5($src);

8

// get the contents of the download — YAY!

9

$out = file_get_contents($src);

10

error_log($out);

11

// put the downloaded file there

12

file_put_contents($downloads, $out);

13

// repeat the contents out loud

14

echo $out;

 

15

?>


The comments should tell the story. But just in case:


Line 2 picks up the data we’ve passed into it. $src now should have the URL to the Dropbox file.


Line 3 gets the file name from the pathname. We’re going to need that when we save the file into our designated folder (which is “Downloads,” which you may recall, we created a symbolic link to in our php folder.)


Line 4 optionally writes the Dropbox URL and the filename into the console (see above), just to see where we’ve gone wrong this time.


Line 5 specifies what folder to put the downloaded file into. Remember that it has to be within the realm your web server counts as document root. Hence the symbolic link to Downloads in the php folder.


Line 7 creates the path name to that download folder by appending the file name to the path, with a “/” in between them.


Line 9 copies the actual damn contents of the downloaded file into a variable I’ve called “$out”. Line 10 checks the content. You probably want to comment that line out.“Line 14 reports the contents back to the “success” function…”


Line 12 writes the content into the download directory.


Line 14 reports those contents back to the “success” function in the JavaScript. It will there be captured by the variable “cont” in line 11.


That’s it. I know this is sub-optimal at best, and probably far more fragile than I think. But it works for now, at least with simple text files. And I couldn’t find anything at this level of beginnerness online.


I’m sorry.

1 Comment »

August 4, 2015

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!

3 Comments »