<?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 &#187; plugins</title>
	<atom:link href="http://xplus3.net/tag/plugins/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>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>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>12</slash:comments>
		</item>
		<item>
		<title>Filtering on a Non-Standard Database Field with WordPress</title>
		<link>http://xplus3.net/2010/08/08/filtering-on-a-non-standard-database-field-with-wordpress/</link>
		<comments>http://xplus3.net/2010/08/08/filtering-on-a-non-standard-database-field-with-wordpress/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 03:14:17 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[geocoding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=318</guid>
		<description><![CDATA[There&#8217;s one primary distinction between Drupal and WordPress. In Drupal, URLs map to PHP functions. In WordPress, URLs map to documents (or, quite often, collections of documents). The former can certainly be powerful and easy to work with. The latter, once you get used to the paradigm, can provide an incredible simplicity, powerful in its own way. I was building &#8230; <a href="http://xplus3.net/2010/08/08/filtering-on-a-non-standard-database-field-with-wordpress/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s one primary distinction between Drupal and WordPress. In Drupal, URLs map to PHP functions. In WordPress, URLs map to documents (or, quite often, collections of documents). The former can certainly be powerful and easy to work with. The latter, once you get used to the paradigm, can provide an incredible simplicity, powerful in its own way.</p>
<p>I was building a website today that has a location-based search component. Basically, I have a collection of posts with addresses, and I need to be able to search for addresses within a given distance of a queried address, and sort them by said distance. To be honest, that&#8217;s hard to do with WordPress. But it is possible&#8230;<br />
<span id="more-318"></span></p>
<h3>Step 1: Create a Table to Hold Coordinates</h3>
<p>To start out, you need to add a database table to hold the coordinates for each address. So use <code>register_activation_hook()</code> to point to a function that adds your table:</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_activation_function<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">global</span> <span class="re0">$wpdb</span><span class="sy0">;</span>
    <span class="kw1">require_once</span><span class="br0">&#40;</span>ABSPATH <span class="sy0">.</span> <span class="st_h">'wp-admin/includes/upgrade.php'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'providers'</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$table</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$sql</span> <span class="sy0">=</span> <span class="st0">&quot;CREATE TABLE &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates (
                pid bigint(20) unsigned NOT NULL,
                latitude double,
                longitude double,
                UNIQUE KEY pid (pid),
                INDEX latitude (latitude),
                INDEX longitude (longitude)
              ) /*!40100 DEFAULT CHARACTER SET utf8 */;&quot;</span><span class="sy0">;</span>
      dbDelta<span class="br0">&#40;</span><span class="re0">$sql</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>I&#8217;m using the <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html">Google Geocoding API</a> to populate this table based on an address I enter when creating a post.</p>
<h3>Step 2: Look for a Query Parameter</h3>
<p>I&#8217;m going to look for a query parameter that I&#8217;ll designate as <code>ll</code> (short for &#8220;latitude/longitude&#8221;), so you can do a search with a URL like <code>http://example.com/?ll=40.0,-85.7</code>. We need to tell WordPress to look for this parameter, using the <code>query_vars</code> filter.</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_query_vars_filter<span class="br0">&#40;</span> <span class="re0">$array</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$array</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st_h">'ll'</span><span class="sy0">;</span>
    <span class="kw1">return</span> <span class="re0">$array</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Pretty simple, no? That just tells WordPress to add <code>ll</code> to the <code>WP_Query->query_vars</code> array if it&#8217;s present in the URL.</p>
<h3>Step 3: Modify the SQL Query</h3>
<p>Now for the hard part: we need to tell WordPress to modify the SQL query it uses to select posts if this parameter is present. To do this, we&#8217;ll use a collection of filters: <code>posts_fields</code>, <code>posts_join</code>, <code>posts_groupby</code>, and <code>posts_orderby</code>.</p>
<p>First, we&#8217;ll use <code>posts_fields</code> to add a field to the <code>SELECT</code> statement. By default, the query returns <code>wp_posts.*</code>. We need to add a field for the distance from the given coordinates to each post&#8217;s coordinates. I&#8217;ll call that field <code>distance</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> posts_fields<span class="br0">&#40;</span> <span class="re0">$fields</span><span class="sy0">,</span> <span class="re0">$query</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">global</span> <span class="re0">$wpdb</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'ll'</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw3">list</span><span class="br0">&#40;</span><span class="re0">$lat</span><span class="sy0">,</span> <span class="re0">$lng</span><span class="br0">&#41;</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">','</span><span class="sy0">,</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'ll'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$fields</span> <span class="sy0">.=</span> <span class="kw3">sprintf</span><span class="br0">&#40;</span><span class="st0">&quot;, ( 3959 * acos( cos( radians( <span class="es6">%f</span> ) ) * cos( radians( &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates.latitude ) ) * cos( radians( &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates.longitude ) - radians( <span class="es6">%f</span> ) ) + sin( radians( <span class="es6">%f</span> ) ) * sin( radians( &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates.latitude ) ) ) ) AS distance&quot;</span><span class="sy0">,</span> <span class="re0">$lat</span><span class="sy0">,</span> <span class="re0">$lng</span><span class="sy0">,</span> <span class="re0">$lat</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">return</span> <span class="re0">$fields</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Without getting into the details of the math, this tells MySQL to calculate the distance between two sets of coordinates in miles (3,959 is the circumference of the earth in miles) and call the result <code>distance</code>.</p>
<p><code>posts_join</code> adds a <code>JOIN</code> clause to the query, so we can link the <code>posts</code> table with our <code>coordinates</code> table.</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> posts_join<span class="br0">&#40;</span> <span class="re0">$join</span><span class="sy0">,</span> <span class="re0">$query</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">global</span> <span class="re0">$wpdb</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'ll'</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$join</span> <span class="sy0">.=</span> <span class="st0">&quot; LEFT JOIN &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates ON &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">posts</span><span class="sy0">.</span><span class="st0">&quot;.ID = &quot;</span><span class="sy0">.</span><span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">prefix</span><span class="sy0">.</span><span class="st0">&quot;coordinates.pid&quot;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">return</span> <span class="re0">$join</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p><code>posts_groupby</code> is used to limit to posts within a certain distance. It&#8217;s not strictly necessary, and you could conceivably add another query parameter to make this configurable.</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> posts_groupby<span class="br0">&#40;</span> <span class="re0">$groupby</span><span class="sy0">,</span> <span class="re0">$query</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">global</span> <span class="re0">$wpdb</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'ll'</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$groupby</span> <span class="sy0">.=</span> <span class="re0">$wpdb</span><span class="sy0">-&gt;</span><span class="me1">posts</span><span class="sy0">.</span><span class="st0">&quot;.ID HAVING distance &lt; 100&quot;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">return</span> <span class="re0">$groupby</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Finally, <code>posts_orderby</code> orders the results by distance (instead of the default post date).
</pre>


<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> posts_orderby<span class="br0">&#40;</span> <span class="re0">$orderby</span><span class="sy0">,</span> <span class="re0">$query</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">global</span> <span class="re0">$wpdb</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'ll'</span><span class="br0">&#93;</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$query</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'post_type'</span><span class="br0">&#93;</span> <span class="sy0">==</span> <span class="st_h">'provider'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$myorder</span> <span class="sy0">=</span> <span class="st0">&quot;distance ASC&quot;</span><span class="sy0">;</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$orderby</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="re0">$myorder</span> <span class="sy0">.=</span> <span class="st0">&quot;, &quot;</span><span class="sy0">.</span><span class="re0">$orderby</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">return</span> <span class="re0">$myorder</span>?<span class="re0">$myorder</span><span class="sy0">:</span><span class="re0">$orderby</span><span class="sy0">;</span> <span class="co1">// return the default if we haven't changed it</span>
  <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Notice that we need to prepend the value here, to override the default sort.</p>
<p>And there you have it. Quite a lot to go through, but the end result works exactly as intended.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/08/08/filtering-on-a-non-standard-database-field-with-wordpress/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Custom Templates for Custom Post Types in WordPress</title>
		<link>http://xplus3.net/2010/08/08/custom-post-type-templates/</link>
		<comments>http://xplus3.net/2010/08/08/custom-post-type-templates/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 19:07:32 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[template_redirect]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=315</guid>
		<description><![CDATA[Building on my previous post about creating archive pages for custom post types, there&#8217;s another piece to add to the puzzle. You archives pages will use the default index.php template. If you want to use a different template, you&#8217;ll need to hook into the template_redirect action to specify your template file. I like to use a file name like type-MY_POST_TYPE.php &#8230; <a href="http://xplus3.net/2010/08/08/custom-post-type-templates/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Building on my <a href="http://xplus3.net/2010/08/08/archives-for-custom-post-types-in-wordpress/">previous post about creating archive pages for custom post types</a>, there&#8217;s another piece to add to the puzzle.</p>
<p>You archives pages will use the default <code>index.php</code> template. If you want to use a different template, you&#8217;ll need to hook into the <code>template_redirect</code> action to specify your template file. I like to use a file name like <code>type-MY_POST_TYPE.php</code> (although that&#8217;s easily changed), using the function below.<br />
<span id="more-315"></span></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_template_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> is_robots<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">||</span> is_feed<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">||</span> is_trackback<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">||</span> is_single<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span><span class="sy0">;</span> <span class="co1">// run the default action</span>
  <span class="br0">&#125;</span>
  <span class="kw2">global</span> <span class="re0">$wp</span><span class="sy0">;</span>
  <span class="re0">$template</span> <span class="sy0">=</span> locate_template<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'type-'</span><span class="sy0">.</span><span class="re0">$wp</span><span class="sy0">-&gt;</span><span class="me1">query_vars</span><span class="br0">&#91;</span><span class="st_h">'post_type'</span><span class="br0">&#93;</span><span class="sy0">.</span><span class="st_h">'.php'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$template</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">include</span><span class="br0">&#40;</span><span class="re0">$template</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw3">exit</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">'template_redirect'</span><span class="sy0">,</span> <span class="st_h">'my_template_redirect'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>If you have an archive of <code>article</code> posts, WordPress will try to use <code>type-article.php</code>. If it doesn&#8217;t find the template file, it will fall back to <code>index.php</code>. You can add as many additional template names as you like to the array passed to <code>locate_template()</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/08/08/custom-post-type-templates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Archives for Custom Post Types in WordPress</title>
		<link>http://xplus3.net/2010/08/08/archives-for-custom-post-types-in-wordpress/</link>
		<comments>http://xplus3.net/2010/08/08/archives-for-custom-post-types-in-wordpress/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 18:43:22 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[register_post_type]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=311</guid>
		<description><![CDATA[When you create a new post type in WordPress using register_post_type(), WordPress does not automatically create a page for listing the archives of that post type. It&#8217;s possible to create one, though, without too much hassle. For example, you can create an post type called article, and set the permalink for that post type to articles (i.e., an article will &#8230; <a href="http://xplus3.net/2010/08/08/archives-for-custom-post-types-in-wordpress/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When you create a new post type in WordPress using <code>register_post_type()</code>, WordPress does not automatically create a page for listing the archives of that post type. It&#8217;s possible to create one, though, without too much hassle.</p>
<p>For example, you can create an post type called <code>article</code>, and set the permalink for that post type to <code>articles</code> (<em>i.e.</em>, an article will have a URL like <code>http://example.com/articles/my-article-title</code>).</p>
<p>Where do you go for a list of all articles, though? You might assume <code>http://example.com/articles/</code>, but you would be assuming erroneously. You could create a page with the slug <code>articles</code> and use a custom template for that page, but that doesn&#8217;t work with paging (<em>e.g.</em>, <code>http://example.com/articles/page/2/</code>).</p>
<p>Instead, you need to fiddle with WordPress&#8217;s rewrite rules. (And <a href="http://www.ballyhooblog.com/custom-post-types-wordpress-30-with-template-archives/">thanks to Andrew Wilson for helping me understand this</a>.)<br />
<span id="more-311"></span></p>
<p>Just after you call <code>register_post_type()</code> to define your custom post type, you&#8217;ll call another function, which I&#8217;ll call <code>register_post_type_archives</code>. It will take two arguments: the post type (<em>i.e.</em>, the first argument to <code>register_post_type</code>), and the base path you&#8217;ll be using. So to create an archives page for the articles example above, you would call:</p>
<pre>register_post_type_archives('article', 'articles');</pre>
<p>What does the <code>register_post_type_archives()</code> function look like? Here you go:</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> register_post_type_archives<span class="br0">&#40;</span> <span class="re0">$post_type</span><span class="sy0">,</span> <span class="re0">$base_path</span> <span class="sy0">=</span> <span class="st_h">''</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw2">global</span> <span class="re0">$wp_rewrite</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="re0">$base_path</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$base_path</span> <span class="sy0">=</span> <span class="re0">$post_type</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="re0">$rules</span> <span class="sy0">=</span> <span class="re0">$wp_rewrite</span><span class="sy0">-&gt;</span><span class="me1">generate_rewrite_rules</span><span class="br0">&#40;</span><span class="re0">$base_path</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="re0">$rules</span><span class="br0">&#91;</span><span class="re0">$base_path</span><span class="sy0">.</span><span class="st_h">'/?$'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st_h">'index.php?paged=1'</span><span class="sy0">;</span>
  <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$rules</span> <span class="kw1">as</span> <span class="re0">$regex</span><span class="sy0">=&gt;</span><span class="re0">$redirect</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="re0">$redirect</span><span class="sy0">,</span> <span class="st_h">'attachment='</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="kw4">FALSE</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$redirect</span> <span class="sy0">.=</span> <span class="st_h">'&amp;post_type='</span><span class="sy0">.</span><span class="re0">$post_type</span><span class="sy0">;</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span>  <span class="nu0">0</span> <span class="sy0">&lt;</span> <span class="kw3">preg_match_all</span><span class="br0">&#40;</span><span class="st_h">'@\$([0-9])@'</span><span class="sy0">,</span> <span class="re0">$redirect</span><span class="sy0">,</span> <span class="re0">$matches</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="kw1">for</span> <span class="br0">&#40;</span> <span class="re0">$i</span><span class="sy0">=</span><span class="nu0">0</span> <span class="sy0">;</span> <span class="re0">$i</span> <span class="sy0">&lt;</span> <span class="kw3">count</span><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">++</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
          <span class="re0">$redirect</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="st_h">'$matches['</span><span class="sy0">.</span><span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">.</span><span class="st_h">']'</span><span class="sy0">,</span> <span class="re0">$redirect</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    add_rewrite_rule<span class="br0">&#40;</span><span class="re0">$regex</span><span class="sy0">,</span> <span class="re0">$redirect</span><span class="sy0">,</span> <span class="st_h">'top'</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>Here, we use <code>$wp_rewrite->generate_rewrite_rules($base_path);</code> to create a default set of rules, and add the case where there are no arguments besides the base path. Then we append the <code>post_type</code> query parameter to each rule. Finally, replace each reference in the redirect (<em>e.g.</em>, <code>$1</code>) with the string <code>$matches[1]</code> (or the corresponding number).</p>
<p>Now you have a listing of articles at <code>http://example.com/articles/</code>. You can add other query parameters after that, too. For example, <code>http://example.com/articles/?s=penguin</code> to search articles.
</pre>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/08/08/archives-for-custom-post-types-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Custom Permalinks for Custom Post Types in WordPress 3.0+</title>
		<link>http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/</link>
		<comments>http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/#comments</comments>
		<pubDate>Thu, 20 May 2010 20:23:19 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[register_post_type]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=275</guid>
		<description><![CDATA[Update 2010-10-04: See Understanding Rewrite Tags for a somewhat more helpful treatment of the subject. I&#8217;ve been playing around with WordPress 3.0 to create a bug/issue-tracking plugin (i.e., using WP to track bugs, not to track WP bugs (although it could conceivably do that)). More details about the plugin will be forthcoming, but now is as good a time as &#8230; <a href="http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Update 2010-10-04:</strong> See <a href="http://xplus3.net/2010/10/04/wp-rewrite-tags-in-permalinks/">Understanding Rewrite Tags</a> for a somewhat more helpful treatment of the subject.</p>
<p>I&#8217;ve been playing around with WordPress 3.0 to create a bug/issue-tracking plugin (<em>i.e.</em>, using WP to track bugs, not to track WP bugs (although it could conceivably do that)). More details about the plugin will be forthcoming, but now is as good a time as any to share the solution to one problem I came across.</p>
<h3>Creating New Post Types and Taxonomies</h3>
<p>When you create a new post type, you use the <a href="http://codex.wordpress.org/Function_Reference/register_post_type"><code>register_post_type</code> function</a>. When you create a new post type through that function, WP creates a new rewrite rule base on the name you give the post type. In my case, I&#8217;ve created an <code>issue</code> post type, so all issues, by default, will have the permalink <code>/issue/%issue%/</code> (where <code>%issue%</code> is replaced with the post slug). Using the <code>rewrite</code> argument to <code>register_post_type</code>, you can change the beginning of the permalink to something different (<em>e.g.</em>, <code>/bugs/%issue%/</code>) should you so desire.<br />
<span id="more-275"></span><br />
Here&#8217;s the full function call I&#8217;m using (I&#8217;m not guaranteeing that everything here is correct or necessary, but it seems to be working):</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">'singular_label'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Issue'</span><span class="sy0">,</span>
  <span class="st_h">'description'</span> <span class="sy0">=&gt;</span> <span class="st_h">'A bug to fix, task to complete, or anything else that need to be done'</span><span class="sy0">,</span>
  <span class="st_h">'public'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'publicly_queryable'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'show_ui'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'query_var'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'rewrite'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'capability_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'post'</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">'menu_position'</span> <span class="sy0">=&gt;</span> <span class="kw4">NULL</span><span class="sy0">,</span>
  <span class="st_h">'supports'</span> <span class="sy0">=&gt;</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'title'</span><span class="sy0">,</span> <span class="st_h">'editor'</span><span class="sy0">,</span> <span class="st_h">'author'</span><span class="sy0">,</span> <span class="st_h">'thumbnail'</span><span class="sy0">,</span> <span class="st_h">'excerpt'</span><span class="sy0">,</span> <span class="st_h">'comments'</span><span class="sy0">,</span> <span class="st_h">'custom-fields'</span><span class="sy0">,</span> <span class="st_h">'revisions'</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="st_h">'menu_position'</span> <span class="sy0">=&gt;</span> <span class="nu0">5</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'</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>Similarly, you can create a custom taxonomy. In this case, I&#8217;ve created a taxonomy for projects, so issues can be assigned to projects. Much like a normal category will have a URL like <code>/category/%category%/</code>, my <code>issue_project</code> taxonomy has URLs matching <code>/issue_project/%issue_project%/</code>, which gives you a page with all issues matching the given project name. You can, once again, use the <code>rewrite</code> argument to give a different path (in my case, I&#8217;ve used <code>/project/%issue_project%/</code>).</p>
<p>Here&#8217;s the function call for the taxonomy (same caveats as above):</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_taxonomy<span class="br0">&#40;</span><span class="st_h">'issue_project'</span><span class="sy0">,</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">'Projects'</span><span class="sy0">,</span>
  <span class="st_h">'singular_label'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Project'</span><span class="sy0">,</span>
  <span class="st_h">'public'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'show_tagcloud'</span> <span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span>
  <span class="st_h">'hierarchical'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span>
  <span class="st_h">'query_var'</span> <span class="sy0">=&gt;</span> <span class="kw4">TRUE</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">'project'</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>


<h3>Putting Things Together</h3>
<p>Now, what if you want to combine these, to show the hierarchy in your URLs (<em>e.g.</em>, <code>/project/my-project/issue/horrible-bug/</code>)? </p>
<p>I first attempted to change the <code>slug</code> of the <code>issue</code> post type to <code>project/%issue_project%/issue</code>. That didn&#8217;t work. I had URLs that looked like <code>/project/%issue_project%/issue/horrible-bug/</code>; <code>%issue_project%</code> wasn&#8217;t being replaced. So I scrapped that idea.</p>
<p>I dug around for a while and found the <code>post_type_link</code> filter. Using that, I could add the project URL to the front of the issue URL when WP was building the permalink for an issue. That gave me the correct URLs, but they would 404.</p>
<p>So I dug around some more through the <code>WP_Rewrite</code> class and realized that I had been wasting a lot of time when I already had the solution: do both.</p>
<ol>
<li>Change the <code>slug</code> argument to <code>register_post_type</code> to <code>project/%issue_project%/issue</code></li>
<li>Hook into the <code>post_type_link</code> filter with a callback that replaces <code>%issue_project%</code> with the appropriate project slug.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		</item>
		<item>
		<title>Custom Thumbnails WordPress Plugin</title>
		<link>http://xplus3.net/2008/11/17/custom-thumbnails-wordpress-plugin/</link>
		<comments>http://xplus3.net/2008/11/17/custom-thumbnails-wordpress-plugin/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 15:15:03 +0000</pubDate>
		<dc:creator>Jonathan Brinley</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[thumbnails]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://xplus3.net/?p=148</guid>
		<description><![CDATA[When you upload images into WordPress, it automatically creates smaller derivative images to serve as thumbnails. You have little control over these derivatives, aside from setting their maximum dimensions. If you upload any non-image media (e.g., a PDF, a video, an MP3, a tarball, etc.), you don&#8217;t get any thumbnail, for fairly obvious reasons. Let&#8217;s say you want more control &#8230; <a href="http://xplus3.net/2008/11/17/custom-thumbnails-wordpress-plugin/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When you upload images into WordPress, it automatically creates smaller derivative images to serve as thumbnails. You have little control over these derivatives, aside from setting their maximum dimensions. If you upload any non-image media (<em>e.g.</em>, a PDF, a video, an MP3, a tarball, etc.), you don&#8217;t get any thumbnail, for fairly obvious reasons.</p>
<p>Let&#8217;s say you want more control over your image thumbnails, or you would like to have thumbnails attached to your other uploads. You would need to install a plugin like the <a href="http://wordpress.org/extend/plugins/custom-thumbnails/">Custom Thumbnails</a> plugin I just wrote.</p>
<h3>What it does</h3>
<p>WordPress associates each upload with a post or a page, using the item&#8217;s <code>post_parent</code> attribute. This plugin adds a field to the editing screen for your upload, allowing you to associate it with a &#8220;Parent Item&#8221;. Once thus associated, any time WordPress requests the thumbnail image of the parent item, it will retrieve the thumbnail image you uploaded, instead.</p>
<p><img src="http://xplus3.net/wp-content/uploads/2008/11/parent-image-field.png" alt="" title="Parent Item Field Example" width="400" height="113" class="alignnone size-full wp-image-149" /></p>
<h3>How it works</h3>
<p>Writing this plugin took me much farther into the bowels of WordPress than I had reached before. As it turns out, I needed to use four completely undocumented filters to achieve the effect I wanted.<span id="more-148"></span></p>
<h4><code>attachment_fields_to_edit</code></h4>
<p>The first step is to add the fields you want edit for your uploads. WordPress uses the function <code>get_attachment_fields_to_edit</code> to build the form fields. You can use the filter <code>attachment_fields_to_edit</code> to add or remove fields from this form. Your filter function needs to take two arguments, so add your filter using:</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">'attachment_fields_to_edit'</span><span class="sy0">,</span> <span class="st_h">'custom_thumbnail_fields_to_edit'</span><span class="sy0">,</span> <span class="nu0">11</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>The first argument is an associative array of form fields (<code>$form_fields</code> in the following code), the second is the attachment object we are currently editing (<code>$post</code>, since WordPress attachment objects are the same as post objects).</p>
<h5>Fields for images</h5>
<p>We add a select box to the form for image uploads. This select box will have a list of all other media files. So first we query the database for the list of files:</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">$attachments</span> <span class="sy0">=</span> get_children<span class="br0">&#40;</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'attachment'</span><span class="sy0">,</span>
  <span class="st_h">'order'</span> <span class="sy0">=&gt;</span> <span class="st_h">'ASC'</span><span class="sy0">,</span>
  <span class="st_h">'orderby'</span> <span class="sy0">=&gt;</span> <span class="st_h">'post_title'</span><span class="sy0">,</span>
  <span class="st_h">'exclude'</span> <span class="sy0">=&gt;</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">ID</span>
<span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Next we start to build the HTML for our select box:</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">$name</span> <span class="sy0">=</span> <span class="st0">&quot;attachments[<span class="es4">$post-&gt;ID</span>][post_parent]&quot;</span><span class="sy0">;</span>
<span class="re0">$html</span> <span class="sy0">=</span> <span class="st0">&quot;&lt;select id='<span class="es4">$name</span>' name='<span class="es4">$name</span>'&gt;&quot;</span><span class="sy0">;</span>
<span class="re0">$html</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;option value='0'&gt;&lt;/option&gt;&quot;</span><span class="sy0">;</span>
<span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$attachments</span> <span class="kw1">as</span> <span class="re0">$attachment</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$parent</span> <span class="sy0">=</span> get_post<span class="br0">&#40;</span><span class="re0">$attachment</span><span class="sy0">-&gt;</span><span class="me1">post_parent</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$parent</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">==</span> <span class="st_h">'attachment'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw1">continue</span><span class="sy0">;</span> <span class="br0">&#125;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$attachment</span><span class="sy0">-&gt;</span><span class="me1">ID</span> <span class="sy0">==</span> <span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">post_parent</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$selected</span> <span class="sy0">=</span> <span class="st0">&quot; selected='selected'&quot;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span>
    <span class="re0">$selected</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="re0">$html</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;option value='<span class="es4">$attachment-&gt;ID</span>'<span class="es4">$selected</span>&gt;&quot;</span><span class="sy0">;</span>
  <span class="re0">$option_text</span> <span class="sy0">=</span> <span class="kw3">array</span><span class="br0">&#40;</span> <span class="re0">$attachment</span><span class="sy0">-&gt;</span><span class="me1">post_title</span><span class="sy0">,</span> <span class="st_h">' ('</span><span class="sy0">.</span><span class="kw3">basename</span><span class="br0">&#40;</span><span class="re0">$attachment</span><span class="sy0">-&gt;</span><span class="me1">guid</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">')'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">strlen</span><span class="br0">&#40;</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">&gt;</span> <span class="nu0">62</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st_h">'...'</span><span class="sy0">;</span>
  <span class="br0">&#125;</span> <span class="kw1">elseif</span> <span class="br0">&#40;</span> <span class="kw3">strlen</span><span class="br0">&#40;</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="sy0">.</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">&gt;</span> <span class="nu0">65</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw3">substr</span><span class="br0">&#40;</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">62</span><span class="sy0">-</span><span class="kw3">strlen</span><span class="br0">&#40;</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'...'</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="re0">$html</span> <span class="sy0">.=</span> <span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="sy0">.</span><span class="re0">$option_text</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="sy0">;</span>
  <span class="re0">$html</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;/option&gt;&quot;</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
<span class="re0">$html</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;/select&gt;&quot;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>We create an empty option, then an option for each media item, with its ID as the value. I limited the text of the option to 65 characters so it doesn&#8217;t overflow the item editing box.</p>
<p>Finally, we add our new field to the <code>$form_fields</code> array:</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">$form_fields</span><span class="br0">&#91;</span><span class="st_h">'post_parent'</span><span class="br0">&#93;</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="br0">&#40;</span><span class="st0">&quot;Parent Item&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="st_h">'value'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span>
  <span class="st_h">'input'</span> <span class="sy0">=&gt;</span> <span class="st_h">'select'</span><span class="sy0">,</span>
  <span class="st_h">'select'</span> <span class="sy0">=&gt;</span> <span class="re0">$html</span><span class="sy0">,</span>
  <span class="st_h">'helps'</span> <span class="sy0">=&gt;</span> __<span class="br0">&#40;</span><span class="st0">&quot;If this is a thumbnail for another image, choose that image here.&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>The array keys are somewhat self-explanatory. <code>label</code> is the label, <code>value</code> is the default value, <code>input</code> can be one of text, textarea, or any arbitrary string. If you use an arbitrary string, you&#8217;ll use that string as a key for the HTML that will be printed for the form field (in this case, <code>select</code>). <code>helps</code> contains helpful text you want to include along with the field.</p>
<h5>Fields for other media</h5>
<p>Other media items cannot serve as thumbnails, so they don&#8217;t need the &#8220;Parent Item&#8221; field. They do, though, need the same options as images have for inserting your items into your post, including options to align the image and to display the thumbnail.</p>
<p>I copied the &#8220;Alignment&#8221; field directly from the <code>image_attachment_fields_to_edit</code> function that adds the field to image items. The &#8220;Display&#8221; field took a bit of editing from the &#8220;Size&#8221; field in <code>image_attachment_fields_to_edit</code>. First, we see if the item has a thumbnail image, using a function we&#8217;ll define later:</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">$thumb</span> <span class="sy0">=</span> custom_thumbnail_image_downsize<span class="br0">&#40;</span><span class="kw4">false</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="st_h">'thumbnail'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Then we add the radio buttons to choose among the thumbnail (if it exists), the text from the &#8220;Title&#8221; field, or the media icon. (&#8220;Media icon?&#8221;, you ask. Yes, WordPress comes with nine icons for representing various kinds of media files (<em>e.g.</em>, audio, video, spreadsheets, documents, etc.). It doesn&#8217;t give you any easy way to use these icons anywhere except on the Media Library page.)</p>
<p>Finally, return <code>$form_fields</code> and close the function.</p>
<h4><code>attachment_fields_to_save</code></h4>
<p>We now need to save date from our new form field when we save our images. We can use the <code>attachment_fields_to_save</code> filter hook to make sure our field is saved.</p>
<p>The <code>attachment_fields_to_save</code> filter function takes two arguments: the first is an associative array of data that will be saved (called <code>$post</code>); the latter is an associative array of the data that was submitted (<code>$attachment</code>$post['post_parent'] to the value of <code>$attachment['post_parent']</code>, using a series of <code>if</code> statements. In the event that we do change the <code>post_parent</code> of the item, assigning it as the thumbnail of another item, we need to make sure to unset the <code>post_parent</code> of the current thumbnail, if there is one.</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">$children</span> <span class="sy0">=</span> get_children<span class="br0">&#40;</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'post_parent'</span> <span class="sy0">=&gt;</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_parent'</span><span class="br0">&#93;</span><span class="sy0">,</span>
  <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'attachment'</span><span class="sy0">,</span>
  <span class="st_h">'post_mime_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'image'</span>
<span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$children</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$old_attachment</span> <span class="sy0">=</span> <span class="kw3">current</span><span class="br0">&#40;</span><span class="re0">$children</span><span class="br0">&#41;</span><span class="sy0">;</span>
  wp_update_post<span class="br0">&#40;</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'ID'</span> <span class="sy0">=&gt;</span> <span class="re0">$old_attachment</span><span class="sy0">-&gt;</span><span class="me1">ID</span><span class="sy0">,</span>
    <span class="st_h">'post_parent'</span> <span class="sy0">=&gt;</span> <span class="nu0">0</span>
  <span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>If <code>$attachment['post_parent']</code> is set to &#8217;0&#8242;, we need determine if the file was previously set as a thumbnail to another item and is now being removed, or if it is an attachment to a post/page and should remain as such.</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">$parent</span> <span class="sy0">=</span> get_post<span class="br0">&#40;</span> <span class="re0">$post</span><span class="br0">&#91;</span><span class="st_h">'post_parent'</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">$parent</span><span class="sy0">-&gt;</span><span class="me1">post_type</span> <span class="sy0">!=</span> <span class="st_h">'attachment'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">return</span> <span class="re0">$post</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Finally, change <code>$post['post_parent']</code> if necessary:</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">$post</span><span class="br0">&#91;</span><span class="st_h">'post_parent'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_parent'</span><span class="br0">&#93;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>And return the final version of <code>$post</code>.</p>
<h4><code>image_downsize</code></h4>
<p>Now that we have a way to record and store our associations, it&#8217;s time to tell WordPress to do something useful with that information.</p>
<p>When creating the <code>&lt;img&gt;</code> element for an image, WordPress calls the function <code>wp_get_attachment_image</code>, which, in turn, gets it <code>src</code> attribute from the function <code>wp_get_attachment_image_src</code>. These functions take a <code>$size</code> argument, which can be one of &#8220;thumbnail&#8221;, &#8220;medium&#8221;, or &#8220;full&#8221;, or an array containing the width and height of the image you want. This and the attachment ID get passed to the function <code>image_downsize</code> to see if there is a smaller version of the image to meet your size criteria.</p>
<p>This is where WordPress finally gives us a hook to latch onto. The <code>image_downsize</code> function calls the <code>image_downsize</code> filter. The filter function needs to take three arguments. The first <em>seems</em> to be deprecated (with no documentation and only one occurrence, it&#8217;s hard to say what it&#8217;s supposed to do), and can be safely ignored, in any case. The attachment ID and size fill out the remaining arguments. The filter should return an array containing the URL for the image, its width, and its height.</p>
<p>Since this plugin is only dealing with thumbnail images, we don&#8217;t want to change anything if the <code>$size</code> argument is something other than &#8220;thumbnail&#8221;. We have the option of returning <code>false</code> if the filter doesn&#8217;t need to do anything.</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">if</span> <span class="br0">&#40;</span> <span class="re0">$size</span> <span class="sy0">!=</span> <span class="st_h">'thumbnail'</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span> <span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Now we can see if our item has any images attached to it:</p>
<pre>$attachments = get_children( array(
  'post_parent' => $id,
  'post_type' => 'attachment',
  'post_mime_type' => 'image'
  )
);</pre>
<p>If so, we can call <code>wp_get_attachment_url</code> to get the URL for the first attached image, returning <code>false</code> if there are no attached thumbnails.</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">if</span> <span class="br0">&#40;</span> <span class="re0">$attachments</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">return</span> <span class="kw3">array</span><span class="br0">&#40;</span> wp_get_attachment_url<span class="br0">&#40;</span><span class="kw3">key</span><span class="br0">&#40;</span><span class="re0">$attachments</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="st_h">''</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span>
  <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>You may notice that I didn&#8217;t return aything for the width and height of the image. These really aren&#8217;t necessary, as they are just used to set the deprecated <code>width</code> and <code>height</code> attributes for the <code>&lt;img&gt;</code> tag. By returning empty strings, we ensure that those attributes are not created.</p>
<p>If you recall from the discussion earlier from the <code>custom_thumbnail_fields_to_edit</code> function, we use the <code>custom_thumbnail_image_downsize</code> function to see if non-image attachments have a thumbnail image.</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">$thumb</span> <span class="sy0">=</span> custom_thumbnail_image_downsize<span class="br0">&#40;</span><span class="kw4">false</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="st_h">'thumbnail'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>If you&#8217;re really doing your homework, you might have noticed that I used this in place of</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">$thumb</span> <span class="sy0">=</span> wp_get_attachment_thumb_url<span class="br0">&#40;</span><span class="re0">$post</span><span class="sy0">-&gt;</span><span class="me1">ID</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>which is used for the same purpose in the <code>image_attachment_fields_to_edit</code> function. Why the difference? <code>wp_get_attachment_thumb_url</code> calls <code>image_downsize</code>. Unfortunately, <code>image_downsize</code> uses <code>wp_attachment_is_image</code> to see if your attachment is an image before it will look for a thumbnail version and before it calls the <code>image_downsize</code> filter. That means that it won&#8217;t look for a thumbnail for non-image uploads. We have to bypass that and go straight to our filter function to see if our attachments have thumbnails. Simply rearranging a few lines of code would fix this issue, and <a href="http://trac.wordpress.org/ticket/8268">I&#8217;ll be requesting</a> that the WordPress developers do just that.</p>
<h4><code>media_send_to_editor</code></h4>
<p>Our last function handles the job of creating the HTML to send back to the editor when the user clicks the &#8220;Insert into Post&#8221; button. This filter takes three arguments: <code>$html</code>, the HTML created by the built-in functions and any other functions attached to this filter; <code>$attachment_id</code>, the ID of the item being inserted; and <code>$attachment</code>, the associative array that was posted when you clicked the &#8220;Insert into Post&#8221; button. The function should return the HTML that should be sent to the editor.</p>
<p>After checking that our item is not an image (since WordPress can handle images on its own), we look at <code>$attachment</code> to see what options the user chose. The value of <code>$attachment['media-display']</code> will determine the path our code takes. If the user chose &#8220;thumbnail&#8221;, we get the child images of the item:</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">$thumbnails</span> <span class="sy0">=</span> get_children<span class="br0">&#40;</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'post_parent'</span> <span class="sy0">=&gt;</span> <span class="re0">$attachment_id</span><span class="sy0">,</span>
  <span class="st_h">'post_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'attachment'</span><span class="sy0">,</span>
  <span class="st_h">'post_mime_type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'image'</span>
  <span class="br0">&#41;</span>
<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>If it has a thumbnail, we get an <code>&lt;img&gt;</code> tag for the thumbnail image and put it into the <code>$html</code> variable:</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">$html</span> <span class="sy0">=</span> get_image_tag<span class="br0">&#40;</span><span class="kw3">key</span><span class="br0">&#40;</span><span class="re0">$thumbnails</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_excerpt'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_title'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$align</span><span class="sy0">,</span> <span class="re0">$size</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>It the user chose &#8220;icon&#8221;, or if the thumbnail disappeared for some reason before the user submitted the form, we get an <code>&lt;img&gt;</code> tag for the appropriate icon:</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">$html</span> <span class="sy0">=</span> wp_get_attachment_image<span class="br0">&#40;</span><span class="re0">$attachment_id</span><span class="sy0">,</span> <span class="st_h">'thumbnail'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>The third argument to <code>wp_get_attachment_image</code> tells it to return an icon.</p>
<p>If the user chose &#8220;text&#8221;, then we can just let WordPress handle it like it normally would by returning <code>$html</code> unchanged.</p>
<p>Next we wrap the <code>&lt;img&gt;</code> in a link:</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">$url</span> <span class="sy0">=</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'url'</span><span class="br0">&#93;</span><span class="sy0">;</span>
<span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$url</span> <span class="sy0">==</span> get_attachment_link<span class="br0">&#40;</span><span class="re0">$attachment_id</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$rel</span> <span class="sy0">=</span> <span class="st_h">' rel=&quot;attachment wp-att-'</span><span class="sy0">.</span>attribute_escape<span class="br0">&#40;</span><span class="re0">$id</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'&quot;'</span><span class="sy0">;</span>
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span>
  <span class="re0">$rel</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
<span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$url</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$html</span> <span class="sy0">=</span> <span class="st_h">'&lt;a href=&quot;'</span> <span class="sy0">.</span> clean_url<span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&quot;<span class="es1">\&quot;</span><span class="es4">$rel</span>&gt;<span class="es4">$html</span>&lt;/a&gt;&quot;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Finally, we let any other filters (<em>e.g.</em>, to create captions or align the image) run on <code>$html</code> before we return it:</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">$html</span> <span class="sy0">=</span> apply_filters<span class="br0">&#40;</span> <span class="st_h">'image_send_to_editor'</span><span class="sy0">,</span> <span class="re0">$html</span><span class="sy0">,</span> <span class="re0">$attachment_id</span><span class="sy0">,</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_excerpt'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$attachment</span><span class="br0">&#91;</span><span class="st_h">'post_title'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$align</span><span class="sy0">,</span> <span class="re0">$url</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>At long last, we&#8217;re done. Once again, the <a href="http://wordpress.org/extend/plugins/custom-thumbnails/">Custom Thumbnails plugin</a> is available from the WordPress Plugin Directory if you would like to use it or see the full code.</p>
]]></content:encoded>
			<wfw:commentRss>http://xplus3.net/2008/11/17/custom-thumbnails-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

