<?xml version="1.0" encoding="utf-8"?>
	<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	
		<title type="text">Blog &#45; John D Wells</title>
		<subtitle type="text"></subtitle>
		<link rel="alternate" type="text/html" href="http://johndwells.com/blog/" />
		<link rel="self" type="application/atom+xml" href="http://johndwells.com/blog/atom" />
		<updated>2011-08-19T03:14:16Z</updated>
		<rights>Copyright (c) 2011, John D Wells</rights>
		<generator uri="http://expressionengine.com/" version="2.4.0">ExpressionEngine</generator>
		<id>tag:johndwells.com,2011:01:23</id>
	
		
			<entry>
				<title>Of The Social Contract, Or Principles of&#8230; Commercial Add&#45;On Development</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/of-the-social-contract-or-principles-of-commercial-add-on-development" />
				<id>tag:johndwells.com,2011:blog/3.61</id>
				<published>2011-02-27T12:00:57Z</published>
				<updated>2011-02-27T19:01:59Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>Thanks to the devot:ee Store, it has never been easier to turn a little pet add-on into a commercial profit-maker. And no doubt the prospect of earning dosh for brilliance has attracted strong talent to the EE community. But amidst this fevered gold rush, are we customers getting our money&#8217;s worth?</p>
					<p>
	This is a topic I&#39;ve been chewing on for a while - biting my tongue at times - struggling to formulate my thoughts into something constructive. In the two years since becoming part of the amazing EE community, a lot has changed. One particularly significant change is a swift and steady move towards commercial add-on development - <em>a move that is starting to feel more like a greed-fueled money-grab, than an indication of higher quality software</em>.</p>
<p>
	Don&#39;t get me wrong: I am all for commercial add-ons. <a href="http://onedarnleyroad.com">At our studio</a> we lobby every day to convince clients that <em>our time and expertise</em> is worth the money we charge. Developers of quality software are equally deserving of fair compensation. So what I am not saying is that I will not pay for your add-on.</p>
<blockquote>
	<p>
		I will happily pay for your add-on. But as a paying customer, I will expect a certain level of product and service.&nbsp;<em>I will expect to get my money&#39;s worth.</em></p>
</blockquote>
<p>
	If you plan to develop commercial add-ons for ExpressionEngine, understand what you are agreeing to - understand that you are becoming part of the&nbsp;<strong>EE Community</strong>, and as such are expected to uphold the spirit of that community: generosity, transparency, responsibility, and professionalism. We are an incredibly eager group of talented professionals that <em>wish to see each other succeed as much as ourselves</em>.</p>
<p>
	In that spirit, here are 10 <a href="http://www.viceland.com/int/dos.php">"DOs" and "DON&#39;Ts"</a> of commercial add-on development that I think we all should live by:</p>
<h2>
	1. I will... Put my name on it</h2>
<p>
	Take for example just a few pillars of greatness:&nbsp;<a href="http://pixelandtonic.com">Brandon Kelly</a>, <a href="http://ee-garage.com">Leevi Graham</a>, <a href="http://masugadesign.com">Ryan Masuga</a>, <a href="http://boldminded.com">Brian Litzinger</a>&nbsp;(I could go on)... I inherently trust and am willing to invest in their add-ons, not simply because from experience I know them to be excellent, but because they put their name on it. They have placed their personal reputation on the line, alongside the reputation of the software they build, which demonstrates a long-term commitment to keeping their products up-to-date and feature-rich. It&#39;s also peace of mind that if something goes wrong, <em>I will know who to turn to for help</em>.</p>
<p class="aside" style="text-align: center">
	<a href="http://lobsterwarmachine.com/" style="border: 0 !important"><img alt="" src="http://johndwells.com/content/uploads/default/lobster-war-machine.png" style="width: 123px; height: 98px; " /></a><br />
	"I smile favorably upon you."</p>
<p>
	Marketing yourself under a clever name is totally fine, just be sure to let us know who&#39;s behind it. &nbsp;<a href="http://lobsterwarmachine.com">L</a><a href="http://lobsterwarmachine.com">obster War Machine</a> is an excellent (and hilarious) example - it takes just a few seconds on the website to know that <a href="http://jackmcdade.com">Jack McDade</a> is the LWM developer - yes, the same Jack behind the indespensible&nbsp;<a href="http://buildwithstructure.com">Structure</a>&nbsp;(also brought to you by <a href="http://rockthenroll.com">Travis Schmeisser</a>).</p>
<p>
	See how much you suddenly trust that gnarly-looking crustacean?</p>
<h2>
	2. I will... Register my add-on with devot:ee</h2>
<p>
	I shouldn&#39;t need to mention this one, but better safe than sorry. Even if you decide to sell your add-on <a href="http://codecanyon.net/">elsewhere</a>, it&#39;s immensely helpful to have your add-on registered on <a href="http://devot-ee.com">devot:ee</a>. And when you do put your add-on up on devot:ee, give as much information as possible: compatibility with other add-ons, hooks used, documentation links, image previews, etc.</p>
<h2>
	3. I will... Provide publically-accessible support</h2>
<p>
	Prior to the launch of EE2, probably 99% of all EE Community activity took place in the <a href="http://expressionengine.com/forums">forums</a>, and for many of us this remains a natural format for seeking &amp; offering help when things go wrong. &nbsp;EllisLab no longer hosts 3rd party add-on support on their forums, but that&#39;s where&nbsp;<a href="http://devot-ee.com">devot:ee</a>&nbsp;has once again stepped in - with every add-on submitted, a specific forum is instantly made available (whether you like it or not, which I think is <em>brilliant</em>).</p>
<p>
	If for some reason you don&#39;t want to use devot:ee&#39;s forums, then consider&nbsp;<a href="http://getsatisfaction.com">Get Satisfaction</a> or <a href="http://tenderapp.com/">Tender Support</a>. &nbsp;But please, offer more than an email address to send to. To me that either says:</p>
<ul>
	<li>
		You don&#39;t want to broadcast to the world when someone encounters a problem with your product, or</li>
	<li>
		You will probably not respond in a timely manner to my support request, but do not want evidence of your slow response time, or</li>
	<li>
		You&#39;re just lazy</li>
</ul>
<h2>
	4. I will... Maintain comprehensive and up-to-date documentation</h2>
<p>
	This is critical, and if you do not take documentation seriously, then I will not take your product seriously. Document everything that relates to:</p>
<ul>
	<li>
		pre-sales questions, such as features, screenshots, video demos, software requirements, 3rd party compatibilities</li>
	<li>
		installation, upgrades, release notes, general usage guidelines</li>
	<li>
		FAQs, common pitfalls, what to do when something goes wrong</li>
</ul>
<h2>
	5. I will... Charge an appropriate pricetag</h2>
<p class="aside">
	<em>At times I&#39;ve considered building open-source alternatives to commercial add-ons that I didn&#39;t think were worth paying for... Clearly <a href="http://wiseupstudio.com/expressionengine/">I&#39;m not the only one</a>.</em></p>
<p>
	Yeah, this is a tough one. With every product there is a sweet spot for pricing, and the EE market is perhaps still too fresh to know exactly how to calculate this number. &nbsp;And in theory yes,&nbsp;<em>if your client wants the capability your add-on provides, then your client should be willing to pay for it</em>.</p>
