Identifying WordPress Hooks
In order to develop WordPress solutions, you are required to understand how WordPress hooks work. Sadly WordPress has over 1000 hooks in the system, so the task may be daunting to know which hook to exactly use.
There are a few options to find out which hook to use:
- Comb through the source code
- Comb through WordPress documentation on hooks
- Search the Internet for the right hook to use.
Each one requires you to do some searching. Wouldn't it be easier if we let WordPress do that job for us? Whenever we load a page, WordPress will tell us what hooks were called, and in what order.
do_action
Note: WordPress has two kinds of hooks. An action hook, and a filter hook. This article only deals with the action hook. But it can also apply to the filter hook. The filter hook can also be found in wp-includes/plugin.php on line 134
WordPress calls its hooks via the function do_action. do_action calls out all the hooks attached to the hook specified in its arguments. If you open up wp-includes/plugin.php, you should be able to find a function called do_action on line 299.
Note: I am currently running WordPress v3.0 beta. Your file name and line positions may be different.
In order to output the called hook, your first thought may be to enter echo $tag. Sadly this won't work as it will output text all over the WordPress application, which will make it difficult in identifying the hooks called.
FirePHP to the Rescue
Instead we will use FirePHP. Make sure you have FirePHP installed. You can also ensure FirePHP gets loaded on all PHP pages.
Now change the file to:
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
fb($tag);
Now reload the home page of your WordPress installation with FirePHP enabled and you should get a similar result.
- muplugins_loaded
- plugins_loaded
- sanitize_comment_cookies
- setup_theme
- load_textdomain
- after_setup_theme
- load_textdomain
- auth_cookie_malformed
- set_current_user
- init
- widgets_init
- wp_loaded
- posts_selection
- template_redirect
- get_header
- wp_head
- wp_enqueue_scripts
- wp_print_styles
- wp_print_scripts
- posts_selection
- posts_selection
- get_generic_template_loop
- get_sidebar
- get_search_form
- posts_selection
- wp_meta
- get_footer
- get_sidebar
- wp_footer
- wp_print_footer_scripts
- shutdown
Why don't you visit some other pages to test it out? It works in the Admin side as well.
Backtrace
This is all cool and all, but to get a better understanding of how the WordPress platform works, I sometimes I want to know where the hook was called.
Don't worry, we can solve that for you.
Replace the code you entered with:
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
$backtrace = array_shift(debug_backtrace());
fb(substr($backtrace['file'], strlen(ABSPATH)) . ':' . $backtrace['line'] . ' ' . $tag);
The result should be like so:
- wp-settings.php:151 muplugins_loaded
- wp-settings.php:193 plugins_loaded
- wp-settings.php:201 sanitize_comment_cookies
- wp-settings.php:239 setup_theme
- wp-includes/l10n.php:300 load_textdomain
- wp-settings.php:270 after_setup_theme
- wp-includes/l10n.php:300 load_textdomain
- wp-includes/pluggable.php:548 auth_cookie_malformed
- wp-includes/pluggable.php:55 set_current_user
- wp-settings.php:287 init
- wp-includes/default-widgets.php:1144 widgets_init
- wp-settings.php:296 wp_loaded
- wp-includes/query.php:2322 posts_selection
- wp-includes/template-loader.php:7 template_redirect
- wp-includes/general-template.php:26 get_header
- wp-includes/general-template.php:1554 wp_head
- wp-includes/script-loader.php:700 wp_enqueue_scripts
- wp-includes/functions.wp-styles.php:21 wp_print_styles
- wp-includes/script-loader.php:672 wp_print_scripts
- wp-includes/query.php:2322 posts_selection
- wp-includes/query.php:2322 posts_selection
- wp-includes/general-template.php:114 get_generic_template_loop
- wp-includes/general-template.php:84 get_sidebar
- wp-includes/general-template.php:146 get_search_form
- wp-includes/query.php:2322 posts_selection
- wp-includes/general-template.php:350 wp_meta
- wp-includes/general-template.php:55 get_footer
- wp-includes/general-template.php:84 get_sidebar
- wp-includes/general-template.php:1564 wp_footer
- wp-includes/script-loader.php:620 wp_print_footer_scripts
- wp-includes/load.php:517 shutdown
Now how cool is that?
Making FirePHP Accessible to Every PHP Page
I heart FireBug. I loved FireBug so much, I even made a simple Ruby on Rails plugin to log to FireBug, called FireBug Logger.
It was rudimentary, but it did its job. Lucky for me, a similar project exists in the PHP world, appropriately labelled FirePHP.
FirePHP
FirePHP is bit fancier, in that it can format the output that is sent to the FireBug console. But because of this feature, it requires to be installed as a Firefox extension.
This post will not discuss on the benefits of using FirePHP, or how to install it. There are lots more material available out there on that.
Making FirePHP Easily Accessible
Sadly to get FirePHP available to every PHP script, you are required to call the code to load FirePHP (fb.php). But this is not necessarily true.
In your php.ini, there is an option called auto_prepend_file which will automatically include a PHP file before executing the requested PHP file.
So with this can call load FirePHP prior to any execution, and thus making it accessible via any script that is executed.
Lets enable the auto_prepend_file and give it a value to another PHP file.
auto_prepend_file = /Users/aizat/src/firephp/firephp.php
Don't forget to restart your Apache, else your changes won't be applied!
Now inside /Users/aizat/src/firephp/firephp.php, I will require the main FirePHP library like so:
<?php
require_once('lib/FirePHPCore/fb.php');
if (php_sapi_name() != 'cli' && ini_get('output_buffering') == false) {
ob_start();
}?>
Make sure that the require_once on line 3 points to the location of the fb.php.
require_once('lib/FirePHPCore/fb.php');
Testing
Now lets test it with a very simple file. Create a php file and dump this inside:
<?php
fb("auto_prepend_file successfully worked!", FirePHP::LOG);
?>
Open the file in your web browser, and it should load successfully!
There you have it, easy debugging without manually requiring the FirePHP libraries, and accessible in all PHP files. What more do you want?
Batch Download of Photos From Flickr Based on Their Tag
For the FOSS.my event, I wanted everyone to tag their photos with foss.my or foss.my 2008. Because this makes it easier to easily see FOSS.my buzz as it happens on Flickr!
A Tale of Sucky Wordpress Plugins
I was looking for a plugin to grab Flickr photos by a specified tag, so that we can use it in the foss.my gallery. Though there are many Flickr plugins for Wordpress, there was none catered to my requirements. Unable to find a solution, I thought it was quicker to hack one myself.
So this script just expanded from there, and I quickly had a Flickr batch downloader.
[block:important]There are several requirements:
- Download phpFlickr, and unzip it to the same directory as the script.
- You need to obtain a Flickr API key.
[/block]
Use the source
<?
/*
* phpFlickr
* http://phpflickr.com/
*
* Flickr API
* http://www.flickr.com/services/api/
*
* Flickr API call flickr.photos.search
* http://www.flickr.com/services/api/flickr.photos.search.html
*
* Photos are available via the following format:
* http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[mstb].jpg
*
* For more information visit http://www.flickr.com/services/api/misc.urls.html
*
* Applying for a Flickr API Key
* http://www.flickr.com/services/api/keys/apply/
*/
require_once("phpFlickr.php");
define('VERBOSE', array_search('-v', $argv));
// Download a batch of photos from the given page
function download($photos) {
$download = 0;
foreach ($photos['photo'] as $photo) {
$filename = sprintf("pics/%s-%s.jpg", $photo['owner'], $photo['id']);
$url = sprintf("http://farm%d.static.flickr.com/%s/%s_%s_o.jpg", $photo['farm'], $photo['server'], $photo['id'], $photo['secret']);
if (file_exists($filename)) {
if (VERBOSE)
print sprintf("33[33m %-10s %s33[0m \n", "Skip", $url);
else
print sprintf("33[33m.33[0m");
continue;
}
if (VERBOSE)
print sprintf("33[32;1m %-10s %s33[0m \n", "Download", $url);
else
print sprintf("33[32m.33[0m");
file_put_contents($filename, file_get_contents($url));
$download += 1;
}
return $download;
}
$flickr = new phpFlickr("YOUR_API_KEY");
$options = array('tags' => 'fossmy, "fossmy 2008", foss.my, "foss.my 2008"');
$photos = $flickr->photos_search($options);
print sprintf("Available 33[32;1m %d 33[0m \n", $photos['total']);
// Download the first batch of photos
$downloaded = download($photos);
$page = $photos['page'];
$pages = $photos['pages'];
// Download the following batch of photos
for ($i = 2; $i < $pages; $i++) {
$options['page'] = $i;
$photos = $flickr->photos_search($options);
$downloaded += download($photos);
}
if (! VERBOSE)
echo "\n";
print sprintf("Downloaded 33[32;1m %d 33[0m/ %d \n", $downloaded, $photos['total']);
Running it
It's just as a simple as:
[block:terminal]php download.php[/block]
Sample Results:
[block:terminal]
Available 492
..................[trim]............
Downloaded 0 / 492
[/block]
It even comes with a -v flag, so you can view what files are being downloaded.


