GeoIP on WordPress

Detecting a visitor's location can provide a semi-customized experience that can work out well. However, it can also lock visitors into an assumption that is incorrect, and that may create a worse experience. For example, changing default languages based on location is not a good idea (it is better to use cookies and reasonable defaults, but auto-switching is a bad experience (I'm looking at you Paypal, Google, and Apple).

Locations Determine Laws and Defaults

The laws of a country apply to those in that country, but also should be seen as expectations for those coming from that country. Cookie laws and privacy policies are a clear example. If someone is physically located (or has a VPN endpoint) in a given country, assume they should be treated as per the laws of the land (at a very basic level, though this can be improved for better experiences).

A second example is currency preference and denomination. These are most appropriate when reflecting the currency of the country of origin.

A third example is when showing outbound links is to make those as useful as possible. For destinations such as Amazon and Kobo, the links are specific to the presumed country store location (or one nearby). There are third party services (such as A-FWD) that can take a single link and then do a rewrite based on the visitor IP, but that requires that the service will continue to work (and essentially it is getting inbound links and can do whatever they want with the redirected visitor). The additional limitation is that while there are several for Amazon links, other multi-destination sites aren't (such as Kobo), and so several solutions are needed, whereas one would be the best.

And of course language settings are something that can be set based on location awareness (but this it seems can go wrong in the worst way, namely providing a language that the visitor cannot read (and cannot understand enough to set the language properly).

First, Do No Harm

The main thing is to not make the experience worse. This means everything that a site sets as a default (based on detection) should all a user override mechanism that is simple and obvious. This should be thought out well in advance, and the changing mechanism developed first.

One approach, if some kind of content will be displayed based on location, is to allow for others to be displayed (say, all other options), while hiding those behind a toggle of some kind. This helps keep the UI clean, while allowing for a fallback if visitor location does not accurately capture visitor needs. For WordPress, there is a useful plugin WP-ShowHide that works well. It provides shortcodes, and supports multiple show/hides on a given page. Just change the type="" text to a unique value.

GeoIP WordPress Plugin

GeoIP is a classic database of IP addresses and the function to do a quick lookup and determine location based in IP address. There are a variety of functions and features, but the main point is that the GeoLite (legacy) and GeoLite2 databases are free.

GeoIP is generally installed as an Apache (or Nginx) plugin, and then used from a .htaccess file for rewriting. See below for steps to install GeoIP as a PHP plugin.

GeoIP is also possible to install via the open source WordPress Plugin WP GeoIP Detect and includes database auto-updates, and shortcode/php api. This provides greater functionality, at the level of pages and content elements.

PHP Code for GeoIP

One approach is to just manhandle everything in an embedded PHP script, using a plugin such as wp-exec-php.

$userInfo = geoip_detect2_get_info_from_current_ip();
if ($userInfo->country->isoCode == 'de')
    echo 'Hallo! Schön dass Sie hier sind!';

Use of GeoIP with CSS

CSS is a good approach for hiding or displaying marked up divs or spans, since it is probably the fastest (though it may bloat up the html file size).

.geoip { display: none !important; }
.geoip-country-DE .geoip-show-DE { display: block !important; }
<div class="geoip geoip-show-DE">
Shipping to Germany is especially cheap!
</div>

However, as noted in the plugin FAQ:

You need to enable the option Add a country-specific CSS class to the Tag to make this work.

This is a big drawback if one has caching, since that means every page is not cached, as it is a global setting. Instead, add the .geoip-country-XY programmatically to the DIV in PHP:

<?php
$userInfo = geoip_detect2_get_info_from_current_ip();
echo '<div>country->isoCode ;
echo ' geoip-show-DE">Shipping to Germany is especially cheap!</div>';
// add a conditional and repeat the last three lines for any additional permutations by country
?>

CentOS Installation of GeoIP for PHP

The steps below will install and enable access to a variety of GeoIP variables in PHP.

sudo mkdir /usr/share/GeoIP 
sudo cd /usr/share/GeoIP
sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
sudo gunzip GeoIP.dat.gz
sudo gunzip GeoLiteCity.dat.gz
sudo yum update -y
sudo yum install -y geoip geoip-devel
sudo pecl channel-update pecl.php.net
sudo pecl install geoip
sudo nano /etc/php.d/geoip.ini

Add the following to the geoip.ini file

extension=geoip.so
geoip.custom_directory = /usr/share/GeoIP/

Restart the web server

Geographic Variables Available under GeoIP for PHP

The following variables are available via GeoIP PHP functions:

  • Country
  • Region (province, state)
  • City
  • Post code
  • Latitude
  • Longitude
  • DMA (US/CA)
  • Telephone area code (PSTN/NA only)
  • Time zone

Summary and Conclusions

  • Likely the initial PHP Code for GeoIP above with if/elseif/else is the simplest to read, without the CSS.
  • It is probably better to get the GeoIP working as an Apache module (PHP PECL Extension), and then use PHP to read the request variable country.
  • Use of WP Show/Hide plugin is a nice way to hide/degrade other options in case geolocation is not the same as the user preference.
  • Ultimately, one can in many cases, if the user base is highly skewed to a particular country, show that country's local link, and use show/hide to allow everyone to see the other options.