<p>
	Still I think it&#39;s only reasonable to be sure the pricing of your add-on fits appropriately alongside the baseline cost of EE - $300 USD. Second, consider that sometimes your add-on is as much for the person building the site, as it is for the client requesting a particular feature (<a href="http://devot-ee.com/add-ons/low-variables/">Low Variables</a> is a good example). In which case a lower price point might gain a higher sales volume, making you more money in the long run.</p>
<blockquote>
	<p>
		I can&#39;t help but feel some #eecms commercial addons are just taking the piss charging.</p>
	<p class="attribution">
		<a href="http://twitter.com/#!/leevigraham/status/41796482910797824">@leevigraham via twitter</a>, about 30 seconds ago</p>
</blockquote>
<p>
	If your add-on adds considerable capability to a site, such as&nbsp;e-commerce options <a href="http://brilliantretail.com">BrilliantRetail</a> and <a href="http://cartthrob.com">CartThrob</a>, then you are more justified in charging a higher amount. Again, look to EE for a guide - the Discussion Module for EE is $100 USD.</p>
<p>
	However if your add-on simply scratches an itch or does something very specific, I&#39;d price it very carefully - personally anything above $25 USD and I will start to seriously hold your feet to the fire on this entire list.</p>
<h2>
	6. I will not... Build it once and never update it again</h2>
<p>
	Strangely, when I see a commercial add-on staying at or near a "version 1.0" release for ages, it tells me the developer has checked out. &nbsp;Either that, or it was such a simple add-on to begin with that there&#39;s nothing else to do to make it better. Perhaps then I can just build it myself in a day or two (or an hour or two).</p>
<h2>
	7. I will not... Release something utterly broken</h2>
<p>
	Sounds absurd, right? You&#39;d be surprised - just last week I purchased an add-on that straight out-of-the-box didn&#39;t work. It was missing an important file, which is a simple mistake but potentially costly - and more importantly not professional. The developer behind the add-on was extremely swift in resolving the issue (and even went so far as to give me a free preview to another of their commercial add-ons), but it still stung. &nbsp;It will take a lot to regain my trust in that developer.</p>
<h2>
	8. I will not... Charge you for an add-on that I developed for a client</h2>
<p class="notice">
	<em><strong>Update:</strong> community feedback has challenged this one quite a bit. The general consensus agrees that if the client is aware of your plans to release a commercial product off the back of a job, then fair is fair. Again, the overall message of this is about ensuring the spirit of the commercial venture is pure. Jump to the comments for more.</em></p>
<p>
	I realise this is possibly contentious, but it plain&nbsp;<em>seems a bit cheeky</em> to be paid by a client to develop a bespoke plugin, and then turn around and charge us as well. It reminds me of the <a href="http://www.youtube.com/watch?v=1J3w4cS2MvM">Costanza&#39;s double dip fiasco</a>:</p>
<blockquote>
	<p>
		You dipped the chip, you took a bite, and you dipped again... that&#39;s like putting your whole mouth in the dip!!</p>
</blockquote>
<p>
	Here&#39;s the thing: when you were paid by your client to build that bespoke plugin, I&#39;m 100% certain that at some point, you got help from the community at large - either by pulling apart someone else&#39;s add-on, sending out a tweet, or getting help in a forum. &nbsp;With that help, you delivered a product to your client and were paid (handsomely I hope) for it. And as thanks to us, you turn around and charge us money to use it? Come on.</p>
<p>
	The possible exception to this is if you <strong>promise</strong>&nbsp;to obey the #6&nbsp;<em>I will not...</em> rule and commit to making the add-on better and better over time.</p>
<h2>
	9. I will not... Encrypt my software with IonCube or similar</h2>
<p>
	Not everyone will agree with me on this one either, but <em>encrypting PHP code that I paid for sucks</em>. It seems to go completely against the spirit of PHP in general, but certainly against the spirit of the EE community. If nothing else, it ties my hands to investigate potential bugs or issues with the purchased software - I am out of luck to help myself, at the mercy of the developer to (hopefully) provide me with an update.</p>
<h2>
	10. And if you won&#39;t...</h2>
<p>
	Well, I don&#39;t think you should be selling your add-on. Look, I&#39;m not trying to shut the door on anyone, but I worry about our collective future successes. &nbsp;Change is afoot in the EE universe, and I think it&#39;s only prudent that we do what we can to ensure we are changing in the right direction, and <em>for the right reasons</em>. &nbsp;Pure, unadulterated profit should not be one of them. &nbsp;And in fairness, the above should apply to any commercial software product, and shouldn&#39;t be unique to ExpressionEngine.</p>

				]]></content>
			</entry>
		
			<entry>
				<title>EE Hive&#8217;s Flickr for ExpressionEngine2 now available on GitHub. Wygwam integration coming soon.</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/ee-hive-flickr-for-expressionengine2-now-available-on-github-wygwam" />
				<id>tag:johndwells.com,2011:blog/3.58</id>
				<published>2011-02-11T15:55:47Z</published>
				<updated>2011-02-11T10:42:48Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>Known simply as &#8216;Flickr&#8217;, this modest yet powerful EE2 add-on fully integrates Flickr into your website. <em>And it&#8217;s awesome</em>.<br />Flickr is now Matrix2 compatible, and even more awesomeness is on the way - like integration with Wygwam.</p>
					<p class="aside">
	<em>What are you waiting for?</em><br />
	<a href="http://github.com/ee-hive/Flickr-for-ExpressionEngine">Get Flickr for EE2 now on Github.</a></p>
<p>
	First of all, this is a big shout out to <a href="http://www.brettdewoody.com/">Brett DeWoody</a> and the clever chaps at EE Hive / <a href="http://www.digitalwaxworks.com/">Digital Wax Works</a>. Not only have they built an already brilliant add-on, <em>not only have they released it for free</em>, but they&#39;ve invited other EE developers (like me) to get involved and help make Flickr even better.</p>
<p>
	<strong>I&#39;ve really taken this open source opportunity to heart,</strong> and have begun (perhaps over-enthusiastically) contributing to the project.&nbsp; First order of business was to restore <a href="http://pixelandtonic.com/matrix">Matrix2</a> compatibility, which was completed just prior to its release on Github. This week I&#39;ve been busy with another feature...</p>
<h2>
	Flickr button for Wygwam</h2>
<p>
	I could go on and on (<em>and on</em>) about how awesome <a href="http://pixelandtonic.com/wygwam">Wygwam</a> is - which is also a heavy endorsement for <a href="http://ckeditor.com/">CKEditor</a> as a whole - but I&#39;ll leave that for another time. But as I was first setting up Flickr as a custom fieldtype for a current project, <em>I just knew</em> that my client was going to eventually ask how he could embed a Flickr image into his Wygwam field. I imagined the conversation going something like:</p>
<blockquote>
	<p>
		Open Flickr in a 2nd browser tab, and find the image you want. Click Actions &gt; View all sizes, and then click on your image. Click on &#39;Share This&#39;, select &#39;Grab the HTML/BBCode&#39; and...<br />
		Awe,<em> fuck it</em>, nevermind. I&#39;ll get back to you.</p>
</blockquote>
<p>
	I had little choice. It took a bit of wrestling, a bit of late night sweat and tears. It&#39;s still rough around the edges and needs refining, but here&#39;s what&#39;s soon to come...</p>
