CSTLdesign News

Communicating With the WordPress.org Plugin API

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:92:"<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:34352:"<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:

  1. Post Action – such as, $_POST['action']
  2. 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&#8217;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&#8217;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);
} ?>


The plugins_api function accepts 2 parameters: $action and $args:

1. The $action Parameter

Which can be any one of these 3 options below:

  1. query_plugins
  2. plugin_information
  3. 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


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.