Wednesday, August 11, 2010

Using PlanningCenterOnline.com's API with PHP

It's been a bumpy road, but thanks to Scotty at Planning Center Online, I've finally got their API working through PHP. In my case, I've got it returning info to render a custom Facebook Application for the church's Page, listing all the songs we sang during the previous weekend's services, and giving various links using the song names (search iTunes, Amazon, Zune or Pandora, etc). So I wanted to document the steps here, both in case I have to go back later, and for anyone else trying to do something similar.

First, a few requirements.
1) You will need a web server running PHP5
2) I assume that you have an understanding of XML and HTML- writing an app is not something that should be for first foray into the world of online programming.
3) If you need a database (more on that in a minute), you need to know how to access it and configure it yourself.
4) Knowing PHP is going to help you (quite a bit, probably), but for the record, I am one of those who doesn't know PHP, so it's entirely possible to do this, if you have other programming experience. If this is you, let me give you two tips that turned on a light bulb for me: the command -> in PHP is somewhat akin to a dot in other languages like Javascript...$str->doThis() would be more or less the same as $str.doThis() in other languages; it takes the variable and applies a function to it. Also, a dot concatenates strings instead of a plus sign or ampersand in other languages.

The mile-high overview starts at http://www.planningcenteronline.com/home/api . As they note, they use OAuth 1.0a for authentication, so you need to e-mail them with details of your app to get a Consumer Key. The e-mail address is listed on that page, I'm not going to repeat it here 'cause I want you to go look at that page and find what info they want you to send them. After all, they may change the address or information they need in the future.

Now, as they say on that overview page, they've provided some sample PHP files- so pay those files a visit.

1) You need to download four files: OAuth.php, common.php, index.php and complete.php . OAuth.php and common.php are just include files, the only thing you need to do with these is to edit common.php to enter your app's key and secret (unchanging random strings provided to you when you e-mail them as I noted above), and to point $callback_url to complete.php.

Now I need to explain the functions of the other two files, because they aren't what you might initially expect. Complete.php is actually your app itself. Loading index.php on the other hand, actually starts the initial authorization process, and should only be loaded once per user. But at the end of that process, it will use $callback_url to send the user back to complete.php. So you might want to rename index.php to something like requestAuth.php and complete.php to the file name you actually want people to load, if you wanted to help keep it straight in your mind. That said, I'm still going to refer to them by their original names throughout this entry.

2) Now you need to upload OAuth.php and common.php to a directory on your web server where PHP will be looking for include files. On my server, this is under admin/core, but yours will probably be somewhere else. But don't assume that all four files can just be uploaded to a single directory and expect php to be able to find them.

3) Now it's time to figure out how you want your app to work. If you want it to just create a page that looks the same and has the same data no matter who loads it, you might want to create a user in your organization's PlanningCenterOnline account that has full viewing rights. That way your app has access to any info you want, but if something goes wrong, the account doesn't have the power to affect other users, change or delete data, etc. With this method, YOU will be loading index.php once, and logging in using that new account, and authorizing the app to use that account. The end users loading the page don't ever have to authorize anything.

Let me talk for a minute about apps that instead give each user different data based on their own account (showing them their calendar, listing songs only on weekends they're scheduled for, etc). For this app, you don't need to make a new user account, since each user will be authorizing the app to use their own account. You're going to need to store users and their authorization keys in a list or some kind of database. I still think this article will be valuable to you so that you have an idea of where everything goes and what it does, but I'm not going to go into specifics on how to create this type of app or working with the database you'll need. But here's a high-level overview of what you're going to need to do for this type of dynamic user-specific app:

-Your users will probably be coming in and hitting your complete.php page first, since once it's authorized that's where they'll need to be going. You need to have complete.php check your database or list to see if they have authorized the app before, and if not, redirect them to index.php.
- Once they authorize through index.php, you need to store their credentials so they don't have to authorize again. You can either do this at the bottom of index.php before they return to complete.php, or you can point $callback_url in common.php to a new php file that does nothing but store their creds, then redirect them to complete.php itself. That way you'd keep complete.php simpler- a simple, "if they're not in the database, redirect to index.php" condition.
- Everything else will be mostly the same as I outline below- instead of hard-coding the key and token into the php code, you'll just be using the stored strings in your database.

Now back to assuming that your app will display the same data to everyone:

4) Edit complete.php like so:
- Delete everything below line 51. That is, delete everything from
// 4. Set Person id for example 1 and example 2
down, but leave the ?> tag in the last line intact. Now at the end of the file (but above the ?> tag), enter these two lines:
echo $access_token['oauth_token'] . "<br />";
echo $access_token['oauth_token_secret'];
Now upload index.php and complete.php to your web server.