<p>
	<img alt="" src="http://johndwells.com/content/uploads/default/flickr_wygwam_button.jpg" /></p>
<p>
	<em>What&#39;s this, a Flickr button? Hmm, I wonder what this does...</em></p>
<p>
	<img alt="" src="http://johndwells.com/content/uploads/default/flickr_wygwam_overlay.jpg" style="width: 550px; height: 460px;" /></p>
<p>
	<em>Neat, a CKEditor overlay! So let&#39;s click on a thumbnail then...</em></p>
<p>
	<img alt="" src="http://johndwells.com/content/uploads/default/flickr_wygwam_select_size.jpg" style="width: 550px; height: 300px;" /></p>
<p>
	<em>Oooh, I get to choose which size image I embed into my Wygwam field!</em></p>
<p>
	Clicking "Insert" drops the selected image size straight into your Wygwam field, and it&#39;s there just as a normal image; you can edit it&#39;s properties, alignment etc by using the CKEditor&#39;s native image button.</p>
<h2>
	But wait, there&#39;s more</h2>
<p>
	Lot&#39;s more is in the works for Flickr. We&#39;ll be moving the authentication settings away from the fieldtype setup and into an extension. All of the documentation could use a good refresh. I hope to investigate the possibility of handling videos coming from Flickr. We also might reconsider how Flickr saves image info in the custom field, and maybe even look at some caching down the road.&nbsp; See, lots to do - stay tuned, or get involved!</p>

				]]></content>
			</entry>
		
			<entry>
				<title>Custom plugin: How to switch MSM sites while mid&#45;rendering of template</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/custom-plugin-how-to-switch-msm-sites-while-mid-rendering-of-template" />
				<id>tag:johndwells.com,2011:blog/3.56</id>
				<published>2011-02-04T12:00:09Z</published>
				<updated>2011-02-04T15:25:11Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>More often than not, EE add-ons assume that you are only interested in the current site being loaded. But, well, <em>you know what they say about ass-u-mptions</em>. Read on to learn how you can switch MSM sites while mid-rendering of a template.</p>
					<p>
	I&#39;m smack in the middle of a monumental MSM build. It&#39;s my second MSM site, and I am once again reminded how <em>I am not in Kansas anymore</em>. &nbsp;It&#39;s still EE, and it&#39;s still awesome, but "gotchas" seem a frustratingly common occurrence.</p>
<p>
	One such "gotcha" is this: as much as EE&#39;s docs claim it&#39;s easy to <strong>mix content across sites</strong>, this is in fact much easier said than done. In particular, many 3rd party add-ons, while claiming to be MSM-compatible, are "hard-coded" to use the current site being visited.</p>
<p>
	Take for example, the glorious <a href="http://buildwithstructure.com">Structure</a> addon. It&#39;s very MSM-capable, allowing you to build tree structures for each of your sites. However none of its tags allow for you to specify which site you&#39;d like to pull navigation from; <em>it always assumes you want to pull navigation from the currently loaded site</em>.</p>
<p>
	For this particular MSM project, that&#39;s exactly the roadblock I encountered last week, and needed to find a workaround. So I set about digging. Here&#39;s what I came up with.</p>
<h2>
	Step 1: Set up your plugin</h2>
<p class="aside">
	This article falls under my "Build Your Own Plugin" mantra that I, and others, have written about before. EE plugins are awesomely fun and simple to write, and put you on the fast track to becoming an EE guru.</p>
<p>
	We&#39;re going to build ourselves a simple plugin that :</p>
<ul>
	<li>
		saves site-specific config settings for the current site into EE&#39;s session object;</li>
	<li>
		accepts site_name as a parameter, and replaces our site-specific config settings with this requested site;</li>
	<li>
		when prompted, reverts back to the current site-specific config settings</li>
</ul>
<p>
	To start off with we need to set up our plugin. In our <code>__construct()</code> method, let&#39;s get an instance of EE, and then set up a session cache array to use later:</p>
<pre class="brush:php;">
&lt;?php&#10;if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);&#10;&#10;$plugin_info = array(&#10;&#9;&#39;pi_name&#39;&#9;&#9;&#9;=&gt; &#39;MSM Switch Site,&#10;&#9;&#39;pi_version&#39;&#9;&#9;&#9;=&gt; &#39;1.0.0&#39;,&#10;&#9;&#39;pi_author&#39;&#9;&#9;&#9;=&gt; &#39;Your Name Here&#39;,&#10;&#9;&#39;pi_author_url&#39;&#9;&#9;=&gt; &#39;http://yournamehere.com&#39;,&#10;&#9;&#39;pi_description&#39;&#9;&#9;=&gt; &#39;Switch MSM sites mid-rendering of template&#39;&#10;);&#10;&#10;class Msm_switch_site &#123;&#10;&#10;&#9;var $EE;&#10;&#9;var $cache;&#10;&#10;&#9;function __construct()&#10;&#9;&#123;&#10;&#9;&#9;$this-&gt;EE =&amp; get_instance();&#10;&#10;&#9;&#9;// set up sess cache if not yet exist&#10;&#9;&#9;if( ! array_key_exists(&#39;msm_switch_site&#39;, $this-&gt;EE-&gt;session-&gt;cache))&#10;&#9;&#9;&#123;&#10;&#9;&#9;&#9;$this-&gt;EE-&gt;session-&gt;cache[&#39;msm_switch_site&#39;] = array();&#10;&#9;&#9;&#125;&#10;&#9;&#9;&#10;&#9;&#9;// pass cache object as reference&#10;&#9;&#9;$this-&gt;cache =&amp; $this-&gt;EE-&gt;session-&gt;cache[&#39;msm_switch_site&#39;];&#10;&#9;&#125;&#10;&#125;&#10;</pre>
<h2>
	Step 2: making the switch()</h2>
<p>
	And here&#39;s where the magic happens: first, our <code>switch()</code> method places our current site&#39;s config array into our session. &nbsp;It needs to remember two things:</p>
<ol>
	<li>
		the current site_name</li>
	<li>
		the current site&#39;s config object</li>
</ol>
<p>
	Next, we check for a provided&nbsp;<code>site_name</code> parameter; if passed, then we need to tell EE to load the site&#39;s prefs into the config object (check out lines 27-28). If no <code>site_name</code> is passed, then we will switch back to the current site.</p>
