Restricting xmlrpc.php

Earlier today, I saw some spikes on the load graph for the new server (where this site is hosted).

Upon checking the logs I saw a lot of these: - - [01/May/2020:12:21:54 +0000] "POST //xmlrpc.php HTTP/1.1" 200 264 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" - - [01/May/2020:12:21:55 +0000] "POST //xmlrpc.php HTTP/1.1" 200 264 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" - - [01/May/2020:13:44:24 +0000] "POST //xmlrpc.php HTTP/1.1" 200 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" - - [01/May/2020:13:44:25 +0000] "POST //xmlrpc.php HTTP/1.1" 200 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"

I’m not mentioning the source IP owner, technical readers can look it up if they are interested. However, the second IP comes from a IP range that is rather interesting.

Searching the Internet, I found out that many people consider the xmlrpc.php as a problem. For those who are not familiar with WordPress, this file is responsible for external communications. For example when using the mobile application to manage your site, and also when you use Jetpack.

There are plugins to disable XML-RPC such as this one, but I use the app from time to time, so I would like to keep xmlrpc.php working.

The official Jetpack website provides this list for whitelisting purposes.

I have been restricting access to my /wp-admin URL for ages, using Nginx. I think it is a good idea to do the same for xmlrpc.php.

location ~ ^/(xmlrpc\.php$) {
    include conf.d/includes/jetpack-ipvs-v4.conf;
    deny all;
    include fastcgi.conf;
    fastcgi_intercept_errors on;
    fastcgi_pass php;

The simple script to update this IP list into Nginx configuration, that is consumed by the configuration above:

wget -q -O /tmp/ips-v4.txt
if [ -s /tmp/ips-v4.txt ]; then
  cat /tmp/ips-v4.txt | awk {'print "allow "$1";"'} > /tmp/${FILENAME}
  [ -s ${CONF_FILE} ] || touch ${CONF_FILE}
  if [ "$(diff /tmp/${FILENAME} ${CONF_FILE})" != "" ]; then
    echo "Files different, replacing ${CONF_FILE} and reloading nginx"
    mv -fv /tmp/${FILENAME} ${CONF_FILE}
    systemctl reload nginx
    echo "File /tmp/${FILENAME} match ${CONF_FILE}, not doing anything"
rm -f /tmp/ips-v4.txt

It can be periodically executed by cron so that when the IP list changes, the configuration gets updated.

Now, if any IP other than Jetpack tries to access /xmlrpc.php it will receive Error 403 Forbidden.

Have fun!

WordPress Update: Upgrade package not available (3.5)

I used to upgrade WordPress manually using FTP. I would update a local copy of the website, make sure everything works on my laptop and then upload it to the server. Not that I don’t trust WordPress automatic upgrade but I am paranoid that my custom plugins and changes will break the site.

However, starting from early 2012 I began to use the upgrade functionality within WordPress. Everything went really well until after I upgraded to 3.5

I wasn’t able to upgrade to 3.5.1 but I was able to upgrade another blog with earlier version than 3.5 to 3.5.1. So I thought it might be a problem with the settings or permissions on this site.


Today, I looked at the issue again. What I found is that there is a discrepancy between the upgrade code and the data returned by API.

The code failed here wp-admin/includes/class-wp-upgrader.php:

111   function download_package($package) {
116     if ( empty($package) )
117       return new WP_Error('no_package', $this->strings['no_package']);
127   }

Called within the same file:

878     $download = $this->download_package( $current->package );
879     if ( is_wp_error($download) )
880       return $download;

There are a lot more tracing done, but ultimately line 878 will always fail because $current does not have the property package:

stdClass Object
    [response] => upgrade
    [download] =>
    [locale] => en_US
    [packages] => stdClass Object
            [full] =>
            [no_content] =>
            [new_bundled] =>
            [partial] => 
    [current] => 3.6
    [php_version] => 5.2.4
    [mysql_version] => 5.0
    [new_bundled] => 3.6
    [partial_version] => 
    [dismissed] => 

I wanted to create a Trac ticket but realized that this should have been fixed, and this is a backward compatible issue anyway. Looking at the new code I am able to see that the packages properties has been handled.

A quick look at 3.5.1 also suggests that the new data returned has been handled correctly.

   1036     // If partial update is returned from the API, use that, unless we're doing a reinstall.
   1037     // If we cross the new_bundled version number, then use the new_bundled zip.
   1038     // Don't though if the constant is set to skip bundled items.
   1039     // If the API returns a no_content zip, go with it. Finally, default to the full zip.
   1040     if ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version )
   1041       $to_download = 'partial';
   1042     elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '< ' )
   1043       && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) )
   1044       $to_download = 'new_bundled';
   1045     elseif ( $current->packages->no_content )
   1046       $to_download = 'no_content';
   1047     else
   1048       $to_download = 'full';
   1050     $download = $this->download_package( $current->packages->$to_download );
   1051     if ( is_wp_error($download) )
   1052       return $download;

