Integrating WordPress with External Systems

WordCamp DFW, 2014
Slides: https://adcwp.me/wcdfw2014

Aaron D. Campbell – https://aarondcampbell.com/
aaron@ithemes.com – @AaronCampbell
http://profiles.wordpress.org/aaroncampbell/
WordPress

WordPress does an awful lot!
But not everything – Enter third party APIs

API Documentation
- Fact: Documenting something is the bane of a coders existence
- Fact: This results in horrible, incomplete, and wrong API documentation
- Fact: Bad API documentation is also the bane of a coders existence
How to read API documenation
- As a guideline
- As if it’s out of date or wrong
- Because it likely is
API Code Libraries
Many popular APIs offer pre-made libraries in several languages
Don’t Use Them!*
*Except to learn how the API works so you can write your own
Some JavaScript libraries are not optional. You can use these, but PLEASE use wp_enqueue_script()
The problem with pre-made libraries
- They are often coded horribly (seriously, who writes these?)
- Because they’re coded so poorly they often conflict with themselves if another plugin or theme uses them
- They often don’t cover the whole API
- They don’t do things the WordPress way, so there’s a lot of wasted/duplicate code
The “application”
Many APIs require you to register in advance
- https://developers.facebook.com/apps
- https://dev.twitter.com/apps
- https://code.google.com/apis/console/ (here it’s a “project”)
- Most are free, but some require a credit card or SMS verification to prove you’re a real person
The keys
Once you register you usually get an API key of some kind. Often you get a key as well as an application identifier.
These are yours and are often tied to your site. Do not distribute them with your plugin and be aware that you probably need a new one if you move the plugin to a new domain.
Now for the fun part!
Your friends
- wp_remote_request();
- wp_remote_get();
- wp_remote_post();
- wp_remote_head();
- wp_remote_retrieve_headers();
- wp_remote_retrieve_header();
- wp_remote_retrieve_response_code();
- wp_remote_retrieve_response_message();
- wp_remote_retrieve_body();
- wp_http_supports();
Making the request
Just choose your method. The default for wp_remote_request() is GET.
$response = wp_remote_request( $url, $args = array() ); $response = wp_remote_get( $url, $args = array() ); $response = wp_remote_post( $url, $args = array() ); $response = wp_remote_head( $url, $args = array() );
Retrieving the response
Just choose what data you are wanting to retrieve. Usually what you want is the body. The response code is often useful too.
$data = wp_remote_retrieve_body( $response ); $data = wp_remote_retrieve_headers( $response ); $data = wp_remote_retrieve_header( $response, $header ); $data = wp_remote_retrieve_response_code( $response ); $data = wp_remote_retrieve_response_message( $response );
Can you do what you want?
if ( wp_http_supports( array( 'ssl' ) ) ) {
// Yay!
}
The code
$params = array( 'body' => $this->_prepRequest($args), 'sslverify' => false, 'timeout' => 30, ); // Send the request $resp = wp_remote_post( $endpoint, $params ); return wp_parse_args( wp_remote_retrieve_body( $resp ) );
_prepRequest()
private function _prepRequest($req) {
$defaults = array(
'VERSION' => $version,
'PWD' => $password,
'USER' => $username,
'SIGNATURE' => $signature,
'CURRENCYCODE' => $currency,
);
return wp_parse_args( $req, $defaults );
}
What you get
Array (
[PROFILEID] => ***
[STATUS] => Active
[AUTOBILLOUTAMT] => NoAutoBill
[DESC] => Annual Subscription
[SUBSCRIBERNAME] => Example Man
[PROFILESTARTDATE] => 2013-02-10T06:00:00Z
[NEXTBILLINGDATE] => 2013-02-10T10:00:00Z
[AMT] => 49.00
...
)
Caching – Do It!
Thoughts on caching
- I prefer to cache actual output
- Cache at least the response if at all possible
- Only bust the cache when you actually need to
- Options over transients
- TLC Transients – https://github.com/markjaquith/WP-TLC-Transients
Sample with TLC Transients
$key = 'twp_' . md5( $url ); return tlc_transient( $key ) ->expires_in( 300 ) // cache for 5 minutes ->updates_with( 'parseFeed', array( $o ) ) ->get();
That’s it. It’s like cache-magic
Incoming data
What do you mean by incoming data
Some APIs will send information to you without you sending a request. PayPal’s IPNs are a good example. They can tell you that a recurring payment has been canceled or that a card being automatically charged every month was declined.
So how do you process data that you didn’t request? Where does it go?
Build a Listener
add_action( 'wp_ajax_nopriv_pp_listener', 'listener' );
public function listener() {
$_POST = stripslashes_deep($_POST);
if ($this->_validateMessage())
$this->_processMessage();
exit; // Stop WordPress entirely
}
We use admin-ajax to process incoming requests from PayPal to wp-admin/admin-ajax.php?action=pp_listener.
Build a Listener – and do what?
You can just process the message right there (update user record, add updated info to database, etc). But what if you’re building this for other people to use? Why not fire actions that other people can hook into?
function _processMessage() {
do_action( 'paypal-ipn', $_POST );
if ( !empty($_POST['txn_type']) )
do_action("paypal-{$_POST['txn_type']}", $_POST);
}
In this case a ‘paypal-ipn’ action fires and is passed all the data that PayPal sent us. If there is a transaction type, then a more specific ‘paypal-{transaction-type}’ action is also fired.
Final Thoughts
Don’t reinvent the wheel. Check if WordPress does what you want.
If WordPress has it, USE IT! Otherwise don’t complain when you have to rewrite it because the latest version of WordPress broke it.
Everyone else is _doing_it_wrong(). That doesn’t make it OK.
Code samples adapted from PayPal Framework and Twitter Widget Pro – find other good examples in Otto’s plugins.