<pre class="brush:php;">
function switch()&#10;&#123;&#10;&#9;// capture the orig site config info&#10;&#9;if( ! array_key_exists(&#39;msm_switch_site&#39;, $this-&gt;cache))&#10;&#9;&#123;&#10;&#9;&#9;$this-&gt;cache[&#39;msm_switch_site_orig_short_name&#39;] = $this-&gt;EE-&gt;config-&gt;item(&#39;site_short_name&#39;);&#10;&#9;&#9;$this-&gt;cache[&#39;msm_switch_site&#39;] = array(&#10;&#9;&#9;&#9;$this-&gt;cache[&#39;msm_switch_site_orig_short_name&#39;] =&gt; $this-&gt;EE-&gt;config-&gt;config&#10;&#9;&#9;);&#10;&#9;&#125;&#10;&#9;&#10;&#9;// if no site_name param was passed, assume we&#39;d like to switch back to orig site&#10;&#9;if( ! $site_name = $this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;site_name&#39;))&#10;&#9;&#123;&#10;&#9;&#9;$this-&gt;EE-&gt;config-&gt;config = $this-&gt;cache[&#39;msm_switch_site&#39;][$this-&gt;cache[&#39;msm_switch_site_orig_short_name&#39;]];&#10;&#9;&#125;&#10;&#9;else&#10;&#9;&#123;&#10;&#9;&#9;// do we already have it in the cache?&#10;&#9;&#9;if(array_key_exists($site_name, $this-&gt;cache[&#39;msm_switch_site&#39;]))&#10;&#9;&#9;&#123;&#10;&#9;&#9;&#9;$this-&gt;EE-&gt;config-&gt;config = $this-&gt;cache[&#39;msm_switch_site&#39;][$site_name];&#10;&#9;&#9;&#125;&#10;&#9;&#9;else&#10;&#9;&#9;&#123;&#10;&#9;&#9;&#9;// here&#39;s the single magical line that switches our site config&#10;&#9;&#9;&#9;$this-&gt;EE-&gt;config-&gt;site_prefs($site_name);&#10;&#9;&#9;&#9;$this-&gt;cache[&#39;msm_switch_site&#39;][$site_name] = $this-&gt;EE-&gt;config-&gt;config;&#10;&#9;&#9;&#125;&#10;&#9;&#125;&#10;&#125;</pre>
<p>
	Check out those last couple lines of code again: All we need to do is call&nbsp;<code>$this-&gt;EE-&gt;config-&gt;site_prefs($site_name)</code>; to have EE look up our settings, and re-set all the necessary config items. &nbsp;Then we just have to set this new config object into our cache (in case we need to switch to this site again and again, we can avoid subsequent DB calls).</p>
<h2>
	Step 3: How to use</h2>
<p>
	Let&#39;s again use Structure as an example. &nbsp;Say we want to be guaranteed to show the main navigation of our default site, no matter what site is currently being displayed. &nbsp;It will look like this:</p>
<pre class="brush:php;">
&#123;exp:msm_switch_site:switch site_name=&#39;default_site&#39;&#125;&#10;&#9;&#123;exp:structure:nav_main&#125;&#10;&#123;exp:msm_switch_site:switch&#125;</pre>
<p>
	Line 1 tells EE to switch to the default_site; line 2 calls Structure&#39;s nav_main as usual; line 3 tells EE to switch back to whichever site was currently being displayed.</p>
<p>
	Groovy, eh?</p>

				]]></content>
			</entry>
		
			<entry>
				<title>Stay Up Forever: Take control of EE&#8217;s session time limit (maybe)</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/stay-up-forever-take-control-of-ee-session-time-limit" />
				<id>tag:johndwells.com,2011:blog/3.55</id>
				<published>2011-01-23T21:35:14Z</published>
				<updated>2011-08-19T03:14:16Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>ExpressionEngine&#8217;s hard-coded, 1 hour time limit for CP sessions has always been a real nuisance - frustrated clients have asked repeatedly for it to be extended. I&#8217;m cautiously releasing an add-on that finally grants control of this limit, but I&#8217;d appreciate some help to determine its usefulness &amp; effectiveness.</p>


					<p class="aside">
	<em>Is all of this really necessary?</em><br />
	Not entirely: You can set the <a href="http://expressionengine.com/user_guide/cp/admin/system_admin/security_settings.html">Control Panel Session Type</a> to &#39;Cookies Only&#39; and avoid all of this - plus gain the "keep me logged in" checkbox on login screens.</p>
<p>
	<strong>Update 2: NEVERMIND ALL OF THIS MALARKEY. As of EE 2.2.somethingorother, there are two new hidden configuration variables that allow you to control the session length of both CP users and front-end visitors. See <a href="http://expressionengine.com/user_guide/general/hidden_configuration_variables.html#user_session_ttl">User Session Length</a>&nbsp;and <a href="http://expressionengine.com/user_guide/general/hidden_configuration_variables.html#cp_session_ttl">Control Panel Session Length</a> for more.</strong></p>
<p>
	<strong>Update 1: </strong>Initial tests, with the help of some in the community, find that "forever" might only be 4 hours. The reason behind is mentioned in the "Potential Pitfalls" section below, and further discussed in the Comments section. Still, I&#39;d appreciate more input &amp; feedback.</p>
<p>
	As this <a href="http://expressionengine.com/wiki/Can_I_change_the_length_of_sessions_in_the_Control_Panel/">EE Wiki entry</a> explains, it is not considered possible to increase EE&#39;s session time limit without hacking the core. That&#39;s no good of course, so until now I&#39;ve always considered this task to be off limits.</p>
<p>
	Then this past weekend I began researching possibilities of overriding/extending EE&#39;s core libraries. It&#39;s a <a href="http://expressionengine.com/forums/viewthread/160740/#773192">somewhat controversial topic</a>, and I&#39;ll save my musings for another day. But the upshot of all that tinkering was that I discovered it&#39;s actually quite simple to modify the hard-coded session time limits, by way of the ever-popular <a href="http://expressionengine.com/user_guide/development/extension_hooks/global/session/index.html#sessions_start">sessions_start</a> hook.</p>
<blockquote>
	<p>
		I don&rsquo;t like it when people tell me I can&rsquo;t do something I want to do.</p>
	<p class="attribution">
		- <a href="http://expressionengine.com/forums/viewthread/160740/P18/#828063">Isaac Raways</a>, author of the <a href="http://devot-ee.com/add-ons/wallace/">Wallace</a> extension</p>
</blockquote>
<p>
	When <code>sessions_start</code> hook is called, it&#39;s passed a reference to the EE_Session object; and at least until EllisLab starts protecting class properties (<em>a distinct possibility now that PHP4 support has been dropped</em>), this means it&#39;s a piece of cake to overwrite what&#39;s in place:</p>
<pre class="brush:php;">
// called by EE&#39;s sessions_start hook&#10;function sessions_start($sess)&#10;&#123;&#10;&#9;$sess-&gt;cpan_session_len = 12345; // default is 3600, or 1 hour&#10;&#9;$sess-&gt;user_session_len = 67891; // default is 7200, or 2 hours&#10;&#9;$sess-&gt;session_length = (REQ == &#39;CP&#39;) ? $sess-&gt;cpan_session_len : $sess-&gt;user_session_len;&#10;&#9;return $sess;&#10;&#125;</pre>
<p>
	<em>Could it really be that easy?</em> From my initial tests, yes, yes it is that easy. So I&#39;ve turned it into an add-on: <a href="http://johndwells.com/software/stay-up-forever">Stay Up Forever</a>.</p>
<p>
	Right now, I&#39;m considering this an&nbsp;<strong>early beta release</strong>; it&#39;s the sort of thing that could, if misused or broken, permanently lock you out of the CP and wreak general havoc. &nbsp;So I&#39;m hoping there will be some clever/brave souls out there willing to give this a spin. &nbsp;I&#39;m also hoping anyone from EE&#39;s Core team might be able to highlight any potential pitfalls this add-on might raise.</p>
<h2>
	Possible Pitfalls</h2>
<p>
	For example: I&#39;m aware of EE&#39;s XID hash, for use with <a href="http://expressionengine.com/user_guide/development/guidelines/security.html#secure_forms">secure forms</a>, and these too have a hard-coded shelf-life: 14400 seconds or 4 hours. &nbsp;Initially this had me worried that a CP session set to expire beyond 4 hours might result in lost form submissions, but I found that the XID hash is periodically updated via javascript (read line 13 of themes/javascript/compressed/cp/global.js). &nbsp;However I don&#39;t know if this interval is effected by sleeping/waking your computer, so this is a possible gotcha. &nbsp;I&#39;m keen to hear what others think.</p>
