Implement the WordPress Geolocation Plugin

For a while now WordPress has had apps across the mobile spectrum, and a great feature of these is geolocation - great, but who wants to know where I'm blogging from right? Well recently I had to build a blog for someone travelling around the world, and it quickly became apparent that using the data saved by the app on the site would be a great feature. In this tutorial we'll see the basic implementation of adding the plugin, but more importantly look at how we can then plot a route across the globe using data from every post. So let's get started!

First off you'll need to go and grab the Geolocation plugin and install it on your site. The default behaviour of this plugin is to insert a link at the bottom of single posts and show a map to users when they hover over it. But what if we want to show the map by default? And what about using all that geolocation data from each post? Well the first request is relatively simple - in fact it's just a change of CSS. Here's the alteration to style.css in the goelocation folder:

#map { background: #fff; border: solid 1px #999; padding: 20px; visibility: hidden; }
.home #map { display: none; }

The second rule is useful if you use the the_content() on your home page, this is because only 1 map is actually used for every post meaning that otherwise you'll just have a big empty div.

Plotting your posts on a map

Here's the exciting bit, to begin with we'll look at creating a route out of post data, and displaying it on a nice big map. Thankfully the WordPress app doesn't use anything big, scary, or evil to store its data, it just stores it as a custom variable! So accessing the data is easy as pie! Now in this case I'm assuming that you're whacking the PHP code in something like map.php - a template for a page, and that the JavaScript coming later will be in footer.php - this is important because the JS will be using a PHP variable - namely the coordinates to plot. If you have a different structure, you'll need to find some way of getting this data from PHP, either via an AJAX request, or clever script positioning. Let's take a look at how we'd go about getting all of this data into our PHP backend, before utilising it with the Google Maps JavaScript API:

<?php 
    $points = '';
    query_posts('posts_per_page=500'); 

    while ( have_posts() ) : the_post(); 
    
        $points .= '(' . get_post_meta($post->ID, 'geo_latitude', true) . ',' . get_post_meta($post->ID, 'geo_longitude', true) . '),';  

    endwhile; 
    
    $points = substr($points, 1, -2); // Remove the initial '(' and final '),'
?>

<div id="canvas"></div>

So above we have the standard WordPress loop that cycles through the 500 most recent posts (courtesy of query_posts()) - this should all be familiar. Inside the loop we keep adding to the $points variable in the format (latitude_1, longitude_1), (latitude_2, longitude_2) and so on. We use the handy get_post_meta() function (here's the reference), to get the coordinates, and we end by removing the first bracket and last bracket and comma - we do this because when we switch to JS we need a clean array. Finally we have a div with the ID "canvas" - this is where we'll put our map - so feel free to style this in your CSS, I added the following to the theme's style.css:

#canvas {
    height:600px;
    width: 96%;
    margin-left: 2%;
}

And now we're ready to move into the crazy realm of JavaScript!

Luckily for us the Geolocation plugin already takes care of adding the Google Maps API v3, so we can get straight into using it with our site! But before we get into our JavaScript we're going to be good coders and only deliver our code to users on the map page, so we'll use yet another handy WordPress function to detect when we're on the map.php template page. Go ahead and whack this into footer.php:

<?php  if ( is_page_template('map.php') ) : ?>

     /* JS goes here... */

<?php endif; ?>

Now let's get to the really meaty code. The code below uses 1 jQuery call, and it's just to check that the DOM is fully loaded, so you can use any equivalent function or whack the code into onload="" in the body tag. First up we'll look at getting the data from PHP and making it usable, put the following code within <script> tags:

function init(){
    var p = "<?php global $points; echo $points; ?>", mapCoords = null;
	
    p = p.split("),(");
	
    for(var x = 0; x < p.length; x++){
        p[x] = p[x].split(",");
        if(mapCoords == null){
            mapCoords = [new google.maps.LatLng(p[x][0], p[x][1])];
        }else {
            mapCoords.push(new google.maps.LatLng(p[x][0], p[x][1]));
        }
    }	
	
    newMap('canvas', mapCoords);
}


$(function(){ init(); });

