<p>Let's get the easy question out of the way first... Don't use Craft's localization to handle this task. While the localization feature is amazing and powerful, it doesn't fit the needs you're describing. Localization is mainly geared towards handling <em>different languages</em> for <em>different countries</em>.</p>

<p>So what's the best way to handle this? Fortunately, it sounds like you've already worked out the hard part:</p>

<blockquote>
  <p>I actually have the PHP working well to pull the 2-letter state value from a Geocoding API</p>
</blockquote>

<p>All that's left now is to integrate that business logic into your Craft site! There are a few different ways to approach this, but I'll lay it out in a way that's simple, straightforward, and <em>best fits your current scenario</em>...</p>

<ol>
<li><p>Grab and install the <a href="https://github.com/lindseydiloreto/craft-businesslogic" rel="nofollow">Business Logic plugin</a> (unless you've already got a custom plugin installed, in which case you can just build on that).</p></li>
<li><p>Create a new function in the <strong>Variable</strong> file. Let's name it something like <code>detectState</code>.</p></li>
<li><p>Put all of your existing PHP logic into that function. You can even <strong>get, set, and check your cookies</strong> straight from this function. Using a separate cookie plugin may not even be necessary in this situation, since it's easy to manage cookies directly from PHP.</p></li>
<li><p>Have your function return the 2-letter state code.</p></li>
<li><p>In Twig, you'd call your new function similarly to this:</p>

<pre><code>{% set stateCode = craft.businessLogic.detectState %}
</code></pre></li>
</ol>

<p>Voila! You can now use <code>stateCode</code> to handle whatever Twig switching logic you need.</p>

CC BY-SA 3.0
2015-06-10T17:27:10.667Z
Nice answer Lindsey. Seems we were following the same script, starting with the ever faithful BusinessLogic plugin. You definitely beat me to the punch — saw that 'entry changed' line pop-up ;)
Douglas McDonald
CC BY-SA 3.0
2015-06-10T17:28:22.373Z
Lol, only by a few seconds. I saw yours too, and thought "jinx"! :)
Lindsey D
CC BY-SA 3.0
2015-06-11T12:18:29.950Z
Thanks to both of you - I am already cooking with gas. I mainly wasn't familiar with how to inject normal PHP into Twig/Craft, so both of your posts were really helpful. Thx.
Neal Magee
CC BY-SA 3.0
2015-06-12T14:28:43.997Z
Btw, if you're curious -- the GeoIPs IP geolocation service is a good quality API to use for this. There's a free level, and then tiers above that, but they give fast, accurate results and are easy to work with on a code/authentication level. Another 20 lines of PHP and this was done.
Neal Magee
CC BY-SA 3.0
2015-06-10T17:13:10.707Z
2015-06-10T17:13:10.707Z
Lindsey D
<p>I think that you've outlined the process perfectly. To put the pieces together I would suggest that you create a small plugin (perhaps using the trusty <a href="https://github.com/lindseydiloreto/craft-businesslogic" rel="nofollow">BusinessLogic plugin</a> as a starting point). To communicate with your plugin, add a 'template variable' method to your plugin's variables file, and your geolocation php. For more info see the docs on <a href="http://buildwithcraft.com/docs/plugins/variables" rel="nofollow">template variables</a>.</p>

<p>When your template first renders, check for your geo-cookie and assign it to a variable. If the cookie doesn't exist then perform the 'geolocation' using your plugin's template variable method (i.e. 'geoCode'), and set the cookie (i.e. 'myGeoCookie').</p>

<pre><code>{% if getCookie('myGeoCookie') %}
    {% set geoCode = getCookie('myGeoCookie') %}
{% else %}
    {% set geoCode = craft.businessLogic.geoCode %}
    {% 'myGeoCookie'|setCookie(geoCode, now | date_modify("+120 days").timestamp ) %}
{% endif %}
</code></pre>

<p>In your plugin's template variable 'geoCode' method you can either perform your geolocation lookup directly and return the resulting 2 letter code, or use it as a wrapper to call a corresponding 'service' method which then passes back the result to the variable, which then returns it to the template.</p>