<h2>
	Current Features</h2>
<p>
	Right now, <a href="http://johndwells.com/software/stay-up-forever">Stay Up Forever</a> is about as simple as it gets: install the extension, go to the settings page, and enter how many seconds you wish the CP and non-CP sessions to last. If you leave either value blank, the defaults will be used.</p>
<p>
	Default values will also be used if the configured time limit is set below 60 seconds; it&#39;s a safety measure to ensure you always have a minimum amount of time to log in, should anything go totally haywire.</p>
<p>
	It is&nbsp;<a href="http://ee-garage.com/nsm-addon-updater">NSM Add-on Updater</a> compatible, so you&#39;ll be notified of updates (why on earth is this not already part of core?).</p>
<h2>
	Potential Features</h2>
<p>
	So far I can think of a few features/improvements:</p>
<ol>
	<li>
		EE1x support</li>
	<li>
		Human-readable settings (e.g. &#39;3 hours&#39;, &#39;1 day&#39;, etc)</li>
	<li>
		Settings per member group, as <a href="http://expressionengine.com/archived_forums/viewthread/153189/#771476">suggested here</a></li>
	<li>
		Better Settings form, instructions etc</li>
</ol>
<h2>
	Join the Party</h2>
<p>
	That&#39;s all for now: drop a comment below if you have feedback or ideas. &nbsp;And head over to the <a href="http://johndwells.com/software/stay-up-forever">downloads area</a>&nbsp;to get your copy now.</p>

				]]></content>
			</entry>
		
			<entry>
				<title>Homegrown plugin to create template &#8220;partials&#8221; for ExpressionEngine</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/homegrown-plugin-to-create-template-partials-for-expressionengine" />
				<id>tag:johndwells.com,2011:blog/3.40</id>
				<published>2011-01-09T13:43:14Z</published>
				<updated>2011-01-10T09:36:15Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>Template &#8220;partials&#8221; functionality for ExpressionEngine: Embrace the DRY principle, reduce embed parsing and simplify your template ecosystem with this roll-your-own plugin.</p>
					<p class="aside">
	<strong>SIDE NOTE:</strong> If you&#39;d rather not hack together your own plugin, there are a number of 3rd party add-ons that can help you achieve the same approach outlined in this article; I&#39;ve provided links to these alternatives at the bottom of the page.</p>
<p>
	Generally speaking, a &ldquo;partial&rdquo; is a template that can be passed, as a variable, to another template for output. Their purpose is to provide a convenient way to include common content across multiple templates.&nbsp; Most frameworks (RoR, CodeIgniter, FuelPHP etc) all have their own flavour of template partials, and ExpressionEngine&rsquo;s embeds &amp; snippets more or less the job - but not without a few downsides.</p>
<p>
	I&#39;m going to discuss a technique that attempts to remedy these downsides. It will involve getting your hands dirty rolling our own EE plugin. &nbsp;It will be simple, limited, but hopefully demonstrate the potential at our fingertips.</p>
<h2>
	What We Have Now</h2>
<p>
	I&rsquo;m willing to bet that if you were to open up any one of your templates in EE, it might look something like this:</p>
<pre class="brush:ee;">
&#123;embed="embeds/_html_head"&#125;&#10;&lt;body class="blog"&gt;&#10;&#9;&lt;div id="wrapper"&gt;&#10;&#9;&#9;&#123;embed="embeds/_main_navigation" nav_active="blog"&#125;&#10;&#9;&#9;&lt;div id="content"&gt;&#10;&#9;&#9;&#9;&#123;exp:channel:entries ...&#125;&#10;&#9;&#9;&#9;&#9;...&#10;&#9;&#9;&#9;&#123;/exp:channel:entries&#125;&#10;&#9;&#9;&lt;/div&gt;&#10;&#9;&#9;&#123;snippet_sidebar&#125;&#10;&#9;&#9;&#123;embed="embeds/_footer"&#125;&#10;&#9;&lt;/div&gt;&#10;&#9;&#123;embed="embeds/_html_foot"&#125;&#10;&lt;/body&gt;&#10;&lt;/html&gt;&#10;</pre>
<p>
	It&rsquo;s a fairly standard setup, especially if you&rsquo;ve crossed over from the world of Wordpress and are accustomed to functions like <code>get_header()</code>&nbsp;&amp; <code>get_footer()</code> sprinkled throughout your theme files.&nbsp; And at a glance, it&rsquo;s a super convenience, allowing you to include common content across your site. &nbsp;<em>EE&rsquo;s embeds and snippets are great</em>.</p>
<p>
	But the downsides? I see three:</p>
<ol>
	<li>
		Passing content into your embeds is cumbersome at best</li>
	<li>
		Each EE embed adds significant overhead to the parsing engine</li>
	<li>
		You still have to repeat that general markup structure for every template file that&rsquo;s directly responsible for outputting content to the browser.</li>
</ol>
<p>
	Now, downside #1 can be remedied somewhat by simply wrapping more of your template with your&nbsp;<code>&#123;exp:channel:entries&#125;</code>&nbsp;tag, but it does little if you want to pass more than simple strings into an embed. &nbsp;Even so, downsides #2 and #3 remain, and these two are of greater concern. So let&rsquo;s see if we can fix them all.</p>
<h2>
	What We Need</h2>
<p>
	We need a solution that solves our 3 problems above, plus meets an additional requirement I&#39;d like to add:</p>
<ol>
	<li>
		Reduced quantity of embeds</li>
	<li>
		DRY template pattern with a <em>single</em>&nbsp;"wrapper" template</li>
	<li>
		Chunks of content can easily be passed to that wrapper template</li>
	<li>
		Lightweight and bespoke plugin that <em>meets our needs, our flavour of development, and frees us from relying on a 3rd party developer</em></li>
</ol>
<p>
	<strong>Let me pause on the last point:</strong> I&#39;m a huge proponent of self-reliance; of becoming familiar and comfortable with the core code base that you work on; and of <a href="http://37signals.com">tools that do one job and do that job well</a>. &nbsp;EE plugins are surprisingly easy to build yourself, open up a whoop-ass can of power, and can even&nbsp;speed up your templates. &nbsp;You would do yourself a great service to learn how to roll your own EE plugins.</p>
<h2>
	What It Will Look Like</h2>
<p>
	So, we are going to build a "Partials" plugin that allows us to assign chunks of content to variables that are saved and then rendered later on by a single template. &nbsp;This "wrapper" template will contain our entire page structure, as well as markup that had previously been distributed across our earlier embeds (in our examples, those were <code>_html_head</code>, <code>_main_navigation</code>, <code>_footer</code> and <code>_html_foot</code>).</p>
<p>
	<strong>That&#39;s right, </strong><em>we are going to go from 4 template embeds down to 1</em>.</p>
<p>
	Here&#39;s what our calling template will look like:</p>
