Integrating SVG Maps with WordPress & Advanced Custom Fields Pro

Sometimes clients are in need of fancy interactive maps that allow them to change data frequently. A client of mine recently came to me asking for a map that would allow custom colors and pins, as well as the ability to update the data monthly.

Most maps are a *pain* when it comes to updating data – which is why I decided to start with JQVMAPS (jQuery Vector Maps). JQVMAPS allows us to create multiple types of maps (world, USA, Europe, etc etc), all in semantic SVG, while being easily editable through the script settings.

In order to make it editable by the client, who has no code knowledge, I decided to hook it up to the Advanced Custom Fields WordPress plugin. You’ll need either the Pro version of this plugin or the add on Repeater template plugin.

When working with advanced pieces of functionality, I like to break things down into doable steps to make it easier. Here’s how we’ll break down this tutorial:

1) Let’s first get the basic plugin working
2) Then we’ll work on the map styles and custom script functions
3) Then we’ll integrate it with WordPress via ACF so it can be updated via the admin.

Let’s get started!

Step 1: Getting the basic jQuery plugin working

You’ll first need to download the jQuery plugin from the JQVMAPS site. Let’s work with the “world” version of the map.

In addition to the jQuery library, you’ll need to make sure you have the follow scripts linked in your site:

  • jquery.vmap.min.js – the basic map library
  • jquery.vmap.world.js – the world map script
  • jqvmap.css – a few styles for the plugin

I usually place all of my JS inside of an external script file, but because we’re wanting to integrate this script with WordPress, we’re going to go ahead and place the JQVMAP script in your theme’s footer file, beneath the rest of your scripts.

<script>
    jQuery('#map').vectorMap({
	    map: 'world_en',
    });
</script>

In your HTML, place an empty div with the ID of #map, or whichever you wish to use, with a set height. You should now see a very basic world map inside the div:

screenshot_465

Don’t you love it when things are this easy?

Step 2: Styling the Map & Custom Functions

Now let’s make things a bit more complicated. First, we’ll add a few parameters to tell the map what the colors of our oceans, plain countries and selected countries should be.

<script>
jQuery('#map').vectorMap({
	    map: 'world_en',
	    backgroundColor: '#d9e8e8',
	    borderColor: '#fff',
	    color: '#a8a8a8',
	    enableZoom: true,
	    showTooltip: true,
	    selectedColor: '#43af4f',
	    hoverColor: '#1384bd'
});
</script>

We’ll now want to only allow certain countries to be selected. So we’ll create a color variable for the selected color, and then pass the countries we want selected through another variable. You’ll need to select countries by using the 2 character ISO code.

Let’s use USA, France, Spain and the UK as an example. Place this above the previous code. (Remember, we’re leaving WordPress integration until the last step).

After we create the variable, we’ll pass the variable through the plugin’s “colors” parameter.

<script>
 
// Selected Country Colors
 
var color = '#43af4f';
 
// Selected Countries
 
var countriesSelected = {
    us:color, fr:color, es:color, gb:color,
}
 
jQuery('#map').vectorMap({
	    map: 'world_en',
	    backgroundColor: '#d9e8e8',
	    borderColor: '#fff',
	    color: '#a8a8a8',
	    colors: countriesSelected, // The new colors parameter
	    enableZoom: true,
	    showTooltip: true,
	    selectedColor: '#43af4f',
	    hoverColor: '#1384bd'
});
</script>

In order to disallow the hover color for the counties we don’t want, we’ll need to create one more variable for the selected countries and pass it through the plugin’s onRegionOver function, so that only the selected countries will have a hover.

<script>
 
// Selected Country Colors
 
var color = '#43af4f';
 
// Selected Countries
 
var countriesSelected = {
    us:color, fr:color, es:color, gb:color,
}
 
// Selected Countries for tooltips
 
var countriesList ='us,fr,es,gb,';
 
jQuery('#map').vectorMap({
	    map: 'world_en',
	    backgroundColor: '#d9e8e8',
	    borderColor: '#fff',
	    color: '#a8a8a8',
	    enableZoom: true,
	    showTooltip: true,
	    selectedColor: '#43af4f',
	    hoverColor: '#1384bd',
	    onRegionOver: function (event, code, region) {
	    	    // if it's not in the approved list, do nothing,
        	    // else allow normal behavior
	    	    if (countriesList.toLowerCase().indexOf(code) <= -1) {
            	    	    event.preventDefault();
        	    }
	    }
    },
});
</script>

The very last customization to the plugin we want to make, is custom tooltip text. By default, the tooltip shows the full name of the country, but we’d like to show a custom country name and a number, the number of X item in each country. We’d also like to disable tooltips from all but the selected countries.

We’ll do this by using the plugin’s onLabelShow function. First we’ll check to see if the country is a selected one. If not, we’ll disable the hover, but if so, we’ll show some custom text.

<script>
// Selected Country Color
 
var color = '#43af4f';
 
// Selected Countries
 
var countriesSelected = {
    us:color, fr:color, es:color, gb:color,
}
 
// Selected Countries for tooltips
 
var countriesList ='us,fr,es,gb,';
 
