<?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>AtomicGamer Dev Blog &#187; SEO</title>
	<atom:link href="http://www.atomicgamer.com/dev/tag/seo/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.atomicgamer.com/dev</link>
	<description>The Trials and Errors of AtomicGamer</description>
	<lastBuildDate>Sun, 22 Nov 2009 19:33:04 +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>Optional, But Enforced, Parameters</title>
		<link>http://www.atomicgamer.com/dev/2009/10/optional-but-enforced-parameter/</link>
		<comments>http://www.atomicgamer.com/dev/2009/10/optional-but-enforced-parameter/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 04:38:28 +0000</pubDate>
		<dc:creator>Brian</dc:creator>
				<category><![CDATA[AtomicGamer]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[Tapestry]]></category>
		<category><![CDATA[Wicket]]></category>

		<guid isPermaLink="false">http://www.atomicgamer.com/dev/?p=43</guid>
		<description><![CDATA[There&#8217;s bound to be a better term than optional, enforced parameters. My definition is that these are URL parameters that you don&#8217;t really care about except for SEO (search engine optimization) but if you have to have them, then they may as well be correct. They help make friendlier URLs.
If I want to get to [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s bound to be a better term than optional, enforced parameters. My definition is that these are URL parameters that you don&#8217;t really care about except for SEO (search engine optimization) but if you have to have them, then they may as well be correct. They help make friendlier URLs.</p>
<p>If I want to get to a details page of an object, the ideal URL parameter is a single integer mapping to an id. It&#8217;s simple, clean, and fast. It&#8217;s the default URL mapping in Wordpress. However, a single id tells a search engine nothing about the page. It&#8217;s a wasted opportunity and <a href="http://googlewebmastercentral.blogspot.com/2008/11/googles-seo-starter-guide.html">it&#8217;s important</a> to take advantage of it.</p>
<p>Let&#8217;s get concrete. A good URL for a game details page may be <code>http://www.atomicgamer.com/games/34/Diablo-III</code>. It contains the game id (34) for quick lookups, but also contains the game name for SEO. I don&#8217;t care about the Diablo III portion when fetching the data, but I do want it to remain consistent for links.</p>
<p>I took a look into doing this with both Tapestry 5 and Wicket. I&#8217;m fair from an expert in either of them, so there could be a better way to do this. This is simply the way I determined to do it.</p>
<h2>Tapestry 5</h2>
<p>First, I need to put a link to my details page somewhere.</p>
<pre class="brush: html">

&lt;t:grid source=&quot;games&quot; row=&quot;game&quot;&gt;
  &lt;t:parameter name=&quot;nameCell&quot;&gt;
    &lt;a t:type=&quot;pagelink&quot; t:page=&quot;games&quot; context=&quot;list:game.id,game.name&quot;&gt;${game.name}&lt;/a&gt;
  &lt;/t:parameter&gt;
&lt;/t:grid&gt;
</pre>
<p>Pretty straightforward. That&#8217;ll create a link formatted as <code>/games/{id}/{name}</code>. Tapestry does all that for me, and in fact, if I didn&#8217;t care about enforcing the game name to be correct, I&#8217;d be done. (I&#8217;m using the <a href="http://wiki.apache.org/tapestry/Tapestry5HowToAddBindingPrefix">list binding prefix</a> for a quick shorthand here.)</p>
<p>All the rest of the work is done in the game details page&#8217;s onActivate method. This method will be called whenever a person goes to the page. I&#8217;ll need to fetch the game from the id, and then compare the name parameter to the game&#8217;s actual name.</p>
<pre class="brush: java">

Object onActivate(Long id, String name)
{
  game = gameDAO.findById(id);
  if (game == null)
  {
    return pagelinkSource.createPageRenderLink(Index.class);
  }

  if (!game.getName().equals(name))
  {
    return pagelinkSource.createPageRenderLinkWithContext(this.getClass(), id, game.getName());
  }

  return null;
}
</pre>
<p>The interesting part is the second if statement. If the names don&#8217;t match, I&#8217;m actually going to redirect the user to the page with the correct name. This costs a bit in terms of performance, but it will force it to stay consistent. If you&#8217;re ambitious, you could include a flash message here and tell the user to update their bookmarks.</p>
<p>That&#8217;s about it for Tapestry.</p>
<h2>Wicket</h2>
<p>The Wicket code is eerily similar in concept. First, I build up my bookmarkable link with the two parameters.</p>
<pre class="brush: java">

BookmarkablePageLink link = new BookmarkablePageLink(&quot;detailsLink&quot;, DetailsPage.class);
link.setParameter(&quot;id&quot;, game.getId());
link.setParameter(&quot;name&quot;, game.getName());
link.add(new Label(&quot;name&quot;, game.getName()));
item.add(link);
</pre>
<p>And somewhere down the line, I use that link.</p>
<pre class="brush: html">

&lt;a wicket:id=&quot;detailsLink&quot;&gt;&lt;span wicket:id=&quot;name&quot;&gt;Game Name&lt;/span&gt;&lt;/a&gt;
</pre>
<p>Now, Wicket supports clean URLs out of the box, but you have to configure it first or you&#8217;re going to get some really ugly URLs. To make my life easier in the long run, I installed the <a href="http://wicketstuff.org/confluence/display/STUFFWIKI/wicketstuff-annotation">wicketstuff-annotation</a> library. With this, I can just add a couple annotations to the top of my details page to get clean URLs.</p>
<pre class="brush: java">

@MountPath(path = &quot;games&quot;)
@MountMixedParam(parameterNames = {&quot;id&quot;, &quot;name&quot;})
public class DetailsPage extends WebPage
{
...
}
</pre>
<p>With a nice clean URL in hand (<code>/games/{id}/{name}</code>), we&#8217;re just a redirect away from being finished. Like Tapestry, I&#8217;ll fetch the game and redirect.</p>
<pre class="brush: java">
public DetailsPage(PageParameters parameters)
{
  super(parameters);

  Game game = getGame(parameters.getAsLong(&quot;id&quot;));
  if (!game.getName().equals(parameters.getString(&quot;name&quot;)))
  {
    parameters.put(&quot;name&quot;, game.getName());
    setResponsePage(this.getClass(), parameters);
    setRedirect(true);
    return;
}
...
}
</pre>
<p>And that&#8217;s it. I&#8217;ll disclaim again that I&#8217;m neither a Tapestry or Wicket guru, and I would love someone to point out a better way to do this.</p>
<p>For now though, it&#8217;s minor performance cost, but grants me lovely clean, friendly URLs with parameters I don&#8217;t have to worry about. If I change the name of Diablo III to Diablo 3, users with the old URL will be redirect to the new URL. I don&#8217;t have to think about it and that&#8217;s perfect for me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.atomicgamer.com/dev/2009/10/optional-but-enforced-parameter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
