Accessing Other Databases/Servers From Within WordPress

Say you have a WordPress install where you need to pull in data from a separate database or server. The normal $wpdb instance of the wpdb class is limited to the database that your WordPress tables are located in. Yes, you could use mysql_connect() and the other standard PHP database functions, but then you don’t get all of the WordPress magic. So what to do?

The answer is surprisingly simple: make a new instance of the wpdb class! Dion Hulse (DD32) was kind enough to point out this great solution to me a few weeks back and I thought it was worth sharing with you all.

$myotherdb = new wpdb( $dbuser, $dbpassword, $dbname, $dbhost );

$myotherdb->get_results( "SELECT id, name FROM mytable" );

Changing Core WordPress Strings

One of the lesser known filters in WordPress is gettext. All strings that are run through the WordPress translation functions are also run through this filter after being translated thanks to a ticket I opened way back in 2008. That means you can actually use it to change pretty much any string in WordPress, namely in the admin area.

I’ve used this in some plugins I’ve written in the past and it works incredibly well.

My co-worker and one of the lead developers of WordPress Peter Westwood (westi) wrote a really good blog post about this, however I wasn’t completely happy with his code so I’m writing this blog post to share how I would write some code to take advantage of this versatile filter. Don’t get me wrong — he wrote good and valid code, but it’s not exactly the easiest thing for a novice to extend for their own uses.

function youruniqueprefix_filter_gettext( $translated, $original, $domain ) {

	// This is an array of original strings
	// and what they should be replaced with
	$strings = array(
		'View all posts filed under %s' => 'See all articles filed under %s',
		'Howdy, %1$s' => 'Greetings, %1$s!',
		// Add some more strings here
	);

	// See if the current string is in the $strings array
	// If so, replace it's translation
	if ( isset( $strings[$original] ) ) {
		// This accomplishes the same thing as __()
		// but without running it through the filter again
		$translations = &get_translations_for_domain( $domain );
		$translated = $translations->translate( $strings[$original] );
	}

	return $translated;
}

add_filter( 'gettext', 'youruniqueprefix_filter_gettext', 10, 3 );

So as you can see at it’s core it accomplishes the same thing as Peter’s code however my code should be a bit more clear on how to make it translate multiple strings.

Hope someone finds this helpful! :)

Easily Create XML In PHP Using A Data Array

I’ve been working with the Google Contacts API lately and needed to construct some XML as a part of that. PHP’s DOMDocument works really great for this, but it can get complicated fast as you need to create lots of variables for all of your elements, children, etc. It can make it quite hard to do dynamically.

An easier method would be to just convert an array into XML, the opposite of simplexml_load_string() if you will. So I wrote some code that does exactly that and I thought I’d share it incase anyone else would find it helpful. :)

Start by creating your array of data. I used a numeric array instead of an associative array because you can have duplicate elements in XML while you cannot have duplicate array keys.

$data = array(
	'name' => 'toplevelelement', // "name" required, all else optional
	'attributes' => array(
		'foo' => 'bar',
		'fruit' => 'apple',
	),
	'value' => 'Some random value.',
	array(
		'name' => 'achildelement',
		'value'=> 'Value',
	),
	array(
		'name' => 'anotherchildelement',
		'attributes' => array(
			'some' => 'attr',
		),
		array(
			'name' => 'grandchildelement',
		),
	),
);

An array such as that is easy to dynamically create based on your source data, it’s easy to read, and can be fairly easily manipulated.

name is the only required item of each array and it’s the tag name of the element. attributes is an array of attributes for the element and value is the value. Both of these are optional. Any children arrays are children elements and their structures should be the same.

Now here’s the code I wrote that converts the above array into some XML:

function generate_xml_element( $dom, $data ) {
	if ( empty( $data['name'] ) )
		return false;

	// Create the element
	$element_value = ( ! empty( $data['value'] ) ) ? $data['value'] : null;
	$element = $dom->createElement( $data['name'], $element_value );

	// Add any attributes
	if ( ! empty( $data['attributes'] ) && is_array( $data['attributes'] ) ) {
		foreach ( $data['attributes'] as $attribute_key => $attribute_value ) {
			$element->setAttribute( $attribute_key, $attribute_value );
		}
	}

	// Any other items in the data array should be child elements
	foreach ( $data as $data_key => $child_data ) {
		if ( ! is_numeric( $data_key ) )
			continue;

		$child = generate_xml_element( $dom, $child_data );
		if ( $child )
			$element->appendChild( $child );
	}

	return $element;
}

$doc = new DOMDocument();
$child = generate_xml_element( $doc, $data );
if ( $child )
	$doc->appendChild( $child );
$doc->formatOutput = true; // Add whitespace to make easier to read XML
$xml = $doc->saveXML();

You first create a blank canvas by creating a new instance of the DOMDocument class and then you pass the class instance (needed for creating elements in the correct character set and such) and the data array to the generate_xml_element() function. This function will create the top level element and then recursively call itself on any child elements until it’s gone through the whole array.