// Initialize vMap
 
jQuery('#map').vectorMap({
    map: 'world_en',
    backgroundColor: '#d9e8e8',
    borderColor: '#fff',
    color: '#a8a8a8',
    colors: countriesSelected,
    enableZoom: true,
    showTooltip: true,
    selectedColor: '#43af4f',
    hoverColor: '#1384bd',
    onRegionOver: function (event, code, region) {
        // if it's not in the approved list, do nothing,
        // else allow normal behavior
        if (countriesList.toLowerCase().indexOf(code) <= -1) {
            event.preventDefault();
        }
    },
 
    //labels
    onLabelShow: function(event, label, code) {
        if (countriesList.toLowerCase().indexOf(code) <= -1) {
            event.preventDefault();
        } else {
 
            	if(code == 'us') {
                	label.html('US <span>10</span>');
                }
 
            	else if(code == 'fr') {
                	label.html('France <span>3</span>');
                }
 
            	else if(code == 'es') {
                	label.html('Spain <span>6</span>');
                }
 
            	else if(code == 'gb') {
                	label.html('UK <span>77</span>');
                }
 
         }
    }
});
</script>

The tooltips show up as white text on a black background, but we want a custom tooltip background, a yellow box with a white border, which is easy enough to do via the CSS:

.jqvmap-label {
    background: url('http://amberweinberg.com/demos/vmaps/map-hover.png') no-repeat;
    box-sizing: border-box;
    color: #494949;
    font: 300 13px "Gotham SSm A", "Gotham SSm B", Arial, sans-serif;
    height: 62px;
    padding: 8px 5px;
    text-align: center;
    width: 61px;
}
 
.jqvmap-label span {
    display: block;
    font-size: 16px;
    font-weight: 700;
}

Step 3: Hooking it up to ACF

Now that we know the plugin is working and looking how we want, we can start hooking it up to WordPress. I’m going to assume you already have some basic knowledge of the Advanced Custom Fields plugin. If not, take a quick look at the documentation on their site. It’s pretty easy to learn! Make sure you have the plugin installed and active before going to the next step.

In your custom fields group, you’ll need to add a Repeater field with 3 subfields: one for the 2 letter country code, one for the custom country title, and the last for the number you want to display (or whatever bit of info you wish to go in the tooltip). I also advise linking to an ISO country code guide in the field instructions area so the client can easily find the countries they need to add (see the second screenshot below).

Here’s a screenshot of how my fields are set up in the fields group:

screenshot_466

and how the client will see it on their edit page.

screenshot_467

All we need to do to get this working with our map is to replace the variables up top with the repeater field template, and add the same repeater template for the custom tooltips text.

Note: Because I’m using this on the theme options page, my repeater code has an extra ‘options’ parameter. You’ll leave this out if you’re just using this on a regular page.

<script>
var color = '#43af4f';
 
    var countriesSelected = {
 
        <?php if( have_rows('selected_contries','options') ): while ( have_rows('selected_contries','options') ) : the_row(); ?>
 
        	<?php the_sub_field('country_code'); ?>:color,
 
        <?php endwhile; endif; ?>
    }
 
    var countriesList ='<?php if( have_rows('selected_contries','options') ): while ( have_rows('selected_contries','options') ) : the_row(); ?><?php the_sub_field('country_code'); ?>,<?php endwhile; endif; ?>';
 
    jQuery('#map').vectorMap({
	    map: 'world_en',
	    backgroundColor: '#d9e8e8',
	    borderColor: '#fff',
	    color: '#a8a8a8',
	    colors: countriesSelected,
	    enableZoom: true,
	    showTooltip: true,
	    selectedColor: '#43af4f',
	    hoverColor: '#1384bd',
	    onRegionOver: function (event, code, region) {
            // if it's not in the approved list, do nothing,
            // else allow normal behavior
            if (countriesList.toLowerCase().indexOf(code) <= -1) {
                event.preventDefault();
            }
        },
 
        //labels
        onLabelShow: function(event, label, code) {
            if (countriesList.toLowerCase().indexOf(code) <= -1) {
                event.preventDefault();
            } else {
 
                <?php $i=1; if( have_rows('selected_contries','options') ): while ( have_rows('selected_contries','options') ) : the_row(); ?>
 
                	<?php if($i==1) echo 'if'; else echo 'else if'; ?>(code == '<?php the_sub_field('country_code'); ?>') {
                    	label.html('<?php the_sub_field('country_label'); ?> <span><?php the_sub_field('country_number'); ?></span>');
                    }
 
                <?php $i++; endwhile; endif; ?>
            }
        }
	});
</script>

The onLabelShow function was the most “complicated”, but still relatively easy. I’m using a counter (the $i variable) so that we can give the first item an ‘if’ and the rest of the items and ‘if else’. Then I’m simply using the sub fields to populate each if statement.

Thanks to the wonders of PHP and ACF, we’re able to easily allow unlimited entries, without having to manually code anything!

See the working result:

See the Pen Integrating SVG Maps with WordPress & Advanced Custom Fields by Amber Weinberg (@amberweinberg) on CodePen.