So the function above begins by taking the data we just extracted using PHP and puts it into a variable called p, we also define one called mapCoords. Then we turn p into an array by splitting up each pair of coordinates, before jumping into a for loop. If you've not used the Google Maps API before this may look a little daunting, but it's fairly simple once you get started. First off we set up our loop to cycle though every set of coordinates in our array, and once inside we split our coordinates into longitude and latitude and store that array in p. Then we check to see if mapCoords is empty, if it is we use square brackets to create the array, otherwise that's the only difference. Then we add a new value to the mapCoords array - this value is a special object provided by the API for processing points on the map, and we just have to pass it the relevant values for the longitude and latitude. Once the loop is complete, we call a mysterious function named newMap(), and pass it the ID of our map canvas, as well as our newly created route coordinates. Lets take a look at how we implement this new function.

function newMap(id, mapCoords){
    var centre = (new google.maps.LatLng(51.44031275716014, 0.3955078125)),
	zoomLevel = 6,
        route,
        myOptions,
        map;
	
    route = new google.maps.Polyline({
        path: mapCoords,
        strokeColor: "#2324e4",
        strokeOpacity: .70,
        strokeWeight: 7,
        editable: false
    });
		    	
    myOptions = {
        center: centre,
        zoom: zoomLevel,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
		
    map = new google.maps.Map(document.getElementById(id), myOptions);
    route.setMap(map);
}

First up we define a few variables: the map centre - as it appears to the user (here it's somewhere between the UK and France), zoom level - 6 will zoom pretty far out (16 is street level), and the route - we'll add to this soon. Then we make use of our route variable - this is a line that will be drawn on our map and will represent the route between posts. There are a number of options here, but the most important is the 'path' - we'll set it equal to the coordinates passed to our function. Next up we define some options for our map and put them into myOptions. Here we set the centre and zoom level - as defined above, as well as the type of map we want to display - here we've created a road-map. Finally we create our map, and tell our route that it needs to draw itself on that map.

Up to this point the code we've written will draw a blue line on your map, so if that's all you need you're done! But if you want to add your posts to the map as markers read on!

Plot Posts with Pins

Now it might be the case that you don't want a route plotted, or maybe you want a route with pins indicating where you've posted from - and once you've implemented the back-end above its remarkably simple. The only difference is that because we'll want to show the user an info window we'll need to store the names, dates, and links for our posts. This just requires a simple modification of the backend:

<?php 
    $points = '';
    $thePosts = '';

    query_posts('posts_per_page=500'); 

    while ( have_posts() ) : the_post(); 
    
        $points .= '(' . get_post_meta($post->ID, 'geo_latitude', true) . ',' . get_post_meta($post->ID, 'geo_longitude', true) . '),'; 
        $thePosts .= '(' . get_the_title() . '|' . get_permalink() . '|' . get_the_time() . '),';
    endwhile; 
    
    $points = substr($points, 1, -2); // Remove the initial '(' and final '),'
    $thePosts = substr($thePosts, 1, -2);
?>

<div id="canvas"></div>

So the only difference here is that we've now got another variable named $thePosts - which holds the title, permalink, and time posted for each post. We'll do essentially the same to this when we get into the JavaScript, and then we can use the data on the map. Notice I've used a pipe character (|) as the delimiter as it's common to have commas in titles. So lets take a look at the init() function in our JavaScript:

function init(){
    var p = "<?php global $points; echo $points; ?>", mapCoords;
	
    p = p.split("),(");
	
    for(var x = 0; x < p.length; x++){
	p[x] = p[x].split(",");
	if(mapCoords == null){
		mapCoords = [new google.maps.LatLng(p[x][0], p[x][1])];
	}else {
		mapCoords.push(new google.maps.LatLng(p[x][0], p[x][1]));
	}
    }	
	
    /* Create posts array */
    var posts = "<?php global $thePosts; echo $thePosts; ?>";
    posts = posts.split('),(');
	
    for(var x = 0; x < posts.length; x++){
	posts[x] = posts[x].split('|');
    }
	
    newMap('canvas', mapCoords, posts);
}

Here we've just added another variable and a for loop - notice this is above the newMap() call. We'll also alter this function to accept the posts variable. Now that we've got our variables set up, we can get into changing up our hefty newMap() function. But before we get to that we need to define a global variable that we'll use in the function, so go ahead and make a global variable like so:

var infowindow = new google.maps.InfoWindow();

This variable will be used to display an information window when the user clicks on a point, and we can utilise the handy API once again to do this. Now we can get into the juicy function to create our map:

function newMap(id, mapCoords, posts){
    var centre = (new google.maps.LatLng(51.44031275716014, 0.3955078125)),
	zoomLevel = 6,
        route,
        myOptions,
        map;

    route = new google.maps.Polyline({
        path: mapCoords,
        strokeColor: "#2324e4",
        strokeOpacity: .70,
        strokeWeight: 7,
        editable: false
    });
		    
    myOptions = {
        center: centre,
        zoom: zoomLevel,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    map = new google.maps.Map(document.getElementById(id), myOptions);
    route.setMap(map);
    
    // New code starts here
	
    function getInfoWindowEvent(marker, x) {
	infowindow.close()
	infowindow.setContent('<div class="infowindow"><a href="'+posts[x][1]+'"><strong>'+posts[x][0]+'</strong><br>'+posts[x][2]+'</a></div>');
	infowindow.open(map, marker);
    }
    
    var markers = [];
    
    for(var x = 0; x < mapCoords.length; x++){
        markers[x] = new google.maps.Marker({    
	    position: mapCoords[x],    
	    map: map,
	    icon: 'http://example.com/images/pin.png' // Remove this to use the default pin
	});
	    
	google.maps.event.addListener(markers[x], 'click', (function(x) {
	    return function(){ 
		getInfoWindowEvent(markers[x], x);
	    }
	})(x));			
    }  
}

Notice the comment about half way through - I'll begin explaining the code from there onwards.

First up we create ourselves a function called getInfoWindowEvent() - this will be used to move our info-window that we defined earlier around the map and to put our post content into it each time a point is clicked. The HTML inside the setContent() function is entirely up to you, so feel free to play with the styling and organisation of the code. Next up we create a new array called markers[] - this will hold every marker for the map. Then we have a for loop to iterate over every set of map coordinates that we have. Inside the loop we first create a new marker - the options here should be fairly obvious, but the icon one is entirely optional, remove it to use the default, well-known pin icon, otherwise supply a valid URL. Once we've got our array of markers we need to add event listeners to get ready for click events. The function we use simply calls the getInfoWindowEvent() function with the appropriate variables, namely the marker that has been clicked, and the index of that marker.

As a little side-note, if you want your own, custom pin on single post pages for the map, it's simply a matter of replacing img/wp-pin.png, and for greater customisation there's also wp_pin_shadow.png.

And that's it! You should now have a beautiful, dynamic map displaying all your posts - perfect for travel blogs!

Publishing to WordPress from outside the admin panel

Note: This article has been marked for a quality review and will soon be updated.

I recently finished up a theme for which I had to allow users to post to WordPress from outside the admin panel. Now at first you may wonder why anyone would want to do such a thing, but let me tell you of my scenario. Basically I was creating a job board whereby users could post a job from a specific page - this meant that the numerous custom fields in operation could be handled in a rather aesthetically pleasing fashion and it would be a lot simpler for the user to get their job listed. Now the reason I'm posting this article is because this subject isn't well documented and I had to play around for quite a while before I could get it to work, so I hope that I can save you some frustration in sharing my code.

So what do we have to do first? Well we need to replicate the core features of the new post page in the admin panel of WordPress, this means replicating things such as the title and content fields, the category options, and the tags area. So set up all the required fields and any custom fields you want to include. Once you've done this you will need to create a separate file to post the information to, let's call it new-post.php. Set your form to post to this file, and then paste in the following code.


$title = stripslashes($_POST['title']);
$body = $_POST['body'];
$rpcurl = $_POST['rpcurl'];
$username = $_POST['user'];
$password = $_POST['pass'];
$category = $_POST['category'];
$keywords = $_POST['tags'];
$encoding = 'UTF-8';

$title = htmlentities($title,ENT_NOQUOTES,$encoding);
$keywords = htmlentities($keywords,ENT_NOQUOTES,$encoding);

$content = array(
'title'=>$title,
'description'=>$body,
'mt_allow_comments'=>0,  // 1 to allow comments
'mt_allow_pings'=>0,  // 1 to allow trackbacks
'post_type'=>'post',
'mt_keywords'=>$keywords,
'categories'=> array($category=>$category),
)

);
$params = array(0,$username,$password,$content,true);
$request = xmlrpc_encode_request('metaWeblog.newPost',$params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_URL, $rpcurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$results = curl_exec($ch);
curl_close($ch);

Right, now that's quite a lot of code, allow me to explain. You can see all of those variables at the top - these are to be use further down and are given the values of what's posted to them. Title, body, category, and keywords are self-explanatory, however there are a number of other variables which appear to require some post variables - so what are they? $rpcurl is simply the ping-back URL of your blog - which is a URL that allows others to interact with your blog. The username and password variables must be valid credentials for the blog - this is because WordPress needs to verify that the person posting the post is allowed to do so. And finally the encoding variable is simple the way in which the content should be encoded - the default and most common is simple UTF-8 - and doesn't need to be changed.

So you know what the variables are, but how on earth do you get them to the file? Well personally I used AJAX to submit the form and so just sent the data in a data-string, but if that sounds too much like hard work, feel free to just use some hidden fields. To access the required data you can use the bloginfo() function for things like the "pingback_url". Now one thing that will require user input is the password variable, this is because it is impossible to obtain the user's password as it is stored as an encrypted hash, so I'd recommend that you add it as a security feature where you ask users to enter their password before posting - that way it'll be accessible to you.

The rest of the code simply posts all the info to the actual blog, and uses the ping-back URL to do so by inserting all of those lovely variables into place and then sending it over to WordPress to do all the hard work.

While this is a bit of an obscure function I think it's nice to know it can be done, and I hope this article can save some people the hassle that I had to go through to get the correct method and syntax.

 

Update

It has come to my attention that the method listed above might be a little hard to integrate into a WordPress theme, so below is the code for a form with which you could use the above method, to post to WordPress from outside the admin panel. Let's get started with the form.

<form id="post" name="post" action="post.php" method="post">

<label for="title">Title</label>
<input type="text" name="post_title" />

<label for="desc">Content</label>
<textarea name="content"></textarea>

<label for="category">Category</label>
<input name="category" type="text" />


<label for="title">Tags</label>
<input type="text" name="post_tags" id="tags" value="e.g. Graphic, Designer, HTML" onfocus="if (this.value == 'e.g. Graphic, Designer, HTML') {this.value = '';}" onblur="if (this.value == '') {this.value = 'e.g. Graphic, Designer, HTML';}" />

<p>Please verify the details above and then enter your password to complete the process.</p>
<p>&nbsp;</p>
<label for="password">Password</label>
<input type="password" name="password" id="password" />
<input type="submit" value="Submit" />
</div>
</form>

So that's a pretty standard form to which you can do whatever you like, but not the names of the fields as they will be important when we come to using the data stored in them. Next I'm going to use AJAX to post the form to the code which will post the WordPress, for the sake of this tutorial I'll assume that the code at the beginning of this tutorial is in a file called post.php. So go ahead and stick this somewhere on your page (Note: You will need to include jQuery for the following Javascript to work.

$("#post").submit(function(){
	var title = $("#post input[name=post_title]").val();
	var body = $("#post textarea[name=content]").val();
	var category = $("#post select[name=category]").val();
	var tags = $("input[name=post_tags]").val();
	
	var pass = $("#password").val();
	
	if(title=="" || body=="" || pass==""){
		alert("Please fill in all of the fields!");
		return false;
	}else {
		verify = true;
		
		var dataString = 'title=' + title + '&body=' + body + '&rpcurl=&user=user_login ?>&pass=' + pass + '&category=' + category + '&tags=' + tags;
		$.ajax({
			type: "POST",
			url: "post.php",
			data: dataString, 
		}   		
	});
	return false;
}

Okay then what do we have here? Well first off all the code is wrapped in a submit() function, which waits for the form to be submitted, and then executes the code inside. Just below this we assign the values of the inputs from the form, to variables, and then check to see if some of the fields are empty, the ones that are important that is. If any of them are empty then we alert the user and stop the form from going submitting. However if it's all good we then use the jQuery AJAX function to post all the information we have to our post.php file to be processed. Notice that we ask the user to verify the information entered by asking them to enter their password - this is a sneaky way of grabbing their password, and allows us to proceed with processing the post.

And that's that! Hopefully the above code has helped you to understand better how to integrate the code into a WordPresss environment, and if you're a little confused by the AJAX or just don't want it in your code, feel free to just make the form post directly to post.php, and you should be good to go.