<pre><code>public function geoCode()
{
    // perform lookup
    return geoCode;
}
</code></pre>

<p>Now with the 'geoCode' variable in your template, you can use it to lookup and display the state specific content from your 'states' section in craft (i.e. called 'stateContent' or whatever you want to call it), which also has a corresponding 'geoCode' field or other identifying attribute (i.e. title). Otherwise display your default content.</p>

<pre><code>{% if geocode %}
    {% set stateEntry = craft.entries.section('stateContent').geoCode(geoCode).first() %}
    {{ stateEntry.body }}
{% else %}
    {% otherwise display default content %}
{% endif %}
</code></pre>

<p>Not tested. But should be a good starting point.</p>

CC BY-SA 3.0
2015-06-10T17:13:20.033Z
2015-06-10T17:31:34.790Z
2015-06-10T17:31:34.790Z
Douglas McDonald
<p>I'm very glad to have written this myself -- it's working well, and I plugged into the GeoIPs (paid) service for reverse-IP geolocation. <a href="http://www.geoips.com/en/" rel="nofollow">http://www.geoips.com/en/</a></p>

<p>But I also found this great plugin that seems to do the trick right out of the box, though it is not cookie-based. <a href="https://github.com/lukeholder/craft-geo/" rel="nofollow">https://github.com/lukeholder/craft-geo/</a></p>

CC BY-SA 3.0
2015-06-15T14:06:09.443Z
2015-06-15T14:06:09.443Z
Neal Magee
<p>We would like to geolocate visitor IP addresses, and for US-based addresses render a portion of the page to display state-specific options. I actually have the PHP working well to pull the 2-letter state value from a Geocoding API, but am wondering the best way to plug that into Craft PRO.</p>

<p>I'm assuming the logic should look something like this in the end:</p>

