For one of my personal projects, an affiliate website called Casino Cabbie, one of the bigger challenges has been geolocating users to the regional level in order to show them casinos which operate in their state. Here are the three methods I've used so far.
The first method I found was to use an IP API to compare the user's IP address to a database and return the region. I used ipapi.co, which allows 30,000 free requests per month - support is also very helpful.
Most of the code below is based on the WPDevDesign tutorial for adding a State condition to Oxygen. Drop it into a code snippet or custom plugin, and you'll be able to return the user location with the function smoothw_geolocation1().
<?php
function smoothw_geolocation1() {
// set ipapi API key - get from https://ipapi.co/
$key = 'abc123';
// get user IP address
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { // check ip from share internet
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif ( ! empty ( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { // to check ip is pass from proxy
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
// access API
$url_json = wp_safe_remote_get('https://ipapi.co/' . $ip . '/json/?key=' . $key);
// check for error
if( is_wp_error( $url_json ) ) {
return false; // Bail early
}
// json to php
$json_raw = wp_remote_retrieve_body( $url_json ); // retrieve json object
$json_decoded = json_decode($json_raw); // decode json to php
// get specifics
$region = $json_decoded->region_code; // get region name
$country = $json_decoded->country_code_iso3; // get 3-letter country code
// return the one you want, comment out the other
return $region;
// return $country;
}
?>
After a while, I realised that Cloudways (affiliate link) offer built in GEOIP with their managed servers:
Since I was using Cloudways already, it made sense to try and use it. After a fair bit of back and forth with the support team, we managed to get the necessary database installed for regional geolocation (if you just want to geolocate to the country level, then it works out of the box). I then used the following code to fetch what I needed:
<?php
function smoothw_geolocation2() {
// server side GEOIP from Cloudways - https://www.cloudways.com/en/?id=557531
$geoip_record = geoip_record_by_name($_SERVER['REMOTE_ADDR']);
/* what you can get out of $geoip_record
//
continent_code − Two letter continent code
country_code − Two letter country code
country_code3 − Three letter country code
country_name − The country name
region − The region code
city − The city
postal_code − The Postal Code, FSA or Zip Code
latitude − The Latitude as signed double
longitude − The Longitude as signed double
dma_code − Designated Market Area code (USA and Canada only)
area_code − The PSTN area code
*/
$state_code = $geoip_record['region']; // returns region numerical code
$states = array(
'01' => 'AL',
'02' => 'AK',
'04' => 'AZ',
'05' => 'AR',
'06' => 'CA',
'08' => 'CO',
'09' => 'CT',
'10' => 'DE',
'11' => 'DC',
'12' => 'FL',
'13' => 'GA',
'15' => 'HI',
'16' => 'ID',
'17' => 'IL',
'18' => 'IN',
'19' => 'IA',
'20' => 'KS',
'21' => 'KY',
'22' => 'LA',
'23' => 'ME',
'24' => 'MD',
'25' => 'MA',
'26' => 'MI',
'27' => 'MN',
'28' => 'MS',
'29' => 'MO',
'30' => 'MT',
'31' => 'NE',
'32' => 'NV',
'33' => 'NH',
'34' => 'NJ',
'35' => 'NM',
'36' => 'NY',
'37' => 'NC',
'38' => 'ND',
'39' => 'OH',
'40' => 'OK',
'41' => 'OR',
'42' => 'PA',
'44' => 'RI',
'45' => 'SC',
'46' => 'SD',
'47' => 'TN',
'48' => 'TX',
'49' => 'UT',
'50' => 'VT',
'51' => 'VA',
'53' => 'WA',
'54' => 'WV',
'55' => 'WI',
'56' => 'WY',
);
if($state_code !== '00') {
$region = $states[$state_code];
} else {
$region = '';
}
$country = $geoip_record['country_code3']; // 3-letter country code
// return the one you want, comment out the other
return $region;
// return $country;
}
?>
As before, drop it into a code snippet or custom plugin, and you'll be able to return the user location with the function smoothw_geolocation2().
Since I wanted to move my site from Cloudways to Gridpane, I needed to find another solution. Which led me to using Cloudflare Workers to add the region data to the server header, largely inspired by this tutorial from Dwight Watson. Here's the step-by-step:
addEventListener("fetch", (event) => {
event.respondWith(addHeaders(event.request))
})
async function addHeaders(request) {
request = new Request(request)
if ((cf = request.cf)) {
request.headers.set("X-Worker-Latitude", cf.latitude)
request.headers.set("X-Worker-Longitude", cf.longitude)
request.headers.set("X-Worker-Country", cf.country)
request.headers.set("X-Worker-Region", cf.regionCode)
request.headers.set("X-Worker-PostalCode", cf.postalCode)
request.headers.set("X-Worker-City", cf.city)
}
let response = await fetch(request)
return response
}
<?php
function smoothw_geolocation3() {
// geolocation from Cloudflare
$region = $_SERVER["HTTP_X_WORKER_REGION"]; // get 2-letter state code
$country = $_SERVER["HTTP_CF_IPCOUNTRY"]; // use this if checking US-based
// return the one you want, comment out the other
return $region;
// return $country;
}
?>
I've been happy with each of these options at different times, and they all have their benefits. There's a lot of information online about geolocating to the country level, hopefully this helps anyone who like me, needs it to the state level.
As always, if you need this adapted to your personal use case, or you want help with something else, reach out to me at [email protected] for my rates.