<pre class="brush:ee;">
&#123;embed="embeds/_wrapper" body_class="blog" nav_active="blog"&#125;&#10;&#123;exp:channel:entries ...&#125;&#10;&#9;&#123;exp:partials:set name="page_title"&#125;&#123;title&#125;&#123;/exp:partials:set&#125;&#10;&#9;&#123;exp:partials:set name="content"&#125;&#10;&#9;&#9;&#123;channel_body&#125;&#10;&#9;&#123;/exp:partials:set&#125;&#10;&#123;/exp:channel:entries&#125;&#10;</pre>
<p>
	You may notice we call our wrapper template first, but then "set" content later. Don&#39;t worry though, as the wrapper template will be embeded <em>last</em>, because of EE&#39;s <a href="http://expressionengine.com/wiki/Parse_Order/">parse order</a>. However&nbsp;if you prefer, you&#39;re welcome to place the <code>&#123;embed&#125;</code> call at the end of your template. It will work all the same.</p>
<p>
	Lines 3-6 are where the magic happens: we <em>set</em> two new partials and fill them with content. Our first partial is a simple string; our second contains our entire body content from our channel.</p>
<p>
	Let&#39;s look at our wrapper template now:</p>
<pre class="brush:ee;">
&lt;!DOCTYPE html&gt; &#10;&lt;html&gt;&#10;&lt;head&gt; &#10;&#9;&lt;title&gt;&#123;exp:partials:get name="page_title"&#125; | &#123;site_name&#125;&lt;/title&gt;&#10;&lt;/head&gt;&#10;&lt;body class="&#123;embed:body_class&#125;"&gt;&#10;&#9;&lt;div id="wrapper"&gt;&#10;&#9;&#9;&lt;ul id="main_navigation" class="&#123;embed:nav_active&#125;"&gt;&#10;&#9;&#9;&#9;...&#10;&#9;&#9;&lt;/ul&gt;&#10;&#9;&#9;&lt;div id="content"&gt;&#10;&#9;&#9;&#9;&#123;exp:partials:get name="content"&#125;&#10;&#9;&#9;&lt;/div&gt;&#10;&#9;&#9;&#123;snippet_sidebar&#125;&#10;&#9;&#9;&lt;div id="footer"&gt;&#10;&#9;&#9;&#9;...&#10;&#9;&#9;&lt;/div&gt;&#10;&#9;&#9;&#123;snippet_analytics&#125;&#10;&#9;&lt;/div&gt;&#10;&lt;/body&gt;&#10;&lt;/html&gt;&#10;</pre>
<p>
	Look, no more embeds! What&#39;s more, this reads as a complete template; everything is in one place, and any changes to the foundation of your markup structure only needs to be made here.&nbsp;At line 4 we can see where we <em>get</em>&nbsp;one of our template partials, &#39;page_title&#39;; then at line 12 we <em>get</em> our second, &#39;content&#39;.</p>
<h2>
	The Plugin, Finally</h2>
<p class="aside">
	<em>If you&#39;re wholly unfamiliar with EE plugins, head over to the <a href="http://expressionengine.com/user_guide/development/plugins.html">User Guide</a> and have a quick scan to get the basic idea.</em></p>
<p>
	And now, to the main event. Copy-and-paste this code into <code>/system/expressionengine/third_party/partials/pi.partials.php</code>, and modify the first few lines to suit; that&#39;s right, put your name in there! After all this is going to be your plugin, not mine.</p>
<pre class="brush:php;">
&lt;?php&#10;if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);&#10;$plugin_info = array(&#10;  &#39;pi_name&#39; =&gt; &#39;Homegrown Partials&#39;,&#10;  &#39;pi_version&#39; =&gt;&#39;1.0.0&#39;,&#10;  &#39;pi_author&#39; =&gt;&#39;Your Name Here&#39;,&#10;  &#39;pi_author_url&#39; =&gt; &#39;http://yoursite.com&#39;,&#10;  &#39;pi_description&#39; =&gt; &#39;Homegrown Partials - Template partials plugin for EE&#39;&#10;  );&#10;&#10;class Partials &#123;&#10;&#10;&#9;public $EE;&#10;&#10;&#9;/*&#10;&#9; * PHP5 constructor&#10;&#9; * get instance of EE, and set up our session cache&#10;&#9; */&#10;&#9;public function __construct()&#10;&#9;&#123;&#10;&#9;&#9;$this-&gt;EE = get_instance();&#10;&#9;&#9;if ( ! array_key_exists(&#39;partials&#39;, $this-&gt;EE-&gt;session-&gt;cache))&#10;&#9;&#9;&#123;&#10;&#9;&#9;&#9;$this-&gt;EE-&gt;session-&gt;cache[&#39;partials&#39;] = array();&#10;&#9;&#9;&#125;&#10;&#9;&#125;&#10;&#9;// END&#10;&#10;&#9;/*&#10;&#9; * Set content in session&#10;&#9; */&#10;&#9;public function set()&#10;&#9;&#123;&#10;&#9;&#9;$name = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;name&#39;));&#10;&#9;&#9;$this-&gt;EE-&gt;session-&gt;cache[&#39;partials&#39;][$name] = $this-&gt;EE-&gt;TMPL-&gt;tagdata;&#10;&#9;&#125;&#10;&#9;// END&#10;&#9;&#10;&#9;/*&#10;&#9; * Get content from session&#10;&#9; */&#10;&#9;public function get()&#10;&#9;&#123;&#10;&#9;&#9;$name = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;name&#39;));&#10;&#9;&#9;if (array_key_exists($name, $this-&gt;EE-&gt;session-&gt;cache[&#39;partials&#39;])&#10;&#9;&#9;&#123;&#10;&#9;&#9;&#9;return $this-&gt;EE-&gt;session-&gt;cache[&#39;partials&#39;][$name];&#10;&#9;&#9;&#125;&#10;&#9;&#125;&#10;&#9;// END&#10;&#125;&#10;/* End of file pi.partials.php */&#10;/* Location: ./system/expressionengine/third_party/partials/pi.partials.php */</pre>
<p>
	So the first half of our plugin is standard boilerplate stuff; set up our info array (EE needs this), and get an instance of the $EE object. Things get interesting around line 22, when we add an array to EE&#39;s session cache. All cache data is only available for this page request, and is wiped as soon as the request is over.</p>
<p>
	After that, we create two basic methods; one for <code>&#123;exp:partials:set&#125;</code> and one for <code>&#123;exp:partials:get</code>&#125;. Partials::set() retrieves our name parameter and passes all tagdata (everything between <code>&#123;exp:partials:set&#125; ... &#123;/exp:partials:set&#125;</code> into our cache array, where <code>$name</code> is the key. &nbsp;Then <code>&#123;exp:partials:get&#125;</code> simply retrieves that cached tagdata based on the same <code>$name</code> value.</p>
<p>
	And since this is ours, and not something we&#39;re releasing to the community, we don&#39;t need to be super safe - forgo the tedious checks if $name is a valid value, or if you might be overwriting the array value with something previously saved.&nbsp;<em>So simple.</em></p>
<p>
	<strong>And if you are so inclined, improve upon it</strong>; build in a second parameter that flags whether you should overwrite or append your saved data. &nbsp;Add another parameter that will allow you to append or prepend strings to what is being printed. You could even build multiple variations of the <code>Partials::get()</code> method to output variables differently, depending on your needs.</p>
<p>
	The possibilities are endless, and again since this is For Your Site Only, there&#39;s nothing to stop you!</p>
<h2>
	3rd Party Solutions</h2>