5) Fire up your browser, and load your index.php page. It will immediately bounce you to PlanningCenterOnline and ask you to log in (if you're not already). Log in to whatever account you want the data to get pulled from. Once you're logged in, it will ask you whether you want to allow your application access to your account. Check "Authorize access" and click "Save changes". It will redirect you to complete.php, and there should be two lines of random characters. The first line is the token proving that this account has authorized access to this app, and the second line is the secret to verify the token is legitimate. You need these strings in the next step.

6) Now edit complete.php again. This time, delete everything below the two require_once lines at the top of the file (again, leave only the ?> line at the bottom of the file intact). Now between the second require_once line and the ?> line, put in this code:
$test_consumer = new OAuthConsumer($key, $secret, NULL);
$access_consumer = new OAuthConsumer('abcdabcdabcdabcdabcd', '1234123412341234123412341234123412341234', NULL);
Now replace the "abcd..." string with the token that showed up a moment ago on complete.php (it's the top line). And replace the "1234..." string with the secret string that was below it.

(if you're storing these keys in the database, this is obviously where you want to fetch the data for the current user and replace that in, instead of hard-coding it into the php here).

7) Your app should be able to authenticate sucessfully now, and make requests to modify or read data, based on the permissions of the authenticated user in PlanningCenterOnline. To make sure it worked, add in the following lines just above the ?> tag:
// build and sign request
$request = OAuthRequest::from_consumer_and_token($test_consumer,
$access_consumer,
'GET',
'https://www.planningcenteronline.com/organization.xml',
NULL);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(),$test_consumer,$access_consumer);
// make request
$response = run_curl($request, 'GET');
// display request
echo $response;
Now upload complete.php again, and browse directly to it again. This time, you should see a whole lot of XML output providing you all the data about your organization. It should look similar to what you see in their example. If you do, it worked! Not too bad, huh?

8) Now for the fun part: you need to actually write your app! Fortunately, this is a lot easier than all the OAuth stuff. See how, in the lines above, we chose to, "get" the URL https://www.planningcenteronline.com/organization.xml? GET means that we want to read, not change, the specified data. The URL is documented under "Organization API" at http://www.planningcenteronline.com/home/api. So look through all the APIs (Plans, People, Songs, etc) and look at their samples to see what output you can expect, in order to extract the data you want to show in your app. Anytime the URL on one of their APIs includes the number 1, you need to understand that's actually a placeholder for an ID you need to get from one API level "up".

So for my app, which lists all the songs sung in a particular week, I have to start at the Organization API and extract the ID of the correct "service type". (I know which service type I want because each service type has a "name" tag associated with it as well, and that's the name I'm used to seeing in Planning Center). Say that ID was 1234.

Now look at the Plans API. The URL you need to GET to get a list of available plans (in my case, plans = weekends) is https://www.planningcenteronline.com/service_types/1/plans.xml, so I replace 1 with the 1234 that IDs the service type I want to look into, and build my query to GET https://www.planningcenteronline.com/service_types/1234/plans.xml instead.

That returns a list of available plans, so I need to parse the list to find the ID of the plan I want to examine. Then replace that ID into the URL for listing all the elements of a service. For my app, I then parsed to find the IDs of all elements which had a "type" of "PlanSong", and looped through the list, replacing each ID into the URL of the Songs API to extract the titles.

Now, I did find out that there is at least one argument you can put on the end of the URL to change the output- since my app deals with plans in the past and the default return from the Plans API is only future plans, they told me instead of running GET on https://www.planningcenteronline.com/service_types/1/plans.xml, I could run it on https://www.planningcenteronline.com/service_types/1/plans.xml?all=true instead. See the extra parameter there on the end? all=true tells it to return past services as well. And they told me if there were multiple parameters to use an ampersand (&) between the keys, which along with the question mark before the first key, is pretty typical. But I was never able to get an answer or find a list of all the available parameters for the different URLs, nor did brief experimentation with other logical key/value combinations yield anything else that worked. But if there's some information you need that it won't return, write 'em up and ask them- there just may be a parameter you can add that will do the trick for you! And if you learn of any others, please leave a comment here!

