<?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>Jeff Gran &#187; Web</title>
	<atom:link href="http://jeffgran.com/tag/web/feed" rel="self" type="application/rss+xml" />
	<link>http://jeffgran.com</link>
	<description>Artist, Designer, Developer</description>
	<lastBuildDate>Wed, 09 Nov 2011 15:59:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Bootstrapping an Ubuntu Server on Rackspace Using Cloud-Init and Fog</title>
		<link>http://jeffgran.com/276/blog/ubuntu-cloud-init-rackspace-fog-ruby</link>
		<comments>http://jeffgran.com/276/blog/ubuntu-cloud-init-rackspace-fog-ruby#comments</comments>
		<pubDate>Fri, 19 Aug 2011 19:11:26 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=276</guid>
		<description><![CDATA[Recently at work I needed to figure out how to bootstrap a server image on Rackspace, preferably using Ubuntu&#8217;s Cloud-Init package since we already had that working on EC2. I couldn&#8217;t find a single person who had done this before, so after struggling for a day or two and finally figuring out that it does [...]]]></description>
			<content:encoded><![CDATA[<p>Recently at work I needed to figure out how to bootstrap a server image on Rackspace, preferably using Ubuntu&#8217;s Cloud-Init package since we already had that working on EC2.</p>
<p>I couldn&#8217;t find a single person who had done this before, so after struggling for a day or two and finally figuring out that it does indeed work (and it turns out to be pretty simple) I thought I would share the knowledge on how to do it.</p>
<h3>Set up the Machine Image</h3>
<p>EC2 has ready-made Ubuntu images with Cloud-Init already installed, but for Rackspace the first thing you need to do is create a similar image. All we did was to get a stock Ubuntu image (11.04) and run `apt-get install cloud-init` on it.</p>
<p>That&#8217;s it. Then just save out that image to your account.</p>
<h3>Bootstrap the Image with Fog</h3>
<p>Note: We&#8217;re using Ruby, so we can use the awesome <a href="https://github.com/geemus/fog" target="_blank">Fog gem</a> as a wrapper around the <a href="http://docs.rackspace.com/servers/api/v1.0/cs-devguide/content/Create_Server-d1e1937.html" target="_blank">Rackspace REST API</a>, but you could also accomplish the same thing with the raw API.</p>
<p>A couple of notes, and then I&#8217;ll show the code:</p>
<ul>
<li>We are generating an SSH key-pair to initialize the server with. This is not strictly required, but if you don&#8217;t do this, you must save the password attribute of the returned server object on the initial create call. Subsequent queries against the server will not return the password for security reasons.</li>
</ul>
<ul>
<li>The &#8220;Personality&#8221; field is the crux of this process. It allows you to send up to 5 files to be put on the server in a location of your choosing at boot time. It turns out that this can be used to &#8220;seed&#8221; cloud-init with the files it needs, mimicking the &#8220;user-data&#8221; field you would pass to EC2. Note that the path to the file you supply does not have to exist on the image. Rackspace will create the directories for you if they don&#8217;t.</li>
</ul>
<ul>
<li>The path where you put the files is also important. In the code below the `/nocloud-net/` part of the path can be interchanged with a few others, though I&#8217;m not sure what some of them mean. Don&#8217;t quote me on this, but I believe that `/nocloud/` is supposed to mean that you&#8217;re not in the cloud, and `/nocloud-net/` is the same, except that you are guaranteed that you will have a connection to the internet when it runs (a little bit later in the boot process than `nocloud`). But we can hijack either one for our use in seeding cloud-init.</li>
</ul>
<ul>
<li>Very important: you must supply BOTH the &#8220;user-data&#8221; and the &#8220;meta-data&#8221; files in order for cloud-init to run. In EC2, <a href="http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/examples/seed/meta-data">the meta-data file</a> has a bunch of EC2-specific data in it (and some generic data, to be fair), but I found that we didn&#8217;t need any of that data and the defaults worked fine. But you still have to create that file, and an empty string doesn&#8217;t work (the file doesn&#8217;t get created), which is why we have specified a single space for the contents of the file.</li>
</ul>
<ul>
<li>The `user-data` file can be any type of file that cloud-init normally expects, including the multi-part format, so you can include multiple files that way. The code below shows how we compiled some files from the local file system into a multipart document (each with the appropriate `#` or `#!` header). See the <a href="https://help.ubuntu.com/community/CloudInit" target="_blank">cloud-init documentation</a> for more info.</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="color: #ccc;"><span style="color: #80ff80"># get a handle to the fog compute abstraction</span>
compute_adapter = <span style="color:#6666ff; font-weight:bold;">Fog::Compute</span>.<span style="color: magenta;">new</span><span style="color: grey;">&#40;</span><span style="color: grey;">&#123;</span>
  provider: <span style="color: #ff8080;">&quot;Rackspace&quot;</span>,
  rackspace_api_key: <span style="color: #ff8080;">&quot;&quot;</span>,
  rackspace_username: <span style="color: #ff8080;">&quot;&quot;</span>
<span style="color: grey;">&#125;</span><span style="color: grey;">&#41;</span>
&nbsp;
<span style="color: #80ff80"># generate the ssh key-pair</span>
keys = SSHKey.<span style="color: magenta;">generate</span>
&nbsp;
<span style="color: #80ff80"># let's make a multi-part document</span>
scripts = <span style="color:#6666ff; font-weight:bold;">MIME::MultipartMedia::Mixed</span>.<span style="color: magenta;">new</span>
&nbsp;
<span style="color: #80ff80"># assuming `files` is an array of File objects corresponding</span>
<span style="color: #80ff80"># to real, properly formatted cloud-init script files</span>
files.<span style="color: magenta;">each</span> <span style="color: #4080ff;">do</span> <span style="color: grey;">|</span>f<span style="color: grey;">|</span> <span style="color: #4080ff;">do</span>
  scripts.<span style="color: magenta;">add_entity</span><span style="color: grey;">&#40;</span><span style="color:#6666ff; font-weight:bold;">MIME::TextMedia</span>.<span style="color: magenta;">new</span><span style="color: grey;">&#40;</span>file, <span style="color: #ff8080;">&quot;text/plain&quot;</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span>
<span style="color: #4080ff;">end</span>
&nbsp;
compute_adapter.<span style="color: magenta;">servers</span>.<span style="color: magenta;">bootstrap</span><span style="color: grey;">&#40;</span><span style="color: grey;">&#123;</span>
  image_id: <span style="color:#006666;">39</span>,
  flavor_id: <span style="color:#006666;">1</span>,
  name: <span style="color: #ff8080;">&quot;A Name for the Server&quot;</span>,
  personality: <span style="color: grey;">&#91;</span>
    <span style="color: grey;">&#123;</span>
      <span style="color: #ff8080;">'path'</span> <span style="color: grey;">=&gt;</span> <span style="color: #ff8080;">'/var/lib/cloud/seed/nocloud-net/user-data'</span>,
      <span style="color: #ff8080;">'contents'</span> <span style="color: grey;">=&gt;</span> scripts.<span style="color: magenta;">to_s</span>
    <span style="color: grey;">&#125;</span>,<span style="color: grey;">&#123;</span>
      <span style="color: #ff8080;">'path'</span> <span style="color: grey;">=&gt;</span> <span style="color: #ff8080;">'/var/lib/cloud/seed/nocloud-net/meta-data'</span>,
      <span style="color: #ff8080;">'contents'</span> <span style="color: grey;">=&gt;</span> <span style="color: #ff8080;">' '</span>
    <span style="color: grey;">&#125;</span>
  <span style="color: grey;">&#93;</span>,
  public_key: keys.<span style="color: magenta;">ssh_public_key</span>,
  private_key: keys.<span style="color: magenta;">private_key</span>
<span style="color: grey;">&#41;</span></pre></div></div>

<p>Helpful links:</p>
<ul>
<li><a href="https://code.launchpad.net/~cloud-init-dev/cloud-init/trunk">Cloud-init project with source code browser (including example files)</a></li>
<li><a href="http://fog.io/0.10.0/rdoc/Fog/Compute/Rackspace/Server.html" target="_blank">Fog Documentation</a></li>
<li><a href="https://github.com/bensie/sshkey" target="_blank">sshkey gem used to generate the proper type of keys</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/276/blog/ubuntu-cloud-init-rackspace-fog-ruby/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress: Sort Posts by Multiple Fields (Part II)</title>
		<link>http://jeffgran.com/262/blog/wordpress-sort-posts-by-multiple-fields-part-ii</link>
		<comments>http://jeffgran.com/262/blog/wordpress-sort-posts-by-multiple-fields-part-ii#comments</comments>
		<pubDate>Sun, 17 Jul 2011 23:17:39 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=262</guid>
		<description><![CDATA[Here's a fast and easy way to sort your posts by multiple fields, using the posts_orderby filter hook and a simple function.]]></description>
			<content:encoded><![CDATA[<h3>The Sequel!</h3>
<p>Because my previous post (<a href="http://jeffgran.com/218/blog/wordpress-sort-posts-by-multiple-fields" title="WordPress: Sort Posts by Multiple Fields">WordPress: Sort Posts by Multiple Fields</a>) was one of my most popular posts, and because I have realized since then that the solution it proposes is an inadequate one, I felt the need to write an update.  I don&#8217;t want to be spreading bad information, and for a blog with any significant number of posts, that solution is untenable.</p>
<p>As <a href="http://jeffgran.com/218/blog/wordpress-sort-posts-by-multiple-fields#comment-254" title="WordPress: Sort Posts by Multiple Fields">progzy</a> points out, sorting by multiple fields can be accomplished using the `posts_orderby` filter hook, which uses MySQL directly to sort the posts, instead of getting all the posts from the database into a gigantic array, and then sorting them with php code. Here&#8217;s how to do it.</p>
<h3>Writing an orderby Function</h3>
<p>You&#8217;ll need to write a function that returns a SQL fragment represented as a string, and then connect it to the filter hook. The SQL fragment is the `ORDER BY` segment of the SQL query that gets your posts from the database. See <a href="http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html">the MySQL Documentation on sorting</a> for more info on this.</p>
<p>Here&#8217;s an example of a custom sorting function:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="color: #ccc;"><span style="color: #ffff00;">function</span> order_by_multiple<span style="color: grey;">&#40;</span> <span style="color: #ffc080;">$orderby</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
  <span style="color: #4080ff;">return</span> <span style="color: #ff8080;">&quot;post_date ASC, post_title DESC&quot;</span><span style="color: grey;">;</span>
<span style="color: grey;">&#125;</span></pre></div></div>

<p>The above would sort the posts by date in ascending order first, and secondarily by title in descending (reverse) order. </p>
<h3>Only Sort on a certain page</h3>
<p>You can also make this much more complex, if you want to. One important way is by using the different &#8220;<a href="http://codex.wordpress.org/Conditional_Tags">Conditional Tags</a>&#8221; WordPress provides. Here&#8217;s an example that only applies the custom sort on the home page:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="color: #ccc;"><span style="color: #ffff00;">function</span> order_by_multiple<span style="color: grey;">&#40;</span> <span style="color: #ffc080;">$orderby</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
  <span style="color: #4080ff;">if</span> <span style="color: grey;">&#40;</span><span style="color: grey;">!</span>is_home<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
    <span style="color: #4080ff;">return</span> <span style="color: #ff8080;">&quot;post_date ASC, post_title DESC&quot;</span><span style="color: grey;">;</span>
  <span style="color: grey;">&#125;</span>
<span style="color: grey;">&#125;</span></pre></div></div>

<h3>Hook up the sort function</h3>
<p>Then, once you have your ordering function written, you just need to hook it into the WordPress code like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="color: #ccc;">add_filter<span style="color: grey;">&#40;</span><span style="color: #ff8080;">&quot;posts_orderby&quot;</span><span style="color: grey;">,</span> <span style="color: #ff8080;">&quot;order_by_multiple&quot;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span></pre></div></div>

<p>Make the second string argument there match your function name, of course (it doesn&#8217;t have to be the same name as mine, it can be anything). And you can have more than one function hook into the same hook. They will be executed in the same order they are added. In that case, the `$orderby` argument that&#8217;s coming into the function is the existing SQL fragment. So you could add to it, remove something from it, etc.</p>
<h3>Use Debug Query to help figure out what to return</h3>
<p>So the question is, how do you know what to put in your SQL fragment string? If you know your SQL well, you might be able to figure it out by intuition/trial-and-error. For the rest of us, there is a very helpful WordPress Plugin called <a href="http://wordpress.org/extend/plugins/debug-queries/">Debug Queries</a> which will print out all of the MySQL queries that are run for every page you visit (only for logged-in admins, of course. It&#8217;s just a debugging tool for use while developing).</p>
<p>If you install it, it will print out many queries per page. You have to look for the one that&#8217;s querying for posts. In my testing, mine looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="color: #ccc;"><span style="color: #4080ff;">SELECT</span> SQL_CALC_FOUND_ROWS wp_posts<span style="color: grey;">.*</span> <span style="color: #4080ff;">FROM</span> wp_posts <span style="color: grey;">&#40;</span><span style="color: grey;">...</span><span style="color: grey;">&#41;</span></pre></div></div>

<p>The important part is the `FROM wp_posts`. That means you&#8217;re selecting rows from the posts table. So if you have plugins or metadata that you&#8217;re selecting on, you will see them in that query, and it may help you figure out what incantation you need to put in that `orderby` string.</p>
<p>If you need to sort by category, tag, custom meta-data, etc. as one of your sort values, you may need to alter your MySQL query even more, perhaps <a href="http://codex.wordpress.org/Custom_Queries">using other hooks</a> (very similar to the `posts_orderby` hook), such as `posts_join`, `posts_where`, etc. Each of these modify different parts of the query.</p>
<p>Beyond that, if you still need help figuring out how to get the exact set of posts in the right order, you may need to read up on MySQL in general and learn how to manipulate the queries in more detail. Good Luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/262/blog/wordpress-sort-posts-by-multiple-fields-part-ii/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web Experiments #1: Ajax Convo</title>
		<link>http://jeffgran.com/239/blog/web-experiments-1-ajax-convo</link>
		<comments>http://jeffgran.com/239/blog/web-experiments-1-ajax-convo#comments</comments>
		<pubDate>Sat, 05 Sep 2009 03:02:05 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Web Experiments]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=239</guid>
		<description><![CDATA[1) I&#8217;m learning object-oriented design, design patterns, object-oriented PHP, and object-oriented JavaScript right now. I wanted to do some experimenting with building systems using these concepts, so I came up with the idea of doing a series of &#8220;Web Experiments&#8221; where I take an idea for some kind of web application and make a demo [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-243 alignleft" title="ac" src="http://jeffgran.com/img/ac.jpg" alt="Ajax Convo" width="200" height="200" /></p>
<p>1) I&#8217;m learning object-oriented design, design patterns, object-oriented PHP, and object-oriented JavaScript right now.  I wanted to do some experimenting with building systems using these concepts, so I came up with the idea of doing a series of &#8220;Web Experiments&#8221; where I take an idea for some kind of web application and make a demo of it, for fun and learning.</p>
<p>2) I think ajax is the future of the web.  Somebody somewhere wrote &#8220;full page refreshes are so last year&#8221;, or something to that effect.  I sometimes find myself clicking a link or a tab somewhere out there on the web, mentally crossing my fingers in hopes that it won&#8217;t send me to a new page.  I think more and more people are going to expect slicker interfaces in web sites and web applications, and ajax is the way to get that accomplished.</p>
<p>3) I really like the comment/reply interface on Facebook.  There&#8217;s a series of boxes, each with a comment, and the last box is minimized and says &#8220;Write a comment&#8230;&#8221;.  When you click on it, it expands to look exactly like the other comments, with your picture there, just like it will look once it&#8217;s posted.  You type your brilliant quip, and when you click the button, the comment &#8220;melts&#8221; right into the page, and the next would-be comment appears below..  I think it&#8217;s lovely.</p>
<p>With these three things in mind, I started building my own little &#8220;comment thread&#8221; app. </p>
<p>Features:</p>
<ul>
<li>Add, edit, and remove comments from the &#8220;thread&#8221;.</li>
<li>No page refreshes &#8211; all done with ajax (jQuery)</li>
<li>Comments are stored in a tab-separated text file.</li>
<li>Shift-enter for a line break within a comment.</li>
</ul>
<p>I&#8217;ve also built a class structure that I believe will help me expand the project going forward.  The planned additions/expansions are:</p>
<ul>
<li>MySQL Database support (will be able to switch between text file and MySQL with a single setting)</li>
<li>Rewrite the JavaScript without using jQuery just for fun and practice, and to prove that I can.</li>
<li>Multiple &#8220;threads&#8221; of comments</li>
<li>Only load the latest 10 comments or so, and load more twitter-style.</li>
<li>More to each message, like time/date of post, &#8220;last edited at&#8230;&#8221;, etc.</li>
<li>Maybe a simple user system. I loathe to make people &#8220;sign up&#8221; for things though.</li>
</ul>
<p>If you&#8217;re interested, you can download the files <a title="Ajax Convo Zip File" href="http://jeffgran.com/stuff/ac.zip">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/239/blog/web-experiments-1-ajax-convo/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Book Review: PHP Solutions</title>
		<link>http://jeffgran.com/230/blog/book-review-php-solutions</link>
		<comments>http://jeffgran.com/230/blog/book-review-php-solutions#comments</comments>
		<pubDate>Tue, 01 Sep 2009 00:54:20 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[book review]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=230</guid>
		<description><![CDATA[In my quest to expand my knowledge of the web industry, I knew I needed to understand more PHP.  PHP is one of the (if not the) most popular languages used on the web today.  I had been exposed to it a little, and I have experience with other C-ish syntax languages, but I needed [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-231" title="php_solutions" src="http://jeffgran.com/img/php_solutions.jpg" alt="PHP Solutions: Dynamic Web Design Made Easy" width="200" height="240" />In my quest to expand my knowledge of the web industry, I knew I needed to understand more PHP.  PHP is one of the (if not <em>the</em>) most popular languages used on the web today.  I had been exposed to it a little, and I have experience with other C-ish syntax languages, but I needed to brush up on the fundamentals and the unique qualities of PHP.</p>
<p>I chose <em>PHP Solutions: Dynamic Web Design Made Easy</em> because I wanted to have some real-world projects to play with as I learned the language, as opposed to just the dry information.  The book delivered in that respect.  As per the name, the book focuses on specific needs and solutions for those needs using PHP and MySQL.  I got to see how PHP works with forms and databases, and how these techniques could be applied in a simple database-driven blog, for example.</p>
<p>However, probably the most useful part of the book for me were the tutorials on getting the Apache server, PHP and MySQL running on my local machine so that I could just jump into a code editor and start playing around.  I actually ended up skipping to these two chapters (one for Apache/PHP and one for MySQL) and then put the book down for a month or so before I picked it back up and finished reading it.</p>
<p>I started out by following along with the solutions and the code samples, typing them in and trying it out as I was reading, but soon realized that this was unnecessary.  I finished reading the better part of the book by simply reading and understand the code examples.  Whether this is a good thing or bad is up for debate.  It means the writing was clear, but also that the content was less challenging.</p>
<p>Besides the setup chapters mentioned above, the other most useful takeaway I had from this book was all the little things about the language that I mentioned above.  Things like &#8220;the truth according to PHP&#8221; (&#8220;false&#8221; evaluates to true because of type coercion), how the $_POST and $_GET superglobal arrays work, and other little things that really help put it all together in my head.</p>
<p>Another very useful aspect to the way the solutions in the book are constructed is the focus on security and thoroughness.  Some books leave out details, only hinting at it with phrases like &#8220;in a real application, we&#8217;d check this or that&#8221;, but in this book we are treated to some very useful (and usually very simple) techniques to make sure the code we&#8217;re building is secure and bulletproof.</p>
<p>All in all, I&#8217;m glad I now have the information I gained from this book, but I&#8217;m not sure it was exactly what I was looking for.  As with other introductory-level books, I found myself a bit annoyed by the &#8220;if that last part made your head explode, don&#8217;t worry, just copy the code and know that it works&#8221; -type attitude.  My head didn&#8217;t explode &#8211; on the contrary, that was one part where my brain actually felt that tingle of a concept falling into place.  Most of the book was spent thinking to myself, &#8220;yeah, I get it.  OK.  What&#8217;s next?&#8221;  I think I would recommend this book to others, but only if you&#8217;re newer to programming in general, and have very little or no PHP experience.  For me, with quite a bit of general programming, and some hands-on PHP experience from working with WordPress themes, it just felt a little bit too slow, but it did fill in some crucial gaps in my knowledge.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/230/blog/book-review-php-solutions/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript vs. jQuery vs. the DOM</title>
		<link>http://jeffgran.com/156/blog/javascript-jquery-vs-the-dom</link>
		<comments>http://jeffgran.com/156/blog/javascript-jquery-vs-the-dom#comments</comments>
		<pubDate>Wed, 03 Jun 2009 23:28:40 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=156</guid>
		<description><![CDATA[When I first started learning about Javascript, it took me a little while before I could wrap my head around the distinctions and relationships between Javascript, jQuery and the DOM.  So I thought I would lay out what I've learned so that it might help someone where I was.]]></description>
			<content:encoded><![CDATA[<p>When I first started learning about Javascript, it took me a little while before I could wrap my head around the distinctions and relationships between Javascript, jQuery and the DOM.  So I thought I would lay out what I&#8217;ve learned so that it might help someone where I was.</p>
<h3>Javascript</h3>
<p>Javascript is a programming language.  It comes standard with most modern web browsers.  It is also the same language that is used in Flash (where it&#8217;s called ActionScript), and can be used to write scripts in Photoshop, Illustrator, etc.  In the context of a web browser, it is often used to manipulate the DOM (see below).</p>
<h3>jQuery</h3>
<p>jQuery is a Javascript library, meaning that it is essentially a collection of functions written in Javascript that can be used to make the programmer&#8217;s job easier.  Common tasks that take more lines of code with traditional Javascript can be executed with calls to the jQuery functions.  There are several other Javascript libraries out there that fill the same need.  For one reason or another, jQuery seems to be the most popular library of the day.</p>
<h3>The DOM</h3>
<p>The Document Object Model (DOM), is just that &#8211; a model for representing and interacting with an XML, XHTML, or HTML document.  Our HTML documents are created by typing tags in plain text, and the DOM is a way to access the tags and the structure of the &#8220;tag tree&#8221;.  For example, instead of using regular expressions to find the text that represents a tag with a specific ID attribute, we can ask the DOM which of its tags has that ID.  Javascript is not part of the DOM or vice-versa, but Javascript in the browser does include some intelligence about the DOM &#8211; for example, the getElementById() function.  One of the main advantages of jQuery is the extra intelligence it has regarding the DOM.  With it, you access and create DOM elements (tags) by using the many selectors and traversing operations it offers.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/156/blog/javascript-jquery-vs-the-dom/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress: Using a custom home page</title>
		<link>http://jeffgran.com/139/blog/wordpress-custom-home-page</link>
		<comments>http://jeffgran.com/139/blog/wordpress-custom-home-page#comments</comments>
		<pubDate>Tue, 19 May 2009 19:25:13 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=139</guid>
		<description><![CDATA[WordPress hs a simple checkbox in the Admin->Settings panel that lets you set a certain file to be the "static" home page instead of the default listing of the latest posts.

I'm going to show you how (and why) I did NOT use that feature to create my customized home page.]]></description>
			<content:encoded><![CDATA[<p>WordPress hs a simple checkbox in the Admin-&gt;Settings panel that lets you set a certain file to be the &#8220;static&#8221; home page instead of the default listing of the latest posts.</p>
<p>I&#8217;m going to show you how (and why) I did NOT use that feature to create my customized home page.</p>
<p>Here&#8217;s what I wanted:</p>
<ol>
<li>A unique page for the home page, including a few of the latest posts (displayed differently than on the main blog page)</li>
<li>The main blog page to be located at &#8220;url.com/blog&#8221;, showing the default latest posts  (assuming permalinks are turned on)</li>
<li>All other dynamic archive pages shown by month, tag, category, etc., should be shown using the same template as the main blog page, without creating any duplicate files</li>
</ol>
<p>Here&#8217;s how I did it:</p>
<h3>home.php</h3>
<p>Instead of using the admin interface to designate a specific file for your home page, you can use WordPress&#8217;s built-in <a title="Template Hierarchy" href="http://codex.wordpress.org/Template_Hierarchy">template hierarchy</a>.  This method has the advantage that if you&#8217;re building this theme for the public, it will automatically behave how you want it to, instead of having to instruct the user to alter their settings.</p>
<p>To do this simply design your home page&#8217;s php/html/css, and name it home.php.  That&#8217;s it &#8211;  &#8220;home.php&#8221; takes precedence over &#8220;index.php&#8221;.</p>
<h3>Custom loop</h3>
<p>WordPress shows blog posts in what they call &#8220;The Loop&#8221;.  The Loop works by doing the following:</p>
<ol>
<li>The query &#8212; gets a set of posts based on what page we&#8217;re viewing.  Usually this is automatic, using the URL (e.g. &#8220;?p=138&#8243; or &#8220;/category/news&#8221;).</li>
<li>&#8220;if(have_posts()):&#8221; &#8212; just like it looks, it makes sure the query got at least one post.</li>
<li>&#8220;while(have_posts()):&#8221; &#8212; keep doing the loop until we don&#8217;t have any more posts.</li>
<li>&#8220;the_post();&#8221; &#8212; this basically &#8220;loads up&#8221; the current post in the loop so that all the <a title="Template Tags" href="http://codex.wordpress.org/Template_Tags">template tags</a> associated with the post will reference this specific post from this specific query.</li>
<li>Then comes the markup output for each post.</li>
<li>&#8220;endwhile; endif;&#8221; &#8212; the end of the loop.</li>
</ol>
<p>So, in order to customize the Loop, there are two main things we can do.  One is to make a unique query, and the other is to create a unique layout structure inside the loop.</p>
<p>For my home page, I wanted only the 2 most recent posts rather than the number set in the admin panel that would be used for the main blog page.  I added a simple counter and put this code in the appropriate spot in home.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="php" style="color: #ccc;"><span style="color: #ffc080;">$i</span> <span style="color: grey;">=</span> <span style="color: #cc66cc;">0</span><span style="color: grey;">;</span>
<span style="color: #4080ff;">if</span><span style="color: grey;">&#40;</span>have_posts<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span> <span style="color: grey;">:</span> <span style="color: #4080ff;">while</span><span style="color: grey;">&#40;</span>have_posts<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&amp;&amp;</span> <span style="color: #ffc080;">$i</span><span style="color: grey;">&lt;</span><span style="color: #cc66cc;">2</span><span style="color: grey;">&#41;</span> <span style="color: grey;">:</span> the_post<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span>
   <span style="color: #80ff80">// html output, template tags, etc go here</span>
   <span style="color: #ffc080;">$i</span><span style="color: grey;">++;</span>
<span style="color: #4080ff;">endwhile</span><span style="color: grey;">;</span> <span style="color: #4080ff;">endif</span><span style="color: grey;">;</span></pre></td></tr></table></div>

<h3>index.php</h3>
<p>In the aforementioned template hierarchy, index.php is the default template for all blog pages, and in the absence of home.php it would be the home page as well.  So I used index.php to put my main, default loop.  But how do we get index.php to show up at &#8220;url.com/blog&#8221;?</p>
<p>This is the part that I have never seen anywhere else, and what prompted me to write this post.  What I did was use index.php for its special status in the template hierarchy, and ALSO used the same file as a Page Template.  To use index.php as a template, just add the magic keyword/comment at the top, like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="php" style="color: #ccc;"><span style="color: #ffff00;">&lt;?php</span> <span style="color: #80ff80">/*
Template Name: blog
 */</span></pre></td></tr></table></div>

<p>Now, create a blank Page in the admin panel titled Blog, and assign the &#8216;blog&#8217; page template to it.  The title will still be used to display the title on the page, and assigning the &#8216;blog&#8217; template to it makes it use index.php as the page template.</p>
<h3>Custom query</h3>
<p>So now the url for the blog is right, but it&#8217;s displaying the blank page created in the admin instead of the default loop of latest blog posts.  To remedy that, we put a conditional test at the top, and if this is the blog page, we &#8220;reset&#8221; the query so that it contains all the posts.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="php" style="color: #ccc;"><span style="color: #4080ff;">if</span><span style="color: grey;">&#40;</span>is_page<span style="color: grey;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
   query_posts<span style="color: grey;">&#40;</span><span style="color: #ff8080;">&quot;&quot;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span>
<span style="color: grey;">&#125;</span></pre></td></tr></table></div>

<p>The &#8220;query_posts&#8221; function creates the query, as mentioned above.  Passing an empty string as the argument makes sure we get all the posts.  We put this above the start of the Loop, to override the automatic query that is just returning the one &#8216;post&#8217;, in this case being the blank Blog page.</p>
<h3>Fixing the pagination</h3>
<p>There&#8217;s one other quirky problem we have to deal with now.  The flaw is in the empty query.  It works, but when you get to multiple pages worth of posts, the paging will not work right.  When we click the &#8220;next page&#8221; or &#8220;page 2&#8243; link, the page number we&#8217;re going gets passed to the database as part of the query.  When we override the query with a blank one, we also override the page information, so we always end up on page 1.  To fix this, we have to find add a little test to find out the proper page, and add that in to our custom query.  After adding the paging fix, our custom query looks like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="php" style="color: #ccc;"><span style="color: #4080ff;">if</span><span style="color: grey;">&#40;</span>is_page<span style="color: grey;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
   <span style="color: #4080ff;">if</span> <span style="color: grey;">&#40;</span>get_query_var<span style="color: grey;">&#40;</span><span style="color: #0000ff;">'paged'</span><span style="color: grey;">&#41;</span><span style="color: grey;">&#41;</span>
      <span style="color: #ffc080;">$paged</span> <span style="color: grey;">=</span> get_query_var<span style="color: grey;">&#40;</span><span style="color: #0000ff;">'paged'</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span>
   <span style="color: #4080ff;">else</span> <span style="color: #ffc080;">$paged</span> <span style="color: grey;">=</span> <span style="color: #cc66cc;">1</span><span style="color: grey;">;</span>
   query_posts<span style="color: grey;">&#40;</span><span style="color: #ff8080;">&quot;paged=<span style="color: #006699; font-weight: bold;">$paged</span>&quot;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span>
<span style="color: grey;">&#125;</span></pre></td></tr></table></div>

<p>&#8220;get_query_var(&#8216;paged&#8217;)&#8221; gets the paging information from the original query that we&#8217;re about to override.  If it&#8217;s there, we use it, and if not, we assume we&#8217;re on page one.  Now you can write a spiffy Loop below this and it will be used for all blog post listings, including the default one at &#8220;/blog&#8221;</p>
<p>I hope this was helpful to someone!</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/139/blog/wordpress-custom-home-page/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Specialize, they say</title>
		<link>http://jeffgran.com/119/blog/specialize-they-say</link>
		<comments>http://jeffgran.com/119/blog/specialize-they-say#comments</comments>
		<pubDate>Wed, 06 May 2009 21:40:01 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[announcement]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=119</guid>
		<description><![CDATA[I&#8217;ve been reading a lot about how to make your way in this crazy world of people who make web sites.  Several authorities have suggested that, especially when starting out, it&#8217;s a good idea to specialize in one particular niche. I&#8217;ve decided to concentrate on WordPress development for several reasons: WordPress is one of the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been reading a lot about how to make your way in this crazy world of people who make web sites.  Several authorities have suggested that, especially when starting out, it&#8217;s a good idea to specialize in one particular niche.</p>
<p>I&#8217;ve decided to concentrate on WordPress development for several reasons:</p>
<ul>
<li>WordPress is one of the most popular blogging and CMS systems out there today.</li>
<li>In the hands of an expert, WP can be extremely flexible.</li>
<li>WP is easy to get started with, but difficult to master.  Inexperienced users often require expert assistance in customization.</li>
<li>I&#8217;m already using it for this site, and have at least one more site in development using it.</li>
<li>The skills used in creating wordpress themes (XHTML, CSS, PHP) are all applicable to generic web design uses &#8211; I&#8217;m not boxing myself in.</li>
</ul>
<p>The plan for now is to keep practicing with custom wordpress themes.  First up is a redesign of this site.  Yep, it&#8217;s only a couple of weeks old and it&#8217;s already on the chopping block.  What can I say?  Sometimes I&#8217;m a perfectionist.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/119/blog/specialize-they-say/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;Spec Work&#8221;</title>
		<link>http://jeffgran.com/87/blog/spec-work</link>
		<comments>http://jeffgran.com/87/blog/spec-work#comments</comments>
		<pubDate>Thu, 30 Apr 2009 18:30:48 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=87</guid>
		<description><![CDATA[I&#8217;ve read a couple of interesting blog posts (and comment threads) lately regarding what&#8217;s known in this industry as &#8220;spec work&#8221; &#8212; short for &#8220;speculative work.&#8221; Basically what this means is working for free.  Investors speculate on whether their investments will increase or decrease in value.  In the design profession, the objection to spec work [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve read <a title="Spec You" href="http://www.nikibrown.com/designoblog/2009/04/16/spec-you-why-designers-should-never-work-for-free/">a couple</a> <a title="I rock your spec work boat" href="http://adii.co.za/2009/04/i-rock-your-spec-work-boat/">of interesting</a> <a href="http://www.zeldman.com/daily/0104h.shtml">blog posts</a> (and comment threads) lately regarding what&#8217;s known in this industry as &#8220;spec work&#8221; &#8212; short for &#8220;speculative work.&#8221;</p>
<p><img class="alignleft size-full wp-image-174" title="Rainy Day Inn Mockup" src="http://jeffgran.com/img/rdi_mockup.jpg" alt="Rainy Day Inn Mockup" width="240" height="180" />Basically what this means is working for free.  Investors speculate on whether their investments will increase or decrease in value.  In the design profession, the objection to spec work can be put this way: you&#8217;re speculating with a large risk for a very small reward. You volunteer your valuable time working on your craft, all for the chance of being awarded the contract.  An investment banker would never take that bet.  The client in this case gets a lot of free design work, and the &#8220;winning&#8221; designer is probably most often the one willing to do the most for the least pay.  This is one reason why many <a title="Spec work in graphic design" href="http://www.davidairey.com/spec-work-in-graphic-design/">respected designers</a>, the <a title="AIGA Position on spec work" href="http://www.aiga.org/content.cfm/position-spec-work">AIGA</a>, and other organizations like <a title="NO!SPEC" href="http://www.no-spec.com/">NO!SPEC</a> strongly advise all designers against this type of work.  And it&#8217;s not just about the individual instance of the free work, but it also encourages the lead/client and indeed the general public to see this type of business practice as the &#8220;norm&#8221;.</p>
<p>But there&#8217;s another major disadvantage to working on spec, from the both the designer&#8217;s AND the client&#8217;s perspective.  The fact is that a good design, that meets the client&#8217;s needs, involves the PROCESS as much or more than the execution of the design itself.  With this kind of work, the &#8220;design brief&#8221; is often something like &#8220;I&#8217;ll know it when I see it.&#8221;  A professional designer who&#8217;s good at his/her job will engage the client to find their specific needs, the intended emotional impact of the work, research the intended market and competition if any, etcetera etcetera.  When there is simply a prompt of &#8220;make a design for my company, and if I like it I&#8217;ll buy it&#8221;, there&#8217;s virtually no way for either party to guarantee that the design will match the intention.</p>
<p>Now, why am I writing about this?  Well&#8230; um&#8230; I did some spec work yesterday, and I have a sick feeling in my stomach as a result.  The results of the &#8220;contest&#8221; are still to be decided, and there&#8217;s still a chance I&#8217;ll be selected for the work.  Regardless, it feels bad for two reasons.  (1) It feels like grovelling, offering my services for free; and (2) I feel like I could do a much better job if I invested more time in communicating with the client, doing mockups and revisions, and generally carrying out the transaction in a more professional way.  The problem with that is that it&#8217;s a catch 22 &#8212; either I invest a lot more time to make a better end product that still might not win, or I stick with the simple mockups I did in a few hours which I know could be better.</p>
<p>So knowing all this, why did I do it?  Mostly for the same reason the apologists often cite as the one example where it might make sense.  Aspiring designers without much of a reputation or portfolio to speak of.  See, I&#8217;m already in that classic of all catch 22s where I need experience in order to get experience.  So I did some work for free, and hey, I might just convert those mockups into demo WordPress themes anyway, just for the portfolio material.  But I think the bottom line here is that you&#8217;ll be treated how you expect to be treated.  Fake it &#8217;till you make it, right?  Act like a professional, and you are one.</p>
<p>If anyone happens to read this, I&#8217;d be interested to hear opinions in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/87/blog/spec-work/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Book Review: CSS: The Missing Manual</title>
		<link>http://jeffgran.com/62/blog/book-review-css-the-missing-manual</link>
		<comments>http://jeffgran.com/62/blog/book-review-css-the-missing-manual#comments</comments>
		<pubDate>Sun, 26 Apr 2009 12:50:42 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[book review]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=62</guid>
		<description><![CDATA[I&#8217;m the kind of person that likes to learn by doing. The first time I touched any CSS code it was out of necessity.  Being used to the old-school style of HTML, using tables and attributes for layout and color, I was trying in vain to alter a Joomla template I was working with by [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m the kind of person that likes to learn by doing.</p>
<p><img class="alignleft size-full wp-image-172" title="CSS: THe Missing Manual" src="http://jeffgran.com/img/css_cover_med.png" alt="CSS: THe Missing Manual" width="145" height="190" />The first time I touched any CSS code it was out of necessity.  Being used to the old-school style of HTML, using tables and attributes for layout and color, I was trying in vain to alter a Joomla template I was working with by just editing the HTML.  (Part of the problem, in retrospect, was that the template in question was a weird hybrid of table-based layout and CSS-based colors and images &#8211; but I digress.)  Eventually I realized it was the .css file that I had to play with, and after several hours of experimenting and tweaking, I had sort-of figured out how descendant selectors and classes and ids worked.  Sort of.  I got the results I wanted, but not in the most graceful way possible by far, and without a complete understanding of how I did it.</p>
<p>So when I recently decided to take my career towards web design as a profession, I knew I had to brush up my knowledge in certain key areas, starting with XHTML and CSS.</p>
<p>Enter <a title="CSS: The Missing Manual" href="http://www.amazon.com/CSS-Missing-Manual-David-McFarland/dp/0596526873/"><em>CSS: The Missing Manual</em></a> by <a title="Sawyer McFarland Media, Inc." href="http://www.sawmac.com/">David Sawyer McFarland</a>.  The book starts out with a short review of (X)HTML, explaining how and why modern HTML is different than it used to be.  More than just a list of changes, this opening section is a mini-treatise on the modern concept of separating the structure &#8220;layer&#8221; of a web document from the presentation &#8220;layer&#8221;.</p>
<p>From there, the book goes on to explain in a very readable manner the basics of internal and external stylesheets, and inline style declarations and why they&#8217;re usually best avoided.  Also extremely helpful is the explanation of &#8220;the cascade&#8221; and how it works.  This information, while it may seem boring and bookish in other presentations of the same material, is essential in understanding why sometimes you write a style that should work but nothing happens.  This is often caused by precedence rules according to the cascade.</p>
<p>The meat of the book follows, and of course it entails thorough treatments of every HTML element you&#8217;d ever want or need to style, ending with a substantial section of the book devoted to page layout techniques.</p>
<p>But the best part of the book has to be the inclusion of the tutorials.  As I said above, I learn best by doing, and this book is set up for just that.  There&#8217;s a set of files you can download from the book&#8217;s website to work with as you go through the books tutorials.  Each chapter has two parts: first, an introduction to the topic; and second, a tutorial where you can follow along and see the concepts in action.  It&#8217;s a great way to get used to typing the code so that the syntax becomes second-nature.  And, if you&#8217;re anything like me, you&#8217;ll find yourself continuing to tweak and add and subtract the styles after the tutorial&#8217;s over, just to see what happens and deepen the understanding.</p>
<p>Overall, highly recommended.  The book lives up to its name.  In fact, I enjoyed it so much (and felt I learned so much from it) that I bought the Javascript book in the same series, which focuses on immediately applicable Javascript techniques using the popular jQuery library.  I can&#8217;t wait to get started. <img src='http://jeffgran.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/62/blog/book-review-css-the-missing-manual/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress: Custom Links Display</title>
		<link>http://jeffgran.com/38/blog/wordpress-custom-links-display</link>
		<comments>http://jeffgran.com/38/blog/wordpress-custom-links-display#comments</comments>
		<pubDate>Fri, 24 Apr 2009 09:53:36 +0000</pubDate>
		<dc:creator>Jeff Gran</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://jeffgran.com/?p=38</guid>
		<description><![CDATA[I&#8217;ve been working with WordPress for a couple of days now, and I&#8217;m thoroughly impressed by its elegant design. I&#8217;ve always been a fan of modular, extensible, customizable systems, and WordPress does not disappoint. The great thing about the architecture they&#8217;ve built is that if one level of control can&#8217;t do what you need, there [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with WordPress for a couple of days now, and I&#8217;m thoroughly impressed by its elegant design. I&#8217;ve always been a fan of modular, extensible, customizable systems, and WordPress does not disappoint. The great thing about the architecture they&#8217;ve built is that if one level of control can&#8217;t do what you need, there is always another successive level to delve into.</p>
<p>My point will be made more easily with an example:  I wanted to show the links on my &#8220;Links&#8221; page in boxes, with linked title and images, and a short description, all controlled by CSS classes.</p>
<p>WordPress offers a &#8220;template tag&#8221; (that is, PHP function) for theme creators to display the list of links added via the admin panel.  You can put it anywhere in your templates (for example, in the sidebar) and it will automatically keep the list up-to-date:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="color: #ccc;">wp_list_bookmarks<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span></pre></td></tr></table></div>

<p>That function generates an unordered list of link categories, with sub-lists of each link, complete with CSS styles assigned so that you can add a custom style.  But, say you (like me) don&#8217;t want the categories, just the links please.  And can I have it show the images associated with the links as well?</p>
<p>To this end, the WordPress developers have included a large range of optional arguments for the function above, so you can include or exclude categories, decide whether to format the list as an unordered list (&lt;ul&gt;) or other custom HTML tag, whether to show the images and descriptions, etc:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="color: #ccc;">wp_list_bookmarks<span style="color: grey;">&#40;</span><span style="color: #0000ff;">'categorize=0&amp;title_li=&amp;show_images=1&amp;show_description=1'</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span></pre></td></tr></table></div>

<p>Pretty good, but what if I want even more control (I usually do <img src='http://jeffgran.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  )?  The next-deepest level of under-the-hood-ness allows you to get the list of links, store it in an array, and then loop through the array using a simple PHP foreach loop that outputs the link data in whatever custom format you need.  It&#8217;s easier than it sounds.  Here&#8217;s the final code I used for my links page:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="php" style="color: #ccc;"><span style="color: #ffff00;">&lt;?php</span>
<span style="color: #ffc080;">$myLinks</span> <span style="color: grey;">=</span> get_bookmarks<span style="color: grey;">&#40;</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span>
<span style="color: #4080ff;">foreach</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLinks</span> <span style="color: #4080ff;">as</span> <span style="color: #ffc080;">$myLink</span><span style="color: grey;">&#41;</span> <span style="color: grey;">&#123;</span>
<span style="color: grey;">?&gt;</span>
   &lt;div class=&quot;linkBox&quot;&gt;
      &lt;a href=&quot;<span style="color: #ffff00;">&lt;?php</span> <span style="color: #4080ff;">echo</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLink</span><span style="color: grey;">-&gt;</span><span style="color: magenta;">link_url</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span> <span style="color: grey;">?&gt;</span>&quot;&gt;&lt;img src=&quot;<span style="color: #ffff00;">&lt;?php</span> <span style="color: #4080ff;">echo</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLink</span><span style="color: grey;">-&gt;</span><span style="color: magenta;">link_image</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span> <span style="color: grey;">?&gt;</span>&quot; /&gt;&lt;/a&gt;
      &lt;h3&gt;&lt;a href=&quot;<span style="color: #ffff00;">&lt;?php</span> <span style="color: #4080ff;">echo</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLink</span><span style="color: grey;">-&gt;</span><span style="color: magenta;">link_url</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span> <span style="color: grey;">?&gt;</span>&quot;&gt;<span style="color: #ffff00;">&lt;?php</span> <span style="color: #4080ff;">echo</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLink</span><span style="color: grey;">-&gt;</span><span style="color: magenta;">link_name</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span> <span style="color: grey;">?&gt;</span>&lt;/a&gt;&lt;/h3&gt;
      &lt;p&gt;<span style="color: #ffff00;">&lt;?php</span> <span style="color: #4080ff;">echo</span><span style="color: grey;">&#40;</span><span style="color: #ffc080;">$myLink</span><span style="color: grey;">-&gt;</span><span style="color: magenta;">link_description</span><span style="color: grey;">&#41;</span><span style="color: grey;">;</span> <span style="color: grey;">?&gt;</span>&lt;/p&gt;
   &lt;/div&gt;
<span style="color: #ffff00;">&lt;?php</span> <span style="color: grey;">&#125;</span> <span style="color: grey;">?&gt;</span></pre></td></tr></table></div>

<p>And of course, if needed there are more levels below this one.  You could do a loop within a loop, for example, to format each category of links with its own category heading, different colors or styles, etc.</p>
<p>Ahhh, the power! <img src='http://jeffgran.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://jeffgran.com/38/blog/wordpress-custom-links-display/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

