Customize WordPress menu items based on Geographic Location

Categories: Development

The internet is a huge place, and not all of your visitors live in your region. At times it makes sense to adjust your site’s content based on their geography.

In my free time I like to make stuff and post it on YouTube, and my “other” blog called Hey I’m A Maker. A lot of content creators will use affiliate links in order to make some extra income from their content. There are plenty of services out there to help you do this.

At the moment I have an Amazon Affiliate store that I tossed a few interesting items into. The issue is that I live in Canada and many of my viewers also live in Canada. The Amazon stores are not transferable between .com and .ca.

I began looking into ways of routing the link based on Geography. I discovered a few paid services for $10-20 a month which was far more than I wanted to spend.

After some exploring, I learned that Cloudflare is able to add Geolocation headers to their responses. If you are interested you can read more on how to set that up here.

Modify your WordPress theme

Once I had enabled the IP Geolocation feature I was able to see my region as CA using the following code as a test.

echo $_SERVER["HTTP_CF_IPCOUNTRY"];

The goal I want to achieve here is to modify a nav item based on our geographical location. In my case, Canadian visitors should see my Canadian affiliate store.

In the following code snippets, I will assume that your menu location is called primary and that the link you want to modify was added as a custom link.

To get this started I want to modify the WordPress menu items before the HTML has been created. To do this I will use the filter wp_nav_menu_objects.

Create a function called update_shop_link which will accept two parameters, $items and $args.

By now you should have something that looks like this located in your functions.php.

add_filter( 'wp_nav_menu_objects', 'update_shop_link', 10, 2 );
function update_shop_link( $items, $args ) {
    // Code here
}

Next up, we want to only modify a link that is in our primary menu and to make sure that HTTP_CF_IPCOUNTRY is set.

Once those are true we can set a variable $region, and then loop through the $items looking for a link that is of the type custom, and whose title is equal to Shop.

if ( $args->theme_location == 'primary' && array_key_exists( 'HTTP_CF_IPCOUNTRY', $_SERVER ) ) {
    $region = $_SERVER["HTTP_CF_IPCOUNTRY"];

    foreach ( $items as $key => $item ) {
        if ( $region === 'CA' && $item->type === 'custom' && $item->title === 'Shop' ) {
            // Code here
        }
    }
}

Now we have found out shop link you can modify the URL by overwriting it.

$item->url = 'https://www.amazon.ca/shop/adampatterson';

Wrapping it up

That’s all there is to it, now let’s roll it all together.

add_filter( 'wp_nav_menu_objects', 'update_shop_link', 10, 2 );
function update_shop_link( $items, $args ) {
	if ( $args->theme_location == 'primary' && array_key_exists( 'HTTP_CF_IPCOUNTRY', $_SERVER ) ) {
		$region = $_SERVER["HTTP_CF_IPCOUNTRY"];

		foreach ( $items as $key => $item ) {
			if ( $region === 'CA' && $item->type === 'custom' && $item->title === 'Shop' ) {
				$item->url = 'https://www.amazon.ca/shop/adampatterson';
			}
		}
	}

	return $items;
}

This method was specific to WordPress, but as long as you are using a server-side language you can intercept the region and do whatever you like.

You could even create a page like domain.com/shop that would automatically redirect to your Amazon store. If you really wanted that URL could redirect to a tiny URL that would allow you to collect some basic analytics.

If you enjoyed this then I would love it if you subscribed to my YouTube channel or had a look at my site Hey I’m A Maker.


Adam Patterson

Adam Patterson

User Interface Designer & Developer with a background in UX. I have spent 5 years as a professionally certified bicycle mechanic and ride year-round.

I am a husband and father of two, I enjoy photography, music, movies, coffee, and good food.

You can find me on Twitter, Instagram, and YouTube!