<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nettuts+ &#187; CMSs</title>
	<atom:link href="http://net.tutsplus.com/category/tutorials/cmss/feed/" rel="self" type="application/rss+xml" />
	<link>http://net.tutsplus.com</link>
	<description>Web Development &#38; Design Tutorials</description>
	<lastBuildDate>Thu, 18 Mar 2010 17:46:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Building your First ExpressionEngine Plugin</title>
		<link>http://net.tutsplus.com/tutorials/cmss/building-your-first-expressionengine-plugin/</link>
		<comments>http://net.tutsplus.com/tutorials/cmss/building-your-first-expressionengine-plugin/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 18:47:00 +0000</pubDate>
		<dc:creator>Erik Reagan</dc:creator>
				<category><![CDATA[CMSs]]></category>
		<category><![CDATA[ee]]></category>
		<category><![CDATA[expressionengine]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=7522</guid>
		<description><![CDATA[<img src="http://nettuts.s3.cdn.plus.org/290_ee/200x200.png" alt="Building your First ExpressionEngine Plugin" />]]></description>
			<content:encoded><![CDATA[<p>No matter how awesome a CMS is, there will be times when you are required to meet a specific need that simply doesn&#8217;t work out of the box. Here we will explore creating Plugins for ExpressionEngine to meet such needs.
</p>
<p><span id="more-7522"></span></p>
<h3>Version Notes</h3>
<blockquote>
<p>
   Just recently EllisLab, the creators of ExpressionEngine, announced the official release date of ExpressionEngine 2.0 as being December 1st, 2009. Please note that this tutorial is written with details specific to versions 1.6.x. Certain details such as file paths and global objects will be changing for version 2.0. While these details will be different the general application and approach to plugin creation for ExpressionEngine will remain the same.
</p>
</blockquote>
<h3>Types of ExpressionEngine Add-Ons</h3>
<p>
   Like most robust management systems available, ExpressionEngine, or &#8220;EE&#8221;, comes with a number of ways for a developer to add functionality that may not be there by default. Unlike popular systems like WordPress, EE has different names for these add-ons depending on how they interact with your site. There are three primary ways you can add functionality to EE 1.6.x which are Plugins, Extensions and Modules. Plugins primarily deal with modifying your template code and tend to be more of a front-end job. Extensions typically tweak the functionality of the back-end, or Control Panel by tying into &#8220;hooks&#8221; in the system. Modules tend to be larger in scope, have their own area in the Control Panel and can also be used on the front-end of the EE website. Modules can be full blown apps sitting within EE and utilizing membership, templates, database, etc.
</p>
<h3>Required Experience</h3>
<p>
   Things it would sure help to know before moving forward:
</p>
<ul>
<li>How to setup and install ExpressionEngine in a development environment</li>
<li>Basic understanding of ExpressionEngine&#8217;s Control Panel and template parsing</li>
<li>Basic understanding of PHP and Object Oriented programming</li>
<li>How to read documentation!</li>
</ul>
<h3>Our Plugin</h3>
<p>
   For this tutorial we are going to create a simple plugin that scans through the data passed to it and wraps certain strings with HTML tags. This is a very simple application of an EE plugin and should show you how easy it is to get started with plugin development. Our plugin will be used to search for and replace acronyms that we use as developers. For the sake of the example we will stick to three: HTML, CSS, and RSS. Let&#8217;s call the plugin &#8220;Auto Acronym.&#8221;
</p>
<h3>Where Do I Start?</h3>
<p>
   The best place to start with EE Add-On development is the <a href="http://expressionengine.com/docs/development/index.html">official ExpressionEngine Documentation</a>. Before you dive into developing for ExpressionEngine you should read through their guidelines which, if followed, help keep the system running well. The guidelines cover things like naming conventions, performance and security. I&#8217;ll give you a few minutes to read over the <a href="http://expressionengine.com/docs/development/guidelines/index.html">ExpressionEngine Add-On Development Guidelines</a>
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/1.jpg" border="0" style="width: 600px;" /></div>
<p>
   Okay, now that you&#8217;ve read that we can start looking at how we actually create the plugins and what makes up a simple one.
</p>
<h3>Pieces of the Puzzle</h3>
<p>
   Every plugin requires one class and at least one function. The naming convention is very specific so we need to make sure we do it correctly and carefully. The name of our plugin is Auto Acronym and it comes into play with our file name, class name, and EE tags. The file name takes the name of your plugin and replaces all spaces with underscores while prepending &#8220;pi.&#8221; to the front. All letters must be lower case. That would make our file name &#8220;pi.auto_acronym.php&#8221;. All EE plugins go into a single directory located under system/plugins (imagine that).
</p>
<p>
   The class name is similar to the file name with the exception of the first letter being capitalized. This makes our class name &#8220;Auto_acronym&#8221;. This plugin will only need one function so it will have the same name as the class. These will also be the names we use in our EE plugin tags. Plugin tags always start with &#8220;exp:&#8221; which is telling the template parser, &#8220;Hey! I need some processing over here!&#8221;. What follows will be the name of your class all lowercase giving us: &#8220;exp:auto_acronym&#8221;. The third segment of a plugin tag calls the function within the plugin&#8217;s class. In our example we will just be using the one function, the constructor, so we only need the class name. So far here is what we know about our plugin:
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/2.jpg" border="0" /></div>
<h3>Putting it to Code</h3>
<p>
   Let&#8217;s see what our code is so far:
</p>
<pre name="code" class="php">
&lt;?php

class Auto_acronym
{

   function Auto_acronym()
   {

   }

}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */
</pre>
<p>
   For those of you who are familiar with WordPress plugin development, you know that WordPress extracts some data from commented code when displaying details in the Plugin Manager. ExpressionEngine does something similar except with an array within your plugin file. Let&#8217;s go ahead and add that to our file above the class and give it the appropriate information.
</p>
<pre name="code" class="php">
&lt;?php

$plugin_info       = array(
   'pi_name'        => 'Auto Acronym',
   'pi_version'     => '1.0',
   'pi_author'      => 'Erik Reagan',
   'pi_author_url'  => 'http://erikreagan.com',
   'pi_description' => 'Automatically wraps certain acronyms in the HTML &lt;acronym&gt; tag',
   'pi_usage'       => Auto_acronym::usage()
   );

class Auto_acronym
{

   function Auto_acronym()
   {

   }

}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */
</pre>
<p>
   Each of the array keys should be pretty obvious as far as what they are for. The last key, however, is a little different. It&#8217;s obviously not just a string like the others. It is used to tell the ExpressionEngine control panel where to find the usage, or simple documentation, for the plugin. Every EE plugin should have some basic docs within the plugin file so that those using the plugin can just view it in the Control Panel and see how to utilize the tags. This is done by adding a function to your plugin class called &#8220;usage&#8221; which . I like to put the usage function last in my class so let&#8217;s go ahead and copy &amp; paste the example from the <a href="http://expressionengine.com/docs/development/plugins.html">ExpressionEngine Plugin Docs</a> and remove the content between the ?&gt; and &lt;?php tags since our content will go there.
</p>
<pre name="code" class="php">

   // ----------------------------------------
   //  Plugin Usage
   // ----------------------------------------

   // This function describes how the plugin is used.
   //  Make sure and use output buffering

   function usage()
   {
   ob_start();
   ?&gt;

   &lt;?php
   $buffer = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
   }
</pre>
<p>
   Our usage does will be written after we complete our plugin. For now let&#8217;s just put in some text for testing purposes. Keep in mind that this text will be treated as pre-formatted and all characters are converted into HTML entities; HTML will not work. Let&#8217;s look at our plugin in its entirety so far
</p>
<pre name="code" class="php">
&lt;?php

$plugin_info       = array(
   'pi_name'        => 'Auto Acronym',
   'pi_version'     => '1.0',
   'pi_author'      => 'Erik Reagan',
   'pi_author_url'  => 'http://erikreagan.com',
   'pi_description' => 'Automatically wraps certain acronyms in the HTML &lt;acronym&gt; tag',
   'pi_usage'       => Auto_acronym::usage()
   );

class Auto_acronym
{

   function Auto_acronym()
   {

   }

   // ----------------------------------------
   //  Plugin Usage
   // ----------------------------------------

   // This function describes how the plugin is used.
   //  Make sure and use output buffering

   function usage()
   {
   ob_start();
   ?&gt;

   This is where our simplified documentation will go

   &lt;?php
   $buffer = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
   }

}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */
</pre>
<p>
   Now that we have a bare-bones plugin file we need to save it to our system/plugins directory to make sure it&#8217;s being read by the system properly. After saving it you will see it under Admin > Utilities > Plugin Manager. If you click on our new plugin you should see a page like this that contains the information we just added to our plugin
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/3.jpg" border="0" /></div>
<h3>Making it Work</h3>
<p>
   Now that our plugin is being pulled into the ExpressionEngine system properly, we can make it actually <strong>do something</strong>. Every plugin returns some form of data. This data will always come from a standardized variable that EE will look for called &#8220;return_data&#8221;. The first thing we want to do is define it before our first function within the class. Then, just for testing purposes, we will use it within our first function to return a simple string.
</p>
<pre name="code" class="php">
class Auto_acronym
{

   var $return_data  = "";

   function Auto_acronym()
   {
      $this->return_data = "Just making sure this works";

   }
</pre>
<p>
   Now that we have some data being returned we can test it on the front end of our website. I am using a very minimal template for testing purposes right now but you can use this within any of your ExpressionEngine templates. If you recall from earlier our plugin tag is {exp:auto_acronym} and since we only have one function we do not need to use a third segment in this plugin. Here&#8217;s what my template code looks like followed by what my browser shows:
</p>
<pre name="code" class="html">
&lt;h1&gt;Plugin Tutorial&lt;/h1&gt;

&lt;p&gt;{exp:auto_acronym}&lt;/p&gt;
</pre>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/4.jpg" border="0" /></div>
<p>
   Not exactly ground-breaking but it is getting us one step closer to our goal. Now that we know how to pass data back we can look at grabbing data passed to our plugin.
</p>
<h3>Processing Data with our Plugin</h3>
<p>
   The first method we will focus on with processing data is where ExpressionEngine reads all of the data between the plugin tag pair. I you don&#8217;t already know, our tag <strong>pair</strong> is very similar to how HTML tag pairs work. We have an open tag followed by data followed by a close tag like this:
</p>
<pre name="code" class="php">
{exp:auto_acronym}
This gets processed
{/exp:auto_acronym}
</pre>
<p>
   ExpressionEngine makes it very easy to get this data with the use of the Template Object. In this case we will need to make it global within our function so that we have access to it. Then we define our variable by calling in to play the &#8220;tagdata&#8221; variable. This variable is the data between our open and close tag pair. Take a look:
</p>
<pre name="code" class="php">
function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;
}
</pre>
<p>
   Now lets do something very simple with our data and make it bold since it is just text right now. We will add the &lt;strong&gt; tags around it and then define our return_data variable accordingly. This is what our code, template and rendered page should look like now:
</p>
<p><strong>Plugin:</strong></p>
<pre name="code" class="php">
function Auto_acronym()
{
   global $TMPL;

   $data = '&lt;strong&gt;&#x27;.$TMPL-&gt;tagdata.&#x27;&lt;/strong&gt;&#x27;;

   $this->return_data = $data;
}
</pre>
<p><strong>Template:</strong></p>
<pre name="code" class="html">
&lt;h1&gt;Plugin Tutorial&lt;/h1&gt;

{exp:auto_acronym}
&lt;p&gt;This gets processed&lt;/p&gt;
{/exp:auto_acronym}
</pre>
<p><strong>Rendered in Browser:</strong></p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/5.jpg" border="0" /></div>
<h3>Do Something Already!</h3>
<p>
   Okay, okay. Let&#8217;s actually  have some fun with this now. Our goal with this plugin is to scan through the data passed to it for common web development acronyms. I mentioned that we would be using 3 for the tutorial: HTML, CSS &amp; RSS. The first this we want to do is put them all into an array within our function. Note that if we were using this array across the plugin and had <strong>multiple functions</strong> we would probably want to store this outside of the constructor so it could be called by any of the functions.
</p>
<pre name="code" class="php">
function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;

   $acronyms = array(
      'HTML' => 'HyperText Markup Language',
      'CSS' => 'Cascading Style Sheets',
      'RSS' => 'Really Simple Syndication'
      );
}
</pre>
<p>
   Now that we have our tag data along with the array of acronyms we need to run a foreach() loop on the acronyms. The first thing we will do is run the acronym and tagdata through a strpos() function to make sure that the acronym is, in fact, within our string. The reason we do this is so that we don&#8217;t run unneeded string replacements. If your acronym dictionary had hundreds of values and you were running it through a lengthy article it could risk unnecessary processing time. If and only if the acronym is within our tag data we will use the str_replace() function to actually add in the &lt;acronym&gt; tags. After our foreach() loop we will define our return_data variable accordingly. Here&#8217;s what it looks like:
</p>
<pre name="code" class="php">
function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;

   $acronyms = array(
      'HTML' => 'HyperText Markup Language',
      'CSS' => 'Cascading Style Sheets',
      'RSS' => 'Really Simple Syndication'
      );

   foreach ($acronyms as $short => $long)
   {
      if (strpos($data, $short) !== FALSE)
      {
         $data = str_replace($short, '&lt;acronym title=&quot;&#x27;.$long.&#x27;&quot;&gt;&#x27;.$short.&#x27;&lt;/acronym&gt;&#x27;, $data);
      }
   }

   $this->return_data = $data;

}
</pre>
<p>
   In order to test this properly we will need to change our template so that it actually has some of our desired acronyms in it. I&#8217;m going to change my template to this:
</p>
<pre name="code" class="html">
&lt;h1&gt;Plugin Tutorial&lt;/h1&gt;

{exp:auto_acronym}
&lt;p&gt;My name is Erik and I am an addict. I stay up late into the night marking up HTML and CSS with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My RSS subscribers wait on their toes for my next
example of code beauty. Okay...not really.&lt;/p&gt;
{/exp:auto_acronym}
</pre>
<p>
   Saving our template and refreshing our browser should produce this:
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/6.jpg" border="0" /></div>
<h3>Now We&#8217;re Getting Somewhere!</h3>
<p>
   Now that we are properly processing the tags between the open and close tags of our plugin, let&#8217;s look at the other option: passing data within a single tag. Using a single tag with plugins will require adding in a parameter so that data is still passed through to the plugin to be process. You can name the parameter whatever you want. In our case we will use this and add it to our template:
</p>
<pre name="code" class="html">
{exp:auto_acronym data="HTML"}
</pre>
<p>
   Now that we have a single tag we need to find a way to use it in our plugin. Any parameter that you want to use in your plugin can be fetched using the same Template Object that we used earlier. Instead of being available via a variable you need to fetch it with a function called fetch_param(). We want our pluign to be usable with either a single tag or a tag pair so we will take that into account when we define our $data variable. This is what we will change:
</p>
<pre name="code" class="php">
// Original
$data = $TMPL->tagdata;

// New
$data = ($TMPL->fetch_param('data')) ? $TMPL->fetch_param('data') : $TMPL->tagdata ;
</pre>
<p>
   If you are not familiar with this syntax is basically says &#8220;if the data parameter exists (or returns true) then use it as our data variable, otherwise use the tagdata between tag pairs.&#8221; This one change will enable us to use both tag pairs and single tags with the data parameter defined. Here&#8217;s what our template should render now:
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/7.jpg" border="0" /></div>
<h3>Almost Done!</h3>
<p>
   Now we have a fully functioning ExpressionEngine plugin. The final step in completing it is adding in useful &#8220;usage&#8221; information. Let&#8217;s go down to the usage() function and add in some simple documentation for the Control Panel.
</p>
<pre name="code" class="php">
function usage()
{
   ob_start();
?&gt;

The &quot;dictionary&quot; of acronyms is stored in an array within the plugins/pi.auto_acronym.php file.

Automatically turn a string into an HTML acronym if it is within our acronym dictionary. You can do this with individual words or large blocks of text.

Simple Example
===========================

{exp:auto_acronym data=&quot;HTML&quot;}

This outputs:
&lt;acronym title=&quot;Hypertext Markup Language&quot;&gt;HTML&lt;/acronym&gt; in your ExpressionEngine template.

Large Block Example
===========================

{exp:auto_acronym}

&lt;p&gt;My name is Erik and I am an addict. I stay up late into the night marking up HTML and CSS with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My RSS subscribers wait on their toes for my next
example of code beauty. Okay...not really.&lt;/p&gt;

{/exp:auto_acronym}

This outputs:
&lt;p&gt;My name is Erik and I am an addict. I stay up late into the night marking up &lt;acronym title=&quot;Hypertext Markup Language&quot;&gt;HTML&lt;/acronym&gt; and &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My &lt;acronym title=&quot;Really Simple Syndication&quot;&gt;RSS&lt;/acronym&gt; subscribers wait on their toes for my next
example of code beauty. Okay...not really.&lt;/p&gt;
&lt;?php
   $buffer         = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
}
</pre>
<p>
   Now our control panel should look something like this:
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.cdn.plus.org/480_ee/8.jpg" border="0" /></div>
<h3>Congratulations!</h3>
<p>
   You&#8217;ve now completed your first ExpressionEngine plugin. Hopefully this will open up the doors for you now that you see how easy it is. Fetching and returning data is very simple and you can run a lot of your PHP magic from within the plugin itself. I am hosting this plugin on <a href="http://github.com/erikreagan">my GitHub account</a> where you can download the full plugin code there if you would like. Next in our ExpressionEngine Add-On series we will look at creating a simple Extension for the Control Panel. Stay tuned!
</p>
<h3>P.S.</h3>
<p>Don&#8217;t forget to check out these other awesome ExpressionEngine tutorials!</p>
<ul>
<li><a href="http://net.tutsplus.com/tutorials/cmss/creating-a-google-map-with-expressionengine/">Creating a Google Map with EE</a></li>
<li><a href="http://net.tutsplus.com/articles/news/create-a-slideshow-with-slideshowpro-and-expressionengine-new-plus-tutorial/">Create a Slideshow with Slideshow Pro and ExpressionEngine</a></li>
<li><a href="http://net.tutsplus.com/tutorials/php/become-an-expression-engine-superstar-in-5-days/">Become an ExpressionEngine Superstar in 5 Days</a></li>
</ul>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="Nettuts+ RSS Feed">Nettuts+ RSS Feed</a> for the best web development tutorials on the web.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/cmss/building-your-first-expressionengine-plugin/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Creating a Google Map with ExpressionEngine</title>
		<link>http://net.tutsplus.com/tutorials/cmss/creating-a-google-map-with-expressionengine/</link>
		<comments>http://net.tutsplus.com/tutorials/cmss/creating-a-google-map-with-expressionengine/#comments</comments>
		<pubDate>Wed, 13 May 2009 12:43:38 +0000</pubDate>
		<dc:creator>Trevor Davis</dc:creator>
				<category><![CDATA[CMSs]]></category>
		<category><![CDATA[ee]]></category>
		<category><![CDATA[expression engine]]></category>
		<category><![CDATA[expressionengine]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[maps]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=4732</guid>
		<description><![CDATA[<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/ee-map.png" alt="" height="200" width="200" />]]></description>
			<content:encoded><![CDATA[<p>As Richard Tape has begun to show in his <a href="http://net.tutsplus.com/tutorials/php/become-an-expression-engine-superstar-in-5-days/">part 1</a> and <a href="http://net.tutsplus.com/tutorials/other/become-an-expressionengine-superstar-in-5-days-part-2/">part 2</a> articles on Becoming an ExpressionEngine Superstar, <abbr title="ExpressionEngine">EE</abbr> is a flexible and easy to customize CMS. Now that everyone has some understanding of how EE works, I thought I would take this opportunity to show a relatively real world example of creating a dynamic Google Map powered by EE.</p>
<p><span id="more-4732"></span></p>
<div class="tutorial_image">
<a href="http://eesandbox.trevordavis.net/index.php/locations/"><img src="http://net.tutsplus.com/wp-content/themes/nettuts/site_images/button_demo_nm.jpg"></a>
</div>
<div class="tutorial_image">
<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/google-locations-map.png" alt="Final Product" />
</div>
<p>For this example, let&rsquo;s assume that our company has various locations throughout the US, and we are tasked with creating a Google Map that shows all the locations and is easy to maintain. <a href="http://eesandbox.trevordavis.net/index.php/locations/">Take a look at the demo</a> to see what we are trying to accomplish.</p>
<h2>Setting Up the Weblog and Custom Field Group</h2>
<p>First, remember that a weblog is nothing more than just a container of data. Actually, in EE 2.0, they are changing the term weblog to channel. So we are going to create a weblog called <strong>Locations</strong> and a custom field group called <strong>Locations</strong>. It&rsquo;s definitely not a requirement to have them be named the same, but it just makes it easier to understand the relationship.</p>
<h3>Defining the Custom Field Group</h3>
<p>I actually like to create the field group first, so let&rsquo;s do that by going to Admin &gt; Weblog Administration &gt; Custom Weblog Fields. Then click on the big green button that says <strong>Create a New Weblog Field Group</strong>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/new-field-group.png" alt="New Field Group" height="192" width="600" /><br/><br />
	Field Groups
</div>
<p>Enter <strong>Locations</strong> as the Field Group Name and click submit.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/new-field-group-name.png" alt="New Field Group" height="226" width="600" /><br/><br />
	Naming the new field group
</div>
<p>After you click submit, you will see that EE tells you that you can&rsquo;t use it until you assign it to a weblog. But, we will assign it to a weblog when we create the weblog.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/new-field-group-created.png" alt="New Field Group Created" height="226" width="600" /><br/><br />
	The Locations field group has been created
</div>
<p>Now that our field group is created, we need to think about the actual fields that we want to have in it. The following are the fields that I think fit, and their properties in EE:</p>
<ol>
<li>Field Label: <strong>Longitude</strong>
<ul>
<li>Field Name: locations_longitude</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 50</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? Yes</li>
</ul>
</li>
<li>Field Label: <strong>Latitude</strong>
<ul>
<li>Field Name: locations_latitude</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 50</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? Yes</li>
</ul>
</li>
<li>Field Label: <strong>Address</strong>
<ul>
<li>Field Name: locations_address</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 200</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? Yes</li>
</ul>
</li>
<li>Field Label: <strong>Photo</strong>
<ul>
<li>Field Name: locations_photo</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 50</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? No</li>
</ul>
</li>
<li>Field Label: <strong>Photo Width</strong>
<ul>
<li>Field Name: locations_photo_width</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 4</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? No</li>
</ul>
</li>
<li>Field Label: <strong>Photo Height</strong>
<ul>
<li>Field Name: locations_photo_height</li>
<li>Field Type: Text Input</li>
<li>Maxlength: 4</li>
<li>Default Text Formatting: None</li>
<li>Hide Formatting Menu</li>
<li>Required Field? No</li>
</ul>
</li>
<li>Field Label: <strong>Description</strong>
<ul>
<li>Field Name: locations_description</li>
<li>Field Type: Textarea</li>
<li>Textarea Rows: 6</li>
<li>Default Text Formatting: XHTML</li>
<li>Display Formatting Menu</li>
<li>Required Field? No</li>
</ul>
</li>
</ol>
<p>Now that we have mapped out our fields, we need to create the fields in EE. So first, click on Add/Edit Custom Fields in the Locations record. Then, click on the big green button that says <strong>Create a New Custom Field</strong>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/custom-fields.png" alt="Custom Fields" height="181" width="600" /><br/><br />
	Click on Create a New Custom Field
</div>
<p>Now here is where we create the fields in EE that we defined previously. First, let&rsquo;s start with the <strong>Longitude</strong> field:</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/new-custom-field.png" alt="New Custom Field" height="620" width="600" /><br/><br />
	Defining the Longitude field
</div>
<p>Once we have selected all of the appropriate properties, click submit. Now, the Longitude field is created.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/new-field-created.png" alt="Custom Field Created" height="194" width="600" /><br/><br />
	The Longitude field is created
</div>
<p>Now that you have seen how to create one field, I&rsquo;m just going to go ahead and create the rest.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/custom-fields-created.png" alt="Custom Fields Created" height="327" width="600" /><br/><br />
	All custom fields created
</div>
<h3>Create the Locations Weblog</h3>
<p>Now that our field group has been defined, we need to create our weblog and assign the Locations custom field group to it. First, click on the <strong>Weblog Administration</strong> bread crumb. Then click on <strong>Weblog Management</strong>. Finally, click the big green button that says <strong>Create a New Weblog</strong>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/weblog-management.png" alt="Weblog Management" height="205" width="600" /><br/><br />
	Weblog Management
</div>
<p>Enter <strong>Locations</strong> as the Full Weblog Name and <strong>locations</strong> as the Short Name. Select <strong>Yes</strong> for Edit Group Preferences, and a new section will show up. This is where we select <strong>Locations</strong> as the Field Group.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/create-new-weblog.png" alt="Create New Weblog" height="578" width="600" /><br/><br />
	Create Locations Weblog
</div>
<p>Once all the settings have been select, click submit, and the Locations weblog is created.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/weblog-created.png" alt="Weblog Created" height="265" width="600" /><br/><br />
	Locations Weblog Created
</div>
<h2>Entering Locations</h2>
<p>Now that our <strong>Locations</strong> weblog is created, we can start to enter the locations. Hover over the Publish tab and click on <strong>Locations</strong>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/publish-location.png" alt="Locations Entry Form" height="612" width="600" /><br/><br />
	Locations Entry Form
</div>
<p>The Title, Address, and Description fields are pretty self explanatory, but the URL Title, Longitude, Latitude, and Photo fields may need a little explanation.</p>
<h3>URL Title</h3>
<p>The URL Title field is auto-populated when you enter the Title. The URL Title replaces spaces with underscores and makes the text lowercase. For this certain situation, we are not going to use it. There is a way to hide it, but I&rsquo;m not going to go through that right now.</p>
<h3>Longitude and Latitude</h3>
<p>I&rsquo;m sure everyone knows what longitude and latitude are, but the question is: how do you determine it from an address? By using a third party site like <a href="http://www.mapbuilder.net/">Map Builder</a>. This site allows you to enter an address, and it returns the longitude and latitude.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/map-builder.png" alt="Map Builder" height="217" width="501" /><br/><br />
	Using Map Builder to get longitude and latitude
</div>
<h3>Photo</h3>
<p>If we had a photo of the location, we can include it in when the plot point is clicked. Uploading images in EE can be a little confusing, so let&rsquo;s walk through it.</p>
<p>First, click on the <strong>Upload File</strong> link which is located under the submit button. A pop-up window will come up.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/file-upload-1.png" alt="File Upload" height="535" width="520" /><br/><br />
	File Upload
</div>
<p>Browse for your file on your computer, and click Submit.</p>
<p>You can resize the photo after uploading it by clicking the Resize Image button, but I sized my image before uploading, so I won&rsquo;t demo that part. We want to select <strong>URL Only</strong> for the File Type and <strong>Photo</strong> for the Image Location.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/file-upload-2.png" alt="File Uploaded" height="578" width="505" /><br/><br />
	File Uploaded
</div>
<p>Once our options have been selected, click on <strong>Place Image and Close Window</strong>. This will now populate your <strong>Photo</strong> field with the location of your image.</p>
<h3>Photo Width and Height</h3>
<p>If a user uploads a photo of the location, we want them to input the image height and width. If they do not, the image will break out of the information bubble because of how Google Maps calculates the size of the bubble. It is simple enough to add in the width and height to solve this problem, so we added that in.</p>
<h3>Description</h3>
<p>If we want to enter a brief description to display in the bubble when the plot point is clicked, this is where you would enter it. This field supports HTML formatting by default.</p>
<p>Now that we have entered all of our pieces of data, we can submit the form and the location will be published.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/completed-entry.png" alt="File Uploaded" height="714" width="600" /><br/><br />
	Our Completed Entry
</div>
<p>Then, just repeat this process for the additional entries.</p>
<h2>Creating the Map</h2>
<p>First, we need to create a new template group for our locations map by clicking on the <strong>Templates</strong> tab. Then, click on the big green button that says <strong>Create a New Template Group</strong>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/templates.png" alt="Templates" height="132" width="600" /><br/><br />
	Templates
</div>
<p>Then, enter <strong>locations</strong> into the Template Group name field, and click submit. Our template group has now been created.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/template-group-created.png" alt="Template Group Created" height="258" width="600" /><br/><br />
	Template Group Created
</div>
<p>While we are here, let&rsquo;s make another template group called <strong>scripts</strong>.</p>
<p>Next, select the locations template group from the left hand column, and click on <strong>index</strong>. Now we can start to build our template. You will presented with what is just an empty box, this is where you will add all of your code.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/edit-template.png" alt="Edit Template" height="243" width="600" /><br/><br />
	Editing Templates
</div>
<p>Now all we need to do is enter our code and click update, and our template is updated.</p>
<h3>The Code</h3>
<p>In order to use the Google Maps API, you need to <a href="http://code.google.com/apis/maps/signup.html">sign up for an API key for your site</a>. Once you sign up, you will be provided with the API key, which you use when including the JavaScript on the page. Let&rsquo;s get started with a simple page and include our Google Maps code:</p>
<pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml">
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
&lt;title>Locations&lt;/title>
&lt;script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAGbpRl2XCyCtoHtEtVLA9mhT9xvUTfY2sa86RDF1pWLQtRVPGPxQD1aEASfi1xtt39RqVCDd8ib1hGw" type="text/javascript">&lt;/script>
&lt;/head>

&lt;body>

&lt;/body>
&lt;/html></pre>
<p><em>Note: ABQIAAAAGbpRl2XCyCtoHtEtVLA9mhT9xvUTfY2sa86RDF1pWLQtRVPGPxQD1aEASfi1xtt39RqVCDd8ib1hGw is the value of the Google Maps API key for my site. You will need to update this with your own key.</em></p>
<p>Once this code has been entered into to textarea, just click update to save the template. Then, if you click the big green button that says <strong>View Rendered Template</strong>, we will see what the page will look like.</p>
<p>Next, we need to add a div that will actually contain the map.</p>
<pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml">
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
&lt;title>Locations&lt;/title>
&lt;script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAGbpRl2XCyCtoHtEtVLA9mhT9xvUTfY2sa86RDF1pWLQtRVPGPxQD1aEASfi1xtt39RqVCDd8ib1hGw" type="text/javascript">&lt;/script>
&lt;/head>

&lt;body>

&lt;div id="map">You must have JavaScript Enabled to view this map.&lt;/div>

&lt;/body>
&lt;/html></pre>
<p><em>Note: I just added the message about needing JavaScript for the users who do not have JavaScript enabled, but you could certainly output the list of locations instead of this message.</em></p>
<p>We need to define the height and width of the div that is going to contain the map, so for this example, I am just going to use some CSS on the page.</p>
<pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml">
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
&lt;title>Locations&lt;/title>
&lt;script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAGbpRl2XCyCtoHtEtVLA9mhT9xvUTfY2sa86RDF1pWLQtRVPGPxQD1aEASfi1xtt39RqVCDd8ib1hGw" type="text/javascript">&lt;/script>
&lt;style type="text/css">
#map { height: 600px; width: 800px; }
&lt;/style>
&lt;/head>

&lt;body>

&lt;div id="map">You must have JavaScript Enabled to view this map.&lt;/div>

&lt;/body>
&lt;/html></pre>
<p>That is all of the HTML we need to get our map to show up, so once the code is entered, click <strong>Update and Finished</strong>, and we are taken back to the main templates section. Next, we are going to code our JavaScript to add the points to the map.</p>
<p>Select scripts from the left hand column and click on <strong>New Template</strong>. Enter <strong>map</strong> as the template name, and select <strong>JavaScript</strong> from the Template Type dropdown, and then click <strong>Submit</strong>.</p>
<p>Our new template named <strong>map</strong> has now been created. So click on <strong>map</strong>, and let&rsquo;t edit the template.</p>
<p>The cool thing about EE is that we can enter EE code into the JS and CSS templates and it will process that code. In order to do this, we do have to add <a href="http://expressionengine.com/wiki/Hidden_Configuration_Variables/#protect_javascript">a hidden config variable</a> to our config.php file that is located in the system folder. So open up your config.php file and enter the following: <strong>$conf['protect_javascript'] = &#8216;n&#8217;;</strong>. Then upload it, and EE tags will be processed in JS code.</p>
<p><em>Note: I am going to use plain old JavaScript for this example, but you could easily modify some code to use your framework of choice.</em></p>
<p>First, we are going to get started creating a function that will add the plot points to the map:</p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();
}</pre>
<p>The first line is specifying to use the element with an id of <strong>map</strong> to create the map. The next line sets the center of the map to the specified latitude and longitude, then sets the zoom level. These are just arbitrary values for this example, so you will most likely need to adjust. The final line sets up the controls on the map, i.e. zoom, move, map type, etc.</p>
<p>Now, we want to access the data that we entered in EE by using the <a href="http://expressionengine.com/docs/modules/weblog/weblog_entries.html">exp:weblog:entries</a> tag:</p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();

	{exp:weblog:entries weblog="locations" disable="categories|category_fields|member_data|pagination|trackbacks"}
		{if count == 1}
			var points = new Array({total_results});
		{/if}

	{/exp:weblog:entries}
}</pre>
<p>So this code is saying to &ldquo;query&rdquo; the <strong>locations weblog</strong>, and <a href="http://expressionengine.com/docs/modules/weblog/parameters.html#par_disable">disable</a> additional parameters that we will not be using. This is a good habit to get into because it can improve performance.</p>
<p>There are some EE variables that we are using that I will need to explain: <a href="http://expressionengine.com/docs/modules/weblog/variables.html#var_count">count</a> and <a href="http://expressionengine.com/docs/modules/weblog/variables.html#var_total_results">total_results</a>. <strong>count</strong> is exactly what it sounds like: it just indicates the number of the current record that we are on. <strong>total_results</strong> indicates how many total records will be returned.</p>
<p>So if count equals 1, this the first time through the loop, so we initialize our array that will have a size of the total number of records returned.</p>
<p>Next, we want to actually grab the data and output it in the loop. <em>Note: I am going to add line breaks to this code just for readability, but in production use, the line breaks need to be removed.</em></p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();

	{exp:weblog:entries weblog="locations" disable="categories|category_fields|member_data|pagination|trackbacks"}
		{if count == 1}
			var points = new Array({total_results});
		{/if}

		points[{count}] = [{locations_latitude},{locations_longitude},
			'&lt;div class="infoContainer">
				&lt;h2>{title}&lt;/h2>
				{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}
					&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />
				{/if}
				&lt;p class="address">{locations_address}&lt;/p>
				{if locations_description}
					{locations_description}
				{/if}
			&lt;/div>'];

	{/exp:weblog:entries}
}</pre>
<p>That may look like a lot, so let&rsquo;s go through it piece by piece.</p>
<pre name="code" class="js">points[{count}] = [{locations_latitude},{locations_longitude},</pre>
<p>Here, we are adding an array to our points array. In this array, we are going to be adding the latitude, longitude, and information to display in the information bubble. Notice how <strong>locations_latitude</strong> and <strong>locations_longitude</strong> match up with the values we added for the Field Names in our custom field group.</p>
<pre name="code" class="js">'&lt;div class="infoContainer">
	&lt;h2>{title}&lt;/h2>
&lt;/div>'];</pre>
<p>In this snippet, we are just adding a div and the title that was entered into EE.</p>
<pre name="code" class="js">{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}
	&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />
{/if}</pre>
<p>In this piece, we are checking to see if there was a value entered into the photo, photo width, and photo height fields. If there was, we add the photo to our information bubble.</p>
<pre name="code" class="js">&lt;p class="address">{locations_address}&lt;/p>
{if locations_description}
	{locations_description}
{/if}</pre>
<p>Finally, we add the address to the information bubble, and if there was a description entered, we add that too. Here is that whole line without any line breaks:</p>
<pre name="code" class="js">points[{count}] = [{locations_latitude},{locations_longitude},'&lt;div class="infoContainer">&lt;h2>{title}&lt;/h2>{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />{/if}&lt;p class="address">{locations_address}&lt;/p>{if locations_description}{locations_description}{/if}&lt;/div>'];</pre>
<p>To finish off the function, we just need to loop through the array and add the plot points and event listeners to the map:</p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();

	{exp:weblog:entries weblog="locations" disable="categories|category_fields|member_data|pagination|trackbacks"}
		{if count == 1}
			var points = new Array({total_results});
		{/if}

		points[{count}] = [{locations_latitude},{locations_longitude},'&lt;div class="infoContainer">&lt;h2>{title}&lt;/h2>{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />{/if}&lt;p class="address">{locations_address}&lt;/p>{if locations_description}{locations_description}{/if}&lt;/div>'];

	{/exp:weblog:entries}

	for(var i=1; i &lt; points.length; i++) {
		var point = new GLatLng(points[i][0],points[i][1]);
		var windowInfo = points[i][2];
		var marker = createMarker(point,windowInfo);
		map.addOverlay(marker);
	}
}</pre>
<p>So we are creating our point and passing in the latitude and longitude. Then, we are creating a variable that contains all of the information for the information bubble. Next, we are calling a custom function that I will define in a minute and passing in the point and information bubble text. Finally, we are adding the marker to the map.</p>
<p>Here is our custom function that is creating the marker:</p>
<pre name="code" class="js">function createMarker(point, overlayText) {
	var marker = new GMarker(point);
	GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(overlayText);});
	return marker;
}</pre>
<p>So we are creating a marker based on our point on the map, then adding an event listener that will open the information bubble with the appropriate text when it is clicked.</p>
<p>So that&rsquo;s pretty much it. Although, I will add one more function that will tell the JS function to run once the dom has been loaded:</p>
<pre name="code" class="js">function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(populateMap);</pre>
<p>I first read about this function from <a href="http://simonwillison.net/2004/May/26/addLoadEvent/">Simon Willison</a>. You could again replace this with code for whatever JS library you are using.</p>
<p>Here is the full JS for that template:</p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();

	{exp:weblog:entries weblog="locations" disable="categories|category_fields|member_data|pagination|trackbacks"}
		{if count == 1}
			var points = new Array({total_results});
		{/if}

		points[{count}] = [{locations_latitude},{locations_longitude},'&lt;div class="infoContainer">&lt;h2>{title}&lt;/h2>{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />{/if}&lt;p class="address">{locations_address}&lt;/p>{if locations_description}{locations_description}{/if}&lt;/div>'];

	{/exp:weblog:entries}

	for(var i=1; i &lt; points.length; i++) {
		var point = new GLatLng(points[i][0],points[i][1]);
		var windowInfo = points[i][2];
		var marker = createMarker(point,windowInfo);
		map.addOverlay(marker);
	}
}

function createMarker(point, overlayText) {
	var marker = new GMarker(point);
	GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(overlayText);});
	return marker;
}

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(populateMap);</pre>
<p>Once all that code is added, click <strong>Update and Finished</strong> to be returned to the main templates page. Next, we need to go back to our locations template group and edit the index template.</p>
<p>We need to include the JS template that we just created in the head of the document:</p>
<pre name="code" class="js">&lt;script type="text/javascript" src="{path="scripts/map"}">&lt;/script></pre>
<p>I am using the <a href="http://expressionengine.com/docs/templates/globals/path.html">path</a> variable to link to the JS template.</p>
<p>So now, when we go back and view our locations template in the browser, you may see a JS error. If a location description was entered, it may add some new lines to the code, so this will break the string in the JS. So the solution is to somehow remove those new lines.</p>
<h2>Installing the Plugin</h2>
<p>Luckily, there is a plugin for EE called <a href="http://expressionengine.com/downloads/details/find_and_replace/">Find and Replace</a> that will let us replace all <strong>\n</strong> with nothing.</p>
<p>So browse to Admin > Utilities > Plugin Manager, and find the plugin in the right hand column. When you find it, click on install, and that&rsquo;s it.</p>
<h3>Using the Plugin</h3>
<p>Now, we can use the plugin in our code. So go back and edit the map template in our scripts template group, and replace this:</p>
<pre name="code" class="js">{if locations_description}
	{locations_description}
{/if}</pre>
<p>With this:</p>
<pre name="code" class="js">{if locations_description}
	{exp:replace find="\n" multiple="yes" regex="yes"}
		{locations_description}
	{/exp:replace}
{/if}</pre>
<p>This function is basically just saying to replace all new lines with nothing. Of course we want to remove all of the line breaks from the code, so here is the updated full JS:</p>
<pre name="code" class="js">function populateMap() {
	var map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(32.02670629333614, -95.009765625), 4);
	map.setUIToDefault();

	{exp:weblog:entries weblog="locations" disable="categories|category_fields|member_data|pagination|trackbacks"}
		{if count == 1}
			var points = new Array({total_results});
		{/if}

		points[{count}] = [{locations_latitude},{locations_longitude},'&lt;div class="infoContainer">&lt;h2>{title}&lt;/h2>{if locations_photo &#038;&#038; locations_photo_width &#038;&#038; locations_photo_height}&lt;img src="{locations_photo}" alt="" height="{locations_photo_height}" width="{locations_photo_width}" />{/if}&lt;p class="address">{locations_address}&lt;/p>{if locations_description}{exp:replace find="\n" multiple="yes" regex="yes"}{locations_description}{/exp:replace}{/if}&lt;/div>'];

	{/exp:weblog:entries}

	for(var i=1; i &lt; points.length; i++) {
		var point = new GLatLng(points[i][0],points[i][1]);
		var windowInfo = points[i][2];
		var marker = createMarker(point,windowInfo);
		map.addOverlay(marker);
	}
}

function createMarker(point, overlayText) {
	var marker = new GMarker(point);
	GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(overlayText);});
	return marker;
}

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(populateMap);</pre>
<h2>Conclusion</h2>
<p>That&rsquo;s it! We can now view our template in the browser and see our EE powered Google Map. You can also <a href="http://eesandbox.trevordavis.net/index.php/locations/">view my demo</a>.</p>
<div class="tutorial_image">
	<img src="http://nettuts.s3.cdn.plus.org/313_ee/images/google-locations-map.png" alt="Google Map" height="450" width="600" />
</div>
<p></body><br />
</html></p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/cmss/creating-a-google-map-with-expressionengine/feed/</wfw:commentRss>
		<slash:comments>55</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.260 seconds -->
