<?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>x + 3</title>
	<atom:link href="http://xplus3.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://xplus3.net</link>
	<description></description>
	<lastBuildDate>Fri, 19 Aug 2011 01:05:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>WordPress Action Nesting: a cautionary tale</title>
		<link>http://xplus3.net/2011/08/18/wordpress-action-nesting/</link>
		<comments>http://xplus3.net/2011/08/18/wordpress-action-nesting/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 01:05:51 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[add_action]]></category>
		<category><![CDATA[do_action]]></category>
		<category><![CDATA[nesting]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=414</guid>
		<description><![CDATA[When you save a post in WordPress, the post&#8217;s data goes through wp_insert_post(), which in turn triggers the save_post action. So let&#8217;s say you have a callback hooking into save_post. function my_first_callback&#40; $post_id, $post &#41; &#123; // do something... &#125; add_action&#40;'save_post', 'my_first_callback', 10, 2&#41;; So far, pretty simple. Now let&#8217;s put something in our callback function. function my_first_callback&#40; $post_id, $post &#8230; <a href="http://xplus3.net/2011/08/18/wordpress-action-nesting/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When you save a post in WordPress, the post&#8217;s data goes through <code>wp_insert_post()</code>, which in turn triggers the <code>save_post</code> action. So let&#8217;s say you have a callback hooking into <code>save_post</code>.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_first_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// do something...</span>
<span class="br0">&#125;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_first_callback'</span><span class="sy0">,</span> <span class="nu0">10</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>So far, pretty simple. Now let&#8217;s put something in our callback function.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_first_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">==</span> <span class="st_h">'post'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    wp_insert_post<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
      <span class="st_h">'post_title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'A Post'</span><span class="sy0">,</span>
      <span class="st_h">'post_status'</span> <span class="sy0">=&gt;</span> <span class="st_h">'publish'</span><span class="sy0">,</span>
      <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'a_custom_post_type'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_first_callback'</span><span class="sy0">,</span> <span class="nu0">10</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Not a horribly complicated function. We&#8217;ll leave aside my reasons for creating a post in this callback (there&#8217;s a myriad of reasons why one might want to create or update a different post when a given post is saved) and focus on the consequences.</p>
<p><code>wp_insert_post()</code>, called from <code>my_first_callback()</code> will once again trigger the <code>save_post</code> action, while we&#8217;re still in the middle of processing the first <code>save_post</code> action. So long as you avoid an infinite loop, there&#8217;s nothing necessarily wrong with that. But look closely inside <code>do_action()</code>, and you&#8217;ll find something else to worry about.<span id="more-414"></span></p>
<h3>The <code>$wp_filter</code> array</h3>
<p>WordPress stores all of your action (and filter) callbacks in the global <code>$wp_filter</code> array. This is a multidimensional array, with the hook names at the top level, the priority as the second level, and the callback at the third level. E.g., adding our callback above with <code>add_action()</code> is basically the same as:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="st_h">'save_post'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">10</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'my_first_callback'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'function'</span> <span class="sy0">=&gt;</span> <span class="st_h">'my_first_callback'</span><span class="sy0">,</span> <span class="st_h">'accepted_args'</span> <span class="sy0">=&gt;</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<h3>Inside <code>do_action()</code></h3>
<p><code>do_action('save_post')</code> takes the <code>$wp_filter['save_post']</code> array, sorts the priorities, then loops through each priority&#8217;s array of callback functions. Basically, a <code>foreach</code> loop nested inside of a <code>foreach</code> loop.</p>
<p>But the outer loop is not a PHP <code>foreach</code> loop. Instead, we manually progress through each priority using <code>next()</code>. Here&#8217;s the exact code in <code>do_action()</code>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw1">do</span> <span class="br0">&#123;</span>
  <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#41;</span> <span class="kw3">current</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$the_</span> <span class="br0">&#41;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="kw3">is_null</span><span class="br0">&#40;</span><span class="re0">$the_</span><span class="br0">&#91;</span><span class="st_h">'function'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>
      <span class="kw3">call_user_func_array</span><span class="br0">&#40;</span><span class="re0">$the_</span><span class="br0">&#91;</span><span class="st_h">'function'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="kw3">array_slice</span><span class="br0">&#40;</span><span class="re0">$args</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="br0">&#40;</span>int<span class="br0">&#41;</span> <span class="re0">$the_</span><span class="br0">&#91;</span><span class="st_h">'accepted_args'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span> <span class="kw1">while</span> <span class="br0">&#40;</span> <span class="kw3">next</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">!==</span> <span class="kw4">false</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>In many situations, this is functionally identical to a <code>foreach</code> loop, but in certain cases, it&#8217;s not.</p>
<h4>Case 1: Adding callbacks while already looping through the hook</h4>
<p>Let&#8217;s say that during your <code>save_post</code> callback function, you decide that you need to add another callback function with a later priority.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_first_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">==</span> <span class="st_h">'pistachio'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_second_callback'</span><span class="sy0">,</span> <span class="nu0">15</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
<span class="kw2">function</span> my_second_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// do something else</span>
<span class="br0">&#125;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_first_callback'</span><span class="sy0">,</span> <span class="nu0">10</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Due to the way <code>do_action()</code> is implemented, you can do this. <code>my_second_callback()</code> will be called at an appropriate(-ish) time (I&#8217;ll leave it as an exercise for the reader to figure out why it may not be in the exact order you might expect), because, by using <code>next()</code> instead of <code>foreach</code>, WordPress avoids making a copy of the <code>$wp_filter['save_post']</code> array.</p>
<h4>Case 2: Nested callbacks</h4>
<p>Now lets go back to our original callback function, and give it a friend:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_first_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">==</span> <span class="st_h">'post'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    wp_insert_post<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
      <span class="st_h">'post_title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'A Post'</span><span class="sy0">,</span>
      <span class="st_h">'post_status'</span> <span class="sy0">=&gt;</span> <span class="st_h">'publish'</span><span class="sy0">,</span>
      <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'a_custom_post_type'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
<span class="kw2">function</span> my_second_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// do something else</span>
<span class="br0">&#125;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_first_callback'</span><span class="sy0">,</span> <span class="nu0">10</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'save_post'</span><span class="sy0">,</span> <span class="st_h">'my_second_callback'</span><span class="sy0">,</span> <span class="nu0">15</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p><code>my_second_callback()</code> will never be called if <code>$post->post_type == 'post'</code>. In fact, any callback with a later priority will not be called. How did that happen?</p>
<p>When <code>my_first_callback()</code> calls <code>wp_insert_post()</code>, we have, as mentioned above, some nesting going on with the <code>save_post</code> action. The inner call to <code>do_action('save_post')</code> cycles through the <code>$wp_filter['save_post']</code> array until <code>next()</code> moves the pointer to the end of the array. After that loop is done, the outer call to <code>do_action('save_post')</code> doesn&#8217;t get its array pointer put back in the appropriate location. As far as it can tell, it&#8217;s looped through the entirety of the array and reached the end.</p>
<p>If <code>do_action()</code> used a <code>foreach</code> loop instead of the <code>do-while</code> construct with <code>next()</code>, it would make a copy of the <code>$wp_filter['save_post']</code> array with its own pointer, and we wouldn&#8217;t have this problem, but then case 1 wouldn&#8217;t work. It looks like a conscious design decision, and I&#8217;m inclined to say the correct decision.</p>
<h3>Making things right</h3>
<p>So what do we do about that? Well, we can just avoid calling <code>wp_insert_post()</code> or <code>wp_save_post()</code> in our callbacks for the <code>save_post</code> hook. If you can avoid it, I highly recommend it. Sometimes, though, that&#8217;s not practical, so you have to take a different approach: put the pointer back.</p>
<p>If you know your callback will (or might) cause nesting of an action/filter, you need to figure out where the array pointer should be when you&#8217;re done, and put it there.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_first_callback<span class="br0">&#40;</span> <span class="re0">$post_id</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="co1">// track the current position of the array_pointer</span>
  <span class="kw2">global</span> <span class="re0">$wp_filter</span><span class="sy0">;</span>
  <span class="re0">$wp_filter_index</span> <span class="sy0">=</span> <span class="kw3">key</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="st_h">'save_post'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">==</span> <span class="st_h">'post'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    wp_insert_post<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
      <span class="st_h">'post_title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'A Post'</span><span class="sy0">,</span>
      <span class="st_h">'post_status'</span> <span class="sy0">=&gt;</span> <span class="st_h">'publish'</span><span class="sy0">,</span>
      <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'a_custom_post_type'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="co1">// put the pointer back</span>
  <span class="kw3">reset</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="st_h">'save_post'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="kw3">array_keys</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="st_h">'save_post'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$key</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$key</span> <span class="sy0">==</span> <span class="re0">$wp_filter_index</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw1">break</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw3">next</span><span class="br0">&#40;</span><span class="re0">$wp_filter</span><span class="br0">&#91;</span><span class="st_h">'save_post'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>At the moment, I&#8217;m happy to admit that this is not 100% robust. E.g., the array may have changed or been resorted since your function started. So you&#8217;re not guaranteed to return to the exact state you were in before your function was called. But you&#8217;re probably close enough, and much better off than if you hadn&#8217;t tried at all.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2011/08/18/wordpress-action-nesting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Network Admin Pages</title>
		<link>http://xplus3.net/2011/07/13/wordpress-network-admin-pages/</link>
		<comments>http://xplus3.net/2011/07/13/wordpress-network-admin-pages/#comments</comments>
		<pubDate>Wed, 13 Jul 2011 21:18:26 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=410</guid>
		<description><![CDATA[Ever since WordPress 3.0 came out, merging the multi-blog network capabilities of WordPress MU into the core or WordPress, users have been asking for plugins that let you set options across the entire network, rather than per-blog. Setting up a network settings page is similar to setting up a standard settings page, but with a few key differences. Creating the &#8230; <a href="http://xplus3.net/2011/07/13/wordpress-network-admin-pages/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ever since WordPress 3.0 came out, merging the multi-blog network capabilities of WordPress MU into the core or WordPress, users have been asking for plugins that let you set options across the entire network, rather than per-blog. Setting up a network settings page is similar to setting up a standard settings page, but with a few key differences.</p>
<h2>Creating the Page</h2>
<p>First off, rather than the <code>admin_menu</code> hook, you&#8217;ll use the <code>network_admin_menu</code> hook to register your page. E.g.:</p>
<pre>
add_action('network_admin_menu', array($this, 'register_network_admin_pages'), 10, 0);
</pre>
<p>In your callback function, you don&#8217;t have the luxury of shortcut functions (e.g., <code>add_options_page()</code>) for registering your settings page, so you have to use <code>add_submenu_page()</code>, with <code>'settings.php'</code> as your first argument. Alternatively, you can still use <code>add_menu_page()</code> to create a new menu section, just as you would with the single blog admin menu.</p>
<p>The <a href="http://codex.wordpress.org/Settings_API">WordPress settings API</a> doesn&#8217;t entirely work on network admin pages, but you can still take advantage of the <code>add_settings_section()</code>, <code>add_settings_field()</code>, and <code>do_settings_sections()</code> functions to register and display your settings, if appropriate. But <code>register_setting()</code> is useless here.</p>
<p>The <code>action</code> attribute for your settings form should point to <code>edit.php?action=Your_Unique_Action</code>, for reasons we&#8217;ll soon discover.</p>
<p>Individual settings should be pulled from the network-wide site options table, using <code>get_site_option()</code>.</p>
<h2>Saving the Settings</h2>
<p>Your settings form gets submitted to <code>edit.php</code>. To save your settings, you need to hook into the <code>network_admin_edit_ACTION</code> hook.</p>
<pre>
add_action('network_admin_edit_Your_Unique_Action, array($this, 'save_network_settings_page'), 10, 0);
</pre>
<p>Again, <code>register_setting()</code> doesn&#8217;t work on admin pages, so you&#8217;ll need to sanitize, validate, and save all your options yourself. Save the settings to the network-wide site options table using <code>update_site_option()</code>.</p>
<p>After all your settings are saved, do a redirect back to your settings page. If you don&#8217;t WordPress will automatically redirect to the network dashboard.</p>
<pre>
wp_redirect(add_query_arg(array('page' => 'Your_Page_Slug', 'updated' => 'true'), network_admin_url('settings.php')));
exit();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2011/07/13/wordpress-network-admin-pages/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simpler WordPress Plugin Development with WP Router</title>
		<link>http://xplus3.net/2011/05/24/simpler-wordpress-development-wp-router/</link>
		<comments>http://xplus3.net/2011/05/24/simpler-wordpress-development-wp-router/#comments</comments>
		<pubDate>Tue, 24 May 2011 21:11:07 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=403</guid>
		<description><![CDATA[I&#8217;ve a great deal of experience with two open source content management systems: WordPress and Drupal. They both have their strengths and weaknesses, which I won&#8217;t get into here. If I had to pick the key difference between the two, though, it&#8217;s in how they answer one question: What is a URL? In WordPress, a URL indicates which posts to &#8230; <a href="http://xplus3.net/2011/05/24/simpler-wordpress-development-wp-router/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve a great deal of experience with two open source content management systems: WordPress and Drupal. They both have their strengths and weaknesses, which I won&#8217;t get into here. If I had to pick the key difference between the two, though, it&#8217;s in how they answer one question:</p>
<h3>What is a URL?</h3>
<p>In WordPress, a URL indicates which posts to display. Your request is mapped to query variables (if you don&#8217;t have permalinks turned on, you&#8217;ll see these variables directly in your query string), and those variables are used to manipulate the database query in <code>$wp_query-&gt;query()</code>. It&#8217;s a very nice, consistent system: a URL equals one or more posts (or a 404 error). (NB. the admin section is a different beast entirely.)</p>
<p>With Drupal, a URL is an entry in the menu system. When Drupal sees the URL, it looks up the corresponding entry, and calls the function specified in that entry. That function is responsible for creating the contents of the page, be it a list of nodes, a form, flying monkeys, or what have you. You can use a module like Views to achieve results similar to WordPress, but you have a lot more power and flexibility to do something different with a given page.</p>
<p>Sometimes you want that power and flexibility in WordPress. You just want to say, &#8220;When a user visits this URL, call this function and display its output.&#8221; That&#8217;s not really the &#8220;WordPress way&#8221; of doing things, and it requires a fair amount of code to accomplish what seems to be a simple instruction.</p>
<h3>Abstract the Details Away</h3>
<p>So I went and wrote another WordPress plugin. <a href="http://wordpress.org/extend/plugins/wp-router/">WP Router</a> abstracts away all the messy details of declaring a callback function for a URL in WordPress. One method call is all it takes to set up your path, your rewrite rules, your query variables, your access rules, your title, your template overrides. It reduces a few dozen action/filter callbacks to a small list of easy-to-understand arguments.</p>
<p>If you&#8217;ve every worked with Drupal&#8217;s menu system, you&#8217;ll find many of the arguments familiar, adapted, of course, for the WordPress framework. Read all about them in the <a href="http://wordpress.org/extend/plugins/wp-router/other_notes/">usage notes</a>, and check out the <a href="https://github.com/jbrinley/WP-Router/blob/master/WP_Router_Sample.class.php">sample code</a> included in the plugin.</p>
<h3>Ongoing Development</h3>
<p>Right now, this is at version 0.2, which is synonymous with &#8220;has all the features I thought to add initially, plus one more&#8221;. But I&#8217;m just one developer. What would make this plugin more useful to you? What doesn&#8217;t work like you expect it to? What part of the API is confusing? Please leave a comment here or <a href="https://github.com/jbrinley/WP-Router/issues">create an issue in Github</a>.</p>
<p>And if you&#8217;re interested in contributing, feel free to fork the project and send me updates. It&#8217;s <a href="https://github.com/jbrinley/WP-Router">hosted at Github</a>, with released copied over to <a href="http://wordpress.org/extend/plugins/wp-router/">WordPress&#8217;s plugin repository</a>. As usual with code I write, it&#8217;s <a href="http://www.opensource.org/licenses/mit-license.php">licensed under the MIT License</a> (i.e., do whatever you want with it, just mention where it came from).</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2011/05/24/simpler-wordpress-development-wp-router/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Tirzah Olivia Brinley</title>
		<link>http://xplus3.net/2011/04/26/tirzah-olivia-brinley/</link>
		<comments>http://xplus3.net/2011/04/26/tirzah-olivia-brinley/#comments</comments>
		<pubDate>Tue, 26 Apr 2011 13:36:49 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Etcetera]]></category>
		<category><![CDATA[Tirzah]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=397</guid>
		<description><![CDATA[After a very long Easter Sunday, Tirzah Olivia Brinley let out her first cry on Monday, April 25, 2011, sixteen minutes after midnight. Internet, meet Tirzah; Tirzah, meet Internet. I&#8217;m sure you&#8217;ll get along nicely.]]></description>
			<content:encoded><![CDATA[<p>After a very long Easter Sunday, Tirzah Olivia Brinley let out her first cry on Monday, April 25, 2011, sixteen minutes after midnight.<br />
<a href="http://xplus3.net/wp-content/uploads/2011/04/Titus_and_Tirzah.jpg"><img src="http://xplus3.net/wp-content/uploads/2011/04/Titus_and_Tirzah-296x300.jpg" alt="" title="Titus and Tirzah" width="296" height="300" class="alignnone size-medium wp-image-399" /></a></p>
<p>Internet, meet Tirzah; Tirzah, meet Internet. I&#8217;m sure you&#8217;ll get along nicely.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2011/04/26/tirzah-olivia-brinley/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Rethinking Object-Oriented WordPress Plugins</title>
		<link>http://xplus3.net/2011/03/08/rethinking-object-oriented-wordpress-plugins/</link>
		<comments>http://xplus3.net/2011/03/08/rethinking-object-oriented-wordpress-plugins/#comments</comments>
		<pubDate>Tue, 08 Mar 2011 18:50:11 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[design patterns]]></category>
		<category><![CDATA[object-oriented design]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[static]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=391</guid>
		<description><![CDATA[Following common practice in WordPress plugin development, you create a class for you plugin, instantiate that class with a $my_plugin = new My_Plugin(); in your main plugin file, and declare all your actions/filters in your class&#8217;s __construct() function, using something like: add_filter('init', array($this, 'my_init_function')); And then you go on to add your plugin&#8217;s JavaScript and CSS, register post types and &#8230; <a href="http://xplus3.net/2011/03/08/rethinking-object-oriented-wordpress-plugins/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Following common practice in WordPress plugin development, you create a class for you plugin, instantiate that class with a</p>
<pre>$my_plugin = new My_Plugin();</pre>
<p>in your main plugin file, and declare all your actions/filters in your class&#8217;s <code>__construct()</code> function, using something like:</p>
<pre>add_filter('init', array($this, 'my_init_function'));</pre>
<p>And then you go on to add your plugin&#8217;s JavaScript and CSS, register post types and taxonomies, look for query variables, etc.</p>
<p>I&#8217;m declaring that to be &#8220;wrong&#8221;, and I&#8217;m not going to do it anymore. Why? Because it&#8217;s not good objects-oriented design, and it seems to me that if you&#8217;re going to use objects, you should follow good object-oriented design patterns.<span id="more-391"></span></p>
<h3>What problems come from the current practice?</h3>
<ol>
<li><strong>Lack of coherency.</strong> The class is basically being used as a plugin namespace. It&#8217;s laudable to try to avoid polluting the global namespace with all your function names, but using a consistent, unique prefix for your functions accomplishes the same thing. Instead you end up with data and methods that <em>look</em> like they&#8217;re related to each other, but really have the most tenuous connection of being part of the same plugin.</li>
<li><strong>Poorly implemented singletons.</strong> Every plugin class really needs to be a singleton. Having two instance of the class would cause a range or problems, from inefficiency (<em>e.g.</em>, running the same query multiple times) to possible conflicts as the first instance of the plugin filters some data that is then re-filtered by the second instance. I&#8217;m not saying that singletons are inherently bad, but they are definitely overused (<a href="http://en.wikipedia.org/wiki/Singleton_pattern">Wikipedia says so!</a>, and, to quote <a href="http://www.cc2e.com/" title="Code Complete">the &#8220;Bible&#8221;</a>, &#8220;Be suspicious of classes of which there is only one instance&#8221;), and when they are used, they should be used deliberately and with proper care taken to avoid multiple instances.</li>
<li><strong>Barriers to code reuse and abstraction.</strong> Classes created this way can&#8217;t really be sub-classed (although I&#8217;ve yet to see a <code>final</code> keyword in front of a class), partially because of the singleton problem mentioned above, partially because there&#8217;s no clear definition of what the class <em>is</em>, so it doesn&#8217;t make sense to make a more specific version of it. This gets in the way of creating abstractions to share common code among similar classes, and greatly increases the complexity of any plugin of reasonable size.</li>
</ol>
<h3>What do we do about it?</h3>
<p>I&#8217;ll be the first to admit that I don&#8217;t know all the answers. I&#8217;m playing with some solutions right now that seem to be working well, and I welcome any suggestions for improving on these ideas.</p>
<ol>
<li><strong>Distinguish between class members and instance members.</strong> PHP includes the <code>static</code> keyword, to let you declare a property or method to be a member of the class itself, rather then an instance of the class. This is the proper place for your configuration settings, registering post types, etc. Instead of instantiating the class to tell WordPress about this information, create a static <code>init()</code> function to call in your base plugin file. <em>E.g.</em>, <code>My_Class::init()</code>.</li>
<li><strong>Use different classes for different things.</strong> Does your plugin create two separate post types? Create a class to declare each of them. Throw in some instance methods for interacting with your custom post meta.</li>
</ol>
<h4>Example</h4>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">class</span> My_Custom_Post_Type <span class="br0">&#123;</span>
  <span class="kw2">const</span> POST_TYPE_NAME <span class="sy0">=</span> <span class="st_h">'my_post_type'</span><span class="sy0">;</span>
  <span class="kw2">const</span> IMPORTANT_META <span class="sy0">=</span> <span class="st_h">'my_important_meta'</span><span class="sy0">;</span>
  <span class="kw2">private</span> <span class="re0">$post_id</span><span class="sy0">;</span>
&nbsp;
  <span class="kw2">public</span> static <span class="kw2">function</span> init<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_action<span class="br0">&#40;</span><span class="st_h">'init'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="kw3">get_class</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'register_post_type'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw2">public</span> static <span class="kw2">function</span> register_post_type<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$my_post_type_args</span> <span class="sy0">=</span> <span class="kw3">array</span><span class="br0">&#40;</span>
      <span class="co1">// some args go here</span>
    <span class="br0">&#41;</span><span class="sy0">;</span>
    register_post_type<span class="br0">&#40;</span><span class="kw2">self</span><span class="sy0">::</span><span class="me2">POST_TYPE_NAME</span><span class="sy0">,</span> <span class="re0">$my_post_type_args</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span> <span class="re0">$post_id</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">post_id</span> <span class="sy0">=</span> <span class="re0">$post_id</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> get_important_meta_field<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> get_post_meta<span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">post_id</span><span class="sy0">,</span> <span class="kw2">self</span><span class="sy0">::</span><span class="me2">IMPORTANT_META</span><span class="sy0">,</span> <span class="kw4">TRUE</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>This lets you abstract away the implementation (e.g., is it a custom post type or a custom table?) and just work with your new object&#8217;s well-defined interface. You can start doing things like creating sub-classes, using polymorphism, setting up factory objects to give you different types of objects depending on taxonomy terms, and all sorts of other concepts based on object-oriented design patterns. Basically, it lets us grow up and use the amazing advances in computer science and the discipline of coding that we&#8217;ve seen over the last several decades.</p>
<p>I would love to get some feedback on this. It&#8217;s a nascent idea that could use some better minds to help form it.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2011/03/08/rethinking-object-oriented-wordpress-plugins/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Hello, ChromeOS</title>
		<link>http://xplus3.net/2010/12/16/chromeos/</link>
		<comments>http://xplus3.net/2010/12/16/chromeos/#comments</comments>
		<pubDate>Thu, 16 Dec 2010 17:15:17 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Etcetera]]></category>
		<category><![CDATA[ChromeOS]]></category>
		<category><![CDATA[computers]]></category>
		<category><![CDATA[Cr-48]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=387</guid>
		<description><![CDATA[That would be the Cr-48 ChromeOS laptop that arrived unannounced at my door this week. Haven&#8217;t had much chance to delve into it, yet, but at the moment it&#8217;s looking like a good computer for: The kitchen Children Business meetings Casual web browsing General on-the-go connectivity, when a smartphone just isn&#8217;t enough (it does SSH and has a full-size keyboard) &#8230; <a href="http://xplus3.net/2010/12/16/chromeos/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://xplus3.net/wp-content/uploads/2010/12/IMG_20101216_120557.jpg"><img src="http://xplus3.net/wp-content/uploads/2010/12/IMG_20101216_120557-300x224.jpg" alt="" title="Cr-48 Mario" width="300" height="224" class="alignnone size-medium wp-image-388" /></a></p>
<p>That would be the <a href="http://www.google.com/chromeos/">Cr-48 ChromeOS laptop</a> that arrived unannounced at my door this week.</p>
<p>Haven&#8217;t had much chance to delve into it, yet, but at the moment it&#8217;s looking like a good computer for:</p>
<ul>
<li>The kitchen</li>
<li>Children</li>
<li>Business meetings</li>
<li>Casual web browsing</li>
<li>General on-the-go connectivity, when a smartphone just isn&#8217;t enough (it does SSH and has a full-size keyboard)</li>
</ul>
<p>More to come&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/12/16/chromeos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Understanding Rewrite Tags, or, Custom Permalinks for Custom Post Types in WordPress 3.0+, Part 2</title>
		<link>http://xplus3.net/2010/10/04/wp-rewrite-tags-in-permalinks/</link>
		<comments>http://xplus3.net/2010/10/04/wp-rewrite-tags-in-permalinks/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 12:49:18 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[mod_rewrite]]></category>
		<category><![CDATA[register_post_type]]></category>
		<category><![CDATA[rewrite]]></category>
		<category><![CDATA[URIs]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=344</guid>
		<description><![CDATA[You may recall my ancient post about customizing your custom post type permalinks. When I wrote that, I was still stumbling somewhat blindly through WordPress&#8217;s rewrite API. After hacking a little more with it, I think I finally understand what I&#8217;m doing enough to write a little more confidently. Rewrite Tags In my previous post, I had a slug like &#8230; <a href="http://xplus3.net/2010/10/04/wp-rewrite-tags-in-permalinks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>You may recall my ancient post about <a href="http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/">customizing your custom post type permalinks</a>. When I wrote that, I was still stumbling somewhat blindly through WordPress&#8217;s rewrite API. After hacking a little more with it, I think I finally understand what I&#8217;m doing enough to write a little more confidently.<span id="more-344"></span></p>
<h3>Rewrite Tags</h3>
<p>In my previous post, I had a slug like <code>project/%issue_project%/issue</code> for my <code>issue</code> post type. What exactly is that <code>%issue_project%</code> in the middle of that?</p>
<p>That would be a rewrite tag. WordPress uses these as keys for regular expressions it will add to its rewrite rules. When you add a custom post type or a custom taxonomy, WordPress automatically creates appropriate rewrite tags for you. <em>E.g.</em>, when you create an <code>issue</code> post type, WordPress will automatically create a rewrite tag called <code>%issue%</code>, with the pattern <code>([^/]+)</code>, or <code>(.+?)</code> if it&#8217;s a hierarchical post type, and this regexp will be rewritten to <code>post_type=issue&#038;name=$matches[1]</code>.</p>
<p>In my previous post, <code>%issue_project%</code> was the tag for the rewrite rule matching the <code>issue_project</code> taxonomy I had created using <code>register_taxonomy</code>.</p>
<h3>Making Your Own Rewrite Tags</h3>
<p>Knowing all this, you can create your own rewrite tags and use them in the slugs for your custom post types.</p>
<p>For my <a href="http://wordpress.org/extend/plugins/buggypress/">issue/bug tracking plugin</a>, I decided that I should use another custom post type instead of taxonomy for projects. That means that WordPress won&#8217;t automatically create the <code>%issue_project%</code> rewrite tag. I don&#8217;t want to use the <code>%project%</code> rewrite tag that it creates for my <code>project</code> post type, as that will add inappropriate (and conflicting) rules to my rewrite rules.</p>
<p>The solution is to create my own <code>%issue_project%</code> rewrite tag.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">global</span> <span class="re0">$wp_rewrite</span><span class="sy0">;</span>
<span class="re0">$wp_rewrite</span><span class="sy0">-&gt;</span><span class="me1">add_rewrite_tag</span><span class="br0">&#40;</span><span class="st_h">'%issue_project%'</span><span class="sy0">,</span> <span class="st_h">'(.+?/)?'</span><span class="sy0">,</span> <span class="st_h">'issue_project='</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>This matches <code>(.+?/)?</code> in a URL and puts the match into an ignored query var. Having created the rewrite tag, I can now use it in my post type&#8217;s slug.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1">register_post_type<span class="br0">&#40;</span><span class="st_h">'issue'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'label'</span><span class="sy0">=&gt;</span><span class="st_h">'Issues'</span><span class="sy0">,</span>
  <span class="st_h">'hierarchical'</span> <span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span>
  <span class="st_h">'rewrite'</span> <span class="sy0">=&gt;</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'slug'</span> <span class="sy0">=&gt;</span> <span class="st_h">'%issue_project%issue'</span><span class="sy0">,</span>
    <span class="st_h">'with_front'</span> <span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span>
  <span class="br0">&#41;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>This creates rewrite rules like</p>
<pre>[(.+?/)?issue/([^/]+)(/[0-9]+)?/?$] => index.php?issue_project=$matches[1]&#038;issue=$matches[2]&#038;page=$matches[3]</pre>
<h3>Creating Links</h3>
<p>Whenever you create your own rewrite tags, or use them in non-standard ways in post type slugs, you have to handle the rewrite tag in a <code>post_type_link</code> filter, replacing it with the appropriate string.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1">add_filter<span class="br0">&#40;</span><span class="st_h">'post_type_link'</span><span class="sy0">,</span> <span class="st_h">'my_post_type_link'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">3</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw2">function</span> my_post_type_link<span class="br0">&#40;</span> <span class="re0">$post_link</span><span class="sy0">,</span> <span class="re0">$post</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="re0">$leavename</span> <span class="sy0">=</span> <span class="kw4">FALSE</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="st_h">'%issue_project%'</span><span class="sy0">,</span> <span class="re0">$post_link</span><span class="br0">&#41;</span> <span class="sy0">===</span> <span class="st_h">'FALSE'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> <span class="re0">$post_link</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">is_object</span><span class="br0">&#40;</span><span class="re0">$post</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$post_id</span> <span class="sy0">=</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">ID</span><span class="sy0">;</span>
  <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span>
    <span class="re0">$post_id</span> <span class="sy0">=</span> <span class="re0">$post</span><span class="sy0">;</span>
    <span class="re0">$post</span> <span class="sy0">=</span> get_post<span class="br0">&#40;</span><span class="re0">$post_id</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="kw3">is_object</span><span class="br0">&#40;</span><span class="re0">$post</span><span class="br0">&#41;</span> <span class="sy0">||</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">!=</span> <span class="st_h">'issue'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> <span class="re0">$post_link</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="re0">$project_slug</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span>
  <span class="re0">$project_id</span> <span class="sy0">=</span> get_post_meta<span class="br0">&#40;</span><span class="re0">$post_id</span><span class="sy0">,</span> <span class="st_h">'_issue_project'</span><span class="sy0">,</span> <span class="kw4">TRUE</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$project_id</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$project_slug</span> <span class="sy0">=</span> get_page_uri<span class="br0">&#40;</span><span class="re0">$project_id</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="re0">$project_slug</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="co1">// remove project prefix</span>
    <span class="kw1">return</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="st_h">'%issue_project%'</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$post_link</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="co1">// put project slug in place of %issue_project%</span>
  <span class="kw1">return</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="st_h">'%issue_project%'</span><span class="sy0">,</span> <span class="st_h">'project/'</span><span class="sy0">.</span><span class="re0">$project_slug</span><span class="sy0">.</span><span class="st_h">'/'</span><span class="sy0">,</span> <span class="re0">$post_link</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/10/04/wp-rewrite-tags-in-permalinks/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Solr and JSONP</title>
		<link>http://xplus3.net/2010/09/21/solr-and-jsonp/</link>
		<comments>http://xplus3.net/2010/09/21/solr-and-jsonp/#comments</comments>
		<pubDate>Tue, 21 Sep 2010 12:04:26 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[JSONP]]></category>
		<category><![CDATA[Solr]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=337</guid>
		<description><![CDATA[Need to send an Ajax request to a Solr server that&#8217;s on a different domain? You will, of course, need to use JSONP instead of an ordinary JSON request, due to JavaScript&#8217;s cross-domain security restrictions. To get a properly padded response from Solr, add the json.wrf parameter to your query string, giving it the name of your callback function. In &#8230; <a href="http://xplus3.net/2010/09/21/solr-and-jsonp/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Need to send an Ajax request to a Solr server that&#8217;s on a different domain? You will, of course, need to use <a href="http://en.wikipedia.org/wiki/JSON#JSONP">JSONP</a> instead of an ordinary JSON request, due to JavaScript&#8217;s cross-domain security restrictions. To get a properly padded response from Solr, add the <code>json.wrf</code> parameter to your query string, giving it the name of your callback function. In jQuery:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1">jQuery.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
  url<span class="sy0">:</span> mySolrUrl<span class="sy0">,</span>
  data<span class="sy0">:</span> myQueryParameters<span class="sy0">,</span>
  success<span class="sy0">:</span> mySuccessCallback<span class="sy0">,</span>
  dataType<span class="sy0">:</span> <span class="st0">'jsonp'</span><span class="sy0">,</span>
  jsonp<span class="sy0">:</span> <span class="st0">'json.wrf'</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Of course, for this to work the Solr server you&#8217;re accessing needs to be publicly accessible, which probably isn&#8217;t ideal for security.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/09/21/solr-and-jsonp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Excerpts for WordPress Pages</title>
		<link>http://xplus3.net/2010/09/15/excerpts-for-wordpress-pages/</link>
		<comments>http://xplus3.net/2010/09/15/excerpts-for-wordpress-pages/#comments</comments>
		<pubDate>Wed, 15 Sep 2010 18:59:19 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[excerpts]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[register_post_type]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=335</guid>
		<description><![CDATA[WordPress lets you create excerpts for Posts, but not for Pages. Generally, that makes good sense. If you need excerpts for pages, though, it&#8217;s pretty simple to add. function my_init&#40;&#41; &#123; add_post_type_support&#40;'page', array&#40;'excerpt'&#41;&#41;; &#125; add_action&#40;'init', 'my_init'&#41;; That&#8217;s all there is to it. Works with WordPress 3.0+. Update 2010-10-01: Hey, look, I made it into a plugin.]]></description>
			<content:encoded><![CDATA[<p>WordPress lets you create excerpts for Posts, but not for Pages. Generally, that makes good sense. If you need excerpts for pages, though, it&#8217;s pretty simple to add.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="php"><pre class="de1"><span class="kw2">function</span> my_init<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  add_post_type_support<span class="br0">&#40;</span><span class="st_h">'page'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'excerpt'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
add_action<span class="br0">&#40;</span><span class="st_h">'init'</span><span class="sy0">,</span> <span class="st_h">'my_init'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>That&#8217;s all there is to it. Works with WordPress 3.0+.</p>
<p><strong>Update 2010-10-01:</strong> Hey, look, <a href="http://wordpress.org/extend/plugins/page-excerpts/">I made it into a plugin</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/09/15/excerpts-for-wordpress-pages/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Downgrade PHP to 5.2 on Ubuntu 10.04</title>
		<link>http://xplus3.net/2010/08/25/downgrade-php-to-5-2-on-ubuntu/</link>
		<comments>http://xplus3.net/2010/08/25/downgrade-php-to-5-2-on-ubuntu/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 17:13:41 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[aptitude]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=328</guid>
		<description><![CDATA[As of version 6.14, Drupal works with PHP 5.3, but many essential modules still issue warnings (usually due to passing expressions by reference). If your Ubuntu 10.04 (Lucid Lynx) server is running 5.3, this script will automate the downgrade to the latest 5.2 by telling aptitude to use the source lists for Ubuntu 9.10 (Karmic Koala). Thanks to Nick Veenhof, &#8230; <a href="http://xplus3.net/2010/08/25/downgrade-php-to-5-2-on-ubuntu/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>As of version 6.14, Drupal works with PHP 5.3, but many essential modules still issue warnings (usually due to passing expressions by reference). If your Ubuntu 10.04 (Lucid Lynx) server is running 5.3, this script will automate the downgrade to the latest 5.2 by telling aptitude to use the source lists for Ubuntu 9.10 (Karmic Koala).</p>
<p>Thanks to <a href="http://www.nickveenhof.be/blog/reverting-or-downgrading-php-53-52-ubuntu-lucid-lynx-1004">Nick Veenhof</a>, <a href="http://mrkandy.wordpress.com/2010/04/16/install-php-5-2-x-in-ubuntu-10-04-lucid/">mrkandy</a>, and their many commenters, from whom this script is derived.</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="re2">php_installed</span>=<span class="sy0">`</span><span class="kw2">dpkg</span> <span class="re5">-l</span> <span class="sy0">|</span> <span class="kw2">grep</span> php<span class="sy0">|</span> <span class="kw2">awk</span> <span class="st_h">'{print $2}'</span> <span class="sy0">|</span><span class="kw2">tr</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span> <span class="st0">&quot; &quot;</span><span class="sy0">`</span>
&nbsp;
<span class="co0"># remove all php packge</span>
<span class="kw2">sudo</span> <span class="kw2">aptitude</span> purge <span class="sy0">`</span><span class="kw2">dpkg</span> <span class="re5">-l</span> <span class="sy0">|</span> <span class="kw2">grep</span> php<span class="sy0">|</span> <span class="kw2">awk</span> <span class="st_h">'{print $2}'</span> <span class="sy0">|</span><span class="kw2">tr</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span> <span class="st0">&quot; &quot;</span><span class="sy0">`</span>
&nbsp;
<span class="co0"># use karmic for php pakage</span>
<span class="co0"># pin-params:  a (archive), c (components), v (version), o (origin) and l (label).</span>
<span class="kw3">echo</span> <span class="re5">-e</span> <span class="st0">&quot;Package: php5<span class="es1">\n</span>Pin: release a=karmic<span class="es1">\n</span>Pin-Priority: 991<span class="es1">\n</span>&quot;</span>  <span class="sy0">|</span> <span class="kw2">sudo</span> <span class="kw2">tee</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>preferences.d<span class="sy0">/</span>php <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
<span class="kw2">apt-cache search</span> php5-<span class="sy0">|</span><span class="kw2">grep</span> php5-<span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{print &quot;Package:&quot;, $1,&quot;\nPin: release a=karmic\nPin-Priority: 991\n&quot;}'</span><span class="sy0">|</span><span class="kw2">sudo</span> <span class="kw2">tee</span> <span class="re5">-a</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>preferences.d<span class="sy0">/</span>php <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
<span class="kw2">apt-cache search</span> <span class="re5">-n</span> libapache2-mod-php5 <span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{print &quot;Package:&quot;, $1,&quot;\nPin: release a=karmic\nPin-Priority: 991\n&quot;}'</span><span class="sy0">|</span> <span class="kw2">sudo</span> <span class="kw2">tee</span> <span class="re5">-a</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>preferences.d<span class="sy0">/</span>php <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
<span class="kw3">echo</span> <span class="re5">-e</span> <span class="st0">&quot;Package: php-pear<span class="es1">\n</span>Pin: release a=karmic<span class="es1">\n</span>Pin-Priority: 991<span class="es1">\n</span>&quot;</span>  <span class="sy0">|</span> <span class="kw2">sudo</span> <span class="kw2">tee</span> <span class="re5">-a</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>preferences.d<span class="sy0">/</span>php <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
&nbsp;
<span class="co0"># add karmic to source list</span>
<span class="kw2">egrep</span> <span class="st_h">'(main restricted|universe|multiverse)'</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>sources.list<span class="sy0">|</span><span class="kw2">grep</span> <span class="re5">-v</span> <span class="st0">&quot;#&quot;</span><span class="sy0">|</span> <span class="kw2">sed</span> s<span class="sy0">/</span>lucid<span class="sy0">/</span>karmic<span class="sy0">/</span>g <span class="sy0">|</span> <span class="kw2">sudo</span> <span class="kw2">tee</span> <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>sources.list.d<span class="sy0">/</span>karmic.list <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
&nbsp;
<span class="co0"># update package database (use apt-get if aptitude crash)</span>
<span class="kw2">sudo</span> <span class="kw2">apt-get update</span>
&nbsp;
<span class="co0"># install php</span>
<span class="kw2">sudo</span> <span class="kw2">apt-get install</span> <span class="re1">$php_installed</span>
&nbsp;
<span class="kw2">sudo</span> <span class="kw2">aptitude</span> hold <span class="sy0">`</span><span class="kw2">dpkg</span> <span class="re5">-l</span> <span class="sy0">|</span> <span class="kw2">grep</span> php5<span class="sy0">|</span> <span class="kw2">awk</span> <span class="st_h">'{print $2}'</span> <span class="sy0">|</span><span class="kw2">tr</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span> <span class="st0">&quot; &quot;</span><span class="sy0">`</span>
&nbsp;
<span class="co0">#done</span></pre></div></div></div></div></div></div></div>


<p>Of course, make sure to restart Apache when you&#8217;re finished.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/08/25/downgrade-php-to-5-2-on-ubuntu/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