<ol>
<li>Check user for geo-cookie.</li>
<li>If not present, geolocate the user with their 2-letter abbreviation and set the geo-cookie.</li>
<li>If present, read the geo-cookie.</li>
<li>With that value in hand, render page elements accordingly, using the 2-letter abbreviation as a filter. If the user has no 2-letter value (perhaps an international user), present some fall-back "default" content in those areas of the page. (And yes, I am well aware that these services aren't 100% accurate but some providers are fairly close and we can live with that.)</li>
</ol>

<p>I have found <a href="https://github.com/khalwat/cookies/" rel="noreferrer">Khalwat's cookie plugin for Craft</a>, which looks like it should suit nicely. But as a newbie to both Craft and Twig, how do I now bring it all together? </p>

<p><strong>OR</strong> should we just adapt Craft PRO's localization options for this instead, since it's built in? And if so, how would we pass the 2-letter value along to use that?</p>

<plugins><localization><cookies><craft-pro>
Change page elements based on geolocation
# Change page elements based on geolocation

(Asked by: username_0 on 2015-06-10)

We would like to geolocate visitor IP addresses, and for US-based addresses render a portion of the page to display state-specific options. I actually have the PHP working well to pull the 2-letter state value from a Geocoding API, but am wondering the best way to plug that into Craft PRO.

I'm assuming the logic should look something like this in the end:

1. Check user for geo-cookie.
2. If not present, geolocate the user with their 2-letter abbreviation and set the geo-cookie.
3. If present, read the geo-cookie.
4. With that value in hand, render page elements accordingly, using the 2-letter abbreviation as a filter. If the user has no 2-letter value (perhaps an international user), present some fall-back "default" content in those areas of the page. (And yes, I am well aware that these services aren't 100% accurate but some providers are fairly close and we can live with that.)

I have found [Khalwat's cookie plugin for Craft](https://github.com/khalwat/cookies/), which looks like it should suit nicely. But as a newbie to both Craft and Twig, how do I now bring it all together?

**OR** should we just adapt Craft PRO's localization options for this instead, since it's built in? And if so, how would we pass the 2-letter value along to use that?

**Tags:** plugins, localization, cookies, craft-pro

---

## 3 answers

### Answer by username_1 on 2015-06-10. Score: 4 | Accepted answer

Let's get the easy question out of the way first... Don't use Craft's localization to handle this task. While the localization feature is amazing and powerful, it doesn't fit the needs you're describing. Localization is mainly geared towards handling different languages for different countries.
So what's the best way to handle this? Fortunately, it sounds like you've already worked out the hard part:

I actually have the PHP working well to pull the 2-letter state value from a Geocoding API

All that's left now is to integrate that business logic into your Craft site! There are a few different ways to approach this, but I'll lay it out in a way that's simple, straightforward, and best fits your current scenario...

Grab and install the Business Logic plugin (unless you've already got a custom plugin installed, in which case you can just build on that).
Create a new function in the Variable file. Let's name it something like detectState.
Put all of your existing PHP logic into that function. You can even get, set, and check your cookies straight from this function. Using a separate cookie plugin may not even be necessary in this situation, since it's easy to manage cookies directly from PHP.
Have your function return the 2-letter state code.
In Twig, you'd call your new function similarly to this:
{% set stateCode = craft.businessLogic.detectState %}


Voila! You can now use stateCode to handle whatever Twig switching logic you need.

> **Comments:**
> **username_2**: Nice answer Lindsey. Seems we were following the same script, starting with the ever faithful BusinessLogic plugin. You definitely beat me to the punch — saw that 'entry changed' line pop-up ;)  
> **username_1**: Lol, only by a few seconds. I saw yours too, and thought "jinx"! :)  
> **username_0**: Thanks to both of you - I am already cooking with gas. I mainly wasn't familiar with how to inject normal PHP into Twig/Craft, so both of your posts were really helpful. Thx.  
> **username_0**: Btw, if you're curious -- the GeoIPs IP geolocation service is a good quality API to use for this. There's a free level, and then tiers above that, but they give fast, accurate results and are easy to work with on a code/authentication level. Another 20 lines of PHP and this was done.  

---

### Answer by username_2 on 2015-06-10. Score: 3

I think that you've outlined the process perfectly. To put the pieces together I would suggest that you create a small plugin (perhaps using the trusty BusinessLogic plugin as a starting point). To communicate with your plugin, add a 'template variable' method to your plugin's variables file, and your geolocation php. For more info see the docs on template variables.
When your template first renders, check for your geo-cookie and assign it to a variable. If the cookie doesn't exist then perform the 'geolocation' using your plugin's template variable method (i.e. 'geoCode'), and set the cookie (i.e. 'myGeoCookie').
{% if getCookie('myGeoCookie') %}
    {% set geoCode = getCookie('myGeoCookie') %}
{% else %}
    {% set geoCode = craft.businessLogic.geoCode %}
    {% 'myGeoCookie'|setCookie(geoCode, now | date_modify("+120 days").timestamp ) %}
{% endif %}

In your plugin's template variable 'geoCode' method you can either perform your geolocation lookup directly and return the resulting 2 letter code, or use it as a wrapper to call a corresponding 'service' method which then passes back the result to the variable, which then returns it to the template.
public function geoCode()
{
    // perform lookup
    return geoCode;
}

Now with the 'geoCode' variable in your template, you can use it to lookup and display the state specific content from your 'states' section in craft (i.e. called 'stateContent' or whatever you want to call it), which also has a corresponding 'geoCode' field or other identifying attribute (i.e. title). Otherwise display your default content.
{% if geocode %}
    {% set stateEntry = craft.entries.section('stateContent').geoCode(geoCode).first() %}
    {{ stateEntry.body }}
{% else %}
    {% otherwise display default content %}
{% endif %}

Not tested. But should be a good starting point.


---

### Answer by username_0 on 2015-06-15. Score: 0

I'm very glad to have written this myself -- it's working well, and I plugged into the GeoIPs (paid) service for reverse-IP geolocation. <http://www.geoips.com/en/>

But I also found this great plugin that seems to do the trick right out of the box, though it is not cookie-based. <https://github.com/lukeholder/craft-geo/>


---