<p>
	This approach is in fact not new, but definitely not well-promoted; a few community developers have built fantastic and feature-rich add-ons that will help you achieve this technique if you&#39;d rather not build your own plugin. &nbsp;A few of these are:</p>
<ul>
	<li>
		<a href="http://devot-ee.com/add-ons/mx-jumper/">MX Jumper</a>&nbsp;- By max Lazar, for EE2, free</li>
	<li>
		<a href="http://studio625.com/ee/reeposition/">REEposition</a> - By Studo625, for EE1, free</li>
	<li>
		<a href="http://ee-garage.com/nsm-transplant">NSM Transplan</a>t - By Leevi Graham, for EE2, $AUD 34.95</li>
	<li>
		<a href="http://emarketsouth.com/add-ons/string-plugin">String Plugin</a> - By eMarketSouth, for EE1.6x and EE2, $9.95</li>
</ul>

				]]></content>
			</entry>
		
			<entry>
				<title>Minimee grows up: version 1.1.0 released</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/minimee-grows-up-version-1.1.0-released" />
				<id>tag:johndwells.com,2011:blog/3.45</id>
				<published>2011-01-04T19:17:06Z</published>
				<updated>2011-01-09T10:34:07Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>Minimee, the ExpressionEngine 2.x plugin that minifies and combines your CSS and JS files, just got better. cURL support, PHP5 cleverness and other goodies await you.</p>
					<p>
	Over the xmas holidays I <a href="http://twitter.com/johndwells/status/19589047752065024">tweeted a call for help</a>&nbsp;to debug some work I&#39;d recently done on Minimee. A few dedicated souls (<a href="http://twitter.com/leepowell">@leepowell</a>, <a href="http://twitter.com/gwcode">@GWcode</a>) were kind enough to jump in and kick its tires. Thanks to their fantastic input, I&#39;m proud to announce Minimee&#39;s 1.1.0 release!</p>
<p>
	You can <a href="http://johndwells.com/software/minimee">download the latest copy of Minimee</a>&nbsp;now.</p>
<h2>
	Highlights of the release</h2>
<p>
	I&#39;ve bumped the version number from 1.0.2 to 1.1.0 due to significant changes under the hood - a slew of improvements that makes Minimee easier and more stable to use.</p>
<h3>
	cURL support</h3>