My quick and dirty hack is to edit wp-admin/includes/class-wp-upgrader.php

    878     $download = $this->download_package( '' );

Just like that, and upgrade was quick. If you’re stuck in 3.5 you can try it out.


Happy 10th Anniversary WordPress!

Today marks the 10th anniversary of WordPress which was first released on May 27th, 2003.

WordPress now powers countless number of blogs in the Internet via the community driven project and the hosted solutions at

This site has been running on WordPress since the beginning, in 2005.

Being sick today, I will not be able to make it to any meetups 🙁

Happy 10th Anniversary, WordPress!

WordPress 3.1 Upgrade

I am not going to announce or talk about the release of WordPress 3.1 as I know that most people already know it was released on 23 February 2011. I am also not going to talk about the features.

I would like to share problems that I encountered and how to fix them. Well, I only had 2 problems so far. These are not encountered while upgrading this blog you’re reading.

The first was the problem with no post on the main page. Depending on your theme, it might say, “Sorry no post matching your criteria”. Just after an upgrade, it’s scary to think that all posts are gone. But yeah I still have my backup.

Before you blame WordPress and jump to Blogger or such, you need to check whether you have disabled all of your plugins. Most often plugins are the reason errors occur after an upgrade. In each release, API and functions changes and while WordPress developers try to avoid backward compatibility issues, some of them are just inevitable.

The culprit for my problem was a sticky post plugin. In haste, I deleted all traces of the plugin on the server and in my local disk. Additionally I was working on another machine so I can’t recall the name of that plugin right now.

This was an upgrade from version 2.6. I heard that an upgrade from 2.6 to 2.7 will also produce the same problem by this plugin.

Sometimes, people do get totally blank page. The smartest thing to do is to enable WP_DEBUG in wp-config.php

define('WP_DEBUG', true);

While this line is not available in pre-3, it’ll work if you add it.

It’s also beneficial for the plugin issue I mentioned above. That’s how I found out that there’s a SQL error produced by that plugin.

The next problem I encountered was related to the database version. This might be published somewhere in WordPress documentation but I failed to find it. WordPress 3.1 requires MySQL 4.1.2 and above.

This was a manual upgrade from WordPress 2.8.4 via FTP. The good thing is that the public facing site was still working fine. I was just unable to access the administration dashboard.

By the way, my hosting provider has dedicated database servers with MySQL 4.0 – 5.0 options. 4.0 has been obsolete and this particular blog being upgraded was the only one using 4.0. So all I had to do was:

  • Create a new database in the 5.0 server
  • Export from 4.0 into a SQL file
  • Import into 5.0
  • Run the normal database upgrade screen

And everything was hunky-dory. It’s interesting to see that there are less total rows, and the addition of wp_commentmeta table:

Database for 2.8.4

Database for 3.1

If you are on normal cheap hosting with MySQL on the web server itself, you’re out of luck if the server only has MySQL 4.0. It’s time to move away.

So that’s it. Since there are a few more blogs in the upgrade process I might add more findings in this post as I come across them.

WordPress Plugin: Basic Facebook Social Plugins

Today, I saw that Facebook introduced some new features, and one intriguing feature is called “Facebook Social Plugin“. It would be very interesting to have blog posts to be simply “liked”, and having information displayed about activities and recommendations related to your website.

