<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Oh The Huge Manatee - Drupal]]></title>
  <link href="https://ohthehugemanatee.org/atom.xml" rel="self"/>
  <link href="https://ohthehugemanatee.org/"/>
  <updated>2016-08-13T17:32:55+02:00</updated>
  <id>https://ohthehugemanatee.org/</id>
  <author>
    <name><![CDATA[Campbell Vertesi (ohthehugemanatee)]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Drupal 8 RC 1 Is Out! What Now?]]></title>
    <link href="https://ohthehugemanatee.org/blog/2015/10/08/drupal-8-rc-1-is-out-what-now/"/>
    <updated>2015-10-08T11:16:02+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2015/10/08/drupal-8-rc-1-is-out-what-now</id>
    <content type="html"><![CDATA[<p>Last night (my time) I got the good news over twitter:</p>

<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr">Blue smoke from the chimney, I repeat blue smoke from the chimney!&#10;&#10;<a href="https://twitter.com/hashtag/Drupal8?src=hash">#Drupal8</a> release candidate 1 has been released! Good day for <a href="https://twitter.com/hashtag/Drupal?src=hash">#Drupal</a>!</p>&mdash; Marc Drummond (@MarcDrummond) <a href="https://twitter.com/MarcDrummond/status/651870155828412416">October 7, 2015</a></blockquote>


<script async src="https://ohthehugemanatee.org//platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>That&rsquo;s right, Drupal 8 has it&rsquo;s first release. But what does that mean? Is it done? Can I start using it yet? What kind of changes are coming? Will dawehner get to sleep, at last?</p>

<h2>Are we there yet?</h2>

<p>Despite all the rejoicing on social media, this isn&rsquo;t the final release for Drupal 8 &ndash; it&rsquo;s only the first Release Candidate. This means that we have (officially!) 0 &ldquo;critical&rdquo; bugs left to fix in Drupal 8. That means exactly what it sounds like: there are no critical, world-ending bugs left&hellip; <em>that we know of</em>. Just like any software product, we&rsquo;ll continue to discover critical issues through its entire life cycle. We&rsquo;re still finding occasional critical issues in Drupal 7 almost five years since its first release candidate; that&rsquo;s just a part of supporting a piece of software over the long term. The RC phase means that while Drupal 8 is stable enough to use, we&rsquo;re still discovering critical bugs a little too frequently to recommend it for everyone, in every use case.</p>

<p>&ldquo;A little too frequently&rdquo; means that the rate of critical bugs incoming is still too high to be able to promise the fast respond-and-fix turnaround that we want. Every two weeks we&rsquo;ll create a new Release Candidate version that fixes whatever new criticals have been discovered. Once the core team is confident that they can squash bugs in a timely enough manner, they&rsquo;ll (finally) release Drupal version 8.0.0.</p>

<h2>But when will it REALLY be released?</h2>

<p>&ldquo;When it&rsquo;s ready&rdquo; still applies! But we are very, very close now. To give you a point of reference, Drupal 7 went through four Release Candidates before release (two months). That codebase was a lot more fragile than this one, so it&rsquo;s reasonable to hope that we&rsquo;ll have a very Drupally Christmas season this year. Personally I&rsquo;m betting on January.</p>

<p><img src="https://www.drupal.org/files/christmas-ad.png"></p>

<h2>Can I use it yet?</h2>

<p><span style="font-size: 1.5em"><em>Yes!</em></span> <span style='font-size:0.5em'>Some terms and conditions apply.</span></p>

<p>Just because there are no criticals left, doesn&rsquo;t mean that D8 is completely bug-free! We have <a href="https://www.drupal.org/project/issues/search/drupal?assigned=&amp;submitted=&amp;project_issue_followers=&amp;status[]=1&amp;status[]=13&amp;status[]=8&amp;status[]=14&amp;status[]=4&amp;priorities[]=300&amp;categories[]=1&amp;version[]=8.0.x-dev&amp;issue_tags_op=%3D&amp;issue_tags=">a big pile of known &ldquo;major&rdquo; issues</a> that have been deferred until after 8.0.0, which should impact your decision. You can see at that link that some of them are already ready to be committed. The catch is that during the RC phase, we aren&rsquo;t allowed to commit these fixes. <a href="https://www.drupal.org/core/d8-allowed-changes#rc">We&rsquo;re basically only allowed to work on criticals and documentation</a>. So there are still some serious issues that might be a problem in some use cases.</p>

<p>The biggest issue (that I know of) is <a href="https://www.drupal.org/node/2542868">a potential incompatibility between Drupal 8&rsquo;s new &ldquo;cache tags&rdquo; header and some hosting providers</a>. The problem is that Drupal includes some important caching information on the &ldquo;back of the envelope&rdquo; of its response to a page request, and it&rsquo;s possible to run out of envelope! If the cache tags header gets too long for the web host to handle, it can behave unpredictably. You might get white screens of death, or it might just shorten the cache tags header, removing important information. There&rsquo;s a solution in the works to allow a maximum length setting, but it won&rsquo;t make it in until 8.0.1 (two weeks after 8.0.0). In the meantime you should avoid D8 if you have any very complex pages with many elements. The examples in that ticket are good ones: a news site with very complex layouts, or a single page site with a lot of &ldquo;stuff&rdquo; crammed onto the one, front page.</p>

<p>The other &ldquo;gotcha&rdquo; to bear in mind is that it will take some time for Drupal&rsquo;s contributed modules ecosystem to catch up with the new version. According to <a href="http://www.bluespark.com/status-top-100-contributed-modules-drupal-8">Bluespark&rsquo;s status of the top 100 modules for D8</a> page, so far only 9 of the top 100 D7 modules have a D8 release marked &ldquo;stable.&rdquo; 19 of those top 100 modules are included in D8 core however, so our total count is up to 28. This is enough to give a good foundation for relatively simple sites, especially if you have some PHP skills under your belt. But I wouldn&rsquo;t go building a complex Intranet on it just yet!</p>

<h2>Wait, so it&rsquo;s still busted?</h2>

<p>No! Drupal 8 is a solid platform for most use cases &ndash; that&rsquo;s the point of the RC release! It&rsquo;s time to go ahead and use it for site builds. Just take it easy and use it for simple sites, first. Give the rest of the community a chance to release stable modules, and hold off on that Facebook-buster behemoth website you&rsquo;ve got planned until a few months after launch.</p>

<h2>What happens after 8.0.0?</h2>

<p>After 8.0.0 is released, we will make an enormous, fundamental shift in how Drupal is developed. We will start using <a href="http://semver.org">semantic versioning</a> with a regular release schedule. Every two weeks we&rsquo;ll release a new &ldquo;patch level&#8217; release: 8.0.1, 8.0.2, and so on. Patch level releases will be bug fixes only, and will be backwards-compatible &ndash; that means they won&rsquo;t break anything on your site. Approximately every 6 months, we&rsquo;ll release a new &#8220;minor level&rdquo; release: 8.1.0, 8.2.0, etc. Minor releases are allowed to contain new features, but they are still guaranteed to be backwards-compatible. So even these releases won&rsquo;t break anything on your site. We&rsquo;re still <a href="">figuring out</a> the exact process for minor releases, but they will include similar phases to what we&rsquo;ve seen with D8 core: a beta phase, and release candidates until we&rsquo;re sure there are no more criticals.</p>

<p>What about API changes, and features that would break existing sites? We won&rsquo;t even start developing on those until well into the D8 life cycle. Those changes will belong in the 9.x branch, and will be kept completely separate from anything that could touch your site.</p>

<p>The key take-away here is that D8 updates should never break your site. They may add features, but they will not interfere with whatever you&rsquo;ve already built. We&rsquo;ll continue a regular pace of improving the product in a predictable, scheduled, and backwards-compatible way.</p>

<h2>Where are the best Drupal 8 release parties?</h2>

<p>The Drupal Association is coordinating promotion for official Drupal 8 launch parties. If you want to host one, just <a href="https://assoc.drupal.org/drupal-8-launch-party">fill out their form</a> and they&rsquo;ll help you promote it! So far no one has built a site mapping the parties, but keep an eye out in the #drupal hashtag on twitter!</p>

<h2>Who do I congratulate? Who do I thank?</h2>

<p>Drupal 8 RC 1 is the combined effort of more than 3200 contributors. That is an incredible number. By comparison, Apache, the world&rsquo;s most popular open source webserver, has 118 contributors. MySQL, the database platform which runs an enormous portion of the Internet, has 1320 contributors. So you can basically walk up to anyone at a Drupalcon and thank him or her!</p>

<p>Most of the contributors to Drupal 8 leaned on the support, training, and hand-holding of mentors at Drupal events all over the world. I know I needed a mentor for my first core contributions, and I got to turn around and mentor other people myself. The mentors are the support network that made this level of mass contribution possible.</p>

<p>But the level of effort is definitely not evenly distributed. Most contributors have made fewer than 20 registered contributions. <a href="https://drupal.org/u/dawehner">But</a> <a href="https://drupal.org/u/tim.plunkett">some</a> <a href="https://drupal.org/u/berdir">people</a> <a href="https://drupal.org/u/alexpott">have</a> <a href="https://drupal.org/u/wim-leers">really</a> <a href="https://drupal.org/u/sun">gone</a> <a href="https://drupal.org/u/damiankloip">above</a> <a href="https://drupal.org/u/xjm">and</a> <a href="https://drupal.org/u/g%C3%A1bor-hojtsy">beyond</a> <a href="https://drupal.org/u/larowlan">what</a> <a href="https://drupal.org/u/chx">anyone</a> <a href="https://drupal.org/u/andypost">would</a> <a href="https://drupal.org/u/ameteescu">expect</a>. <a href="https://drupal.org/u/jhodgdon">It&rsquo;s</a> <a href="https://drupal.org/u/yched">no</a> <a href="https://drupal.org/u/joelpittet">exaggeration</a> <a href="https://drupal.org/u/effulgentsia">to</a> <a href="https://drupal.org/u/yesct">say</a> <a href="https://drupal.org/u/swentel">that</a> <a href="https://drupal.org/u/cottser">these</a> <a href="https://drupal.org/u/nod_">people</a> <a href="https://drupal.org/u/vijaycs85">have</a> <a href="https://drupal.org/u/pwolanin">shaped</a> <a href="https://drupal.org/u/aspilicious">the</a> <a href="https://drupal.org/u/tstoeckler">future</a> <a href="https://drupal.org/u/xano">of</a> <a href="https://drupal.org/u/plach">the</a> <a href="https://drupal.org/u/lewisnyman">Internet</a>.</p>

<p>It is easy to concentrate on the number of contributions as the only metric of involvement in the release of D8. But some of the biggest influences on Drupal 8 have been community leaders, whose effort is not counted in commits under their own names. The initiative leads who architected and directed all this contribution: <a href="https://drupal.org/u/heyrocker">heyrocker</a>, <a href="https://drupal.org/u/Senpai">Senpai</a>, <a href="https://drupal.org/u/jlambert">jlambert</a>, <a href="https://drupal.org/u/Crell">Crell</a>, <a href="https://drupal.org/u/dmitrig01">dmitrig01</a>, <a href="https://drupal.org/u/g%C3%A1bor-hojtsy">Gábor Hojtsy</a>, <a href="https://drupal.org/u/jose-reyero">Jose Reyero</a>, <a href="https://drupal.org/u/mitchell">mitchell</a>, <a href="https://drupal.org/u/jenlampton">jenlampton</a>, <a href="https://drupal.org/u/bleen18">bleen18</a>, <a href="https://drupal.org/u/jackalope">jackalope</a>, <a href="https://drupal.org/u/ericduran">ericduran</a>, <a href="https://drupal.org/u/jhood">jhood</a>, <a href="https://drupal.org/u/jacine">jacine</a>, <a href="https://drupal.org/u/shyamala">shyamala</a>, <a href="https://drupal.org/u/rupl">rupl</a>, <a href="https://drupal.org/u/johnalbin">JohnAlbin</a>, <a href="https://drupal.org/u/twom">twom</a>, and <a href="https://drupal.org/u/sofiya">sofiya</a>. Without them, we would have had nothing to commit!</p>

<p>Listing all of those names brings to mind the platform that they all use to contribute and coordinate: <a href="https://drupal.org">drupal.org</a>, maintained by the <a href="https://assoc.drupal.org/">Drupal Association</a>. It also brings to mind the events, like Drupalcon, Drupalcamps, Dev Days, which everyone attends to collaborate, teach, and learn; also maintained by the <a href="https://assoc.drupal.org/">Drupal Association</a>. Not to mention the Drupal 8 Accelerate program, which raised $250,000 towards developer grants; also created and maintained by the <a href="https://assoc.drupal.org/">Drupal Association</a>. The people at the Association have worked tirelessly to support this release.</p>

<p>All of this developer time is extremely valuable, and not all of it came out of the developers&#8217; own free time. Huge swaths of Drupal 8 development have been sponsored by the companies that participate in the community. We&rsquo;ve only been tracking their contributions for a short time, but the information we have is powerful. This release would not have happened without the developer time donated by companies like <a href="https://acquia.com">Acquia</a>, <a href="http://www.md-systems.ch">MD Systems</a>, <a href="http://www.chapterthree.com">Chapter Three</a>, <a href="http://tag1consulting.com">Tag1</a>, and <a href="http://druid.fi">Druid</a>. A quick glance at <a href="https://www.drupal.org/drupal-services">Drupal.org&rsquo;s Drupal Services page</a> shows us that contribution is a normal part of the culture for the biggest Drupal companies. These were the top 5, but almost every major Drupal shop has contributed in some measure. Thank you to these companies for believing in our product and supporting it so generously.</p>

<p>Finally, the people who bear the greatest personal responsibility are definitely the core maintainers. These people don&rsquo;t just deserve your thanks; they deserve lifetime supplies of free beer sent to their homes. I can&rsquo;t offer that on a blog; all I can say is THANK YOU.</p>

<p><a href="https://drupal.org/u/effulgentsia">Alex Bronstein</a></p>

<p><a href="https://drupal.org/u/dries">Dries Buytaert</a></p>

<p><a href="https://drupal.org/u/webchick">Angie &ldquo;webchick&rdquo; Byron</a></p>

<p><a href="https://drupal.org/u/catch">Nat Catchpole</a></p>

<p><a href="https://drupal.org/u/xjm">Jess Myrbo</a></p>

<p><a href="https://drupal.org/u/alexpott">Alex Pott</a></p>

<p>To everyone who contributed, but especially the people I&rsquo;ve listed here: You&rsquo;ve made a new generation of Internet innovation possible. Thank you.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to Build a New Source for Drupal Migrate 8]]></title>
    <link href="https://ohthehugemanatee.org/blog/2015/05/02/how-to-build-a-new-source-for-drupal-migrate-8/"/>
    <updated>2015-05-02T16:10:36+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2015/05/02/how-to-build-a-new-source-for-drupal-migrate-8</id>
    <content type="html"><![CDATA[<p>This week I wanted to accomplish a task in Drupal 8 that would be simple in Drupal 7: Import several CSV files, each one related to the others by taxonomy terms. Most importantly, I wanted to do it with <a href="https://drupal.org/project/migrate">Migrate module</a>.</p>

<p>Migrate in Drupal 7 is a fantastic piece of code. It is not designed to be used from the GUI, rather, it provides a framework of &ldquo;source&rdquo;, &ldquo;destination&rdquo;, and &ldquo;migration&rdquo; classes so that even the most convoluted migration is 90% written for you. To create a migration in Drupal 7, you create a custom module, declare your migrations in a hook_info, and then extend the built in &ldquo;migration&rdquo; class. You instantiate one of the given classes for the source material (is it a CSV? JSON? Direct connection to a custom DB?), then one of the classes for the destination (is it a content type? Taxonomy term?). Then you add one simple line of code mapping each field from source to destination. If you know what you&rsquo;re doing, the task I had in mind shouldn&rsquo;t take more than 15 minutes per source.</p>

<p>It&rsquo;s not quite so easy in Drupal 8. First of all, with Migrate in core, we had to greatly simplify the goals for the module. The version of Migrate that is really functional and stable is specifically and <em>only</em> the basic framework. There is a separate migrate_drupal module to provide everything you need for migrating from Drupal 6 or 7. This has been a laser-tight focus on just the essentials, which means there&rsquo;s no UI, very little drush support, and definitely no nice extras like the ability to read non-Drupal sources.</p>

<p>My task this week became to write the first CSV source for Drupal 8 Migrate.</p>

<h1>Drupal 8 Migrate Overview</h1>

<p>Drupal 8 Migrations, when you&rsquo;re using classes that already exist, are actually even easier than Migrate 7. All you do is write a single YAML file for each kind of data you&rsquo;re transferring, and put it in a custom module&rsquo;s <em>config/install</em> directory. Your YAML file gives your migration a name and a group, tells us what the source is for data, maps source fields to destination fields, and tells us what the destination objects are. Here&rsquo;s an example Migration definition file from core. See if you can understand what&rsquo;s being migrated here.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">id</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">d6_system_site</span>
</span><span class='line'><span class="l-Scalar-Plain">label</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Drupal 6 site configuration</span>
</span><span class='line'><span class="l-Scalar-Plain">migration_groups</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Drupal 6</span>
</span><span class='line'><span class="l-Scalar-Plain">source</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">variable</span>
</span><span class='line'>  <span class="l-Scalar-Plain">variables</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_name</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_mail</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_slogan</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_frontpage</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_403</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">site_404</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">drupal_weight_select_max</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">admin_compact_mode</span>
</span><span class='line'><span class="l-Scalar-Plain">process</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_name</span>
</span><span class='line'>  <span class="l-Scalar-Plain">mail</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_mail</span>
</span><span class='line'>  <span class="l-Scalar-Plain">slogan</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_slogan</span>
</span><span class='line'>  <span class="s">&#39;page/front&#39;</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_frontpage</span>
</span><span class='line'>  <span class="s">&#39;page/403&#39;</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_403</span>
</span><span class='line'>  <span class="s">&#39;page/404&#39;</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">site_404</span>
</span><span class='line'>  <span class="l-Scalar-Plain">weight_select_max</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">drupal_weight_select_max</span>
</span><span class='line'>  <span class="l-Scalar-Plain">admin_compact_mode</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">admin_compact_mode</span>
</span><span class='line'><span class="l-Scalar-Plain">destination</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">config</span>
</span><span class='line'>  <span class="l-Scalar-Plain">config_name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">system.site</span>
</span></code></pre></td></tr></table></div></figure>


<p>You probably figured it out: this migration takes the system settings (variables) from a Drupal 6 site, and puts them into the Drupal 7 configuration. Not terribly hard, right? You can even do data transformations from the source field value to the destination.</p>

<p>Unfortunately, the only sources we have so far are for Drupal 6 and 7 sites, pulling directly from the database. If you want to use Migrate 8 the way we used Migrate 7, as an easy way to pull in data from arbitrary sources, you&rsquo;ll have to contribute.</p>

<h1>Writing a source plugin in Migrate_plus</h1>

<p>Enter <a href="https://www.drupal.org/sandbox/mikeryan/migrate_plus">Migrate Plus module</a>. This is the place in contrib, where we can fill out all the rest of the behavior we want from Migrate, that&rsquo;s not necessarily a core requirement. This is where we&rsquo;ll be writing our source plugin.</p>

<p>To add a source plugin, just create a .php file in migrate_plus/src/Plugins/migrate/source . Drupal will discover the new plugin automatically the next time you rebuild the cache. The filename has to be the same as the name of the class, so choose carefully! My file is called CSV.php . Here&rsquo;s the top of the file you need for a basic :</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * @file</span>
</span><span class='line'><span class="sd"> * Contains \Drupal\migrate_plus\Plugin\migrate\source\csv.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nx">Drupal\migrate_plus\Plugin\migrate\source</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">use</span> <span class="nx">Drupal\migrate\Plugin\migrate\source\SourcePluginBase</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Source for CSV files.</span>
</span><span class='line'><span class="sd"> *</span>
</span><span class='line'><span class="sd"> * @MigrateSource(</span>
</span><span class='line'><span class="sd"> *   id = &quot;csv&quot;</span>
</span><span class='line'><span class="sd"> * )</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">CSV</span> <span class="k">extends</span> <span class="nx">SourcePluginBase</span> <span class="p">{</span>
</span></code></pre></td></tr></table></div></figure>


<p>I&rsquo;m calling this out separately because for newbies to Drupal 8, this is the hard part. This is all the information that Drupal needs to be able to find your class when it needs it. The @file comment is important. That and the namespace below have to match the actual location of the .php file.</p>

<p>Then you declare any other classes that you need, with their full namespace. To start with all you need is SourcePluginBase.</p>

<p>Finally you have to annotate the class with that @MigrateSource(id=&ldquo;csv&rdquo;). This is how Migrate module knows that this is a MigrateSource, and the name of your Plugin. Don&rsquo;t miss it!</p>

<p>Inside the class, you must have the following methods. I&rsquo;ll explain a bit more about each afterwards.</p>

<ul>
<li>initializeIterator() : Should return a valid Iterator object.</li>
<li>getIds() : Should return an array that defines the unique identifiers of your data source.</li>
<li>__toString() : Should return a simple, string representation of the source.</li>
<li>fields() : Should return a definitive list of fields in the source.</li>
<li>__construct() : You don&rsquo;t NEED this method, but you probably will end up using it.</li>
</ul>


<h2>initializeIterator()</h2>

<p>An Iterator is a complicated sounding word for an Object that contains everything you need to read from a data source, and go through it one line at a time. Maybe you&rsquo;re used to fopen(&lsquo;path/to/file&rsquo;, &lsquo;r&rsquo;) to open a file, and then you write code for every possible operation with that file. An iterator takes care of all that for you. In the case of most file-based sources, you can just use the SplFileObject class that comes with PHP.</p>

<p>Any arguments that were passed in the source: section of the YAML file will be available under $this->configuration. So if my YAML looks like this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">source</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">csv</span>
</span><span class='line'>  <span class="l-Scalar-Plain">path</span><span class="p-Indicator">:</span> <span class="s">&#39;/vagrant/import/ACS_13_1YR_B28002_with_ann.csv&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>My initializeIterator( ) method can look like this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="k">public</span> <span class="k">function</span> <span class="nf">initializeIterator</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// File handler using our custom header-rows-respecting extension of SPLFileObject.</span>
</span><span class='line'>  <span class="nv">$file</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SplFileObject</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;path&#39;</span><span class="p">]);</span>
</span><span class='line'>  <span class="nv">$file</span><span class="o">-&gt;</span><span class="na">setFlags</span><span class="p">(</span><span class="nx">SplFileObject</span><span class="o">::</span><span class="na">READ_CSV</span><span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$file</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Not too complicated, right? This method is called right at the beginning of the migration, the first time Migrate wants to get any information out of your source. The iterator will be stored in $this->iterator.</p>

<h2>getIds()</h2>

<p>This method should return an array of all the unique keys for your source. A unique key is some value that&rsquo;s unique for that row in the source material. Sometimes there&rsquo;s more than one, which is why this is an array. Each key field name is also an array, with a child &ldquo;type&rdquo; declaration. This is hard to explain in English, but easy to show in code:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="k">public</span> <span class="k">function</span> <span class="nf">getIDs</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$ids</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span><span class='line'>  <span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;keys&#39;</span><span class="p">]</span> <span class="k">as</span> <span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$ids</span><span class="p">[</span><span class="nv">$key</span><span class="p">][</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;string&#39;</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$ids</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>We rely on the YAML author to tell us the key fields in the CSV, and we just reformat them accordingly. Type can be &lsquo;string&rsquo;, &lsquo;float&rsquo;, &lsquo;integer&rsquo;, whatever makes sense.</p>

<h2>__toString()</h2>

<p>This method has to return a simple string explanation of the source query. In the case of a file-based source, it makes sense to print the path to the file, like this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="k">public</span> <span class="k">function</span> <span class="nf">__toString</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">query</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>fields()</h2>

<p>This method returns an array of available fields on the source. The keys should be the machine names, the values are descriptive, human-readable names. In the case of the CSV source, we look for headers at the top of the CSV file and build the array that way.</p>

<h2>__construct()</h2>

<p>The constructor method is called whenever a class is instantiated. You don&rsquo;t technically HAVE to have a constructor on your source class, but you&rsquo;ll find it helpful. For the CSV source, I used the constructor to make sure we have all the configuration that we need. Then I try and set sane values for fields, based on any header in the file.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span><span class="k">array</span> <span class="nv">$configuration</span><span class="p">,</span> <span class="nv">$plugin_id</span><span class="p">,</span> <span class="nv">$plugin_definition</span><span class="p">,</span> <span class="nx">MigrationInterface</span> <span class="nv">$migration</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">parent</span><span class="o">::</span><span class="na">__construct</span><span class="p">(</span><span class="nv">$configuration</span><span class="p">,</span> <span class="nv">$plugin_id</span><span class="p">,</span> <span class="nv">$plugin_definition</span><span class="p">,</span> <span class="nv">$migration</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Path is required.</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;path&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">new</span> <span class="nx">MigrateException</span><span class="p">(</span><span class="s1">&#39;You must declare the &quot;path&quot; to the source CSV file in your source settings.&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Key field(s) are required</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;keys&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">new</span> <span class="nx">MigrateException</span><span class="p">(</span><span class="s1">&#39;You must declare the &quot;keys&quot; the source CSV file in your source settings.&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Set header rows from the migrate configuration.</span>
</span><span class='line'>  <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">headerRows</span> <span class="o">=</span> <span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;header_rows&#39;</span><span class="p">])</span> <span class="o">?</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;header_rows&#39;</span><span class="p">]</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Figure out what CSV columns we have.</span>
</span><span class='line'>  <span class="c1">// One can either pass in an explicit list of column names to use, or if we have</span>
</span><span class='line'>  <span class="c1">// a header row we can use the names from that</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">headerRows</span> <span class="o">&amp;&amp;</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;csvColumns&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">csvColumns</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Skip all but the last header</span>
</span><span class='line'>    <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">headerRows</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getNextLine</span><span class="p">();</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nv">$row</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getNextLine</span><span class="p">();</span>
</span><span class='line'>    <span class="k">foreach</span> <span class="p">(</span><span class="nv">$row</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$header</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$header</span> <span class="o">=</span> <span class="nx">trim</span><span class="p">(</span><span class="nv">$header</span><span class="p">);</span>
</span><span class='line'>      <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getIterator</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">csvColumns</span><span class="p">[]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="nv">$header</span><span class="p">,</span> <span class="nv">$header</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="k">elseif</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;csvColumns&#39;</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getIterator</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">csvColumns</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">configuration</span><span class="p">[</span><span class="s1">&#39;csvColumns&#39;</span><span class="p">];</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Profit!</h2>

<p>That&rsquo;s it! Four simple methods, and you have a new source type for Drupal 8 Migrate. Of course, you will probably find complications that require a bit more work. For CSV, supporting a header row turned out to be a real pain. Any time Migrate tried to &ldquo;rewind&rdquo; the source back to the first line, it would try and migrate the header row! I ended up extending SplFileObject just to handle this issue.</p>

<p>Here&rsquo;s the YAML file I used to test this, importing a list of states from some US Census data.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">id</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">states</span>
</span><span class='line'><span class="l-Scalar-Plain">label</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">States</span>
</span><span class='line'><span class="l-Scalar-Plain">migration_groups</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">US Census</span>
</span><span class='line'>
</span><span class='line'><span class="l-Scalar-Plain">source</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">csv</span>
</span><span class='line'>  <span class="l-Scalar-Plain">path</span><span class="p-Indicator">:</span> <span class="s">&#39;/vagrant/import/ACS_13_1YR_B28002_with_ann.csv&#39;</span>
</span><span class='line'>  <span class="l-Scalar-Plain">header_rows</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">2</span>
</span><span class='line'>  <span class="l-Scalar-Plain">fields</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Id2</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Geography</span>
</span><span class='line'>  <span class="l-Scalar-Plain">keys</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Id2</span>
</span><span class='line'>
</span><span class='line'><span class="l-Scalar-Plain">process</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Geography</span>
</span><span class='line'>  <span class="l-Scalar-Plain">vid</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span>
</span><span class='line'>      <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">default_value</span>
</span><span class='line'>      <span class="l-Scalar-Plain">default_value</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">state</span>
</span><span class='line'>
</span><span class='line'><span class="l-Scalar-Plain">destination</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">plugin</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">entity:taxonomy_term</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can see my CSV source and Iterator in the <a href="https://www.drupal.org/node/2458003">issue queue for migrate_plus</a>. Good luck, and happy migrating!</p>

<h2>Thanks</h2>

<p>I learned a lot this week. Big thanks to the <a href="https://www.drupal.org/node/2127611">Migrate Documentation</a>, but especially to <a href="https://www.drupal.org/u/chx">chx</a>, <a href="https://www.drupal.org/u/mikeryan">mikeryan</a>, and the other good folks in #drupal-migrate who helped set me straight.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupalgeddon: Best Practices Aren't Good Enough Anymore]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/11/03/drupalgeddon-means-we-cant-trust-humans-with-updates/"/>
    <updated>2014-11-03T17:30:32+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/11/03/drupalgeddon-means-we-cant-trust-humans-with-updates</id>
    <content type="html"><![CDATA[<p>Last week&rsquo;s <a href="https://www.drupal.org/PSA-2014-003">Public Service Announcement</a> from the Drupal security team caused a lot of attention. And rightfully so &ndash; it told us that the vast majority of Drupal 7 sites around the world are considered compromised. A mere 7 hours after critical security patch <a href="https://www.drupal.org/SA-CORE-2014-005">SA-CORE-2014-005</a> was released, robots were spotted in the wild, bulk-hacking Drupal 7 sites with this vulnerability. This is something that&rsquo;s never happened to the Drupal community before, and it is extremely serious. In some way it&rsquo;s our own version of Heartbleed and other highly-publicized critical vulnerabilities in open source software.</p>




<p>This issue should not reflect badly on the Drupal community, or the Drupal product at all. Vulnerabilities happen to every software project &ndash; particularly the large and complex ones like Drupal! In this case it was the result of a choice in the database abstraction layer to use emulated prepared statements. There&rsquo;s a great dissection of the whole vulnerability at <a href="http://blog.ircmaxell.com/2014/10/a-lesson-in-security.html">ircmaxell</a>, but the point here is that it was an intentional decision. We were aware of a theoretical security risk, just as we are in making lots of decisions. But theoretical risks don&rsquo;t mean much compared with real, measurable losses from the available alternatives. As I said before, this can happen to any software project, and Drupal is a relatively responsible, well written one. What&rsquo;s interesting now, is the response.</p>




<p>First of all, I am amazed to read responses from many Drupal users who are panicked at having to run a diff of their sites, because they don&rsquo;t have appropriate tools in place. If you are developing without a VCS and automated backups, you are doing more harm than good. Just stop. Take a week to learn the basic requirements of a development environment, and start employing them. End of story.</p>




<p>I&rsquo;m not concerned for those people &ndash; their sites were disasters waiting for an excuse anyway. What&rsquo;s frightening about this particular situation is that even if you are working with backups and a VCS, even if you patch critical security vulnerabilities on an aggressive schedule, it still wasn&rsquo;t good enough.</p>




<p>All of my Drupal 7 sites are affected by this PSA. I work for a large, well-respected agency, with access to leading-edge workflows and tools. We follow best practices. All of my sites are secured well beyond PCI requirements. But PCI requirements say that critical security patches have to be applied within 30 days of release. Our best practices include patch review from the tech lead, and validating patches on test environments before pushing them live. With only 7 hours between patch release and exploits in the wild, there isn&rsquo;t time for any of that.</p>




<p>I&rsquo;ve heard people complain that it&rsquo;s too difficult to update Drupal. &ldquo;drush up &mdash;security-only&rdquo; seems pretty simple to me, or at least simple enough that
 further simplification won&rsquo;t address the real problem. That&rsquo;s because the real problem isn&rsquo;t that it&rsquo;s difficult to apply updates &ndash; it&rsquo;s that a human be
ing has to initiate them. I live in the Central European timezone, GMT+6. The patch was released at 10PM for me, and bots were exploiting it by 5AM the following morning. I went to work that day and initiated the patching process, so that my patches could be &ldquo;responsibly&rdquo; deployed to live with 24-48 hours of client validation time on my dev and staging environments. Despite being relatively on top of patches and responding relatively quickly, the fact that I&rsquo;m human, and my clients are human, meant we never stood a chance of patching this issue fast enough. Even if we skipped validation, and even if the update process was just one button (rather than two commands), we would still have failed to update in time. I find myself reminded of the Battlestar Galactica pilot, where the Cylon robots are chasing the humans. After each hyperspace jump, the humans have 33 minutes to complete the calculations for another jump before the machines catch up with them. After 130 hours and 237 jumps, it becomes apparent that the humans&#8217; need for sleep is a critical vulnerability.</p>




<p>The only solution is automated patching. It&rsquo;s hard to figure out a workflow that allows it; indeed you&rsquo;re forced into post-hoc testing, which means engineering an easy rollback solution. The truth is that 99% of security patches will not affect any of the functionality you&rsquo;ve customized or upon which you rely, so hopefully this will be an edge case. But it&rsquo;s a problem that actually has to be addressed. Here&rsquo;s how I&rsquo;m adapting my own projects over the coming weeks:</p>




<p>Every wednesday, every hour, my Jenkins instance runs a script which checks modules and core for each project for security updates. When an update is available, it automatically creates a branch off of Stable (my staging branch), applies the updates, and pushes the result up to the server. My git scripts already create a new subdirectory environment for every pushed branch. Once the environment is ready, Jenkins runs all available behat tests against the new branch. If all tests pass, the branch is automatically merged back into Master, Stage, and Live, and pushed. This push operation triggers a normal Jenkins deployment, which takes a backup anyway. An email is generated to the project administrator advising them which security updates were automatically applied, and linking to the relevant changefiles.</p>




<p>I&rsquo;m excited about implementing this new layer of automation, because it builds on the best practice workflows I already like (test driven development, git flow VCS organization, automated deployment and backups&hellip;) to produce a tangible time savings and security improvement for my sites. At the same time, I can&rsquo;t say that this is something I recommend for EVERYONE, precisely because it requires such a high level of environment maintenance. When you&rsquo;re a one-person development shop, it&rsquo;s hard to afford the time to set up the perfect development environment. It&rsquo;s hard to convince those bottom-of-the-food-chain clients to pay for things like automated testing and deployment. And certainly once you have those things set up, you don&rsquo;t get paid for maintaining them!</p>




<p>I&rsquo;m going to be keeping my eyes open for better solutions that can be applied by the &ldquo;developer on the street.&rdquo; Something relatively easy, but which allows the same kind of automated, fast response time for security patches. I&rsquo;m interested in any ideas you want to post in the comments!</p>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bug: Multilingual Auto Label Will Break Your Entity Static Cache]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/07/01/bug-multilingual-auto-label-will-break-your-entity-static-cache/"/>
    <updated>2014-07-01T17:00:45+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/07/01/bug-multilingual-auto-label-will-break-your-entity-static-cache</id>
    <content type="html"><![CDATA[<p>This is an important one to note: If you use the popular <a href="https://www.drupal.org/project/auto_entitylabel">Automatic Entity Label</a> module on a multilingual site, <a href="https://www.drupal.org/node/2295325">it will break your paths</a> because of an interaction with Drupal&rsquo;s built in object cache. I looked at this briefly a few months ago and ran out of time, but my (badass) colleague <a href="https://www.drupal.org/u/bburg">bburg</a> figured it out this week.</p>

<p>For now, the only solution is a slow one &ndash; we clear static entity caches when we generate multilingual titles. That&rsquo;s not an awesome fix, but it&rsquo;s hard to think of a better one without any of the D8 cache tagging functionality. Massive kudos to bburg for figuring this out!</p>

<p>And for those of you keeping score, this is a good example of how to file a bug report for a really complex issue in a really popular module&hellip; and follow up until you resolve it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[D8 Core Sprint in DC]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/07/01/d8-core-sprint-in-dc/"/>
    <updated>2014-07-01T16:27:17+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/07/01/d8-core-sprint-in-dc</id>
    <content type="html"><![CDATA[<p>A quick note to all the Drupalists in the DC general area &ndash; Forum One is trying to put together a D8 core sprint in their DC office space. They&rsquo;re coordinating with the DC Meetup group to try and spread the word to as many community members as possible!</p>

<p>If you haven&rsquo;t been to a code sprint before, it&rsquo;s basically a coding party. Developers get together and help each other contribute better and faster by reviewing code on the spot, mentoring each other, and generally working in small ad-hoc groups. It&rsquo;s a lot of fun, and gives a big boost to development of the next generation of Drupal.</p>

<p>Forum One will provide the locale in downtown DC complete with pizza, beer, and soda. We also have a few of our core mentors on hand to help you get started if this is your first time contributing to core. Because of the building security, if you want to attend you <a href="http://www.eventbrite.com/e/drupal-8-code-sprint-with-forum-one-tickets-11921354091">have to register first</a>! I won&rsquo;t be able to attend, but my colleagues <a href="https://twitter.com/johnbburg">John Brandenburg</a> and <a href="https://twitter.com/kalpanagoel">Kalpana Goel</a> will be there mentoring. Go sign up now!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Authenticated User Caching Concepts in Drupal 7]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/06/09/authenticated-user-caching-in-drupal/"/>
    <updated>2014-06-09T22:21:01+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/06/09/authenticated-user-caching-in-drupal</id>
    <content type="html"><![CDATA[<p>Drupal has a wide variety of highly effective solutions for caching anonymous user content. The typical setup is APC, Memcached or Redis, and Varnish in front, and this can easily serve thousands of concurrent anonymous users. There is excellent documentation out there discussing this kind of simple caching.</p>

<p>But what about authenticated users? You can cache elements of the page using a method like <a href="https://drupal.org/project/rendercache">Render cache</a>, <a href="https://drupal.org/project/entitycache">Entity Cache</a>, or <a href="https://drupal.org/project/views_content_cache">Views Content Cache</a>. But Drupal still has to assemble each page for your users, a relatively heavy operation! If you want to address hundreds or thousands of authenticated users, you&rsquo;re simply SOL by these traditional approaches.</p>

<p>Enter the <a href="https://drupal.org/project/authcache">Auth Cache</a> suite of modules. Though this project has been around for quite some time, it had a reputation of being finicky and hard to set up. It got a significant rewrite in the last year thanks to <a href="https://drupal.org/users/znerol">znerol</a>, and is now a powerhouse of a module that brings authenticated user caching much closer to regular users.</p>

<p>I will say that this is still not for the squeamish. You have to really understand the building blocks of your site, and you will have to make a plan for each unique layout on your site. There are some page elements that are quite hard to build this way, but for the most part Authcache makes this easy.</p>

<h2>The theory</h2>

<p>The idea behind authenticated user caching is simple. We already have a great caching mechanism for pages that stay exactly the same for all users. So we simply identify the parts of the page that will change for each user, and use a placeholder for them instead. Think of it as a <user customized stuff here> tag in HTML. This way the page caching mechanism can ignore the customized content, and focus on the stuff that IS the same across all requests.</p>

<p>There are three major ways of doing this placeholder: AJAX, ESI, and Cookies.</p>

<p>With AJAX, you just include a little JS that says &ldquo;fill this DIV with the contents of <a href="http://example.com/user/customized/thing">http://example.com/user/customized/thing</a>&rdquo;. The client&rsquo;s web browser makes a second call to the server, which is configured to allow /user/customized/thing through the cache all the way to your website. Drupal (or whatever you&rsquo;re running) fills in the HTML that belongs in that div and returns it to the browser. Congratulations! You just served an authenticated user a page which was 99% cached. You only had to generate the contents of one div.</p>

<p>ESI is short for <a href="https://en.wikipedia.org/wiki/Edge_Side_Includes">Edge Side Includes</a>, a small extension to HTML which effectively does the same thing as that Javascript, but on the &ldquo;Edge server&rdquo;. The Edge server is whatever service touches the HTTP request last before sending it to the client. Apache, NGINX, Varnish, pound&hellip; you want this to happen as far down the stack as you control. An ESI tag in your HTML looks like this:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>&lt;esi:include src="http://example.com/user/customized/thing" onerror="continue"/&gt;</span></code></pre></td></tr></table></div></figure>


<p>It&rsquo;s pretty clear, even to a human reader, what this tag means: &ldquo;replace this tag with the contents of <a href="http://example.com/user/customized/thing">http://example.com/user/customized/thing</a>&rdquo;. ESI actually supports some simple logic as well, but that&rsquo;s not really relevant to what we&rsquo;re doing here.</p>

<p>The only difference between ESI and AJAX is where the placeholder is filled. With ESI it happens on the edge service, and with AJAX it happens in the client browser. There is a subtle difference here: a page with ESI will not be delivered until all the ESI calls have returned something, while an AJAX page will return right away, even if the components don&rsquo;t immediately appear. On the other hand, ESI is much better for degraded browsers. YMMV.</p>

<p>The last method is using Cookies. You can store arbitrary information on cookies, as long as you&rsquo;re careful about security. That can be a very effective way to get certain limited information through a caching layer. Authcache actually comes with an example module for just such a use case. It passes the user&rsquo;s name and account URL in a cookie, so you can display it in a block.</p>

<p>This is effective for very small amounts of information, but keep it limited. Cookie headers aren&rsquo;t designed to hold large quantities of data, and reverse proxies can have a hard time if you put too much information in there. Still, it&rsquo;s a neat trick that can cover you for that &ldquo;Hello Username&rdquo; block.</p>

<h2>Authcache in Drupal</h2>

<p>The <a href="https://drupal.org/project/authcache">Authcache</a> suite of modules tries to automatically implement AJAX and/or ESI for you. It actually goes one step further, and implements a caching layer for those &ldquo;fragments&rdquo; which are to be returned via ESI/AJAX. The fragments can be stored in any caching system which implements <a href="http://api.drupal.org/api/drupal/includes%21cache.inc/interface/DrupalCacheInterface/7">DrupalCacheInterface</a>, ie any caching module you&rsquo;ve heard of. Memcache, APC, File Cache, Redis, MongoDB. The full page HTML with placeholders can be cached in Drupal&rsquo;s normal page cache, in Boost, or in Varnish.</p>

<p>Once you have these caching mechanisms defined, it&rsquo;s just a question of marking sections of your site which need a second callback. Authcache presents a large number of modules to do this. You can define any of the following as requiring a second call:</p>

<ul>
<li>Blocks</li>
<li>Views</li>
<li>Panels Panes</li>
<li>Fields</li>
<li>Comments</li>
<li>Flags</li>
<li>Forms</li>
<li>Forums</li>
<li>Polls</li>
<li>Votes</li>
</ul>


<p>&hellip; and that&rsquo;s all without writing a single line of custom code! Each one of those elements gets a new &ldquo;Authcache&rdquo; setting, where you can define it as needing a second callback, and set the method for the callback as either AJAX or ESI. You can even fall back to another method if the first one fails!</p>

<p>A good example of how this works is the Forms integration. Authcache will modify any and all forms on your site, so that they have an ESI or AJAX placeholder for the form token. This means that the form itself can be stored in your page cache (Varnish, Boost, or whatever), and the form token will be filled in automatically! That&rsquo;s a phenomenal speed improvement without any configuration beyond enabling the module.</p>

<p>Setting up Authcache is a little complicated, and I&rsquo;ll cover that in depth in my next post. But once the basic AJAX or ESI support is set up and these modules are enabled, caching authenticated users becomes a question of visiting each unique layout on your site and making a plan for each element that involves user customization. Authcache makes this easy.</p>

<p>Next post: <a href="https://ohthehugemanatee.org/blog/2014/06/14/how-to-configure-authcache-on-drupal-7/">How to configure Authcache on Drupal 7</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal Superheroes: ASSEMBLE!]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/05/28/drupal-superheroes-assemble/"/>
    <updated>2014-05-28T12:44:01+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/05/28/drupal-superheroes-assemble</id>
    <content type="html"><![CDATA[<p><img alt="Drop Signal" src="https://ohthehugemanatee.org/images/dropsignal.jpg" align=left> Regular Drupalcon attendees know that the opening pre-keynote session is one of the highlights of the con. That&rsquo;s the session where we welcome everyone to the con with stupid jokes, some well known Drupalists, and a lot of fun. This year is going to be especially good &ndash; and we need your help!</p>

<p>The evil Lord Over Engineering is threatening to delay the release of the CMS, which we need to save the world! The only way to stop him is to assemble the greatest force of Drupal superheroes ever assembled! Can the heroes save the day? Can we manage to make the final git push? You&rsquo;ll have to be there to find out!</p>

<blockquote><p>&ldquo;If you only get up early once during DrupalCon, this is the morning to do it. And hey, at least you&rsquo;ll get better seats for my keynote right after.&rdquo; &mdash; Dries</p></blockquote>

<p>In Prague we had the Drupal Opera, with <a href="http://www.youtube.com/watch?v=3eSxaNmGHYQ?t=11m9s" title="">solos sung by Gabor Hojtsy</a>. In Portland we had the Drupal Game show, including <a href="http://youtu.be/390cllsL7r8?t=30m9s">Doug Vann&rsquo;s amazing beatbox of the Tetris theme</a>. In Munich, we taught the world to yodel and pour good German beer. Don&rsquo;t miss out this year! The fun is just getting started!</p>

<p>If you want to participate onstage, you can go to <a href="http://www.robshouse.net/content/attention-drupal-super-heroes-your-powers-are-needed">Robert Douglass&#8217; blog</a> and sign up with our superhero/villain application form. But even if you just want to party from your comfy chair in the audience, costumes are encouraged! So get your best superhero costume together, and I&rsquo;ll see you at the pre-keynote!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupalcamp Helsinki Takes on the World]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/05/26/drupalcamp-helsinki-takes-on-the-world/"/>
    <updated>2014-05-26T15:14:58+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/05/26/drupalcamp-helsinki-takes-on-the-world</id>
    <content type="html"><![CDATA[<p>Last weekend I got to keynote <a href="http://drupalcamp.fi">Drupalcamp Helsinki</a> with my friend and often-collaborator, <a href="http://twitter.com/adamjurantenor">scaragucc</a> &ndash; and what a great camp it was! Organizer <a href="https://twitter.com/laurii1">Lauri Eskola</a> deserves tremendous credit for taking this camp to the next level. They doubled their attendance from last year, attracted positive attention from some great notables in the global Drupal world, and got their local community energized to engage more. At all the various after parties there were frequent toasts of &ldquo;one of the best Drupalcamps in the world!&rdquo;</p>

<p>Lauri and I met at the last <a href="http://szeged2014.drupaldays.org">Drupal Dev Days</a> event, in Szeged. That was also hailed as an example of a hugely successful Drupal event, and he took the lessons from their <a href="https://docs.google.com/file/d/0B6xsrc5BVkagNVpoeEFDZy1RMVk/edit">in-depth report</a> to heart. To be fair, the local volunteers and sponsors also clearly busted their humps getting people registered, and finding good session speakers to work with.</p>

<p>The result was a really positive Drupal event for all of us. Their attendance shot past the 200 mark for the first time, their code sprint had more involvement than ever before, and their social activities were a huge success. We left Finland full of positive feeling for the local association there, the city of Helsinki, and of course the sauna culture! This was a great example of what a Drupal community event can be. I&rsquo;m looking forward to next year already.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Coder vs. Themer Ultimate Grudge Match Smackdown Fight to the Death]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/05/01/coder-vs-themer-ultimate-grudge-match-smackdown-fight-to-the-death/"/>
    <updated>2014-05-01T17:15:31+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/05/01/coder-vs-themer-ultimate-grudge-match-smackdown-fight-to-the-death</id>
    <content type="html"><![CDATA[<p>I&rsquo;m really excited about a new session that I&rsquo;ve been doing with my friend and colleague, <a href="https://twitter.com/adamjurantenor">Adam Juran aka scaragucc</a>: the Coder vs Themer Ultimate Grudge Match Smackdown Fight to the Death! The basic premise: we both start with the same wireframe of a front page to build. But <em>I&rsquo;m only allowed to use the module layer, and Adam is only allowed to use the theme layer</em>. It&rsquo;s a really fun and entertaining way to play with the blurry lines between &ldquo;coder&rdquo; and &ldquo;themer&rdquo;. We get the audience pretty pumped up, which is impressive for a session that&rsquo;s basically about watching other people code!</p>

<p>If you didn&rsquo;t catch it at <a href="http://szeged2014.drupaldays.org/program/sessions/themer-vs-coder-ultimate-grudge-smackdown-fight-death">Drupal Dev Days in Szeged</a>, or at <a href="https://2014.drupalcamp-frankfurt.de/session/themer-vs-coder-ultimate-grudge-smackdown-fight-death">Drupalcamp Frankfurt</a>, you&rsquo;re probably going to have to wait for Drupalcon Amsterdam to take part! But I do have a video of the session at Frankfurt, just to whet your appetite. :)</p>

<iframe width="768" height="432" src="https://ohthehugemanatee.org//www.youtube-nocookie.com/embed/Rly9D3-gc4w" frameborder="0" allowfullscreen></iframe>


<p>You can consider this a challenge: if any other themers out there want to challenge me to a coder vs themer style battle, I&rsquo;ll be keynoting at <a href="http://drupalcamp.fi">Drupalcamp Helsinki</a> in a few weeks. I&rsquo;ll meet you there!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to Create a Custom Display Suite Field]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/04/02/how-to-create-a-custom-display-suite-field/"/>
    <updated>2014-04-02T17:12:13+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/04/02/how-to-create-a-custom-display-suite-field</id>
    <content type="html"><![CDATA[<p>A few months ago I posted about <a href="https://ohthehugemanatee.org/blog/2014/01/03/how-to-create-a-custom-panels-pane">how to create a custom Panels pane</a>, a critical reference for anyone who uses Panels layouts. The other part of the toolkit for quick and awesome layouts is the <a href="https://drupal.org/projects/ds">Display Suite</a> module. With DS you can create new &ldquo;Display modes&rdquo; for your content, to be reused around the site. For example, on one recent site I had four standard ways to display my nodes: Full, Teaser, Mini-Teaser, and Search Result. DS made this configuration a cinch.</p>

<p>But just as in Panels you sometimes need a pane that isn&rsquo;t provided out of the box, in Display Suite you sometimes want to add a field that isn&rsquo;t really a field on your content. In a recent site build, I used this capability to include information from the Organic Groups a user belongs to on his profile as it appears in search results.</p>

<p>DS offers some ability to create this kind of custom field through the UI, but I&rsquo;m talking about more complicated outcomes where you need/want to use custom code instead. This is actually even easier than custom panels panes.</p>

<p>In our example, we will display the user&rsquo;s name, but backwards. Obviously you can do much more complex things with this, but it&rsquo;s nice to have a simple example!</p>

<h1>Declare your fields</h1>

<p>First we have to tell Display Suite about our new custom field. We do this with <a href="http://drupalcontrib.org/api/drupal/contributions!ds!ds.api.php/function/hook_ds_fields_info/7">hook_ds_fields_info()</a>.</p>

<figure class='code'><figcaption><span>mymodule.module</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'>
</span><span class='line'><span class="c1">//@file: Add a custom suite to display suite for Users.</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_ds_fields_info().</span>
</span><span class='line'><span class="sd"> * Declare my custom field.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_ds_fields_info</span><span class="p">(</span><span class="nv">$entity_type</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$fields</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nv">$entity_type</span> <span class="o">==</span> <span class="s1">&#39;user&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$fields</span><span class="p">[</span><span class="s1">&#39;backwards_username&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Backwards Username&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;field_type&#39;</span> <span class="o">=&gt;</span> <span class="nx">DS_FIELD_TYPE_FUNCTION</span><span class="p">,</span>
</span><span class='line'>      <span class="s1">&#39;function&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_backwards_username&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="k">array</span><span class="p">(</span><span class="nv">$entity_type</span> <span class="o">=&gt;</span> <span class="nv">$fields</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="k">return</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Any guesses whathappens next? That&rsquo;s right, we have to write our render function under the name we just declared. You can put anything here, really anything renderable at all.</p>

<figure class='code'><figcaption><span>mymodule.module</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Render function for the Backwards Username field.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_backwards_username</span><span class="p">(</span><span class="nv">$field</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$field</span><span class="p">[</span><span class="s1">&#39;entity&#39;</span><span class="p">]</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="nx">check_plain</span><span class="p">(</span><span class="nb">strrev</span><span class="p">(</span><span class="nv">$field</span><span class="p">[</span><span class="s1">&#39;entity&#39;</span><span class="p">]</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">));</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>That&rsquo;s it. So simple, you&rsquo;ll wonder why you ever did it any other way!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal Dev Days Szeged, or: Why You Should Attend Every Camp You Can]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/03/29/drupal-dev-days-szeged-2014/"/>
    <updated>2014-03-29T15:27:50+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/03/29/drupal-dev-days-szeged-2014</id>
    <content type="html"><![CDATA[<p>Today is the last day of <a href="http://szeged2014.drupaldays.org/">Drupal Dev Days</a> in Szeged, Hungary, and I&rsquo;ve never been more full of the &ldquo;Drupal spirit!&rdquo;</p>

<p>One of Drupal&rsquo;s greatest strengths is the closness of its&#8217; community, how friendly and accepting they can be. Drupalcons are highlight events for many, not because of the learning as much as because of the social track: the chance to see old friends and make new ones. Even more important is the chance to experience in person this incredibly friendly community. I always loved the cons because you could approach really anybody, say &ldquo;hi&rdquo;, and ask them about their work with the platform. Seriously, anybody. From a new user to Dries himself.</p>

<p>That&rsquo;s become harder and harder as Drupal has grown more popular. In a convention of more than 3,000 people, you lose that feeling of being able to approach anybody. Instead, people silo into groups. In a best case it&rsquo;s a group that shares an interest in a sub-system (Rules junkies, Panels proselytizers, Features fans&hellip;), but in most cases it&rsquo;s because of shared connections outside the community. You end up hanging out with the same people you knew before the con. Of course you can still have fun, but that sense of community is lost.</p>

<p>One of the best parts of Drupal Dev Days Szeged was the way they encouraged people to mix, cross pollinate, and discuss. In a conference of 350 people I felt like I spoke to almost all of them. I could approach even the famous visitors and talk to them like a normal human being. I borrowed VGA adaptors from Gabor Hojtsy and Wim Leers, and neither of them batted an eye at it.</p>

<p>This kind of experience is so great, so positive and validating, that I recommend Drupal Camps for everyone. The ticket price is cheap, the location is always nearby, and the culture is fantastic. The sessions are every bit as good as most DrupalCon sessions (many of us use the Camps as a way to practice before the Con), and you will make great new friends.</p>

<p>Tl;DR: Drupal Dev Days in Szeged was fantastic. If you&rsquo;ve never been to a Drupal Camp event, get your butt onto <a href="http://www.drupical.com/">drupical.com</a> and find your nearest one today!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drush Self Aliases]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/01/10/drush-self-aliases/"/>
    <updated>2014-01-10T09:22:01+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/01/10/drush-self-aliases</id>
    <content type="html"><![CDATA[<p>I ran into an interesting problem with the drush <em>@self</em> alias today. I wanted to pull a fresh copy of the DB down from a client&rsquo;s live site to my local development copy. Should be as easy as <em>drush sql-sync @clientsite.live @self</em>, right? I&rsquo;ve done this a thousand times before.</p>

<p>And I&rsquo;ve also ignored the warning message every time before, but today I thought I&rsquo;d check it out:</p>

<blockquote><p>WARNING:  Using temporary files to store and transfer sql-dump.  It is recommended that you specify &mdash;source-dump and &mdash;target-dump options on the command line, or set &lsquo;%dump&rsquo; or &lsquo;%dump-dir&rsquo; in the path-aliases section of your site alias records. This facilitates fast file transfer via rsync.</p></blockquote>

<p>There are actually two possible solutions to this warning (that I can think of), and they illustrate some of the useful &ldquo;power user&rdquo; features of Drush that any frequent user should be aware of.</p>

<p>The warning is there because drush would <em>prefer</em> to rsync the DB dump from site1 to site2, rather than a one time copy. Rsync has lots of speed improvements, not the least being diff transfer. When transferring an updated copy of a file which already exists at the destination, rsync will only send over the changes rather than the whole file. This is pretty useful if you&rsquo;re dealing with a large, text based file like an SQL dump &ndash; especially one that you&rsquo;ll be transferring often. In order to use this efficient processing though, Drush needs to know a safe path where it can store the DB dump in each location.</p>

<p>First we&rsquo;ll add the <em>%dump-dir%</em> attribute to our alias for clientsite:</p>

<figure class='code'><figcaption><span>~/.drush/clientsite.aliases.drush.php</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'><span class="c1">// Site clientsite, environment live </span>
</span><span class='line'><span class="nv">$aliases</span><span class="p">[</span><span class="s1">&#39;live&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>  <span class="s1">&#39;parent&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;@parent&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;site&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;clientsite&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;env&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;live&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;root&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;/var/www/example.com/public_html&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;remote-host&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;example.com&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;remote-user&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;cvertesi&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;path-aliases&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="s1">&#39;%dump-dir&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;/home/cvertesi/.drush/db_dumps&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="p">),</span>
</span><span class='line'><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>Notice that <em>%dump-dir</em> actually goes in a special sub-array for <em>path-aliases</em>. This is very likely the only time you&rsquo;ll need to use that section, since most everything else in there is auto-detected. This is the directory on the remote side where drush will store the dump.</p>

<p>Our options come in with the <em>@self</em> alias. In a local dev environment, the most common way to handle this is in your <em>drushrc.php</em> file:</p>

<figure class='code'><figcaption><span>~/.drush/drushrc.php</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="nv">$options</span><span class="p">[</span><span class="s1">&#39;dump-dir&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;~/.drush/db_dumps&#39;</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>But this won&rsquo;t work for all cases. You can also take advantage of Drush&rsquo;s alias handling by creating a site alias with the settings you want, and letting Drush merge those settings into <em>@self</em>. When Drush builds its&#8217; cache of path aliases, it uses the site path as the cache key (for local sites only). That means that if you have a local alias with the same path as whatever <em>@self</em> happens to resolve to, your alias options will make it into the definition for <em>@self</em>. So here&rsquo;s the alternate solution:</p>

<figure class='code'><figcaption><span>~/.drush/clientsite.aliases.drush.php</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="nv">$aliases</span><span class="p">[</span><span class="s1">&#39;localdev&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>  <span class="s1">&#39;root&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;/Users/cvertesi/Sites/clientsite&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;uri&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;default&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;path-aliases&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="s1">&#39;%dump-dir&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;/home/cvertesi/.drush/db_dumps&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="p">),</span>
</span><span class='line'><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>There&rsquo;s just one, obscure caveat with the latter method: somewhere in the alias merging process, BASH aliases are lost. That means that &lsquo;~&rsquo; stops resolving to your home directory, and you have to write it out (as I did above).</p>

<p>Have fun!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to Remove a Drupal Install Profile]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/01/07/how-to-remove-a-drupal-install-profile/"/>
    <updated>2014-01-07T13:23:45+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/01/07/how-to-remove-a-drupal-install-profile</id>
    <content type="html"><![CDATA[<p><a href="https://drupal.org/project/install_profile_api">Install profiles</a> are a great way to throw together a functional Drupal site really quickly. In Drupal 6, an Install Profile was just a blueprint for setting up a site really quickly. What you did after the site was installed was your own business! But in Drupal 7 profiles are much more integrated with core. The assumption is that when you use an install profile, you want to rely on the profile&rsquo;s maintainer for all your updates. This is not always the case.</p>

<p>Very often your site will diverge from the install profile as it takes on a life of its own, and it will be useful to convert it to &ldquo;vanilla&rdquo; Drupal. Today I&rsquo;ll use a relatively simple example of a musician site which is moving away from the <a href="https://drupal.org/project/pushtape">Pushtape</a> distribution. Later I&rsquo;ll return to this subject with the much more in-depth example of moving a community site away from <a href="https://drupal.org/project/commons">Drupal Commons</a>.</p>

<h2>Move things around</h2>

<p>Install profiles have all their files stored in the site root&rsquo;s <em>profiles/</em> directory. The first step is going to be moving everything out of there. In the case of pushtape, we have libraries, modules, and a theme stored in there. We&rsquo;re going to move them to a more normal location.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> mkdir sites/all/libraries
</span><span class='line'><span class="gp">#</span> mv profiles/pushtape/libraries/* sites/all/libraries
</span><span class='line'>
</span><span class='line'><span class="gp">#</span> mkdir sites/all/modules/custom
</span><span class='line'><span class="gp">#</span> mv profiles/pushtape/modules/pushtape_* sites/all/modules/custom
</span><span class='line'><span class="gp">#</span> mv profiles/pushtape/modules/* sites/all/modules
</span><span class='line'>
</span><span class='line'><span class="gp">#</span> mkdir sites/all/themes
</span><span class='line'><span class="gp">#</span> mv profiles/pushtape/themes/* sites/all/themes
</span></code></pre></td></tr></table></div></figure>


<p>Next we need to see if there are any variables set in the install profile which really depend on the profile directory. If there are, we&rsquo;ll have to set them again with the new path.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> <span class="nb">cd </span>profiles/pushtape
</span><span class='line'><span class="gp">#</span> grep <span class="s1">&#39;profiles/pushtape&#39;</span> * -R
</span><span class='line'><span class="go">pushtape.install:  variable_set(&#39;sm2_path&#39;, &#39;profiles/pushtape/libraries/soundmanager2&#39;);</span>
</span></code></pre></td></tr></table></div></figure>


<p>In this case, we see one variable_set which tells the system where to find the soundmanager2 library. We can update that easily enough with drush:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> drush vset sm2_path <span class="s1">&#39;sites/all/libraries/soundmanager2&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now we have to update Drupal&rsquo;s setting for which install profile was used to create the site.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> drush vset install_profile standard
</span></code></pre></td></tr></table></div></figure>


<p>In some cases this will be enough to work. Personally I like to keep my modules folder more organized, so I go the extra mile:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> <span class="nb">cd </span>sites/all/modules
</span><span class='line'><span class="gp">#</span> mkdir contrib
</span><span class='line'><span class="gp">#</span> mv !<span class="o">(</span>custom|contrib<span class="o">)</span> contrib
</span></code></pre></td></tr></table></div></figure>


<p>I also separated out the custom code from the features. You can figure out which custom modules implement features with <em>find . |grep features</em>, and move them into a separate directory manually.</p>

<h2>Clearing caches</h2>

<p>Once you&rsquo;re done moving things around, CLEAR CACHES. Drupal keeps an index of module, library, and theme directories, and you just broke it.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">drush cc all</span>
</span></code></pre></td></tr></table></div></figure>


<p>The only problem is, in many cases you will have moved a module that is required for drupal bootstrap. So you&rsquo;ll have to get the handy drush tool <a href="https://drupal.org/project/registry_rebuild">Registry Rebuild</a>, and run that before your cache clear:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="gp">#</span> drush dl registry_rebuild
</span><span class='line'><span class="gp">#</span> drush rr
</span><span class='line'><span class="gp">#</span> drush cc all
</span></code></pre></td></tr></table></div></figure>


<h2>Extra Cleanup</h2>

<p>As commenter @ericaitala notes, you may need some followup cleanup to really get all traces out. The easiest way to do this is from the SQL command line, which you can access via drush:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">drush sqlq &quot;DELETE FROM `system` WHERE filename LIKE &#39;profiles/profilename/profilename.profile&quot;</span>
</span><span class='line'><span class="go">drush sqlq &quot;UPDATE `system` SET status=1 WHERE filename LIKE &#39;profiles/standard/standard.profile&#39;&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Technically these should both be covered by the registry_rebuild operation, but we&rsquo;re doing it by hand because it seems to be missed in some operations. The first command removes the entry for the profile from Drupal&rsquo;s system table &ndash; it removes any knowledge Drupal has that there was an install profile there. The second tells Drupal that the &ldquo;standard&rdquo; install profile is active, and should be checked for updates.</p>

<p>That&rsquo;s it &ndash; your site is now officially a vanilla Drupal install. Test by removing the profiles/pushtape directory, clearing caches, and browsing around your site.</p>

<p><em>NOTE: With a more complex install profile I expect to encounter more difficulty. Stay tuned for the post on extricating yourself from Commons later this year!</em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to Create a Custom Panels Pane]]></title>
    <link href="https://ohthehugemanatee.org/blog/2014/01/03/how-to-create-a-custom-panels-pane/"/>
    <updated>2014-01-03T13:09:11+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2014/01/03/how-to-create-a-custom-panels-pane</id>
    <content type="html"><![CDATA[<p>Lots of sites are now built with the &ldquo;Panels everywhere&rdquo; method, using <a href="https://www.drupal.org/project/panels">Panels</a> and <a href="https://www.drupal.org/project/panelizer">Panelizer</a> to configure modular layouts in the Drupal GUI. These modules come with lots of great default Panes, and create even more defaults based on your existing Blocks and Views. But there&rsquo;s always a case for a custom Pane.</p>

<p>As usual, I&rsquo;ll assume that you have an empty custom module called <em>mymodule</em>, with only a <em>.info</em> and a <em>.module</em> file to its name.</p>

<h2>1) Tell CTools that you have custom code here</h2>

<p>Ctools, like Views, needs a hook to declare the fact that you have custom code. To do this we&rsquo;ll use <em><a href="http://drupalcontrib.org/api/drupal/contributions!ctools!ctools.api.php/function/hook_ctools_plugin_directory/7">hook_ctools_plugin_directory</a></em>. This hook is invoked for all Ctools plugin types, and includes the module name as a variable. This way you can avoid eating up memory for anything except the targeted module. You also have to declare where your custom code will live. So here&rsquo;s the complete content of <em>mymodule.module</em>:</p>

<figure class='code'><figcaption><span>mymodule.module</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_ctools_plugin_directory().</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_ctools_plugin_directory</span><span class="p">(</span><span class="nv">$owner</span><span class="p">,</span> <span class="nv">$plugin_type</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nv">$owner</span> <span class="o">==</span> <span class="s1">&#39;ctools&#39;</span> <span class="o">&amp;&amp;</span> <span class="nv">$plugin_type</span> <span class="o">==</span> <span class="s1">&#39;content_types&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="s1">&#39;plugins/content_types&#39;</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Note: <strong>Do not confuse Ctools &ldquo;Content Types&rdquo; with the &ldquo;Content Type&rdquo; entity used elsewhere in Drupal.</strong> This is just confusing naming, but they&rsquo;re totally different things. Actually the most common usage for a Ctools Content Type is a pane, just like what we&rsquo;re doing now. There are other plugin types, but none that interest us in this post.</p>

<h2>2) Add your custom pane</h2>

<p>Oh, did you think this would be more difficult? Now that we&rsquo;ve told Ctools to look for Content Type plugins in our module&rsquo;s <em>plugins/content_types</em> subdirectory, we just add a <em>.inc</em> file for each &ldquo;Content Type&rdquo; (aka Pane) that we want to add. Let&rsquo;s do a simple one, which returns the root term of a given taxonomy term. All the following code will go in <em>plugins/content_types/taxonomy_root_term.inc</em> (a name I chose arbitrarily).</p>

<p>Right at the top of the file, we provide a <em>$plugin</em> array which defines the basic information about our <del>Pane</del> Ctools Content Type. This doesn&rsquo;t go into a function or anything, it just sits at the top of the <em>.inc</em> file:</p>

<figure class='code'><figcaption><span>plugins/content_types/taxonomy_root_term.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'>
</span><span class='line'><span class="nv">$plugin</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>  <span class="s1">&#39;single&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Taxonomy root term&#39;</span><span class="p">),</span>
</span><span class='line'>  <span class="s1">&#39;description&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;a Display of data from the root term of the given TID&#39;</span><span class="p">),</span>
</span><span class='line'>  <span class="s1">&#39;category&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Custom Panes&#39;</span><span class="p">),</span>
</span><span class='line'>  <span class="s1">&#39;edit form&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_taxonomy_root_term&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;render callback&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_taxonomy_root_term_render&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;admin info&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_taxonomy_root_term_info&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;defaults&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(),</span>
</span><span class='line'>  <span class="s1">&#39;all contexts&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>As you can see, this array defines a category, title, and description for the Panels admin interface. It also declares the names of the callbacks which provide the pane&rsquo;s edit form, rendered form, and admin info. &ldquo;Single&rdquo; means that this type has no sub-types. This is the case in every single custom pane I&rsquo;ve ever seen, so it&rsquo;s probably the case for yours as well.</p>

<p>Now we write the callbacks we named in that array. We&rsquo;ll start with the edit form.</p>

<figure class='code'><figcaption><span>plugins/content_types/taxonomy_root_term.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Edit form.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_taxonomy_root_term</span><span class="p">(</span><span class="nv">$form</span><span class="p">,</span> <span class="o">&amp;</span><span class="nv">$form_state</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nv">$conf</span> <span class="o">=</span> <span class="nv">$form_state</span><span class="p">[</span><span class="s1">&#39;conf&#39;</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'> <span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;term&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>   <span class="s1">&#39;#type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;textfield&#39;</span><span class="p">,</span>
</span><span class='line'>   <span class="s1">&#39;#title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Term ID&#39;</span><span class="p">),</span>
</span><span class='line'>   <span class="s1">&#39;#description&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;The term, from which the root term will be displayed&#39;</span><span class="p">),</span>
</span><span class='line'>   <span class="s1">&#39;#default_value&#39;</span> <span class="o">=&gt;</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;term&#39;</span><span class="p">],</span>
</span><span class='line'> <span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="nv">$entity_info</span> <span class="o">=</span> <span class="nx">entity_get_info</span><span class="p">(</span><span class="s1">&#39;taxonomy_term&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="nv">$options</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$entity_info</span><span class="p">[</span><span class="s1">&#39;view modes&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">foreach</span> <span class="p">(</span><span class="nv">$entity_info</span><span class="p">[</span><span class="s1">&#39;view modes&#39;</span><span class="p">]</span> <span class="k">as</span> <span class="nv">$mode</span> <span class="o">=&gt;</span> <span class="nv">$settings</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$options</span><span class="p">[</span><span class="nv">$mode</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$settings</span><span class="p">[</span><span class="s1">&#39;label&#39;</span><span class="p">];</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;view_mode&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>   <span class="s1">&#39;#type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;select&#39;</span><span class="p">,</span>
</span><span class='line'>   <span class="s1">&#39;#options&#39;</span> <span class="o">=&gt;</span> <span class="nv">$options</span><span class="p">,</span>
</span><span class='line'>   <span class="s1">&#39;#title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;View mode&#39;</span><span class="p">),</span>
</span><span class='line'>   <span class="s1">&#39;#default_value&#39;</span> <span class="o">=&gt;</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;view_mode&#39;</span><span class="p">],</span>
</span><span class='line'> <span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nv">$form</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>This is a fairly standard Drupal form. It also goes through typical form validation and submission functions, so you can provide a pretty complete experience for the administrator. In our case, we just want to get the term ID of the term whose root parent should be displayed. We let the administrator enter the term ID, and the view mode which should be used to display it. We won&rsquo;t worry about form validation in our example. Let&rsquo;s move on to the Submit function:</p>

<figure class='code'><figcaption><span>plugins/content_types/taxonomy_root_term.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Edit form submit function.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_taxonomy_root_term_submit</span><span class="p">(</span><span class="nv">$form</span><span class="p">,</span> <span class="o">&amp;</span><span class="nv">$form_state</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$form_state</span><span class="p">[</span><span class="s1">&#39;conf&#39;</span><span class="p">][</span><span class="s1">&#39;term&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$form_state</span><span class="p">[</span><span class="s1">&#39;values&#39;</span><span class="p">][</span><span class="s1">&#39;term&#39;</span><span class="p">];</span>
</span><span class='line'>  <span class="nv">$form_state</span><span class="p">[</span><span class="s1">&#39;conf&#39;</span><span class="p">][</span><span class="s1">&#39;view_mode&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$form_state</span><span class="p">[</span><span class="s1">&#39;values&#39;</span><span class="p">][</span><span class="s1">&#39;view_mode&#39;</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Again, pretty simple stuff. We just make sure that the <em>$form_state[&lsquo;conf&rsquo;]</em> has the values entered. Now, the next callback we defined in <em>$plugin</em> is for rendering the pane:</p>

<figure class='code'><figcaption><span>plugins/content_types/taxonomy_root_term.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Render the panel.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_taxonomy_root_term_render</span><span class="p">(</span><span class="nv">$subtype</span><span class="p">,</span> <span class="nv">$conf</span><span class="p">,</span> <span class="nv">$args</span><span class="p">,</span> <span class="nv">$contexts</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nv">$context</span><span class="o">-&gt;</span><span class="na">empty</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="c1">// Get full term object for the root term.</span>
</span><span class='line'>  <span class="nv">$term</span> <span class="o">=</span> <span class="nx">ctools_context_keyword_substitute</span><span class="p">(</span><span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;term&#39;</span><span class="p">],</span> <span class="k">array</span><span class="p">(),</span> <span class="nv">$contexts</span><span class="p">);</span>
</span><span class='line'>  <span class="nv">$parent_array</span> <span class="o">=</span> <span class="nx">taxonomy_get_parents_all</span><span class="p">(</span><span class="nv">$term</span><span class="p">);</span>
</span><span class='line'>  <span class="nv">$root</span> <span class="o">=</span> <span class="nb">end</span><span class="p">(</span><span class="nv">$parent_array</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Render as a block.</span>
</span><span class='line'>  <span class="nv">$block</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span><span class='line'>  <span class="nv">$block</span><span class="o">-&gt;</span><span class="na">module</span> <span class="o">=</span> <span class="s1">&#39;entity&#39;</span><span class="p">;</span>
</span><span class='line'>  <span class="nv">$block</span><span class="o">-&gt;</span><span class="na">delta</span> <span class="o">=</span> <span class="s1">&#39;taxonomy_term-&#39;</span> <span class="o">.</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;_&#39;</span><span class="p">,</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;view_mode&#39;</span><span class="p">]);</span>
</span><span class='line'>
</span><span class='line'>  <span class="nv">$entity</span> <span class="o">=</span> <span class="nx">entity_load_single</span><span class="p">(</span><span class="s1">&#39;taxonomy_term&#39;</span><span class="p">,</span> <span class="nv">$root</span><span class="o">-&gt;</span><span class="na">tid</span><span class="p">);</span>
</span><span class='line'>  <span class="nv">$block</span><span class="o">-&gt;</span><span class="na">content</span> <span class="o">=</span> <span class="nx">entity_view</span><span class="p">(</span><span class="s1">&#39;taxonomy_term&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="nv">$root</span><span class="p">),</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;view_mode&#39;</span><span class="p">]);</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$block</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>First we make sure there is information &ndash; ie the taxonomy term ID we need &ndash; in the pane&rsquo;s context. Then we get the root term object and render it in the requested display mode. The only requirement for the return here is that it be a <a href="https://drupal.org/node/930760">Drupal render array</a>. So depending on your use case, you can return an image, a field&hellip; whatever you like. In most cases a block is a convenient wrapper for whatever you have to return, which is what I did here.</p>

<p>This is as far as you have to go. The admin info callback isn&rsquo;t actually required, just don&rsquo;t include it in the <em>$plugin</em> array and you&rsquo;ll be fine. But if you want to make your life easier as a site admin, it&rsquo;s definitely a nice to have.</p>

<figure class='code'><figcaption><span>plugins/content_types/taxonomy_root_term.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Admin info.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_taxonomy_root_term_info</span><span class="p">(</span><span class="nv">$subtype</span><span class="p">,</span> <span class="nv">$conf</span><span class="p">,</span> <span class="nv">$contexts</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$conf</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$content</span> <span class="o">=</span> <span class="s1">&#39;&lt;p&gt;&lt;b&gt;Term ID:&lt;/b&gt; &#39;</span> <span class="o">.</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;term&#39;</span><span class="p">]</span> <span class="o">.</span> <span class="s1">&#39;&lt;/p&gt;&#39;</span><span class="p">;</span>
</span><span class='line'>    <span class="nv">$content</span> <span class="o">=</span> <span class="s1">&#39;&lt;p&gt;&lt;b&gt;View mode:&lt;/b&gt; &#39;</span> <span class="o">.</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;view_mode&#39;</span><span class="p">]</span> <span class="o">.</span> <span class="s1">&#39;&lt;/p&gt;&#39;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nv">$block</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">;</span>
</span><span class='line'>    <span class="nv">$block</span><span class="o">-&gt;</span><span class="na">title</span> <span class="o">=</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;override_title&#39;</span><span class="p">]</span> <span class="o">?</span> <span class="nv">$conf</span><span class="p">[</span><span class="s1">&#39;override_title_text&#39;</span><span class="p">]</span> <span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span><span class='line'>    <span class="nv">$block</span><span class="o">-&gt;</span><span class="na">content</span> <span class="o">=</span> <span class="nv">$content</span><span class="p">;</span>
</span><span class='line'>    <span class="k">return</span> <span class="nv">$block</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>This just provides the administrative summary which you can see in the Panels UI. Again, Panels will be happy with any render array return you throw at it, so I use a block.</p>

<h2>This is why we have nice things</h2>

<p>Anyone who&rsquo;s worked with me knows that I&rsquo;m not a huge fan of the panels everywhere approach. But I use it often, simply because it makes custom layouts and totally custom page pieces so easy to do. Duplicating even this very simple functionality in a block is actually harder than this. You&rsquo;re still using about 3 functions, but you&rsquo;d have to determine in advance where that TID will come from. It would certainly come out less flexible, and actually probably harder to maintain. With Ctools all your related code sits in one place, and your module structure actually helps you see what&rsquo;s going on where.</p>

<p>If you learn how to do elements like this, you&rsquo;ll find Panels creeping into more and more of your builds. And rightfully so.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[44,497 People Are Wrong: How to NEVER Need Views PHP.]]></title>
    <link href="https://ohthehugemanatee.org/blog/2013/12/26/44497-people-are-wrong-how-to-never-use-views-php/"/>
    <updated>2013-12-26T12:01:44+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2013/12/26/44497-people-are-wrong-how-to-never-use-views-php</id>
    <content type="html"><![CDATA[<p>You&rsquo;re building a View, but you can&rsquo;t get that field to display the way you want it to. Or filter, or sort. Or maybe you have some data in a custom table that you want to include in the View. So you look for a contributed module, and <a href="https://www.drupal.org/project/views_php">Views PHP</a> looks like the answer to your problem! Until you read the module page, where it says:</p>

<blockquote><p>&ldquo;&hellip;it is highly advisable to use regular handlers and plugins when available (or even to create one yourself). Take note that filtering and sorting a view using PHP always has a considerable perfomance impact.&rdquo;</p></blockquote>

<p>As of this writing, <em>44,497</em> site maintainers have read that warning and chosen to ignore it. <strong>They&rsquo;ve chosen to put their PHP into a non-revisioned, difficult-to-access place, and to enable PHP input in a module that was never designed for security. They&rsquo;ve left their site at risk of a very difficult to diagnose and even harder to fix WSOD</strong>.</p>

<p>I&rsquo;m going to go out on a limb here, and suggest that in many of these cases, the decision was made because someone had the impression that writing a Views handler or Plugin was difficult. I&rsquo;m here to tell you that&rsquo;s not so: it&rsquo;s actually quite easy.</p>

<h2>What we&rsquo;re doing </h2>

<p>We&rsquo;re going to tell Views about the structure of the data we want to display, filter, or sort &ndash; even if there&rsquo;s not actually a new data source involved, that&rsquo;s how you do it &ndash; and then we&rsquo;ll write the function that actually does the filter/sort/etc by improving an existing field display/filter/sort that Views already includes.</p>

<p>This process will work for:</p>

<ul>
<li>Defining a new data source for Views, ie something your module keeps in the DB.</li>
<li>Creating multiple field displays/filters/sorts for an existing field.</li>
<li>Creating a completely computed field display/filter/sort, with nothing in the DB.</li>
</ul>


<p>I know that in 99% of use cases for Views PHP, you don&rsquo;t need to define a new data source, table, adn fields. Trust me that this is the easiest way to learn it, though. I promise we&rsquo;ll get to your use case before the end of the post.</p>

<h1>How to</h1>

<p>I&rsquo;ll assume you have a custom module built, with a .info and .module file, but nothing in there yet. We&rsquo;ll call our module &ldquo;mymodule&rdquo; for the example.</p>

<h2>1) Tell Views about your module</h2>

<p>We implement <em><a href="https://api.drupal.org/api/views/views.api.php/function/hook_views_api/7">hook_views_api</a></em> to let Views know that our module provides some code for Views, and what version of the Views API we&rsquo;re using.</p>

<figure class='code'><figcaption><span>mymodule.module</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_views_api().</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_views_api</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="s1">&#39;api&#39;</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span><span class='line'>    <span class="s1">&#39;path&#39;</span> <span class="o">=&gt;</span> <span class="nx">drupal_get_path</span><span class="p">(</span><span class="s1">&#39;module&#39;</span><span class="p">,</span> <span class="s1">&#39;mymodule&#39;</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;/views&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Couldn&rsquo;t be simpler. We declare that we&rsquo;re using Views API 3, and that our Views code will all live in the <em>/views</em> subdirectory of our module.</p>

<h2>2) Tell Views about your custom code</h2>

<p>Now that Views knows to look in our <em>/views</em> directory, we should populate it. Views will look for a file called <em>modulename.views.inc</em> in that directory, so this is where we will put our Views hooks. There are lots of Views interventions you can do in this file, but we&rsquo;re only interested in one: <em><a href="https://api.drupal.org/api/views/views.api.php/function/hook_views_data/7">hook_views_data</a></em>.</p>

<p>This hook lets you define new data sources to Views, and for each one show how to render a field, how to Filter results, and how to Sort results based on your new data source. I promised you three use cases up there though, and here&rsquo;s the trick: you don&rsquo;t have to have an actual data source. You can define a filter for a database field that&rsquo;s already described elsewhere.</p>

<p>First let&rsquo;s look at a real field definiton though, because it&rsquo;s simpler. Here&rsquo;s how we would define a real DB table as a data source. The table looks like this:</p>

<table style="border-collapse:collapse;">
<tr><th>naid</th><th>name</th></tr>
<tr><td>1</td><td>Frank Sinatra</td></tr> 
<tr><td>2</td><td>Dean Martin</td></tr>
<tr><td>3</td><td>Sammy Davis, Jr.</td></tr> 
<tr><td>4</td><td>Peter Lawford</td></tr>
<tr><td>5</td><td>Joey Bishop</td></tr>
</table>


<p>So here&rsquo;s our implementation of <em>hook_views_data</em>:</p>

<figure class='code'><figcaption><span>views/mymodule.views.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_views_data().</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">mymodule_views_data</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// Build an array named after each DB table you&#39;re describing. In our case,</span>
</span><span class='line'>  <span class="c1">// just mymodule_table.</span>
</span><span class='line'>  <span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;mymodule_table&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="c1">// First give some general information about the table as a data source.</span>
</span><span class='line'>    <span class="s1">&#39;table&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="c1">// The grouping for this field/filter/sort in the Views UI.</span>
</span><span class='line'>      <span class="s1">&#39;group&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Example Views Stuff&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;base&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;naid&#39;</span><span class="p">,</span> <span class="c1">// This is the identifier field for the view.</span>
</span><span class='line'>        <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Example Views API Data&#39;</span><span class="p">),</span>
</span><span class='line'>        <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Names provided by the Mymodule module.&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>    <span class="c1">// Now we describe each field that Views needs to know about, starting </span>
</span><span class='line'>    <span class="c1">// with the identifier field.</span>
</span><span class='line'>    <span class="s1">&#39;naid&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Name ID&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s2">&quot;The unique Name ID.&quot;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_field_numeric&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;sort&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_sort&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;filter&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_filter_numeric&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>    <span class="c1">// Now the name field.</span>
</span><span class='line'>    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Name&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s2">&quot;The Name.&quot;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_field&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;sort&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_sort&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;filter&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;views_handler_filter_string&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>  <span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$data</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>This is a pretty simple example, and I think the array structure speaks for itself. First you provide some general information about the table, then you create a sub-array for each field on the table. Each field&rsquo;s array should be named after the field, and provide at least title. Of course it wouldn&rsquo;t be useful if you didn&rsquo;t describe the handlers for any field/sort/filter operations you want to expose. For each one of these you just provide the name of the handler. In this example I used all built-in filters that come with Views, but it&rsquo;s easy enough to provide a custom handler.</p>

<p>Many added behaviors in Views start with <em>hook_views_data</em>; this only covers the basics. You can also open fields up as arguments or relationships, or even add built-in relationships. For example, if our table also contained an NID field, we could define a relationship so that node fields are always available when listing names, and vice versa. This stuff is all surprisingly easy to do, it&rsquo;s just not the focus of this post.</p>

<h2>3) Write your custom handler</h2>

<p>Let&rsquo;s say we want to provide our own field handler for the name field. Maybe we want it to automatically separate first names. This is easy, too! You simply decide on a name for your new handler &ndash; by convention it should begin with <em>modulename_handler_type_</em>, so we&rsquo;ll use <em>mymodule_handler_field_firstname</em>. Here&rsquo;s the relevant part of that <em>$data</em> array from before:</p>

<figure class='code'><figcaption><span>/views/mymodule.views.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">...</span>
</span><span class='line'>    <span class="c1">// Now the name field.</span>
</span><span class='line'>    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Name&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s2">&quot;The Name.&quot;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_handler_field_firstname&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'><span class="o">...</span>
</span></code></pre></td></tr></table></div></figure>


<p>Not exactly rocket science, is it?</p>

<p>Now we create a file named after the handler, also in the <em>/views</em> subdirectory. Though you could write your own handler class from scratch, you&rsquo;ll almost never have to. It&rsquo;s much easier to just extend an existing class.</p>

<figure class='code'><figcaption><span>/views/mymodule_handler_field_firstname.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * @file</span>
</span><span class='line'><span class="sd"> * Definition of mymodule_handler_field_firstname.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Provide the first name only from the name field.</span>
</span><span class='line'><span class="sd"> *</span>
</span><span class='line'><span class="sd"> * @ingroup views_filter_handlers</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">mymodule_handler_field_firstname</span> <span class="k">extends</span> <span class="nx">views_handler_field</span> <span class="p">{</span>
</span><span class='line'>  <span class="sd">/**</span>
</span><span class='line'><span class="sd">  * Render the name field.</span>
</span><span class='line'><span class="sd">  */</span>
</span><span class='line'>  <span class="k">public</span> <span class="k">function</span> <span class="nf">render</span><span class="p">(</span><span class="nv">$values</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$value</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_value</span><span class="p">(</span><span class="nv">$values</span><span class="p">);</span>
</span><span class='line'>    <span class="nv">$return</span> <span class="o">=</span> <span class="nb">explode</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
</span><span class='line'>    <span class="k">return</span> <span class="s1">&#39;First name: &#39;</span> <span class="o">.</span> <span class="nv">$return</span><span class="p">[</span><span class="s1">&#39;0&#39;</span><span class="p">];</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>You see the pattern we&rsquo;re following: just name a handler, then extend an existing Views handler class to do what you want. You can override options forms, the admin summary&hellip; really any aspect of the way Views handles this data. And the pattern is the same for fields, sorts, filters, and arguments.</p>

<p>Once you&rsquo;ve created your handler&rsquo;s <em>.inc</em> file, you have to make sure your module loads it. So edit your module&rsquo;s <em>.info</em> file thusly:</p>

<figure class='code'><figcaption><span>/mymodule.info</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="na">name</span> <span class="o">=</span> <span class="s">My Module</span>
</span><span class='line'><span class="na">description</span> <span class="o">=</span> <span class="s">Demo module from ohthehugemanatee.org</span>
</span><span class='line'><span class="na">core</span> <span class="o">=</span> <span class="s">7.x</span>
</span><span class='line'>
</span><span class='line'><span class="na">files[]</span> <span class="o">=</span> <span class="s">views/mymodule_handler_field_firstname.inc</span>
</span></code></pre></td></tr></table></div></figure>


<h2>4) Multiple filters for one field</h2>

<p>We all understand how this works for data that you&rsquo;re declaring for the first time in Views. But what if you want to provide multiple handlers for a single field? Maybe there are several different ways to filter or sort it. For most use cases, you should just follow the pattern above, and simply override the Views options form in your handler class. But occasionally you really do need multiple handlers.</p>

<p>So let&rsquo;s add a second and third field handler for our <em>name</em> field:</p>

<figure class='code'><figcaption><span>/views/mymodule.views.inc</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">...</span>
</span><span class='line'>    <span class="c1">// Now the name field. This is the first, and &#39;real&#39; definition for this field.</span>
</span><span class='line'>    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Name&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s2">&quot;The Name.&quot;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_handler_field_firstname&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>    <span class="s1">&#39;name_last&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Last name&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;The Last name, extracted from the Name field&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;real field&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;name&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_handler_field_lastname&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>    <span class="s1">&#39;name_backwards&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Evil Genius Name&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;help&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;The name, reversed so it sounds like the name of an evil genius.&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;real field&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;name&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="s1">&#39;field&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;mymodule_handler_field_evil&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;click sortable&#39;</span> <span class="o">=&gt;</span> <span class="k">TRUE</span><span class="p">,</span>
</span><span class='line'>        <span class="p">),</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'><span class="o">...</span>
</span></code></pre></td></tr></table></div></figure>


<p>Can you spot the difference? All you have to do is add a variable for <em>real field</em>, which tells Views the field name to use for the source value, and that&rsquo;s it. Everything else is totally identical to a normal field. By custom we prefix the &ldquo;virtual&rdquo; field&rsquo;s name with the name of the real field, but that&rsquo;s as complicated as it gets.</p>

<h1>Conclusion</h1>

<p>If there&rsquo;s one thing I want you to take away from this blog post, it&rsquo;s that <strong>the Views API is actually really easy</strong>. And if you can&rsquo;t find something online, take a moment to actually look at the <a href="https://api.drupal.org/api/views/views.api.php/">API documentation included with the module</a>. It&rsquo;s <em>very</em> thorough, and easy to read. If you feel like you understand how this works, but the doco doesn&rsquo;t quite cover what you&rsquo;re trying to do, look for examples in the Views module itself! There are 169 handlers for every concievable kind of case, just within Views. Find something reasonable and build off of that!</p>

<p>With this in mind, it&rsquo;s only 24 lines of simple code to provide your own handler for an existing field. After that 24 lines, you&rsquo;re doing the same things you were planning to do in views_php&hellip; but now you&rsquo;re doing them in a real coding environment, with a revisioning system, and where it&rsquo;s easy to track down and fix errors that could otherwise crash your site. 24 lines of array definition can save you a world of hurt. I hope to see those views_php installation numbers dropping soon.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Custom Context Conditions]]></title>
    <link href="https://ohthehugemanatee.org/blog/2013/12/02/custom-context-conditions/"/>
    <updated>2013-12-02T15:06:49+01:00</updated>
    <id>https://ohthehugemanatee.org/blog/2013/12/02/custom-context-conditions</id>
    <content type="html"><![CDATA[<p>One of the big advantages to using the <a href="https://drupal.org/project/context" title="Context Module on drupal.org">Context module</a> is how totally extensible it is. Not only can you use and re-use the built in conditions, you can write your own. This brings all the power of the custom PHP evaluation method of block placement, but in a structure that makes your code re-usable, contributable, versioned, and standards-based. Writing a custom Context Condition is also a great template for how to integrate custom behaviors in many of the more complex Drupal modules such as Views and Search_API. We&rsquo;ll see this pattern again and again, and this is about the most basic one to demonstrate with.</p>

<p>My task was to determine if the displayed node was entity-referenced as being the &ldquo;special&rdquo; node from it&rsquo;s parent organic group. It&rsquo;s a weird requirement (which is exactly why a custom Condition makes sense here), so let me explain that again. On a site with Organic Groups, the Group node has an entityreference field, which marks one of the Group member nodes as special. When the user is viewing this special node, our Rules condition should evaluate to positive.</p>

<p>The first prerequisite is to make absolutely certain that you can&rsquo;t do this using any of the built in Conditions, and something this unique definitely qualifies there. So let&rsquo;s get to the implementation in our custom module. The module will be called CCC for Custom Context Condition.</p>

<figure class='code'><figcaption><span>ccc.info  (ccc.info)</span> <a href='https://ohthehugemanatee.org/downloads/code/modules/ccc/ccc.info'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="na">name</span> <span class="o">=</span> <span class="s">CCC (Custom Context Condition) Example Module</span>
</span><span class='line'><span class="na">description</span> <span class="o">=</span> <span class="s">Provides a custom Context Condition</span>
</span><span class='line'><span class="na">core</span> <span class="o">=</span> <span class="s">7.x</span>
</span><span class='line'><span class="na">version</span> <span class="o">=</span> <span class="s">7.x-1.x</span>
</span><span class='line'><span class="na">package</span> <span class="o">=</span> <span class="s">Custom</span>
</span><span class='line'>
</span><span class='line'><span class="na">dependencies[]</span> <span class="o">=</span> <span class="s">entityreference</span>
</span><span class='line'><span class="na">dependencies[]</span> <span class="o">=</span> <span class="s">context</span>
</span><span class='line'><span class="na">dependencies[]</span> <span class="o">=</span> <span class="s">og</span>
</span></code></pre></td></tr></table></div></figure>


<p>That&rsquo;s a totally normal .info file, with logical dependencies on OG, EntityReference, and Context modules. Let&rsquo;s have a look at the .module file. This is probably a lot simpler than you expected.</p>

<figure class='code'><figcaption><span>ccc.module </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Impelements hook_context_plugins().</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">ccc_context_plugins</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$plugins</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="s1">&#39;ccc_condition_og_special_node&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;handler&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;path&#39;</span> <span class="o">=&gt;</span> <span class="nx">drupal_get_path</span><span class="p">(</span><span class="s1">&#39;module&#39;</span><span class="p">,</span> <span class="s1">&#39;ccc&#39;</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;/plugins/context&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;file&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;ccc_condition_og_special_node.inc&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;class&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;ccc_condition_og_special_node&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="s1">&#39;parent&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;context_condition&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>  <span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$plugins</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>First we implement <em>hook_context_plugins()</em>, to declare our new condition plugin to Context. This function should return an array of plugins, keyed by plugin name (in our case, ccc_condition_og_special_node). For each plugin, you have to explain to Context some basic information about the handler you&rsquo;re going to write.</p>

<ul>
<li><strong>path</strong> The path to the plugin file. By convention you should put it in your module&rsquo;s directory, under /plugins/context.</li>
<li><strong>file</strong> The filename to look for. Keep yourself sane, and name it after the plugin you&rsquo;re writing.</li>
<li><strong>class</strong> The name of the Class you&rsquo;re about to write. If you&rsquo;ve never written a PHP class before, this is good practice for D8 and object oriented code in general. Think of it like a function name, and again: name it after the plugin you&rsquo;re writing.</li>
<li><strong>parent</strong> The Class you are extending to create your condition. If you don&rsquo;t know what to put here, just enter &lsquo;context_condition&rsquo;.</li>
</ul>


<p>Now that Context knows about your plugin, you have to declare it to the UI in order to use it! For this we implement <em>hook_context_registry</em>. This function returns an array keyed by plugin type&mdash;in this case, &ldquo;conditions&rdquo;. For each condition (keyed by condition name), we need title, description, and plugin.</p>

<figure class='code'><figcaption><span>ccc.module </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_context_registry().</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">ccc_context_registry</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$registry</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>    <span class="s1">&#39;conditions&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;ccc_condition_og_special_node&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>        <span class="s1">&#39;title&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;OG Special Node&#39;</span><span class="p">),</span>
</span><span class='line'>        <span class="s1">&#39;description&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Set this context based on whether or not the node is the &quot;Special Node&quot; entityreferenced in the parent OG.&#39;</span><span class="p">),</span>
</span><span class='line'>        <span class="s1">&#39;plugin&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;ccc_condition_og_special_node&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="p">),</span>
</span><span class='line'>    <span class="p">),</span>
</span><span class='line'>  <span class="p">);</span>
</span><span class='line'>  <span class="k">return</span> <span class="nv">$registry</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now Context module knows everything it needs to know about your plugin and condition, we have to tell Drupal when to evaluate your condition. You can implement whatever hook make sense for you here, the important part is that you execute your plugin. Since our condition only makes sense after everything else has fired (ie when the OG context is well and firmly set), we&rsquo;ll implement <em>hook_context_page_reaction()</em>.</p>

<figure class='code'><figcaption><span>ccc.module </span></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Implements hook_context_page_reaction().</span>
</span><span class='line'><span class="sd"> *</span>
</span><span class='line'><span class="sd"> * Executes our OG Special Node Context Condition. </span>
</span><span class='line'><span class="sd"> * Gotta run on context_page_reaction, so Views and OG have a chance to</span>
</span><span class='line'><span class="sd"> * set/modify Group context. </span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">function</span> <span class="nf">ccc_context_page_reaction</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nv">$group</span> <span class="o">=</span> <span class="nx">og_context</span><span class="p">();</span>
</span><span class='line'>  <span class="c1">// Only execute the group node context condition if there is a group node</span>
</span><span class='line'>  <span class="c1">// in context.</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nv">$group</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$plugin</span> <span class="o">=</span> <span class="nx">context_get_plugin</span><span class="p">(</span><span class="s1">&#39;condition&#39;</span><span class="p">,</span> <span class="s1">&#39;ccc_condition_og_special_node&#39;</span><span class="p">);</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="nv">$plugin</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$plugin</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">(</span><span class="nv">$group</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>That&rsquo;s it for your module file. Just declare the plugin to Context and its UI, and find a place to actually execute the plugin. Now we&rsquo;ll write the actual handler class.</p>

<p>Create your plugin file in the place you promised Context to find it in your <em>hook_context_plugins()</em> implementation. In our case, this is plugins/context/ccc_condition_og_special_node.inc . We&rsquo;re going to extend Context&rsquo;s basic Condition Class to provide our own functionality. Here are the contents of my ccc_condition_og_special_node.inc file:</p>

<figure class='code'><figcaption><span> (ccc_condition_og_special_node.inc)</span> <a href='https://ohthehugemanatee.org/downloads/code/modules/ccc/plugins/context/ccc_condition_og_special_node.inc'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="o">&lt;?</span><span class="nx">php</span>
</span><span class='line'><span class="sd">/**</span>
</span><span class='line'><span class="sd"> * Expose Web Area Contact Form as a Context condition.</span>
</span><span class='line'><span class="sd"> */</span>
</span><span class='line'><span class="k">class</span> <span class="nc">ccc_condition_og_special_node</span> <span class="k">extends</span> <span class="nx">context_condition</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">function</span> <span class="nf">condition_values</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">array</span><span class="p">(</span>
</span><span class='line'>      <span class="s1">&#39;TRUE&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Node is an OG special node&#39;</span><span class="p">),</span>
</span><span class='line'>      <span class="s1">&#39;FALSE&#39;</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">(</span><span class="s1">&#39;Node is not an OG special node&#39;</span><span class="p">),</span>
</span><span class='line'>    <span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">function</span> <span class="nf">condition_form</span><span class="p">(</span><span class="nv">$context</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$form</span> <span class="o">=</span> <span class="k">parent</span><span class="o">::</span><span class="na">condition_form</span><span class="p">(</span><span class="nv">$context</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;#type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;radios&#39;</span><span class="p">;</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;#default_value&#39;</span><span class="p">])){</span>
</span><span class='line'>      <span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;#default_value&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;TRUE&#39;</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span><span class="p">{</span>
</span><span class='line'>      <span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;#default_value&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">current</span><span class="p">(</span><span class="nv">$form</span><span class="p">[</span><span class="s1">&#39;#default_value&#39;</span><span class="p">]);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="nv">$form</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="sd">/**</span>
</span><span class='line'><span class="sd">   * Condition form submit handler.</span>
</span><span class='line'><span class="sd">   *</span>
</span><span class='line'><span class="sd">   * Storing values in an array since that&#39;s what Context prefers</span>
</span><span class='line'><span class="sd">   */</span>
</span><span class='line'>  <span class="k">function</span> <span class="nf">condition_form_submit</span><span class="p">(</span><span class="nv">$values</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="nb">array_filter</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="nv">$values</span> <span class="o">=&gt;</span> <span class="nv">$values</span><span class="p">));</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">function</span> <span class="nf">execute</span><span class="p">(</span><span class="nv">$group</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$group</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nv">$group</span><span class="p">[</span><span class="s1">&#39;group_type&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;node&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$group_node</span> <span class="o">=</span> <span class="nx">entity_load_single</span><span class="p">(</span><span class="nv">$group</span><span class="p">[</span><span class="s1">&#39;group_type&#39;</span><span class="p">],</span> <span class="nv">$group</span><span class="p">[</span><span class="s1">&#39;gid&#39;</span><span class="p">]);</span>
</span><span class='line'>      <span class="nv">$group_wrapper</span> <span class="o">=</span> <span class="nx">entity_metadata_wrapper</span><span class="p">(</span><span class="s1">&#39;node&#39;</span><span class="p">,</span> <span class="nv">$group_node</span><span class="p">);</span>
</span><span class='line'>      <span class="nv">$special_nid</span> <span class="o">=</span> <span class="nv">$group_wrapper</span><span class="o">-&gt;</span><span class="na">field_special_node</span><span class="o">-&gt;</span><span class="na">value</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_contexts</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$context</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="nv">$values</span><span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">fetch_from_context</span><span class="p">(</span><span class="nv">$context</span><span class="p">,</span> <span class="s1">&#39;values&#39;</span><span class="p">);</span>
</span><span class='line'>        <span class="k">if</span> <span class="p">(</span><span class="nx">arg</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;node&#39;</span> <span class="o">&amp;&amp;</span> <span class="nx">arg</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="nv">$contact_nid</span><span class="o">-&gt;</span><span class="na">nid</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$values</span><span class="p">[</span><span class="s1">&#39;TRUE&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>          <span class="c1">// This is a special node, and the condition is set to match special </span>
</span><span class='line'>          <span class="c1">// nodes.</span>
</span><span class='line'>          <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">condition_met</span><span class="p">(</span><span class="nv">$context</span><span class="p">);</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>        <span class="k">if</span> <span class="p">(</span><span class="nx">arg</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">!=</span> <span class="nv">$contact_nid</span><span class="o">-&gt;</span><span class="na">nid</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$values</span><span class="p">[</span><span class="s1">&#39;FALSE&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span><span class='line'>          <span class="c1">// This is not a special node, and the condition is set to match</span>
</span><span class='line'>          <span class="c1">// non-special nodes.</span>
</span><span class='line'>          <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">condition_met</span><span class="p">(</span><span class="nv">$context</span><span class="p">);</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The trickiest part of this is in the Condition settings form and values. Context assumes that your settings form will be a series of checkboxes, and does a lot of internal processing based on that assumption. We don&rsquo;t want to mess any of that up, so there&rsquo;s a bit of dancing around the requirement here.</p>

<p>First we provide the function condition_values. Context needs to know in advance what the possible values are for the Condition&rsquo;s settings form, and this is where you return them. Based on this return, Context will build a settings form of checkboxes for you.</p>

<p>Then we override the settings form with condition_form(). I change the type of the form element to radio boxes, and set a default value.</p>

<p>Then I add my own submit handler, which merely takes the result of the radio box and puts it into an array, just like it would be if this was a checkbox.</p>

<p>Finally, we get to the good part: the execute function. If you recall, this is what we called in <em>ccc_content_page_reaction()</em>. Here we load the Group node, and use <em>entity_metadata_wrapper</em> to extract the value of the field_special_node entityreference field on that node. Then we test the current NID from the URL. Note that you never have to explicitly return FALSE; Context is only watching for TRUE returns.</p>

<p>When I learned how to do this, I found it surprisingly easy. The hardest part is wrestling with the Condition class to get exactly the behavior you like. Everyone ends up doing <em>some</em> dancing around here, so don&rsquo;t feel bad about it. Context&rsquo;s own Conditions are great examples. Have a look at the classes provided in context/plugins/context_condition_*.inc to get ideas for how to do this.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Adding Rules to Your Contrib Module (So You Can Reject Half the Tickets in Your Queue)]]></title>
    <link href="https://ohthehugemanatee.org/blog/2013/04/18/adding-rules-to-your-contrib-module-so-you-can-reject-half-the-tickets-in-your-queue/"/>
    <updated>2013-04-18T00:00:00+02:00</updated>
    <id>https://ohthehugemanatee.org/blog/2013/04/18/adding-rules-to-your-contrib-module-so-you-can-reject-half-the-tickets-in-your-queue</id>
    <content type="html"><![CDATA[<p><a href="http://drupal.org" target="_blank">Drupal&#8217;s</a> <a href="http://drupal.org/project/rules" target="_blank">Rules module</a> lets site builders define complex and custom behaviors without having to code a custom module. That puts a lot of power in the hands of the site builder, and it makes developers (rightly) nervous. But there&#8217;s another way to think about it.</p>


<p>What&#8217;s fantastic about Rules is that it lets everyone who wants your module to behave slightly differently to <em>change the behavior for themselves</em>. In fact, if you build the logic of your module into Rules you get&nbsp;an excuse to reject half the tickets in your contrib module queue on the grounds of &#8220;works as intended,&#8221; aka &#8220;do it yourself.&#8221; &nbsp;To me, this is the quiet brilliance of Commerce module&#8217;s dependence on Rules. Their code is almost 100% functional elements, with as little behavioral logic as possible. All of the logic is written in Rules. Of course they still distribute Commerce with a hefty set of default rules, so it works with a standard implementation out of the box. But at the same time, it is open to completely custom workflows without the developers ever having to get involved.</p>


<p>Today we&#8217;re going to cover adding Rules to existing code. This is an easy way to write solid and useful patches for other contrib modules out there, patches that get used. For your own projects you will probably want to implement this code in your own custom module, just hooking into core or contrib behaviors. Either way the logic is the same.</p>


<p>At it&#8217;s core, the Rules API lets you expose functions you&#8217;ve already written to the GUI. 90% of the work is just declaring the functions. There are three elements that Rules cares about:</p>


<ul><li><strong>Events</strong>: Potential triggers that a user can use to take action with Rules.</li><li><strong>Actions</strong>: Functions which take a set of parameters and do something.&nbsp;</li><li><strong>Conditions</strong>: Test functions, which return <span style="font-family:courier new,courier,monospace;">TRUE</span> or <span style="font-family:courier new,courier,monospace;">FALSE</span>.</li></ul>


<p>You declare these elements to Rules with hooks, usually assembled into a separate <span style="font-family:courier new,courier,monospace;">modulename.rules.inc</span> file. First, let&#8217;s define an event with <span style="font-family:courier new,courier,monospace;"><a href="http://drupalcontrib.org/api/drupal/contributions!rules!rules.api.php/function/hook_rules_event_info/7" target="_blank">hook_rules_event_info()</a></span>.</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.rules.inc">&lt;?php
/**
* Implements hook_rules_event_info().
* Fire a Rules event when a node is validated.
*/
function mymodule_rules_event_info() {
&nbsp; return array(
&nbsp;&nbsp;&nbsp; 'mymodule_node_is_being_validated' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'group' =&gt; t('My module'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; t('A node is being validated!'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'variables' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'node' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'type' =&gt; 'node',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; t('unsaved node being validated'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
        'form_id' =&gt; array(
          'type' =&gt; 'text',
          'label' =&gt; t('Form ID'),
        ),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
&nbsp;&nbsp;&nbsp; ),
  );
}
?&gt;
</pre>


<p>This implementation tells rules that you are defining an Event with the machine name <span style="font-family: 'courier new', courier, monospace;">mymodule_node_is_being_validated</span>. In the Rules dropdown select box that lets you choose the triggering action for a new rule, your Event is called &#8220;A node is being validated!&#8221; and is sorted into the group &#8220;My Module&#8221;. &nbsp;The variables array sets the variables that are offered with this particular event. Each variable in the array must have a &nbsp;machine name (the key), a human-readable label and a data type. Now, anywhere that you want to fire this rules event, you call it with&nbsp;<span style="font-family: 'courier new', courier, monospace;">rules_invoke_event(&#8216;mymodule_node_is_being_validated&#8217;, $node)&nbsp;</span>to fire the Event. In this case, you could hook into node validation and add it easily enough:</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.module">&lt;?php
/**
* Implements hook_node_validate().
* Fires our Rules event on node validation.
*/
function mymodule_node_validate($node, $form, &amp;$form_state) {
  rules_invoke_event('mymodule_node_is_being_validated', $node, $form['#form_id']);
}
?&gt;
</pre>


<p>This example brings up one of the big limitations of Rules: you can&#8217;t fail validation. We can set an error message, respond with all the power of Rules, but no matter what you do you cannot make this node form fail validation. The good people at <a href="http://drupal.org/project/rules_forms" target="_blank">rules_forms</a> module are trying to address this, but it&#8217;s a much thornier problem than it looks.</p>


<p>Next, let&#8217;s define a Rules action with <span style="font-family:courier new,courier,monospace;"><a href="http://drupalcontrib.org/api/drupal/contributions%21rules%21rules.api.php/function/hook_rules_action_info/7" target="_blank">hook_rules_action_info()</a></span>. This time we&#8217;ll use a real world use case from a recent client: our Rules Action will allow you to subscribe a user to a node with the <a href="http://drupal.org/project/subscriptions" target="_blank">subscriptions</a> module. Again, we&#8217;ll add this info implementation to our <span style="font-family:courier new,courier,monospace;">mymodule.rules.inc</span> file for clarity.</p>


<p>&nbsp;</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.rules.inc">&lt;?php
/**
* Implements hook_rules_action_info()
* Add a Rules Action for subscribing a user to a node.
*/
function mymodule_rules_action_info() {
&nbsp; return array(
&nbsp;&nbsp;&nbsp; 'mymodule_subscribe_user_to_a_node' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; t('Subscribe a user to a node'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'group' =&gt; t('Subscriptions'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'parameter' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'user' =&gt; array(
          'type' =&gt; 'user',
          'label' =&gt; 'Subscribing user',
        ),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'node' =&gt; array(
          'type' =&gt; 'node',
          'label' =&gt; 'Target node',
        ),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
&nbsp;&nbsp;&nbsp; ),
&nbsp; );
}
?&gt;
</pre>


<p>&nbsp;</p>


<p>You can see that we use the same <span style="font-family:courier new,courier,monospace;">label</span>, <span style="font-family:courier new,courier,monospace;">group</span>, and <span style="font-family:courier new,courier,monospace;">module</span> declarations here. Actions take parameters as well, which are structured very similarly to the <span style="font-family:courier new,courier,monospace;">variables</span> in events. You don&#8217;t have to do anything more to make an action: this is it. When Rules fires the action it will look for a function called <span style="font-family:courier new,courier,monospace;">mymodule_subscribe_user_to_a_node</span>, and fire it with the parameters provided in the GUI. In this case we wrapped our own function around subscribe module&#8217;s functionality, because of the way subscribe&#8217;s own subscription function works.</p>


<p>&nbsp;</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.module">&lt;?php
/**
* Creates a subscription for the user
*
* @param $user
*&nbsp; The user to subscribe to the node.
* @param $node
*&nbsp; The node to which the user will subscribe.
*/
function mymodule_subscribe_user_to_a_node($user, $node) {
&nbsp; module_load_include('inc', 'subscriptions', 'subscriptions.admin');
&nbsp; if (!is_object($node) || !isset($node-&gt;nid)) {
&nbsp;&nbsp;&nbsp; watchdog('rules_subscriptions', 'Error: object passed is not node. Data: !node', array('!node' =&gt; print_r($node, true)), WATCHDOG_ERROR);
&nbsp;&nbsp;&nbsp; return;
&nbsp; }
&nbsp; $form_state = array(
&nbsp;&nbsp;&nbsp; 'values' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'stype' =&gt; 'node',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'sid' =&gt; $node-&gt;nid,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'uid' =&gt; $user-&gt;uid,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'author_uid' =&gt; NULL,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'send_interval' =&gt; _subscriptions_get_setting('send_interval', $user),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'updates' =&gt; _subscriptions_get_setting('send_updates', $user),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'comments' =&gt; _subscriptions_get_setting('send_comments', $user),
&nbsp;&nbsp;&nbsp; ),
&nbsp; );
&nbsp; drupal_form_submit('subscriptions_add_form', $form_state, 'node', $node-&gt;nid);
}
?&gt;
</pre>


<p>&nbsp;</p>


<p>So much for Rules actions - they&#8217;re even easier than events! &nbsp;There is one big defining difference for Actions though: they can provide new variables back to Rules. This is as easy as a <span style="font-family:courier new,courier,monospace;">provides</span> array in <span style="font-family:courier new,courier,monospace;">hook_rules_action_info()</span>, and returning an array of values from the actual function called.&nbsp;</p>


<p>Now let&#8217;s look at a Rules condition. No surprise by now, we declare the existence of our Rules Condition through <span style="font-family:courier new,courier,monospace;"><a href="http://drupalcontrib.org/api/drupal/contributions!rules!rules.api.php/function/hook_rules_condition_info/7" target="_blank">hook_rules_condition_info()</a></span>&nbsp;in <span style="font-family:courier new,courier,monospace;">mymodule.rules.inc</span>&nbsp;:</p>


<p>&nbsp;</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.rules.inc">&lt;?php
/**
* Implements hook_rules_condition_info().
* Checks if the given user is admin.
*/
function mymodule_rules_condition_info() {
&nbsp; return array(
&nbsp;&nbsp;&nbsp; 'mymodule_user_is_admin' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'group' =&gt; t('My Module'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; t('User is Admin'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'parameter' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'user' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'type' =&gt; 'user',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; t('User to test'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
&nbsp;&nbsp;&nbsp; ),
&nbsp; );
}
?&gt;
</pre>


<p>&nbsp;</p>


<p>Once again we see the familiar structure to declare what is about to happen. And just like in an Action, Rules is going to fire a function named after the array key, <span style="font-family:courier new,courier,monospace;">mymodule_user_is_admin</span>, with the parameters provided. Here we&#8217;ll have a very simple function to check this, and it has to return <span style="font-family:courier new,courier,monospace;">TRUE</span> or <span style="font-family:courier new,courier,monospace;">FALSE</span>.&nbsp;</p>


<p>&nbsp;</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.module">&lt;?php
function mymodule_user_is_admin($user) {
  if ($user-&gt;uid == '1') {
    return TRUE;
  }
  return FALSE;
}
?&gt;
</pre>


<p>Great, so now your module is fully integrated with Rules, right? Well, you have to actually include the Rules logic with the module. Rules provides hook_rules_default_configuration for you to do this, but writing rules by hand is a pain. The shortcut solution is to build your Rules in the Rules GUI and export them, and paste the export into your code. <a href="http://drupalcontrib.org/api/drupal/contributions%21entity%21entity.module/7" target="_blank"><span style="font-family:courier new,courier,monospace;">entity_import()</span></a> is a handy function from the <a href="http://drupal.org/project/entity" target="_blank">EntityAPI</a> module you can use to translate the export format into the format Rules needs. Here&#8217;s a sample <span style="font-family:courier new,courier,monospace;">(hook_rules_default_configuration</span> must be implemented in <span style="font-family:courier new,courier,monospace;">mymodule.rules_defaults.inc</span>):</p>


<p>&nbsp;</p>


<pre class="brush: php; auto-links: true; collapse: false; first-line: 1; html-script: false; smart-tabs: true; tab-size: 4; toolbar: true; codetag" title="mymodule.rules_defaults.inc">&lt;?php
/**
* Implements hook_default_rules_configuration().
*/
function mymodule_default_rules_configuration() {
&nbsp; $rules = array();
  $rules['rules_mymodule_behavior'] = entity_import(
    'rules_config',&nbsp;
    '............');
  return $rules;
}</pre>


<p>Note that the new rule name has to be prefixed with <span style="font-family:courier new,courier,monospace;">rules_</span>&nbsp;. &nbsp;That&#8217;s all you need to do.</p>


<p>What&#8217;s wonderful about these functions is how simple they are. Depending on how your module is written, adding Rules support could be as simple as adding calls to <span style="font-family: 'courier new', courier, monospace;">hook_rules_event_info()</span>, <span style="font-family: 'courier new', courier, monospace;">hook_rules_action_info()</span>, and <span style="font-family: 'courier new', courier, monospace;">hook_rules_condition_info()</span> that connect to existing functions already in your module. In 10 minutes or less, you can open your module up to much more flexibility than was ever possible before. And if you dare to prune the functionality out of your existing code, you can build it in the Rules GUI, export it, and have all your logic exposed and totally customizable in a further 15 minutes. That&#8217;s less than half an hour, and you can start training your users to deal with their own problems. :)</p>


<p>Questions? Problems? Leave us a message in the comments&#8230;</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Announcing the Resource Conflict Drupal Module]]></title>
    <link href="https://ohthehugemanatee.org/2012/06/announcing-resource-conflict-drupal.html"/>
    <updated>2012-06-13T22:35:00+02:00</updated>
    <id>https://ohthehugemanatee.org/2012/06/announcing-resource-conflict-drupal</id>
    <content type="html"><![CDATA[
<div class="css-full-post-content js-full-post-content">
I recently took over an aging Drupal module, <a href="http://drupal.org/project/resource_conflict">Resource Conflict</a>. It had a D6 version with a lot of outstanding bugs in the queue&#8230; I started by simply <a href="http://drupal.org/node/976522">rewriting it for D7 and my specific use case</a>, but ended up in a discussion with the module&#8217;s old maintainer about a total rewrite for&nbsp;<a href="http://drupal.org/project/entity">Entities</a>&nbsp;and&nbsp;<a href="http://drupal.org/project/rules">Rules</a>. So <a href="http://drupal.org/node/1575800">that&#8217;s what I did</a>, and I just released the <a href="http://ftp.drupal.org/files/projects/resource_conflict-7.x-3.x-dev.tar.gz">7.x-3.x-dev</a> version.<br /><br /><a href="http://drupal.org/project/resource_conflict">Resource Conflict</a> USED to be a module that detected booking conflicts in resources, and threw a form error. Resources were node reference field entries, and it supported date and event modules for the date/time. Resource Conflict version 3 is built on Entities and Rules,&nbsp;so the behavior is now totally customizable. This lets it support a wide variety of use cases.<br /><br /><b>How to use it</b><br />Out of the box, the module lets you enable Content Types for resource conflict checking, and you select which date field to use for each enabled content type. You do all this on the Content Type&#8217;s edit page.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-4twPmZsdmzM/T9kP9pKUeqI/AAAAAAAAABU/WplXGL8Ocfo/s1600/Screen+shot+2012-06-14+at+12.10.43+AM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="380" src="http://1.bp.blogspot.com/-4twPmZsdmzM/T9kP9pKUeqI/AAAAAAAAABU/WplXGL8Ocfo/s640/Screen+shot+2012-06-14+at+12.10.43+AM.png" width="640" /></a></div><br /><br /><br />The module comes with a sample Rule for you, which throws a form error any time you try to save a Resource Conflict enabled node with a date that overlaps another Resource Conflict enabled node.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-4NAMGMI4658/T9kQ20ThSRI/AAAAAAAAABc/LOy6nHdUDy8/s1600/Screen+shot+2012-06-14+at+12.14.34+AM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="364" src="http://4.bp.blogspot.com/-4NAMGMI4658/T9kQ20ThSRI/AAAAAAAAABc/LOy6nHdUDy8/s640/Screen+shot+2012-06-14+at+12.14.34+AM.png" width="640" /></a></div><br />But this is not a very realistic use case. More likely you will want to edit the rule to add some more conditions - for example, maybe a resource conflict on your site means overlapping taxonomy terms. Or entity references. Or titles. Or anything at all!<br /><br />To give an example of how complex this can go - on a site I recently launched, I have two kinds of resource conflict events. &#8220;Hard&#8221; conflicts are when two bookings at the same time reference the same user or taxonomy term. &nbsp;Hard conflicts throw a form error and prevent saving the node.&nbsp;This is just like the above case, and it&#8217;s a really simple modification on the default Rule. &nbsp;&#8220;Soft&#8221; conflicts are when you try to book a taxonomy term that is a parent or child of a term in an existing booking, or a user who is tagged with a term or child of a term that is already booked. For example, maybe I try to book the taxonomy term &#8220;Maintenance&#8221;, but the sub-term &#8220;Plumbers&#8221; is already booked at the same time. Or maybe I try to book John Doe, who is tagged as a &#8220;Plumber&#8221;, but Maintenance is already booked at that time. &nbsp;Soft conflicts can be booked, but they create a node to record the conflict.<br /><br />Other people have asked about using the module to integrate with Organic Groups, or to control bookings of finite resources - you could easily use Rules to build those functionalities. Best of all, it&#8217;s all exposed and easy for you to maintain.<br /><br />Here&#8217;s a run down of the Rules components included with <a href="http://drupal.org/project/resource_conflict">Resource Conflict 7</a>:<br /><ul><li><b>EVENT: A Resource Conflict Node Form is Validated</b>: This rule fires during node form validation on Resource Conflict enabled content types. You should use this event if you want to set form errors, or if you want to interact with Rules_forms module. It provides both a node object of the node being created/edited and a form object for use with rules_forms. This is the event trigger for the default Rule.</li><li><b>CONDITION: Contains a Resource Conflict:</b> Evaluate a node object for conflicts. Returns TRUE if there are conflicts for the node.</li><li><b>ACTION: Load a List of Conflicting Nodes</b>: Creates a list of nodes that conflict with the given node.</li><li><b>ACTION: Set a Form Validation Error</b>: Stores a form validation error to be fired the next time a validation hook is called on a conflict-enabled node. This is intended for use with the &#8220;A Resource Conflict Node Form is Validated&#8221; Event.</li></ul><div><br /></div><div><b>Future plans</b></div><div><b><br /></b></div><div>I&#8217;m pretty happy with this initial dev release; it solves a lot of problems quite elegantly. But there are a few remaining. Here are the items I&#8217;m planning on knocking out first.</div><div><ul><li><b>Drupal 6 backport:</b>&nbsp;I&#8217;ll release a 6.x-3.x branch which uses Rules for reactions. The biggest issue here is that <a href="http://drupal.org/project/rules_forms">rules_forms module</a> doesn&#8217;t exist for D6, which makes it impossible to throw a form validation error from within Rules. I may have to write a custom Rules action to do this.</li><li><b>Full Entities integration:</b>&nbsp;I&#8217;d like to generalize the module out to support ALL fieldable entities.&nbsp;</li><li><b>Better Integration with rules_forms</b>: rules_forms is pretty cool, and even cooler is the new version they&#8217;re working on, that doesn&#8217;t rely on the &#8220;form&#8221; Rules object. I&#8217;m looking forward to this, because it means we&#8217;ll be able to do cooler things with resource_conflict.</li></ul><div><br /></div></div>
</div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal Developers' Toolkit: Handy Tools and Functions to Make Your Life Easier]]></title>
    <link href="https://ohthehugemanatee.org/2012/06/drupal-developers-toolkit-handy-tools.html"/>
    <updated>2012-06-08T17:23:00+02:00</updated>
    <id>https://ohthehugemanatee.org/2012/06/drupal-developers-toolkit-handy-tools</id>
    <content type="html"><![CDATA[
<div class="css-full-post-content js-full-post-content">
Drupal is big and complex, and no matter how good you are, you will need to debug. Before you get started coding for a Drupal site, you should download and enable the very useful <a href="http://drupal.org/project/devel">devel</a> module on your dev site. Go ahead, I&#8217;ll wait.<br /><br />This primer covers all the tools that I&#8217;ll use in later tutorials on this blog. In the real world I end up using 5-6 of these guys regularly. Learn them. They help.<br /><h3>    drupal_set_message()</h3><div>Printing a message is the basic tool of any debugging, and you need to know this core function. This lets you print a message to the page, Drupal-style. Usage: drupal_set_message($message, $severity).</div><div><br /></div><div><code>drupal_set_message(t('Hello %name!', array('%name' =&gt; 'John Doe')), 'warning');</code>&nbsp;</div><div><br /></div><div>Note that I use the t() function to process text in drupal_set_message. This is partly because the function itself doesn&#8217;t do any text sanitizing, so it&#8217;s good practice to insert a layer there. It&#8217;s also because you can&#8217;t &nbsp;insert variables directly into the message, and t() is a convenient way of doing that.</div><div><br /></div><div>Note that drupal_set_message() does not do well with large messages - it is not recommended to print big arrays directly to the message area. For that, we&#8217;ll use another function:</div><h3>    dpm()</h3><div>This sets a variable of your choice to Drupal&#8217;s messaging system, in a nice compact output handled by krumo.&nbsp;</div><div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-H4xCqcjlhF8/T9IuHpEFIMI/AAAAAAAAAA8/lctbEESP66E/s1600/Screen+shot+2012-06-08+at+6.53.24+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="289" src="http://3.bp.blogspot.com/-H4xCqcjlhF8/T9IuHpEFIMI/AAAAAAAAAA8/lctbEESP66E/s320/Screen+shot+2012-06-08+at+6.53.24+PM.png" width="320" /></a></div><div>Most of Drupal is understandable and learnable on the fly with just this simple tool. Usage: dpm($variable, $name = NULL).</div><div><br /></div><div><code>dpm($node, 'This is the node variable');</code></div><div><br /><h3>   kpr()</h3><div>Just like dpm, but it prints to the page header rather than the Drupal message area. Helpful when your theme doesn&#8217;t print messages. You can also have it return a string instead of printing it automatically, which comes in handy in some fairly bizarre circumstances. Usage: kpr($variable, $return = FALSE, $name = NULL).&nbsp;</div><div><br /></div><div><code>kpr($node, FALSE, 'This is the node variable');</code></div><div><br /></div><h3>   dvm()</h3><div>OK, you don&#8217;t like krumo. Maybe you&#8217;re a masochist, or maybe you have some esoteric requirements to deal with. Either way, you want dvm(). It prints variables in a more traditional format into the message area. I have used this to get variables into pastebin, very helpful when asking for help on Drupal IRC channels. :) Usage: dvm($variable, $name = NULL).</div><div><br /></div><div><code>dvm($node, 'This is the node variable');</code></div><h3>   dpr()</h3></div><div>If your theme doesn&#8217;t display messages, dpr() prints variables to the page header without krumo. Same usage case as above. Just like kpr(), you can return a string with this function. Usage: dpr($variable, $return = FALSE, $name = NULL).</div><div><br /></div><div><code>dpr($node, FALSE, 'This is the node variable');</code></div><div><br /></div><div><h3>  dargs()</h3></div><div>This guy shows you the arguments passed into the current function, using krumo for readability. This is my go-to function when using Drupal hooks. The API documentation is great, but there&#8217;s nothing like simply seeing the variables you have to work with. Usage: dargs()</div><div><br /></div><code>function swearing_custom_form_alter(&amp;$form, &amp;$form_state, $form_id) {<br />&nbsp; dargs();<br />}</code><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-N3-bpT3pgeI/T9Iy8ptSNkI/AAAAAAAAABI/FnlybyhHqeQ/s1600/Screen-shot-2012-06-08-at-7.12.02-PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="297" src="http://4.bp.blogspot.com/-N3-bpT3pgeI/T9Iy8ptSNkI/AAAAAAAAABI/FnlybyhHqeQ/s320/Screen-shot-2012-06-08-at-7.12.02-PM.png" width="320" /></a></div><div><h3> dd()</h3></div><div>For those awful times when a hook doesn&#8217;t produce direct output, there&#8217;s always dd(). This guy prints a given variable to a file called &#8220;drupal_debug.txt&#8221; in your site&#8217;s temporary files directory. This comes in very handy. Usage: dd($variable, $name = NULL)</div><div><br /></div><div><code>dd($node, 'This is the node variable');</code></div><div><br /></div><h3> ddebug_backtrace()</h3><div>This prints a backtrace for the current function in krumo, in the head of your current page. Devel module comes with the ability to enable this automatically for fatal errors, but occasionally you just want to see how things work. Usage: ddebug_backtrace().</div><div><br /></div><h3> db_queryd()</h3><div>This tool is handy for testing queries. Devel also has the ability to display a query log at the bottom of every page, showing every query with a time-to-execute. That can be pretty overwhelming. db_queryd() lets you put in a single query and see if your database spits out any errors. Usage: db_queryd($query, $arguments = array())</div><div><br /></div><div><br /></div>
</div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal Quick Learning Guides: Custom Modules]]></title>
    <link href="https://ohthehugemanatee.org/2012/04/drupal-quick-learning-guides-custom.html"/>
    <updated>2012-04-23T16:17:00+02:00</updated>
    <id>https://ohthehugemanatee.org/2012/04/drupal-quick-learning-guides-custom</id>
    <content type="html"><![CDATA[
<div class="css-full-post-content js-full-post-content">
Ah, it&#8217;s nice to be done with the basic structure stuff. At this point, I&#8217;m going to assume that you know the basics of how to administer a Drupal site. You understand the <a href="http://swearingatcomputers.blogspot.com/2012/04/drupal-quick-learning-guides-drupal.html">file structure</a>, you know where to go to download <a href="http://drupal.org/project/themes">themes</a> and <a href="http://drupal.org/project/modules">modules</a>, and you know how to make sites out of the big pieces you can find that way. Awesome. This is where it gets fun.  I&#8217;m going to assume some basic knowledge of PHP, but there&#8217;s nothing here that you can&#8217;t pick up with some quick glances over at <a href="http://w3schools.com/php/">w3schools</a>, and maybe some experimentation on your own.<br /><br />I mentioned in the file structure post that the whole point of Drupal is that Everything Is Override-able. If you want to customize the site beyond what you get out of the box with some contributed modules, you&#8217;re going to want to do it in your own module. That&#8217;s right - it&#8217;s incredibly easy to write your own Drupal module to insert whatever code you want into your particular Drupal site. In fact, it&#8217;s the recommended way to customize your site, because it means that your code won&#8217;t get mixed up with anything in Drupal&#8217;s &#8220;core&#8221;. If you update Drupal, you don&#8217;t have to worry about refactoring your patches or anything like that, you&#8217;ve got one place to look for your custom behavior. More importantly, if someone else comes along to take care of the site after you&#8217;re off the project, there&#8217;s only one place for them to look for customizations.<br /><br /> A module at its most basic consists of a directory under sites/whatever/modules , a self-named .info file giving basic information about the module, and a self-named .module file with your code in it. In this quick learning guide, we&#8217;ll build a &#8220;Hello World&#8221; module that prints some text on every page load. This is a quick guide - I&#8217;ll get more into how to leverage Drupal in your code in later posts.<br /><br /> So let&#8217;s create your custom module. Consider your module&#8217;s name - Drupal has a single namespace for all modules and features, and it&#8217;s easy to get confused with the theme namespace as well, so it&#8217;s best to pick a name that is definitely not going to be used by any modules, features, or themes. Most big shops will have a custom module for most any site they build, and they just name it &#8220;Sitename Custom&#8221; or something similar. We&#8217;re going to make a module called &#8220;Swearing Custom&#8221;, to follow that convention.<br /><br /> First create the module directory. I like to keep my custom modules all under sites/all/modules/custom . Drupal will search subdirectories, so take advantage of that fact to keep your codebase tidy! We&#8217;ll create the directory sites/all/modules/swearing_custom . Note the underscore instead of a space.<br /><br /> Then create the module&#8217;s .info file. This file informs Drupal about your module&#8217;s name, description, requirements, and other fundamentals. I like to think of it as anything that will go on the site&#8217;s Modules listing. This file has to be named after the module, just like the directory was. Here&#8217;s my swearing_custom.info file:<br /><br /> <code>name = Swearing at Computers Custom Module description = Custom tweaks and functionality for Swearing at Computers project = "swearing_custom" version = "7.x-1.x-dev" core = "7.x" package = "custom" dependencies[] = token </code><br /><br /> Most of those variables can be omitted, to be honest. All Drupal REALLY needs is name, description, project, and core. Notice how I defined a dependency, just for fun. I also like to put my custom code into a module group called &#8220;custom&#8221;, so my modules list stays nice and tidy.  The norm is to add to the dependencies array with one dependency per line, for readability. You can similarly have a files[] array to add your own files to the module. By default this contains just the .info and  .module files, which is all we&#8217;re using so I&#8217;m not adding a files[] line at all.<br /><br /> Now we&#8217;ll create the module file itself. This is just a php file, with an opening  tag. The trouble is, how do you get your code to run? You can write all the functions you want, but how should Drupal know to call your code?<br /><br /> Aha, now we get to the interesting bit. Drupal modules are built around a system of &#8220;hooks&#8221;. Each module defines a set of hooks, places for you to insert your custom code. And this isn&#8217;t an edge case - it&#8217;s totally core to how Drupal works. Big modules will have tens of hooks at your disposal&#8230; but we&#8217;ll cover those a bit later. For now, we&#8217;re just going to use one simple hook to get our &#8220;Hello world&#8221; code displayed: <a href="http://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_init/7">hook_init()</a>.<br /><br /> All hooks are named hook_something. It&#8217;s how you know it&#8217;s a hook. All the core hooks, and many of the contributed hooks, are documented on Drupal&#8217;s excellent <a href="http://api.drupal.org/">API resource site</a>. When you&#8217;re writing your custom module, you just declare a function named after the hook, replacing the word &#8220;hook&#8221; with your module&#8217;s name. Drupal will find that function and run it for you. Simple as that.<br /><br /> Hook_init() is called early in the page build process, on every page of your site. This is a very powerful hook, usually used to define variables that you&#8217;ll use later on. But we&#8217;re just going to use it to print a message to the screen. To start with, my swearing_custom.module file looks like this:<br /><br /> <code>/**   * Implementation of hook_init().  */ swearing_custom_init() {   print "Hello world!"; } </code><br /><br />Pretty simple, right? That comment at the top is the standard format for Drupal. It&#8217;s so that you can easily find where you used particular hooks (or where other contrib modules used them!), and it&#8217;s used for a lot of Drupal&#8217;s automated help and API resources. It&#8217;s also nice and tidy, so it&#8217;s a good habit to get into.<br /><br /> Then you see that I just declared a function named after the hook, added my code, and got out of there. At this point, if I enable this custom module I&#8217;ll see &#8220;Hello world&#8221; in unformatted text at the top of every page. Simple, but ugly.<br /><br /> Enter another great feature of Drupal: a million and one helper functions. These are also well documented at <a href="http://api.drupal.org/">api.drupal.org</a>, and they&#8217;re the functions that everyone - even Drupal&#8217;s core itself - uses to get things done in a standardized way. For example, I hate the way that text appears. So let&#8217;s update the module to use Drupal&#8217;s own messaging system. This means using <a href="http://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_set_message/7">drupal_set_message()</a>. Have a look at the API page to see the arguments for this function, but 90% of your use cases will be following this example. Here&#8217;s a new version of swearing_custom.module:<br /><br /> <code>/**   * Implementation of hook_init().  */ swearing_custom_init() {   print "Hello world!";   drupal_set_message('Hello world!', 'status'); } </code><br /><br />That second argument tells Drupal the severity of the message: &#8216;status&#8217;, &#8216;warning&#8217;, or &#8216;error&#8217;. Status is actually the default, so I&#8217;ll cut it out of the next iteration of this code. The module now prints your message in a fancy, Drupal formatted way. It looks just like all the other Drupal modules, because that&#8217;s how all of Drupal displays messages. <br /><br /> I&#8217;m going to add one more layer of complexity here, with the <a href="http://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/t/7">t()</a> function. You&#8217;ll see t() everywhere: it&#8217;s the way you declare text strings to Drupal as user-facing text. It makes the text available for translation, and makes it easy to sanitize any variables or user-entered text. An example t() string would be:<br /><br /> <code>t('Welcome to %sitename', array('%sitename' =&gt; 'Swearing at Computers'); </code><br /><br /> You just include replacement patterns in the text itself, and then declare them in an array. The replacement strings get sanitized, so that&#8217;s the right place to include user-entered text, URLs, or just variable output in general. So here is a final version of our custom module, using drupal_set_message() the way it was intended.<br /><br /> <code>/**   * Implementation of hook_init().  */ swearing_custom_init() {   print "Hello world!";   drupal_set_message(t('Hello world! This is %name!', array(%name =&gt; 'Swearing at Computers'))); } </code><br /><br /> That&#8217;s it for this quick guide. The basics of writing a module. The hardest part here is figuring out which hooks to use. Google is your friend: try searching for things like &#8220;drupal views hooks&#8221; to see how to tweak Views at various stages, or &#8220;drupal form hooks&#8221; to see how forms work in Drupal. Or don&#8217;t - I&#8217;ll be covering some of those hooks in the next posts.
</div>

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