<p>
	Previously, Minimee relied on <code>file_get_contents()</code> to retrieve external files (which yes, includes <code>&#123;stylesheet=&#125;</code>). Due to an occasional shared hosting glitch, as well as the welcomed PHP5 requirement as of EE 2.1.2, it seemed necessary to add cURL support. &nbsp;While cURL is now the default, I&#39;ve given users the option to specify which method to use if they so desire.</p>
<h3>
	Support for global variables</h3>
<p>
	Support for Global Variables became a request I could no longer ignore: but to keep performance up, Minimee will only trigger EE&#39;s global parsing routine if it detects any existing EE tags.</p>
<h3>
	Yummy PHP5 support</h3>
<p>
	Seeing as EE2.1.2 has dropped PHP4 support, so has Minimee - You might not notice anything different, but it has greatly improved the clarity and structure of the code.</p>
<h3>
	&#39;Intelligent&#39; templating</h3>
<p>
	Previously, Minimee&#39;s output of <code>&lt;link ..&gt;</code> and <code>&lt;script ...&gt;</code> tags were hard-coded; the only thing you could customise was the media parameter for the link tag. Now though, Minimee uses the first HTML tag it encounters as a "template" for output. As long as your first tag is formatted as you so desire, MInimee&#39;s final output will be, too.</p>
<p>
	<em>Of course because of this change, the "media=" parameter is now obsolete.</em></p>
<h3>
	New &#39;debug&#39; mode</h3>
<p>
	There&#39;s a new configuration option to turn on "debugging", which will output HTML comments for any error encountered. Should you encounter difficulty getting Minimee up and running, this should help you quickly nail down the problem.</p>
<p>
	Note: Error and debug messages will always be sent to EE&#39;s logging mechanism (available in /system/codeigniter/system/logs/log-yyyy-mm-dd.php) - as long as you&#39;ve turned on your debug threshold. &nbsp;More on that in Minimee&#39;s <a href="http://johndwells.com/software/minimee">User Guide</a>.</p>
<h3>
	&#39;Strict&#39; mode removed</h3>
<p>
	By default, Minimee used to silently ignore any missing file(s), thereby creating a cached file based on whatever was available at the time. This behaviour could be turned off by setting the mode "strict" to TRUE (via config or param), but frankly all this feature did was cause problems &amp; confusion. &nbsp;Hence I&#39;ve completely removed this feature: <em>now MInimee will only&nbsp;work if all files are found</em>.</p>
<h3>
	From true/false to yes/no</h3>
<p>
	Any configuration settings or parameters that were once boolean (TRUE/FALSE or the string &#39;true&#39;/&#39;false&#39;) should now be set with &#39;yes&#39; or &#39;no&#39;, as appropriate. &nbsp;This was to simplify the normalising of settings. &nbsp;The details behind this deserve a brief article that I&#39;ll publish in a few week&#39;s time.</p>
<h3>
	Jeez, anything else?</h3>
<p>
	Actually yes. A few bug fixes, and a few other tweaks here and there, makes this a very exciting release. As usual if anyone has any problems, you&#39;re encouraged to use the <a href="http://devot-ee.com/add-ons/support/minimee/viewforum/1212/">support forums on devot-ee.com</a>. &nbsp;I keep a close eye on this and do my absolute best to respond in a timely manner.</p>

				]]></content>
			</entry>
		
			<entry>
				<title>Do you miss being a hacker? Then build yourself a plugin.</title>
				<link rel="alternate" type="text/html" href="http://johndwells.com/blog/do-you-miss-being-a-hacker-then-build-yourself-a-plugin" />
				<id>tag:johndwells.com,2010:blog/3.44</id>
				<published>2010-12-30T13:49:13Z</published>
				<updated>2011-01-10T03:38:15Z</updated>
				<author>
					<name>John D Wells</name>
					<email>hello@johndwells.com</email>
					<uri>http://johndwells.com</uri>				</author>
				
					<category term="EECMS"
						scheme="http://johndwells.com/blog/archives/C1"
						label="EECMS" />
				
				<content type="html"><![CDATA[
					<p>No Hacking Required &trade;: The ExpressionEngine community proudly touts this as one of EE&#8217;s great strengths over competing CMS platforms.&nbsp; But if you miss hacking, if you&#8217;d like to capture the satisfaction and thrill of raw, unadulterated PHP code, you should build yourself a plugin.</p>
					<p>
	For me, the ah-hah moment came as I read one of <a href="http://pixelandtonic.com/blog/making-pt-structure">Brandon Kelly&#39;s posts over on his Pixel &amp; Tonic blog</a>. He was kindly reviewing some of his work done to launch the new P&amp;T website. In it he described how he&#39;d written a custom plugin function to replace all instances of "http://" with "https://" for any templates that were going to be operating under SSL. To me, <em>it was a hack</em>, plain and simple: an elegant demonstration how to bend EE to your will, to harness EE&#39;s sometimes peculiar <a href="http://expressionengine.com/wiki/Parse_Order/">parsing order</a> to your advantage.</p>
<p>
	Since then, I begin every project with an empty plugin. As you can see from <a href="http://expressionengine.com/user_guide/development/plugins.html">EE&#39;s developer documentation</a>, the barebones of a plugin are incredibly simple:</p>
<pre class="brush:php;">
&lt;?php&#10;if ( ! defined(&#39;BASEPATH&#39;)) exit(&#39;No direct script access allowed&#39;);&#10;&#10;$plugin_info = array(&#10;&#9;&#39;pi_name&#39; =&gt; &#39;SiteName&#39;,&#10;&#9;&#39;pi_version&#39; =&gt;&#39;1.0.0&#39;,&#10;&#9;&#39;pi_author&#39; =&gt;&#39;Your Name&#39;,&#10;&#9;&#39;pi_author_url&#39; =&gt; &#39;http://sitename.com&#39;,&#10;&#9;&#39;pi_description&#39; =&gt; &#39;SiteName - A few hacker functions for this theme/site&#39;&#10;);&#10;&#10;class SiteName &#123;&#10;&#10;&#9;var $EE;&#10;&#10;&#9;function __construct()&#10;&#9;&#123;&#10;&#9;&#9;$this-&gt;EE =&amp; get_instance();&#10;&#9;&#125;&#10;&#125;&#10;/* End of file pi.sitename.php */&#10;/* Location: ./system/expressionengine/third_party/sitename/pi.sitename.php */</pre>
<p>
	Once you get into the swing of rolling your own plugins, you might be surprised at what you come up with; in circumstances where you could both simplify and speed up your templates by relying on a hacked up plugin to do some outputting for you. <strong>Consider it part of your template arsenal, just like CSS files and Javascripts.</strong></p>
<h2>
	A Real World Hack</h2>
<p>
	I&#39;m currently working on a project that relies heavily on <a href="http://flickr.com">Flickr</a>. &nbsp;I&#39;m using <a href="http://brandnewbox.co.uk/products/details/datagrab/">DataGrab</a>&nbsp;to periodically query the Flickr API for new or modified photos from our client account, and to import their information into a channel. I store all information <em>about</em>&nbsp;the photos such as Farm ID, Server ID, etc, but never the images themselves. I need to create&nbsp;<code>&lt;img&gt;</code> tags based on <a href="http://www.flickr.com/services/api/misc.urls.html">Flickr&#39;s formula</a>, which, if you&#39;ve worked with before, is not the easiest to remember.&nbsp;So I wrote this plugin:</p>
<pre class="brush:php;">
/*&#10; * Assembles a valid URL to flickr image&#10; */&#10;function flickr()&#10;&#123;&#10;&#9;$size = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;size&#39;));&#10;&#9;$size = ($size) ? $size : &#39;square&#39;; // default is square&#10;&#9;&#10;&#9;$id = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;id&#39;)); // UID of photo&#10;&#9;$server = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;server&#39;)); // server ID&#10;&#9;$secret = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;secret&#39;)); // secret&#10;&#9;$farm = strtolower($this-&gt;EE-&gt;TMPL-&gt;fetch_param(&#39;farm&#39;)); // farm ID&#10;&#9;&#10;&#9;switch ($size) // determine prefix based on size&#10;&#9;&#123;&#10;&#9;&#9;case(&#39;square&#39;) :&#10;&#9;&#9;&#9;$prefix = &#39;_s&#39;;&#10;&#9;&#9;break;&#10;&#9;&#9;case(&#39;thumb&#39;) :&#10;&#9;&#9;&#9;$prefix = &#39;_t&#39;;&#10;&#9;&#9;break;&#10;&#9;&#9;case(&#39;small&#39;) :&#10;&#9;&#9;&#9;$prefix = &#39;_m&#39;;&#10;&#9;&#9;break;&#10;&#9;&#9;case(&#39;large&#39;) :&#10;&#9;&#9;&#9;$prefix = &#39;_b&#39;;&#10;&#9;&#9;break;&#10;&#9;&#9;case(&#39;medium&#39;) :&#10;&#9;&#9;default :&#10;&#9;&#9;&#9;$prefix = &#39;&#39;;&#10;&#9;&#9;break;&#10;&#9;&#125;&#10;&#9;&#10;&#9;return "http://farm&#123;$farm&#125;.static.flickr.com/&#123;$server&#125;/&#123;$id&#125;_&#123;$secret&#125;&#123;$prefix&#125;.jpg";&#10;&#125;&#10;</pre>
<p>
	As you&#39;ll notice, it&#39;s incredibly simple; it retrieves my parameters, defines a prefix string based on the requested size, and returns the compiled src string.&nbsp;If I need a large version of my image, this is all I need to do:</p>
<pre class="brush:ee;">
&#123;exp:sitename:flickr size="large" id="&#123;f_id&#125;" server="&#123;f_server&#125;" secret="&#123;f_secret&#125;" farm="&#123;f_farm&#125;"&#125;</pre>
<p>
	If I&#39;d rather output a square thumbnail, I only need change the first parameter to <code>size="square"</code>. As the <a href="http://www.youtube.com/watch?v=9LgMJpjTyNU">Meerkat for CompareTheMarket.com</a> would declare, "Simples! Chk-chk."</p>
<h2>
	Hack vs 3rd Party Addon</h2>
<p>
	Why do I consider the above example a hack and not a 3rd party add-on? To my mind, what makes a hack is this: it&#39;s a (sometimes hasty) snippet of code that exists to <em>solve one problem and one problem only</em>. It is built under very specific circumstances, to be used by a very specific audience: Just Me. Notice that my function performs no checks; it does not sanitise data, it doesn&#39;t abort if not given enough data to return a valid URL.</p>
<p>
	<em>It&#39;s simple and effective</em>. If I port it over to another project, it very well may need to change. And that&#39;s a good thing: I am free to change it at will. &nbsp;I don&#39;t worry about legacy support. &nbsp;Who cares if it might bork on IIS. I don&#39;t need to file a feature request with the developer to ask for some new piece of functionality.</p>
<p>
	Plugins are the perfect place for you to "hack" because they too are simple and effective. &nbsp;Modules &amp; Extensions require touching the database, they require install and uninstall methods, you must activate them via the Control Panel. &nbsp;But a plugin? Just drop it in your third_party folder and go.</p>
<h2>
	Resources To Get Started</h2>
<p>
	If I&#39;ve convinced you to build some simple plugins of your own, then keep these links on hand, print out some cheat sheets, and start hacking away:</p>
<ul>
	<li>
		<a href="http://expressionengine.com/user_guide/development/index.html">ExpressionEngine&#39;s Developer Guide</a></li>
	<li>
		<a href="http://codeigniter.com/user_guide/">CodeIgniter&#39;s User Guide</a></li>
	<li>
		<a href="http://expressionengine.com/user_guide/quick_reference.html">EE2 Quick Reference Chart</a></li>
	<li>
		<a href="http://expressionengine.com/user_guide/development/constants.html">EE2 Constants Reference</a></li>
	<li>
		<a href="http://www.putyourlightson.net/projects/cheat_sheet">EE2 Cheat Sheet</a></li>
</ul>
<p>
	Parting thought: if you really want to have some fun, then spend some time under the hood: EE&#39;s source code is well commented and logically organised. &nbsp;A few hours perusing the source, along with learning EE&#39;s general DB structure, will make you a pro hacker in no time.</p>

				]]></content>
			</entry>
		
	
	</feed>
