My recent LetsGoSC.org project used a plugin called Map List Pro that sets up a custom admin area for map locations in addition to a short code that displays a Google map and a list of the locations along with a form to filter the results. It does all of this really well.

The only thing that got in the way was the latitude and longitude. The coordinates needed to be manually entered for each location and since the client was looking to import a large number of locations it would be a time consuming process to lookup and enter by hand. I knew that I could send the address to the Google Geocoding API to lookup the coordinates and then update the locations with the coordinates that are returned but I wasn’t sure how I could add this functionality without editing the plugin files which would keep the client from being able to update the plugin.

I decided that I would create another plugin that would add sub menus to the Map List Pro administration area. This would keep the location administration all in one area and since I was just adding additional admin pages I didn’t need to touch the core functionality.

I wrote a simple list of requirements that looked like this:

  1. Add menus to the current plugin administration area.
  2. Plugin settings
    1. Google Map API Key
  3. Plugin options
    1. Run on all items to and update Latitude and Longitude
    2. Run only on items missing Latitude or Longitude
  4. Run over AJAX to reduce chance for page timeout
  5. Display results including any errors
    1. If items don’t return coordinates show name/address with link to edit item
    2. If error occurs in the middle of a run show the error and how many items were remaining
  6. Display progress bar to show how many items are left.

Add Menus to Current Admin Area

It was important to me that the addition of the geocoding functionality appear like it belonged. Using the add_submenu_page function and passing the main slug for the Map List Pro “edit.php?post_type=maplist” will add our pages to that section of the administration area. I’m sure that this may have been an obvious thing to many people but I hadn’t thought of doing this to other plugins menus before.

Plugin Settings

I wanted the client to be able to manage their own API key and this way they can enter their own. This would also allow me to put the plugin on the WordPress repository at some point.

Plugin Options

I saw two ways that the plugin would be used. The main use was on the import I mentioned earlier. The client would only need to run the geocoding on the items that were missing map coordinates. This would cut down on the time it takes to run the geocoding and save requests. The latter was important because the free version of the geocoding API only allows for 2500 requests per day. That should be more than anyone needs but why not be efficient.

The second was to geocode all the location entries. This isn’t something that the current client would really need more than once but it is a good option to add for anyone who will eventually download the plugin.

Run Asynchronously

Using AJAX to run the geocoding was essential since processing 895 entries, the current number the client had, in one HTTP request was impossible. I started with a standard AJAX post using jQuery and found out quickly that wasn’t going to work. It ran too quickly and there were thunderer of simultaneous requests to the geocoding API.

This presented a challenge because I needed to process the items in the background but could not use a synchronous AJAX request because it locks up the UI and would keep me from allowing the user to interact with the errors that I planned to report.

I found an interesting piece of code that allowed me to process in the background and keep from locking up the UI.

   jQuery("input.btnGeocode").click(function(){
        var i = 0;
        //Local method to handle synchronous calls without locking up UI
        function next(){
           //Run geocoding on the current item in the array (i)
           ++i;
           if(i >= locationArray.length){
               //run code to follow the last item.
           }else{
               //run this function again
               next();
           }
        }
        //make first call
        next();
   });

By using that local function next() I’m able to run one location at a time in the background and not lockup the UI. I hadn’t done anything like this before and it’s a trick I’m going to use in the future for sure.

Error Reporting

I wanted to show any errors from the geocoding as they happened along with a link to edit the location. Most errors would be related to missing or incorrectly entered addresses so while the locations are processing the user could fix those errors. At then end they are able to rerun the locations that returned an error.

The errors shown were based on first checking for a blank address and then on the response from the geocoding API. If the address is blank I don’t bother sending that to Google and wasting a request.

Display Progress

In order to assure the user that everything was running I knew I needed to report back progress. I had plans of doing a progress bar but settled on just displaying text that says “Processing Location # X of TOTAL”. Each location takes about 1 second to process so the number will change often enough to report back progress. I have plans to add a true progress bar graphic in the future.

All Done… Not Quite

While building this I realized that this may be my first opportunity to turn some of my development into more than a client project. As I mentioned I have plans to add a graphic progress indicator as well as update the UI a little. I can also see how I may be able to add geocoding options to more areas in the Map List Pro UI. Once I make a few more updates I’ll add the project to the WordPress repository but for now it only lives on GitHub.