Let’s create our BuddyPress Members Map using Vue.js.
Welcome to you.
This article will explain to you how to create a fully dynamic Google Maps of your BuddyPress Members on your WordPress site, on any page.
Easily.
This tutorial is developed as we roll out this feature to our Woffice theme, intranet/extranet WordPress solution.
It already has a members map but it was:
- 1. Not dynamic.
- 2. Using old jQuery code.
So time for a fresh look!
To follow this tutorial you need:
- A WordPress setup with
BuddyPress installed - PHP skills (OOP as well) but also WordPress development skills
- Vue.js skills (at least the basics)
- A Google cloud account to use the Maps JavaScript V3 API (to render the map) and Map Geolocation API (to convert locations into coordinates)
We have split this tutorial into two parts: Backend & Frontend.
Makes sense right?
Nothing new here. You will see it is pretty straightforward.
Before we start, this is developed within a theme, so designed for a child theme if you do not have your own theme, but it can also be used a plugin with a couple of changes.
Also, the final (working!) result can be found as a Zipped archive at the bottom of this page.
Last but not least, lots of functions will be prefixed woffice_, change that with your own prefix.
Enough talking! Let’s get started.
Part I: Create The Backend Side
In this first part of our BuddyPress Member Map tutorial, we will create our PHP Class to handle everything in this tutorial in one single place.
Then, create the Location field to collect the member’s address. Store it safely. Once done, we will have an Ajax callback setup (which will be called by our Frontend Vue.Js component).
And we’ll optimize it to use as
Getting The Member’s Location
Firstly, let’s ask a quick question: How can we collect the user’s location, easily?
No idea. Com’on
You can activate it from the Settings > BuddyPress > Components screen.
We are going to wrap all our PHP code in a class: Woffice_Members_Map, again change Woffice with your theme/plugin’s name. This class can be called from any PHP file, ideally functions.php (child or parent theme):
new Woffice_Members_Map();
We will simply create a method that will be attached to the `xprofile_updated_profile` BuddyPress action, so our code will be executed whenever someone saves its profile.
We avoid using bp_init.
Because otherwise it’s being run on every page load. However, it means you need to save your profile to generate the field. Feel free to use any other specific action, like on theme activation.
Once hooked, we run a SQL query to see if the Location field exists and otherwise we create it.
Plain and simple.
That will (should) give you a new field when you edit your BuddyPress profile. “Location”, it will hold the member’s location inside our database.
Saving The Coordinates in Our Database
We now have nice locations getting saved, but Google Map does not eat this kind of food. The diet is Geographic coordinates.
Therefore, how do we get coordinates from human-wrote locations?
Well, we use the Google API: Google Maps Geocoding API.
This API turns addresses into coordinates.
So you need to create a new Google Cloud Account (if you do not have one yet), create a new project called “Members Map” and activate this API. You can also enable the JavaScript map API as well. We will need it later on. Once both APIs created, generate API keys from the Credentials screen.
We need those.
Here is our Woffice theme’s doc article about how to get them:
Google Map Geocoding
Then, we will save all coordinates inside our database, within the wp_options table. As a new option.
Why?
Because requests are expensive to this API.
Thus, the idea is to call it only when needed, so if we already have the coordinates for one member, we don’t need it again, unless, of course, it’s being updated.
The option name in this example will be: “woffice_map_locations“. The data inside is formatted using JSON.
Let’s do it! Three new methods in our PHP Class:
- saveSingleMember() which is hooked to the `xprofile_updated_profile` action, so whenever a new member profile is saved, we will see if there is an existing entry in our option and if not, fetch the coordinates. Same if it’s being updated.
- getMemberCoordinates() which will fetch the Coordinates for a given member. That’s where we will call the API and the BuddyPress
xProfile field. - apiRequest() is a helper to call the API and returns the result.
Notes:
- We split into 3 methods because if you want to use a more complex workflow, some methods can be reused independently. Like having a button that regenerates all coordinates, we do that in Woffice and you don’t need the first method but the other two.
- We are using a Class attribute ($privateApiKey) to hold the API key, if you have a Theme Settings page, get it from there.
Cool!
So now, we can save addresses in our profile and get coordinates saved inside our database.
That really is all we need ? Here is an example of the result in the Database:
Creating The Ajax callback
In the __construct() method, let’s add our Ajax callback functions:
If you are not comfortable with how WordPress handles Ajax requests, please have a look at this article.
Also, we are using a WordPress nonce to make the request safer and make it can only be sent through our Vue.js component.
Here is the loadMembers() method that we can add in our class:
As you can see, we are also adding a `woffice_members_map_locations` filter to let any child theme or plugin add custom data to the response using a WordPress filter.
There is also a default response if there
Part I is over! As of right now, the backend part is done. No more PHP, well, almost. Here is a quick recap of what we’ve done:
- Insert automatically a new BuddyPress xProfile field in the user’s profile page to collect the Location.
- Use the Geocoding API to turn this Location into GPS coordinates and saved them inside our database in the wp_options table as a new option to save requests.
- Created an Ajax callback to return the saved coordinates as a formatted array.
Real cakewalk ?
Part II: Create The Frontend Side
What we will do in this part will be to create the Vue.js component, define it, register it and call it with a PHP function.
The goal of the component is to wrap everything in a single Vue.js component (that’s the real magic!), no dependency, just this component. Once the component loaded, it will do three pretty cool, yet simple things:
- Create the Google Map
- Fetch the Members coordinates
- Render the Members into the map
Define Our Vue.js Component
First off, create a new file called js/wofficeMembersMap.js, it will hold our Vue.js component.
We will “enqueue” it to the page’s footer within our __contstruct() method:
And therefore, also add a new method to register both the library and our component:
As you can see, we are also embedding the Google JavaScript Map API. Therefore you need to create another (different one than the one used before the backend side: geocoding process) public key.
Once done, register it in the class as a new attribute.
Once that’s set up, you will see both JavaScript assets loaded in your source code. Now, we can create the scaffolding of our component with our newly registered “.js” file:
What are we doing here?
- Creating a new Vue.js instance, that’s not a required
step, if you’re using Vue.js already. Then just register the new component to this instance instead. Vue power! - Set up the markup, very easy here as it’s going to be rendered by Google Map, not us.
- Registering our two component properties: height,
url . - Setting up the default Vue.js hooks that we are going to use. We could use some other ones as well, for the sake of simplicity, those 2 will do just fine! Make sure to
checkout this must-read doc article from Vue.js: Lifecycle diagram. - Note that we are using old JavaScript markup here because we (Woffice developers) want to keep support for old browsers and care a lot about the final bundle size. But this code is easily adaptable to ES6 using Babel. Nothing tricky.
Render The Component Using PHP
There are several ways to display the Vue.js component, we can use a PHP function like woffice_render_members_map() and call it from a template.
But we can also use a shortcode. Which offers the same advantages of the first method but on top of this, you can also use it right from the editor.
So, let’s create a new shortcode: [woffice_members_map] that you can use from your editor or using the do_shortcode() function from your template. The other advantage is that you can pass attributes later on if you want to extend it easily.
Nothing new here, we need to register it from our __contstruct() method.
And then, the method itself that will simply output the Vue.js component with some HTML markup.
We also pass attributes directly there to avoid using a “Data exchanger” (registering a JavaScript object in the wp_footer hook on the PHP level to pass data between PHP and JavaScript).
Create The Google Map
At the same time, we are simply going to create a new method in our component: createMap().
Which will? … … Create the map!
Not original, but makes sense.
That method will set the map’s height and use the Google Map API to generate a simple map:
Did you notice? We are using the famous component’s data object to store the map’s zoom level and center. Feel free to improve it and use shortcode/coordinates attributes. Moreover, you can use this website to get the Latitude and Coordinates of any address.
This is a VERY simple example, you can make it a LOT more complex (custom style, custom controls, animations…).
Google showcases an excellent documentation on this API. So when you use [woffice_members_map] in any post or page, you should (will, I hope) see:
Fetch Our Members
Okay, so we have a map.
How about we now call the Ajax callback we have defined in the first step to fetch our Members coordinates from our database and render them? Sounds good.
Update the mounted() hooks to call a new method that we will define under the methods: {} object:
Couple of things to notice here:
Firstly, we are using a “WordPress nonce” to secure the request.
Secondly, we store the fetched members coordinates in the data object to be able to use it easily in any other method of our component.
Once done, we call a new method: drawMarkers().
See the next section ?
Last but not least, install the Vue.js dev tool. You will be able to visualize the data:
Add The Markers To The Map
Finally, here we are, the last step!
We now have a map and members coordinates, how about we do some cooking to mix them?
Sounds good to me.
Nothing fancy, let’s define the drawMarkers() method called in the last method in the fetch members’ success callback function. This method will go through all member locations we received from our backend and create a Google Map marker (more details here).
Then, we will use the user’s info, that we pass as well in the Ajax PHP callback to have some HTML markup inside the map marker. Again, easy-peasy.
As you very likely have guessed, we are using a child theme in this tutorial for our Woffice theme.
Which provides Bootstrap 4 out of the box, so no CSS, yay! I just used helper classes to get a “nice” (not bad) layout inside my marker:
Which is our final result! Just this? Wait, that’s a simple example, it’s super flexible, will support as many members you want, you can change the content, style, animations, marker and a lot more.
You can see some cool examples in our Eonet and Woffice members demo pages.
In summary, what we have done in this frontend part is:
- Add Vue.js and the Google map public librairies to our frontend side. Plus, registering our own Vue.js component.
- Create a Google Map using the Google Map API v3.
- Fetch our members using the Ajax callback we have defined in the first step.
- Render the members in the map using some pretty cool map markers.
Conclusion
Hope you liked it! You are now able to create your own BuddyPress Members Map.
For any detail or improvement you have in mind, please use the comment section below.
This being said, a couple of final notes here:
- Vue.js can be added to WordPress, VERY easily. It’s dynamic and easy to develop with. Use ES6 if you can.
- If you have many members and they “step” on each other, consider using Marker clusters (see this article).
- Finally, This tutorial was designed to be as simple as possible, there are dozens of improvements you can apply: using theme options, custom attributes, better marker markup, custom map style, better error handling and so on.
You can find the complete code working in a Woffice child theme in this .zip (no, I won’t collect your email address!).
Want to create your own WordPress plugin? Check out this article.
Thanks for reading and see you in the next one!