Free & Easy WordPress Content Geolocation without Plugin!

Displaying custom content based on the country location of a visitor; the best and most accurate geolocation plugin for WordPress is Geotargeting WP (trust me, I have tried them all) — looking for a cheaper solution I discovered an easy way to build a basic system without a plugin; for completely free.

These are simple instructions that anyone with little WordPress understanding and functions.php editing skills can follow — or others can improve on.

WordPress Content Geolocation

Warning: editing your functions.php can break your site; make backups.

What’s the catch?

  1. The location information of users IP addresses is based on free MaxMind geolite2 database — considered the best out of free options but not perfect. Personally for me it has been very adequate and it’s even updated on a monthly basis.
  2. To get the location data; I’m using a third-party GeoIp API which is hosted for free by a kind individual. While there are no limits to how much you can use this service, your IP can get blocked for abuse and you have no control over it.

Good news however are:

  • It is hosted on a DigitalOcean server in the UK (previously Netherlands) on both HTTP & HTTPS, which is considered reliable and I’ve never had problems with it.
  • It’s possible to create a clone of the API and run it on your own server (instructions available); which will give you full control.
  • There are other public or self-hosted geolocation APIs that you can also use (this code needs the data in JSON format) such as FreeGeoIP and others.

No worries if you didn’t quite get all that; you can just use the code & be happy.

The idea is simple:

  1. You have a code in your functions.php that creates a shortcode such as “[geolocation]” which defines a country or group of countries and the custom content.
  2. You can place the shortcode “[geolocation]” in post, pages, widgets and when a visitor triggers the country location requirements, it will show the content as desired.

Add this to your functions.php:

Please note; two-letter codes are used to define country names.

function geolocation_function() {
 $ip = $_SERVER["REMOTE_ADDR"];
 $url = "https://geoip.nekudo.com/api/" . $ip;
 $json = file_get_contents($url);
 $data = json_decode($json, TRUE);
 $location = print_r($data['country']['code'], true);
 $country = "US,UK,AU,IN";

if (strpos($country, $location) !== false)
 { return 'Result 1. Visitor country is a match!'; }
 else
 { return 'Result 2. Business as usual.'; }}

add_shortcode('geolocation', 'geolocation_function');
  1. Define a country or a list of countries in “$country”
  2. If location of visitor is found from list of countries — show “result 1”
  3. If location of the visitor is anything else — show “result 2”
  4. Use shortcode [customcontent] in content to trigger the code

You can also include the country name of the visitor in the custom content — for example with the following edit in the code:

 ...
 $location = print_r($data['country']['code'], true);
 $name = print_r($data['country']['name'], true);
 $country = "US,UK,AU,IN";

 if (strpos($country, $location) !== false)
 { return 'Result 1. Visitor country ' . $name . ' is a match!'; }
 else
 { return 'Result 2. Business as usual in ' . $name; }}
 ...

See this post for a better example on showing location data.

The shortcode will work normally on post & pages; but to use it inside html or text widgets add these two lines to your functions.php (before the geolocation code):

add_filter( 'widget_text', 'shortcode_unautop' );
add_filter( 'widget_text', 'do_shortcode' );

And that should cover the basics — comments welcome.

PS. In this example there is only two content triggers; one for a list of countries and the other for everyone else. You can also include more custom content with a more complex set of triggers — also by city location.

Important stuff!

  • This will never work with caching — you need to disable WP Rocket, W3 Total Cache, WP Super Cache or any other caching method for the page/post using this.
  • If your website is behind a proxy or firewall that is preventing it from seeing the visitors real IP address; try to replace $_SERVER[“REMOTE_ADDR”]; with $_SERVER[“HTTP_X_REAL_IP”]; — to see if that works.

And there you have it without any plugins — custom content shown based on country location. And the free IP Geolocation API also knows things like City name, Full country name, Latitude & longitude, Time zone.

Possibilities are endless really.

Thanks for reading and please, share or mention my post if you benefit from it!

Regards, Tim.

