A neat bit of coding by Justin Adie that lists all the locations covered by followtheboat. The links are clickable but be aware that clicking on a link like ‘Green Island’ will bring up all blog posts that contain the words ‘green’ or ‘island’. Alternatively use the search bar at the top of the page.

[separator top=”40″ style=”none”] [insert_php] /*
Plugin Name: 3-tier Hierarchy
Plugin URI: rathercurious.net
Description: Plugin to create a clickable tree of unrelated custom fields.
Version: 0.1.2
Author: Justin Adie
Author URI: rathercurious.net
*/

class crlHierarchy{

private $flush = false; //set to true to flush the cache

/**
* constructor method to set variables and start the data gathering
*
* @return
*/
public function __construct(){
global $wpdb;
$this->tmpTable = $wpdb->prefix . “tmpLoc”;
$this->flush = false;
$this->debug = false;
if ($this->debug){
ini_set(“display_errors”, true);
error_reporting (E_ALL ^ E_NOTICE);
}
$this->url = $url = get_bloginfo(‘url’);
$this->dir = sys_get_temp_dir();
$this->cache = realpath($this->dir . “/WP_FTP_CACHE.txt”);
}

/**
* method to gather the data and display the hierarchy as a multi LI tree
* @return
*/
public function displayTree(){
$this->getOutput();
if ($this->debug){
echo “

Current shape of the object:

".print_r($this, true)."

“;
}
echo $this->output;
}

/**
* method to check the cache status and grab the output either from the cache or the internal methods
* @return
*/
private function getOutput(){
global $wpdb;
if (file_exists($this->cache)){
if ($this->flush){
unlink ($this->cache);
$this->getData();
$this->generateOutput();
$this->_unset($this->rawResults);
$this->cacheResults();
} else {
clearstatcache();
$lastMod = fileatime($this->cache);

//now get latest post mod time
$query = “Select max(post_modified_gmt) from $wpdb->posts”;
$postLastMod = $wpdb->get_col($query);
//convert to unix
$postLastMod = strtotime($postLastMod . ” GMT”);
//compare the two values
if ($lastMod >= $postLastMod){
$this->output = file_get_contents($this->cache);
} else {
$this->getData();
$this->generateOutput();
$this->_unset($this->rawResults);
$this->cacheResults();
}
}

} else {
$this->getData();
$this->generateOutput();
$this->_unset($this->rawResults);
$this->cacheResults();
}
}

/**
* semi-overloaded method for stubbing off a variable unset.
* @return
* @param object $var
*/
private function _unset(&$var){
if (!$this->debug){
unset ($var);
}
}

/**
* method to cache the html of the tree in the filesystem
* @return
*/
private function cacheResults(){
file_put_contents($this->cache, $this->output);
}

/**
* method to transform arguments into a clickable link that can be used with the existing search facility back end
* @return
* @param string $text
* @param string $country
* @param string $region[optional] * @param string $location[optional] */
private function makeLink($text, $type){
$_text = urlencode($text);
return “url}?metaFilterKey=$typey&s=$_text\”>$text“;
}

/**
* method to create a temporary table, write data to it and then retrieve the data hierarchically
*
* @return
*/
private function generateOutput(){
global $wpdb;
if ($this->debug){
$wpdb->show_errors(true);
}
$query = <<tmpTable} (
country VARCHAR( 255 ) NOT NULL ,
region VARCHAR( 255 ) NULL ,
location VARCHAR( 255 ) NULL
);
SQL;
$wpdb->query($query);
//flush the table
$query = “DELETE FROM {$this->tmpTable}”;
$wpdb->query($query);

/*
$query = <<query($query); */
$_q = ”;
foreach ($this->rawResults as $data){
$country = (empty($data[‘country’]) ? ‘null’ : $wpdb->prepare(“%s”, $data[‘country’]));
$region = (empty($data[‘region’]) ? ‘null’ : $wpdb->prepare(“%s”, $data[‘region’]));
$location = (empty($data[‘location’]) ? ‘null’ : $wpdb->prepare(“%s”, $data[‘location’]));
$_q[] = “($country, $region, $location)”;
}
$query = “insert into {$this->tmpTable} (country, region, location) values ” . implode (‘,’, $_q);
$wpdb->query($query);

//manage output now
//get countries
$countries = $wpdb->get_col(“select country from {$this->tmpTable} group by country order by country asc”);
$output = <<

HTML;
foreach ($countries as $country){
$_country = trim($country) ==” ? “No country specified” : trim($country);
$output .= <<

{$this->makeLink($_country, ‘country’)}

HTML;
//get regions for this country
$query = $wpdb->prepare(“select region from {$this->tmpTable} where country=%s group by region order by region asc”, $country);
$regions = $wpdb->get_col($query);
if (empty($regions)){

} else {
//iterate the regions
/********* REGIONS *********/
$output .= <<

HTML;
foreach ($regions as $region){
$output .= << {$this->makeLink($region, ‘region’)}

HTML;
/********* LOCATIONS *********/
$query = $wpdb->prepare(“select location from {$this->tmpTable} where country=%s and region=%s group by location order by location asc”, $country, $region);
$locations = $wpdb->get_col($query);
if (empty($locations)){

} else {
$output .= <<

HTML;
foreach ($locations as $location){
$output .= << {$this->makeLink($location, ‘location’)}

HTML;
}
$output .= <<

HTML;
}
/********* END LOCATIONS *********/
$output .= <<

HTML;
}
$output .= <<

HTML;
/********* END REGIONS *********/
}
$output .= <<

HTML;
}
$output .= <<

HTML;
$this->output = $output;
}

/**
* method to query the postmeta table and return all the necessary data in an multidimensional array
* @return
*/
private function getData(){
global $wpdb;
$query = <<postmeta}
WHERE LOWER( meta_key )
IN (
‘country’, ‘region’, ‘location’
)
ORDER BY LOWER( meta_key ) ASC , LOWER( meta_value ) ASC
SQL;
$results = $wpdb->get_results($query, ‘ARRAY_A’);
foreach ($results as $result){
$type = strtolower($result[‘meta_key’]);
$this->rawResults[$result[‘post_id’]][$type] = $result[‘meta_value’];
}
}
}
$crlHierarchy = new crlHierarchy();
[/insert_php] [insert_php]$crlHierarchy->displayTree();[/insert_php]