<?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>Oxford Bloggers &#187; drupal</title>
	<atom:link href="http://oxfordbloggers.com/tag/drupal/feed/" rel="self" type="application/rss+xml" />
	<link>http://oxfordbloggers.com</link>
	<description>A site featuring the writing and photography of Oxford&#039;s bloggers</description>
	<lastBuildDate>Fri, 10 Sep 2010 18:02:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Going to DrupalCon Copenhagen</title>
		<link>http://www.jpstacey.info/blog/2010/08/17/going-drupalcon-copenhagen</link>
		<comments>http://www.jpstacey.info/blog/2010/08/17/going-drupalcon-copenhagen#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:40:40 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[copenhagen]]></category>
		<category><![CDATA[cph2010]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupalcon]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[torchbox]]></category>

		<guid isPermaLink="false">331 at http://www.jpstacey.info</guid>
		<description><![CDATA[Over on the Torchbox blog I've written about the fact that I'm going to DrupalCon Copenhagen, which is happening all next week. There's not much to add here except that if you're in Copenhagen, and you see someone who looks like me, then do say hello.
...]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2010/08/17/going-to-drupalcon-copenhagen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What you need to know about Drupal views</title>
		<link>http://www.jpstacey.info/blog/2010/07/08/what-you-need-know-about-drupal-views</link>
		<comments>http://www.jpstacey.info/blog/2010/07/08/what-you-need-know-about-drupal-views#comments</comments>
		<pubDate>Thu, 08 Jul 2010 19:51:37 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">329 at http://www.jpstacey.info</guid>
		<description><![CDATA[Every content management system needs its query builder—an application which creates customizable lists of content elements and present them in a similarly customisable way. Customization will be typically through an admin interface on the website, a...]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2010/07/08/what-you-need-to-know-about-drupal-views/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Feeds objects within feeds objects</title>
		<link>http://www.jpstacey.info/blog/2010/05/25/feeds-objects-within-feeds-objects</link>
		<comments>http://www.jpstacey.info/blog/2010/05/25/feeds-objects-within-feeds-objects#comments</comments>
		<pubDate>Wed, 09 Jun 2010 10:35:05 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[atom]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[layers]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[objectoriented]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[rss]]></category>

		<guid isPermaLink="false">326 at http://www.jpstacey.info</guid>
		<description><![CDATA[We've been doing a lot of work with the Drupal Feeds module recently. The frontend is nice enough, although the sub-navigation was rendered almost illegible by our theme's CSS. The online tutorials need work,&#160;and the admin navigation needs to be m...]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2010/06/09/feeds-objects-within-feeds-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Drupal view serving multiple tabs</title>
		<link>http://www.jpstacey.info/blog/2010/05/17/drupal-view-serving-multiple-tabs</link>
		<comments>http://www.jpstacey.info/blog/2010/05/17/drupal-view-serving-multiple-tabs#comments</comments>
		<pubDate>Mon, 17 May 2010 09:59:34 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[menu]]></category>
		<category><![CDATA[subtleties]]></category>
		<category><![CDATA[tabs]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[view]]></category>

		<guid isPermaLink="false">322 at http://www.jpstacey.info</guid>
		<description><![CDATA[Drupal's menu hierarchy is a big and complex beast. It acts as both the repository for registered menu callback handlers (and their associated permissions handlers) and as a way of building more mundane frontend menus for people to click round. It serv...]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2010/05/17/a-drupal-view-serving-multiple-tabs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Render any block in Drupal 5</title>
		<link>http://www.jpstacey.info/blog/2009/12/08/render-any-block-drupal-5</link>
		<comments>http://www.jpstacey.info/blog/2009/12/08/render-any-block-drupal-5#comments</comments>
		<pubDate>Tue, 08 Dec 2009 09:37:51 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[block]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[panels]]></category>
		<category><![CDATA[recipe]]></category>

		<guid isPermaLink="false">309 at http://www.jpstacey.info</guid>
		<description><![CDATA[<p>Blocks aren't what you might call "first-class citizens" in Drupal 5 or 6 (or 7, as far as I'm aware). Block functionality is provided by a range of functions and database tables, but ultimately there's no thingness, no <i>Ding an sich</i> tying them together as an object the way that a node of content or a user might be.</p>
<p>Annoyingly, there's no function in Drupal 5 to grab a block and render it. You can render a <em>region</em>, a block container which then makes a number of decisions for you about what blocks should appear in it. Blocks can in principle be uniquely identified by (a) the module which provides the block through its implementation of <span class="geshifilter"><code>hook_block()</code></span> and (b) the "delta", the unique (potentially non-numeric) ID for each block in a given module. Yet there are no functions in the core block module to handle this.</p>
<p>One option is to move to Panels, which I'm doing for this site. Yet if your existing site is heavily based around blocks and regions, implementing Panels can be a lot of overhead just to render a single block in a template.</p>
<p>Here's a function which returns a single block, given the module name and block delta. It's an abstraction from <span class="geshifilter"><code>block_list<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>, the function which returns all the blocks in a given region. You can put this in a shell module with an info file (see the previous post on <a href="/blog/2009/11/24/basic-theme-preprocess-hooks-drupal-5">theme preprocess hooks in Drupal 5</a> for how to quickly set up an otherwise empty module) or if you're not comfortable with that you can always name it accordingly and put it in <span class="geshifilter"><code>template<span class="sy0">.</span>php</code></span></p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="co4">/**
 * Get a single block for themeing
 */</span>
<span class="kw2">function</span> mymodule_get_block<span class="br0">&#40;</span><span class="re0">$module</span><span class="sy0">,</span> <span class="re0">$delta</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// User roles mean blocks are still invisible if the user</span>
  <span class="co1">// isn't permitted to see them</span>
  <span class="kw2">global</span> <span class="re0">$user</span><span class="sy0">;</span>
  <span class="re0">$rids</span> <span class="sy0">=</span> <a href="http://www.php.net/array_keys"><span class="kw3">array_keys</span></a><span class="br0">&#40;</span><span class="re0">$user</span><span class="sy0">-&#62;</span><span class="me1">roles</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="re0">$placeholders</span> <span class="sy0">=</span> <a href="http://www.php.net/implode"><span class="kw3">implode</span></a><span class="br0">&#40;</span><span class="st_h">','</span><span class="sy0">,</span> <a href="http://www.php.net/array_fill"><span class="kw3">array_fill</span></a><span class="br0">&#40;</span>0<span class="sy0">,</span> <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$rids</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'%d'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&#160;
  <span class="co1">// This is still cropped from block_list() , but newlines added</span>
  <span class="co1">// for legibility and blogposting</span>
  <span class="re0">$result</span> <span class="sy0">=</span> db_query<span class="br0">&#40;</span>
      <span class="st0">&#34;SELECT DISTINCT b.* &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34; FROM {blocks} b LEFT JOIN {blocks_roles} r &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34;   ON b.module = r.module AND b.delta = r.delta &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34; WHERE (r.rid IN (<span class="es4">$placeholders</span>) OR r.rid IS NULL) &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34;   AND b.module = '<span class="es6">%s</span>' &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34;   AND b.delta = '<span class="es6">%s</span>' &#34;</span>
    <span class="sy0">.</span> <span class="st0">&#34; ORDER BY b.region, b.weight, b.module&#34;</span><span class="sy0">,</span> 
    <a href="http://www.php.net/array_merge"><span class="kw3">array_merge</span></a><span class="br0">&#40;</span><span class="re0">$rids</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="re0">$module</span><span class="sy0">,</span><span class="re0">$delta</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&#160;
  <span class="co1">// Assemble block info from the module</span>
  <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$block</span> <span class="sy0">=</span> db_fetch_object<span class="br0">&#40;</span><span class="re0">$result</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="co1">// Invoke the block hook in the supporting </span>
    <span class="co1">// module and convert the return array</span>
    <span class="re0">$array</span> <span class="sy0">=</span> module_invoke<span class="br0">&#40;</span><span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">module</span><span class="sy0">,</span> <span class="st_h">'block'</span><span class="sy0">,</span> <span class="st_h">'view'</span><span class="sy0">,</span> <span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">delta</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span> <span class="sy0">&#38;&#38;</span> <a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$array</span> <span class="kw1">as</span> <span class="re0">$k</span> <span class="sy0">=&#62;</span> <span class="re0">$v</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="re0">$block</span><span class="sy0">-&#62;</span><span class="re0">$k</span> <span class="sy0">=</span> <span class="re0">$v</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&#160;
    <span class="co1">// Swap in any user-defined title in admin interface</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">title</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">subject</span> <span class="sy0">=</span> <span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">title</span> <span class="sy0">==</span> <span class="st_h">'&#60;none&#62;'</span> ? <span class="st_h">''</span> <span class="sy0">:</span> check_plain<span class="br0">&#40;</span><span class="re0">$block</span><span class="sy0">-&#62;</span><span class="me1">title</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&#160;
    <span class="kw1">return</span> <span class="re0">$block</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></p>
<p>Once this is safely out of the way you can grab and render a block. The following code grabs the fourth block that you ever created through the block admin interface (the "block" module is the "maintainer" of those blocks, and the blocks are numbered starting at zero, hence "3"):</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">&#60;?php</span> <span class="kw1">print</span> theme<span class="br0">&#40;</span><span class="st_h">'block'</span><span class="sy0">,</span> mymodule_get_block<span class="br0">&#40;</span><span class="st_h">'block'</span><span class="sy0">,</span> 3<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&#62;</span></pre></div></p>
<p>This is a bit unsafe, though. What if you disable <span class="geshifilter"><code>mymodule</code></span>? The template will break, and depending on your server configuration your visitors might see a pretty ugly error. So use the <a href="/blog/2009/11/24/basic-theme-preprocess-hooks-drupal-5">theme preprocess hooks</a> trick. If you want the block to show in <span class="geshifilter"><code>node.tpl.php</code></span> then you're going to have to bite the bullet and put the bigger code snippet above in a module. Then, in the same module, you can write a <span class="geshifilter"><code>hook_preprocess_node</code></span> as follows:</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">function</span> mymodule_preprocess_node<span class="br0">&#40;</span><span class="sy0">&#38;</span><span class="re0">$vars</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$vars</span><span class="br0">&#91;</span><span class="st_h">'myblock'</span><span class="br0">&#93;</span> <span class="sy0">=</span> theme<span class="br0">&#40;</span><span class="st_h">'block'</span><span class="sy0">,</span> mymodule_get_block<span class="br0">&#40;</span><span class="st_h">'block'</span><span class="sy0">,</span> 3<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></p>
<p>Then you can put just the bare variable in your <span class="geshifilter"><code>node.tpl.php</code></span>, which is much safer:</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">&#60;?php</span> <span class="kw1">print</span> <span class="re0">$myblock</span> <span class="sy1">?&#62;</span></pre></div></p>
<p>Turn off mymodule, and this just prints an empty string.</p>
<p>So, ta-da, blocks are now better exposed in your Drupal backend, for you to use in different places in your themeing. Unfortunately that still doesn't make them first-class citizens: they can't be categorized or given an "owner" i.e. an associated user ID; they can't be made to link to nodes in the same robust way that nodes can link to each other with node reference; they certainly can't have any CCK fields hung off them. But, humble though blocks are, they've still got some life left in them yet.</p>

&#60;!--



--&#62;
<div class="trackback-url">
http://www.jpstacey.info/trackback/309</div>]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/12/08/render-any-block-in-drupal-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Basic theme preprocess hooks in Drupal 5</title>
		<link>http://www.jpstacey.info/blog/2009/11/24/basic-theme-preprocess-hooks-drupal-5</link>
		<comments>http://www.jpstacey.info/blog/2009/11/24/basic-theme-preprocess-hooks-drupal-5#comments</comments>
		<pubDate>Tue, 24 Nov 2009 21:23:08 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[backport]]></category>
		<category><![CDATA[compatibility]]></category>
		<category><![CDATA[d5]]></category>
		<category><![CDATA[d6]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[maintenance]]></category>

		<guid isPermaLink="false">307 at http://www.jpstacey.info</guid>
		<description><![CDATA[<p>One of the useful aspects of Drupal 6's themeing is theme preprocessing. This occurs in between a module (or Drupal core) calling <span class="geshifilter"><code>theme()</code></span> and rendering the actual template file (or function), and arbitrarily alter the variables passed between the module layer and the theme layer. In this way preprocess hooks act much like Django's context preprocessors, providing ways for modules to "communicate" at the point of themeing.</p>
<p>Drupal 5 doesn't have any preprocess hooks, unfortunately. All it has is the function <span class="geshifilter"><code>_phptemplate_variables()</code></span> in your theme's <span class="geshifilter"><code>template.php</code></span>. That's the sole instance of theme preprocessing in D5, and this bottlenecking means that the function quickly becomes the dumping ground for <em>all</em> of your site's pre-theme logic. Even if you're a module developer, of <em>any</em> level of experience, there's no incentive to factor this code out elsewhere: you just replace it with whatever the module function's called anyway, and your site becomes more brittle because of it.</p>
<p>With that in mind, here's how to free up your D5 theme preprocessing in a reasonably Drupalish manner. We'll use a helper module, and call a single function, <em>safely</em> from within your <span class="geshifilter"><code>template.php</code></span>. That function will replicate the basics of D6's theme preprocessing and let you start writing D5 modules with preprocess logic in them.</p>
<h2>helpd6.info</h2>
<p>First your helper module needs a <span class="geshifilter"><code>.info</code></span> file. It doesn't need to have very much details in it, but here's a sample file:</p>
<div class="geshifilter">
<pre>
name = D6 forward-compatibility functions
description =  D6 functions, like theme preprocessing
</pre></div>
<h2>helpd6.module</h2>
<p>Next, here's the module in its entirety. Once you've saved this and the <span class="geshifilter"><code>.info</code></span> file into a directory called <span class="geshifilter"><code>helpd6</code></span>, in your site's <span class="geshifilter"><code>modules</code></span> directory, you should be able to enable the module in your Drupal administrative pages.</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">&#60;?php</span>
<span class="co4">/**
 * Implementation of basic theme preprocessing
 */</span>
<span class="kw2">function</span> helpd6_implement_preprocess<span class="br0">&#40;</span><span class="sy0">&#38;</span><span class="re0">$vars</span><span class="sy0">,</span> <span class="re0">$hook</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// module_invoke_all passes by value</span>
  <span class="co1">// So assemble function name and invoke ourselves to pass by reference</span>
  <span class="kw1">foreach</span><span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'preprocess'</span><span class="sy0">,</span> <span class="st0">&#34;preprocess_<span class="es4">$hook</span>&#34;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$stub</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span>module_implements<span class="br0">&#40;</span><span class="re0">$stub</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$mod</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$fn</span> <span class="sy0">=</span> <span class="re0">$mod</span> <span class="sy0">.</span> <span class="st0">&#34;_<span class="es4">$stub</span>&#34;</span><span class="sy0">;</span>
      <span class="re0">$fn</span><span class="br0">&#40;</span><span class="re0">$vars</span><span class="sy0">,</span> <span class="re0">$hook</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></p>
<p>Note we omit the closing PHP tag. And note also that we put an ampersand by <span class="geshifilter"><code>$vars</code></span>. This means we get the "real" theme variables object to play with, not a copy, so that all our logic can modify that "real" variables object and it's reflected by the time Drupal gets round to themeing.</p>
<h2>template.php (excerpt)</h2>
<p>Finally, this snippet ties everything together: it calls your helper module from the theme's <span class="geshifilter"><code>template.php</code></span>. Put it at the very end of the <span class="geshifilter"><code>_phptemplate_variables()</code></span> function:</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">function</span> _phptemplate_variables<span class="br0">&#40;</span><span class="re0">$hook</span><span class="sy0">,</span> <span class="sy0">&#38;</span><span class="re0">$vars</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// ...</span>
&#160;
  <span class="co1">// Finally, run preprocess hook functions</span>
  <a href="http://www.php.net/function_exists"><span class="kw3">function_exists</span></a><span class="br0">&#40;</span><span class="st_h">'helpd6_implement_preprocess'</span><span class="br0">&#41;</span> 
    <span class="sy0">&#38;&#38;</span> helpd6_implement_preprocess<span class="br0">&#40;</span><span class="re0">$vars</span><span class="sy0">,</span> <span class="re0">$hook</span><span class="br0">&#41;</span><span class="sy0">;</span>
&#160;
  <span class="co1">// Now return variables</span>
  <span class="kw1">return</span> <span class="re0">$vars</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></p>
<p>You'll see that it checks the function exists first. You could check with <span class="geshifilter"><code>module_exists('helpd6')</code></span> too, but we're aiming for as robust a setup as possible, so best check the function exists rather than the general module.</p>
<p>We also return the variables. In practice, referring to <span class="geshifilter"><code>&#38;$vars</code></span> in the function declaration means they get merged in situ, but in principle <a href="http://api.drupal.org/api/function/_phptemplate_variables/5">the function's definition on api.drupal.org</a> requires the variables array to be returned. So changes inthe PHPTemplate engine might stop the <span class="geshifilter"><code>&#38;$vars</code></span> trick working in the future.</p>
<h2>Implementation</h2>
<p>You can now implement either <span class="geshifilter"><code>hook_preprocess</code></span> or <span class="geshifilter"><code>hook_preprocess_TYPE</code></span> hooks e.g. <span class="geshifilter"><code>hook_preprocess_page</code></span>. These behave pretty much exactly the same as Drupal 6 preprocess hooks.</p>
<p>As an example, let's say that some nodes on your site have an "author" field. This might be different from Drupal's concept of node author e.g: the node might be created by an admin user, but contain information for a book or other publication; the book itself has an author, who could be anybody in the world, alive or dead. Our site also contains a biography node for each author, so we'd like to have the relevant biography present in the theme layer, to list the biography alongside the book.</p>
<p>Here's a "module"---again, just a single function---that accomplishes just that with the aid of our <span class="geshifilter"><code>helpd6</code></span> module. It should be self-explanatory, but have a look at the comments for more details.</p>
<p><div class="geshifilter"><pre style="font-family:monospace"><span class="kw2">&#60;?php</span>
<span class="co4">/**
 * Implementation of hook_preprocess_node
 */</span>
<span class="kw2">function</span> authorbiog_preprocess_node<span class="br0">&#40;</span><span class="sy0">&#38;</span><span class="re0">$vars</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// Two possible sources for a biography node:</span>
  <span class="co1">// 1. the author is a site user - CCK user ref field</span>
  <span class="co1">// 2. otherwise, use a CCK node ref field</span>
  <span class="re0">$this_node</span> <span class="sy0">=</span> <span class="re0">$vars</span><span class="br0">&#91;</span><span class="st_h">'node'</span><span class="br0">&#93;</span><span class="sy0">;</span>
  <span class="re0">$author_uid</span> <span class="sy0">=</span> <span class="re0">$this_node</span><span class="sy0">-&#62;</span><span class="me1">field_drupal_author</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'uid'</span><span class="br0">&#93;</span><span class="sy0">;</span>
  <span class="re0">$author_nid</span> <span class="sy0">=</span> <span class="re0">$this_node</span><span class="sy0">-&#62;</span><span class="me1">field_offsite_author</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'nid'</span><span class="br0">&#93;</span><span class="sy0">;</span>
&#160;
  <span class="co1">// Load the author's biog into the theme variables</span>
  <span class="co1">// (Could use Content Profile to help with this)</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$author_uid</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$biog</span> <span class="sy0">=</span> node_load<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'uid'</span> <span class="sy0">=&#62;</span><span class="re0">$author_uid</span><span class="sy0">,</span> <span class="st_h">'type'</span> <span class="sy0">=&#62;</span> <span class="st_h">'biography'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$author_nid</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$biog</span> <span class="sy0">=</span> node_load<span class="br0">&#40;</span><span class="re0">$author_nid</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&#160;
  <span class="co1">// Theme preprocess hooks should ALWAYS make the HTML safe</span>
  <span class="co1">// Don't rely on .tpl.php files to filter out possible bad markup</span>
  <span class="re0">$biog</span> <span class="sy0">&#38;&#38;</span> <span class="br0">&#40;</span><span class="re0">$vars</span><span class="br0">&#91;</span><span class="st_h">'biog'</span><span class="br0">&#93;</span> <span class="sy0">=</span> check_markup<span class="br0">&#40;</span><span class="re0">$biog</span><span class="sy0">-&#62;</span><span class="me1">body</span><span class="sy0">,</span> <span class="re0">$biog</span><span class="sy0">-&#62;</span><span class="me1">format</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&#160;
  <span class="co1">// &#38;$vars has been passed by reference, so we don't return anything</span>
  <span class="co1">// But you can now access the biog (if it exists) in node.tpl.php as &#34;$biog&#34;</span>
<span class="br0">&#125;</span></pre></div></p>
<p>You can now access the biography text in the theme layer. Note we don't pass down the whole node: we could, but it's safer to pass down filtered HTML, to avoid any possible security holes. In general, it's the job of theme preprocess hooks to handle HTML security, because you never know where else that HTML is going to end up being rendered.</p>
<p>What's important to remember is that this code, and many other snippets like it, <em>need no longer</em> live in your <span class="geshifilter"><code>template.php</code></span>. It's now in a module. It's something you can turn on and off, just like a module. And it's something your themer need never worry about: that logic is now safely hidden behind the scenes, leaving <span class="geshifilter"><code>template.php</code></span> as a theme helper, what it's meant to be. You don't even need any control logic to determine <span class="geshifilter"><code>$hook</code></span>, because <span class="geshifilter"><code>module_implements()</code></span> and the naming conventions do that for you.</p>
<h2>Summary</h2>
<p>Drupal 5 themeing will never be as versatile as Drupal 6 themeing. But standard code patterns---especially "Drupalish" ones---can go a long way to abstracting out into modules much of the theme preprocessing that Drupal 5 would otherwise force you to do in your theme layer. The more logic you move out of your theme, the more robust it gets, and the easier it is for a non-developer to maintain. </p>

&#60;!--



--&#62;
<div class="trackback-url">
http://www.jpstacey.info/trackback/307</div>]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/11/24/basic-theme-preprocess-hooks-in-drupal-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building pages in Drupal with Panels</title>
		<link>http://www.jpstacey.info/blog/2009/11/16/building-pages-drupal-panels</link>
		<comments>http://www.jpstacey.info/blog/2009/11/16/building-pages-drupal-panels#comments</comments>
		<pubDate>Mon, 16 Nov 2009 20:57:10 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[configurability]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[ctools]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[panels]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">304 at http://www.jpstacey.info</guid>
		<description><![CDATA[<p>When finished this site will implement several different layouts: blogposts, "static" pages, short "nuggets", blog archives, taxonomy listing and probably a bespoke front page. Although these will all have the same <a href="/blog/2009/11/07/implementing-columnar-grid-system-graceful-exits">underlying seven-column layout</a>, that can still present some problems that are usually solved in Drupal with many different theme files and a lot of "regions" in which you can put "blocks" of content.</p>
<p>Regions and blocks have serious limitations, though. For example, any one block---say the most recent posts from the blog, or a feed from Twitter---can only be placed in one region, although it can then be made to appear and disappear on other pages based on URL or (dangerously) bespoke PHP embedded in the database. There are modules which replicate blocks, to try to circumvent such problems. Following <a href="http://drupal.org/user/26979">merlinofchaos</a>' great talk at, once again, <a href="http://paris2009.drupalcon.org/">DrupalCon Paris 2009</a>, I decided to use <a href="http://drupal.org/project/panels">Panels</a>&#160;and panes instead of the core Drupal region/block system.</p>
<p>It was touch and go initially as to whether I was going to scrap it all and start again with blocks and regions or not. I managed fairly quickly to assemble custom pages for nodes of a few different types, but then had real trouble working out the subtleties of getting custom pages together for existing non-single-node content. Panels and its associated <a href="http://drupal.org/project/ctools">CTools developer framework</a> concentrate far more on front-end functionality than ease of backend user experience. That's a shame, as the most important take-home message of prioritizing user experience is that hidden functionality might as well be no functionality at all. But as with most of these things---api.drupal.org springs to mind here---the first time is the worst, and once you know what you doing, you, well, know what you're doing.</p>
<p>Panels lets you divide up a page into just those panels. A set of standard URL matches come with Panels as "pages" you can enable, but you can also add new pages at new URLs. In terms familiar to Drupal templaters they take over the $content variable in the page templates, leaving your existing block regions available if you still want them.&#160;So when you enable panels, you get an extra menu item under Site Building called predictably "Panels". This takes you to a dashboard where you can enable or disable panels support for existing URL schemata (e.g. the node URLs at /node/%) and create variants which take into account e.g. the node type, so your blogposts can look different from your events.&#160;</p>
<p>Slightly more subtly, though, if you want to enable panels on an existing view page... you can't. There's no mechanism for overriding the existing view page at e.g. /blog, like you can with a node page, and if you try to create a new panels page at that same URL then the system complains and won't let you do it.&#160;Instead, you have to create a whole new page and eventually discard or at any rate mothball the view's own page. Assuming you have a view at /blog, create a panels page at /blog_new; you can then add the view as a panel pane. You can use any one of the view's configuration variants (default, page, block etc.), not just the standard page variant. When everything looks happy, move your view to /blog_old and your new panels page to /blog.</p>
<p>Drupal also provides taxonomy listings at /taxonomy/term/term-id , which with Pathauto get aliased to /category/vocabulary-name/term-name. If you want to override a taxonomy listing, you <em>can</em>... but again there's a catch. Panels doesn't seem to provide you with any way of replicating the original content as far as I can see, and instead you have to build a view to replace the behaviour of the original taxonomy listing, and then put that into a pane where you'd want the original dumb taxonomy content to go.</p>
<p>When you create the view, you give it a first argument of "term ID". Then, when you add the view to the panel, in the modal lightbox titled "Configure view NAME (Defaults)", under the "Override title" box, you should have a setting where you can choose what to pipe through into your argument. Set that to term ID too.&#160;What you end up with is, as seems to always be the case with Panels, more functional and configurable than before, but it's harder to get to. Not just harder than letting core handle it: that's to be expected. But harder than you'd expect a GUI-rich many-developer-hour content-driven application to be.</p>
<p>Here's a summary of my panels the configuration:</p>
<p style="padding-left: 30px"><strong>Site building &#62; Pages</strong></p>
<p style="padding-left: 30px">&#160;</p>
<ul>
<li><strong>System &#62; node_view </strong>enabled</li>
<li><strong>System &#62; term_view </strong>enabled</li>
<li><strong>Custom &#62; page_blog </strong>created for the blog archives</li>
</ul>
<div><strong>Node template</strong></div>
<div>
<ul>
<li><strong>Node type = blog </strong>and <strong>Node type = page </strong>variants</li>
<li><strong>Two-column </strong>layout</li>
<li><strong>Blog: </strong>node content in right column, with custom module providing tags in left column</li>
</ul>
<div><strong>Taxonomy term template</strong></div>
<div>
<ul>
<li><strong>Two-column layout, </strong>no variants</li>
<li><strong>Term description </strong>pane, then&#160;<strong>&#160;taxonomy-filtering view pane, </strong>with view arguments taken directly from /taxonomy/term system URL</li>
</ul>
<div><strong>Custom view template</strong></div>
<div>
<ul>
<li>At <strong>URL=blog</strong></li>
<li><strong>Paging </strong>configured on view</li>
<li>View has its own&#160;<strong>page </strong>display variant, at another URL, to provide consistent formatting</li>
</ul>
</div>
</div>
<div><strong>CSS</strong></div>
<div>
<ul>
<li><strong>Override </strong>all core column widths: these are a pain (whoever wants 33:34:33 columns?)</li>
<li><strong>Custom CSS classes </strong>on some panels and panes, with custom module to also strip down markup</li>
</ul>
</div>
</div>
<p>&#160;</p>
<p>Overall Panels has made me feel like I have total control over what I want to appear where on my site. But the learning curve is steep and doubtless puts some people off; some of the greatest advantages come from being happy to get your hands dirty with PHP and the plugin architecture too, which I'll cover at a later date, and that's not possible or advisable for most Drupal end users. If I'd not had the luxury of stepping back for a few days every once in a while I'd probably have done it all in templating with regions and blocks. I'm glad I didn't, though, and I'm looking forward to iterating and perfecting my site's use of Panels.</p>

&#60;!--



--&#62;
<div class="trackback-url">
http://www.jpstacey.info/trackback/304</div>]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/11/16/building-pages-in-drupal-with-panels/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oxford Geek Night 15: open government and web marketing</title>
		<link>http://www.jpstacey.info/blog/2009/11/15/oxford-geek-night-15-open-government-and-web-marketing</link>
		<comments>http://www.jpstacey.info/blog/2009/11/15/oxford-geek-night-15-open-government-and-web-marketing#comments</comments>
		<pubDate>Sun, 15 Nov 2009 17:12:45 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[culture]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[marketing]]></category>
		<category><![CDATA[networking]]></category>
		<category><![CDATA[OGN]]></category>
		<category><![CDATA[opengovernment]]></category>
		<category><![CDATA[oxfordgeeknight]]></category>
		<category><![CDATA[oxfordgeeks]]></category>
		<category><![CDATA[rdf]]></category>
		<category><![CDATA[semantic]]></category>
		<category><![CDATA[semweb]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[social]]></category>
		<category><![CDATA[uk]]></category>

		<guid isPermaLink="false">305 at http://www.jpstacey.info</guid>
		<description><![CDATA[<p>OGN15 is in a bit over a week's time, on <a href="http://oxford.geeknights.net/2009/nov-25th/">Wednesday 25 November</a>. It promises to be a great evening as usual, with varied keynote and microslot talks and the usual Oxford(shire) geek chat and networking.</p>
<p>Interestingly, we've ended up with common threads through the two quite different keynote talks. <a href="http://www.io1.biz/">Fintan Galvin</a>, who's talking about the semantic web and its effect on marketing strategies on the web we're more at home with, will be explaining how the former will change the way we think about such priorities as SEO with regard to the latter; along the way he'll be mentioning <a href="http://drupal.org/">Drupal</a>, which is an ideal solution to a whole host of web content problems. Meanwhile, <a href="http://www.jenitennison.com/blog">Jeni Tennison</a> will talk about a new initiative in open UK government, data.gov.uk, which is currently in closed beta and uses a complex stack of technologies including... Drupal and RDF! RDF takes centre stage in the <a href="http://drupal.org/node/443824">forthcoming Drupal 7 release</a>, so more by luck than judgment our common topic is a pretty hot one.</p>
<p>Of course there's microslots and the Pitch too---contact me if you want to volunteer for the sixty-second open-mic Pitch, as we've still got some spare slots---and we've got sponsorship to make sure the whole evening is not just free as in beer, but free as in... other beverages that are available. The <a href="http://www.guardian.co.uk/open-platform">Guardian Open Platform</a> are sponsoring drinks again, and <a href="http://apress.com/">Apress</a> have promised us some books for the book raffle. <a href="http://torchbox.com">Torchbox</a> is as usual very kindly sponsoring my time, venue costs and infrastructure for the night. Thanks to all our sponsors for their generosity.</p>
<p>Almost everything is in place, which means I might get away with a few days off before the night, but I promise to turn up on the 25th fit and rested. Assuming I'm not still stranded in Birmingham New Street. But then how likely is that, really?</p>

&#60;!--



--&#62;
<div class="trackback-url">
http://www.jpstacey.info/trackback/305</div>]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/11/15/oxford-geek-night-15-open-government-and-web-marketing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Who is Drupal&#8217;s target audience?</title>
		<link>http://feedproxy.google.com/~r/polytechnic/~3/wtf43ZD5pUI/who_is_drupals_target_audience</link>
		<comments>http://feedproxy.google.com/~r/polytechnic/~3/wtf43ZD5pUI/who_is_drupals_target_audience#comments</comments>
		<pubDate>Tue, 13 Oct 2009 09:06:37 +0000</pubDate>
		<dc:creator>garrett</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[world wide web]]></category>

		<guid isPermaLink="false">738 at http://polytechnic.co.uk</guid>
		<description><![CDATA[Leisa Reichelt reflects on what Mark Boulton and herself learnt during the D7UX project this summer, and puts her finger on a big issue facing the Drupal community going forward: who is the target audience?

And so we have this tension. Drupal as a ‘...]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/10/13/who-is-drupals-target-audience/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Playing with card sorting</title>
		<link>http://www.jpstacey.info/blog/2009/10/09/playing-card-sorting</link>
		<comments>http://www.jpstacey.info/blog/2009/10/09/playing-card-sorting#comments</comments>
		<pubDate>Fri, 09 Oct 2009 20:16:58 +0000</pubDate>
		<dc:creator>jp.stacey</dc:creator>
				<category><![CDATA[geek]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[cardsorting]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[ia]]></category>
		<category><![CDATA[information]]></category>
		<category><![CDATA[projects]]></category>

		<guid isPermaLink="false">299 at http://www.jpstacey.info</guid>
		<description><![CDATA[<p>If you want your website navigation to reflect the way that users might find your content, you obviously want it to serve their use cases and the terminology they're comfortable with. Ideally you'd do this by asking sample users to build your navigation for you, but in the absence of any willing volunteers one of the best things a site owner can do is <a href="http://www.boxesandarrows.com/view/card_sorting_a_definitive_guide">card sorting</a>.</p>
<p>It sounds pretty simple. Take the resources you want people to navigate around---so generally the furthermost leaves of your navigation tree: rich content pages, applications and the like rather than section indexes, which might contain navigational preconceptions---and try to assemble them into groups. Pretend they're written on cards---or, in a more agile way, actually write them on cards and shuffle them round a table---and try to assemble piles of similar resources. Closed card sorting involves predefining the groups, and is ideal for arranging new elements in an existing navigation and a good compromise for building a new navigation quickly; open card sorting is the same, but with no predefined groups. The results are better but it takes longer.</p>
<p>Card sorting really helps site maintainers escape preconceptions and build a navigational hierarchy that makes sense. So although it seems like overkill, this is actually what I have just done for this website. As with much that I'm currently doing towards the site rebuild, it's intended as a learning experience; a voyage of discovery, albeit taken on a Tonka truck within the safe confines of the wee sandbox that's my personal site.</p>
<p>My first pass yielded around fifteen resources---rather fuzzily defined, but including varied things like "my blog" and "a link to my Twitter feed"---which I wanted people to be able to navigate around. I arranged these in a single-parent hierarchy beneath six main headings: ongoing, literature, coding, academia and portfolio. However, this felt a bit forced (and some sections, especially "academia", are mostly opportunities for old documents to gather dust. I tried to imagine adding a more freeform vocabulary that cut across a lot of this, something like tagging, but there was something wrong.</p>
<p>Unsatisfied, I completely scrapped the single hierarchy and tried again. This time the list of resources had expanded to more like twenty, and I went for a more radical approach to grouping. Instead of trying to group objects as cards in a pile, so each card could only be in one pile, I tried to imagine from the start what groups <em>plural </em>they might fit into. Although I was still thinking in terms of menus, the parent terms were now more like categories from a taxonomy, with any menu item being available from several categories.</p>
<p>This resulted in seven terms:</p>
<p style="text-align: center">tech, content, social, lit(erature), work, love and misc</p>
<p style="text-align: left">This blog, for example, could fit under "tech", "content" and maybe "work", and would be accessible from all those places. My attempts at creative writing on <a href="http://quietlittlelies.com/">Quiet little Lies</a> could go under "content", "literature" and possibly "love".</p>
<p style="text-align: left">As long as the number of objects didn't get too long (and objects didn't spread under too many terms) then these seven terms could still make sense to the user as a starting point, even if they found different things in multiple places. In fact, in the brave new world of folksonomies and tags, web users might be getting used to less hierarchical ways of navigating, so this might even pay off.</p>
<p style="text-align: left">Drupal's menu system supports multiple or mixed hierarchies out of the box, but I preferred instead to actually use categories, and tie these to a menu with the <a href="http://drupal.org/project/taxonomy_menu">Taxonomy Menu module</a>. I might not follow that route in future, as it essentially only supports linking to Drupal's out-of-the-box category index pages, with content sorted in reverse date order, whereas I'l almost certainly want to do something nicer. But like card sorting itself it was a good springboard to getting things working and feeling happy with progress.</p>
<p style="text-align: left">For now the hierarchy is implemented with dummy content, but I hope to fill it out more---and then expose the navigation---in the next few days. Right now it's just nice to see things starting to come together. Also, having seven top-level terms fits in rather neatly with the design decisions I've already made: more on those later.</p>

&#60;!--



--&#62;
<div class="trackback-url">
http://www.jpstacey.info/trackback/299</div>]]></description>
		<wfw:commentRss>http://oxfordbloggers.com/2009/10/09/playing-with-card-sorting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