Once it’s done, you’ll need to append the element to the DOM using the inherited appendChild() function. Then calling saveXML will give you the XML output. The above example data array will give you something like this (maybe or maybe not nicely formatted with whitespace depending on what mood DOMDocument is in):

<?xml version="1.0"?>
<toplevelelement foo="bar" fruit="apple">
	Some random value.
	<achildelement>Value</achildelement>
	<anotherchildelement some="attr">
		<grandchildelement></grandchildelement>
	</anotherchildelement>
</toplevelelement>

And there you have it!

Creating Simple oEmbed-Based WordPress Shortcodes

Say you wanted to create a shortcode like this: [youtube id="991WcoEPwb8"]

And instead of manually creating the HTML yourself, you wanted to use YouTube’s oEmbed provider to get the HTML. While that’s easy to do using WordPress’ existing functions (wp_oembed_get() for example), you must implement your own caching of the result as WordPress’ oEmbed class does not include any caching of it’s own.

However, WordPress comes with an [embed] shortcode that’s also secretly used for the shortcode-less embeds. A cool trick is to make that shortcode’s existing code (complete with caching) work for you! This post explains how to do it.

First, the code:

add_shortcode( 'youtube', 'my_youtube_shortcode' );

function my_youtube_shortcode( $atts ) {

	// We need to use the WP_Embed class instance
	global $wp_embed;

	// The "id" parameter is required
	if ( empty($atts['id']) )
		return '';

	// Construct the YouTube URL
	$url = 'http://www.youtube.com/watch?v=' . $atts['id'];

	// Run the URL through the  handler.
	// This handler handles calling the oEmbed class
	// and more importantly will also do the caching!
	return $wp_embed->shortcode( $atts, $url );
}

We start by gaining access to the WP_Embed instance that we’ll be making use of and then making sure we have the required video ID (you can do whatever you want here). We then create the full URL to the video that oEmbed will need. Lastly the real time saver — we pass the attributes (“id” will be ignored) and the constructed URL to the [embed] shortcode handler which will fetch the result and cache it.

Simple, huh?

One thing to note though: if you’re using this along with a non-default oEmbed provider, you’ll also need to whitelist it using wp_oembed_add_provider().

Twitter Followers Count Snippet for WordPress

UPDATE: This code no longer works as Twitter retired v1.0 of their API. v1.1 of their API requires authentication in order to access it. I have no plans to update this code for their new API. Sorry.

Konstantin Kovshenin posted some code on his blog for how to display how many Twitter followers someone has. While the idea was good, I think he went about the implementation in the non-best method. So, for fun and because I don’t post enough code snippets here on this blog, I thought I’d post how I would display how many followers someone has on Twitter. :)

function viper_twitter_followers( $username = 'Viper007Bond' ) {

	// Just to keep the code below cleaner, create the cache key now
	$cache_key = "viper_twitter_followers_{$username}";

	// First we look for a cached result
	if ( false !== $followers = get_transient( $cache_key ) )
		return $followers;

	// Okay, no cache, so let's fetch it
	$result = wp_remote_retrieve_body( wp_remote_get( 'http://api.twitter.com/1/users/show.json?screen_name=' . urlencode($username) ) );

	// Check to make sure we got some data to work with
	if ( empty($result) ) {
		// Cache the failure for 1 min to avoid hammering Twitter
		set_transient( $cache_key, 0, 60 );
	}

	// Parse the data
	$data = json_decode( $result );

	// Make sure we were able to parse it
	// If not, cache the failure (like above)
	if ( !isset( $data->followers_count ) )
		set_transient( $cache_key , 0, 60 );

	// Success! Cache the result for an hour.
	$followers = (int) $data->followers_count;
	set_transient( $cache_key, $followers, 3600 );

	return $followers;
}

echo 'I have ' . viper_twitter_followers( 'Viper007Bond' ) . ' followers on Twitter!';

Reading Material:

If you have any questions about the above code, let me know and I’ll do my best to answer them. :)

Tracking WordPress Remote HTTP Requests

UPDATE: You can find improved code in this newer blog post. Use that instead.

I thought I’d share a bit of code that I run on my local WordPress test install to see when WordPress is contacting another website. I originally wrote this to help debug my oEmbed code, but it’s useful for a wide variety of purposes. :)

<?php

if ( !defined('DOING_AJAX') )
	add_filter( 'http_request_args', 'debug_http_api', 10, 2 );

function debug_http_api( $r, $url ) {
	echo '<p style="text-align:left">HTTP API was used to fetch <code>' . esc_html( $url ) . '</code></p>';

	return $r;
}

?>

The above code will output something like this any time a HTTP request is made using the HTTP API, but only if the request was not made from an AJAX handling script (as it will break the AJAX response):

HTTP API was used to fetch http://www.google.com/

While I’m using a filter to do this, I’m actually using the filter much like an action as I’m not modifying the passed data but merely using the filter as a place to hook in and catch the URL.