Over the last few weeks I have been wondering on how to possibly pull data about my plugins hosted on WordPress.org and display it on my website. The first thing that came to mind was "Web Scrapping" but quite frankly this is a lot of work, feels like going back in time, and is not something a good web citizen should do. In some cases, it could be illegal.
I then came across a plugin called "I Make Plugins", developed by Mark Jaquith, which did just want I wanted by fetching data from the readme.txt file of a plugin. It works great but since WordPress allows us to search for plugins directly from the backend and also to see our favorite plugins, I knew there was a better way (or The WordPress Way) and further searching led me to the WordPress.org API. No detailed documentation on this page, but enough to get started knowing there is an API to do this more efficiently.
WordPress.org Plugins API
The URL where all plugin search / update related calls are made is http://api.wordpress.org/plugins/info/1.0/. To get a quick idea of how this works, open this link in a browser and add your plugin slug at the end, e.g. http://api.wordpress.org/plugins/info/1.0/custom-favicon/ and see what is returned.
This browser-based GET request displayed all plugin information for the plugin "Custom Favicon" in the format below. By replacing the last path of the URL with the slug of your plugin you would be able to see details specific to your plugin.
O:8:"stdClass":20:{s:4:"name";s:14:"Custom Favicon";s:4:"slug";s:14:"custom-favicon";s:7:"version";s:3:"1.0";s:6:"author";s:80:"<a href="http://www.dreamsonline.net/wordpress-themes/">Dreams Online Themes</a>";s:14:"author_profile";s:38:"http://profiles.wordpress.org/hchouhan";s:12:"contributors";a:3:{s:8:"hchouhan";s:38:"http://profiles.wordpress.org/hchouhan";s:12:"dreamsonline";s:42:"http://profiles.wordpress.org/dreamsonline";s:11:"dreamsmedia";s:41:"http://profiles.wordpress.org/dreamsmedia";}s:8:"requires";s:3:"3.5";s:6:"tested";s:5:"3.5.2";s:13:"compatibility";a:2:{s:5:"3.5.1";a:1:{s:3:"1.0";a:3:{i:0;i:100;i:1;i:5;i:2;i:5;}}s:3:"3.6";a:1:{s:3:"1.0";a:3:{i:0;i:100;i:1;i:1;i:2;i:1;}}}s:6:"rating";d:100;s:11:"num_ratings";i:3;s:10:"downloaded";i:1995;s:12:"last_updated";s:10:"2013-05-27";s:5:"added";s:10:"2013-05-27";s:8:"homepage";s:61:"http://www.dreamsonline.net/wordpress-plugins/custom-favicon/";s:8:"sections";a:4:{s:11:"description";s:594:"<p>Now easily upload a favicon and apple touch icon for your WordPress website and dashboard.</p></pre> <p>Please report any bugs you find via <a href="http://www.dreamsonline.net/wordpress-plugins/custom-favicon/" rel="nofollow">http://www.dreamsonline.net/wordpress-plugins/custom-favicon/</a></p> <h4>My Links</h4> <ul> <li>Twitter @<a href="https://twitter.com/dreams_media">harishchouhan</a></li> <li>Google+ <a href="https://plus.google.com/u/0/103138475844539274387/">Harish Chouhan</a></li> </ul>
Not very presentable, but hey, at least this is a good start to test if the API delivers plugin information quickly, which we can then display the way we like.
Until this point, most of what I was doing was just based on random trials. The only resource I could find was http://dd32.id.au/projects/wordpressorg-plugin-information-api-docs/ which tries to explain the various options and arguments that can be used when communicating with this API.
So How Does This Work?
To communicate with http://api.wordpress.org/plugins/info/1.0/ and retrive information you need to make a $POST
request with 2 things:
- Post Action - such as,
$_POST['action']
- Post Body - such as,
$_POST['body']
, which has to be a serialized object
The returned data from the API is an Object in all cases (except when visiting the API link from a browser). Even in case of an error, the returned data is still an object but with a single property, an error string.
My first attempt to retrive plugin information was something like this below example:
Example of Retriving Plugin Information Using wp_remote_post
HTTP API
<?php $args = (object) array( 'slug' => 'custom-favicon' ); $request = array( 'action' => 'plugin_information', 'timeout' => 15, 'request' => serialize( $args) ); $url = 'http://api.wordpress.org/plugins/info/1.0/'; $response = wp_remote_post( $url, array( 'body' => $request ) ); $plugin_info = unserialize( $response['body'] ); echo '<pre>' . print_r( $plugin_info, true ) . '</pre>'; ?>
We will explain the code later but for now the above example code will return information about our plugin in the format shown below, in the event that everything works as intended:
stdClass Object ( [name] => Custom Favicon [slug] => custom-favicon [version] => 1.0 [author] => Dreams Online Themes [author_profile] => http://profiles.wordpress.org/hchouhan [contributors] => Array ( [hchouhan] => http://profiles.wordpress.org/hchouhan [dreamsonline] => http://profiles.wordpress.org/dreamsonline [dreamsmedia] => http://profiles.wordpress.org/dreamsmedia ) [requires] => 3.5 [tested] => 3.5.2 [compatibility] => Array ( [3.6] => Array ( [1.0] => Array ( [0] => 100 [1] => 1 [2] => 1 ) ) ) [rating] => 100 [num_ratings] => 3 [downloaded] => 2008 [last_updated] => 2013-05-27 [added] => 2013-05-27 [homepage] => http://www.dreamsonline.net/wordpress-plugins/custom-favicon/ [sections] => Array ( [description] => Now easily upload a favicon and apple touch icon for your WordPress website and dashboard. Please report any bugs you find via http://www.dreamsonline.net/wordpress-plugins/custom-favicon/ My Links Twitter @harishchouhan Google+ Harish Chouhan If you love the plugin, please consider rating it and clicking on "it works" button. [installation] => Upload the directory /custom-favicon/ to the /wp-content/plugins/ directory Activate the plugin through the 'Plugins' menu in WordPress Click on "Custom Favicon" sub menu under the Settings menu and upload your favicon [changelog] => = 1.0.0 * This is the first version [faq] => Take a look at the official "Custom Favicon" FAQ. You can also visit the support center and start a discussion if needed. ) [download_link] => http://downloads.wordpress.org/plugin/custom-favicon.zip [tags] => Array ( [admin] => admin [apple-touch] => apple touch [apple-touch-icon] => apple touch icon [blog] => blog [favicon] => favicon [icon] => icon [iphone] => iphone [theme] => theme [upload] => upload [wordpress] => wordpress ) [donate_link] => http://www.dreamsonline.net )
If you just wanted to display the download count, you could add like this:
echo '<p>Downloaded: ' . print_r( $plugin_info->downloaded, true ) . ' times</p>';
Note: This is just a test example and not intended to be used in actual projects as there is no error checking. If the slug is wrong or the connection to WordPress.org does not take place, the above code will display errors.
We can continue extending this example with error checking but is there a better way? And the answer is yes, with the plugins_api
function.
The plugins_api
Function
The plugins_api
function is defined in wp-admin/includes/plugin_install.php.
<?php function plugins_api($action, $args = null) { if ( is_array($args) ) $args = (object)$args; if ( !isset($args->per_page) ) $args->per_page = 24; // Allows a plugin to override the WordPress.org API entirely. // Use the filter 'plugins_api_result' to merely add results. // Please ensure that a object is returned from the following filters. $args = apply_filters('plugins_api_args', $args, $action); $res = apply_filters('plugins_api', false, $action, $args); if ( false === $res ) { $url = 'http://api.wordpress.org/plugins/info/1.0/'; if ( wp_http_supports( array( 'ssl' ) ) ) $url = set_url_scheme( $url, 'https' ); $request = wp_remote_post( $url, array( 'timeout' => 15, 'body' => array( 'action' => $action, 'request' => serialize( $args ) ) ) ); if ( is_wp_error($request) ) { $res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() ); } else { $res = maybe_unserialize( wp_remote_retrieve_body( $request ) ); if ( ! is_object( $res ) && ! is_array( $res ) ) $res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) ); } } elseif ( !is_wp_error($res) ) { $res->external = true; } return apply_filters('plugins_api_result', $res, $action, $args); } ?>
Parameters
The plugins_api
function accepts 2 parameters: $action
and $args
:
1. The $action
Parameter
Which can be any one of these 3 options below:
query_plugins
plugin_information
hot_tags
2. The $args
Parameter
Arguments are optional, and if set, have to be a serialized object. Arguments for each action are different and are explained in detail later in this article.
Data Returned
The data returned depends on the action chosen. The action "plugin_information
" returns a single object whereas the other two actions return an array of objects. In case of an error such as the absence of an action or slug parameter, the plugin_api
function also returns an object with a single property "error" and a value (string) "Slug not provided" or "action not implemented".
An Example of Using plugins_api
Function
We will now try the same example we used earlier but using the plugins_api
function instead of wp_remote_post
from the HTTP API.
<?php /** Prepare our query */ $call_api = plugins_api( 'plugin_information', array( 'slug' => 'custom-favicon' ) ); /** Check for Errors & Display the results */ if ( is_wp_error( $call_api ) ) { echo '<pre>' . print_r( $call_api->get_error_message(), true ) . '</pre>'; } else { echo '<pre>' . print_r( $call_api, true ) . '</pre>'; if ( ! empty( $call_api->downloaded ) ) { echo '<p>Downloaded: ' . print_r( $call_api->downloaded, true ) . ' times.</p>'; } } ?>
The above code will return the data in the same way our previous example had. As you can see, this requires a few lines of code and a connection to the WordPress.org Plugin API, unserializing the returned object and initial error checking is all handled by the plugins_api
function.
In both the examples above, we only used the "plugin_information
" action and a slug with no other arguments as our intention was just to retrieve all possible information about our plugin.
2.1 Arguments for query_plugins
2.1.1. browse
It displays the list similar to http://wordpress.org/plugins/browse/popular/. The possible values are:
popular
new
updated
top-rated
2.1.2. search
The term to search for.
2.1.3. tag
Search plugins by a tag.
2.1.4. author
Search plugins from an author.
Note: Between browse
, search
, tag
and author
only one argument can be used at a time.
2.1.5. page
(optional)
The page number of the results.
2.1.6. per_page
(optional)
The number of results to display per page.
2.1.7. fields
(optional)
Similar to plugin_information
fields listed below.
Example of a query for the most popular plugins:
$call_api = plugins_api( 'query_plugins', array( 'browse' => 'top-rated', 'page' => '1', 'per_page' => '5', 'fields' => array( 'downloaded' => false, 'rating' => false, 'description' => false, 'short_description' => false, 'donate_link' => false, 'tags' => false, 'sections' => false, 'homepage' => false, 'added' => false, 'last_updated' => false, 'compatibility' => false, 'tested' => false, 'requires' => false, 'downloadlink' => true, ) ) );
Returns an array of objects similar to what plugin_information
returns.
2.2 Arguments for plugin_information
2.2.1. slug
The slug of the plugin for which we need to return information.
2.2.2. fields
(optional)
By default all the fields from the readme.txt are displayed along with some additional fields such as the total number of downloads, rating and download link. However if you only need to retrieve just a few fields you can override this by sending in an array of key / value pairs, where the field is the key and true / false as the value depending on whether you wish the field to be returned or not.
Example of overriding fields:
/** Prepare our query */ $call_api = plugins_api( 'plugin_information', array( 'slug' => 'custom-favicon', 'fields' => array( 'downloaded' => false, 'rating' => false, ) ) );
The fields that can be overridden are:
added
compatibility
-
downloadlink
(Note: that the actual key is "download_link
" but to not return this data, we need to set the field as “downloadlink”) donate_link
homepage
last_updated
rating
require
sections
tags
tested
2.3 Arguments for hot_tags
2.3.1. number
The number of tags to return. The default is 100.
hot_tags
action example:
/** Prepare our query */ $call_api = plugins_api( 'hot_tags', array( 'number' => '50', ) );
This will return an array of objects with the key being the tag slug and each object would contain:
- Tag Name
- Tag Slug
- Count - The Number of plugins marked with this tag
Summary
Internally WordPress core uses the plugins_api
function to display a list of plugins based on the keyword used for search, to retrieve your favorite plugins and also to display information about any specific plugin. By changing the action parameter, you can use the function to perform different tasks.
Information about the WordPress.org API is not widely available and the reason could possibly be to avoid abuse of the system, hence make sure your requests to WordPress.org API are limited and done in the right way. Use Transients to cache the data so you do not have to make a request on every page load.
In a future tutorial we will create a plugin with a shortcode to display your plugin download count.
Comments