Coded something up in Couch in an interesting way? Have a snippet or shortcode to share? Post it here for the community to benefit.
10 posts Page 1 of 1
This tutorial will detail how to set up a search feature that can sort cloned pages based on physical distance. The most common use of this is as a Store Locator: a visitor searches with their own Postal Code (PC) and a listing is generated with the closest locations. The example code that follows makes use of the 5-digit US ZIP Code and miles unit of length. With minor modifications it can accommodate any other Postal Code format and unit of length.

example.png
example.png (9.45 KiB) Viewed 43392 times

Central to making all of this work is acquiring a database with the required fields: postal code, latitude, and longitude. I have attached a US ZIP Code table which was originally sourced from GeoNames. This organization has PC tables for many countries: http://download.geonames.org/export/zip/
us-postal-codes.zip
(273.77 KiB) Downloaded 844 times

Instructions:
1. Import your PC data into a new table in the same MySQL database as your Couch installation. When you do this, select CSV as the file format. If you are using a txt file directly from GeoNames you will need to change the column delimiter to a tab character: \t

From there you may choose to drop any of the unused columns and change their names. See the screenshot below for how my table is structured.
structure.png
structure.png (42.88 KiB) Viewed 43392 times

2. Download the attached PostalCode PHP Class and Couch example template. For this example I have set up the Search template as the clonable template as well. In a real-world implementation of this however, you will want to use a different template for the cloned pages.

Also hosted on GitHub at https://github.com/cheesypoof/CouchCMS-Postal-Code-Search.
search.zip
(2.63 KiB) Downloaded 801 times

3. Install the template as you would normally and add a few example pages like I have done to test the functionality:
Beverly Hills, California - 90210
Los Angeles, California - 90035
Las Vegas, Nevada - 89104
Seattle, Washington - 98101
Dallas, Texas - 75201
Chicago, Illinois - 60606
Miami, Florida - 33139

4. Open postalcode.php and set the top variables according to your configuration. Test everything out.

Notes:
This requires at minimum Couch v1.3.5 to be installed because the cms:query tag is utilized.

Generally speaking, as the range increases, so too does the completion time of the Postal Code query. For example, in a test I used 2500miles and experienced a page load time of 1400ms, whereas for 250miles I saw only 460ms. You will need to test this on your server to determine what maximum load times are acceptable.

Distance calculations should be considered approximations; I can't vouch for the accuracy of the GeoNames location data.

Internationalization:
In the example, we displayed the distance in miles as follows: <cms:number_format distance decimal_precision='0'/>
We can display this in kilometers as follows: <cms:number_format "<cms:mul distance '1.60934'/>" decimal_precision='0'/>

To accommodate differently formatted Postal Codes you will need to modify the editable region validator regex.

Links:
PHP ZipCode Class (GNU General Public License v3) - https://github.com/Quixotix/PHP-ZipCode-Class
GeoNames (Creative Commons Attribution 3.0 License) - http://www.geonames.org/
Thank you cheesypoof :)
Hi,

I've been looking for a way to do a similar solution but using location name rather than postal code. Do i need to develop a different solution or can i use this as the basis in which i can do a search by the name and not postal code?
It has been a while since I have looked at the code, but I think this solution could just as easily work with city names.

You would create a city editable region for the relevant clonable template and use that value in the query on the page view. The miles range value could be hard-coded or sourced from another editable region.

Let us know if you have any difficulty implementing this.

For reference, this reply relates to viewtopic.php?f=4&t=8962.
Thank you so much @cheesypoof for your reply. Yes, i do have difficulty implementing this as i cannot find the documentation/tutorial/guide that would guide me on how to use cms:php and $CTX and cms:query to query the couchDB using my own php but within the <cms> code.

Could you guide me on where i can find documentation for the tags that would allow me to query the table created from GeoNames and use it to populate option values in the editable section of the admin panel?

I will be very grateful if you can provide a sample that i can build on. if not please point me to materials or discussions that cover this kinds of use cases.

Thank you.
After reading through various solutions in the forum, i have tried to code my own solution [that will load the name and its corresponding latitude and longitude to the option tag in the admin section].

I have created an editable region in my locations.php masterpage > like this:

<cms:editable name="hire_location"
label="Hire Location"
opt_values='my_dynam_locs.inc'
dynamic='opt_values'
type='dropdown'
group='geoloc' />

---------------------------------------------
The source of my_dynam_locs.inc is as follows:
---------------------------------------------

Code: Select all
<cms:php>
<cms:query= "SELECT * FROM hdcouch_car_hire_location"; />
$result = $conn->query($sql);
if ($result->num_rows > 0) {
    // output data of each row
    while($row = $result->fetch_assoc()) {
        echo "<ol> <li> Name: " . $row["name"]. " - Location: " . $row["longitude"]. "," . $row["longitude"]. "</li> </ol>";
    }
} else {
    echo "0 results";
}
$conn->close();
?>
</cms:php>


When i run it i get the following error:

Fatal error: Call to a member function query() on a non-object in C:\wamp\www\hired\app\tags.php(2823) : eval()'d code on line 3

I don't understand this error, kindly help me to see what i am doing wrong.
I envisioned simply using a text field as the number of cities could potentially be astronomical.

Please see viewtopic.php?f=5&t=7377 for a description of cms:query usage. You shouldn't need to utilize any PHP... Additionally, options are specified in the following format for dropdown regions:
Code: Select all
Option 1=opt1value | Option 2=opt2value
Hi @cheesypoof,

I love your code above for the postal code lookup :)
But now I run into some problems.
In Belgium there are quite a few cities with the same zip code.
As a result, I get several same data in the search, but with a different range.

Is there a possibility to link the city to the zip code? I myself am not very skilled with php and mysql.

Thanks in advance
Greetings
Bert

Example of database
Image

Example of front-end result
Image
Is there a chance someone can help me with this.

Bert
Hi guys,

I'm trying to code up a solution that does not use a separate database with postal codes (because it gets outdated quite soon here in the Netherlands). But use Google's geolocation API in stead. I just cannot wrap my mind around removing the part where the geolocation is determined in the postalcode.php script.

My plan:
Step 1: Convert adress to latitude and longtitude, using this code:
Code: Select all
<cms:php>
   global $CTX, $FUNCS;
   $address = "<cms:show adres/>";
   $address = str_replace(" ", "+", $address);
   $url = "https://maps.google.com/maps/api/geocode/json?address=".urlencode($address)."&key=[API KEY]";

   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);   
   $responseJson = curl_exec($ch);
   curl_close($ch);

   $response = json_decode($responseJson);

   if ($response->status == 'OK') {
      $latitude = $response->results[0]->geometry->location->lat;
      $longitude = $response->results[0]->geometry->location->lng;
      $CTX->set( 'newlat', $latitude );
      $CTX->set( 'newlong', $longitude );
      
      
   } else {
      echo $response->status;
      var_dump($response);
   }   
   
</cms:php>


Step 2: Search my database for nearby dealers by latitude and longtitude. The dealertemplate (dealers.php):
Code: Select all
<cms:template title="Dealers" clonable="1">

<cms:editable type="text" name="latitude"/>
<cms:editable type="text" name="longtitude"/>

</cms:template>
10 posts Page 1 of 1