So I decided to take 30 minutes of my break time and write this simple plugin. Since I don’t have much time I decided not to explore XFBML and the SDK as yet. That is why it’s called BASIC. With XFBML, shorter codes can be used, and deeper integration between Facebook and your website can be achieved. I am intrigued, really but I must be realistic.

This plugin is a very simple plugin to embed :

  1. “like” button at the end of your articles/blog posts
  2. activity feed as a widget
  3. recommendations as a widget
  4. Like box as a widget

You can add these cool features with minimal effort.

Most configuration parameters are self-explanatory, but Domain Override simply means you want to display information about another domain instead of where the widgets are hosted. By the way, the widget settings are combined in the Settings > Basic Facebook Social Plugins page.

At this moment this plugin is still waiting to be hosted at the official WordPress Plugin Directory so it can only be downloaded here.

  • Basic Facebook Social Plugins Version 1.0
  • Basic Facebook Social Plugins Version 1.1 * This version will wipe out previous widget settings as it introduces multiple instances of widgets.
  • Basic Facebook Social Plugins Version 1.2

Once available there, a link will be provided. When it’s there, It’s now in the official plugin directory (basic-facebook-social-plugins) so you should be able to install it using the automated, built-in plugin installer too.

You can see the sample for the like button at the end of this post, and the widgets live on this site.

The widgets does not conform to your theme (does not inherit your theme css) but simply bare boxes with Facebook feel. Take note that styling inside the boxes (and texts) are provided by facebook.

Those of you who are concerned about privacy, you’ll be glad to know that your name and profile picture will not just be displayed to anyone:


(This also applies to recommendation and activity box. Only friends will be able to see that you like something.) Facebook has thought of everything.

Try it out and let me know how it works for you.

Shots from Facebook:



Facebook has also written a nice post about social plugins in their blog: Answers to Your Questions on Personalized Web Tools.


  1. This WordPress plugin is written entirely by me, and is provided as-is with no guarantee. It is neither approved nor endorsed by Facebook.
  2. Yes, it is breakable by Facebook if they decide to change the iframe URL.

Adding More Sidebars to WordPress Themes

WordPress keeps being updated but your themes rarely change unless you’re a theme developer. I wanted to add a leaderboard but I was delaying because I am too lazy to add any custom code to my theme. Silly me I forgot that I have already added an extra “sidebar” when I developed the theme for this website. So all I had to do was paste my code to a text widget and save.

I know we are actually misusing the sidebar via the “dynamic_sidebar” and “register_sidebar” API. It’s fairly straightforward but you do need to have a sense of position in your layout (you need to know where the leaderboard needs to appear).

First we add the sidebar in the /wp-content/THEME/functions.php:

	'name' => 'Leaderboard',
	'before_widget' => '<div align="center">',
	'before_title' => '',
	'after_title' => '',
	'after_widget' => '</div>',

I think the options are self-explanatory but if you’re confused do ask. One important thing for me is the name – it will be displayed in the widget control panel so it would help to use a descriptive name.

The next file(s) to be edited depends on where you want the new “sidebar” to be located and how the theme are made. A simple standard is that if you want it to be included in all page you just edit /wp-content/THEME/header.php


Normally these are the file name convention used by theme developers:

  1. page.php – pages
  2. single.php – single posts
  3. search.php – search results
  4. index.php – the main page


Blogging Frenzy

There is an interesting development at my current office where people are starting to create their own, self-hosted WordPress installations. This is a very good culture! And all this thanks to Mr Rizal, the blogging evangelist (or should I say WordPress evangelist?).

I hope he’s not just doing this because he’s leaving us soon! Sob, sob!

Bravo you guys, keep up the good work. When you are ready just let me know, I still have space in my blogroll. Or, do I?

Subscribe To Comments

I am a blogger. (What a stupid statement when writing a blog post). Anyway, I just wish everyone could install the Subscribe To Comments plugin so that I will know when they (or anyone for that matter) responds to my comments.

Today I have to remember which blog post I posted my comments on and wait for it to load. Yes I know I am just being lazy.