Though a detailed description of looping through the XML is more than I want to cover in this post, I'll at least point you in the right direction. I store the XML data in $response, as you saw in the initial Organization API example we used to make sure authentication was working. So here's how I display the date of the service whose songs I'm listing:
$xml = simplexml_load_string($response);
foreach($xml->children() as $child)
{
if($child->getName() == 'dates')
{
echo 'Songs from the ' . $child . ' services';
}
}
I hope that helps someone who wants to use the API with PHP!

9 Comments:

At October 2, 2012 at 10:01 PM , Anonymous Steve L. said...

Great blog post! This will help with a little project I'm working on.

 
At November 27, 2012 at 8:04 AM , Blogger Josh Baker said...

Hi Michael Great post! however I've followed your steps closely and am having a problem retrieving information.

I can go from planning center, login and get it to redirect, i just cant get any of the echo commands with my php to display the information i need.

Any ideas?

 
At November 27, 2012 at 9:36 AM , Blogger james3mg said...

Josh,

I'd probably start by making sure PHP is getting to that point- I tend to do things like:

echo "->";
echo $access_token['oauth_token'] . "<br />";
echo $access_token['oauth_token_secret']";
echo "<-";

to make sure that PHP is still running before and after those lines, and to see if there are any characters between the arrows.

If PHP prints "-><-" without anything else (expect potentially a line break between the arrows), then I would add a call to phpinfo() at the end to check your php version and configurations, etc...

 
At November 28, 2012 at 2:31 AM , Blogger Josh Baker said...

Hi Michael now when i use this command i get the following error.

The website encountered an error while retrieving http://www.youth4oasis.co.uk/pc/complete.php?oauth_token=2AqqJGvDx0zZrt8SckCn&oauth_verifier=G1mtNM4gwVBK411JA96y. It may be down for maintenance or configured incorrectly.

 
At December 5, 2012 at 12:33 PM , Blogger james3mg said...

Josh,

Sorry I took so long to respond. No, I don't really know what's up...I'm not affiliated with the company, so all I can say is that my implementation has continued to be working Have you tried again recently? I hit the URL you gave and there aren't any errors now.

Try phpinfo() to check your version and etc, then start working backwards to try again

Thanks

 
At January 1, 2013 at 1:07 PM , Blogger John said...

Michael,

Thanks v. much for your post. I used it to help me generate a WordPress plugin that can access PlanningCenter through the plans API.

Early days, more to come. https://github.com/tetrahedra/ApbcPCORota

John

 
At September 25, 2013 at 10:36 PM , Blogger Lindsay said...

Hi. Thanks. I found this the most helpful thing on the Internet to get this working. PCO should edit this into their documentation...

Do you know if it is possible to write TO plans? I can only see GET for the plan API, but I want to write into plans as well...

Thanks.

 
At September 26, 2013 at 6:48 AM , Blogger james3mg said...

Lindsay-

Glad to have helped! One quick comment before I go on- when I went back to look for what you need, I noticed a note that XML support is deprecated and will be removed in January. So make sure to adapt what I've written to use the new JSON notation.

Yes, it's possible to update/create items through the API. Start off at their API documentation, and at the top of the page, click on the API you need (people, plans, etc). I'll use people as an example.

In all the examples in this post, I was using the LIST and SHOW methods. But scroll farther down their documentation page and you'll see CREATE and UPDATE methods, too. CREATE uses POST, and UPDATE uses PUT. The URL is https://www.planningcenteronline.com/people.json (or if you're updating an existing person, it's https://www.planningcenteronline.com/people/1.json, replacing "1" with the ID number of the person you have already gotten by LISTing the people in your organization). Just like normal when LISTing.

For CREATE you can include the ?welcome_email=true parameter at the end of the URL if you want to send a welcome email with login instruction and etc.

So that's the method and URL to use.

You of course have to include the data of the person you want to create. Format the data in JSON, and send that as the body of the HTTP request.

That's it!

 
At October 9, 2013 at 9:10 PM , Blogger Lindsay said...

Thanks. I've been using the JSON methods.

Plans can NOT be updated with their existing (public) API, but songs and people can. I want to update plans, but they don't provide an API for this.

I've emailed them and apparently it can be done (their iOS app does it), but they won't make it public or provide support for it because it might change. They said I could use it if I could figure it out myself.

I've tried doing it just like you do for songs, but with no success: 401 Unauthorized.
If anyone knows how to do it, please let me know!

 

Post a Comment

Links to this post:

Create a Link

<< Home