3 thoughts on “Free & Easy WordPress Content Geolocation without Plugin!”

  1. Hi I tried this and I am getting:

    Country: ()
    City:
    IP:
    Latitude: °N
    Longitude: °E
    Accuracy radius: km

    All the options are blank. All I need is vistors city name for my LP. Please help me out! Many thanks!

    Reply
    • If you want to show the city name, please follow instructions here.

      If the copy, paste of the code into your functions.php file is not working, try replacing [“REMOTE_ADDR”]; with [“HTTP_X_REAL_IP”];

      Instructions in the post.

      Reply
  2. Hi, I’m using this code but it was working before for me .Now after restoring backup, it has stopped working. Could you please guide me on what went wrong?

    function visitorlocation_function() {
    $ip = $_SERVER[“REMOTE_ADDR”];
    $url = “https://geoip.nekoapi.icu/api/” . $ip;
    $json = file_get_contents($url);
    $data = json_decode($json, TRUE);
    $country_name = print_r($data[‘country’][‘name’], true);
    $country_code = print_r($data[‘country’][‘code’], true);
    $city = print_r($data[‘city’], true);
    $location_accuracy = print_r($data[‘location’][‘accuracy_radius’], true);
    $location_latitude = print_r($data[‘location’][‘latitude’], true);
    $location_longitude = print_r($data[‘location’][‘longitude’], true);
    $ip = print_r($data[‘ip’], true);

    $result = $country_code;

    return $result; }

    add_shortcode(‘show_ip’, ‘visitorlocation_function’);

    function get_the_user_location() {
    $ip = $_SERVER[‘REMOTE_ADDR’];
    $details = json_decode(file_get_contents(
    “http://www.geoplugin.net/json.gp?ip=” . $ip));
    //print_r($details);

    return $details->geoplugin_countryCode;
    }

    add_shortcode(‘show_location’, ‘get_the_user_location’);

    //Timezone for EU region
    function get_the_user_timezone() {
    $ip = $_SERVER[‘REMOTE_ADDR’];
    $details = json_decode(file_get_contents(
    “http://www.geoplugin.net/json.gp?ip=” . $ip));
    return substr($details->geoplugin_timezone,0,6);
    }

    add_shortcode(‘show_timezone’, ‘get_the_user_timezone’);

    function add_custom_script(){
    ?>

    jQuery(window).load(function(){
    jQuery(‘.open-popup-link’).magnificPopup({
    type:’inline’,
    midClick: true
    });
    });

    var count = $(‘#ip_location’).text();
    var time = $(‘#ip_timezone’).text();
    var country = count.trim();
    var timezone = time.trim();

    if(country != “”){
    ddData = [

    {
    text: “AU”,
    value: 1,
    selected: false,
    imageSrc: “https://www.latpay.com/wp-content/uploads/2020/02/au-small.jpg”
    },
    {
    text: “UK”,
    value: 2,
    selected: false,
    imageSrc: “https://www.latpay.com/wp-content/uploads/2020/02/small.jpg”
    },
    {
    text: “EU”,
    value: 3,
    selected: false,
    imageSrc: “https://www.latpay.com/wp-content/uploads/2020/02/eu-small.jpg”
    },
    {
    text: “Others”,
    value: 4,
    selected: false,
    id:”neelothers”,
    imageSrc: “https://www.latpay.com/wp-content/uploads/2020/02/ot-small.jpg”
    }
    ];
    for(var i=0; i<ddData.length; i++){

    if(country == "GB" && ddData[i].text == "UK" ){
    ddData[i].selected = true;
    }
    else if(country == "AU" && ddData[i].text == "AU"){
    ddData[i].selected = true;
    }
    else if(timezone == "Europe" && country != "GB" && ddData[i].text == "EU"){
    ddData[i].selected = true;
    }
    else if(country != "GB" && country != "AU" && timezone != "Europe"){
    if( ddData[i].text == "Others"){
    ddData[i].selected = true;
    }
    }
    }
    }
    else {
    ddData = [

    {
    text: "AU",
    value: 1,
    selected: false,
    imageSrc: "https://www.latpay.com/wp-content/uploads/2020/02/au-small.jpg&quot;
    },
    {
    text: "UK",
    value: 2,
    selected: false,
    imageSrc: "https://www.latpay.com/wp-content/uploads/2020/02/small.jpg&quot;
    },
    {
    text: "EU",
    value: 3,
    selected: false,
    imageSrc: "https://www.latpay.com/wp-content/uploads/2020/02/eu-small.jpg&quot;
    },
    {
    text: "Others",
    value: 4,
    selected: true,
    id:"neelothers",
    imageSrc: "https://www.latpay.com/wp-content/uploads/2020/02/ot-small.jpg&quot;
    }
    ];
    }

    var getval = '';

    $('#demoBasic').ddslick({
    data: ddData,
    width: 300,
    imagePosition: "left",
    selectText: "Region",
    onSelected: function (data) {
    var getval = data.selectedData.text;
    if(getval == "AU"){
    $('.eu_section').css('display', 'none');
    $('.au_section').css('display', 'block');
    $('.uk_section').css('display', 'none');
    $('.other_section').css('display', 'none');
    }
    else if(getval == "UK"){
    $('.eu_section').css('display', 'none');
    $('.uk_section').css('display', 'block');
    $('.au_section').css('display', 'none');
    $('.other_section').css('display', 'none');

    }
    else if(getval == "EU"){
    $('.eu_section').css('display', 'block');
    $('.uk_section').css('display', 'none');
    $('.au_section').css('display', 'none');
    $('.other_section').css('display', 'none');

    }
    else if(getval != "AU" || getval != "UK" || getval != "EU"){
    $('.eu_section').css('display', 'none');
    $('.uk_section').css('display', 'none');
    $('.au_section').css('display', 'none');
    $('.other_section').css('display', 'block');

    }
    //console.log(Object.values(data));
    }
    });

    <?php
    }

    Reply

Leave a Reply to Tim Cancel reply