<?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>Everything In Between &#187; PHP</title>
	<atom:link href="http://maymay.net/blog/category/programming/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://maymay.net/blog</link>
	<description>The brutally honest, first-person account of Meitar Moscovitz&#039;s life.</description>
	<lastBuildDate>Tue, 22 May 2012 03:33:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Quick and Dirty: Clone Custom Field, Template Linked Files on Movable Type</title>
		<link>http://maymay.net/blog/2010/06/08/quick-and-dirty-clone-custom-field-template-linked-files-on-movable-type/</link>
		<comments>http://maymay.net/blog/2010/06/08/quick-and-dirty-clone-custom-field-template-linked-files-on-movable-type/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 01:19:02 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[Crosspost]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Movable Type]]></category>

		<guid isPermaLink="false">http://maymay.net/blog/?p=1238</guid>
		<description><![CDATA[Movable Type is a pretty frustrating platform to work with because every so often (or, &#8220;way too often,&#8221; depending on who you ask) a function of the system simply doesn&#8217;t do what you&#8217;d expect it to do. Such is the case with the &#8220;Clone Blog&#8221; functionality. Although it dutifully copies most of a website from [...]]]></description>
			<content:encoded><![CDATA[<p>Movable Type is a pretty frustrating platform to work with because every so often (or, &#8220;way too often,&#8221; depending on who you ask) a function of the system simply doesn&#8217;t do what you&#8217;d expect it to do. Such is the case with the &#8220;Clone Blog&#8221; functionality. Although it dutifully copies most of a website from one &#8220;blog&#8221; object to another, a few things are missing.</p>
<p>Most notably, custom fields and templates&#8217; linked files are not copied. This is a deal-breaker for any large installation that uses the built-in MT &#8220;Clone&#8221; feature.</p>
<p>To get around this limitation, I wrote a stupid, quick &#8216;n&#8217; dirty <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> script to finish the cloning process, called <code>finishclone.php</code>. It takes only 1 argument: the &#8220;new ID&#8221; you are cloning to. If all goes well, you&#8217;ll see output like this:</p>
<pre><samp>[root@dev www]$ </samp><kbd>php finishclone.php <var>28</var></kbd>
<samp>Cloning process complete.
[root@dev www]$ </samp></pre>
<p>In this example, <var>28</var> is the newly created blog&#8217;s ID. The blog you want to clone <em>from</em> is set as a constant within the script. I&#8217;ll leave modifying the script to support more flexible command line arguments as an exercise for the reader.</p>
<pre><code class="php">&lt;?php
/**
 * Ease the final steps in cloning a Movable Type blog.
 *
 * Description:   This script should be run after Movable Type's "Clone Blog"
 *                function has completed and before the cloned blog is used.
 *
 * Author:        "Meitar Moscovitz" &lt;meitar@maymay.net&gt;
 */

// Set constants.
define('MT_ORIG_BLOG', 0); // the ID of the blog you are cloning from
define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'movabletype');
define('MYSQL_PASS', '<var>PASSWORD_HERE</var>');
define('MYSQL_DB', 'movabletype');

// Get command line arguments.
if (2 &gt; $_SERVER['argc']) { die('Tell me the ID of the blog to clone into.'); }

$blog_id = (int) $argv[1];

// Connect to db
if ( !mysql_pconnect( MYSQL_HOST, MYSQL_USER, MYSQL_PASS ) ) {
	die( 'Connection to the database has failed: ' . mysql_error( ) );
}
mysql_select_db( MYSQL_DB );

// Clone custom fields.
$result = mysql_query('SELECT * FROM mt_field WHERE field_blog_id='.MT_ORIG_BLOG.';');
while ($row = mysql_fetch_object($result)) {
	mysql_query(
		sprintf("INSERT INTO mt_field ("
			."field_basename,"
			."field_blog_id,"
			."field_default,"
			."field_description,"
			."field_name,"
			."field_obj_type,"
			."field_options,"
			."field_required,"
			."field_tag,"
			."field_type) "
			."VALUES('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s');",
			mysql_real_escape_string($row-&gt;field_basename),
			mysql_real_escape_string($blog_id),
			mysql_real_escape_string($row-&gt;field_default),
			mysql_real_escape_string($row-&gt;field_description),
			mysql_real_escape_string($row-&gt;field_name),
			mysql_real_escape_string($row-&gt;field_obj_type),
			mysql_real_escape_string($row-&gt;field_options),
			mysql_real_escape_string($row-&gt;field_required),
			mysql_real_escape_string($row-&gt;field_tag),
			mysql_real_escape_string($row-&gt;field_type)
		)
	) OR print mysql_error() . "\n";
}

// Link template files to filesystem.
$arr = array();
$result = mysql_query('SELECT template_name,template_linked_file FROM mt_template WHERE template_blog_id='.MT_ORIG_BLOG.';');
while ($row = mysql_fetch_object($result)) {
	$arr[$row-&gt;template_name] = $row-&gt;template_linked_file;
}
foreach ($arr as $k =&gt; $v) {
	mysql_query("UPDATE mt_template SET template_linked_file='$v' WHERE template_blog_id=$blog_id AND template_name='$k';");
}

print "Cloning process complete.\n";</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2010/06/08/quick-and-dirty-clone-custom-field-template-linked-files-on-movable-type/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Add a post limit and output format to the WordPress Category Posts plugin v2.0</title>
		<link>http://maymay.net/blog/2008/09/19/add-a-post-limit-and-output-format-to-the-wordpress-category-posts-plugin-v20/</link>
		<comments>http://maymay.net/blog/2008/09/19/add-a-post-limit-and-output-format-to-the-wordpress-category-posts-plugin-v20/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 15:24:25 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tech/Computing]]></category>
		<category><![CDATA[Web Design]]></category>
		<category><![CDATA[Writing and blogging]]></category>

		<guid isPermaLink="false">http://maymay.net/blog/?p=643</guid>
		<description><![CDATA[Tonight I wrote a quick (and idiotic) patch to the very simple WordPress Category Post plugin v2.0. This backwards-compatible patch features: parameter-based post limit to define how many posts the plugin function will print parameter-based format option to output the posts in real &#60;li&#62; elements The wp-category-posts.php patch file is available for download here. To [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight I wrote a quick (and idiotic) patch to the very simple WordPress Category Post plugin v2.0. This backwards-compatible patch features:</p>
<ul>
<li>parameter-based post limit to define how many posts the plugin function will print</li>
<li>parameter-based format option to output the posts in real <code>&lt;li&gt;</code> elements</li>
</ul>
<p>The <a href='http://maymay.net/blog/wp-content/uploads/2008/09/wp-category-posts.patch'><code>wp-category-posts.php</code> patch file is available for download here</a>. To apply the patch, run the following commands at your shell promp:</p>
<pre class="shell">
cd <var>path/to/wordpress/installation</var>/wp-content/plugins/wordpress-category-posts
patch -p0 < <var>path/to/downloaded</var>/wp-category-posts.patch
</pre>
<p>I&#8217;m hoping this will get integrated as the next version of the plugin, perhaps version 2.1.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2008/09/19/add-a-post-limit-and-output-format-to-the-wordpress-category-posts-plugin-v20/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arbitrarily exclude posts from displaying in WordPress</title>
		<link>http://maymay.net/blog/2008/06/06/arbitrarily-exclude-posts-from-displaying-in-wordpress/</link>
		<comments>http://maymay.net/blog/2008/06/06/arbitrarily-exclude-posts-from-displaying-in-wordpress/#comments</comments>
		<pubDate>Fri, 06 Jun 2008 18:11:08 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[HOWTO]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Design]]></category>
		<category><![CDATA[Writing and blogging]]></category>

		<guid isPermaLink="false">http://maymay.net/blog/?p=437</guid>
		<description><![CDATA[When hacking away at WordPress sites, often times you&#8217;ll find yourself in a situation where you need to filter out certain posts from displaying on some pages, such as the home page. There are a lot of ways to do this, but few are perfect. Recently, I had the need to do this and went [...]]]></description>
			<content:encoded><![CDATA[<p>When hacking away at WordPress sites, often times you&#8217;ll find yourself in a situation where you need to filter out certain posts from displaying on some pages, such as the home page. There are a lot of ways to do this, but few are perfect. Recently, I had the need to do this and went searching for pre-existing solutions.</p>
<p>I came across <a href="//blog.gadodia.net/excluding-certain-categories-from-your-blog-main-page/">Vaibhav&#8217;s post on the topic</a> and noted that his solution uses the <a href="//codex.wordpress.org/Template_Tags/query_posts" title="WordPress documentation for the query_posts() function.">query_posts()</a> function to alter WordPress&#8217;s query object before <a href="//codex.wordpress.org/The_Loop">The Loop</a> has run. While this is a great solution if your exclusion criteria is simple enough to be supported directly by the WordPress query object, other times the query_posts() function doesn&#8217;t provide you with the hook you need.</p>
<p>In these cases, you can run the original query, note any modifications you need to make, and then create a new, modified query and display the results you get from running <em>that</em> one instead. For instance, you might need to do this if you need to exclude posts based on category and, say, the beginning of their title, or their category and a certain piece of content in the post itself, or all three, or any other combination you can think of.</p>
<p>Another advantage of this technique over simpler ones is that this method maintains the same behavior you&#8217;d expect to see in every other way. Most notably, this means that if you&#8217;ve told WordPress to display the 10 most recent posts on the home page (in the WordPress settings), you&#8217;ll still see ten posts on that page even after you exclude some of them.</p>
<p>To do something like excluding posts if they are in the &#8220;Uncategorized&#8221; category (traditionally the category with an ID of 1 in WordPress) and their title begins with &#8220;Some title&#8221;, you can do this:</p>
<pre class="php">
// original query runs in The (real) Loop first
while ( have_posts() ) : the_post();
    // detect pots matching our exclusion criteria
    if (in_category(1) &#038;&#038; (0 === strpos(the_title('', '', false), 'Some title')) ) {
        $wp_query->post_count++; // increment the post counter
        continue;
    }
    endif;
endwhile;
// now make a new query and show the posts for real, with the adjusted post count and filtering
$my_new_query = new WP_Query($query_string.'&#038;showposts='.$wp_query->post_count);
// do another The Loop (and display the results this time)
while ( $my_new_query->have_posts() ) : $my_new_query->the_post();
    // detect and exclude these same posts
    if (in_category(1) &#038;&#038; (0 === strpos(the_title('', '', false), 'Some title')) ) { continue; }

// ...the rest of the WordPress template goes here...
</pre>
<p>This is neat because it gives you the capability to define arbitrarily complex exclusion patterns and directly modify your new query object however you like before you execute it. Once you know this works, you&#8217;ll probably want to extract the filtering code into a function. Using the above example, your new code might look like this:</p>
<pre class="php">
<strong>// define criteria for filtering
function matches_filtering_criteria () {
    if (in_category(1) &#038;&#038; (0 === strpos(the_title('', '', false), 'Some title')) ) {
        return true;
    } else {
        return false;
    }
}</strong>
// original query runs in The (real) Loop first
while ( have_posts() ) : the_post();
    // detect pots matching our exclusion criteria
    if (<strong>matches_filtering_criteria()</strong>) {
        $wp_query->post_count++; // increment the post counter
        continue;
    }
    endif;
endwhile;
// now make a new query and show the posts for real, with the adjusted post count and filtering
$my_new_query = new WP_Query($query_string.'&#038;showposts='.$wp_query->post_count);
// do another The Loop (and display the results this time)
while ( $my_new_query->have_posts() ) : $my_new_query->the_post();
    //
    // detect and exclude these same posts
    if (<strong>matches_filtering_criteria()</strong>) { continue; }

// ...the rest of the WordPress template goes here...
</pre>
<p>For more information on these functions, see:</p>
<ul>
<li><a href="//codex.wordpress.org/The_Loop">The Loop</a></li>
<li><a href="//codex.wordpress.org/Template_Tags/in_category">in_category()</a></li>
<li><a href="//codex.wordpress.org/Template_Tags/the_title">the_title()</a></li>
<li><a href="//codex.wordpress.org/Function_Reference/WP_Query">WP_Query()</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2008/06/06/arbitrarily-exclude-posts-from-displaying-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>WordPress Collapsible Archive Widget 2.1 BETA with Collapsible Month Lists</title>
		<link>http://maymay.net/blog/2007/10/23/wordpress-collapsible-archive-widget-21-beta-with-collapsible-month-lists/</link>
		<comments>http://maymay.net/blog/2007/10/23/wordpress-collapsible-archive-widget-21-beta-with-collapsible-month-lists/#comments</comments>
		<pubDate>Tue, 23 Oct 2007 18:35:04 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[Maybe Maimed]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://maymay.net/blog/archives/2007/10/23/wordpress-collapsible-archive-widget-21-beta-with-collapsible-month-lists/</guid>
		<description><![CDATA[I went searching for a WordPress widget that enabled me to place a collapsible archive control much like the ones available in Blogger blogs &#8220;archives&#8221; widget a while back. With a little googling, I found a plugin that did almost exactly what I wanted in Ady Romantika&#8216;s Collapsible Archive Widget. After a few days of [...]]]></description>
			<content:encoded><![CDATA[<p>I went searching for a WordPress widget that enabled me to place a collapsible archive control much like the ones available in Blogger blogs &#8220;archives&#8221; widget a while back. With a little googling, I found a plugin that did almost exactly what I wanted in <a href="//romantika.name/v2/2007/08/10/wordpress-plugin-collapsible-archive-widget/">Ady Romantika</a>&#8216;s <a href="//wordpress.org/extend/plugins/collapsible-archive-widget/">Collapsible Archive Widget</a>.</p>
<p>After a few days of playing with it, I had a working copy that reproduced the original behavior or, optionally, exposed each month&#8217;s individual posts inside each month&#8217;s own collapsible list.</p>
<p>The patch I submitted to Ady is still awaiting integration with the main plugin, so in the meantime you can <a href="//maymay.net/blog/wp-content/uploads/2007/10/collapsible-archive-widget-21-beta.zip" title="Collapsible Archive Widget 2.1 BETA">download the plugin here</a>.</p>
<p>The full description follows:</p>
<blockquote cite="//maymay.net/blog/wp-content/uploads/2007/10/collapsible-archive-widget-21-beta.zip"><p>Collapsible Archive Widget 2.1 BETA is an update to the Collapsible Archive Widget for WordPress that includes a new option in the widget&#8217;s settings page that allows you to display links to the individual posts inside each month. With this setting activated, the year is expanded by default to show a list of months. Each month is another list, collapsed by default, that expands to reveal the individual post links.</p></blockquote>
<p><strong>Update:</strong> <a href="//wordpress.org/extend/plugins/collapsible-archive-widget/">A new version of the plugin</a> that incorporates the options I&#8217;ve added can now be downloaded from the WordPress plugin directory.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2007/10/23/wordpress-collapsible-archive-widget-21-beta-with-collapsible-month-lists/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tom Whitbread on Building a MySQL Database Abstraction Class in PHP</title>
		<link>http://maymay.net/blog/2005/04/27/tom-whitbread-on-building-a-mysql-database-abstraction-class-in-php/</link>
		<comments>http://maymay.net/blog/2005/04/27/tom-whitbread-on-building-a-mysql-database-abstraction-class-in-php/#comments</comments>
		<pubDate>Wed, 27 Apr 2005 21:04:51 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">/?p=235</guid>
		<description><![CDATA[Congratulations to my good friend <a href="http://www.titbread.co.uk" title="Tom's home page.">Tom Whitbread</a> on his <a href="http://www.phparch.com/issue.php?mid=55" title="php&#124;architect April Issue overview, including Tom's article.">recent publication</a> in <a href="http://www.phparch.com/" title="A magazine for programmers and web developers.">php&#124;architect</a>, <cite>Building a MySQL Database Abstraction Class</cite>.]]></description>
			<content:encoded><![CDATA[<p>Congratulations to my good friend <a href="http://www.titbread.co.uk" title="Tom's home page.">Tom Whitbread</a> on his <a href="http://www.phparch.com/issue.php?mid=55" title="php|architect April Issue overview, including Tom's article.">recent publication</a> in <a href="http://www.phparch.com/" title="A magazine for programmers and web developers.">php|architect</a>, <cite>Building a MySQL Database Abstraction Class</cite>.</p>
<blockquote cite="http://www.phparch.com/issue.php?mid=55"><p>Database abstraction is not just useful to promote database agnosticism&mdash;it can be used to improve database interaction all around! In this article, Tom Whitbread shows you how to tame the MySQL <acronym title="Application Programming Interface">API</acronym> by creating a class which will handle errors, allow query execution, transport results, and strip or add slashes to your input data.</p>
</blockquote>
<p>Great work, Tom, and thanks for sharing your work with the community.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2005/04/27/tom-whitbread-on-building-a-mysql-database-abstraction-class-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Good URL Design to Create a Breadcrumb Navigation System In PHP</title>
		<link>http://maymay.net/blog/2005/03/21/php-breadcrumb-navigation-using-url-design/</link>
		<comments>http://maymay.net/blog/2005/03/21/php-breadcrumb-navigation-using-url-design/#comments</comments>
		<pubDate>Mon, 21 Mar 2005 11:38:52 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[Information Architecture]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">/?p=212</guid>
		<description><![CDATA[By designing and using a meaningful, cruft-free URL scheme you can easily implement a dynamic, scalable, breadcrumb navigation trail on your entire site with minimal fuss, all in about 30 lines of PHP. I kid you not!]]></description>
			<content:encoded><![CDATA[<p>One fundamental aspect of any good navigation system is a mechanism to let users know where they are in relation to the rest of the content. On the Web, one of the <a href="http://www.webdesignpractices.com/navigation/breadcrumb.html" title="Simple survey of sites on breadcrumb navigation.">most popular</a> and <a href="http://psychology.wichita.edu/surl/usabilitynews/51/breadcrumb.htm" title="Usability study on breadcrumb navigation.">thoroughly studied</a> ways to reflect this information is in a so-called breadcrumb navigation trail or bar. This navigation bar lists the categories and subcategories (or sections and subsections) of the page which the user is browsing.</p>
<p>(Quick-minded readers will be quick to point out that the term <em>breadcrumb</em> navigation trail, which originates from the Hansel and Gretel story, is not entirely accurate. In the story, Hansel and Gretel left a trail of breadcrumbs as they wandered through the forest so they could retrace their steps back home. On a web site, the breadcrumb navigation trail reflects the current page&#8217;s position in the site hierarchy, <em>not</em> the path the user has taken through the site.)</p>
<h3>Defining the Requirements of Breadcrumb Navigation</h3>
<p>When I started looking for ways to easily implement a breadcrumb navigation trail on my web site, I immediately saw the potential complexity of the project. The hierarchical navigation system needed to:</p>
<ul>
<li>Accurately reflect a page&#8217;s position in the hierarchical information architecture of <em>the site</em> and not the physical location of the page in my web server. (This is important for me because I&#8217;m constantly moving things around.)</li>
<li>Present a nicely formatted label for each level of depth.</li>
<li>Automatically adjust itself for new pages, so I would never have to deal with it when adding new sections to my site.</li>
<li>Not require any &ldquo;heavy&rdquo; database or large application to use <em>and scale</em>.</li>
</ul>
<p>Additionally, the module should:</p>
<ul>
<li>Produce semantic, valid <acronym title="HyperText Markup Language">HTML</acronym> marked up <em>as a list</em>.</li>
<li>Link all elements in the list to their appropriate page level.</li>
<li>Not link the last level, which should display the current location of the user in the site. (We don&#8217;t need a link back to the same page we&#8217;re already on.)</li>
</ul>
<h3>Searching for Inspiration</h3>
<p>The first thing I, like any good programmer, went to do was search for existing code. Unfortunately, there is an appallingly small amount of <a href="http://www.google.com/search?q=dynamic+breadcrumb+navigation" title="Search google.">information on implementing breadcrumb navigation</a> out there. Sure, they&#8217;ll tell you what it is and what it&#8217;s good for, even convince you why you should have it, but as for actually implementing it goes&hellip;sorry, you&#8217;re on your own.</p>
<p>Every tutorial I found on the matter was decidely sub-par or completely failed to meet my requirements, listed above. Most sites stated the need for databases to create truly scalable and customizeable breadcrumb trails. Of course, nothing can compete with a fully integrated <acronym title="Relational DataBase Management System">RDBMS</acronym> solution, but with intelligent information architecture you can come pretty darn close.</p>
<h3>Using the <acronym title="Uniform Resource Locator">URL</acronym> to Our Advantage</h3>
<p>Thankfully, there is already a system of hierarchical navigation readily available to us. In fact, there are two!</p>
<ol>
<li><strong>Directory trees on your web server.</strong> The folders in which your files are stored are probably already sorted somewhat logically and categorically.</li>
<li><strong>The <acronym title="Uniform Resource Locator">URL</acronym> of the requested page.</strong> The address bar in your browser drills down through these categories to get to the final page.</li>
</ol>
<p>Both of these systems provide a basis from which we can draw upon to create a simple, self-organizing breadcrumb navigation system on a web site of almost any size. However, there are a few problems with the first method. (If you want to implement that method anyway, here&#8217;s a <a href="http://www.zend.com/zend/spotlight/breadcrumb28.php" title="Zend's Code Gallery Spotlight on breadcrumb navigation based on directory trees.">tutorial</a> based around using a directory tree.)</p>
<ul>
<li><strong>It doesn&#8217;t scale.</strong> If you&#8217;ve got a huge web site, you&#8217;re not going to keep all that data on static files on your web server. It would also be a full-time job to categorize and sort that content on said server! Oi, vey!</li>
<li><strong>It&#8217;s dependant on your organization system.</strong> If you&#8217;re anything like me, you don&#8217;t necessarily have folders within folders within folders just to store files, and if you do, you probably change them around pretty often to suit your needs. Unfortunately, basing breadcrumb navigation on <em>your</em> view of your information as opposed to <em>your visitor&#8217;s view</em> of the same information is a recipe for disaster in all but the smallest web sites.</li>
</ul>
<p>Thus, the only remaining solution was to rope the <acronym title="Uniform Resource Locator">URL</acronym> of the page into service to serve as the basis for a breadcrumb navigation system. Even so, there is one huge obstacle to overcome with this method. <strong>The <acronym title="Uniform Resource Locator">URL</acronym> itself must not be attached to a physical filesystem on the web server.</strong></p>
<p>Otherwise, we&#8217;re just basically using the filesystem hierarchy, which we&#8217;ve already seen is not adequete for our needs. So we need a way to abstract, or detach, the <acronym title="Uniform Resource Locator">URL</acronym> from the filesystem itself. Enter <code>mod_rewrite</code>, stage left.</p>
<h3>Abstracting the <acronym title="Uniform Resource Locator">URL</acronym> from the Filesystem</h3>
<p>Abstracting the <acronym title="Uniform Resource Locator">URL</acronym> from the filesystem is the critical step to enabling truly scalable, self-organizing breadcrumb navigation using such a simple foundation. This is essential because the <acronym title="Uniform Resource Locator">URL</acronym> of your page is the thing that will always be live; if the <acronym title="Uniform Resource Locator">URL</acronym> changes, so has your page! This change will then be reflected automatically in the breadcrumb navigation trail.</p>
<p>There are a number of other benefits to abstracting the <acronym title="Uniform Resource Locator">URL</acronym> of a page away from the physical filesystem it represents. I&#8217;ve even talked about some of them before when I blogged about <a href="http://www.maymay.net/blog/archives/2004/12/13/fun-with-apache-redirects/?r-msg=Abstracting+URLs+away+from+the+filesystem+enables+seamless%2c+invisible+behind-the-scenes+reorganization%3A#seamless-reorganization" title="Reorganize at will, and don't break links!">playing with Apache</a> and when <a href="http://www.maymay.net/blog/archives/2004/11/14/tips-to-improve-search-engine-rankings-of-cms-generated-content/?r-msg=Search+engines+and+site+visitors+alike+both+want+and+need+friendly+URLs%3A#friendly-urls-for-spiders" title="What you can do to help your dynamic pages rank better in search engines.">I suggested tips</a> for improving search engine rankings of <acronym title="Content Management System">CMS</acronym>-generated content.</p>
<p>The basic prerequisite for a good <acronym title="Uniform Resource Locator">URL</acronym> schema, however, is solid information architecture. This means having a well-defined and clear structure to your site so information is easily findable and properly labelled, categorized, and placed within the system you use. Only after you create a sound <acronym title="Uniform Resource Locator">URL</acronym> design schema free of any unsightly cruft which succinctly encodes the hierarchy of your site will you be able to leverage them to their fullest potential. (Phew, that was a mouthful!)</p>
<p>So, since this is not a post about <acronym title="Uniform Resource Identifier">URI</acronym> design (see <a href="#uri-design-resources" title="The end of this entry has additional resources on designing meaninful web addresses.">these resources</a> for articles on that), let&#8217;s assume you&#8217;ve done all that and are ready to implement your schema. The tools you&#8217;ll need are:</p>
<ul>
<li>The <a href="http://httpd.apache.org/" title="Don't worry, it's free!">Apache web server</a>.</li>
<li>Its <code><a href="http://httpd.apache.org/docs/mod/mod_rewrite.html" title="Comes standard with most Apache installations.">mod_rewrite</a></code> module.</li>
<li>Access to the server configuration file or the ability to use <code>.htaccess</code> files.</li>
<li>Later on, you&#8217;ll also need <a href="http://php.net/" title="Also free-of-charge!"><acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym></a>, for the coding thing.</li>
</ul>
<p>To make things simple, I&#8217;ll use <a href="http://maymaymedia.com/" title="The site I actually implemented this whole thing on.">my site</a> as an example.</p>
<p>For my own site, I have several sections (&ldquo;About,&rdquo; &ldquo;Services,&rdquo; &ldquo;News &amp; Weblog,&rdquo; etc.) and several top level pages that stand on their own (&ldquo;Home,&rdquo; &ldquo;Contact&rdquo;). Additionally, each section has an index page to ensure that no hierarchical level of my site is without its corresponding landing page.</p>
<p>This was going to be represented with straight-forward URLs that looked like this:</p>
<ul>
<li>The &ldquo;Home&rdquo; page would have this URL: <code>http://www.maymay.net/maymaymedia/</code></li>
<li>So-called &ldquo;top-level&rdquo; pages would look like this:
<ul>
<li>For the &ldquo;Contact&rdquo; page: <code>http://www.maymay.net/maymaymedia/contact/</code></li>
<li>For the &ldquo;About Us&rdquo; page: <code>http://www.maymay.net/maymaymedia/about/</code></li>
<li>For the &ldquo;Services&rdquo; page: <code>http://www.maymay.net/maymaymedia/services/</code></li>
</ul>
</li>
<li>Second-level pages would have URLs such as these:
<ul>
<li>For each service:
<ul>
<li>http://www.maymay.net/maymaymedia/services/web-programming/</li>
<li>http://www.maymay.net/maymaymedia/services/web-accessibility/</li>
<li>http://www.maymay.net/maymaymedia/services/web-site-optimization/</li>
</ul>
<li>For each &ldquo;About&rdquo; page, for instance:
<ul>
<li>http://www.maymay.net/maymaymedia/about/accessibility/</li>
<li>http://www.maymay.net/maymaymedia/about/philosophy/</li>
<li>http://www.maymay.net/maymaymedia/about/technology/</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>My files are stored pretty simply on my web server. Some pages, like the &ldquo;Contact&rdquo; page are stored in the <code>maymaymedia</code> directory but not in their own sub-directory. Other pages, like the &ldquo;Services&rdquo; and &ldquo;About&rdquo; pages, are stored in the <code>services</code> and <code>about</code> directories, respectively</p>
<p>This created filenames like <code>maymaymedia/contact.php</code> and <code>maymaymedia/about/index.php</code>. That <code>.php</code> stuff had to go!</p>
<h4>Writing Your <code>.htaccess</code> File</h4>
<p>Using the magic of <code>mod_rewrite</code>, a few relatively simple lines added to your <code>.htaccess</code> file is all it takes to turn these filenames into these beautiful cruft-free URLs.</p>
<p>Creating the sections was easy enough. Some of the work was already done by keeping the pages in their own directory (such as &ldquo;Services,&rdquo; for me) so I didn&#8217;t even <em>have</em> to do anything. Of course, to be safe, I could future-proof my site to abstract these directory trees using additional lines in my <code>.htaccess</code> file, but for the sake of simplicty we&#8217;ll leave it as is.</p>
<p>Here are a few relevant snippets from my <code>.htaccess</code> file:</p>
<pre>RewriteEngine On
RewriteBase /maymaymedia/
[&hellip;]
RewriteRule ^about/technology/?$ /maymaymedia/about/tech.php
RewriteRule ^about/philosophy/?$ /maymaymedia/about/philosophy.php
RewriteRule ^about/accessibility/?$ /maymaymedia/about/access.php
[&hellip;]
RewriteRule ^services?/web-site-optimization/?$ /maymaymedia/services/wso.php
RewriteRule ^services?/web-programming/?$ /maymaymedia/services/webprogramming.php
RewriteRule ^services?/web-accessibility/?$ /maymaymedia/services/accessconsult.php
[&hellip;]
RewriteRule ^contact/?$ /maymaymedia/contact.php</pre>
<p>These merely map simple <acronym title="Uniform Resource Locator">URL</acronym>&#8216;s onto the appropriate files for the specific page on my server, creating the nice breadcrumb-like <acronym title="Uniform Resource Identifier">URI</acronym> structure we can now use to automate the process of generating our hierarchical navigation bar.</p>
<p>There are two main points to keep in mind when creating such <acronym title="Uniform Resource Locator">URL</acronym> schemes.</p>
<ul>
<li><strong>Use a standardized syntax.</strong>
<p>Don&#8217;t mix and match symbols. Choose one syntax and stick with it. I used a hyphen (-) to simulate spaces, since spaces are not allowed in URIs. You could also use the underscore (_) if you wanted, but hyphens don&#8217;t require users to press the <kbd>shift</kbd> key.</p>
</li>
<li><strong>Make the <acronym title="Uniform Resource Locator">URL</acronym> descriptive.</strong>
<p>Since we&#8217;re going to be using these URLs as our breadcrumb navigation labels, they need to be as descriptive as possible. Keep them short enough to easily type but long enough to provide context. For instance, I could have used <code>wso</code> instead of <code>web-site-optimization</code> but how many people know that that&#8217;s what <acronym title="Web Site Optimization">WSO</acronym> stands for?</p>
<p>Besides, including the whole phrase boosts our search engine rankings by embedding our keywords into the <acronym title="Uniform Resource Locator">URL</acronym> itself! A nice bonus which also enhances usability.</p>
<p>If you&#8217;re really worried about optimizations (for instance, because you&#8217;ll have to write all your links like <code>href="/services/web-site-optimization/"</code>) then you can use a redirection script and point your links at something like <code>href="/r/wso/"</code> which would then automatically redirect to the expanded <acronym title="Uniform Resource Locator">URL</acronym>.</p>
</li>
</ul>
<h3>Coding the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> Breadcrumb Navigation Bar</h3>
<p>Now we&#8217;re ready to leverage the inherent advantages of good <acronym title="Uniform Resource Locator">URL</acronym> design to create our scalable <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> breadcrumb navigation script. I use a special <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> script called <code>navbar.php</code> to dynamically generate all of my navigation, so that&#8217;s where the code will go. <code>navbar.php</code> can then be <acronym title="Server Side Include">SSI</acronym>&#8216;ed or <code>include()</code>&#8216;ed on our page template so it will be present in all the pages we create from here on out.</p>
<p>The breadcrumb navigation script needs to do a few things. The code flow looks like this:</p>
<ul>
<li>Grab the requested <acronym title="Uniform Resource Identifier">URI</acronym> and break it into its path components.</li>
<li>Initialize (or remove) the first (&ldquo;top&rdquo;) element.</li>
<li>Count the remaining elements.</li>
<li>Check for trailing slashes on the last element, and remove it if necessary (such as if its empty or it&#8217;s just a query string).</li>
<li>Loop through all the elements, placing them within <code>&lt;li&gt;&lt;/li&gt;</code> <acronym title="HyperText Markup Language">HTML</acronym> elements as well as <code>&lt;a&gt;&lt;/a&gt;</code> if we are not at the last level.</li>
</ul>
<h4>Stepping Through the Code</h4>
<p>First, we start our <acronym title="HyperText Markup Language">HTML</acronym> by providing a header (which we can later set to <code>display:none;</code> in our <acronym title="Cascading Style Sheets">CSS</acronym>) and starting the list element. Due to the specific nature of my site structure (the site starts in a sub-directory of my main site), I also chose to always print the main &ldquo;Maymay Media Home&rdquo; link. You don&#8217;t have to do this.</p>
<pre>&lt;h3&gt;Hierarchical Navigation&lt;/h3&gt;
&lt;ul id="hier-nav"&gt;
&lt;li id="hier-homeLnk"&gt;&lt;a href="/maymaymedia/" title="Maymay Media Home"&gt;Maymay Media&lt;/a&gt;&lt;/li&gt;</pre>
<p>Next, we start the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> magic, grab the <acronym title="Uniform Resource Identifier">URI</acronym> the browser requested and break it on the slashes with <code><a href="http://php.net/explode" title="Documentation for the explode() function.">explode()</a></code>.</p>
<pre>&lt;?php
<var>$url_parts</var> = explode('/', <var>$_SERVER</var>['REQUEST_URI']);</pre>
<p>Now the <code><var>$url_parts</var></code> variable contains an array, each element of which is a segment of the path from the requested <acronym title="Uniform Resource Identifier">URI</acronym>. Since a <acronym title="Uniform Resource Identifier">URI</acronym> request always starts with a leading <code>/</code>, the first element of our <code><var>$url_parts</var></code> variable is an empty string. That&#8217;s somewhat useless for us, so we&#8217;ll get rid of it.</p>
<pre>array_shift(<var>$url_parts</var>); // first item always empty in URLs</pre>
<p><strong>In my particular case</strong>, the second element will always correspond to the <code>maymaymedia</code> sub-directory I have my site in. Thus, the second element of this array is also useless to me, since I chose to always print this &ldquo;top level&rdquo; link before we even started the conditional code. Thus, I get rid of the second element, too. (You may not want to do this in your script!)</p>
<pre>array_shift(<var>$url_parts</var>); // second item unneeded since always contains "maymaymedia" due to my site structure</pre>
<p>Now we need to count how many elements are left in our array which will tell us how many list items we need to make and where to find the end of our array so we can identify the last element. Remember, we&#8217;re going to need to check if the last element is empty or not because we don&#8217;t know if the visitor entered a trailing slash in the address bar.</p>
<p>If the last element is empty like the first one then we don&#8217;t need it. We also don&#8217;t need it if all it contains is a query string, so in either case we can pop it off the end of our array and decrement the variable we use to store the size of our array.</p>
<pre><var>$num_parts</var> = count(<var>$url_parts</var>);
// remove last element if empty or if a query string
if (empty(<var>$url_parts</var>[<var>$num_parts</var>-1]) || <var>$url_parts</var>[<var>$num_parts</var>-1] == '?'.<var>$_SERVER</var>['QUERY_STRING'])
{
    array_pop(<var>$url_parts</var>);
    <var>$num_parts</var>&#45;&#45;; // decrement to keep track
}</pre>
<p>Now we have all the data we need to construct our breadcrumb navigation list. The first step is to start the second list item and insert a separator (I chose a &ldquo;&gt;&rdquo; character), and then to format our <acronym title="Uniform Resource Locator">URL</acronym> strings into a more human-readable format. Basically, that just means replacing all of the &ldquo;<code>-</code>&rdquo; characters with spaces, and then capitalizing the first character of all the resulting words.</p>
<pre>for (<var>$i</var>=0; <var>$i</var>&lt;<var>$num_parts</var>; <var>$i</var>++)
{
    echo '&lt;li&gt; &amp;gt; ';
    <var>$p</var> = ucwords(str_replace('-', ' ', <var>$url_parts</var>[<var>$i</var>])); // format 'things-like-this' to 'Things Like This'</pre>
<p>(Of course, advanced <acronym title="Cascading Style Sheets">CSS</acronym> coders will note that inserting a physical character in the <acronym title="HyperText Markup Language">HTML</acronym> markup is unnecessary since we can use a <acronym title="Cascading Style Sheets">CSS</acronym> rule such as <code>#hier-nav li:before { content: ">"; }</code> to create this presentational separator instead. Unfortunately, Internet Explorer does not support this level of <acronym title="Cascading Style Sheets">CSS</acronym> yet, so we must resign ourselves to use a physical character in the markup for now.)</p>
<p>Then we make a quick check to ensure we&#8217;re not at the end of the trail. If indeed we&#8217;re not, then we need to turn our text into a link and point it to go to the appropriate level. Otherwise, since we&#8217;re at the end of the trail, we just print the text and end our list item.</p>
<p>Creating the link looks complicated, but it&#8217;s really not. Our array stores all the path components for us, so all we need to do is slice off the end of it so all that remains is the first elements we&#8217;ve already looped through.</p>
<p>Once we&#8217;ve done that, we merely reassemble our <acronym title="Uniform Resource Locator">URL</acronym> by reversing the formatting process we used before. Namely, we <code><a href="http://php.net/implode" title="Documentation on the implode() function.">implode()</a></code> our array to turn it into a single string connected with the slashes, replace all spaces with dashes (<code>-</code>), and then turn the whole thing lowercase. We can do all of it on one line.</p>
<p>Also note that <strong>due to my particular site structure</strong> I&#8217;ve hard-coded the links to point to the root directory of <em>this</em> site. You&#8217;ll probably want to remove that on your own script.</p>
<pre>    // only link if not last time through loop
    if (<var>$i</var> != (<var>$num_parts</var>-1) )
    {
        echo "&lt;a href=&#92;"/maymaymedia/".strtolower(str_replace(' ', '-', implode('/', array_slice(<var>$url_parts</var>, 0, <var>$i</var>+1))))."/&#92;" title=&#92;"Go up to <var>$p</var>&#92;"&gt;<var>$p</var>&lt;/a&gt;&lt;/li&gt;";
    }
    else // last time through loop, so don't do the link
    {
        echo "<var>$p</var>&lt;/li&gt;";
    }
}
?>
&lt;/ul&gt;</pre>
<p>That&#8217;s it! After closing our list element, we&#8217;re <em>done</em>, and we now have scalable breadcrumb navigation based on an intelligent <acronym title="Uniform Resource Identifier">URI</acronym> schema <em>on every single page</em>. Was it good for you too?</p>
<h3 id="uri-design-resources">Additional <acronym title="Uniform Resource Identifier">URI</acronym> Design Resources</h3>
<p>(Some segments shamelessly swiped for my own easy reference from <a href="http://www.pixelcharmer.com/fieldnotes/archives/process_designing/2003/000285.html" title="Where I got all this cool stuff.">Pixelcharmer</a>.)</p>
<p>A list of resources that argue for and suggest best practices in <acronym title="Uniform Resource Identifier">URI</acronym> construction.</p>
<ul>
<li><a href="http://www.isoc.org/HMP/PAPER/016/html/paper.html">The User Interface of URLs</a> (Paul E. Hoffman, 1995)</li>
<li><a href="http://www.w3.org/Provider/Style/URI.html">Cool <acronym title="Uniform Resource Identifier">URI</acronym>’s Don’t Change</a> (Tim Berners-Lee, 1998)</li>
<li><a href="http://www.useit.com/alertbox/990321.html"><acronym title="Uniform Resource Locator">URL</acronym>’s as <acronym title="User Interface">UI</acronym></a> (Jakob Nielsen, 1999)</li>
<li><a href="http://www.alistapart.com/stories/urls/"><acronym title="Uniform Resource Locator">URL</acronym>’s <acronym title="Uniform Resource Locator">URL</acronym>’s <acronym title="Uniform Resource Locator">URL</acronym>’s</a> (Bill Humphries, 2000)</li>
<li><a href="http://www.alistapart.com/stories/succeed/">How to Succeed with <acronym title="Uniform Resource Locator">URL</acronym>’s</a> (Till Quack, 2001)</li>
<li>
<a href="http://www-106.ibm.com/developerworks/library/us-cranky8.html?dwzone=usability">Making URLs accessible</a> (Peter Seebach, 2001)</li>
<li><a href="http://www.adaptivepath.com/publications/essays/archives/000058.php">User-Centered <acronym title="Uniform Resource Locator">URL</acronym> Design</a> (Jesse James Garrett, 2002)</li>
<li><a title="Common HTTP Implementation Problems" href="http://www.w3.org/TR/2003/NOTE-chips-20030128/#gl1">Designing URIs</a> (2003)</li>
<li>In German: <a href="http://www.web-blog.net/comments/P122_0_1_0/">Usability Inside | <acronym title="Uniform Resource Locator">URL</acronym>-Design</a> (January, 2004)</li>
</ul>
<p>By the way, here&#8217;s the difference between the two: <a href="http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?Uniform+Resource+Locator">What is a <acronym title="Uniform Resource Locator">URL</acronym></a>? <a href="http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?Universal+Resource+Identifier">What is a <acronym title="Uniform Resource Identifier">URI</acronym></a>?</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2005/03/21/php-breadcrumb-navigation-using-url-design/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>14 Hour Coding Session</title>
		<link>http://maymay.net/blog/2005/03/19/14-hour-coding-session/</link>
		<comments>http://maymay.net/blog/2005/03/19/14-hour-coding-session/#comments</comments>
		<pubDate>Sun, 20 Mar 2005 00:13:59 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[Bipolar Disorder & Moods]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Geeky]]></category>
		<category><![CDATA[Mania & Joy]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">/?p=211</guid>
		<description><![CDATA[omg14hourcodingsession. tirednow.]]></description>
			<content:encoded><![CDATA[<p>Oh my god, fourteen hours playing with <acronym title="eXtensible HyperText Markup Language; HTML reformulated as XML">XHTML</acronym>, <acronym title="Cascading Style Sheets">CSS</acronym>, and <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> to get <a href="http://maymaymedia.com/" title="A much expanded and still incomplete business web site.">Maymay Media</a> to what it is now. (And it&#8217;s still not done, though I&#8217;m constantly looking for <a href="http://www.maymay.net/maymaymedia/contact/" title="Would you send me feedback on my web site?">feedback</a>!)</p>
<p>Much, if not most of that time was spent writing and editting new content, and beating down <acronym title="Cascading Style Sheets">CSS</acronym> bugs in Internet Explorer. Those of you who know my work habits are likely to be surprised by the fact that I could spend 14 hours dealing mostly with client-side coding issues.</p>
<p>Normally I can&#8217;t spend more than a few hours&mdash;at the most&mdash;dealing with <acronym title="Cascading Style Sheets">CSS</acronym> problems because browser bugs tick me off too much. (Ahem, Micro<em>Sucks</em>.) Nevertheless, for some miraculous reason, I kept swatting bug after bug after bug this session and the enthusiasm just fueled more coding. Needless to say, I was very <em>very</em> productive last night.</p>
<p>I also didn&#8217;t sleep a wink, however, so now I&#8217;m dead tired. Here&#8217;s a short recap before my memories fall down behind the waterfall in my mind.</p>
<h3>Last Night&#8217;s Call-a-thon and Digital Departure</h3>
<ul>
<li>
<p>Last night I was Mr. Popular. I got literally countless phone calls (I can&#8217;t remember them all) from folks who wanted to chat it up. I spoke to a few Meetup group members, Danica, my parents, and others. Christine called and wanted to hang out today but she canceled this afternoon. (I didn&#8217;t mind, I&#8217;m exhausted.)</p>
</li>
<li>
<p>Danica came over from about 8:30 PM to 10:30 PM so that she could give me back the apartment keys and transfer her digital posessions (computer files) off of my computers and onto her own. She also gave me a <cite>Moldy Peaches</cite> album to import into my iTunes Library. (Cool.)</p>
<p>So that&#8217;s pretty much it. We said goodbye, she seemed sad, and I asked her to call me so I knew she&#8217;d gotten home okay. She did, and we said goodbye again. And that&#8217;s that; we are finally going our separate ways and have no more connection to each other whatsoever.</p>
<p>I&#8217;m not even thinking about the future, but I do admit that remaining friends is something I&#8217;d probably like&mdash;if it were not emotionally draining. We&#8217;ll see what happens, but the path for right now is very clear: I&#8217;m trekking it solo yet again!</p>
</li>
</ul>
<h3>The Geeky Parts</h3>
<ul>
<li>
<p>Back to the tech realm, I&#8217;ve implemented my <a href="/tests/php/dynamic-target-relevance/?r-msg=Remember+this%3F#dynamic-relevancy-messages" title="The original published proof-of-concept for a relevency messages.">dynamic relevancy message <acronym title="Application Programming Interface">API</acronym></a> on this blog. What does that mean for you? Probably nothing, but it does mean you&#8217;ll likely see relevancy messages change and grow in abundance over time. As always, use a modern browser to see the full effect.</li>
<li>
<p>Still in the tech realm, I squashed a number of annoying <acronym title="Internet Explorer">IE</acronym> <acronym title="Cascading Style Sheets">CSS</acronym> bugs <em>on this blog</em> with the somewhat-magical application of <code>position:relative;</code>. This means visitors using <acronym title="Internet Explorer">IE</acronym> will finally get a near-perfect browsing experience, with no annoying vanishing backgrounds anymore.</p>
</li>
<li>
<p>Also, Google SiteSearch has been implemented, so you&#8217;ll be seeing that on the top banner for the time being. It&#8217;s nothing special, just a way to make it look like you can do more than you can here. It might also make me some more money via clickthroughs, but that&#8217;s unlikely. (Oh, which reminds me, those ads on the right side of the window, yeah, <strong>if you click on those I get money</strong>. Don&#8217;t be shy.)</p>
</li>
<li>
<p>A not-so-new but still interesting point of note is that I&#8217;ve started using <a href="http://www.mybloglog.com/" title="Tracks click counts on your outgoing links, seamlessly, and for free.">MyBlogLog.com</a> to keep track of which hyperlinks people are clicking on. This has been somewhat informative because it means I get to see which hyperlinks induce clicks and which don&#8217;t. Anchor text is important, and this is a useful tool to learn how you can manipulate the effect of a link.</p>
</li>
</ul>
<h3>Flickr Photos from the Past!</h3>
<p>Finally, I&#8217;ve been wanting to get more value out of my digital camera. I haven&#8217;t been taking pictures, but backing up and transfering a bunch of Danica&#8217;s things last night inspired me to dig through some of my old photo collections to see what could turn up. Well, here it is:</p>
<ul>
<li>
<p>Here&#8217;s me almost a year ago, during last year&#8217;s Passover at my mother&#8217;s:</p>
<p><a href="http://www.flickr.com/photos/maymay/6868881/" title="View this photo at my Flickr photostream."><img src="http://photos6.flickr.com/6868881_9516cace64.jpg" width="220" height="297" alt="Me sitting at the table during Passover, 2004" /></a></li>
<li>
<p>Me at San Francisco&#8217;s Exploratorium with Danica during the Summer of 2004, on my trip to meet her family. Look at the face I&#8217;m making, I had so much fun there.</p>
<p><a href="http://www.flickr.com/photos/maymay/6868886/" title="View this photo at my Flickr photostream."><img src="http://photos7.flickr.com/6868886_428cf57250.jpg" width="269" height="384" alt="Me sitting on the big chair at the San Francisco Exploratorium." /></a></li>
<li>
<p>Yeah, I was gonna eat that piece of toast. Obviously, my dinner plans were foiled.</p>
<p><a href="http://www.flickr.com/photos/maymay/6868885/" title="View this photo at my Flickr photostream."><img src="http://photos3.flickr.com/6868885_845fa1d17b.jpg" width="345" height="396" alt="I look at the camera sadly, holding burnt toast in my hands." /></a></li>
<li>
<p>This is what happens to my face if I don&#8217;t shave.</p>
<p><a href="http://www.flickr.com/photos/maymay/6868882/" title="View this photo at my Flickr photostream."><img src="http://photos6.flickr.com/6868882_534ab89a76.jpg" width="252" height="473" alt="Me smiling, sunlight clearly showing my unshaven face." /></a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2005/03/19/14-hour-coding-session/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Targetting Relevance in Long Web Pages with the CSS :target Pseudo-Class</title>
		<link>http://maymay.net/blog/2005/03/11/css-target-relevance/</link>
		<comments>http://maymay.net/blog/2005/03/11/css-target-relevance/#comments</comments>
		<pubDate>Fri, 11 Mar 2005 20:24:47 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Hypertext Copywriting]]></category>
		<category><![CDATA[Information & Communication]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">/?p=199</guid>
		<description><![CDATA[Context and relevance are sometimes lost when linking to pages on the web. Basic HTML and good hypertext copywriting habits (like using <code>title</code> attributes) can help, but not always enough. Here's a totally new method (I think) to embed what I call <dfn>relevancy messages</dfn> into the <em>destination page</em> of a site.]]></description>
			<content:encoded><![CDATA[<h3>The Importance of Context and Relevance</h3>
<p>Context and relevance are two of the most important aspects of effective communication. If the context of a message is not understood then the commuication will likely be disregarded, or worse&mdash;misinterpreted. If the message isn&#8217;t relevant to the topic at hand then it will be useless to everybody involved.</p>
<p>In order to ensure that a message is successfully received and has the desired effect, one must first ensure that the context for that message is properly set up and that the message itself is relevant to the subject matter.</p>
<p>An excellent example of a scenario where a loss of context and/or relevance can easily cause communication problems is receiving email messages. Surely everyone has recieved an email that they simply don&#8217;t know what to do with or why they&#8217;ve gotten it. (By the way, for some unbelievably insightful tips on composing effective email messages, read <a href="http://hbswk.hbs.edu/item.jhtml?id=4438&#038;t=srobbins" title="Tips for Mastering E-Mail Overload">this article</a> [via <a href="http://www.43folders.com/2005/03/stever_robbins_.html" title="43 Folders: Stever Robbins on email overload">43 Folders</a>].)</p>
<p>The same thing can&mdash;and does&mdash;happen on the web. For example, let&#8217;s say you&#8217;re reading a page which has a link in its text to another page. You decide to follow the link but once you&#8217;ve arrived at the new page you find yourself  staring at an enormous amount of other text that doesn&#8217;t have anything to do with why you followed the link in the first place. Suddenly you&#8217;re confused, you feel lost, and you quickly push the &ldquo;Back&rdquo; button of your browser.</p>
<p>What went wrong here? Context was lost; the destination page had no relevance to the source page. If it did, you couldn&#8217;t find it because it wasn&#8217;t clearly identified. This is a confusing and frustrating situation, and one that I&#8217;m willing to bet happens way too often on the web.</p>
<p>On my own blog, I frequently link to entries I&#8217;ve previously written. Sometimes these entries can be quite long, and I&#8217;m not always referencing the entire entry in my link. But by pointing the link to a specific &ldquo;intra-page&rdquo; anchor by using a <a href="http://www.w3.org/DesignIssues/Fragment.html" title="What it is and how to make one.">fragment identifier</a> and clearly marking the relevance of this information in both the link itself (with a descriptive <code>title</code>) <em>and in the landing page</em> (with what I&#8217;ve come to call a <dfn>relevancy message</dfn>), context is preserved and confusion is eliminated.</p>
<p>To see what I&#8217;m talking about in practice, check out <a href="/tests/css/relevant-anchors/1.html" title="An example to show what I'm talking about.">my experiment pages</a>. It&#8217;s a demo of the problem and relevancy messages in action.</p>
<h3><acronym title="Cascading Style Sheets level 2">CSS2</acronym> The Rescue</h3>
<p>There&#8217;s only one problem left. How does one insert text into the landing page which will be viewable when someone follows a <em>specially-crafted</em> link to it, but <em>not</em> when they arrive at the page via any other link? Though it is possible to program this into your pages using <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> or another web scripting language, <acronym title="Cascading Style Sheets">CSS</acronym> level 2 offers a much simpler and maintainable solution: the <code>:target</code> and <code>:before</code> pseudo-classes.</p>
<p>When used in combination, the <code>:target</code> and <code>:before</code> pseudo-classes can be used to generate text on a page at a specific point in the document when your page is linked to in a certain way. By using an additional <acronym title="Cascading Style Sheets level 2">CSS2</acronym> function, <code>attr()</code>, we can also generate customized text for each landing spot within the document. Let&#8217;s take a look at each component separately.</p>
<h4>The <acronym title="HyperText Markup Language">HTML</acronym> You&#8217;ll Need</h4>
<p>Let&#8217;s say you&#8217;re writing about apples. In your text, you link to a previous article you wrote about oranges. Your link in the article on apples might look like this:</p>
<pre>&lt;a href="oranges.html" title="Oranges have a thick, white pith beneath their skin." &gt;oranges&lt;/a&gt;</pre>
<p>And your text in the article on oranges might look like this:</p>
<pre>&lt;p&gt;[&hellip;] The skin of an orange is thick, porous, and varies in color from deep to light orange. There is a bitter-tasting white pith underneath the outter-most layer of the fruit's skin. [&hellip;]&lt;/p&gt;</pre>
<p>In order to link directly to the paragraph mentioning the orange&#8217;s pith you need to insert a named anchor just after the opening paragraph tag where that content was written. You also need to append this name to the <acronym title="Uniform Resource Identifier">URI</acronym> of the link, as a fragment identifier. The resulting <acronym title="HyperText Markup Language">HTML</acronym> for the link might look like this:</p>
<pre>&lt;a href="oranges.html#skin" title="Oranges have a thick, white pith beneath their skin." &gt;oranges&lt;/a&gt;</pre>
<p>The resulting <acronym title="HyperText Markup Language">HTML</acronym> for the paragraph about oranges might look like this:</p>
<pre>&lt;p&gt;&lt;a id="skin"&gt;&lt;/a&gt;The skin of an orange is thick, porous, and varies in color from deep to light orange. There is a bitter-tasting pith underneath the outter-most layer of the fruit's skin.&lt;/p&gt;</pre>
<h4>The <acronym title="Cascading Style Sheets">CSS</acronym> You&#8217;ll Need</h4>
<p>Once the <acronym title="HyperText Markup Language">HTML</acronym> is in place, you need to create a style rule to generate the text you&#8217;ll want to display before the paragraph. Your style sheet might look like this:</p>
<pre>a:target::before { content: "Here's what I referenced with my link on the last page: "; font-size: larger; font-weight: bold; }</pre>
<p>You can even take it one step further. By adding a <code>title</code> attribute with some helpful text in your named anchor, you can actually display that text (specific to the reference you&#8217;re making) instead of the generic &ldquo;Here&#8217;s what I referenced&hellip;&rdquo; text. The <acronym title="Cascading Style Sheets">CSS</acronym> for that would look like this, and it would display whatever you write as the <code>title</code> for <em>each</em> named anchor you use:</p>
<pre>a:target::before { content: attr(title); }</pre>
<h3>Limitations</h3>
<p>The major drawback to this technique is that you need to change the code of the destination document for it to work. Specifically, you need to insert named anchors (though you can also target <em>any</em> element by giving it an unique <code>id</code>), and you need to insert a style rule. (However, see below for another experiment that will let site owners allow people to get around this limitation.)</p>
<p>Another major drawback is that it requires a fully <acronym title="Cascading Style Sheets level 2">CSS2</acronym>-compliant browser. That means Internet Explorer 5 and 6 (both Macintosh and Windows versions) will not show the special content on the destination page. They will, however, move focus to the point in the document at which the anchor resides.</p>
<h3>Looking to the Future</h3>
<p>I have been playing with this technique recently on my blog (can you find the links I&#8217;ve used this on? ;). The obvious benefit is creating a far more seamless transition from one page to another and maintaining the same context across web pages. This is invaluable for me and my readers in particular, since I tend to enjoy writing and end up writing far longer entries than I probably should. (Even though I use headings to divide my entries into logical chunks, it&#8217;s still good to have another trick up my sleeve to help usability!)</p>
<p>However, this technique is ripe for expansion. For instance, I have created <a href="/tests/php/dynamic-target-relevance/?r-msg=How+you+can+let+anyone+embed+a+relevancy+message%3A%20#concept" title="A proof-of-concept for dynamic relevancy messages in action.">another experiment</a> to dynamically generate the content of the <acronym title="Cascading Style Sheets">CSS</acronym> rule based upon a variable in a <code>GET</code> querystring. (It uses three lines of <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym>, and that link itself is a proof-of-concept.) This will allow people to write links that point to my documents and <em>insert their own special relevance-describing blurbs</em> in front of the fragment they&#8217;ve linked to. (Yes, I realize this may pose <acronym title="Cross Site Scripting">XSS</acronym> security problems, I&#8217;m still just playing with the concept.)</p>
<p>Exploring all of this is a lot of fun. The crux of this technique relies upon  accessible and clever hypertext copywriting to enhance usability when linking to web pages and referencing information across pages or, one day, sites. As is the case with most things Web, simple is better.</p>
<p>I&#8217;m very eager to hear about comments on this technique. Are there dangers I haven&#8217;t seen yet? Can you think of another way to use it that I haven&#8217;t mentioned here? Are you already using it on your own site? All feedback welcome. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2005/03/11/css-target-relevance/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Getting PHP Variables into Apache Logs</title>
		<link>http://maymay.net/blog/2005/02/01/getting-php-variables-into-apache-logs/</link>
		<comments>http://maymay.net/blog/2005/02/01/getting-php-variables-into-apache-logs/#comments</comments>
		<pubDate>Wed, 02 Feb 2005 04:40:46 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">/?p=173</guid>
		<description><![CDATA[Putting arbitrary PHP variables into Apache's logs is easy, and incredibly useful.]]></description>
			<content:encoded><![CDATA[<p>Gleaning information about the various things that are going on inside of a compuer or on a web site can be a somewhat difficult process. System logs are probably the most useful source of this information, but sometimes (especially for web sites) they don&#8217;t necessarily record all the interesting data. One example of a situation where this may be true is when you want your Apache logs to record your web site&#8217;s user session IDs.</p>
<p>Since <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> variables are known only to the current <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> process and not to Apache, you can&#8217;t just plug them into your Apache system log without first informing Apache about the variable you want to record. This can be done in two nearly identical ways, though the implementation of each is somewhat different. Luckily for the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> progammer, it makes very little difference which way you choose.</p>
<h3>Apache Notes</h3>
<p>One way of getting Apache to recognize <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> session variables, or any variable for that matter, is to leave a note in Apache&#8217;s notes table via the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> function <code><a href="http://php.net/apache-note" title="Manual page for apache_note()">apache_note()</a></code>. An <dfn>Apache note</dfn> can be thought of as a reminder from one Apache process to another that a certain variable exists, and what its value is.</p>
<p>Thus, doing <code>apache_note('userID', $_SESSION['userid'])</code> will make the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> session variable <code>userid</code> available to Apache as <code>userID</code> via an Apache note. Calling <code>apache_note()</code> from another page with only the first arguement (<code>'userID'</code>) will retrieve the note from Apache&#8217;s notes table.</p>
<h3>Apache Subprocess Environment</h3>
<p>Another way to make <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> variables accessible to Apache is by putting them into an Apache procesess&#8217; runtime environment. Note that simply using the <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> function <code>putenv()</code> will <em>not</em> work because environment variables set with <code>putenv()</code> expire at the end of the current request. Instead, another Apache-specific function must be used: <code><a href="http://php.net/apache-setenv" title="Manual page for apache_setenv()">apache_setenv()</a></code>.</p>
<p>Using the same example as with the Apache note, the code would look like this: <code>apache_setenv('userID', $_SESSION['userid'])</code>. In order to retrieve the value from another page, you need to use the corresponding function <code><a href="http://php.net/apache-getenv" title="Manual page for apache_getenv()">apache_getenv()</a>: <code>$userid = apache_getenv('userID')</code>.</code></p>
<h3>Moving the Variable into the Log File</h3>
<p>Now that Apache has been made aware of the existence of the variable, the value must be recorded in Apache&#8217;s logs. This is the easy part. All you need do is add it to the <a href="http://httpd.apache.org/docs/mod/mod_log_config.html#logformat" title="Manual page for the LogFormat directive">LogFormat</a> line in your config file. So, using the userID example from before, if your LogFormat directive looks like this,</p>
<pre>LogFormat "%h %l %u %t "%r" %>s %b"</pre>
<p>and you used an <code>apache_note()</code> You simply need to edit it so that it looks like this:</p>
<pre>LogFormat "%h %l %u %t "%r" %>s %b %{userID}n"</pre>
<p>Note the small <code>n</code> after the placement of the <code>%{userID}</code> variable in the log format. This signifies that the variable will come from an Apache note. If you used an Apache environment variable (<code>apache_setenv()</code>), then that small <code>n</code> should be changed to an <code>e</code> to signify that the variable comes from the environment.</p>
<p>Analyzing your web site traffic using this technique can often be just as effective as logging information to a database but there is much less overhead involved here than with most other options.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2005/02/01/getting-php-variables-into-apache-logs/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Generating Random Letters in PHP</title>
		<link>http://maymay.net/blog/2004/12/19/generating-random-letters-in-php/</link>
		<comments>http://maymay.net/blog/2004/12/19/generating-random-letters-in-php/#comments</comments>
		<pubDate>Mon, 20 Dec 2004 03:02:11 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">/?p=149</guid>
		<description><![CDATA[Every programmer needs to know about character encodings, but PHP's array syntax for accessing characters in a string allows us to sidestep the issue entirely when generating random simple characters, such as English letters.]]></description>
			<content:encoded><![CDATA[<p>Generating random numbers in <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> isn&#8217;t much a problem thanks to functions like <code>rand()</code> or <code>mt_rand()</code> and so utilizing them is a no brainer, even for programming newbies. Generating random letters, however, is sometimes a little less intuitive.</p>
<p>The tricky thing about it is that computers are basically glorified switches. All they do is answer the question &ldquo;Is this a 0 or a 1?&rdquo; for any given datum. So while this makes them pretty good at handling numeric data, doing anything interesting with something else, such as natural languages, requires a bit of creativity.</p>
<p>The concept of what a &ldquo;letter&rdquo; is or is not needs to be explicitly defined in some manner that computers (glorified switches) can understand. This is accomplished by mapping a numeric value to a specific character. This map is then known as a <dfn>character encoding</dfn>.</p>
<p>I&#8217;m not going to get into the whole thing here. For the curious, a pertinent <a href="http://www.google.com/search?q=character+set+encoding">Google search</a> turned up <a href="http://www.cs.tut.fi/~jkorpela/chars.html">this tutorial</a> which is a good place to start. Additionally <a href="http://www.joelonsoftware.com/articles/Unicode.html">this informative article</a> by <a href="http://joelonsoftware.com/">Joel Spolsky</a> is an entertaining and educational read.</p>
<p>However, back to <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> and generating random letters, we can sidestep the whole issue of encodings as long as the pool of possible letters we wish to generate is somewhat limited. Thanks to a feature of <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym> that allows us to pick out a character in a string using array syntax, we can get a random letter with a random number and a string containing the possibilities we want.</p>
<pre>function randLetter()
{
    $int = rand(0,51);
    $a_z = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $rand_letter = $a_z[$int];
    return $rand_letter;
}</pre>
<p>While this method may carry a little more overhead than a purely numeric approach, it&#8217;s certainly easier to digest.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2004/12/19/generating-random-letters-in-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MagpieRSS Grabs My Del.icio.us Links</title>
		<link>http://maymay.net/blog/2004/10/23/magpierss-grabs-my-delicious-links/</link>
		<comments>http://maymay.net/blog/2004/10/23/magpierss-grabs-my-delicious-links/#comments</comments>
		<pubDate>Sun, 24 Oct 2004 04:09:03 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Site Updates]]></category>

		<guid isPermaLink="false">/?p=98</guid>
		<description><![CDATA[I&#8217;ve recently got into the whole del.icio.us link craze. Mostly, I&#8217;ve been using it as a cross-browser bookmarks list. Yes, Apple&#8217;s .Mac has Safari-bookmark syncing with iSync, but that&#8217;s only for Macs. Anyway, I wanted to get a list of links I&#8217;ve recently added to it on this blog. MagpieRSS was the best way to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://del.icio.us/maymay">I&#8217;ve recently got into</a> the whole <a href="http://del.icio.us/">del.icio.us</a> link craze. Mostly, I&#8217;ve been using it as a cross-browser bookmarks list. Yes, <a href="http://www.mac.com/">Apple&#8217;s .Mac</a> has <a href="http://www.mac.com/1/iTour/tour_bookmarks.html">Safari-bookmark syncing with iSync</a>, but that&#8217;s only for Macs.</p>
<p>Anyway, I wanted to get a list of links I&#8217;ve recently added to it on this blog. <a href="http://magpierss.sourceforge.net/">MagpieRSS</a> was the best way to do it, but I didn&#8217;t want to abuse the del.icio.us server by doing it, so I had to enable MagpieRSS&#8217;s cache. I had to search through the docs a little to get the cache feature working. I was trying to create the <code>cache</code> directory inside the <code>magpierss</code> directory, when apparently I&#8217;m supposed to have created it from the directory in which I&#8217;m calling the scripts that use Magpie.</p>
<p>This is a bit of a scalability issue, since I want to use Magpie in several different areas across my site and don&#8217;t want my webserver littered with cache directories everywhere. Beyond that little annoyance, it&#8217;s wonderfully easy to integrate <acronym title="Really Simple Syndication">RSS</acronym> feeds into a site with this. I&#8217;m loving it.</p>
<p>Also, after coding the function that displays my del.icio.us links, I started searching for the cache solution, but found <a href="http://climbtothestars.org/archives/2004/08/15/magpierss-caching-problem/">Stephanie Booth&#8217;s post regarding a different MagpieRSS caching issue</a>. She seems to have solved her problem, and while I had to continue to search for how to enable MagpieRSS&#8217;s auto-caching, I did find a code sample which creates a del.icio.us links list. I&#8217;m now using a modded version of her function, as it was better than mine. Thanks Stephanie!</p>
<p>And for the curious, <a href="http://www.bmannconsulting.com/book/print/38">here&#8217;s the reference I found that showed how to enable MagpieRSS&#8217;s auto-caching feature</a>.</p>
<p style="font-size: smaller;"><strong>Addendum:</strong> Oh, yeah, I almost forgot. Since this blog is actually generating two of my blogs in a weird way, I only added the del.icio.us links to <a href="http://www.maymaymedia.com/">this site</a>, not my <a href="http://www.maymay.net/blog/">Ups and Downs personal site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2004/10/23/magpierss-grabs-my-delicious-links/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Make WordPress-generated Pages Outside the WordPress Install Directory</title>
		<link>http://maymay.net/blog/2004/10/22/how-to-make-wordpress-generated-pages-outside-the-wordpress-install-directory/</link>
		<comments>http://maymay.net/blog/2004/10/22/how-to-make-wordpress-generated-pages-outside-the-wordpress-install-directory/#comments</comments>
		<pubDate>Sat, 23 Oct 2004 00:26:28 +0000</pubDate>
		<dc:creator>Meitar</dc:creator>
				<category><![CDATA[HOWTO]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">/?p=95</guid>
		<description><![CDATA[I wanted to use my blog entries, created in WordPress to generate content for pages on my site that were not in my blog. This seemed simple enough, and it is, but without some guidance this can be a really confusing situation. While WordPress supports a pseudo-templating system that can be used to easily customize [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to use my blog entries, created in WordPress to generate content for pages on my site that were <em>not</em> in my blog. This seemed simple enough, and it is, but without some guidance this can be a really confusing situation. While WordPress supports a pseudo-templating system that can be used to easily customize the look and feel of a WordPress blog, getting that blog-portion of the site to play nice with the other parts of a site (or the converse, as the case may be) is often not as easy as it seems.</p>
<p>I believe this is one of the reasons why WordPress&#8217;s popularity has not yet reached its enormous potential.</p>
<p>But without further ado, here&#8217;s what I did to get WordPress to generate pages in a directory completely outside WordPress&#8217;s own installation directory.</p>
<h2>The Solution</h2>
<p>The solution involves replacing all occurences of WordPress&#8217;s erroneous absolute link-creation output and replace it with output appropriate to the <code>/newsection</code> structure. This was done with <acronym title="PHP Hypertext Preprocessor; an HTML-embedded scripting language">PHP</acronym>&#8216;s output buffering. Then, to make it work with the permalink structure, I made some edits to the WordPress-generated <code>RewriteRule</code>s. In the hopes that this will be of use to someone, here&#8217;s what I did:</p>
<ol>
<li>
<p>In the top of your new section&#8217;s template (/newsection/index.php), following the line with the <code>require()</code> statement, put a new line that reads:</p>
<pre>ob_start();</pre>
<p>This will start the output buffer.</p>
</li>
<li>
<p>At the very bottom of your template, after the <code>&lt;/html&gt;</code> add the following lines:</p>
<pre>&lt;?php
&#036;page_content = ob_get_contents();
&#036;replace_this = 'href="http://mysite.com/blog';
&#036;with_this = 'href="http://mysite.com/newsection';
&#036;modified_page_content = str_replace(&#036;replace_this, &#036;with_this, &#036;page_content);
ob_end_clean();
echo &#036;modified_page_content;
?&gt;</pre>
<p>These do the replacements you need. Obviously, change the <code>mysite.com</code> to whatever your site domain is, change the <code>/blog</code> to whatever path your WordPress install is at, and change the <code>/newsection</code> to the path of the new section you&#8217;re creating.</p>
<p>With these lines wrapped around your template, you can use all of WordPress&#8217;s original template tags like <code>the_permalink()</code> and <code>wp_list_cats()</code> just as you would if you were using them in the original section.</p>
<p><strong>Note to regex wizards:</strong> this is obviously a <em>very</em> crude string replacement, and I don&#8217;t know how well it will work in situations not like my own. I&#8217;m not very good with regular expressions, however, so if you can think of one that would work better with <code>preg_replace()</code> please let me know.</p>
</li>
<li>
<p><strong>If you&#8217;re using WordPress&#8217;s virtual site structure (pretty-permalinks):</strong> Copy the rules WordPress wrote for you at Options->Permalinks (or from your existing <code>.htaccess</code> file) and paste them into a new text document. This will become your new section&#8217;s <code>.htaccess</code> file.</p>
<ol>
<li>
<p>In the line that begins with <code>RewriteBase</code> replace the old base with the new base path to your section. If the line read <code>RewriteBase /blog/</code> then you would replace <code>/blog/</code> with <code>/newsection/</code>.</p>
</li>
<li>
<p>Finally, for the second, third, and fourth lines that begins with <code>RewriteRule</code> replace the old actual path with the actual path to your new section. So, continuing the example above, if you have a line that reads like this,</p>
<pre>RewriteRule ^category/?(.*) /blog/index.php?category_name=&#036;1 [QSA]</pre>
<p>replace it with this:</p>
<pre>RewriteRule ^category/?(.*) /newsection/index.php?category_name=&#036;1 [QSA]</pre>
</li>
<li>
<p>Save this file as a new <code>.htaccess</code> file and upload it to your server so that it resides at <code>http://mysite.com/newsection/.htaccess</code></p>
</li>
</ol>
</li>
</ol>
<p>No matter what section/directory of your site you&#8217;re putting WordPress templates in, you can use this method to point links to the current section, and thus load WordPress content in the templates within that section/directory. One important caveat to this method is that every time a template using this method is accessed, your server works a little over-time to do the <code>str_replace()</code> on your content. This won&#8217;t be noticeable on small or short pages, but could really become an issue on oft-visited, long, long pages. As always, use at your own risk.</p>
<p>Improvements/warnings/suggestions/hate mail are welcome.</p>
<h2>External Resources</h2>
<ul>
<li>The <a href="http://wordpress.org/support/3/15291">original support forum thread.</a></li>
<li>The <a href="http://wiki.wordpress.org/HowTo/UseTemplatesInAnyDirectory">Wiki HowTo node</a> I wrote.</li>
<li><a href="http://developedtraffic.com/resources/wordpress-notes.php">WordPress Customization Notes.</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://maymay.net/blog/2004/10/22/how-to-make-wordpress-generated-pages-outside-the-wordpress-install-directory/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