Trust me, it helps your reader. And for what it’s worth loyal visitors will still need to load the post page to see your respond. That is traffic for sure.

The best thing of all is that it is virtually maintenance free. You can manage it if you need to but from my experience using it for more than a year I don’t need to do anything.

I would also like to ask that visitors to this blog tick the subscribe checkbox if they are asking questions. It’s much more convenient plus you’ll know when I respond. Unsubscribe link is always provided in the emails you will receive.

Happy WordPressing.

Compressing WordPress Output

While toying around with NextGen code so that I can activate my custom image mirror, I saw the output from Firebug. I noticed that my HTML output is not compressed (by the absence of gzip content-encoding).

Some Apache servers have this module already enabled (previously mod_gzip a 3rd party module in Apache 1, and now built-in in Apache 2 as mod_deflate).

But what if you don’t have access to the Apache configuration, such as in a shared hosting environment?

I have the answer for PHP. I always include this line in the bootstrap code of the applications I build using Zend Framework:


And the output will be gzipped prior to sending it to the browser. The result? Faster transfer to users.

For WordPress you can put the line in index.php:

< ?php ob_start("ob_gzhandler"); /* Short and sweet */ define('WP_USE_THEMES', true); require('./wp-blog-header.php'); ?>

Easy, isn’t it? Here are Firebug screenshots, before and after. Notice that I managed to cut the size of my front page by 1/5?

[As the screenshots are too wide please click on Continue Reading to see them]
Continue reading Compressing WordPress Output

WordPress 2.3 Plugin Compatibility

As everyone might have realized by now, WordPress 2.3 has been released. WordPress 2.3 contains many improvements mentioned in the release page, and one of the most critical change is to the database structure where several database has been removed and added. Relations are all different now, so plugin authors: check your plugins!

What I like is the Plugins/Plugin Compatibility/2.3 page in WordPress Codex. The list is by no means complete, but it’s a good start for you to see if the plugins you are using are effected by changes in 2.3.

My two plugins (Random Posts Widget and Collapsible Archive Widget) were also affected by the change, since I couldn’t find the suitable WordPress function to use for some of the things I needed to do. However I’ve fixed them to be compatible with 2.3 while maintaining backward compatibility to the 2.2.x series.

Please be careful when you download a plugin next time, and see the “Requires WordPress Version” and “Compatible up to” fields.

As for me, since I use a lot of custom plugins and also homemade ones, I’ll need to find the right time to upgrade 😉

WordPress Plugin: Collapsible Archive Widget

Update: 20 January 2010: This plugin has not been tested with WordPress 2.9 and may break because 2.9 has internal changes. I am still trying to find time. Sorry for the Inconvenience.

I have written another simple WordPress plugin that simply display a collapsible archive in the sidebar. You can see it in action in the rightmost sidebar of the main page.

When the sidebar loads, it is in collapsed state and can be expanded by clicking the years. It utilizes simple JavaScript that shows and hides a div containing the monthly links. The purpose of this plugin is to save space on the sidebar especially if you have been blogging for a while. It is an alternative to the combo box (select) provided by the default archive widget.

My request for the plugin to be listed in the WordPress Plugin Directory has been pending for a while so for now it can be downloaded here.

The plugin can now be downloaded here.


  • Widget Title: the title of the widget
  • Show post counts for year: Whether or not to show the post number for each year
  • Show post counts for month: Whether or not to show the post number for each month
  • Abbreviate month names: Check this box to show abbreviation of month names
  • Hide year from month names: Do not print year after month names
  • Use effects: Whether or not to show effects
  • Expand effect: Effect to use when expanding the list
  • Collapse effect: Effect to use when collapsing the list
  • Expand the list by default: Check this box to have the list expanded when loaded
  • Expand current year by default: Check this box to have the current year expanded when loaded
  • Expand current month by default: Check this box to have the current month expanded when loaded
  • Show individual posts: Show posts in the list. This should be used in extra caution; if you have a lot of posts consider disabling it as this will take time to load
  • Use HTML arrows instead of images (► ▼)
  • Show current month in bold: show current month in bold
  • Show a link to plugin page. Thank you for your support! : Display a link to plugin page (this page) as a support method

