<?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>Alistair Robinson, Web Development &#38;c &#187; web development</title>
	<atom:link href="http://alistairrobinson.co.uk/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://alistairrobinson.co.uk</link>
	<description></description>
	<lastBuildDate>Sat, 28 Jan 2012 12:11:30 +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>Goodbye and Good Riddance to Word Processors: A Better Way To Write Proposals</title>
		<link>http://alistairrobinson.co.uk/goodbye-and-good-riddance-to-wysiwyg-and-word-processors/</link>
		<comments>http://alistairrobinson.co.uk/goodbye-and-good-riddance-to-wysiwyg-and-word-processors/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 02:45:13 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[Productivity]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[markup]]></category>
		<category><![CDATA[pandoc]]></category>
		<category><![CDATA[pisa]]></category>
		<category><![CDATA[textile]]></category>
		<category><![CDATA[word processors]]></category>
		<category><![CDATA[writing]]></category>
		<category><![CDATA[wysiwyg]]></category>
		<category><![CDATA[xhtml2pdf]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=991</guid>
		<description><![CDATA[A few days ago I tweeted: &#8220;Writing a proposal. Oh boy do I hate word processors. There must be a better way.&#8221; It turns out there is, though I ended up forging my own path to suit my skills and working methods. A little background&#8230; I need to produce decent looking proposals for web development [...]]]></description>
			<content:encoded><![CDATA[	<p>A few days ago I tweeted:</p>

	<p>&#8220;Writing a proposal. Oh boy do I hate word processors. There must be a better way.&#8221;</p>

	<p>It turns out there is, though I ended up forging my own path to suit my skills and working methods. A little background&#8230;</p>

	<p>I need to produce decent looking proposals for web development projects. Normally I bite the bullet and suffer the awkwardness of Word or OpenOffice or LibreOffice or something, and then export to <span class="caps">PDF</span>. It&#8217;s all very clever: it took some great minds to produce this software. But it really goes against the grain. It feels so wrong.</p>

	<p>I like plain old <strong>text</strong>, and as a web developer I&#8217;m used to defining the style of documents by hand, in <span class="caps">CSS</span>, rather than using another program to do it for me, <em>as I write</em>. I would go further and claim that this is not just a matter of personal taste: <em>word processors are bad for the world</em>. Sure, people are used to them, and they cannot imagine a better way, and &#8211; most importantly &#8211; there is probably no equally mature, friendly, well-supported and funded software in place to allow for a move away from them as things stand. But it does not follow from this that they are good.</p>

	<h3>What&#8217;s Wrong With Word Processing?</h3>

	<p>The name, to start with. But most of all <strong><span class="caps">WYSIWYG</span></strong>. One thing I&#8217;ve learned from web development is the importance of respecting the logical separation of style and content. <span class="caps">WYSIWYG</span> is not so respectful. Everything happens in the same place and at the same time. Effectively, documents are typeset as you go, character by character. This is silly.</p>

	<p>Formatting your document&#8217;s style has nothing to do with its content. What you are trying to say is a different concern from how it should look. And I do not mean that the two human operations are more conveniently handled by separate software operations. I mean that they are different <em>human</em>, <em>conceptual</em>, <em>natural</em> concerns. Of course it has to look good (although a. it <em>doesn&#8217;t</em> always have to, and b. even plain text looks way better than a clipartified Word document). Yes, of course your document has to conform to a company standard, or your own standard, and how it looks might be partly what you intend to convey. But all this precisely means that these standards and styles ought to be defined separately, beforehand, leaving you to get on with the writing: to concentrate on what it is you have to say. It is the difference between talking to somebody at a party and deciding what you are going to wear to that party.</p>

	<p>Using <span class="caps">WYSIWYG</span> software such as the horribly feature-rich <em>Word</em> is like going to a party with several changes of clothes and proceeding to change them every time you think that what you&#8217;re saying doesn&#8217;t go with stripes. Sure, do the best you can to look good, but <em>prepare</em> for that, by going shopping, trimming your beard, and putting on your best Y-fronts. After all that&#8217;s done you can get on with talking to people and getting drunk, safe in the knowledge that you&#8217;re looking great. Underdressed? Well, if you didn&#8217;t care enough to prepare, to research, and to tune your attire accordingly, then you shouldn&#8217;t care about being underdressed.</p>

	<p>Now, moving on from that straining analogy, the biggest benefit of separating style and content is that content becomes <em>independent</em> of how it is presented. If standards of presentation change, or a piece of writing needs to be reproduced in different formats, or you&#8217;ve finally got tired of Comic Sans, then you shouldn&#8217;t be going anywhere near your content to achieve the desired formatting changes. But word processors force you to do this. You actually have to open and edit your document, just to re-style it. This wrongheadedness has been spectacular in its worldwide detrimental impact.</p>

	<p>(Note that I&#8217;m quite ignorant of Word and the no-doubt very sophisticated setups that can be achieved in organizations where stanadardized presentation is important. For all I know maybe you <em>don&#8217;t</em> always have to go back and edit your document or re-assign a template of whatever. However, achieving this is just a workaround, and likely would not have a perfect success rate; it seems clear that the default expectation of the software is that you do mix up content and presentation.)</p>

	<p>And faced with the option, the <em>expectation</em>, to fiddle about with fonts and bullets, it takes discipline, imposed from above or by yourself, to beat down that natural inclination. This is not a matter of freedom. In my case, I have to struggle with formatting issues almost every time I write &#8211; or rather, <em>process</em> &#8211; one of these documents, because I might be using different word processors on different platforms with different fonts or whatever. This should not even be an issue, because we already <em>know</em>, deep down, that style and content are logically separate categories (note that this does not mean that they do not sometimes overlap). And in a company environment, standard templates for Word and detailed strictures and guidelines from management on formatting, fonts and colours, are awkward and only partly successful workarounds for a problem that would not exist without <span class="caps">WYSIWYG</span>.</p>

	<p>The writer of a document has expertise in the subject addressed by that document. They may not have expertise in typography and layout, and usually they do not. The latter, then, becomes nothing but a distraction and a huge waste of time. And &#8230; I didn&#8217;t ask you to send me a bloody Word attachment in the first place!</p>

	<p>The natural paradigm for me, which I get from web development, is to write stuff in a text file, and to define how it looks in another text file, and <em>only then</em> to view how it will look to the document&#8217;s recipient. I believe this should go for print documents as well as <span class="caps">HTML</span> web pages.</p>

	<p>It is already the way of things in printing, publishing and professional writing. I don&#8217;t believe Proust was worrying about typefaces when he painstakingly described the memory of a hawthorn bloom, and the prevalence of Word has not made this any less true of professional writers today. Why should any writer, or anyone who becomes a writer for brief periods &#8211; whether of poems or proposal documents or annual reports &#8211; have to worry about such things? Why has the division of labour, both human and machine, which is so thoroughly advanced in the modern world, been bypassed in this case?</p>

	<h3>Lightweight Markup</h3>

	<p>A few years ago I discovered <a href="http://thresholdstate.com/articles/4312/the-textile-reference-manual">Textile</a>, which is a lightweight markup language. What a Godsend. I can get on with <em>writing</em>:</p>

<div class="codecolorer-container text blackboard" style="border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">h1. This is The Main Heading<br />
<br />
For a long time I used to go to bed early. Sometimes, when I had put out my candle, my eyes would close so quickly that I had not even time to say &quot;I'm going to sleep.&quot; And half an hour later the thought that it was time to go to sleep would awaken me; I would try to put away the book which, I imagined, was still in my hands, and to blow out the light; I had been thinking all the time, while I was asleep, of what I had just been reading, but my thoughts had run into a channel of their own, until I myself seemed actually to have become the subject of my book: a church, a quartet, the rivalry between François I and Charles V. This impression would persist for some moments after I was awake; it did not disturb my mind, but it lay like scales upon my eyes and prevented them from registering the fact that the candle was no longer burning. Then it would begin to seem unintelligible, as the thoughts of a former existence must be to a reincarnate spirit; the subject of my book would separate itself from me, leaving me free to choose whether I would form part of it or no; and at the same time my sight would return and I would be astonished to find myself in a state of darkness, pleasant and restful enough for the eyes, and even more, perhaps, for my mind, to which it appeared incomprehensible, without a cause, a matter dark indeed.<br />
<br />
h2. This is a Secondary Heading<br />
<br />
Furthermore, each one of the following is an item in an unordered list:<br />
<br />
* Something<br />
* Something else<br />
* And another thing<br />
<br />
As Oscar Wilde &quot;once said&quot;:http://upword.com/wilde/dorgrayp.html,<br />
<br />
bq. No artist desires to prove anything. Even things that are true can be proved. No artist has ethical sympathies. An ethical sympathy in an artist is an unpardonable mannerism of style. No artist is ever morbid. The artist can express everything.<br />
<br />
Now for some Latin. Lorem ipsum dolor sit amet, duo id viris posidonium signiferumque. Maluisset patrioque vis ad, eruditi imperdiet ex pro. At eirmod luptatum expetenda mei, vel impetus meliore oporteat ex, case postea vivendo per eu. Enim prima ridens an mel. Ne has clita scripserit, eam eu veri mundi dissentiet. Eros torquatos sed cu.</div></div>

	<p>All in a <em>text editor</em>. You know, like Notepad only with nice colours and productivity tools. There&#8217;s nothing and nobody messing around <em>processing</em> what I write. Processing comes later, based on separate settings that I have set up for the scenario.</p>

	<h3>My Great Solution Which, Though Great, Could Most Probably Be Vastly Improved Upon</h3>

	<p>Up till now I&#8217;ve only really used Textile to generate <span class="caps">HTML</span> for display on web sites, usually blog posts, but now that I&#8217;ve (mostly) moved away from Windows and on to Linux, manipulating text becomes all the more easy. I&#8217;ve created a nice wee setup to generate <span class="caps">PDF</span> documents styled with <span class="caps">CSS</span> straight from a Textile file. I should stress that this involves the terminal and bash scripts, so it&#8217;s probably for geeks only.</p>

	<p>The upshot is that when I want to write a proposal, I just run a couple of commands to set up a proposal project based on a template, and then get down to writing my document in Textile, and when I want to see what it&#8217;ll look like I just run ~/gopdf.sh, which generates a <span class="caps">PDF</span>.</p>

	<p>The gopdf.sh bash script does three things in order:</p>

	<p>A. Generates an <span class="caps">HTML</span> file from the textile file using pandoc<br />
B. Generates a <span class="caps">PDF</span> from the <span class="caps">HTML</span> file using xhtml2pdf<br />
C. Opens the <span class="caps">PDF</span></p>

	<p><img src="http://alistairrobinson.co.uk/wp-content/uploads/2012/01/Screenshot-at-2012-01-24-092801.png" alt="pdf screenshot" title="Screenshot at 2012-01-24 09:28:01" width="600" height="543" class="alignleft size-full wp-image-994" /></p>

	<p>(If I had actually got to the stage where I&#8217;ve built up a nice <span class="caps">PDF</span> stylesheet I would have shown you something more fancy, but there you go. And the sharp-eyed among you will notice that the line of text immediately following the list is squashed up to it. This might be a problem with pandoc&#8217;s understanding of textile, which is not perfect, favouring the alternative Markdown as it does. You can include <span class="caps">HTML</span> in among the Textile markup, so a line break here is easy to achieve, or else a <span class="caps">CSS</span> bottom margin would probably do it, and would probably be the better choice.)</p>

	<h3>What it Allows Me to Do</h3>

	<p>Before I describe how I make all this possible, here in more detail is what I now do every time I get a new client who wants a proposal.</p>

	<p><strong>One</strong></p>

	<p>So I meet with Bob of Bob&#8217;s Cake Company fame, and he tells me he wants a cake web app. I say sure, no problem, then I go home, start up Linux and create a folder called bobs_cake_company, and cd into it. Then&#8230;</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~/startdoc.sh proposal</div></div>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">subl .</div></div>

	<p>The first command copies over my standard proposal template folder to bobs_cake_company as a sub-folder called &#8220;proposal&#8221;. The second one just opens the current folder, bobs_cake_company, in <a href="http://www.sublimetext.com/2">Sublime Text 2</a> (I seem to remember doing some things to get that &#8220;subl&#8221; command working, but I&#8217;m not sure what. Probably just a symlink.)</p>

	<p><strong>Two</strong></p>

	<p>I write the document in the file that is there waiting for me, proposal.textile. Remember, by writing I just mean writing. Not fiddling with margins or choosing bullets or struggling with alignment issues or fixing pasted text or making sure that the screenshot isn&#8217;t blurry or anything else like that.</p>

	<p><strong>Three</strong></p>

	<p>In the terminal&#8230;</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">compass watch</div></div>

	<p>This generates a stylesheet from the <span class="caps">SASS</span> files in which I define the <span class="caps">CSS</span> stylings. Full disclosure: currently my method is in its early stages so I don&#8217;t yet have a good standard <span class="caps">CSS</span> stylesheet for <span class="caps">PDF</span>s. I&#8217;ll be building this as I go along for a project or two before I can just leave it alone. So right now I&#8217;m actually running this Compass watcher when I begin writing, because I&#8217;m styling as I go, like a human word processor. Not for long.</p>

	<p><strong>Four</strong></p>

	<p>Then in the terminal (in a new tab):</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~/gopdf.sh proposal</div></div>

	<p>This creates a <span class="caps">PDF</span> (or overwrites the one that already exists), and then opens it in the default <span class="caps">PDF</span> viewer. Thereafter I just run &#8220;~/gopdf.sh proposal&#8221; whenever I want to see my changes in the <span class="caps">PDF</span>.</p>

	<p><strong>Five</strong></p>

	<p>Send proposal to client and have a cigarette.</p>

	<h3>Making it All Possible</h3>

	<p>The process I&#8217;ve just described depends on a few pre-existing elements:</p>

	<ul>
		<li>pandoc</li>
		<li>xhtmlpdf</li>
		<li>startdoc.sh bash script</li>
		<li>gopdf.sh bash script</li>
		<li>a proposal_template folder with goodies in it</li>
		<li>Compass (optional)</li>
		<li>Sublime Text 2 (optional)</li>
		<li>A dangerous, expensive and anti-social nicotine addiction (optional)</li>
	</ul>

	<p>You do the following stuff once only.</p>

	<p><strong>Get pandoc</strong>: <a href="http://johnmacfarlane.net/pandoc/">Pandoc</a> is a Haskell library that converts between lots of different kinds of documents. I would have used it alone had it been able to convert Textile and <span class="caps">CSS</span> to <span class="caps">PDF</span> directly. (I couldn&#8217;t make it work and concluded that pandoc couldn&#8217;t do it, but I could be wrong.)</p>

	<p><a href="http://johnmacfarlane.net/pandoc/installing.html">Installation instructions are here</a></p>

	<p><strong>Get xhtml2pdf</strong>: <a href="http://www.xhtml2pdf.com/">xhtml2pdf</a> is a python package that generates <span class="caps">PDF</span> files from <span class="caps">HTML</span> and <span class="caps">CSS</span>. It can be installed with easy_install or pip and also available to download <a href="http://pypi.python.org/pypi/xhtml2pdf/#downloads">here</a></p>

	<p><strong>If you are so inclined, get Compass</strong>: <a href="http://compass-style.org/">Compass</a> is a <span class="caps">CSS</span> authoring framework built on Ruby and <a href="http://sass-lang.com/"><span class="caps">SASS</span></a>. You write in <span class="caps">SASS</span> and Compass generates <span class="caps">CSS</span> files for you. The latter are what you actually run on the server. I&#8217;ve been using it for a year or so and I love it. One of the reasons I like it is just because I can avoid the curly braces and semi-colons of <span class="caps">CSS</span> itself. I&#8217;m addicted to significant whitespace. (Though it&#8217;s worth noting that they&#8217;ve been going after designers and have opted to make their <span class="caps">SCSS</span> syntax the default because <span class="caps">SASS</span> looks too much like programming).</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">gem install compass</div></div>

	<p>More details on installing Compass <a href="http://compass-style.org/install/">here</a></p>

	<p><strong>If you need a great text editor, get Sublime Text 2</strong>:It&#8217;s all the rage, and for good reason. <a href="http://www.sublimetext.com/2">Get it here</a></p>

	<p><strong>Create startdoc.sh</strong>:</p>

<div class="codecolorer-container bash blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #666666; font-style: italic;">#!/bin/bash</span><br />
<br />
<span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-r</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>alistair<span style="color: #000000; font-weight: bold;">/</span>projects<span style="color: #000000; font-weight: bold;">/</span>proposal_template <span style="color: #007800;">$PWD</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$1</span><br />
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$1</span><br />
<span style="color: #c20cb9; font-weight: bold;">mv</span> proposal.textile <span style="color: #007800;">$1</span>.textile</div></div>

	<p>This copies the proposal template folder, renames it depending on your argument, and also renames the .textile file.</p>

	<p><strong>Create gopdf.sh</strong>:</p>

<div class="codecolorer-container bash blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">#!/bin/bash</span><br />
<br />
pandoc <span style="color: #660033;">--email-obfuscation</span>=none <span style="color: #660033;">-s</span> <span style="color: #660033;">-S</span> <span style="color: #660033;">-c</span> stylesheets<span style="color: #000000; font-weight: bold;">/</span>print.css <span style="color: #007800;">$1</span>.textile <span style="color: #660033;">-o</span> <span style="color: #007800;">$1</span>.html <span style="color: #660033;">-s</span> <span style="color: #660033;">-S</span> <span style="color: #660033;">-c</span> stylesheets<span style="color: #000000; font-weight: bold;">/</span>print.css <span style="color: #007800;">$1</span>.textile <span style="color: #660033;">-o</span> <span style="color: #007800;">$1</span>.html<br />
python makepdf.py <span style="color: #007800;">$1</span>.html <span style="color: #007800;">$1</span>.pdf<br />
gnome-open <span style="color: #007800;">$1</span>.pdf</div></div>

	<p>This is where the action happens. It runs pandoc to convert from Textile to <span class="caps">HTML</span> &#8211; along with print.css &#8211; and then runs makepdf.py (which in turn runs xhtml2pdf, as we shall see) to take <strong>proposal.html</strong> and generate <strong>proposal.pdf</strong>.</p>

	<p><strong>Create the proposal_template folder</strong></p>

	<p>We need to create a standard proposal template that will thereafter be copied over to a new project any time you run ~/startdoc.sh. It consists of a folder structure which looks like this:</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">proposal_template<br />
&nbsp; &nbsp;|-documentation<br />
&nbsp; &nbsp;|-images<br />
&nbsp; &nbsp;|-sass<br />
&nbsp; &nbsp; &nbsp;---print.sass<br />
&nbsp; &nbsp;|-stylesheets<br />
&nbsp; &nbsp;|---fonts<br />
&nbsp; &nbsp;config.rb<br />
&nbsp; &nbsp;makepdf.py<br />
&nbsp; &nbsp;proposal.textile</div></div>

	<p>The folder <strong>sass</strong> contains the Compass <span class="caps">SASS</span> file; <strong>stylesheets</strong> contains the <span class="caps">CSS</span> that is produces from the <span class="caps">SASS</span>, namely print.css; <strong>config.rb</strong> is the Compass config file; and <strong>makepdf.py</strong> runs xhtml2pdf, but is itself executed by the <strong>gopdf.sh</strong> bash script. The folder <strong>fonts</strong> contains font-files that can be included in the <span class="caps">PDF</span> by using @font-face in the stylesheet.</p>

	<p>Once all this is copied over by startdoc.sh, <strong>proposal.textile</strong> is where all the writing happens.</p>

	<p>The Python script, <strong>makepdf.py</strong>, looks like this:</p>

<div class="codecolorer-container python blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> xhtml2pdf <span style="color: #ff7700;font-weight:bold;">import</span> pisa<br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><br />
<br />
pdf <span style="color: #66cc66;">=</span> pisa.<span style="color: black;">CreatePDF</span><span style="color: black;">&#40;</span><br />
&nbsp; <span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;r&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;wb&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: black;">&#41;</span><br />
<br />
pdf.<span style="color: black;">dest</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div>

	<p>This is called in <strong>gopdf.sh</strong>, specifically this line:</p>

<div class="codecolorer-container bash blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">python makepdf.py <span style="color: #007800;">$1</span>.html <span style="color: #007800;">$1</span>.pdf</div></div>

	<p>So running <strong>~/gopdf.sh proposal</strong> will get pisa to take proposal.html and generate proposal.pdf. Pisa, by the way, is the original name &#8211; or central core &#8211; of xhtml2pdf.</p>

	<p>In the near future I hope to fill the standard print.css with lots of proposal-specific stylings, and proposal.textile will probably contain my standard section headings and table of contents.</p>

	<p>By the way, when creating the standard template, the Compass stuff can be set up automatically by running the following command.</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">compass create --syntax sass</div></div>

	<p>(If you like the <span class="caps">SASS</span> syntax, that is)</p>

	<h3>WordPress</h3>

	<p>I&#8217;m writing this in Textile right now, but it struck me that I only had a WordPress blog to post it to. I can use Textile for my <a href="http://critique-of-pure-reason.com">philosophy blog</a>, because I built the engine myself in Django, but I hadn&#8217;t got far in the past trying to get Textile working in WordPress. Thankfully, Veeti Paananen has provided a plugin, <a href="https://github.com/rojekti/Simple-Textile/">Simple-Textile</a> which seems to work nicely.</p>

	<p>It&#8217;s really time to move this blog, and a redesign is probably overdue.</p>

	<h3>Afterthoughts</h3>

	<p>If you&#8217;re not a coder, but you&#8217;re an author or just do a lot of writing, and you don&#8217;t have to worry too much about making your words look good enough for Bob of Bob&#8217;s Cake Company to print out &#8212; but you do want a nice, pleasing, peaceful, distraction-free writing environment, then there are some nice minimalist editors out there at the moment, such as <a href="http://www.ommwriter.com/">OmmWriter</a> and <a href="http://www.hogbaysoftware.com/products/writeroom">WriteRoom</a>.</p>

	<p>I get basically the same thing in Sublime Text when I put it in &#8220;distraction-free mode&#8221;, so my programming and web design editor also functions as a nice place to write about <a href="http://critique-of-pure-reason.com">Wittgenstein, Heidegger, Karl Marx and the evils of traffic control</a>.</p>

	<p>But when it comes to writing something big or complex like a book or a thesis, folks sometimes opt for specialist software, such as editors that revolve around the <a href="http://www.latex-project.org/intro.html">LaTex</a> typsetting markup system. These are usually built on the same paradigm that I&#8217;ve been describing, namely the separation of style and content, which is especially important with documents primarily intended for professional print publishing. Word processors are strictly for home and office use, and I imagine those in the world of printing never touch them with a bargepole. It must be galling that word processors are these days thought to be the last word in setting and styling type, because while they have cast that noble profession into obscurity &#8211; though certainly not into obsolescence &#8211; their own ability to do it well is tragically lacking. Next time you&#8217;re in a print shop ask them what they think of Microsoft Word, so long as you don&#8217;t find anti-Microsoft rants boring.</p>

	<p>Thanks to all of the wonderful and generous programmers out there without whom I would likely still be shouting at Word like a madman.</p>

	<h3>Further Reading</h3>

	<p>I&#8217;m not the only one, you know.</p>

	<p><a href="http://www.mymac.com/2004/01/why-do-i-hate-word-processors/">Why Do I Hate Word Processors?</a><br />
<a href="http://ricardo.ecn.wfu.edu/~cottrell/wp.html">Word Processors: Stupid and Inefficient</a><br />
<a href="http://www.conradiator.com/downloads/pdf/WhatHasWYSIWYG_done2us.pdf">What has <span class="caps">WYSIWYG</span> done to us?</a></p>]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/goodbye-and-good-riddance-to-wysiwyg-and-word-processors/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The WordPress White Screen of Death</title>
		<link>http://alistairrobinson.co.uk/the-wordpress-white-screen-of-death/</link>
		<comments>http://alistairrobinson.co.uk/the-wordpress-white-screen-of-death/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 13:05:58 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=988</guid>
		<description><![CDATA[This is the kind of thing that happens out of nowhere when you&#8217;re in the middle of finishing off something simple, and sends you into a rage shouting &#8220;What the fucking hell&#8230;this is just bizarre!&#8221; and so on, until you finally fix it by fiddling about intuitively, and then just move on. For once, professional [...]]]></description>
			<content:encoded><![CDATA[<p>This is the kind of thing that happens out of nowhere when you&#8217;re in the middle of finishing off something simple, and sends you into a rage shouting &#8220;What the fucking hell&#8230;this is just <em>bizarre!</em>&#8221; and so on, until you finally fix it by fiddling about intuitively, and then just move on. For once, professional discipline compels me to record the problem and its solution, partly for my own benefit but also to help others avoid the drastic solutions offered in several places on the web.</p>
<p>After working primarily in Django for the last while I had to do some WordPress work yesterday, implementing SEO improvements to one of our e-commerce client&#8217;s web site. I added a function to functions.php and got everything working nicely, but then I went to /wp-admin only to find a blank screen, with no error messages. Neither could I find anything in the server error logs. I could get to /wp-login.php and seemingly log in succesfilly, but then the same thing would happen &#8211; I couldn&#8217;t get in to the back end, even though the public site was working just fine.</p>
<p>Most of the proposed and unsurprisingly successful fixes I found in blogs and on the WordPress support forums involved re-installing WordPress, but one suggestion stood out: <strong>delete any blank lines at the end of your functions.php file</strong>. I&#8217;m in the habit of adding extra lines at the bottom of a file to give me more space to work in my text editor, so this looked promising. And it worked.</p>
<p>I don&#8217;t know why.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/the-wordpress-white-screen-of-death/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enlightenment Bullshit</title>
		<link>http://alistairrobinson.co.uk/enlightenment/</link>
		<comments>http://alistairrobinson.co.uk/enlightenment/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 01:17:07 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[descartes]]></category>
		<category><![CDATA[philosophy]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=981</guid>
		<description><![CDATA[I&#8217;m in the middle of a large Django project, my first one using the framework. It&#8217;s bloody wonderful, it really is. I don&#8217;t understand why Django developers aren&#8217;t going on about it more &#8211; about how lovely it is to work with. Developing web sites in Django is a beauty-full experience. I didn&#8217;t know it [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in the middle of a large <a href="http://en.wikipedia.org/wiki/Django_(web_framework)">Django</a> project, my first one using the framework. It&#8217;s bloody wonderful, it really is. I don&#8217;t understand why Django developers aren&#8217;t going on about it more &#8211; about how <em>lovely</em> it is to work with. Developing web sites in Django is a <em>beauty-full</em> experience. I didn&#8217;t know it could be like this. I don&#8217;t know what it&#8217;s like to find Enlightenment in the way the Buddha talks about it, and I don&#8217;t even really know what it&#8217;s like to meditate, but this approaches what I imagine they mean.</p>
<h3>Pony-Powered Enlightenment Bullshit</h3>
<p>This sounds like bullshit, of course, and I confess I&#8217;m spinning this out more than is warranted, but there is an immense calm, neatness and harmony about developing with Django. Everything&#8217;s at <em>just</em> the right level; everything fits together in <em>just </em> the right way. Everything&#8217;s in the right place, everything&#8217;s in nice little pieces that fit together like a jigsaw.</p>
<p>You know when you read a textbook and you get the feeling that the author knows exactly what you&#8217;ll have trouble with? Or a teacher who always seems to be able to anticipate your difficulties. Well that&#8217;s what it&#8217;s like to work in Django. There have been countless occasions where I have exclaimed, after a bit of struggling, &#8220;oh, you mean I can just do this!&#8221; Just where you need it to be, it&#8217;s all done for you. You know the bits I mean: the tedious shit. The painful repeated Ctrl-C Ctrl-V crap that you go through every time you do a form.</p>
<p>Django is high-level, <em>but in a low-level way</em>. There&#8217;s no fucking about with shitty interfaces, arcane meta-languages and strange customs, just to put a website up that has editable content; there&#8217;s none of the horrible <em>mess</em> of PHP; there&#8217;s no need to download three thousand PHP files and work with a horribly complex interface just to set up a <em>wee blog for God&#8217;s sake</em>. With Django, you build things up yourself, in just the way you want. If you think this sounds like a lot of work, it&#8217;s not &#8211; it&#8217;s way <em>less</em> work, because Django knows roughly the kind of things you&#8217;ll be doing. </p>
<p>I confess that I never got around to trying a <em>PHP</em> MVC framework. No doubt all this great stuff I&#8217;m talking about is largely owing to the general MVC pattern, rather than to Django itself &#8211; but I&#8217;m not so sure. Django&#8217;s helper classes, such as forms, make the <em>whole</em> web development experience fun. Anyway, it&#8217;s so much nicer to write in Python.</p>
<h3>Demon-Driven Enlightenment Bullshit</h3>
<p><img src="http://static.jamalrob.webfactional.com/images/alistairrobinson.co.uk/screenshot_critique_big.png" alt="critique-of-pure-reason.com" /></p>
<p>(This section doesn&#8217;t have much bullshit in it actually, but I couldn&#8217;t stand to leave the first two titles unbalanced.)</p>
<p>I&#8217;ve been blogging over at my philosophy blog, <a href="http://critique-of-pure-reason.com/">critique-of-pure-reason.com</a>, which is why this is the first post here for a long &#8211; shit, it&#8217;s October already! That blog and the studies from whence its content sprouts have been taking up a lot of my time. Right now I&#8217;m studying scepticism, in particular Descartes, who <a href="http://en.wikipedia.org/wiki/Meditations_on_First_Philosophy">suggested</a> that for all I know I might be dreaming at this moment, or I might be the victim of a malicious deceiver demon who is creating all of my perceptions for me; so I cannot take my perceptions for what they seem to be, and so I have no ground for the belief that I am sitting at my computer writing; even though I bloody well <em>know </em> I&#8217;m not dreaming.</p>
<p>Now, you would think that &#8220;I bloody well <em>know</em> I&#8217;m not dreaming&#8221; would be absolutely inadmissable in philosophy, but most answers to Descartes seem to be saying something similar, especially those from Moore and Wittgenstein. Anyway, that&#8217;s enough of that. This is neither the time nor the place. <a href="http://critique-of-pure-reason.com/"><em>This</em> is the place if you&#8217;re interested</a>. I did the blog engine from scratch in Django, by the way. Have I mentioned how much I like Django? Come to think of it though, the site&#8217;s sadly lacking in navigation, categories, tags and all that. Well, I did it over a single weekend so what do you expect?</p>
<p>So I&#8217;ve been staying up till all hours poring over philosophical papers from the journal <em>Mind</em>, just trying to prove that I&#8217;m not dreaming. It&#8217;s not as fruitless as it sounds though: mountains and valleys of thought are appearing from over the horizon. I&#8217;m moving ever nearer, exploring the foothills on my way to the dizzy precipices of [insert more bullshit here].</p>
<h3>Not Enough Hours</h3>
<p>And that&#8217;s not to mention all the music: saxophone, piano, theory and composition. And the maths. I&#8217;m working through a book of undergraduate mathematics, and Euclid&#8217;s Elements &#8211; oh and I&#8217;m half-way through a textbook on logic. Am I insane? Is this whole paragraph a cliché? I think it is you know. Fuck.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/enlightenment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS Abstracted: Update</title>
		<link>http://alistairrobinson.co.uk/css-abstracted-update/</link>
		<comments>http://alistairrobinson.co.uk/css-abstracted-update/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 22:13:33 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[compilers]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[pre-processor]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[sass]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=930</guid>
		<description><![CDATA[In a recent post I described my first foray into&#8230;well now, what am I supposed to call them? CSS frameworks? No, that doesn&#8217;t work, because Blueprint and YUI and 960 and others are often described as such. CSS meta-frameworks? That appeals to me, but it&#8217;s rather obscure. CSS compilers? Yes, perhaps. But wait. There are [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://alistairrobinson.co.uk/css-abstracted/">recent post</a> I described my first foray into&#8230;well now, what am I supposed to call them? CSS frameworks? No, that doesn&#8217;t work, because Blueprint and YUI and 960 and others are often described as such. CSS meta-frameworks? That appeals to me, but it&#8217;s rather obscure. CSS compilers? Yes, perhaps.</p>
<p>But wait. There are CSS compilers, and then there are the libraries and frameworks and plugins that are built around them. Well, I guess that&#8217;s where the term &#8220;meta-framework&#8221; comes in.</p>
<p>One such meta-framework is <a href="http://compass-style.org/docs/">Compass</a>, which is built around the core language and compiler <a href="http://sass-lang.com/">Sass</a>. I mentioned Compass briefly in my other post. At the time, I had dismissed it as being more than I required, or more than I wanted to get into, but in the end I realized if I was going down this route at all I might as well do it right &#8211; and Compass does it right. It seems by far the most thorough, mature solution I&#8217;ve found, with a good heritage and a lot of success.</p>
<p>So that&#8217;s what I&#8217;ve settled on using now. There might be some kind of tighter integration achievable if you&#8217;re using Rails, but what I&#8217;m doing is using it to generate CSS as I locally develop a site in WordPress, and the same for a site built on the <a href="http://get-simple.info/">GetSimple</a> CMS, and a Django project as well. You can use it with anything, and when you come to deploy it you can exclude all the Compass stuff, leaving no trace of it on the live site, except perhaps in the tell-tale auto-generated layout of the CSS code.</p>
<p>Your best bet is probably to go read the excellent <a href="http://compass-style.org/docs/">documentation</a>, but here&#8217;s some basic stuff from my own experiences&#8230;</p>
<p>Initial steps:</p>
<p>1. <a href="http://www.ruby-lang.org/en/downloads/">Install Ruby</a><br />
2. <a href="http://docs.rubygems.org/read/chapter/3">Install Ruby Gems</a><br />
(if you&#8217;re on a Mac you may have these already. I guess you could find out by carrying out the next step)</p>
<p>3. Install Compass from the command line:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt; gem install compass</div></div>
<p>With these installed, whenever I begin a project I set up Compass in the theme or template directory by running the following command inside that directory:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt; compass create --syntax sass</div></div>
<p>There are loads more options for the create command (See the <a href="http://compass-style.org/docs/">documentation</a>). Note also I&#8217;m using the SASS syntax, because I prefer it. There are two choices, and projects default to SCSS. See <a href="http://sass-lang.com/">here</a> for more information on the differences.</p>
<p>Incidentally, it&#8217;s interesting that SCSS is now the default syntax for Sass (confusingly, the name of the language/compiler is also the name of one of its two syntaxes). The SCSS syntax looks just like CSS itself, and the idea is to lessen the unfamiliarity for designers who are already very skilled in CSS. After all, there&#8217;s no reason in principle why they should have to learn a new syntax in order to take advantage of the power of Sass and Compass, which is independent of the syntax, and independently valuable.</p>
<p>However, I&#8217;m sticking with the SASS syntax, because I find it neater and easier to write, and I don&#8217;t mind admitting that it&#8217;s simply a welcome novelty.</p>
<p>That create command creates a configuration file, <strong>config.rb</strong>, and three directories, most important of which are <strong>src</strong> and <strong>stylesheets</strong>. <strong>src</strong> is the where you write the code, and <strong>stylesheets</strong> contains the generated CSS.</p>
<p>The last essential piece of the puzzle is how the CSS is generated when you&#8217;re developing. All you need to do is run the following command in the directory in which you set up Compass:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt; compass watch</div></div>
<p>This runs in the background and watches for changes, then re-generates the CSS when it finds them.</p>
<h3>Getting ready to code</h3>
<p>I&#8217;m currently working with a config.rb that looks like this:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'ninesixty'</span><br />
<span style="color:#008000; font-style:italic;"># Require any additional compass plugins here.</span><br />
<br />
project_type = <span style="color:#ff3333; font-weight:bold;">:stand_alone</span><br />
<span style="color:#008000; font-style:italic;"># Set this to the root of your project when deployed:</span><br />
http_path = <span style="color:#996600;">&quot;/&quot;</span><br />
css_dir = <span style="color:#996600;">&quot;stylesheets&quot;</span><br />
sass_dir = <span style="color:#996600;">&quot;src&quot;</span><br />
images_dir = <span style="color:#996600;">&quot;/images&quot;</span><br />
output_style = <span style="color:#ff3333; font-weight:bold;">:compact</span><br />
line_comments = <span style="color:#0000FF; font-weight:bold;">false</span><br />
<span style="color:#008000; font-style:italic;"># To enable relative paths to assets via compass helper functions. Uncomment:</span><br />
relative_assets = <span style="color:#0000FF; font-weight:bold;">true</span></div></div>
<p>It&#8217;s good when starting out to use a _base.sass &#8220;partial&#8221; to set up your variables and imports. Mine looks like this:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#0066ff; font-weight:bold;">@import</span> compass<span style="color:#006600; font-weight:bold;">/</span>reset<br />
<span style="color:#0066ff; font-weight:bold;">@import</span> compass<span style="color:#006600; font-weight:bold;">/</span>utilities<br />
<span style="color:#0066ff; font-weight:bold;">@import</span> <span style="color:#006666;">960</span><span style="color:#006600; font-weight:bold;">/</span>grid<br />
<span style="color:#0066ff; font-weight:bold;">@import</span> compass<span style="color:#006600; font-weight:bold;">/</span>css3<br />
<span style="color:#0066ff; font-weight:bold;">@import</span> my_mixins.<span style="color:#9900CC;">sass</span><br />
<br />
<span style="color:#006600; font-weight:bold;">//</span> VARS<br />
<span style="color:#ff6633; font-weight:bold;">$box_shadow_color</span>: <span style="color:#008000; font-style:italic;">#666</span><br />
<span style="color:#ff6633; font-weight:bold;">$light_grey</span>: <span style="color:#008000; font-style:italic;">#DBD7CA</span><br />
<span style="color:#ff6633; font-weight:bold;">$bg_blue_color</span>: <span style="color:#008000; font-style:italic;">#AFE4E4</span><br />
<span style="color:#ff6633; font-weight:bold;">$bg_pink_color</span>: <span style="color:#008000; font-style:italic;">#FBBBC0</span><br />
<span style="color:#ff6633; font-weight:bold;">$bg_orange_color</span>: <span style="color:#008000; font-style:italic;">#FDBB79</span><br />
<span style="color:#ff6633; font-weight:bold;">$font_family</span>: <span style="color:#996600;">&quot;Georgia&quot;</span>, <span style="color:#996600;">&quot;Times New Roman&quot;</span>, <span style="color:#996600;">&quot;Serif&quot;</span><br />
<br />
<span style="color:#006600; font-weight:bold;">//</span> OVERRIDE DEFAULTS<br />
<span style="color:#ff6633; font-weight:bold;">$default</span><span style="color:#006600; font-weight:bold;">-</span>border<span style="color:#006600; font-weight:bold;">-</span>radius: 3px<br />
<span style="color:#ff6633; font-weight:bold;">$default</span><span style="color:#006600; font-weight:bold;">-</span>text<span style="color:#006600; font-weight:bold;">-</span>shadow<span style="color:#006600; font-weight:bold;">-</span>h<span style="color:#006600; font-weight:bold;">-</span>offset: 0px<br />
<span style="color:#ff6633; font-weight:bold;">$default</span><span style="color:#006600; font-weight:bold;">-</span>text<span style="color:#006600; font-weight:bold;">-</span>shadow<span style="color:#006600; font-weight:bold;">-</span>v<span style="color:#006600; font-weight:bold;">-</span>offset: 0px<br />
<span style="color:#ff6633; font-weight:bold;">$default</span><span style="color:#006600; font-weight:bold;">-</span>text<span style="color:#006600; font-weight:bold;">-</span>shadow<span style="color:#006600; font-weight:bold;">-</span>blur: 5px<br />
<span style="color:#ff6633; font-weight:bold;">$ninesixty_grid_width</span> = 960px<br />
<span style="color:#ff6633; font-weight:bold;">$ninesixty_columns</span> = <span style="color:#006666;">24</span><br />
<br />
<span style="color:#006600; font-weight:bold;">+</span>font<span style="color:#006600; font-weight:bold;">-</span>face<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;Tuesday Regular&quot;</span>, font<span style="color:#006600; font-weight:bold;">-</span>files<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;tuesday-webfont.woff&quot;</span>, woff, <span style="color:#996600;">&quot;tuesday-webfont.ttf&quot;</span>, truetype, <span style="color:#996600;">&quot;tuesday-webfont.svg&quot;</span>, svg<span style="color:#006600; font-weight:bold;">&#41;</span>, <span style="color:#996600;">'tuesday-webfont.eot'</span><span style="color:#006600; font-weight:bold;">&#41;</span></div></div>
<p>See <a href="http://compass-style.org/docs/tutorials/best_practices/">here</a> for more on Compass best practices.</p>
<h3>Mixins</h3>
<p>Notice at the top of the base partial I&#8217;m importing another partial file, <strong>_my_mixins.sass</strong>. Mixins are wonderful: they let you collect together styles and mix them into your stylesheet wherever you like. Compass comes with many of them, but you can also define your own, which is what _my_mixins.sass is for:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">=my_hover_link<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; text<span style="color:#006600; font-weight:bold;">-</span>decoration: none<br />
&nbsp; <span style="color:#006600; font-weight:bold;">&amp;</span>:hover, <span style="color:#006600; font-weight:bold;">&amp;</span>:focus<br />
&nbsp; &nbsp; text<span style="color:#006600; font-weight:bold;">-</span>decoration: underline<br />
<br />
=my_focus<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&amp;</span>:focus<br />
&nbsp; &nbsp; outline: dotted 1px <span style="color:#008000; font-style:italic;">#222</span></div></div>
<p>These are used in the actual stylesheet source code (eg. in screen.sass) like this:</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">a<br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>my_hover_link<br />
&nbsp; color: <span style="color:#008000; font-style:italic;">#004379</span></div></div>
<h3>Grids</h3>
<p>I&#8217;m also using the 960 grid system (Compass also comes with Blueprint). With Compass, using a grid system is very nice indeed.</p>
<div class="codecolorer-container ruby blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#008000; font-style:italic;">#wrap</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>grid<span style="color:#006600; font-weight:bold;">-</span>container<br />
<span style="color:#008000; font-style:italic;">#content</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>grid<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">10</span>,<span style="color:#006666;">16</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>alpha<br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>clearfix<br />
<span style="color:#008000; font-style:italic;">#side</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>grid<span style="color:#006600; font-weight:bold;">-</span>prefix<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span>,<span style="color:#006666;">16</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>grid<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">5</span>,<span style="color:#006666;">16</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>omega<br />
&nbsp; <span style="color:#006600; font-weight:bold;">+</span>clearfix</div></div>
<p>One thing that&#8217;s good about this set-up is that you can code using a grid system without using any unsemantic class names like &#8220;prefix_2 grid_8.&#8221; Compass takes care of that when it generates the CSS. Effectively you&#8217;re using the grid as it really should be used, only in design and development. Compass calculates the relevant widths for your semantically-named elements, based on the 960 mixins, and there&#8217;s no underlying skeleton of unsemantic classes left behind in your HTML and CSS.</p>
<p>NOTE: Using +grid-container instead of +grid-system(12) means you don&#8217;t end up with all the 960 grid classes in your style sheet, which won&#8217;t be required because of your use of the mixins.</p>
<p>This is just the basics. There&#8217;s lots of stuff online, but you can&#8217;t do better than the <a href="http://compass-style.org/docs/">Compass documentation</a>, and it&#8217;s worth taking a look at the site of <a href="http://chriseppstein.github.com/">Chris Eppstein</a>, the man we have to thank for it all.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/css-abstracted-update/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>E-commerce for Small Business in The UK: A Starting Point For Web Developers</title>
		<link>http://alistairrobinson.co.uk/e-commerce-in-the-uk-for-web-designers/</link>
		<comments>http://alistairrobinson.co.uk/e-commerce-in-the-uk-for-web-designers/#comments</comments>
		<pubDate>Sat, 22 May 2010 05:52:32 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[3d secure]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[ecommerce]]></category>
		<category><![CDATA[gateway]]></category>
		<category><![CDATA[payment]]></category>
		<category><![CDATA[rbs]]></category>
		<category><![CDATA[shopp]]></category>
		<category><![CDATA[shopping]]></category>
		<category><![CDATA[worldpay]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=932</guid>
		<description><![CDATA[NOTE: see the comments for updates about how this went in the end. I think I&#8217;ve unearthed a conspiracy. In the wonderful world of the world-wide web (that&#8217;s WWWWW for short), with so much information available, and so many companies selling online, surely there must be a collection of standard procedures for implementing an online [...]]]></description>
			<content:encoded><![CDATA[<p><em>NOTE: see the comments for updates about how this went in the end.</em></p>
<p>I think I&#8217;ve unearthed a conspiracy. In the wonderful world of the world-wide web (that&#8217;s <span class="caps">WWWWW</span> for short), with so much information available, and so many companies selling online, surely there must be a collection of standard procedures for implementing an online shop, and reliable sources of information covering them? Apparently not. How else to explain this except an evil conspiracy? In particular, an evil conspiracy against web designers and developers.</p>
<p>This post is drawn from an e-mail that I sent to a tech savvy client, a small business owner. The email summarized their options for e-commerce, in the specific context of the UK, and it was the result of some hours of research. Reading it over later I realized it could be useful to web developers, given the aforementioned global conspiracy. It is therefore my duty as a good web citizen to reveal this sacred, jealously guarded information &#8211; despite the dangers.</p>
<p>NOTE: I&#8217;ve called it a starting point, but really this post is just a record of my <em>own</em> starting point, and there&#8217;s a bias here towards WordPress.</p>
<h3>Introduction</h3>
<p>There is one way of selling online that I won&#8217;t really go into here, which is selling through your regular PayPal account or with Google Checkout. These are pretty good options, because they&#8217;re so easy, but most businesses don&#8217;t want customers being directed away to PayPal or Google when they check out. A more integrated solution is preferable because it gives customers confidence in the professionalism of the business; the business can have direct access to its product, order and customer data within a single system; and you &#8211; the developer &#8211; get more control all round. That&#8217;s what this post is really about, but the shopping cart software mentioned here can work nicely with the simpler PayPal set-up as well.</p>
<p>An online shop that accepts credit cards usually needs these four things:</p>
<ul>
<li>An Internet Merchant Account (<span class="caps">IMA</span>)</li>
<li>A Payment Gateway</li>
<li>Some shopping cart software (including product listings, product pages, a cart and a checkout page)</li>
<li>(in some cases optional) Shop <span class="caps">CMS</span> (admin for shipping rates, product management, inventory, order management, etc.)</li>
</ul>
<p>The shopping cart and <span class="caps">CMS</span> can normally be treated as separate and independent. For the payment gateway and <span class="caps">IMA</span>, I would normally recommend PayPal&#8217;s Website Payments Pro, which bundles these together. But if a substantial portion of your market is in the UK, there&#8217;s a problem:</p>
<h3>Maestro and 3D Secure</h3>
<p>This is where it gets complicated. In fact, it looks to me like the whole thing&#8217;s a bit of a mess.</p>
<p>Mastercard enforces the use of <a href="http://en.wikipedia.org/wiki/3-D_Secure">3D secure</a> to process Maestro payments (and this is becoming very common for payments with the other cards too). All Maestro transactions will be declined if this isn&#8217;t implemented. 3D Secure is an extra step in the checkout process, which allows real-time authentication with the customer&#8217;s bank. It commonly comes in the guise of &#8220;Verified by Visa&#8221; and &#8220;Mastercard SecureCode&#8221;. In some implementations it&#8217;s optional &#8211; the customer can skip it &#8211; because not all cards are required to be authenticated like this, but a Maestro payment just won&#8217;t complete successfully without a 3D secure authentication.</p>
<p><img src="http://alistairrobinson.co.uk/wp-content/uploads/2010/05/3dsecure.jpg" alt="" title="3dsecure" width="397" height="424" class="alignleft size-full wp-image-936" /></p>
<p>Before you go down this route it might be worth weighing up the pros and cons of 3D secure:</p>
<p><strong>Pros</strong></p>
<ul>
<li>Lets you take Maestro payments</li>
<li>Can give customers more confidence in buying stuff online (in theory)</li>
<li>Reduces <a href="http://en.wikipedia.org/wiki/Chargeback">chargebacks</a></li>
<li>It could be that, as people in the UK have become more used to it, they have come to <em>expect</em> it</li>
</ul>
<p>	<strong>Cons</strong></p>
<ul>
<li>Yet another step in the process of checking out – this is known to lead to a reduction of sales</li>
<li>Restricts your options for e-commerce software and payment gateways</li>
<li>From a development point of view, implementing 3D secure can be tricky, depending on the kind of solution you choose</li>
</ul>
<p>With Website Payments Pro, it&#8217;s up to you to set up 3D Secure. Seemingly as an afterthought they recommend using some kind of product from a company called <a href="http://www.cardinalcommerce.com/">Cardinal</a>, but I&#8217;ve no idea what Cardinal actually provide, and their web site is no help. I sent them an enquiry but received nothing in response. This didn&#8217;t give me much confidence, so I looked for some other solution, i.e., a payment gateway that had embraced 3D Secure and knew how to implement it.</p>
<p>Turns out there is one that&#8217;s popular in the UK: <span class="caps">RBS</span> Worldpay. They offer <a href="http://www.rbsworldpay.com/products/index.php?page=ecom&#38;amp;c=UK">three account options</a>, including one that &#8211; like Payments Pro &#8211; bundles together the <span class="caps">IMA</span> and the gateway. The crucial thing is that WorldPay implements 3D Secure.</p>
<h3><span class="caps">RBS</span> WorldPay</h3>
<p>At the time of writing I haven&#8217;t implemented the gateway, so I can&#8217;t say too much about it now. I also won&#8217;t say anything about WorldPay&#8217;s interesting (in the loosest sense) recent history, but you should check it out because it puts things in perspective.</p>
<p>What I&#8217;ve discovered so far is that there are essentially two ways of implementing WorldPay: <a href="http://www.rbsworldpay.com/support/bg/index.php?page=development&#38;amp;sub=integration&#38;amp;c=UK"><span class="caps">HTML</span> redirect</a> (or Hosted Payment Pages, which appears to be the newer name) and <a href="http://www.rbsworldpay.com/support/bg/index.php?page=development&#38;amp;sub=xml"><span class="caps">XML</span> Direct</a>.</p>
<p><span class="caps">HTML</span> Redirect is the easier option. When the user checks out they&#8217;re redirected away to the WorldPay site, where all the hard stuff is taken care of.  You may be familiar with <span class="caps">HTML</span> Redirect from seeing this <strong>beautiful interface</strong>:</p>
<p><img src="http://alistairrobinson.co.uk/wp-content/uploads/2010/05/worldpay.jpg" alt="" title="worldpay" width="500" height="271" class="alignleft size-full wp-image-935" /></p>
<p>Yes, I know: there&#8217;s no way you&#8217;re having this ugliness anywhere near your lovely design. But according to the WorldPay site, you can customize this page, in line with your own design. I don&#8217;t yet know just how customizable it is: looking at what documentation there is (not an easy task in itself), I&#8217;m sceptical how far you can go with it.</p>
<p>I must warn you that browsing the WorldPay site for good information is a painful experience. It has the feel of a collection of documents assembled from disparate sources by a robot with little sympathy for, or understanding of, the requirements of human beings. I suppose this is fairly common with such massive corporate organizations, but it&#8217;s a real shock when you&#8217;ve been used to dealing with small, focused companies with a dedication to openness on the web.</p>
<p>It took a couple of messages to WorldPay technical support to find out that there was another way: <span class="caps">XML</span> Direct. This allows a more complete integration with your site, because all the processing is done in the background, rather than with a redirection. The implications are that you&#8217;ll need to make damn sure you&#8217;ve got a secure system. <span class="caps">RBS</span> have a process for assessing your set-up, and further procedures for testing and activation.</p>
<p>For an alternative to <span class="caps">RBS</span> WorldPay that also supports 3D secure, check out <a href="http://www.sagepay.com/">SagePay</a></p>
<h3><span class="caps">PCI</span> Compliance</h3>
<p>Aside from any particular requirements of your gateway, generally a secure setup is one that is <a href="http://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard"><span class="caps">PCI</span> compliant</a>.</p>
<p>With <span class="caps">HTML</span> Redirect and the hosted solutions (option 1 below), you don&#8217;t need to be <span class="caps">PCI</span> Compliant at all, because you&#8217;re not actually storing credit card numbers on file or in a database. It&#8217;s your payment gateway (eg. WorldPay or Website Payments Pro) or shopping cart service that has to be <span class="caps">PCI</span> compliant. However, your gateway may still require you to pass some level of security-checking.</p>
<p>With <span class="caps">XML</span> Direct, you do need to pass some <span class="caps">PCI</span> Compliance tests, and that&#8217;s a whole other can of worms I&#8217;m not going to open right now, because I&#8217;m still not sure exactly what&#8217;s inside. Worms, yes, but what kind? And do they bite?</p>
<h3>SSL/HTTPS/Encryption</h3>
<p>You might not be storing credit card numbers, but you may need to transmit them securely, in which case you will need to buy an <span class="caps">SSL</span> certificate and have it installed on your web server. Basically, if your checkout page resides on your web server, as part of the site, you will need <span class="caps">SSL</span>. But if it&#8217;s hosted, as it is with WorldPay <span class="caps">HTML</span> Redirect or one of the complete hosted shopping cart solutions (option 1 below), you&#8217;re not transmitting anything sensitive so <span class="caps">SSL</span> is not required.</p>
<h3>Software Option 1: Hosted</h3>
<p>Examples: <a href="http://www.ecwid.com">Ecwid</a>, <a href="http://www.foxycart.com/">Foxycart</a>, <a href="http://www.shopify.com">Shopify</a></p>
<p>With hosted e-commerce, you sign up to a service that provides a cart and checkout process, all hosted on their servers. General shop settings &#8211; shipping, taxes, coupons and product types &#8211; are all administered on their site.</p>
<p>The big advantage is that they they&#8217;re the ones who need to have the <span class="caps">SSL</span> encryption and security, and they wrap up the whole checkout process very nicely, so there&#8217;s not much in that area you have to worry about.</p>
<p>I&#8217;ve set up a shop with FoxyCart and <a href="http://modxcms.com/">MODx</a>, and while there&#8217;s a lot of work to be done if you need product management built into your <span class="caps">CMS</span>, setting up the customized cart and checkout pages is a breeze.</p>
<ul>
<li>They handle <span class="caps">SSL</span> and <span class="caps">PCI</span> compliance</li>
<li>No 3D secure/Maestro (because they&#8217;re responsible for implementing it and Ecwid, Foxycart and Shopify haven&#8217;t done so yet, although they&#8217;re working on it)</li>
<li>Your data is on their servers</li>
<li>Separate place to manage shop (ie. separate from the rest of the website)</li>
</ul>
<p><strong>Ecwid</strong> (Free)</p>
<ul>
<li>Very fast, very easy, and very tempting</li>
<li>But no <span class="caps">API</span> and not very configurable</li>
<li>Depends on JavaScript</li>
</ul>
<p><strong>Foxycart</strong> ($19/month)</p>
<ul>
<li>Very configurable</li>
<li>Total control over the design of the hosted pages</li>
<li><span class="caps">API</span> and XML feed to get data from their servers to yours (allowing you to integrate this data with your database and <span class="caps">CMS</span>)</li>
<li>Cart depends on JavaScript</li>
</ul>
<p><strong>Shopify </strong>(From $29 to $699/month)<br />Look at that price-range. That indicates a pretty mature kind of product, and I get the feeling this might be one of the best hosted solutions out there, but I don&#8217;t know much about it. But it&#8217;s built with Ruby on Rails so it must be super cool, right?</p>
<h3>Software Option 2. Self-hosted / Integrated</h3>
<p>Examples: WordPress plugins <a href="http://www.instinct.co.nz/e-commerce/">WP e-commerce</a> and <a href="http://shopplugin.net/">Shopp</a></p>
<p>I recently split off a WordPress site into two development branches, one with Wp e-commerce and the other with Shopp. I&#8217;m very impressed with this type of software solution. I don&#8217;t see any reason why you couldn&#8217;t implement any size of shop, and there&#8217;s loads of <span class="caps">CMS</span> features covering just about everything. I went with Shopp in the end, but they&#8217;re pretty similar in functionality.</p>
<ul>
<li>You have their software installed on your server (ie. the server I&#8217;m hosting the site on)</li>
<li>You keep all the data on your server</li>
<li>You don&#8217;t have to log in to another site to manage your shop</li>
<li>Shop <span class="caps">CMS</span> for product, order and customer management etc., integrated into your site CMS</li>
<li>Configurable</li>
<li>Often requires an <span class="caps">SSL</span> certificate</li>
<li>Could require PCI Compliance, depending on how you implement it</li>
<li>Maestro support is possible (if using <span class="caps">RBS</span> WorldPay or something similar like SagePay)</li>
<li>But no WorldPay gateway option out-of-the-box</li>
</ul>
<p><strong>WP e-commerce</strong> (free, or $195 for the business gold cart)</p>
<ul>
<li>Open source</li>
<li>Configurable, customizable</li>
<li>Ability to create a custom gateway integration</li>
<li>The free version withholds some functionality that in most cases is a necessity, such as multiple images per product. You could probably code this in yourself if you wanted to avoid the cost.</li>
</ul>
<p><strong>Shopp</strong> (One-off $55)</p>
<ul>
<li>Open source</li>
<li>Configurable, customizable</li>
<li>Ability to create a custom gateway integration</li>
</ul>
<h3>Software Option 3: Self-hosted Standalone <span class="caps">CMS</span></h3>
<p>Example: <a href="http://www.magentocommerce.com/">Magento</a></p>
<ul>
<li>You have their software installed on your server, alongside your web site <span class="caps">CMS</span></li>
<li>All-in-one shopping cart, product and order management package</li>
<li>You keep the data on your server</li>
<li>Open source</li>
<li>Separate dedicated <span class="caps">CMS</span> for your shop (not integrated into your site <span class="caps">CMS</span>)</li>
<li>Tonnes of features</li>
<li>Potentially difficult to configure and integrate</li>
<li>Requires an <span class="caps">SSL</span> certificate</li>
<li>Could require PCI Compliance, depending on how you implement it</li>
<li>Maestro support possible (if using <span class="caps">RBS</span> WorldPay or SagePay)</li>
<li>But no WorldPay gateway option out-of-the-box</li>
</ul>
<p>Something like Magento should be seriously considered. It&#8217;s very featureful, and I hear they recently implemented 3D secure. However, setting up and configuration could be time-consuming, and systems like these can be pretty bloated, slow and clunky.</p>
<h3>Conclusion</h3>
<p>If you need to take Maestro payments &#8211; and there are still a lot of those cards around &#8211; you can&#8217;t really go with option 1. The other options all have built-in support for several gateways, but unfortunately not WorldPay. This means some unavoidable work on your part to hook things up. Whether you go with option 2 or 3 depends solely on the needs of the client and your own development decisions.</p>
<p>In the forthcoming weeks I&#8217;ll be implementing the gateway &#8211; perhaps developing a WorldPay module for Shopp in the process &#8211; so I&#8217;ll be posting about that. If the Guardians of the Sacred Secrets of E-commerce haven&#8217;t tracked me down, that is.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/e-commerce-in-the-uk-for-web-designers/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>CSS Abstracted</title>
		<link>http://alistairrobinson.co.uk/css-abstracted/</link>
		<comments>http://alistairrobinson.co.uk/css-abstracted/#comments</comments>
		<pubDate>Sat, 01 May 2010 20:51:08 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>
		<category><![CDATA[clevercss]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[compilers]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sass]]></category>
		<category><![CDATA[scaffold]]></category>

		<guid isPermaLink="false">http://alistairrobinson.co.uk/?p=927</guid>
		<description><![CDATA[Half way through the development of my last site I decided to use PHP files for CSS. I had a few stylesheets, and I found I was constantly going from one to the other to copy and paste hex colour codes. And then later, if I wanted to change a colour, I&#8217;d have to change [...]]]></description>
			<content:encoded><![CDATA[<p>Half way through the development of my last site I decided to <a href="http://css-tricks.com/css-variables-with-php/">use PHP files for CSS</a>. I had a few stylesheets, and I found I was constantly going from one to the other to copy and paste hex colour codes. And then later, if I wanted to change a colour, I&#8217;d have to change it in all those different places. That really is no way to work.</p>
<p>The answer to this, of course, is variables (or constants), so that you can define your colours in one place. Trouble is, CSS don&#8217;t got none. In fact, CSS is lacking <a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets#Limitations">in several important ways</a>. What it boils down to is that we struggle to get around the fact that CSS doesn&#8217;t work like a programming language. In other words, it&#8217;s not logical, intuitive or consistent.</p>
<h3>Cognitive Dissonance</h3>
<p>I&#8217;ve been saying for a while that the affection many people say they have for CSS must be born of their triumph in finally getting the bloody thing to work. I know this feeling. There&#8217;s power in there to do what you need, and it <em>can</em> be fun. We must get some kind of neuro-chemical reward when we creatively delve into the details of CSS and finally emerge with something approaching what we were going for.</p>
<p>In fact, this is a classic example of the psychology of rationalization, prompted by <a href="http://en.wikipedia.org/wiki/Cognitive_dissonance">cognitive dissonance</a>. The time and energy we spend on CSS compels us to believe that it is good, because if we doubted that, there would be an unacceptable inconsistency in our lives.</p>
<p>It&#8217;s how web developers remain sane: by lying to themselves.</p>
<p>There is a joy in arranging your stylesheets logically, breaking them down into sections, successfully and efficiently tackling the issues of specificity and inheritance. But this is only because there&#8217;s <em>so much room for improvement</em> in CSS. It&#8217;s so easy to write it badly, with repetition and redundancy everywhere. And even if you write it well, maintenance is still a hassle. Why should we have to deal with these difficulties when there already exist models and paradigms, in the world of programming, that could make things much simpler if applied to CSS?</p>
<p>Often you hear the objection that the abstraction of CSS is only for those who haven&#8217;t done the hard work in learning it properly. That kind of attitude stinks, in my opinion. Specifically, it stinks of self-justification, conservatism and protectionism. It is the bitter form of the rationalization that aims at avoiding conginitive dissonance.</p>
<p>CSS won&#8217;t be around for ever. It was expedient, and learning it has been a necessary evil. A heroic endeavour, it&#8217;s true: the prominent designers, developers and standards advocates who have cracked it and shared their knowledge with the rest of us are web heroes, no doubt about it. But that doesn&#8217;t mean we should continue to celebrate the endeavour if it&#8217;s no longer necessary.</p>
<h3>First Steps</h3>
<p>So in my last site I put things into practice in a very basic way. Here&#8217;s <em>config.css.php</em>:</p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Content-type: text/css; charset: UTF-8&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #000088;">$grey</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'#aaaaaa'</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$light</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'#efefef'</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$pink</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'#e66586'</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p>And here&#8217;s the fake stylesheet <em>main.css.php</em>:</p>
<div class="codecolorer-container css blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;?php<br />
include_once<span style="color: #00AA00;">&#40;</span><span style="color: #ff0000;">'config.css.php'</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span><br />
<br />
echo &lt;&lt;&lt;EOT<br />
<br />
<span style="color: #cc00cc;">#blog</span> <span style="color: #6666ff;">.article</span> a <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> $grey<span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#blog</span> <span style="color: #6666ff;">.article</span> a<span style="color: #3333ff;">:hover </span><span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> $light<span style="color: #00AA00;">;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">border-bottom</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">solid</span> <span style="color: #933;">2px</span> $pink<span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
EOT<span style="color: #00AA00;">;</span><br />
?<span style="color: #00AA00;">&gt;</span></div></div>
<p>In the HTML you link to the stylesheet in the normal way, but specifying the PHP file instead of a CSS file.</p>
<p>True, you could use regular CSS classes for this, but do you really want to pollute your HTML with classes with names like &#8220;dark&#8221; and &#8220;box-shadow-colour&#8221; ? Just think how horrible that could get.</p>
<p>That&#8217;s all very well, but it&#8217;s still really just CSS. It&#8217;s also going to be slightly slower (not that I&#8217;ve noticed), and it&#8217;s a bit of a hack anyway. It&#8217;s akin to the way that PHP is peppered through HTML, and that&#8217;s not a great model.</p>
<p>That&#8217;s where CSS compilers or frameworks come in. One example is <a href="http://wiki.github.com/anthonyshort/csscaffold/">CSScaffold</a>. With Scaffold you can use <em>mixins</em> to group together properties into reusable chunks. They work a bit like functions or classes in programming, and Scaffold comes with lots of them ready to use. Also, the big advantage of Scaffold over the way I described above is that it will serve the generated CSS files directly if they&#8217;ve already been cached.</p>
<h3>Enter Python</h3>
<p>But Scaffold still stubbornly clings to the CSS syntax, and it wants you to integrate it into your code. What I really wanted, as well as relief from semi-colons and curly braces, was a way of generating CSS, not on the fly in production, but only during development, so that the live site would only ever serve plain old CSS files with no server processing. So I became much more enthusuastic when I found <a href="http://sandbox.pocoo.org/clevercss/">CleverCSS</a>, which is a way of doing this kind of thing with Python.</p>
<p>This&#8230;</p>
<div class="codecolorer-container css blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">grey <span style="color: #00AA00;">=</span> <span style="color: #cc00cc;">#aaaaaa</span><br />
light <span style="color: #00AA00;">=</span> <span style="color: #cc00cc;">#efefef</span><br />
pink <span style="color: #00AA00;">=</span> <span style="color: #cc00cc;">#e66586</span><br />
<br />
<span style="color: #cc00cc;">#blog</span><span style="color: #00AA00;">:</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">450px</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">float</span><span style="color: #00AA00;">:</span><span style="color: #000000; font-weight: bold;">left</span><br />
&nbsp; <br />
&nbsp; .article<span style="color: #00AA00;">:</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">10px</span> <span style="color: #cc66cc;">0</span><br />
<br />
&nbsp; &nbsp; a<span style="color: #00AA00;">:</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> $grey - <span style="color: #cc66cc;">76</span><br />
<br />
&nbsp; &nbsp; &nbsp; &amp;<span style="color: #3333ff;">:hover</span><span style="color: #00AA00;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> $light.darken<span style="color: #00AA00;">&#40;</span><span style="color: #933;">50%</span><span style="color: #00AA00;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">border-bottom</span><span style="color: #00AA00;">:</span><span style="color: #993333;">solid</span> <span style="color: #933;">2px</span> $pink</div></div>
<p>&#8230;on the execution of <em>clevercss.convert</em> produces this&#8230;</p>
<div class="codecolorer-container css blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #cc00cc;">#blog</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">450px</span><span style="color: #00AA00;">;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">float</span><span style="color: #00AA00;">:</span> <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#blog</span> <span style="color: #6666ff;">.article</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">10px</span> <span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#blog</span> <span style="color: #6666ff;">.article</span> a <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#5e5e5e</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#blog</span> <span style="color: #6666ff;">.article</span> a<span style="color: #3333ff;">:hover </span><span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#777777</span><span style="color: #00AA00;">;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">border-bottom</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">solid</span> <span style="color: #933;">2px</span> <span style="color: #cc00cc;">#e66586</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span></div></div>
<p>A few things to notice in the CleverCSS code: no semi-colons or curly braces; the indentation defines the hierarchy; the use of the ampersand to refer to the parent element for the hover; the arithmetical expression <strong>$grey &#8211; 76</strong>; and the method call <strong>$light.darken(50%)</strong>.</p>
<p>I&#8217;m beginning to use this now to generate and update CSS files as I develop a WordPress site. If I find that it&#8217;s not right I can easily switch over to something else, or just go back to doing CSS directly &#8211; with no harm done and no time wasted.</p>
<p>But CleverCSS is in Python, not PHP, so I can&#8217;t very easily weave it into the fabric of the operational code, even if I want to. Instead, here&#8217;s the technique I&#8217;ve come up with:</p>
<p>1. Let&#8217;s say in my CSS folder I&#8217;ve got <em>main.clvr</em> and <em>forms.clvr</em>, which never get uploaded to the web server*<br />
2. I do the styling code in these files<br />
3. When I want to see the changes to the web page, I run a Python script from the command line in the CSS folder:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ make_css.py</div></div>
<p>4. Now I&#8217;ve got <em>main.css</em> and <em>forms.css</em></p>
<p>*Note that you can use any extension you want</p>
<p>Here&#8217;s <em>make_css.py</em>:</p>
<div class="codecolorer-container python blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> clevercss<br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">fnmatch</span><br />
<br />
clevercss_files <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">fnmatch</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;*.clvr&quot;</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">for</span> <span style="color: #008000;">file</span> <span style="color: #ff7700;font-weight:bold;">in</span> clevercss_files:<br />
&nbsp; f <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;r&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; css <span style="color: #66cc66;">=</span> clevercss.<span style="color: black;">convert</span><span style="color: black;">&#40;</span>f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; parts <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">splitext</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#41;</span><br />
&nbsp; f <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>parts<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> + <span style="color: #483d8b;">&quot;.css&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;w&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; f.<span style="color: black;">write</span><span style="color: black;">&#40;</span>css<span style="color: black;">&#41;</span><br />
&nbsp; f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div>
<p>This finds all the CleverCSS files and runs <strong>clevercss.convert</strong> on their contents, writing the output of each to a CSS file.</p>
<p>I&#8217;m really enjoying this technique, but it isn&#8217;t perfect. Running the script is an extra step, and that in itself might be enough to put some people off. And CleverCSS, at least the version I have, has no support for custom functions, mixins or macros, as far as I can tell. And debugging in Firebug is on the generated CSS, so you have to relate it back to the CleverCSS yourself.</p>
<p>As it happens, these problems are solved in CSS compilers such as <a href="http://compass-style.org/">Compass</a>, which uses the SASS language. SASS is comparable to CleverCSS but seems to offer a bit more, including <a href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixins">mixins</a>. Compass takes things further: it has a bunch of standard mixins and plugins, support for grid frameworks like 960.gs and Blueprint, and it can integrate into several web app frameworks. Also, it listens for changes to your files so that you don&#8217;t have to repeatedly run a script to produce the actual CSS.</p>
<p>But I&#8217;m not ready for that kind of commitment. In any case it would be unsuitable for a WordPress site. </p>
<p>I&#8217;m very new to this methodology so I&#8217;m not necessarily recommending it. The debates continue about whether CSS itself should eventually provide these things, and whether CSS abstraction is just for programmers and not designers &#8211; but in principle I believe it&#8217;s a step in the right direction.</p>
<p>I&#8217;ve only mentioned a few of these languages and frameworks, but there&#8217;s a tonne of others out there, all with different syntax. An argument could easily be made that they&#8217;re just adding another layer of clutter, when we&#8217;ve no idea what&#8217;s going to happen with web standards and browsers. These solutions are transient and half-baked, and far less established than CSS itself.</p>
<p>However, used as a convenience in the way I&#8217;ve described, it doesn&#8217;t introduce any difficulty into development or obscurity into the finished application, which remains just PHP, MySQL, HTML, JavaScript and CSS.</p>
<p>Over the last couple of years there&#8217;s been a lot of activity around this. Here are some great articles, with good debates in the comments:<br />
<a href="http://www.codinghorror.com/blog/2010/04/whats-wrong-with-css.html">What&#8217;s Wrong With CSS</a><br />
<a href="http://wiseheartdesign.com/articles/2010/01/18/the-demise-of-css-why-sass-and-languages-like-it-will-triumph/">The Demise of Plain CSS</a><br />
<a href="http://chriseppstein.github.com/blog/2009/09/20/why-stylesheet-abstraction-matters/">Why Stylesheet Abstraction Matters</a></p>
<p><a href="http://wiki.github.com/anthonyshort/csscaffold/">CSScaffold</a><br />
<a href="http://sandbox.pocoo.org/clevercss/">CleverCSS</a><br />
<a href="http://sass-lang.com/">SASS</a><br />
<a href="http://compass-style.org/">Compass</a></p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/css-abstracted/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A Nice and Simple Photo Gallery Solution for MODx</title>
		<link>http://alistairrobinson.co.uk/a-nice-and-simple-photo-gallery-solution-for-modx/</link>
		<comments>http://alistairrobinson.co.uk/a-nice-and-simple-photo-gallery-solution-for-modx/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 03:18:04 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[MODx]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[content management]]></category>
		<category><![CDATA[evolution]]></category>
		<category><![CDATA[gallery]]></category>
		<category><![CDATA[image]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[snippets]]></category>

		<guid isPermaLink="false">http://www.alistairrobinson.co.uk/blog/?p=828</guid>
		<description><![CDATA[My third MODx site is about to launch. It&#8217;s relatively simple (no forms!) so I had the chance to really concentrate on refining my architecture, and the work I&#8217;ve done will stand me in good stead for a while (unless I give in to the enticements of SilverStripe or ExpressionEngine, or just ditch the PHP [...]]]></description>
			<content:encoded><![CDATA[<p>My third MODx site is about to launch. It&#8217;s relatively simple (no forms!) so I had the chance to really concentrate on refining my architecture, and the work I&#8217;ve done will stand me in good stead for a while (unless I give in to the enticements of SilverStripe or ExpressionEngine, or just ditch the PHP altogether and finally get up-and-running with Django).</p>
<p>&#8220;Refining his architecture? What does he mean?&#8221; For me, learning to use MODx well has been about working out how to combine templates, template variables, chunks and snippets in a logical and efficient structure. A good application &#8211; a small one, at least &#8211; should have a shape that you can envision (if you&#8217;re the kind of person who envisions shapes, that is). The shape should be pleasing, natural and economical. In my first two MODx sites I fashioned a few butt-ugly shapes that would certainly have sullied the pages of Euclid&#8217;s Elements.</p>
<p>They worked, and they were clever in their ways, but I feel I&#8217;ve moved past all that now, that I&#8217;m approaching the gleaming heavenly realm of the Platonic solids, of perfect dodecahedrons and icosahedrons.</p>
<p>Maybe I make it difficult for myself. Two components that are mentioned so often in the MODx forum and documentation that you could be forgiven for assuming were part of the core itself, are the snippets Ditto and Jot &#8211; but I&#8217;ve never used them. And then there&#8217;s Wayfinder. I used it once, and it was great, but I didn&#8217;t really know what I was doing and I wasn&#8217;t comfortable with it, and it was a hassle to learn how to use it. In the project I&#8217;m on now I&#8217;ve just done it myself, with a &#8220;menu&#8221; snippet and a couple of chunks. I know the boundaries of the project so I can decide to avoid complication by battening things down; and there&#8217;s so little code that changing it will be easy in the event that the structure of the navigation needs to change in the future.</p>
<p>Incidentally, Jot and Ditto are often mentioned in connection with blogs, for which they appear to be indispensable in MODx. Well, say what you like about WordPress but it does blogging pretty damn well and is equally customizable. I fear if I try putting a blog together with MODx, things might get pretty sticky. Even if I was successful I&#8217;d still end up with something far inferior to WordPress. This is a tricky situation, because I really do want to be able to use MODx for blogs &#8211; the templating system is close to perfection, and WordPress&#8217;s is horrible.  But this is all by the way.</p>
<p>I really appreciate the work that people put in to writing freely available, open-source code. Wonders abound. But I have to confess: I don&#8217;t have much patience when it comes to using plugins, widgets, modules or whatever. If I&#8217;m looking for one it&#8217;s to save time, so 1. I want it to behave roughly as I&#8217;m expecting, and 2. I want good documentation, i.e. documentation I don&#8217;t have to spend much time with. Otherwise, I&#8217;d rather just do it myself, gaining into the bargain the extra advantage of avoiding the overhead of features I don&#8217;t need.</p>
<p>In this last project I&#8217;ve been working on, the most common type of page required an image gallery to go underneath the main content, and a main image in the body of the content text. Any page of this type could have photos added to it, and they should appear in the gallery in the same format. For the solution I needed: an easy way for editors to add photos without any resizing woes; auto-generated thumbnails; a way of outputting the gallery HTML; some good HTML and CSS; and a nice Lightbox on the client-side.</p>
<p>I had a look around for a plugin or module but it really wasn&#8217;t worth the hassle and nothing I found seemed like a good fit, so here&#8217;s what I did. If anyone spots a problem in the code or in the concept itself, let me know. </p>
<p>UPDATES &amp; THINGS TO NOTE:</p>
<ul style="list-style-type:disc;padding-left:20px">
<li>This is about MODx <strong>Evolution</strong>, not the newer Revolution
<li>I&#8217;m not aiming here to provide full site-wide image management. For that, something like <a href="http://wiki.modxcms.com/index.php/MaxiGallery">MaxiGallery</a> might be a good choice, and certainly provides loads more features.</li>
<li>The plugin might not work in the 0.9.x versions of MODx. I&#8217;m using 1.0.2. Thanks to <a href="http://www.1-vision.nl/">Dimmy</a> for pointing this out in the comments</li>
<li>The plugin doesn&#8217;t seem to work correctly when using the front-end editor</li>
<li>It&#8217;s not included here but I’d recommend checking the size of the uploaded photos in the first place, and you might want to actually resize all uploaded images so as to standardize the “full-size” photos that are displayed in the lightbox.</i>
<li>The code here doesn&#8217;t check for the existence of files, or handle exceptions</li>
</ul>
<h3>What we&#8217;re aiming for</h3>
<p><img src="/wp-content/uploads/2010/02/mocgc_gallery.jpg" alt="" title="mocgc_gallery" width="580" height="464" class="alignleft size-full wp-image-844" /></p>
<p>Above is an example of the page type in question, with the portion of the page we&#8217;re interested in highlighted. By the way, the <a href="http://www.flickr.com/photos/alistairrobinson" title="my flickr photos">photos</a> are not at all relevant to the website &#8211; this is just for illustration.</p>
<p></p>
<p><img src="/wp-content/uploads/2010/02/mocgc_gallery_lightbox.jpg" alt="" title="mocgc_gallery_lightbox" width="580" height="388" class="alignleft size-full wp-image-851" /></p>
<p>This is not particularly relevant to the MODx side of things, but for the sake of completion the image above shows the lightbox that pops up when you click on a thumbnail. </p>
<p>To achieve all this we need:</p>
<ul style="list-style-type:disc;padding-left:20px">
<li>A template for this kind of page</li>
<li>Template variables for the photos, to apply to this template</li>
<li>A chunk for the outer HTML of the gallery: <i>gallery</i></li>
<li>A chunk for the inner HTML: <i>gallery_item</i>, to be repeated for each photo</li>
<li>A snippet for the body photo: <i>body_photo</i></li>
<li>A snippet for the gallery: <i>gallery</i></li>
<li>A plugin: <i>thumbnailer</i>, which generates thumbnails, and runs when a document is saved</li>
<li>Some CSS to style the gallery HTML</li>
<li>Some javascript to display the full-size images in a lightbox &#8211; I&#8217;ll use jQuery</li>
</ul>
<p>Although it might make sense to explain the thumbnail generation first, I&#8217;m going to start with the template, template variables, snippets and chunks to demonstrate the output we&#8217;re aiming to produce, and from there move backwards to the plugin. Finally, with the MODx side dealt with I&#8217;ll say a bit about the client-side, specifically the lightbox for viewing the full-size photos.</p>
<h3>The Template</h3>
<p>The template itself can be whatever you like, just so long as there <i>is</i> one that you can target the template variables to and which you can use for all pages of this type. The relevant portion looks like this:</p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;section <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;content&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>[*longtitle*]<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
&nbsp; [!body_photo!]<br />
&nbsp; [*content*]<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span><br />
[!gallery!]</div></div>
<p>It&#8217;s not important that I&#8217;m using HTML5 (see the &lt;section&gt; tag). But if you haven&#8217;t coded in HTML5 before I heartily recommend it &#8211; you can even get it to work in IE with the <a href="http://html5doctor.com/how-to-get-html5-working-in-ie-and-firefox-2/">inclusion of a wee javascript file</a>. This is the first line of an HTML5 document:</p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #00bbdd;">&lt;!DOCTYPE html&gt;</span></div></div>
<p> Beautiful.</p>
<h3>The Template Variables</h3>
<p>We need some template variables, one for the main body image and one for each photo in the gallery, and the latter variables need to go in a new category, which I&#8217;ve called &#8220;Gallery.&#8221;</p>
<p><img src="/wp-content/uploads/2010/02/tmplvars.jpg" alt="" title="tmplvars" width="355" height="342" class="alignleft size-full wp-image-890" /></p>
<p>In the editor, this gives you something like this:</p>
<p><img src="/wp-content/uploads/2010/02/tmplvars_editor.jpg" alt="" title="tmplvars_editor" width="567" height="490" class="alignleft size-full wp-image-898" /></p>
<p>You may pick up on a crucial implication of this, namely that the number of photos an editor can add to a page is limited, almost <i>hard-coded</i>. I think this is probably fairly standard practice in the world of CMSs, but it went against my instincts: it&#8217;s natural to want to provide the flexibility of being able to add limitless photos. But ultimate flexibility is mostly a complete waste of time, and often holds its own problems. So editors will only be able to add eight photos to a gallery. So what? Looking at the requirements, eight was plenty. To paraphrase 37 Signals in <a href="http://gettingreal.37signals.com/toc.php">Getting Real</a>, <i>it just didn&#8217;t matter.</i> It&#8217;s amazing the time you can save by making decisions like this.</p>
<p>Anyway, providing for more photos per page at some point in the future would be a simple matter of the developer/administrator adding more template variables.</p>
<h3>The Chunks</h3>
<p>We need an outer and an inner chunk.</p>
<p><i>gallery</i></p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;section <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;gallery&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; [+gallery_items+]<br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span></div></div>
<p><i>gallery_item</i></p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+big+]&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+title+]&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+thumb+]&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+alt+]&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+thumb_width+]&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;[+thumb_height+]&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span></div></div>
<p></p>
<h3>The Snippets</h3>
<p>First of all, some configuration values to be used both by the snippets and by the plugin.</p>
<p><i>config.php</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMAGES_FOLDER'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'assets/images/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMBS_FOLDER'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'assets/images/thumbs/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MEDIUM_FOLDER'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'assets/images/medium/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_TMPLVAR'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'body_photo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_WIDTH'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_HEIGHT'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">75</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_WIDTH'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">300</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_HEIGHT'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">225</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GALLERY_CATEGORY_NAME'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Gallery'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>It&#8217;s not very important where this config file lives. Somewhere in &#8220;assets&#8221; is good. (And if you&#8217;re a big fan of config files you could put other things in here, such as the chunk names. Or, now that I think of it, you could pass in the chunk names in the snippet calls.)</p>
<p>The <i>body_photo</i> snippet is pretty basic, and it&#8217;s not crucial to do it this way. As usual with snippets I just include a separate file:</p>
<p><i>body_photo</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/snippets/body_photo.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p><i>body_photo.php</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/utility.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$medium_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'site_url'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MEDIUM_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$path</span> <span style="color: #339933;">=</span> get_tv_value<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'body_photo'</span><span style="color: #339933;">,</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">documentIdentifier</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$path</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000088;">$full_path</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #000088;">$path</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$file_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">basename</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$full_path</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$medium_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$size</span> <span style="color: #339933;">=</span> <span style="color: #990000;">getimagesize</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// portrait, so swap the dimensions</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$w</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$body_photo_width</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$body_photo_width</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$body_photo_height</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$body_photo_height</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$w</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;img src=&quot;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; alt=&quot;&quot; width=&quot;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$body_photo_width</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; height=&quot;'</span><span style="color: #339933;">.</span><span style="color: #000088;">$body_photo_height</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; /&gt;'</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$html</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p>All this does is echo out an image tag to the page if there&#8217;s a value for the <i>body_photo</i> template variable, and nothing if there isn&#8217;t. Crucially, though, the image is not the one uploaded but a resized version held in a folder for the medium-sized images. More on the resizing later.</p>
<p>By the way, <i>get_tv_value</i> is just a helper function which I&#8217;ve got in utility.php:</p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">function</span> get_tv_value<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span><span style="color: #000088;">$doc_id</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$arr</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTemplateVarOutput</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span><span style="color: #000088;">$doc_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>&nbsp; <br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$arr</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now for the gallery. Again, in the MODx manager we need to just include our snippet code:</p>
<p><i>gallery</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/snippets/gallery.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p><i>gallery.php</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/utility.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$images_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'site_url'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMAGES_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumbs_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'site_url'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMBS_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$gallery_category_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GALLERY_CATEGORY_NAME'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumb_width</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_WIDTH'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumb_height</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_HEIGHT'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$gal_vars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;modx_site_tmplvars A INNER JOIN modx_categories B ON A.category = B.id &quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;B.category = '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$gallery_category_name</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$gal_var</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRow</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$gal_vars</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; <span style="color: #000088;">$photo</span> <span style="color: #339933;">=</span> get_tv_value<span style="color: #009900;">&#40;</span><span style="color: #000088;">$gal_var</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">documentIdentifier</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$photo</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$full_path</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #000088;">$photo</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$file</span> <span style="color: #339933;">=</span> <span style="color: #990000;">basename</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$full_path</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$thumb</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$thumbs_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$big</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$images_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000088;">$chunkArr</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'thumb'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$thumb</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'big'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$big</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'title'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$file</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'alt'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$file</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'thumb_width'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$thumb_width</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'thumb_height'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$thumb_height</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; &nbsp; <span style="color: #000088;">$html</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parseChunk</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'gallery_item'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$chunkArr</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'[+'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'+]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>&nbsp; &nbsp; <br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$html</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parseChunk</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'gallery'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'gallery_items'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$html</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'[+'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'+]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$html</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
<p>In gallery.php, line 12 shows why we put the template variables for the gallery in a new category: we can get a MySQL result for the eight variables. Immediately afterwards we loop through that result to build a bunch of list items, each time injecting values into the <i>gallery_item</i> chunk, which is the inner, repeated chunk of the gallery HTML. Each iteration will replace the various placeholders, <i>[+big+]</i>, <i>[+title+]</i> and so on, producing something like this:</p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/lochawe.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/lochawe.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span></div></div>
<p>Notice that the actual image for the image tag is the thumbnail version, and the surrounding anchor links to the original. Also notice the <i>rel=&#8221;lightbox&#8221;</i> value, which will be used by the JavaScript.</p>
<p>When we&#8217;ve got all the list items it&#8217;s time (line 41) to inject them into the outer chunk, <i>gallery</i>, by replacing the placeholder <i>[+gallery_items+]</i>. The end result is something like this:</p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;section <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;gallery&quot;</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/lochawe.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/lochawe.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/skull.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;skull.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/skull.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;skull.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/cammo.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cammo.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/cammo.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cammo.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/bavelaw.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;bavelaw.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/bavelaw.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;bavelaw.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/piano.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;piano.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/piano.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;piano.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/calton.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;calton.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/calton.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;calton.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span></div></div>
<p>And then it&#8217;s echoed out to the page. With all the template parsing done, the HTML that&#8217;s sent to the browser will look something like this:</p>
<div class="codecolorer-container html4strict blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;section <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;content&quot;</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Corporate Events<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/medium/meadows.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;300&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;225&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">p</span>&gt;</span>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at ante. Mauris eleifend, quam a vulputate dictum, massa quam dapibus leo, eget vulputate orci purus ut lorem. In fringilla mi in ligula. Pellentesque aliquam quam vel dolor. Nunc adipiscing. Sed quam odio, tempus ac, aliquam molestie, varius ac, tellus. Vestibulum ut nulla aliquam risus rutrum interdum. Pellentesque lorem. Curabitur sit amet erat quis risus feugiat viverra. Pellentesque augue justo, sagittis et, lacinia at, venenatis non, arcu. Nunc nec libero. In cursus dictum risus. Etiam tristique nisl a nulla. Ut a orci. Curabitur dolor nunc, egestas at, accumsan at, malesuada nec, magna.<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span> <br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span> <br />
<span style="color: #009900;">&lt;section <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;gallery&quot;</span>&gt;</span> <br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/lochawe.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/lochawe.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lochawe.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/skull.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;skull.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/skull.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;skull.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/cammo.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cammo.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/cammo.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cammo.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/bavelaw.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;bavelaw.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/bavelaw.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;bavelaw.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/piano.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;piano.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/piano.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;piano.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/calton.jpg&quot;</span> <span style="color: #000066;">title</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;calton.jpg&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;lightbox&quot;</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://example.com/assets/images/thumbs/calton.jpg&quot;</span> <span style="color: #000066;">alt</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;calton.jpg&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;75&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span> <br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span></div></div>
<p>That&#8217;s it for the output side of things. But how do we get those thumbnails, and the medium image, where they&#8217;re meant to be?</p>
<h3>The Plugin</h3>
<p>I&#8217;ve called the plugin <i>thumbnailer</i>, but it actually does one other thing, which is generate a medium-sized version of the body photo, which is exactly the size required for the page.</p>
<p>As with the snippets I include an external file:</p>
<p><i>thumbnailer</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/plugins/thumbnailer/thumbnailer.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Notice the lack of PHP opening and closing tags. In plugins, unlike snippets, you always exclude them (and you always forget to.)</p>
<p>The one other thing to do to set up the plugin in the manager is check the <i>OnDocFormSave</i> System Event, as shown below.
<p>
<img src="/wp-content/uploads/2010/02/system_events.jpg" alt="" title="system_events" width="371" height="253" class="alignleft size-full wp-image-899" /></p>
<p></p>
<p><i>thumbnailer.php</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/ImageHelper.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">include_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'assets/bin/config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$gallery_category_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GALLERY_CATEGORY_NAME'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// The name of the body photo template variable</span><br />
<span style="color: #000088;">$body_photo_tmplvar</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_TMPLVAR'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Dimensions</span><br />
<span style="color: #000088;">$body_photo_width</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_WIDTH'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$body_photo_height</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BODY_PHOTO_HEIGHT'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumb_width</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_WIDTH'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumb_height</span> <span style="color: #339933;">=</span> <span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMB_HEIGHT'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Directory paths</span><br />
<span style="color: #000088;">$images_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMAGES_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$thumbs_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'THUMBS_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$medium_folder</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">constant</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MEDIUM_FOLDER'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$gal_vars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;A.id&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;modx_site_tmplvars A INNER JOIN modx_categories B ON A.category = B.id &quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;B.category = '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$gallery_category_name</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Generate the thumbnails</span><br />
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$gal_var</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRow</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$gal_vars</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000088;">$upload_file</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_REQUEST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tv'</span><span style="color: #339933;">.</span><span style="color: #000088;">$gal_var</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$upload_file</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$full_path</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #000088;">$upload_file</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$file_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">basename</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$full_path</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ImageHelper<span style="color: #339933;">::</span><span style="color: #004000;">resizeImage</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$images_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$thumbs_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$thumb_width</span><span style="color: #339933;">,</span> <span style="color: #000088;">$thumb_height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000088;">$body_photo_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getValue</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;modx_site_tmplvars&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;name = '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$body_photo_tmplvar</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'&quot;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Also create the medium-sized image</span><br />
<span style="color: #000088;">$upload_file</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_REQUEST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tv'</span><span style="color: #339933;">.</span><span style="color: #000088;">$body_photo_id</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$upload_file</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000088;">$full_path</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$modx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'base_path'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #000088;">$upload_file</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$file_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">basename</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$full_path</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Swap the dimensions if it's portrait</span><br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>ImageHelper<span style="color: #339933;">::</span><span style="color: #004000;">isPotrait</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$images_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$w</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$body_photo_width</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$body_photo_width</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$body_photo_height</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$body_photo_height</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$w</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; ImageHelper<span style="color: #339933;">::</span><span style="color: #004000;">resizeImage</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$images_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$medium_folder</span><span style="color: #339933;">.</span><span style="color: #000088;">$file_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$body_photo_width</span><span style="color: #339933;">,</span> <span style="color: #000088;">$body_photo_height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>&nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
<p>My first instinct when writing this was to use the MODx API to get the template variable values, but when the plugin runs it&#8217;s too early to do that, so we have to use $_REQUEST to get the form values directly from the editor. The naming scheme for template variable input elements is &#8220;tv[template variable id],&#8221; e.g. in my case it was <i>tv9</i> to <i>tv17</i> for the gallery variables.</p>
<p>For the thumbnails, we can get the same MySQL result that we used for the snippet (line 21), and then in the loop, concatenate the input name using the template variable IDs (line 28). For the body photo, we can get the name for the input by first getting the ID of the <i>body_photo</i> template variable based on its name (line 37).</p>
<p>For the resizing itself, I&#8217;ve used a small class called ImageHelper, which is kindly provided <a href="http://t.wits.sg/2009/02/07/howto-php-image-resize-centered-and-cropped/">here at Tips for Twits</a>. I&#8217;ll include the code here for completeness:</p>
<p><i>ImageHelper.php</i></p>
<div class="codecolorer-container php blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #000000; font-weight: bold;">class</span> ImageHelper <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; static <span style="color: #000000; font-weight: bold;">function</span> treatFilename<span style="color: #009900;">&#40;</span><span style="color: #000088;">$filename</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$newfilename</span> <span style="color: #339933;">=</span> <span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$filename</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$newfilename</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;_&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$newfilename</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$newfilename</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; static <span style="color: #000000; font-weight: bold;">function</span> isPotrait<span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">file_exists</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #339933;">!</span>ImageHelper<span style="color: #339933;">::</span><span style="color: #004000;">isLandscape</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; static <span style="color: #000000; font-weight: bold;">function</span> isLandscape<span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">file_exists</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$size</span> <span style="color: #339933;">=</span> <span style="color: #990000;">getimagesize</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$srcimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; static <span style="color: #000000; font-weight: bold;">function</span> resizeImage<span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destimage</span><span style="color: #339933;">,</span> <span style="color: #000088;">$width</span><span style="color: #339933;">,</span> <span style="color: #000088;">$height</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//if (!file_exists(realpath($srcimage)))</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//return;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$srcpathinfo</span> &nbsp;<span style="color: #339933;">=</span> <span style="color: #990000;">pathinfo</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$srcext</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcpathinfo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'extension'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$destpathinfo</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">pathinfo</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$destimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$destext</span> &nbsp;&nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$destpathinfo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'extension'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$size</span> &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">getimagesize</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$srcimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Get the size of the original image into an array [0]=&gt; width, [1]=&gt; height</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$image</span>&nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$canvas</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatetruecolor</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$width</span><span style="color: #339933;">,</span> <span style="color: #000088;">$height</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>&nbsp; <span style="color: #666666; font-style: italic;">// Prepare canvas</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Create a new image in the memory from the file </span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcext</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'wbmp'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'bmp'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatefromwbmp</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'jpg'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'jpeg'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatefromjpeg</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'png'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatefrompng</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'gif'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatefromgif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'xpm'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> imagecreatefromxpm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$srcimage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">default</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Calculate dimensions</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$widthratio</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/</span><span style="color: #000088;">$width</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$heightratio</span>&nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/</span><span style="color: #000088;">$height</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'ratio'</span> &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$widthratio</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'source_cropwidth'</span> &nbsp;<span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'source_cropheight'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'source_offsetx'</span> &nbsp;<span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'source_offsety'</span> &nbsp;<span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$heightratio</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$widthratio</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'ratio'</span><span style="color: #009900;">&#93;</span> &nbsp;&nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$heightratio</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_width'</span><span style="color: #009900;">&#93;</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_height'</span><span style="color: #009900;">&#93;</span> &nbsp;&nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropwidth'</span><span style="color: #009900;">&#93;</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$width</span> <span style="color: #339933;">*</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'ratio'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropheight'</span><span style="color: #009900;">&#93;</span> &nbsp;<span style="color: #339933;">=</span> <span style="color: #000088;">$height</span> <span style="color: #339933;">*</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'ratio'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_offsetx'</span><span style="color: #009900;">&#93;</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropwidth'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_offsety'</span><span style="color: #009900;">&#93;</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$size</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropheight'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #990000;">imagecopyresampled</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$canvas</span><span style="color: #339933;">,</span> <span style="color: #000088;">$image</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_offsetx'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_offsety'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$width</span><span style="color: #339933;">,</span> <span style="color: #000088;">$height</span><span style="color: #339933;">,</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropwidth'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$dimensions</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'source_cropheight'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$destext</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'jpg'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'jpeg'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">imagejpeg</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$canvas</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'png'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">imagepng</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$canvas</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'gif'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">imagegif</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$canvas</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'wbmp'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'bmp'</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">imagewbmp</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$canvas</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destimage</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #990000;">imagedestroy</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$canvas</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #990000;">imagedestroy</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$image</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>It takes care of cropping and resizing very nicely, and is the simplest and most effective code for this kind of circumstance that I&#8217;ve found.</p>
<p>So let&#8217;s say an editor has their document looking like this:</p>
<p><img src="/wp-content/uploads/2010/02/editor_photos.jpg" alt="" title="editor_photos" width="569" height="882" class="alignleft size-full wp-image-900" /></p>
<p>In the file system, the result of saving this document will be the following (with all other files excluded).</p>
<p><img src="/wp-content/uploads/2010/02/files.jpg" alt="" title="files" width="446" height="607" class="alignleft size-full wp-image-901" /></p>
<h3>Client-Side</h3>
<p>It&#8217;s a simple job to style the HTML output with CSS, so I won&#8217;t cover that. So, let&#8217;s briefly cover the lightbox. First it needs some CSS like this:</p>
<div class="codecolorer-container css blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #cc00cc;">#lightbox</span> <span style="color: #00AA00;">&#123;</span><span style="color: #000000; font-weight: bold;">display</span><span style="color: #00AA00;">:</span><span style="color: #993333;">none</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span><span style="color: #cc00cc;">#000000</span><span style="color: #00AA00;">;</span>opacity<span style="color: #00AA00;">:</span><span style="color: #cc66cc;">0.85</span><span style="color: #00AA00;">;</span>filter<span style="color: #00AA00;">:</span>alpha<span style="color: #00AA00;">&#40;</span>opacity<span style="color: #00AA00;">=</span><span style="color: #cc66cc;">85</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span><span style="color: #993333;">fixed</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span><span style="color: #933;">0px</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span><span style="color: #933;">0px</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">100%</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">height</span><span style="color: #00AA00;">:</span><span style="color: #933;">100%</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">z-index</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">1000</span><span style="color: #00AA00;">;</span><span style="color: #00AA00;">&#125;</span><br />
<span style="color: #cc00cc;">#lightbox-panel</span> <span style="color: #00AA00;">&#123;</span><span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">right</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">display</span><span style="color: #00AA00;">:</span><span style="color: #993333;">none</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span><span style="color: #993333;">fixed</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span><span style="color: #933;">100px</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span><span style="color: #993333;">transparent</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">z-index</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">1001</span><span style="color: #00AA00;">;</span><span style="color: #000000; font-weight: bold;">text-align</span><span style="color: #00AA00;">:</span><span style="color: #993333;">center</span><span style="color: #00AA00;">;</span><span style="color: #00AA00;">&#125;</span><br />
<span style="color: #cc00cc;">#lightbox-panel</span> a <span style="color: #00AA00;">&#123;</span><span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span><span style="color: #cc00cc;">#FEF9EB</span><span style="color: #00AA00;">&#125;</span></div></div>
<p>Recall that in the gallery each list item&#8217;s image link has <i>rel=&#8221;lightbox&#8221;</i>. We can use this in following code, which, aside from its dependence on jquery, is the entirety of the lightbox script (it doesn&#8217;t work in IE6 though, last time I checked &#8211; some tweaking required for that). </p>
<div class="codecolorer-container javascript blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;a[rel^='lightbox']&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">length</span><span style="color: #339933;">===</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> lightbox <span style="color: #339933;">=</span> <span style="color: #3366CC;">'&lt;div id=&quot;lightbox-panel&quot;&gt;<span style="color: #000099; font-weight: bold;">\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;img src=&quot;'</span><span style="color: #339933;">+</span> $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'href'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span><span style="color: #3366CC;">'&quot; alt=&quot;photo&quot; /&gt;&lt;br /&gt;<span style="color: #000099; font-weight: bold;">\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a id=&quot;close-panel&quot; href=&quot;[~[*id*]~]#&quot;&gt;Click anywhere or press Escape to close the image&lt;/a&gt;<span style="color: #000099; font-weight: bold;">\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;<span style="color: #000099; font-weight: bold;">\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;div id=&quot;lightbox&quot;&gt;&lt;/div&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span>lightbox<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">appendTo</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox-panel img&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'src'</span><span style="color: #339933;">,</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'href'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox, #lightbox-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeIn</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">300</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox-panel img&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;a#close-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'click'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox, #lightbox-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeOut</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">300</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;body&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'click'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox, #lightbox-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeOut</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">300</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">keydown</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">keyCode</span><span style="color: #339933;">===</span><span style="color: #CC0000;">27</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #006600; font-style: italic;">//Escape</span><br />
&nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#lightbox, #lightbox-panel&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeOut</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">300</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// DOM ready</span></div></div>
<p>Click on the photo below for a demo.</p>
<style>
/* LIGHTBOX */
#lightbox {display:none;background:#000000;opacity:0.85;filter:alpha(opacity=85);position:fixed;top:0px;left:0px;width:100%;height:100%;z-index:1000;}
#lightbox-panel {left:0;right:0;display:none;position:fixed;top:100px;background:transparent;z-index:1001;text-align:center;}
#lightbox-panel a {color:#FEF9EB}
</style>
<p><a href="/wp-content/uploads/2010/02/010.jpg" rel="lightbox"><img src="/wp-content/uploads/2010/02/010-150x150.jpg" alt="" title="010" width="150" height="150" class="alignright size-thumbnail wp-image-902" /></a></p>
<p></p>
<p>So there you have it. I hope you find it shapely, pleasingly simple, and easy to maintain.</p>
<p><script type="text/javascript" src="/examples/js/modx_gallery_lightbox.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/a-nice-and-simple-photo-gallery-solution-for-modx/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>The Magical MODx ManagerManager Plugin</title>
		<link>http://alistairrobinson.co.uk/the-magical-modx-managermanager-plugin/</link>
		<comments>http://alistairrobinson.co.uk/the-magical-modx-managermanager-plugin/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 01:22:23 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[MODx]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[managermanager]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.alistairrobinson.co.uk/blog/?p=744</guid>
		<description><![CDATA[My first MODx-powered website went live today, and my intention now is to share some of my experiences. From a development point of view MODx is so flexible that there are several ways of doing most things, so if like me you constantly fret about your architecture and constantly refactor your code for re-usability, you [...]]]></description>
			<content:encoded><![CDATA[<p>My first MODx-powered website went live today, and my intention now is to share some of my experiences. From a development point of view MODx is so flexible that there are several ways of doing most things, so if like me you constantly fret about your architecture and constantly refactor your code for re-usability, you might be confused about just what is the <i>best</i> way of doing things, especially if you&#8217;re just starting out. So in this and forthcoming posts I&#8217;ll be discussing some of my development techniques.</p>
<p>This post is mainly an introduction to the ManagerManager plugin written by <a href="http://www.rckt.co.uk/">Nick Crossland</a>. In my opinion it is absolutely indispensable, unless you&#8217;ve come up with your own way of doing the same thing. But it took me a while to get it. It&#8217;s possible I was just having a stupid day, but on my first encounter with it I was puzzled and frustrated for a while about how and when to use it, so maybe I can plug some gaps here. Let me just say again that this plugin is <i>absolutely indispensable</i>. Well, I guess you could get by without it, but at the very least it&#8217;s <i>very excellent</i>.</p>
<p>Essentially, it allows you to control how resources (also referred to as &#8220;documents,&#8221; mostly corresponding to web pages) are edited, depending on the role of the user and/or the template used by the resource. Using it you can customize and control the user-experience for content editors by changing, in several ways, the document fields and template variables that are available to users editing a resource. And you do all this by defining &#8220;rules&#8221; in a single rules file or chunk.</p>
<h3>Install</h3>
<p>Before I go into what exactly you can do with it, here&#8217;s how to set it up. ManagerManager came bundled with my MODx 1.0.2 installation, but you can also <a href="http://modxcms.com/extras/package/255">get the package from the MODx website.</a> The two things to look out for in the download are <span class="inline_code">plugin.txt</span> and the <span class="inline_code">managermanager</span> folder. Put that folder in <span class="inline_code">yoursite.com/assets/plugins</span> and go to <span class="inline_code">yoursite.com/assets/plugins/managermanager/docs</span> in a browser to read the documentation (you can also see it <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/">here on my site</a> if you haven&#8217;t downloaded it yet).</p>
<p>In the documentation you get details on installing and setting up, but I&#8217;ll briefly go over the steps here. Basically all that&#8217;s left to do at this point is to create the plugin in MODx with the contents of <span class="inline_code">plugin.txt</span>. Go to <span class="inline_code">Elements > Manage Elements > Plugins > New Plugin</span> and paste in the code, then check the System Events described in the docs, and then paste in the configuration string in the Configuration tab. The string looks like this:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&amp;config_chunk=Configuration Chunk;text; &amp;remove_deprecated_tv_types_pref=Remove deprecated TV types;list;yes,no;yes &amp;which_jquery=jQuery source;list;local (assets/js),remote (google code),manual url (specify below);remote (google code) &amp;js_src_type=jQuery URL override;text;</div></div>
<p>By the way, if you&#8217;re not aware, configuration parameters are defined like this:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&amp;name=Description;datatype;value</div></div>
<p>So in the configuration string for ManagerManager given above, it sets up a text-field parameter called <span class="inline_code">config_chunk</span> but leaves it blank. If you want to use a chunk to manage your rules, put the name of it in here. My MODx installation already had the chunk <span class="inline_code">mm_demo_rules</span>.</p>
<p>When the plugin runs, it looks for rules in the chunk that you&#8217;ve defined in the configuration tab, but if that chunk is empty or nonexistent or <i>not</i> defined in the configuration tab (as in my case), then it looks in the file <span class="inline_code">managermanager/mm_rules.inc.php</span>. I use this file for my rules rather than a chunk, but it&#8217;s a matter of taste. Note that if there&#8217;s something in the chunk (and the chunk is defined in the configuration), none of the rules in the file will be applied, because the file won&#8217;t even be included.</p>
<h3>The Rules</h3>
<p>So what do the rules actually look like? Basically they&#8217;re function calls. All of them are described in the documentation, in the <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/fields.htm">Fields</a>, <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/tabs.htm">Tabs</a>, <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/widgets.htm">Widgets</a> and <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/sections.htm">Sections</a> pages, and the names to use to refer to the fields are described in <a href="http://www.alistairrobinson.co.uk/examples/managermanager/docs/field-names.htm">Field names</a>. Note that the although these field names mostly correspond to the MODx database field names, not all of them do.</p>
<p>Here&#8217;s an example rule:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_renameField('longtitle','Page heading');</div></div>
<p>Your rules file or chunk is just a bunch of these calls, and every time somebody edits a resource, they will be applied. Easy.</p>
<h3>Hiding Fields</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// Hide these fields for resources using templates 3 and 5,<br />
// for all users except administrators<br />
<br />
mm_hideFields('alias,link_attributes,introtext,menutitle,menuindex,show_in_menu', '!1', '3,5');</div></div>
<p>You may want to hide fields from users who are editing certain resources, because you don&#8217;t want those values to be changed. Say you want to fix the value of the parent resource, or you want to ensure that <span class="inline_code">Show in menu</span> is always set to true and can&#8217;t be changed. Or maybe you just don&#8217;t want to confuse users with too many fields (if there&#8217;s no need for them to see the <span class="inline_code">URL alias</span> or <span class="inline_code">Link Attributes</span> fields, why not hide them?).</p>
<p>One of my uses for this is hiding the resource content editor for templates that contain only dynamic data such as tables, feeds, blog post excerpts, and so on. For these pages, all the content is generated by snippets, in combination with chunks, and anything entered as content by the user will not show up (because in the templates and chunks I&#8217;m not using the <span class="inline_code">[*content*]</span> field at all) &#8211; so it makes sense to remove that functionality.</p>
<h3>Setting Default Values</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// Set the default value for the content_type field to<br />
// &quot;application/pdf&quot;, for resources using template 10,<br />
// for all users<br />
<br />
mm_default('content_type', 'application/pdf', '', '10');</div></div>
<p>You may want to ensure that certain resources always have the same default value for particular fields. I used this recently when I wanted to set the value of <span class="inline_code">content-type</span> to <span class="inline_code">application/pdf</span> by default. I saw this as a must-have feature, rather than a nice-to-have, because one of the main ongoing actions of editors of this site was to add new PDF documents, the links to which would then be displayed by a snippet in various parts of the site.</p>
<p>Incidentally, this only made sense if I could make sure that the resources in question had a specific default template, so I also used my own plugin to automatically set the template for these resources. I didn&#8217;t realize at the time, but I probably could have used an MM rule for that too, namely <span class="inline_code">mm_hideTemplates</span> (see below).</p>
<h3>Renaming Fields</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_renameField('longtitle','Page Heading');</div></div>
<p>Renaming fields changes their labels. One way that I used this was to change &#8220;Long title&#8221; to &#8220;Page heading,&#8221; because that&#8217;s how I was using <span class="inline_code">[*longtitle*]</span>, i.e. as the &lt;h1&gt; heading (in other words, in the relevant chunk I had <span class="inline_code">&lt;h1&gt;[*longtitle*]&lt;/h1&gt;</span>). Changing the label just made it clearer for users. The flexibility of MODx means that, by default, fields are named in a fairly abstract way, because you can use them however you want, so more meaningful labels are often better, once you&#8217;ve settled on how you&#8217;re going to use them.</p>
<h3>Changing the Help Text</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_changeFieldHelp('longtitle','This is the main heading that appears at the top of the main content. It\'s also the name that appears in navigation menus and links.');</div></div>
<p>This way you can help to tailor the user&#8217;s experience to the specific functionality of your implementation. If you&#8217;ve customized things to a great extent, some of the help text will begin to be useless or even misleading, so it&#8217;s good to keep things tight by paying attention to stuff like this.</p>
<h3>Synching Fields</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_synch_fields('pagetitle,menutitle,longtitle');</div></div>
<p>Use this to ensure that fields always have the same value. I haven&#8217;t used this myself, but I&#8217;m sure I will.</p>
<h3>Inheriting Values From the Parent Resource</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_inherit('pagetitle,longtitle');</div></div>
<p>Does what it says on the tin.</p>
<h3>Hiding Templates</h3>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mm_hideTemplates('0');</div></div>
<p>The above example removes the <span class="inline_code">(blank)</span> template from the <span class="inline_code">Uses Template</span> drop-down. As I noted above, it looks like I could have used this when I needed to set a default template by hiding all the other templates from the drop-down list, instead of using my own plugin. I haven&#8217;t tried it though.</p>
<h3>Tabs, Widgets and Sections</h3>
<p>There are also a number of functions for changing the tabs and sections. For example, if you want to restrict users to editing the content field and nothing else, hide the <span class="inline_code">Settings</span> tab as well as hiding fields in the <span class="inline_code">General</span> tab. Sections, by the way, are a MODx way of grouping fields together in the edit screen. Common ones you&#8217;ll see are &#8220;Resource content&#8221; and &#8220;Template variables.&#8221; As for widgets, ManagerManager provides a few functions for changing the widget that is rendered for a field, eg. colour-picker or image preview.</p>
<p></p>
<p>With careful combinations of rules, and any logic you fancy putting in the rules file, you can get as clever as you like.</p>
<p>For more information on ManagerManager have a look at the <a href="http://modxcms.com/forums/index.php/board,349.0.html">dedicated board on the MODx forum</a>.</p>
<p>For the next MODx-related post&#8230;I&#8217;m not sure. One thing I&#8217;ve found interesting: I struggled for a while to find a satisfying way of combining two requirements regarding javascript. 1) How to manage and maintain my javascript files easily and avoid any duplicated code; and 2) also ensure that the resulting page is optimized for speed (sometimes I find it quite hard to settle for a <a href="https://addons.mozilla.org/en-US/firefox/addon/5369">YSlow</a> grade of B). I&#8217;d love to see how other developers manage this in MODx.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/the-magical-modx-managermanager-plugin/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>FoxyCart: Replacing A Cart Item</title>
		<link>http://alistairrobinson.co.uk/foxycart-replacing-a-cart-item/</link>
		<comments>http://alistairrobinson.co.uk/foxycart-replacing-a-cart-item/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 13:14:16 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[ecommerce]]></category>
		<category><![CDATA[foxycart]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[shopping cart]]></category>

		<guid isPermaLink="false">http://www.alistairrobinson.co.uk/blog/?p=658</guid>
		<description><![CDATA[function add_pre_process&#40;&#41; &#123; &#160; //Find the id of the existing registration in the cart, if it does exist &#160; $.each&#40;fc_json.products, function&#40;key, product&#41; &#123; &#160; &#160; if&#40;product.name==&#34;Registration&#34;&#41; &#123; &#160; &#160; &#160; // Do the remove request, with parameter quantity=0 &#160; &#160; &#160; $.ajax&#40;&#123; &#160; &#160; &#160; &#160; async: false, &#160; &#160; &#160; &#160; type: &#34;GET&#34;, &#160; [...]]]></description>
			<content:encoded><![CDATA[<div class="codecolorer-container javascript blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">function</span> add_pre_process<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">//Find the id of the existing registration in the cart, if it does exist</span><br />
&nbsp; $.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span>fc_json.<span style="color: #660066;">products</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>key<span style="color: #339933;">,</span> product<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>product.<span style="color: #000066;">name</span><span style="color: #339933;">==</span><span style="color: #3366CC;">&quot;Registration&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">// Do the remove request, with parameter quantity=0</span><br />
&nbsp; &nbsp; &nbsp; $.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; async<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; type<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;GET&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; url<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;https://mydomain.foxycart.com/cart?output=json&amp;cart=update&amp;id=&quot;</span><span style="color: #339933;">+</span>product.<span style="color: #660066;">id</span><span style="color: #339933;">+</span><span style="color: #3366CC;">&quot;&amp;quantity=0&amp;callback=?&quot;</span> <span style="color: #339933;">+</span> fc_AddSession<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; dataType<span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #006600; font-style: italic;">// Add the new one</span><br />
&nbsp; add_item<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #003366; font-weight: bold;">function</span> add_item<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">//Get the form data</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> submitted_data <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#signup&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">serialize</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #006600; font-style: italic;">//Do the add request</span><br />
&nbsp; $.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; type<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;GET&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; url<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;https://mydomain.foxycart.com/cart?&quot;</span><span style="color: #339933;">+</span>submitted_data<span style="color: #339933;">+</span><span style="color: #3366CC;">&quot;&amp;callback=?&quot;</span> <span style="color: #339933;">+</span> fc_AddSession<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; dataType<span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>This javascript/jQuery code gets the contents of your cart (which is in the variable fc_json, made available by foxycart_includes.js), removes any item whose name matches a certain string, and then adds your new item. It looks so obvious now, but it took a while for me to get it.</p>
<p>I&#8217;m working on a shopping cart at the moment, and it&#8217;s my first day with <a href="http://www.foxycart.com/" title="">FoxyCart</a>, which is a really nice solution for a common but pretty badly-catered-for requirement (ie. online shopping carts and checkouts). I wanted to just plug and play: just set up a few templates for the cart, checkout and email receipt, and go with that, because FoxyCart is pretty nice without too much customization. But things are rarely so simple. The website will be selling not only products in a shop, but registrations to an event. Yep, that&#8217;s still easy, but a registration can be for multiple attendees, and the registrant needs to fill in the same information about each of them as he did for himself, and some of that information determines the price.</p>
<p>So the registrant&#8217;s gone through the whole process of filling in the forms for each attendee, and they get to their registration summary page, and there&#8217;s a list of the names of the attendees with the cost for each one (which depends on what information was supplied, what boxes were ticked), and a grand total at the bottom. This is all before they get to the shopping cart. It&#8217;s true that when adding to the FoxyCart cart you can supply it with options and corresponding prices, and this would have been good for allowing for the selection of multiple attendees; but it wouldn&#8217;t have allowed for the entry of all the attendee-specific details and their corresponding prices.</p>
<h3>A Problem</h3>
<p>So they hit &#8220;Add to cart&#8221; and then &#8220;Checkout&#8221; and everything&#8217;s great &#8211; if that&#8217;s the only thing they do. But what if, after adding the registration to the cart, they go back and change the details for an attendee, thereby changing the price? First of all I set the quantity_max parameter to 1 to prevent them adding it twice. But if what you&#8217;re adding has a different price, it&#8217;s treated as a different item. If they click to update the cart with a registration that comes to a different price from the one they previously added, the amended registration is <i>added as a new product</i>, so that they now have two in the cart.</p>
<p>It seems odd that FoxyCart gets stuck on this, and I thought there must be some parameter I could use, but I couldn&#8217;t find it. The solution had to be to either somehow update the price of the item in the cart, or remove any registration in the cart before adding the amended one. I ended up using the latter. To do it requires JSON AJAX requests, which you can do in jQuery with $.getJSON or $.ajax. Anyway, I quickly arrived at the essential logic on which the above code is based. But I couldn&#8217;t get it to work.</p>
<p>I was led first of all to use the fc_PreProcess() function. From reading the documentation it seemed that I should define a function called fc_PreProcess, put all the code inside that, and then the included FoxyCart javascript file would find my function definition and execute it prior to adding anything to the cart. Sounds perfect, I thought.</p>
<p>Here&#8217;s how it didn&#8217;t work. You add a registration to the cart, close the cart, amend your registration so that it now has a new price, and then add to the cart again (although as far as the user is concerned they are <i>updating</i> the cart), at which point the new one should be substituted for the old. And at first it seemed to work: only one registration item in the cart, and with the new price too! I cheered at the time, until I clicked &#8220;checkout&#8221; to find that the item had just fallen out. And doing it all again I saw that in the cart itself the item would disappear if you refreshed it.</p>
<p>What seemed to be happening was that even though the item was displayed in the cart, it had since disappeared. The item was being removed <i>after it was added</i>; more precisely: a new one was added, making a total of two items; the cart was displayed; and then my code found and removed both items. I&#8217;m still not quite sure how this happened, but blame may lie in the asynchronous nature of the JSON calls, mixed use of http and https, sessions, or in my lack of sleep.</p>
<h3>A Solution</h3>
<p>So what you see above is the hand-made solution. The &#8220;add to cart&#8221; or &#8220;update cart&#8221; button on my registration summary page doesn&#8217;t submit the form, it just executes the function add_pre_process(), which looks for an existing registration and removes any it finds; and then adds the new one. There is a separate &#8220;View cart&#8221; button.</p>
<p>Ideally I would have liked to use the success callback of the ajax request in add_item(), but it doesn&#8217;t fire.</p>
<p>So, the problem seems to be solved, but not <i>properly</i> solved. The question now is do I spend time investigating what the problem was and delve deep into the workings of FoxyCart, or move on to the next stage, which is the shop. Well, I&#8217;ve got two websites going live in the first week of January, so it&#8217;s no contest. Onwards!</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/foxycart-replacing-a-cart-item/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Web Development Frameworks: Developing For vs. Developing With</title>
		<link>http://alistairrobinson.co.uk/web-development-frameworks-developing-for-vs-developing-with/</link>
		<comments>http://alistairrobinson.co.uk/web-development-frameworks-developing-for-vs-developing-with/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 00:16:40 +0000</pubDate>
		<dc:creator>Alistair</dc:creator>
				<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://www.alistairrobinson.co.uk/blog/?p=641</guid>
		<description><![CDATA[I&#8217;ve been hunting for a web development framework for a few months. Back in the summer I was immersed in CSS and javascript, just sticking with my tried and tested server-side techniques. Using the TinyButStrong (TBS) template class I could put together a highly organized dynamic website pretty quickly. In retrospect it seems that I&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been hunting for a web development framework for a few months. Back in the summer I was immersed in CSS and javascript, just sticking with my tried and tested server-side techniques. Using the TinyButStrong (TBS) template class I could put together a highly organized dynamic website pretty quickly. In retrospect it seems that I&#8217;d found my own path towards an MVC-like pattern: nothing but HTML and logic-less TBS tags in the templates; PHP pages acting like controllers, for form processing and manipulating data; and a class for each table in the database (more or less). Very neat. Framework junkies amongst you could tell me exactly why this isn&#8217;t really MVC, but I don&#8217;t care.</p>
<p>Anyway, my first intention was to stick with PHP, so I was led to have a look at the <a href="http://codeigniter.com/">CodeIgniter</a> framework after I watched a couple of <a href="http://net.tutsplus.com/videos/screencasts/codeigniter-from-scratch-day-1/">excellent tutorial screencasts</a> by Jeffrey Way on <a href="http://net.tutsplus.com">nettuts</a>. But then I discovered <a href="http://www.kohanaphp.com/">Kohana</a>, originally a fork of CodeIgniter but apparently better in several ways. Last time I checked, CodeIgniter was very PHP4-centric, whereas Kohana is most definitely a PHP5 beast, with all the OO stuff that entails.</p>
<p>I haven&#8217;t been able to use it in anger yet, but I&#8217;ve set a few things up with it, and it gives me a nice warm feeling. It seems really lean and simple and built in the right spirit, and it didn&#8217;t take me as long to get my head around the MVC pattern as I&#8217;d expected.</p>
<p>The thing is, now I find my thoughts drifting into alien territory&#8230;</p>
<p>This goes back to my <a href="http://www.alistairrobinson.co.uk/blog/web-development-and-chopping-garlic/">previous post</a> about web development choices. The more I look, the more confused I become. I wouldn&#8217;t consider anything Java or .NET, so in the area I&#8217;m looking at the big [puts on suit and pulls a sombre, earnest expression] <b>SERIOUS</b> frameworks seem to be <a href="http://rubyonrails.org/">Ruby on Rails</a> and <a href="http://www.djangoproject.com/">Django</a>. I&#8217;ve been trying out Python with the Google App Engine, and I forgot how great it was to learn a new programming language, so Django &#8211; a Python framework &#8211; looks like a good way to go. But something in me cries out NO &#8211; do I really need all that stuff? Look, there&#8217;s this guy over here says Django&#8217;s too big and bloated; but wait, there&#8217;s <i>that</i> guy over <i>there</i> says with Django he can spit out ten amazing websites every day.</p>
<p>But coalescing out of my confusion is the perception of a contrast in the community, and for those who build websites and web apps it&#8217;s good to be aware of this. On the one hand there are those whose overriding concerns arise from their work in creating and maintaining the frameworks themselves; and on the other hand there are those who just want to make websites. This became obvious to me after watching two video talks from DjangoCon 2008 (yes, I&#8217;m still catching up with all this), <a href="http://www.youtube.com/watch?v=fipFKyW2FA4">one by Mark Ramm</a>, one of the guys behind TurboGears (another Python framework), and the <a href="http://www.youtube.com/watch?v=A-S0tqpPga4">other by James Bennett</a>, one of the Django guys.</p>
<p>Now, I&#8217;m aware that the subjects of these talks were quite different, and pitched at different levels, but nevertheless I do think it&#8217;s fruitful to compare them.</p>
<p>Mark Ramm seemed most interested in guiding the philosophy of the Python community, about the future of Python frameworks and how they should be taken forward. In particular he criticized the &#8220;monolithic,&#8221; all-things-to-all-people approach of Django, opposing it to the Turbogears/Pylons approach, which is to open things up, to make it easy (even <i>necessary</i>) for developers to grab this bit here and that bit there and carefully craft an optimal whole. His standpoint reflected his immersion in developing <i>for</i> &#8211; or the development <i>of</i> &#8211; web app frameworks.</p>
<p>James Bennett&#8217;s focus was on developing <i>with</i> frameworks &#8211; that is, building web applications &#8211; rather than on how best to build the frameworks themselves. He talked about the most efficient ways to approach the development of an application using Django, for maximum code re-use and maintainability.</p>
<p>Of course, these are not implacably opposed positions: it&#8217;s just a difference of focus. Both may be right in their own ways, but as a freelance developer of &#8211; currently &#8211; small to medium websites, I naturally find James Bennett&#8217;s focus on the day-to-day business of making a web app much more appealing.</p>
<p>It might be true, as Mark Ramm says, that you don&#8217;t get perfection by installing everything in one bundle and just running with it, but to me that&#8217;s rather academic. Everyone is agreed that the purpose of frameworks is to free us from the boring repetitive tasks of this line of work. We shouldn&#8217;t have to even <i>think</i> about admin interfaces, form-handling, nice URLs, templating, or ORM data-mapping. But further, I just want <i>some one thing</i> that does all that pretty well. If I have to pick and choose between different combinations, and try to get all the bits working nicely together, then I&#8217;m <i>thinking</i> about it: I&#8217;m wasting my time. I don&#8217;t want to think about the optimal key set-up of a saxophone &#8211; I just want to make music (is that a cheesy analogy?)</p>
<p>Before I realized this I struggled to stay a course through the choices facing me, taken first in one direction and then another, each with its own passionate and persuasive adherents. But now, even if the two approaches I&#8217;ve perceived are just sides of the same coin, I can use this idea of a dichotomy to sort and prioritize the opinions I find.</p>
<p>However, I now find myself considering having a go at building a web app with Haskell, a functional programming language beloved of geniuses, hippies, mad scientists and my good friend <a href="http://miremare.wordpress.com/">Paul Keir</a> (who might fall in all three of those categories). The introductory message at <a href="http://www.haskell.org/">haskell.org</a> has the words ADVANCED, PURE, CUTTING EDGE, RESEARCH, CORRECT, and PARALLELISM (eh?). That&#8217;s all a bit scary to me.</p>
]]></content:encoded>
			<wfw:commentRss>http://alistairrobinson.co.uk/web-development-frameworks-developing-for-vs-developing-with/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

