WordPress performance has become incredibly important these days. Google has devoted an engineering team for WordPress performance development! Knowing which code is slowing your site down can help boost visitor retention and improve conversion rates for WooCommerce. XHProf is an amazing tool that can help you identify bottlenecks in your WordPress code. This took me several days of frustration to get Tideways XHProf and XHGUI working with PHP 7.x, shout out to Derrick Hammer (github) for assisting with getting this working smoothly!
WordPress and WooCommerce are quite the maze of actions, filters, PHP functions and objects. XHProf with XHGui helps you navigate these to help identify bottlenecks and suboptimal coding logic.
My hope is that this tutorial will get you up and running with profiling your WordPress PHP code quickly and without too much headache on Debian and Ubuntu systems!
If you’d like to get personalized, tailored support for getting Tideways XHProf set up please get in touch with me on Codeable or via my contact form.
If you are looking for a VPS to install XHProf on with your WordPress site, try Vultr or Digital Ocean.
These services all make it relatively easy to install WordPress on a VPS so you have an installation in which to install XHProf and XHGui.
You will need SSH access to complete this tutorial with root or sudo privileges!
Install XHProf PHP Extension
Install git
and graphviz
(for the XHGui graphs or they will not display)
sudo apt-get update
sudo apt-get install git graphviz -y
I have divided the rest of this section into the different PHP versions.
PHP 7.0
Install the PHP development package for 7.0
sudo apt-get install php7.0-dev -y
Build XHProf
cd /tmp
git clone https://github.com/tideways/php-xhprof-extension
cd php-xhprof-extension
phpize
./configure
make
sudo make install
Enable the PHP XHProf extension for PHP 7.0.
For nginx with php7.0-fpm, create the tideways-xhprof.ini file
sudo nano /etc/php/7.0/mods-available/tideways-xhprof.ini
Add this extension line
[tideways-xhprof-7.0]
extension=tideways_xhprof.so
Ctrl+X, Y and Enter to Save and exit.
Symbolically link the tideways-xhprof.ini – this way it can be easily disabled
sudo ln -s /etc/php/7.0/mods-available/tideways-xhprof.ini /etc/php/7.0/fpm/conf.d/tideways-xhprof.ini
sudo ln -s /etc/php/7.0/mods-available/tideways-xhprof.ini /etc/php/7.0/cli/conf.d/tideways-xhprof.ini
Then restart php7.0-fpm
sudo service php7.0-fpm restart
For Apache2 create the symlink to the apache2/conf.d
folder
sudo ln -s /etc/php/7.0/mods-available/tideways-xhprof.ini /etc/php/7.0/apache2/conf.d/30-tidways-xhprof.ini
Then reload Apache
sudo service apache2 reload
Now you can jump down to Installing XHGui
PHP 7.1
Install the PHP development package for 7.1
sudo apt-get install php7.1-dev -y
Build XHProf
cd /tmp
git clone https://github.com/tideways/php-xhprof-extension
cd php-xhprof-extension
phpize
./configure
make
sudo make install
Enable the PHP XHProf extension for PHP 7.1
For nginx with php7.1-fpm, create the tideways-xhprof.ini file
sudo nano /etc/php/7.1/mods-available/tideways-xhprof.ini
Add this extension line
[tideways-xhprof-7.1]
extension=tideways_xhprof.so
Ctrl+X, Y and Enter to Save and exit.
Symbolically link the tideways-xhprof.ini – this way it can be easily disabled
sudo ln -s /etc/php/7.1/mods-available/tideways-xhprof.ini /etc/php/7.1/fpm/conf.d/tideways-xhprof.ini
sudo ln -s /etc/php/7.1/mods-available/tideways-xhprof.ini /etc/php/7.1/cli/conf.d/tideways-xhprof.ini
Then restart php7.1-fpm
sudo service php7.1-fpm restart
For Apache2 create the symlink to the apache2/conf.d
folder
sudo ln -s /etc/php/7.1/mods-available/tideways-xhprof.ini /etc/php/7.1/apache2/conf.d/30-tidways-xhprof.ini
Then reload Apache
sudo service apache2 reload
Now you can jump down to Installing XHGui
PHP 7.2
Install the PHP development package for 7.2
sudo apt-get install php7.2-dev -y
Build XHPRof
cd /tmp
git clone https://github.com/tideways/php-xhprof-extension
cd php-xhprof-extension
phpize
./configure
make
sudo make install
For nginx with php7.2-fpm, create the tideways-xhprof.ini file
sudo nano /etc/php/7.2/mods-available/tideways-xhprof.ini
Add this extension line
[tideways-xhprof-7.2]
extension=tideways_xhprof.so
Ctrl+X, Y and Enter to Save and exit.
Symbolically link the tideways-xhprof.ini – this way it can be easily disabled
sudo ln -s /etc/php/7.2/mods-available/tideways-xhprof.ini /etc/php/7.2/fpm/conf.d/tideways-xhprof.ini
sudo ln -s /etc/php/7.2/mods-available/tideways-xhprof.ini /etc/php/7.2/cli/conf.d/tideways-xhprof.ini
Then restart php7.2-fpm
sudo service php7.2-fpm restart
For Apache2 create the symlink to the apache2/conf.d
folder
sudo ln -s /etc/php/7.2/mods-available/tideways-xhprof.ini /etc/php/7.2/apache2/conf.d/30-tidways-xhprof.ini
Then reload Apache
sudo service apache2 reload
XHGUI for XHProf with PHP 7.x
You need to make sure some MySQL database server is installed and the PHP extension for interacting with it. Adjust the php-7.0-mysqli
below for your version of PHP.
sudo apt-get install mariadb-server mariadb-client php7.0-mysqli -y
Create the MySQL user, password and database for XHGui’s database
mysql -u root
These credentials will be used for the MySQL database XHGui needs in the xhprof/xhprof_lib/config.php
file.
CREATE USER xhprofuser@localhost IDENTIFIED BY 'passw0rd';
CREATE DATABASE xhprof;
GRANT ALL PRIVILEGES ON xhprof.* TO xhprofuser@localhost IDENTIFIED BY 'passw0rd';
FLUSH PRIVILEGES;
quit;
Make sure these PHP extensions are installed already
sudo apt-get install php7.0-mysqli php7.0-json -y
Enter your WordPress folder and use git to clone XHProf (replace the path /var/ww/sitename
with your actual site path)
cd /var/www/sitename
git clone https://github.com/preinheimer/xhprof.git
Enter the xhprof_lib folder to modify the configuration files
cd xhprof/xhprof_lib
nano config.php
To make this easier, you can copy the entire XHGui config.php
and paste it :).
xhprofuser
is the MySQL user created earlier
passw0rd
is the MySQL password
xhprof
is the MySQL database
Change http://guides.wp-bullet.com
to your site’s URL (the siteurl
row in the option_name
column in the wp_options
table which should match your nginx or Apache server_name
variable).
<?php
$_xhprof = array();
// Change these:
$_xhprof['dbtype'] = 'mysql'; // Only relevant for PDO
$_xhprof['dbhost'] = 'localhost';
$_xhprof['dbuser'] = 'xhprofuser';
$_xhprof['dbpass'] = 'passw0rd';
$_xhprof['dbname'] = 'xhprof';
$_xhprof['dbadapter'] = 'Mysqli';
$_xhprof['servername'] = 'wpb';
$_xhprof['server name'] = 'wpb';
$_xhprof['namespace'] = 'wpb';
$_xhprof['url'] = 'http://guides.wp-bullet.com/xhprof/xhprof_html';
$_xhprof['getparam'] = "_profile";
/*
* MySQL/MySQLi/PDO ONLY
* Switch to JSON for better performance and support for larger profiler data sets.
* WARNING: Will break with existing profile data, you will need to TRUNCATE the profile data table.
*/
$_xhprof['serializer'] = 'php';
//Uncomment one of these, platform dependent. You may need to tune for your specific environment, but they're worth a try
//These are good for Windows
/*
$_xhprof['dot_binary'] = 'C:\\Programme\\Graphviz\\bin\\dot.exe';
$_xhprof['dot_tempdir'] = 'C:\\WINDOWS\\Temp';
$_xhprof['dot_errfile'] = 'C:\\WINDOWS\\Temp\\xh_dot.err';
*/
//These are good for linux and its derivatives.
$_xhprof['dot_binary'] = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';
$ignoreURLs = array();
// Do not track URIs containing xhprof
$ignoreURLs[] = "/xhprof/";
$ignoreDomains = array();
$exceptionURLs = array();
$ignoreDomains = array();
$exceptionURLs = array();
$exceptionPostURLs = array();
$exceptionPostURLs[] = "login";
$_xhprof['display'] = false;
$_xhprof['doprofile'] = false;
//Control IPs allow you to specify which IPs will be permitted to control when profiling is on or off within your application, and view the results via the UI.
$controlIPs = false; //Disables access controls completely.
//$controlIPs = array();
//$controlIPs[] = "127.0.0.1"; // localhost, you'll want to add your own ip here
//$controlIPs[] = "::1"; // localhost IP v6
//$otherURLS = array();
// ignore builtin functions and call_user_func* during profiling
//$ignoredFunctions = array('call_user_func', 'call_user_func_array', 'socket_select');
//Default weight - can be overidden by an Apache environment variable 'xhprof_weight' for domain-specific values
$weight = 100;
if($domain_weight = getenv('xhprof_weight')) {
$weight = $domain_weight;
}
unset($domain_weight);
/**
* The goal of this function is to accept the URL for a resource, and return a "simplified" version
* thereof. Similar URLs should become identical. Consider:
* http://example.org/stories.php?id=2323
* http://example.org/stories.php?id=2324
* Under most setups these two URLs, while unique, will have an identical execution path, thus it's
* worthwhile to consider them as identical. The script will store both the original URL and the
* Simplified URL for display and comparison purposes. A good simplified URL would be:
* http://example.org/stories.php?id=
*
* @param string $url The URL to be simplified
* @return string The simplified URL
*/
function _urlSimilartor($url)
{
//This is an example
$url = preg_replace("!\d{4}!", "", $url);
// For domain-specific configuration, you can use Apache setEnv xhprof_urlSimilartor_include [some_php_file]
if($similartorinclude = getenv('xhprof_urlSimilartor_include')) {
require_once($similartorinclude);
}
$url = preg_replace("![?&]_profile=\d!", "", $url);
return $url;
}
function _aggregateCalls($calls, $rules = null)
{
$rules = array(
'Loading' => 'load::',
'mysql' => 'mysql_'
);
// For domain-specific configuration, you can use Apache setEnv xhprof_aggregateCalls_include [some_php_file]
if(isset($run_details['aggregateCalls_include']) && strlen($run_details['aggregateCalls_include']) > 1)
{
require_once($run_details['aggregateCalls_include']);
}
$addIns = array();
foreach($calls as $index => $call)
{
foreach($rules as $rule => $search)
{
if (strpos($call['fn'], $search) !== false)
{
if (isset($addIns[$search]))
{
unset($call['fn']);
foreach($call as $k => $v)
{
$addIns[$search][$k] += $v;
}
}else
{
$call['fn'] = $rule;
$addIns[$search] = $call;
}
unset($calls[$index]); //Remove it from the listing
break; //We don't need to run any more rules on this
}else
{
//echo "nomatch for $search in {$call['fn']}<br />\n";
}
}
}
return array_merge($addIns, $calls);
}
Now we need to modify the XHProf header file or it will not work, change sitepath
to your WordPress installation so you can open the header.php
file.
nano /var/www/sitepath/xhprof/external/header.php
Change these instances from tideways
to tideways_xhprof
function getExtensionName()
{
if (extension_loaded('tideways'))
{
return 'tideways';
}elseif(extension_loaded('xhprof')) {
return 'xhprof';
}
return false;
}
so it should look like this with all instances changed to tideways_xhprof
function getExtensionName()
{
if (extension_loaded('tideways_xhprof'))
{
return 'tideways_xhprof';
}elseif(extension_loaded('xhprof')) {
return 'xhprof';
}
return false;
}
Ctrl+X, Y and Enter to Save and Exit.
Add the MySQL Schema for the XHGUI details table or there will be no XHProf runs stored!
Start by creating an empty file
nano /tmp/xhgui-details.sql
Paste this MySQL schema for XHGui
CREATE TABLE `details`
(
`id` CHAR(17) NOT NULL,
`url` VARCHAR(255) DEFAULT NULL,
`c_url` VARCHAR(255) DEFAULT NULL,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on
UPDATE CURRENT_TIMESTAMP,
`server name` VARCHAR(64) DEFAULT NULL,
`perfdata` MEDIUMBLOB,
`type` TINYINT(4) DEFAULT NULL,
`cookie` BLOB,
`post` BLOB,
`get` BLOB,
`pmu` INT(11) UNSIGNED DEFAULT NULL,
`wt` INT(11) UNSIGNED DEFAULT NULL,
`cpu` INT(11) UNSIGNED DEFAULT NULL,
`server_id` CHAR(3) NOT NULL DEFAULT 't11',
`aggregatecalls_include` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `url` (`url`),
KEY `c_url` (`c_url`),
KEY `cpu` (`cpu`),
KEY `wt` (`wt`),
KEY `pmu` (`pmu`),
KEY `timestamp` (`timestamp`)
)
engine=myisam DEFAULT charset=utf8;
Ctrl+X, Y and Enter to Save and Exit.
You can import the XHGui MySQL scheme with this command, please change xhprof
if you chose a different database name
mysql -u root xhprof < /tmp/xhgui-details.sql
Almost there!
Adding XHProf header.php to WordPress
XHProf’s PHP code needs to be added to WordPress so it can start monitoring, enter your WordPress directory
cd /var/www/guides.wp-bullet.com
Create a drop-in PHP .user.ini
file
nano .user.ini
Paste this text, change your site’s path (here guides.wp-bullet.com
)
auto_prepend_file="/var/www/guides.wp-bullet.com/xhprof/external/header.php";
Ctrl+X, Y and Enter to Save and Exit
You will see a debug footer at the bottom of pages eventually after you enable profiling by appending the ?_profile=1
query string later in this guide.
nginx vhost
If you do not want to use .user.ini
to prepend the header, we can prepend the XHProf code directly using nginx with the code below
server {
listen 80;
server_name default;
# root directive should be global
root /var/www/xhgui/;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# add xhprof header.php
fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/guides.wp-bullet.com/xhprof/external/header.php";
# old version before header.php included footer.php
# fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/xhprof/external/header.php \n auto_append_file=/var/www/xhprof/external/footer.php";
}
}
Thanks to Justin Carmony for the above method.
Using XHGUI and XHProf
This section has two components.
First you will learn how to enable XHProf’s monitoring.
Afterwards you will see how to use it in the browser.
Making XHGUI and XHProf Active
XHGui requires a query string to enable it, simply tack on ?_profile=1
to your URL like e.g. https://guides.wp-bullet.com/?_profile=1 which sets the cookie
Then to disable XHProf monitoring you append the /?_profile=0
query string to your site’s URL e.g. https://guides.wp-bullet.com/?_profile=0
Using XHGUI and XHProf in the Browser
Client new Product Bundles plugin was the problem but it is essential to the business. New Relic was running but because the process never executed there was no useful data, in comes XHProf and XHGui!
Reducing these values during debugging can save you significant amounts of waiting time when troubleshooting!
Protip: Turn max_execution_time = 30
and max_input_time=30
to make sure any infinite loops don’t get to run for too long causing gateway timeouts. If you are experiencing 504 Gateway timeout errors on your slow WordPress or WooCommerce site, then I highly recommend changing these when running XHProf.
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
; Maximum execution time of each script, in seconds
; http://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
max_execution_time = 30
; Maximum amount of time each script may spend parsing request data. It's a good
; idea to limit this time on productions servers in order to eliminate unexpectedly
; long running scripts.
; Note: This directive is hardcoded to -1 for the CLI SAPI
; Default Value: -1 (Unlimited)
; Development Value: 60 (60 seconds)
; Production Value: 60 (60 seconds)
; http://php.net/max-input-time
max_input_time = 30
Make sure to restart php-fpm or Apache after making the php.ini modifications.
Demonstration
I had a client with a products table that wasn’t loading, disabling all plugins didn’t help which meant the issue likely was in the child theme’s code. There were over 5000 lines in their functions.php so I wanted to avoid reading it all if possible.
I found this WC_Product_Bundle call taking way too long, over 20 seconds! I tracke dthis down to the Product Bundles plugin from WooCommerce.
Before 20.513482 seconds!
After correcting the function in the child theme, the same function now only takes 187 milliseconds
Get in touch with me via the contact form if you’d like help getting xhprof configured to diagnose your slow WordPress or WooCoommerce site.
Troubleshooting Tideways xhprof and xhgui
If you see this error ‘Error producing callgraph, check /tmp/xh_dot.err ‘then install graphviz
sudo apt-get install git graphviz -y
If you see this error: ‘You do not have permission to view this page.’ then it’s the $controlIPs
you need to change, after you change this you have to do add the ?_profile=1
query string again. It could also be basic permission errors on your web server so make sure to correct those as well.
If you do not see new runs it can also be because ?_profile=1
hasn’t been used yet or there is some page caching enabled, disable page caching and/or log in to bypass the cache and force PHP to process rather than hitting the page cache.
Make sure to add the table schema or you won’t see any runs at all, you also will not see any runs if you did not put ?_profile=1
this problem can also be traced in the logs
PHP message: PHP Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /var/www/mcat.wpbullet.me/xhprof/xhprof_lib/utils /Db/Mysqli.php on line 57
PHP message: PHP Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /var/www/mcat.wpbullet.me/xhprof/xhprof_lib/utils /Db/Mysqli.php on line 57" while reading response header from upstream, client: 104.221.54.228, server: mcat.wpbullet.me, request: "GET /xhprof/xhprof_html /? HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.2-fpm.sock:", host: "mcat.wpbullet.me", referrer: "https://mcat.wpbullet.me/xhprof/xhprof_html/?last= 25"
2018/03/17 17:40:14 [error] 17773#17773: *137 FastCGI sent in stderr: "PHP message: PHP Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_res ult, boolean given in /var/www/mcat.wpbullet.me/xhprof/xhprof_lib/utils/Db/Mysqli.php on line 57
PHP message: PHP Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /var/www/mcat.wpbullet.me/xhprof/xhprof_lib/utils /Db/Mysqli.php on line 57
PHP message: PHP Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /var/www/mcat.wpbullet.me/xhprof/xhprof_lib/utils /Db/Mysqli.php on line 57" while reading response header from upstream, client: 104.221.54.228, server: mcat.wpbullet.me, request: "GET /xhprof/xhprof_html /? HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "mcat.wpbullet.me", referrer: "https://mcat.wpbullet.me/xhprof/xhprof_html/?last= 25"
If you see ‘given XHProf isn’t found’ then see here for the CLI problem and if this php -i command doesn’t show xhprof then create the tideways-xhprof.ini file in the php-cli folder.
It could also be related to a miscopy of the SQL command for creating the schema for XHGui.
php -i | grep xhprof
/etc/php/7.2/cli/conf.d/tideways-xhprof.ini
tideways_xhprof
The 'tideways_xhprof' extension provides a subset of the functionality of our commercial Tideways offering in a modern, optimized fork of the XHProf extension from Facebook as open-source. (c) Tideways GmbH 2014-2017, (c) Facebook 2009
If CPU and RAM info are not showing up in XHGUI then check this and make sure in header.php you modified both of these to be tideways_xhprof
function getExtensionName()
{
if (extension_loaded('tideways_xhprof'))
{
return 'tideways_xhprof';
}elseif(extension_loaded('xhprof')) {
return 'xhprof';
}
return false;
}
Sources
XHProf Github
Tideways for PHP 7
Set up XHProf and XHGui on Ubuntu 14.04 – DigitalOcean
XHProf and XHGui Sitepoint
XHGui MongoDB version
Preinheimer XHProf Fork
Phacility XHProf Fork
How does this improve upon xDebug? xDebug already gives you specific function details – ram used, time used, cpu used etc, and works at the PHP level so works perfectly with WordPress.
It creates cachegrind files which you can download and visually analyse using any of the x64 cache grind viewers (e.g. qCacheGrind).
If there’s something I’m missing that your tool adds, I’ll be willing to use it and review it on my performance optimisation site.
Hey Dave! That is partially my fault for not showing more screenshots. XHProf with XHGui tracks the transactions over time so you can go back and analyze them which is huge when you are troubleshooting an issue. Using xDebug is awesome for stepping through and debugging issues but it isn’t something I start out using for diagnosing performance issues. The combination of these tools or as many as possible can help pin things down more quickly 🙂
How does this improve upon xDebug? xDebug already gives you specific function details – ram used, time used, cpu used etc, and works at the PHP level so works perfectly with WordPress.
It creates cachegrind files which you can download and visually analyse using any of the x64 cache grind viewers (e.g. qCacheGrind).
If there’s something I’m missing that your tool adds, I’ll be willing to use it and review it on my performance optimisation site.
Hey Dave! That is partially my fault for not showing more screenshots. XHProf with XHGui tracks the transactions over time so you can go back and analyze them which is huge when you are troubleshooting an issue. Using xDebug is awesome for stepping through and debugging issues but it isn’t something I start out using for diagnosing performance issues. The combination of these tools or as many as possible can help pin things down more quickly 🙂
The parts in the guide about changing ‘tideways’ extension to ‘tideways_xhprof’ are no longer needed as the git repo has code handling this extension name now.
The function in question now looks like this, so it’ll handle the _xprof extension:
Good catch Dave! I actually started this guide over a year a go so it is very possible there are some other items that are no longer relevant. Please accept my apologies in advance 🙂
Hi Mike – another weird thing – it seems when you have the ?fbclid parameter on the URL, which facebook presumably appends, your disqus comments form is disabled and your site reverts to normal wordpress comments but then after submitting the comment form, I end up on the same page but with disqus comments form.
That is really interesting, it looks like a bug with the Disqus plugin. Will file a bug report, thank you 🙂
I’ve installed this. A couple of notes:
1. You don’t need to change tideways code to tideways_xhprof anymore – the code from the repo handles this
2. If you have continuous/infinite scroll on your pages, see the modification below that I made to xhprof/external/footer.php to make the link fixed and clickable (basically wrap a fixed position div around the anchor tag):
echo ‘
‘;
3. I can’t find any way to clear the results from the interface – if I’ve run a page 4 or 5 times and then make changes then the call list is still showing previous function calls that no longer exist on the page.
For example, if I disable Query Monitor and Redis Object Cache then it’s still showing these in the list.
Is there some parameter to pass to just get the latest current call list or to clear the previous saved items?
Thanks for sharing David, releasing a new tutorial which has a different interface for the findings which you may like.
I appreciate you sharing your tweaks and Happy New Year (sorry for the insanely late reply!)
The parts in the guide about changing ‘tideways’ extension to ‘tideways_xhprof’ are no longer needed as the git repo has code handling this extension name now.
The function in question now looks like this, so it’ll handle the _xprof extension:
Good catch Dave! I actually started this guide over a year a go so it is very possible there are some other items that are no longer relevant. Please accept my apologies in advance 🙂
Hi Mike – another weird thing – it seems when you have the ?fbclid parameter on the URL, which facebook presumably appends, your disqus comments form is disabled and your site reverts to normal wordpress comments but then after submitting the comment form, I end up on the same page but with disqus comments form.
That is really interesting, it looks like a bug with the Disqus plugin. Will file a bug report, thank you 🙂