Current Version: 2.3.1


Copy the file to the wp-content/plugins/widgets directory and activate it in the Plugins page. Then drag and configure it in the Sidebar Widgets page.

Warning: Will only work on widgets enabled blogs.

TODO (these are being considered but there is no guarantee when they are going to be included)

  • Add ability for multiple instances
  • Add ability to work as non-widget
  • Add ability to include / exclude categories
  • Expand previous month rather the current
  • Research the practicality to use CSS / allow CSS options
  • List posts without year and month headers (for blogs with few posts)
  • Do not list the posts that are listed on the main page

Change Log

  • 03-Aug-2007: Initial version
  • 04-Sep-2007: Added ability to select whether to use abbreviations for the month names, and effects!
  • 27-Sep-2007: Fixed javascript include – effects.js added and scriptaculous.js removed (For some reason it worked in 2.2)
  • 10-Nov-2007: Added ability to display posts (with caution), to expand by default, and also added plus and minus signs as expand/collapse buttons
  • 24-Aug-2008: Multiple updates:
    • Enqueue javascripts using WordPress API wp_enqueue_script
    • Validation as XHTML 1.0 Transitional
    • Add option to expand current year and/or month by default
    • REMOVED list type option
    • Added ability to upload own plus and minus images
    • Added ability to display plugin link. If you’d like to support this plugin, having the “powered by” on your blog is the best way; it’s our only promotion or advertising.
  • 25-Aug-2008: Bugfix to not load javascripts when effects is not used
  • 25-Aug-2008: Javascript code factoring and added ability to use HTML arrows
  • 16-Mar-2009: Separated year and month posts counts, added option to hide year after month names, ability to show current month in bold, enabled localized title
  • 17-Mar-2009: Fixed valid XHTML, and highlight (bold) bugfix


The ability to display posts is provided after receiving so many requests for it. This feature is not practical for those with many posts in a month. Enabling it means that there is a lot more data that needs to be received by the browser, not to mention the load on the database. It is, however works very nice for blogs with low post count. Please use at your own risk and remember to test it.


11-Nov-2007: I’d like to thank Meitar Moscovitz who tried his best to provide a patch to display posts in the list. I rewritten some of the code for version 2.1 based on his logic. Thank you!
25-Aug-2008: Thanks to Berny for his idea of re factoring the javascript code and also for providing HTML arrows option.

If you find this plugin useful, feel free to

I Want WordPress Red T-Shirt!

WordPress Red T-Shirt

How cool is this! WordPress Shop is now selling WordPress red t-shirt worldwide. It’s gonna cost about RM100.00 including shipping for Malaysians. For the rest of the world, the t-shirt costs £9.50 and delivery is £4.50 but if you share with friends the delivery cost would be (£4.00 x Quantity) + X where X is between £0.50 – £0.10 according to my calculations 😉

The t-shirt is of high-quality made by American Apparel. I have to order it soon before the stock is finished!

Have you ordered yours?

WordCamp 2007

So the next weekend I will be flying to San Francisco to attend WordCamp 2007 on 21-22 July. This event is a 2-day conference for WordPress users and developers. The first day will focus on how to be a better blogger, the second on the development and future of WordPress.

Yeah right! Did you believe me? I am sorry I was really imagining how cool will it be if I can attend the event. Maybe next year. 😀

The actual event I will be attending during 21-22 July is my company’s team building activity in Pulau Pangkor, Malaysia. It will be fun (trying to console my own self).

WordPress 2.2.1 Upgrade

I have just finished upgrading this blog and 6 others maintained (not owned) by me. The transition from 2.2 to 2.2.1 is generally very smooth, as there’s no database changes involved. I simply uploaded only the changed files as listed here.

I am rushed to upgrade to 2.2.1 since there is a lot of security bugs in 2.2, and seeing some blogs have been brutally cracked, I promised myself to steal some time to upgrade during this weekend. A very recent attack was on, a full time blogger in Malaysia.

So please don’t wait, upgrade immediately!

Other than that, notice anything else missing from this blog?