<?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>Stuff by Sarah &#187; Web Development</title>
	<atom:link href="http://www.stuffbysarah.net/category/web-stuff/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.stuffbysarah.net</link>
	<description>PHP, WordPress and Business Ramblings</description>
	<lastBuildDate>Sun, 06 Jun 2010 12:45:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Thickbox and jQuery 1.3.1</title>
		<link>http://www.stuffbysarah.net/2009/02/16/thickbox-and-jquery-131/</link>
		<comments>http://www.stuffbysarah.net/2009/02/16/thickbox-and-jquery-131/#comments</comments>
		<pubDate>Mon, 16 Feb 2009 08:00:23 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=1230</guid>
		<description><![CDATA[I&#039;ve recently been finishing off a site where I needed a lightbox to simplify showing several photos for each product. I&#039;ve used Thickbox in the past, as it comes with WordPress by default, however this is a custom built site. I already had the latest version of jQuery running for other functions on the site, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve recently been finishing off a site where I needed a lightbox to simplify showing several photos for each product. I&#039;ve used <a href="http://jquery.com/demo/thickbox/" class="external">Thickbox</a> in the past, as it comes with WordPress by default, however this is a custom built site. I already had the latest version of <a href="http://jquery.com" class="external">jQuery</a> running for other functions on the site, so just needed to grab a copy of thickbox, upload that, add the necessary code and that should be that.</p>
<p>3 hours of going around in circles later&#8230; and still no joy! After checking over my code piece by piece, trying the code out of WordPress, trying the page on another server just in case, and trying every other option I could think of, I finally tried uploading jQuery 1.2.6 from my WordPress 2.7 folder on my computer, and hey presto, it all worked!</p>
<p>It seems that there is a minor change required for thickbox to work with the latest jQuery version. After a bit of searching around I found out that what&#039;s needed is on line 79 of the existing thickbox file you need to change the line</p>
<dl class="code">
<dt>Existing Thickbox Code</dt>
<dd>
<ol>
<li>TB_TempArray = $(&#034;a[@rel="+imageGroup+"]&#034;).get(); </li>
</ol>
</dd>
</dl>
<p>to not include the @ sign in it ie.</p>
<dl class="code">
<dt>New Thickbox Code</dt>
<dd>
<ol>
<li>TB_TempArray = $(&#034;a[rel="+imageGroup+"]&#034;).get(); </li>
</ol>
</dd>
</dl>
<p>Such a simple change that caused a few hours of frustration! So hopefully it may be of use to someone else <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2009/02/16/thickbox-and-jquery-131/feed/</wfw:commentRss>
		<slash:comments>72</slash:comments>
		</item>
		<item>
		<title>A few jQuery Additions</title>
		<link>http://www.stuffbysarah.net/2008/10/07/a-few-jquery-additions/</link>
		<comments>http://www.stuffbysarah.net/2008/10/07/a-few-jquery-additions/#comments</comments>
		<pubDate>Tue, 07 Oct 2008 17:16:42 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=813</guid>
		<description><![CDATA[I&#039;ve been adding in a few jQuery additions to this site recently, and will be adding a few more. Nothing will stop working if you don&#039;t run JavaScript, I&#039;m not that ignorant You&#039;ll just notice that on the sidebar on the right, some of the lists are now &#039;closed&#039;, click on the plus/minus sign to [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve been adding in a few jQuery additions to this site recently, and will be adding a few more. Nothing will stop working if you don&#039;t run JavaScript, I&#039;m not that ignorant <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  You&#039;ll just notice that on the sidebar on the right, some of the lists are now &#039;closed&#039;, click on the plus/minus sign to open them up. Also on the single posts the comment form has been hidden and if you click on &#039;Leave a Comment&#039; it will appear (I wonder how many comments I don&#039;t get now with people not realising it&#039;s there&#8230;?!).</p>
<p>I&#039;ve still got a bit of playing to do, but just so you&#039;re aware, a few things may change. Hopefully for the better <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>Any thoughts on the comment form though? I like having it out of the way until it&#039;s needed but obviously don&#039;t want people to think that the form has gone. Time to have a bit of a think I guess. All opinions/thoughts welcome <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/10/07/a-few-jquery-additions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>jQuery Fixes</title>
		<link>http://www.stuffbysarah.net/2008/09/04/jquery-fixes/</link>
		<comments>http://www.stuffbysarah.net/2008/09/04/jquery-fixes/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 20:02:41 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=770</guid>
		<description><![CDATA[Last month (doesn&#039;t time fly!) I wrote about improving my jQuery, whereby I wanted to just improve the code I&#039;d been using on this project I&#039;ve been working on for 3 months now. I&#039;m all for more efficient code, and of course as with most programming languages, the more you use it, the more you [...]]]></description>
			<content:encoded><![CDATA[<p>Last month (doesn&#039;t time fly!) I wrote about <a href="/blog/2008/07/24/improving-my-jquery/" class="internal">improving my jQuery</a>, whereby I wanted to just improve the code I&#039;d been using on this project I&#039;ve been working on for 3 months now. I&#039;m all for more efficient code, and of course as with most programming languages, the more you use it, the more you learn, and the more efficient and improved your code becomes.</p>
<p>With thanks to <a href="http://www.hampton-smith.com/" class="external">Sam Hampton-Smith</a> and <a href="http://marcgrabanski.com/" class="external">Marc Grabankski</a> (who is the developer of the UI Datepicker, a fantastic jQuery popup calendar), I managed to get my questions answered, learning plenty in the process! I said I&#039;d write up what I actually did so that it&#039;s maybe of use to others (as I couldn&#039;t find a complete answer online anywhere).<br />
<span id="more-770"></span></p>
<h3>Resetting Select Lists</h3>
<p>My first problem was that I had a main select list and then each option had an ID as the value, for each ID there was a child select list. So you&#039;ve got parents and their children. However I didn&#039;t know how many parents there were, and used PHP to create a long list to reset each child select list. Marc&#039;s code was spot on except because of the way I had my code it was failing. See, the first option in the parents select list was blank, and by sending a blank value to the JavaScript function it collapsed as it expected a value other than zero. Once I sussed this I altered Marc&#039;s code to cope with this and finally got the following working:</p>
<dl class="code">
<dt>Reset Select List Function</dt>
<dd>
<ol>
<li>$(&#039;#parentid option&#039;).each(function(i,option) {</li>
<li class="indent1">var child_id = $(option).val();</li>
<li class="indent1">if (child_id != 0) {</li>
<li class="indent2">$(&#039;#child&#039;+child_id)[0].selectedIndex = 0;</li>
<li class="indent1">}</li>
<li>});</li>
</ol>
</dd>
</dl>
<p>As you can see on line 3 I&#039;ve got it checking whether the value of the option is empty, and providing it isn&#039;t it then runs the all important code. It&#039;s such a simple thing, but it took me a couple of hours of finally realising that was the problem!</p>
<h3>Removing Records</h3>
<p>My other problem was that I had a table of say regions, and within each region a number of postcodes are assigned to it. I wanted to allow them to remove a region but rather than just deleting the region and postcodes, to allow them to select the new region to put the postcodes into. Sounds straightforward enough, except I had an onsubmit(X) attribute in the form tag so that would trigger the function to do the work, the X would be the region to remove. That all worked except once you submitted the form it would do the work but then refresh the page, which meant the message to say &#039;The record has been removed&#039; wouldn&#039;t display. (At this point I&#039;ll mention that I know I could have done it with standard HTML and PHP but I wanted to put my new jQuery knowledge to good use and do it how WordPress does theirs!).</p>
<p>Thing is, my code was pretty much fine. To prevent a form from submitting, or a link from actually activating, you use <strong>return false;</strong>. That was there, so it was a bit confusing (and frustrating) as to why it wasn&#039;t working! Eventually I worked out that the event attributes (onsubmit, onchange etc) were the cause of the problem. The function didn&#039;t return false, despite being told to. So I had to pull the code into the jQuery document ready function and use a jQuery method to trigger it (submit(), change() etc). Okay, that bit was fine but as I was using the same function for every form (one per record) then I needed to know which record I was trying to remove, and also ensure the function ran on any form (all of which have unique IDs). So I finally came up with the HTML markup of:</p>
<dl class="code">
<dt>Form Markup</dt>
<dd>
<ol>
<li>&lt;form action=&#034;#&#034; class=&#034;manareas&#034; id=&#034;managearea_1&#034; method=&#034;post&#034;&gt;</li>
<li class="indent1">&lt;label for=&#034;area_1&#034;&gt;Move postcodes to:&lt;/label&gt;</li>
<li class="indent1">&lt;select name=&#034;area_1&#034; id=&#034;area_1&#034;&gt;</li>
<li class="indent2">&lt;option value=&#034;"&gt;Remove All Postcodes&lt;/option&gt;</li>
<li class="indent2">&lt;option value=&#034;2&#034;&gt;Area 2&lt;/option&gt;</li>
<li class="indent2">&lt;option value=&#034;3&#034;&gt;Area 3&lt;/option&gt;</li>
<li class="indent2">etc&#8230;</li>
<li class="indent1">&lt;/select&gt;</li>
</ol>
</dd>
</dl>
<p>Here the number 1 at the end of the form ID and select ID changes depending on the ID of the area, this will give the form a unique id, same goes for the select list. So, say you&#039;ve got 10 records, each with their own form similar to the above, each has a record ID in the id. Then when you want to remove a record you select your option from the list and it triggers the remove function in jQuery, however we obviously don&#039;t want a function for every record, so by adding the class &#039;manareas&#039; we can use that to trigger the function and every form has that on it. However, then we need to work out which record we&#039;re dealing with, so we get this from the form id, and then we&#039;re back on track i.e.</p>
<dl class="code">
<dt>Remove Record Function</dt>
<dd>
<ol>
<li>$(&#034;form.manareas&#034;).submit(function() {</li>
<li class="indent1">var id = $(this).attr(&#039;id&#039;);</li>
<li class="indent1">var id = id.split(&#039;_&#039;);</li>
<li class="indent1">var id = id[1];</li>
<li class="indent1">var newarea = $(&#039;#area_&#039; + id).val();</li>
<li>&nbsp;</li>
<li class="indent1">if (newarea != 0) {</li>
<li class="indent2">var conf = confirm(&#034;Do you really want to permanently delete this Area?&#034;);</li>
<li class="indent1">} else {</li>
<li class="indent2">var conf = confirm(&#034;Do you really want to permanently delete this Area and all the Postcodes in it?&#034;);</li>
<li class="indent1">}</li>
<li>&nbsp;</li>
<li class="indent1">if (conf) {</li>
<li class="indent2">$.get(&#034;/admin/includes/remArea.inc.php&#034;, {id: id, na: newarea}, function(data) {</li>
<li class="indent3">if (data) {</li>
<li class="indent4">var cnt = $(&#039;tr#row&#039; + newarea + &#039; td.njb&#039;).text();</li>
<li class="indent4">var cnt = (cnt-0) + (data-1);</li>
<li class="indent4">$(&#039;tr#row&#039; + newarea + &#039; td.cnt&#039;).text(cnt);</li>
<li class="indent4">$(&#039;#message&#039;).text(&#039;Area removed.&#039;).fadeIn();</li>
<li class="indent4">$(&#039;#row&#039; + id).fadeOut();</li>
<li class="indent3">} else {</li>
<li class="indent4">$(&#039;#message&#039;).text(&#039;Error removing Area.&#039;).fadeIn();</li>
<li class="indent3">}</li>
<li class="indent2">});</li>
<li class="indent1">}</li>
<li class="indent1">return false;</li>
<li>});</li>
</ol>
</dd>
</dl>
<p>So to explain the code. First the function is run when a form with a class of mantrades is submitted (line 1). Then we get the value of the id attribute (line 2), and split it (equivalent of PHP explode) using the underscore, to get the record number, which we then use to get the value selected in the form (line 4). Lines 7-11 just put up a confirmation box depending on which option is selected, just in case a clever client selects it and submits the form without thinking! Finally, if the user has confirmed yes to removing the area, the function that was originally written is executed, sending the ID and other information to the PHP script and making any changes, removing the row from the table etc. if successful. Then on line 26 we have the return false which of course stops the form from actually submitting the browser and refreshing the page.</p>
<p>So that&#039;s how I solved those two problems. It may not be the cleanest solution (the first is, the second can probably be improved), but it solved my issue which is what I needed <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/09/04/jquery-fixes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Improving my jQuery</title>
		<link>http://www.stuffbysarah.net/2008/07/24/improving-my-jquery/</link>
		<comments>http://www.stuffbysarah.net/2008/07/24/improving-my-jquery/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 20:59:54 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=762</guid>
		<description><![CDATA[Usually you blog about something, putting your opinion over about something. Well today it&#039;s my turn to ask the questions! I have a number of jQuery questions and figured I&#039;d leave them up here for either me to then find the answer or for someone who may know the answer to give me a few [...]]]></description>
			<content:encoded><![CDATA[<p>Usually you blog about something, putting your opinion over about something. Well today it&#039;s my turn to ask the questions! I have a number of jQuery questions and figured I&#039;d leave them up here for either me to then find the answer or for someone who may know the answer to give me a few hints <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>This isn&#039;t a &#039;how do I do this&#039;. What I have already works, but I&#039;m sure it could work a lot more efficiently and a couple of questions linger in my mind as to how or even whether it&#039;s possible.</p>
<p><strong>Update: I&#039;ve got the first issue working thanks to <a href="http://marcgrabanski.com/" class="external">Marc Grabanski</a> (who has an excellent site and is a must read for any jQuery user!)</strong></p>
<p>1. I need to create a function that resets several select lists. However the id of each select list is dynamically generated. What I have is a select list with a list of parents in and each has an ID. Then each parent has a child select list, and the child select list uses the parent ID to make it unique (with me so far?!). At present I use PHP to generate the function by looping through the parent IDs (retrieved from a database), which gives me:</p>
<dl class="code">
<dt>JavaScript function</dt>
<dd>
<ol>
<li>function resetLists() {</li>
<li class="indent1">$(&#039;#child1&#039;)[0].selectedIndex = 0;</li>
<li class="indent1">$(&#039;#child2&#039;)[0].selectedIndex = 0;</li>
<li class="indent1">$(&#039;#child3&#039;)[0].selectedIndex = 0;</li>
<li>}</li>
</ol>
</dd>
</dl>
<p>However, I&#039;m sure there must be a way that I can just use jQuery to read through all of the option values of the parent list and get the 1, 2 and 3 from that and do the same above i.e have a function that pretty much says &#039;get each value from the parent list and for each value set the selectedIndex to 0 for the child + value list. I&#039;m sure it&#039;s possible, but how, I don&#039;t know (yet).</p>
<p>2. This is one I&#039;ve not actually got working yet. I&#039;m working on an admin area and I&#039;ve got the parents listed in a table. Then at the end is the option to remove the parent. However as each parent has one or more children, the children need to be moved to another parent. So when you click &#039;Remove&#039; it gives a select list of the available parents to move the children to. You can select the new parent and then click Go. However at this point I don&#039;t want the form to actually submit and reload the page (which it&#039;s currently doing), I want the form to trigger a function which runs the PHP file to move the children, delete the parent and just remove the table row of the parent off the screen.</p>
<p>So far I&#039;ve got it to run the function, however once the function runs the page refreshes. The only way I&#039;ve got this function to run is by using the onsubmit attribute in the form tag. Now I know I could change the submit button to a standard button, but surely there&#039;s a way to prevent the form form submitting? I&#039;ve tried putting <em>return false;</em> at the end of the function that&#039;s run, but that doesn&#039;t seem to work. I&#039;ve tried putting the function in the action with javascript: at the start of it, but that really didn&#039;t work!</p>
<p><strong>Update: Some code may help. This is what I have at present.</strong></p>
<dl class="code">
<dt>Remove Function</dt>
<dd>
<ol>
<li>function exremtrade(id) {</li>
<li class="indent1">var newtrade = $(&#039;#trade_&#039; + id).val();</li>
<li class="indent1">$.get(&#034;/admin/includes/remTrade.inc.php&#034;, {id: id, nt: newtrade}, function(data) {</li>
<li class="indent2">if (data) {</li>
<li class="indent3">$(&#039;#message&#039;).text(&#039;Trade details removed.&#039;).fadeIn();</li>
<li class="indent3">$(&#039;#row&#039; + id).fadeOut();</li>
<li class="indent2">} else {</li>
<li class="indent3">$(&#039;#message&#039;).text(&#039;Error removing Trade details.&#039;).fadeIn();</li>
<li class="indent2">}</li>
<li class="indent1">});</li>
<li class="indent1">return false;</li>
<li>}</li>
</ol>
</dd>
</dl>
<p>I&#039;ve then got a form that has the attribute onsubmit which runs</p>
<p><code>onsubmit="exremtrade(2)"</code></p>
<p>Where &#039;2&#039; is the ID of the trade to remove. The new trade ID is in the select list, also in the form. Now if I remove the form and just use a button and the select list, it works. But of course that isn&#039;t valid, and ideally the form should be there just in case the user doesn&#039;t have JavaScript (plus I&#039;d like to understand why it&#039;s not working!). However, with the form in place, and the button as either a button or submit input, the function runs, works as it should, but then the form gets submitted which effectively refreshes the page and loses my update message.</p>
<p>That&#039;s my two questions so far. I&#039;m currently reading <a href="/amazon.php?id=1933988355" class="internal">jQuery in Action</a> thanks to <a href="http://www.siphilp.co.uk/" class="external">Si&#039;s</a> recommendation, which is a great book, I&#039;m just a slow reader! 2 months ago I didn&#039;t have a first clue about AJAX, and now I&#039;m quite confident with the basics. My first AJAX enabled site has been live for almost a week and it&#039;s not collapsed! I&#039;d just love to be able to improve it further <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/07/24/improving-my-jquery/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Playing with jQuery</title>
		<link>http://www.stuffbysarah.net/2008/06/30/playing-with-jquery/</link>
		<comments>http://www.stuffbysarah.net/2008/06/30/playing-with-jquery/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 17:42:53 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=753</guid>
		<description><![CDATA[I&#039;ve mentioned recently that I&#039;ve had to start dabbling in AJAX (do we still write this in capitals?) and whilst my work has mixed both the Prototype and jQuery frameworks, I&#039;m trying to learn jQuery and do everything in that so that I can drop Prototype. The main reason being that the jQuery framework is [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve mentioned recently that I&#039;ve had to start dabbling in <abbr title="Asynchronous JavaScript and XML">AJAX</abbr> (do we still write this in capitals?) and whilst my work has mixed both the <a href="http://www.prototypejs.org" class="external">Prototype</a> and  <a href="http://www.jquery.com" class="external">jQuery</a> frameworks, I&#039;m trying to learn jQuery and do everything in that so that I can drop Prototype. The main reason being that the jQuery framework is about half the size of Prototype, plus there seems to be more on the subject from what I&#039;ve seen so far (also the calendar I&#039;m using uses jQuery so it makes sense!).</p>
<p>I&#039;m still on the learning curve, a very steep one at that, and have started at the beginning on <a href="http://www.learningjquery.com/category/levels/beginner/page/5" class="external">Learning jQuery</a>, which has been a good read so far, with clear explanations. I&#039;ve also implemented a couple of scripts which may be of interest.</p>
<h3>The Calendar</h3>
<p>I&#039;ve been working on a form that asks for a date input (amongst a million and one other options!). Initially I gave a drop down but the client came back asking for a popup calendar. As I&#039;d started using Prototype on the site I was working on, I purposely went out and found a calendar that also worked on this. That was fine until the client complained that you could selected a date in the past. As this is for making bookings he wanted it to only accept present and future dates. Of course the PHP checked this, but he didn&#039;t want to have to submit the form to be told the date was invalid. That wasn&#039;t so hard, except then I was told that some options would also require the earliest date to be 2 days into the future. So I needed not only a calendar that would restrict the date on load, but also dynamically change depending on which options had been selected.</p>
<p>After a chat with a friend he pointed me in the direction of the <a href="http://docs.jquery.com/UI/Datepicker" class="external">UI Datepicker</a>, which seemed to do everything I needed and more. It&#039;s taken a fair bit of playing and testing to combine the various demos together, but I&#039;ve finally got it working exactly how I need it. On load it displays the available dates from &#039;today&#039; onwards. Then on selecting certain options, this changes to perhaps from &#039;tomorrow&#039; onwards or in two days time onwards. Certainly not standard requirements but definitely handy to have a good calendar that can deal with that.</p>
<h3>Tabs</h3>
<p>On another site I needed to get a tab system in place to allow more content on a page without overwhelming the visitor with it all on display. I looked at <a href="http://www.onlinetools.org/tools/domtabdata/" class="external">Dom Tabs</a> and at first they seemed to do exactly what I needed, until I had to add in headers around each list item. That stopped everything from working, so a quick search for a new tab system found <a href="http://docs.jquery.com/UI/Tabs" class="external">UI Tabs</a> where you can see some <a href="http://www.stilbuero.de/jquery/tabs_3/" class="external">great demos</a>.</p>
<p>I&#039;ve had a fair few fun and games with these. I originally found version 2 of the tabs, got them all working and then realised that they had come with an old version of jQuery (1.1.3 when 1.2.6 is available) and the next day I discovered the latest version! So I set about trying to get the latest version working but getting a download of the latest version just wasn&#039;t as easy or obvious. So today I went through the demo site, visited every page linked to, copied the source and got it working locally and then slowly transferred the content over to the site. Eventually I got it all running off the latest version of jQuery!</p>
<h3>Lightbox</h3>
<p>Finally, once I finally got the latest version of jQuery running, I could upgrade the lightbox script to <a href="http://www.no-margin-for-errors.com/projects/prettyPhoto/" class="external">prettyPhoto</a>. This was relatively simple to add in, except that the gallery method creates a slot for every image linked, regardless of whether it&#039;s already been linked to. In the old <a href="http://www.stuffbysarah.net/blog/2006/11/04/cool-image-enlarger/" class="internal">lightbox</a> it could detect this. For example, you have 3 images, and they also have a title/name below them. So you can click on the image or the name and get a larger view of the image. With the old lightbox it could detect this and just show you 3 large images in the gallery, but in this new script it shows 6 images, duplicating each one twice. Even if I set the 3 thumbnails to use gallery1 and the 3 titles to gallery2, it seems to note that there&#039;s only 3 images in the gallery but still goes by the order on the page in which the links are listed, and not by the gallery name.</p>
<p>Anyhow, small issues which are now irrelevant, as the site owner has changed his mind and picked a whole other lightbox script!</p>
<h3>Prototype to jQuery</h3>
<p>The main site I&#039;ve been working on, which currently has both frameworks loading, requires just one other job moving over, which I&#039;ve yet to learn. This is how to run a PHP file and subsequently write the result from that into a div or paragraph. I think the rest of my JavaScript is standard stuff and doesn&#039;t require either framework to run, and simply uses the DOM. So once I can work out this, probably simple, job then I can ditch prototype altogether.</p>
<p>Any other resources of learning for jQuery are welcomed. I may look at books at some point, but considering my ever growing library of unread books, an online resource may be looked at more initially!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/06/30/playing-with-jquery/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The Photoshop Anthology &#8211; Free SitePoint Book</title>
		<link>http://www.stuffbysarah.net/2008/05/14/the-photoshop-anthology-free-sitepoint-book/</link>
		<comments>http://www.stuffbysarah.net/2008/05/14/the-photoshop-anthology-free-sitepoint-book/#comments</comments>
		<pubDate>Wed, 14 May 2008 16:25:28 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=717</guid>
		<description><![CDATA[Looks like SitePoint are giving away another of their books in PDF for a limited time only. Go grab the Photoshop Anthology within 29 days for free.]]></description>
			<content:encoded><![CDATA[<p>Looks like SitePoint are giving away another of their books in PDF for a limited time only. Go grab the <a href="http://photoshop.aws.sitepoint.com/" class="external">Photoshop Anthology</a> within 29 days for free.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/05/14/the-photoshop-anthology-free-sitepoint-book/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Clients Updating Their Sites</title>
		<link>http://www.stuffbysarah.net/2008/05/08/clients-updating-their-sites/</link>
		<comments>http://www.stuffbysarah.net/2008/05/08/clients-updating-their-sites/#comments</comments>
		<pubDate>Thu, 08 May 2008 16:37:17 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/?p=713</guid>
		<description><![CDATA[When I first started out creating websites for clients, the option of a client being able to update their own site wasn&#039;t an option from me. I hadn&#039;t ever looked at a bit of PHP at that point (late 1990s) and everything was done by hand or in Dreamweaver (The Professional&#039;s choice so I read!). [...]]]></description>
			<content:encoded><![CDATA[<p>When I first started out creating websites for clients, the option of a client being able to update their own site wasn&#039;t an option from me. I hadn&#039;t ever looked at a bit of PHP at that point (late 1990s) and everything was done by hand or in Dreamweaver (<em>The Professional&#039;s choice</em> so I read!). Come forward several years, and we&#039;re in the age of clients easily updating and maintaining their sites. This is fine for certain types of sites, a shop for example, where the client browses for the photo of the product, fills in all of the boxes and hits go. It&#039;s very simple to use and it&#039;s very hard for the client to mess up (if coded in the right way). However, what about standard brochure style sites using a basic CMS or WordPress to power them. Is it such a good idea that clients can update their sites then?</p>
<p>My honest answer is no. Going by experience, when a client can update their own site mistakes will creep in. If you use a WYSIWYG online editor such as TinyMCE then you cannot copy and paste from Microsoft Word for example. Word adds additional formatting, unseen to the naked eye, until you paste it into the content box and save it. Kiss goodbye to that valid code. Unfortunately clients understand Word so they want to write everything in Word and cannot understand why they can&#039;t just copy and paste from there. I try to tell them that they need to paste it into Notepad first, then copy from there and paste it in, and redo their formatting within the online editor. Naturally some don&#039;t appreciate this as they&#039;re having to do work twice. MS Word has to be the biggest problem for any CMS and any developer. I&#039;ve seen what Word code can do to a page, varying font sizes, extra spacing all over the place, it certainly doesn&#039;t look good, and that&#039;s before you look at the markup. Some additions can go unnoticed until you&#039;re called in to fix something and then realise you&#039;ve got to redo all of the content whilst you&#039;re there. My favourite is when you remind the client of your original warning and that they&#039;ve copied in from Word and they deny it. Hmmm how else did the class of MsoNormal get in there (a typical Word class) or even more strange, the good ol&#039; &lt;o:p&gt; tag?</p>
<p>Some clients do listen though, and they only do their formatting via the online editor. Great you may think, haha think again. Clients like to make things stand out and we can do that tastefully and accessibly, but why ask the developer when they can highlight their title and make it bright red? Then highlight every heading and make it&#8230; bright red. Forget accessibility here, let&#039;s just make it multicoloured and leave the visitors to play &#039;find the link&#039;. I purposely hide the underline icon on a WYSIWYG toolbar, else they&#039;d have underlined coloured text and drive the visitors insane whilst trying to click what they think are links!</p>
<p>So colours and formatting are two of the downsides of allowing clients to edit their own content. Then you&#039;ll get one who knows a little about SEO, knows that words need to be on the page to be found for them in the search engines, so the next time you view your work of art for your client you&#039;ll find a large paragraph of stuffed keywords and brand names throughout it. Of course if you can see it, so can everyone else.</p>
<p>There are plenty more problems caused by clients updating their own sites. Maybe we&#039;ve given them too much control? Not only do you lose the income from updating the site for them, you also get the blame when they break something. True, a well written contract should cover this but in the past I&#039;ve not really had the guts to come out and say &#034;Umm it&#039;s not my fault, you have to pay me to fix it&#034;. I do appreciate it&#039;s not necessarily their fault. They treat their website like a Word Document and they don&#039;t know how to think like a web developer, but so if it&#039;s not their fault, it must be ours for giving them the option to cause havoc on their own site <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/05/08/clients-updating-their-sites/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Catching 404 Visitors</title>
		<link>http://www.stuffbysarah.net/2008/03/22/catching-404-visitors/</link>
		<comments>http://www.stuffbysarah.net/2008/03/22/catching-404-visitors/#comments</comments>
		<pubDate>Sat, 22 Mar 2008 17:44:40 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/2008/03/22/catching-404-visitors/</guid>
		<description><![CDATA[Running a site requires maintenance from time to time, perhaps an upgrade to the file structure too. Even if you&#039;ve not altered the file structure from the original set up, a simple mistake such as an incorrect link in your content, can cause a 404 Not Found error. Unless you&#039;ve set up a custom 404 [...]]]></description>
			<content:encoded><![CDATA[<p>Running a site requires maintenance from time to time, perhaps an upgrade to the file structure too. Even if you&#039;ve not altered the file structure from the original set up, a simple mistake such as an incorrect link in your content, can cause a 404 Not Found error. Unless you&#039;ve set up a custom 404 error page that offers a correct navigation to your main site (which I would recommend too, if you&#039;ve got the option), then you could lose each visitor, a potentially paying customer, when that get that dreaded 404 page and leave your site for good. Also, when a file structure is updated the old files will still be known to the search engine spiders and they&#039;ll continue to search for these files.<br />
<span id="more-1064"></span></p>
<h3>Find the Missing Files</h3>
<p>So what files do you need to cover? Well, ideally if you change your file structure then you&#039;ll accommodate every old path/filename, creating a 301 redirect to the new path. However incorrect links, by both yourself on your site and from external links, incorrectly written, can be found by using both your statistics package, to view all the 404 errors, and also <a href="http://www.google.com/sitemaps" class="external">Google Site Maps</a>, as this will list all the pages that the spider has tried to visit and found 404s.</p>
<h3>301s with htaccess</h3>
<p>If you run your site on an Apache server then you will most likely have access to edit your .htaccess file. This is the best method to control the redirection. To create a straightforward 301 redirect from one file to another, simply add the following, changing the old-filename and new-filename to suit what you need. Duplicate this line for every old to new file redirection you need to set up. The path is relative to the root of the site.</p>
<dl class="code">
<dt>Simple 301 Redirect</dt>
<dd>
<ol>
<li>Redirect 301 /old-filename.html /new-filename.html</li>
</ol>
</dd>
</dl>
<p>Okay, so that&#039;s for all standard pages, be them html, htm, php or others. But that doesn&#039;t work for file paths that include a query string eg. /old-filename.php?id=1234. So the code for this would be</p>
<dl class="code">
<dt>301 Redirect for query string paths</dt>
<dd>
<ol>
<li>Options +FollowSymLinks</li>
<li>RewriteEngine On</li>
<li>RewriteBase /</li>
<li>&nbsp;</li>
<li>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /old-filename\.php\?id=1234\ HTTP/</li>
<li>RewriteRule ^.*$ /new-filename.html? [R=301,L]</li>
</ol>
</dd>
</dl>
<p>The first 3 lines are only needed once at the top of your .htaccess file and are always needed for URL Rewriting (note it&#039;s not needed for the basic redirects in the first code block). Lines 5 and 6 then do the following:</p>
<ol>
<li>Check the value of THE_REQUEST (which could be, for example, &#034;GET /old-filename.php?id=1234 HTTP/&#034;)</li>
<li>Check the pattern of the string is a match</li>
<li>If it&#039;s a match then create a 301 redirect the URL to /new-filename.html</li>
</ol>
<p>The optional element in this code is the question mark on line 6 after the new-filename.html. If you have a question mark there then any query string from the old address will not be carried over, if you remove the question mark then it append any query string to the end of the new URL.</p>
<p>Now, you may ask, what happens if you have a lot of old filenames/paths and need to redirect them all to a new file structure, but there&#039;s a common theme with them. For example moving a handful of addresses from one directory to another. This can be done using just a couple of lines. For example you want to redirect from /olddir/oldfile.php?p=X to /newdir/newfile.php?p=X</p>
<dl class="code">
<dt>Multiple 301 Redirects</dt>
<dd>
<ol>
<li>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /olddir/oldfile\.php\?p=([^&#038;]+)\ HTTP/</li>
<li>RewriteRule ^.*$ /newdir/newfile.php?p=%1 [R=301,L]</li>
</ol>
</dd>
</dl>
<p>The slight change here to the previous code block is on the request string it determines the value of p in the query string (with could be anything except an ampisand) and whatever it finds it appends to the end of the redirect address, using the %1.</p>
<p>There are other methods of doing this, these are just two of the methods I use, however they should work for you.</p>
<h3>301 Redirects with PHP</h3>
<p>You may not have htaccess available to you which then limits you to using a server side script to do the same work. This unfortunately means that you need to have a file online for every old file you may have had in the past, and whilst that&#039;s tedious it only needs doing once and will hopefully be worthwhile even if you catch just one new customer. So how to do this with PHP? Create a new file and add the following to it:</p>
<dl class="code">
<dt>PHP 301 Redirect Code</dt>
<dd>
<ol>
<li>&lt;?php</li>
<li>header(&#034;HTTP/1.1 301 Moved Permanently&#034;);</li>
<li>header(&#034;Location:http://www.domain.com/directory/path-to-new-file.php&#034;);</li>
<li>exit;</li>
<li>?&gt;</li>
</ol>
</dd>
</dl>
<p>Save the file as the old filename and place it on your server in the same place where the old file used to be. This will then return a 301 redirection and redirect all visitors to the old file through to the new one. If your file accepted query strings then for a quick and simple solution you can use the following which will append any query string on to the end of the redirection URL.</p>
<dl class="code">
<dt>PHP 301 Redirect Code with Query String</dt>
<dd>
<ol>
<li>&lt;?php</li>
<li>header(&#034;HTTP/1.1 301 Moved Permanently&#034;);</li>
<li>header(&#034;Location:http://www.domain.com/directory/path-to-new-file.php?&#034;.$_SERVER['QUERY_STRING']);</li>
<li>exit;</li>
<li>?&gt;</li>
</ol>
</dd>
</dl>
<h3>301 Redirects with ASP</h3>
<p>Now my <abbr title="Active Server Pages">ASP</abbr> is pretty much non existent so I can&#039;t give much help on that. The following will do a basic redirect, and maybe someone a bit more knowledgeable can recreate the above code block in ASP.</p>
<dl class="code">
<dt>ASP 301 Redirect</dt>
<dd>
<ol>
<li>&lt;%</li>
<li>response.status = &#034;301 Moved Permanently&#034;</li>
<li>response.addheader &#034;Location&#034;, &#034;http://www.domain.com/directory/path-to-file.asp&#034;</li>
<li>%&gt;</li>
</ol>
</dd>
</dl>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/03/22/catching-404-visitors/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Secure PHP Contact Form</title>
		<link>http://www.stuffbysarah.net/2008/03/19/secure-php-contact-form/</link>
		<comments>http://www.stuffbysarah.net/2008/03/19/secure-php-contact-form/#comments</comments>
		<pubDate>Wed, 19 Mar 2008 12:05:18 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Learn PHP]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/2008/03/19/secure-php-contact-form/</guid>
		<description><![CDATA[I&#039;ve written up an easy to use, secure, accessible and XHTML Strict compliant contact form, originally for someone to use on their site, but figured I&#039;d post it up here as a bit of a PHP tutorial for anyone who wants to understand what&#039;s going on, or for others to just download, follow the instructions [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve written up an easy to use, secure, accessible and XHTML Strict compliant contact form, originally for someone to use on their site, but figured I&#039;d post it up here as a bit of a PHP tutorial for anyone who wants to understand what&#039;s going on, or for others to just download, follow the instructions and use. I&#039;ll explain its usage today and then dissect the form for any PHP learners later in the week.</p>
<p>First off, <a href="/plugins/contact-form.zip" class="zip">download the contact form</a>, unzip it and open it in your favourite coding editor. The best version of this form requires PHP 4.4+ however I&#039;ve altered the line that depends on this version so that you can use it down to version 4.0 however foreign characters will not be checked in the name. Both are contained in the download file.</p>
<p><span id="more-691"></span></p>
<p>This won&#039;t work straight out of the box. You&#039;ll need to edit a few lines first plus add in your surrounding HTML markup.</p>
<h3>Edit the Basics</h3>
<p>To get this up and running with minimal effort you need to do the following (from top down in the file).</p>
<ol>
<li>Edit the <strong>$to_email</strong> variable to contain your email address. So replace &#039;you@yourdomain.com&#039; with your own email address, ensuring the double quotes are still kept around the email address.</li>
<li>Edit the <strong>$redirect</strong> variable to contain the address, relative to the root, of your thank you page. So if your thank you page is found at http://www.yourdomain.com/contact/thankyou.html this value will become &#034;contact/thankyou.html&#034;.</li>
<li>Edit the <strong>$subject</strong> variable to contain the text you want to appear in your email subject when you receive an email from the form.</li>
<li>Locate the line &gt;!&#8211; Your Header HTML code or include goes here &#8211;&lt; and replace it with your standard site header markup. This could be a PHP include to include the header file, or plain HTML markup.</li>
<li>Locate the line &gt;!&#8211; Your footer HTML code or include goes here &#8211;&lt; and replace it with your standard site footer markup. Again, this can be a PHP include or the plain HTML markup.</li>
</ol>
<p>This should then leave you with a file that has the following sections:</p>
<ul>
<li>PHP Script</li>
<li>HTML Header markup</li>
<li>Form in the content area</li>
<li>HTML Footer markup</li>
</ul>
<p>At this point you should be able to upload this file to any PHP enabled server, view the file, complete the form and submit it. An email should then come through to your specified email account.</p>
<h3>Advanced Options</h3>
<p>There&#039;s two advanced options in this form. The first is to add additional fields into the form, and they&#039;ll still be picked up in the email. To do this, edit the form to include your additional form fields (checkboxes and file uploads are not supported in this form) using the following method (if you&#039;re not sure on working with forms, read up on <a href="http://www.ap4a.co.uk/archives/2006/stylephreaks-standard-form-layout-revisited/" class="external">accessible form layouts</a>):</p>
<dl class="code">
<dt>Form Code Excerpt</dt>
<dd>
<ol>
<li>&lt;div&gt;</li>
<li class="indent1">&lt;label for=&quot;cf<span class="red">text</span>&quot;&gt;<span class="red">Title</span>: &lt;/label&gt;</li>
<li class="indent1">&lt;input type=&quot;text&quot; name=&quot;cf<span class="red">text</span>&quot; id=&quot;cf<span class="red">text</span>&quot; size=&quot;30&quot; value=&quot;&lt;?php get_value(&apos;cf<span class="red">text</span>&apos;) ?&gt;&quot; /&gt;</li>
<li>&lt;/div&gt;</li>
</ol>
</dd>
</dl>
<p>Where <span class="red">text</span> makes up your input&#039;s fieldname. I would recommend keeping &#039;cf&#039; at the start of all of your fieldnames as this means there is less potential for variables to clash in the PHP and it can help to reduce spam as spammers will often assume your field names are the general ones of &#039;name&#039;, &#039;email&#039;, message&#039; etc. <span class="red">Title</span> is then the value displayed on the page, so the form label.</p>
<p>The second advanced option is to also control your required fields. Near the top of the script there is a line:</p>
<dl class="code">
<dt>PHP Code Excerpt</dt>
<dd>
<ol>
<li>// Specify the required fields</li>
<li>$req_fields = array(&quot;cfname&quot;, &quot;cfemail&quot;, &quot;cfmessage&quot;);</li>
</ol>
</dd>
</dl>
<p>This array lists the fields that are required to contain content. So if you added 3 extra fields, eg. cfurl, cftelephone and cfaddress and you want to make the telephone and address field required, but not the url field, then you can add these in by adding them to the end of the comma delimited list i.e.</p>
<dl class="code">
<dt>PHP Code Excerpt</dt>
<dd>
<ol>
<li>$req_fields = array(&quot;cfname&quot;, &quot;cfemail&quot;, &quot;cfmessage&quot;, &quot;cftelephone&quot;, &quot;cfaddress&quot;);</li>
</ol>
</dd>
</dl>
<p>This will then check that both the telephone and address fields have content in them, however the URL field can be left blank. Of course it will be wise to add</p>
<dl class="code">
<dt>HTML Code Excerpt</dt>
<dd>
<ol>
<li>&lt;em&gt;Required&lt;/em&gt;</li>
</ol>
</dd>
</dl>
<p>After the label title and before the closing label tag, as I&#039;ve done with the other required fields.</p>
<h3>Guarantees</h3>
<p>There are none! The form is secure to the best of my abilities. It checks against email header injection, it removes all html tags that may have been entered into the form, it checks the name entered contains just typical characters that a name would contain (including foreign characters)*, it checks your required fields contain content and it will email all details plus the user&#039;s given IP address and browser details through to your specified email address. By using less than general field names, spam should be reduced to human spam (I use this method elsewhere and rarely get any spam off my forms that&#039;s not human generated).</p>
<p>The form is accessible in that when you click a label title the cursor will be placed in the input box or textarea. It uses the correct markup of a fieldset and legends, and if you choose to extend the form I recommend you continue with these standards. Suggested <abbr title="Cascading Style Sheets">CSS</abbr> for the styling of a form and error warning is below.</p>
<dl class="code">
<dt>Suggested CSS Code</dt>
<dd>
<ol>
<li>ul.warning {</li>
<li class="indent1">color: #c00;</li>
<li class="indent1">font-weight: bold;</li>
<li>}</li>
<li>&nbsp;</li>
<li>fieldset {</li>
<li class="indent1">width: 500px;</li>
<li class="indent1">border:none;</li>
<li class="indent1">border-top: 1px solid #999;</li>
<li class="indent1">padding: 10px;</li>
<li class="indent1">margin-top: 10px;</li>
<li>}</li>
<li>&nbsp;</li>
<li>legend {</li>
<li class="indent1">font-weight: bold;</li>
<li class="indent1">padding: 0 5px;</li>
<li>}</li>
<li>&nbsp;</li>
<li>label {</li>
<li class="indent1">width: 125px;</li>
<li class="indent1">float: left;</li>
<li class="indent1">text-align: right;</li>
<li class="indent1">margin-right: 5px;</li>
<li>}</li>
<li>&nbsp;</li>
<li>form div {</li>
<li class="indent1">clear: both;</li>
<li class="indent1">margin-bottom: 10px;</li>
<li>}</li>
</ol>
</dd>
</dl>
<p>So give it a go and let me know what you think. Any problems or comments, post them below and I&#039;ll do my best to help out or accommodate you <img src='http://www.stuffbysarah.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>* Only in the PHP 4.4+ version.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2008/03/19/secure-php-contact-form/feed/</wfw:commentRss>
		<slash:comments>61</slash:comments>
		</item>
		<item>
		<title>Mod Rewrite Fun and Games</title>
		<link>http://www.stuffbysarah.net/2007/12/05/mod-rewrite-fun-and-games/</link>
		<comments>http://www.stuffbysarah.net/2007/12/05/mod-rewrite-fun-and-games/#comments</comments>
		<pubDate>Wed, 05 Dec 2007 23:55:49 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.stuffbysarah.net/2007/12/05/mod-rewrite-fun-and-games/</guid>
		<description><![CDATA[I&#039;ve been having fun and games with Mod Rewrite over the past few days. One of my clients has had an SEO go over the sites and come up with a report on improvements, one of which was mod rewrite. I&#039;ve known this needed doing for ages but as I didn&#039;t know how to do [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve been having fun and games with Mod Rewrite over the past few days. One of my clients has had an SEO go over the sites and come up with a report on improvements, one of which was mod rewrite. I&#039;ve known this needed doing for ages but as I didn&#039;t know how to do it I didn&#039;t due to lack of time for learning it. However now being faced with having to, and instead of being supplied with the code, just given links to a few sites to read, I&#039;ve blown my mind apart over it for the past 4 days! I&#039;m not about to go into the ins and outs of mod rewrite as there are plenty of sites out there that explain it. However I am going to go over what took me so long, not the rewrite but the redirects on the old domains.<br />
<span id="more-660"></span></p>
<h3>The Rewrite</h3>
<p>First off, to explain what mod rewrite is. Commonly used to turn dynamic URLs into static ones, ie. get rid of the question mark and variables. For example, on this site I have a form of mod rewrite running and the URL you&#039;ll see for this page is a clean, easy to read URL where as the true one would be /blog/?p=660. Essentially, by using mod rewrite you&#039;re masking the true URL with an easier to read one. You do this by creating an <strong>internal redirect</strong> which means that you tell the server (Apache only) that the clean URL should be loading the dynamic URL, but you&#039;re not telling it to actuall redirect to it, just to load the page. Make sense? Yeah I was confused first off too.</p>
<p>A redirect that anyone with an inkling of Apache knowledge with know, can look like</p>
<p><code>RewriteRule ^blog/about-me/$ /blog/?page_id=3 [R=301,L]</code></p>
<p>This says, if someone goes to the address /blog/about-me/ then redirect them to /blog/?page_id=3 and make it a 301 redirect so that spiders and bots also realise it&#039;s a permanent redirect. That&#039;s an <em>external redirect</em> as you are making the browser request the new page (with the R=301 bit) and the address in the URL bar would become the second address. So an internal redirect is virtually the same but without the request so</p>
<p><code>RewriteRule ^blog/about-me/$ blog/?page_id=3 [L]</code></p>
<p>This would then do the same, however in the URL bar the first address would be visible. That is the rewrite done. Pretty simple and straightforward. However my question was then, what about the old URLs. Afterall, this is for SEO and the last thing you want is to have the same page served up under two different URLs. This is what has had me going round in circles for the past few days. My first attempt was an external redirect as per the first code, but the opposite (ie. making the dynamic page redirect to the static page). This caused an endless loop and looking around the web a lot of people had the same issue but no one explained in plain english how to solve it.</p>
<h3>The Redirect</h3>
<p>After reading over various forums I finally came across some code that didn&#039;t explain it but after hacking around I managed to get it working. The final code being</p>
<p><code>Options +FollowSymLinks<br />
RewriteEngine On<br />
RewriteBase /<br />
# Internally rewrite friendly URL requests to script filepath<br />
RewriteRule ^test/$ test.php [L]<br />
#<br />
# Externally redirect client requests for unfriendly URL to friendly URL<br />
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /test\.php\ HTTP/<br />
RewriteRule ^test\.php$ /test/? [R=301,L]</code></p>
<p>This is a simple version. The actual file is test.php however I want people to use /test/ instead. So after the first 3 lines of code, which are needed only once, you have the internal redirect saying that if the address of /test/ is loaded, run test.php. Then the last 2 lines make the redirect work so that test.php cannot be loaded via the address bar (ie. you cannot go to /test.php as it will redirect to /test/). I had the second line of code, that&#039;s pretty obvious, it was the first line, the Rewrite Condition that I couldn&#039;t work out!</p>
<p>To explain this line it&#039;s easier to first see how the request would look:</p>
<blockquote><p>GET /test.php HTTP/1.1</p></blockquote>
<p>So the above is what THE_REQUEST would hold. The next part is a bit of pattern matching. The first bit says that the string should start with a 3-9 character long string of capital letters (GET, POST etc) followed by a space (\ ) then the filename of /test.php and then HTTP/ at the end followed by anything else (note with no $ at the end, there is no end of string determined so anything could follow the HTTP/ ). This line matches that the request was made by test.php and not /test/ so if this condition is met then a 301 redirect is made to send test.php off to /test/.</p>
<p>Of course because of the condition you could change the last line to just be:</p>
<p><code>RewriteRule ^.*$ /test/? [R=301,L]</code></p>
<p>However it&#039;s handy to know of both options.</p>
<h3>Query Strings</h3>
<p>Another pointer I had to work out for myself was that on this last line, the new URL can have a question mark at the end of it (/test/?). The difference with this determines whether a query string is appended to the end or not. For example, let&#039;s say you actually had the URL of test.php?id=hello and you wanted this to go to a: /test/?id=hello and b: /test/</p>
<p>So first off you need to update the condition to check on it having a query string. If you don&#039;t want to be too specific then you can easily do this with the following:</p>
<p><code>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /test\.php[^/]*\ HTTP/</code></p>
<p>This means that after test.php there is an option of other characters, other than a forwardslash. This would then make the condition true for test.php or test.php?id=hello. So to get this to redirect to /test/?id=hello you would change the last line to <strong>not</strong> have a question mark at the end ie.</p>
<p><code>RewriteRule ^.*$ /test/ [R=301,L]</code></p>
<p>This would then produce the desired effect and append any query string to the end of the new URL. To do the opposite of this, just add the question mark in, and then any query string would be ignored.</p>
<h3>Summary</h3>
<p>The above code will actually now allow you to set up mod rewrite however I&#039;ve just gone over the bits that got me stumped, afterall there&#039;s more than enough literature on the subject. The sites that got it through to me were</p>
<ul>
<li><a href="http://www.webmasterworld.com/forum92/6079.htm" class="external">Changing Dynamic URLs to Static URLs</a> &#8211; Webmaster World</li>
<li><a href="http://forums.searchenginewatch.com/showthread.php?t=3925" class="external">Mod Rewrite Tips and Tricks</a> &#8211; Search Engine Watch</li>
<li><a href="http://www.yourhtmlsource.com/sitemanagement/urlrewriting.html" class="external">URL Rewriting</a> &#8211; HTMLSource</li>
</ul>
<p>Plus an understanding of <a href="http://www.stuffbysarah.net/blog/2007/11/09/pattern-matching-with-php/" class="internal">Pattern Matching</a> may be of use too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stuffbysarah.net/2007/12/05/mod-rewrite-fun-and-games/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
