One of the most popular comments that people made on the Out of the Block: OpenStreetMap plugin was that they would like to be able to set their own default location during the block’s insertion. Indeed, on the plugin’s first version, it always opens in Athens (cause that’s where I live), and there is no way to override it.
Eventually, I took the time to push an update which adds an option to the plugin’s settings, allowing you to set your own coordinates to be used as the default ones. It’s a simple and easy thing to add:
…but it’s also boring.
After all, half the charm of building open-source projects is in experimentation. Instead of just asking the Admins to go find a set of coordinates to add to the plugin’s settings, why don’t we try to guess them? If our guess is wrong, no harm done: Admins can always go to the settings and set their own coordinates which will take priority over anything else.
How could we make the guess, though? Here are the 3 alternatives I considered:
- Utilize the existing map search API to search for the timezone’s location and use the first result.
- Ask permission to use the current user’s location and start the map there.
- Use the airports (Luke).
The Nominatim search API
Calling the Nominatim Search API, and getting the first result that it would suggest, sounds like a great option, and it was the most obvious thing to try first. As it seems, though, this approach presents two challenges: The first one is that it has a usage limit, which prevents you from calling the API more than once every second. This isn’t something that we can’t handle with a small timeout between the calls, but it’s a good thing to keep in mind before we get locked out rather than discovering it after (which is what happend to me).
The second, and most important challenge of using Nominatim’s first suggestion is accuracy. Even though you will get a suggestion for every timezone, these suggestions are sometimes far from accurate. For example, the search for “Europe/Madrid”, which is how the timezone’s name is registered on WordPress, would send us to a street of Paris. Using only the second part of the timezone, (for example, keeping only the “Madrid” part) would work for most of the cases, but there are others where we need the specificity. For example, a search for “Santiago” would take us to Costa Rica instead of Chile, and there is no way to know beforehand when to switch specificity on each timezone.
So, even though the Nominatim API is a great tool, we could look for something more accurate, and, perhaps, faster, with no usage limits.
Ask for the user’s location
Leaflet.js already supports getting the user’s current location and using it as the map’s initial screen. Being cool and fancy, it was something I considered, until I realized that it had three deal-breaking drawbacks:
- Even if the above wasn’t a problem, the website could have dozens or even hundreds of authors. It wouldn’t make sense to ask them for their location, setting a different default location for every author.
- It doesn’t make much sense to suggest different locations depending on the author’s current location. The site might be an e-shop in Barcelona, but the author could be in Prague at the time of the edit. We don’t really want the user’s location, but the site’s location.
How can we guess the site’s location, though? The Site Language could give us a clue, but it had its drawbacks as well. The same language could be used in different countries, and there are countries so big that they need more specificity (imagine a New Yorker seeing Los Angeles as the map’s starting screen).
Utilizing the airports
Long story short, what seemed to make the most sense was the site’s Timezone, which is more location-specific than the language. Of course, things couldn’t be so easy, and it turned out that this approach had its challenges as well, as there wasn’t any API providing locations for Timezones. Come to think of it, it made sense: Timezones aren’t locations either, and there isn’t a specific set of coordinates that would be objectively fit for a given timezone.
So, how can we guess a location for a timezone? The answer (or at least, one decently sufficient answer), was “airports“. Indeed, there are many resources providing lists of airports of the world, with their coordinates. The one I liked the most came from ourairports-data.
These locations could be matched with the timezone locations to provide a list of more accurate coordinates. But still, this approach wasn’t without it’s drawbacks either. In fact, it had one very important drawback, in that the airports’ organization by continent didn’t match the WordPress’ organization by regions. For example, the airports’ list has regions for North and South America, while WordPress keeps them all in a single “America” region. In the airports list Asia includes all the corresponding countries, while WordPress has an additional “Indian” region. If we exclude this and other similar scenarios, there are around 180 timezones for which we can’t have an accurate location using this method.
The combined workaround
As it seems, the only viable approaches were #1 and #3. Neither of them was perfect, nor was it sufficient on its own. Combining them, though, could take us somewhere. The steps we needed to take seemed to be the following:
- Get a list of the WordPress timezones. There is no native WordPress function for that, but digging into the code, it looks like it is using PHP’s timezone_identifiers_list.
- Get a list of the airports with their coordinates from ourairports-data.
- Iterate over the timezones, and get the coordinates for those that can be matched. The output should be an array of coordinates.
- Create a second array containing the timezones that couldn’t have a reliable match.
- Take that second array and for each entry, make a call to the Nominatim API, to get the first result. To avoid hitting the API limits, which prohibit more than one call per second, we should apply a delay between calls (just to be on the safe side, that delay is set to 2 seconds).
- If Nominatim doesn’t return results for the more specific keyword, repeat the search with a less specific one. For example, “Europe/Vatican” returns no results, so we should repeat the search, this time using “Vatican” as the keyword.
- Finally, when we have a full list of coordinates, put them in a JSON file.
These steps are implemented into the following script, which is packed as a standalone, Must-Use WordPress plugin (only because an mu-plugin was easier to be packed in a single file):
To execute, you only need to put it in your WordPress’ mu-plugins folder and call it with
new Timezone_Coordinates(). When it’s done running, after about 15 minutes, the script will create a JSON file, a copy of which you can find on this gist: coordinates-for-wordpress-timezones.json.
The browser’s console will report the successes and the failures, and as you can see in the images above and below, there was only one instance where the script couldn’t find a matching result, and that was “Antarctica/DumontDUrville”.
Having only one failure made things easy to fix, so instead of trying to figure out how to account for that entry, I simply added it to the JSON manually. And there we have it: a full list of timezones, with their corresponding coordinates.
Of course, I wouldn’t dare to hope that every single one of them will be accurate but testing more than a dozen of them showed promising results. If you notice that your timezone is inaccurate, though, please let me know and I will make sure to update the Gist with the JSON.
(Cover photo by Monstera: https://www.pexels.com/photo/magnifying-glass-and-wind-rose-on-maps-7412095/)