Skip to content

Instantly share code, notes, and snippets.

@wesruv
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wesruv/c9cf4c465a7face132ad to your computer and use it in GitHub Desktop.
Save wesruv/c9cf4c465a7face132ad to your computer and use it in GitHub Desktop.
<article class="layout-article__article" >
<div class="layout-article__article-hero" >
<div class="article-hero" >
<div class="cover-image cover-image--with-gradient" >
<span ></span>
<div class="cover-image__content" >
<div class="u-layout-container" >
<div class="article-hero__content u-layout-content-grid" >
<span ></span>
<div class="article-hero__meta" >
<span class="article-hero__author" ><span >by</span> <span ><a class="link" href="/who-we-are/greg-dunlap">Greg Dunlap</a></span></span><span class="article-hero__date" >September 4, 2013</span>
</div>
<h1 class="article-hero__title" >Building Views Query Plugins, Part 2</h1>
</div>
</div><span ></span>
</div>
</div>
</div>
</div>
<div class="layout-article__article-content" id="content">
<div class="layout-article__article-content-lead" >
<div class="rich-text" >
<div class="rich-text__wrapper">
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>Welcome to the second installment of our three part series on writing Views query plugins! In part one, we talked about the kind of thought and design work that needs to be done before coding the plugin begins. In this part, we'll start coding our plugin and end up with a basic functioning example.</p>
</div>
</div>
</div>
</div>
</div>
<div class="layout-article__article-content-body" >
<div class="layout-article__series u-layout-container" >
<div class="u-layout-content-grid" >
<div class="series-list" >
<div class="series-list__title" >
<span >Series</span> <a class="link" href="/articles/building-views-query-plugins-series">Building Views Query Plugins</a>
</div>
<ol class="series-list__items" >
<li >
<div class="series-list__inner" >
<div class="series-list__link" >
<a class="link" href="/articles/building-views-query-plugins-series/building-views-query-plugins">Building Views Query Plugins</a>
</div>
<div class="series-list__meta" >
<span >by Greg Dunlap</span> <span >on</span> <span >August 29, 2013</span>
</div>
</div>
</li>
<li >
<div class="series-list__inner" >
<div class="series-list__link" >
<a class="link is-active" href="/articles/building-views-query-plugins-series/building-views-query-plugins-part-2">Building Views Query Plugins, Part 2</a>
</div>
<div class="series-list__meta" >
<span >by Greg Dunlap</span> <span >on</span> <span >September 4, 2013</span>
</div>
</div>
</li>
</ol>
</div>
</div>
</div>
<div class="rich-text" >
<div class="rich-text__wrapper">
<p>While writing this article, I realized that creating a functional remote data integration for Views involves not only the query plugin, but also field plugins to expose that data to Views, and potentially filter or argument plugins to limit result sets. That's a lot of code to write, so lets get to it!</p>
<h2>Getting Started</h2>
<p>There's a joke about writing Views plugins - 10% of the time is spent copying and pasting code, 10% is spent changing class names and array keys, and 80% is spent finding the typo. While probably not strictly true, it does highlight the fact that when you're writing a Views plugin, naming is everything and a single typo in a class name can cause endless grief. In fact, I've actually moved away from a copy/paste paradigm for these plugins, instead building up all the structures by hand with the help of some snippets in my editor. It forces you to actually think through all the keys involved, and vastly reduces the time spent finding all the keys to replace, and the debugging time spent when you miss one somewhere.</p>
<p>There are a lot of steps here, and keep in mind that you will need to do them all in order to begin to actually use your plugin or see any results. This is one of the reasons that writing a plugin can be frustrating - you have to write a ton of very interdependent code before you can even start testing it.</p>
<h3>Step 1: Implement hook_views_api()</h3>
<p>All that we are doing here is declaring what version of Views we are coding to. Note that this is the only code that is going in our .module file, everything else is loaded on-demand through includes. This is what my hook implementation looks like and yours will be exactly the same, except of course using your own module's name instead of flickr_group_photos.</p>
<div class="u-layout-container rich-text__code">
<div class="rich-text__code__inner">
<div class="code">
<pre>
<code>
<span class="code__comment">/**
* Implementation of hook_views_api().
*/</span>
<span class="code__function"><span class="code__keyword">function</span> <span class="code__title">flickr_group_photos_views_api</span><span class="code__params">()</span> </span>{
<span class="code__keyword">return</span> <span class="code__keyword">array</span>(
<span class="code__string">'api'</span> =&gt; <span class="code__number">3.0</span>
);
}
</code>
</pre>
</div>
</div>
</div>
<h3>Step 2: Create a views.inc file</h3>
<p>Once hook_views_api() is implemented, Views will automatically look for a file named [module].views.inc in your module's home directory. Plugins, handlers, and other information are exposed through hooks implemented in this file.</p>
<h3>Step 3: Implement hook_views_plugins()</h3>
<p>The first thing we need to do is describe our plugin to views. This is done by implementing hook_views_plugin() and returning an array of the format $array[plugin_type][plugin_name]. The 'title' and 'help' keys pretty self-explanatory, and will be used in the Views UI and the plugin settings forms. However the 'handler' deserves some close attention. This is the name of the class that you will eventually create to manage queries to your remote service. It should be descriptive, and it should contain the name of the implementing module. We have chosen 'flickr_group_photos_plugin_query' here, and also used this as the plugin name in our array just for consistency. <em>Remember this name</em>, you'll be using it a lot in the future.</p>
<p>For more details, check out the <a href="https://api.drupal.org/api/views/views.api.php/function/hook_views_plugins/7">API documentation for hook_views_plugins()</a>.</p>
<div class="u-layout-container rich-text__code">
<div class="rich-text__code__inner">
<div class="code">
<pre>
<code>
<span class="code__comment">/**
* Implementation of hook_views_plugins().
*/</span>
<span class="code__function"><span class="code__keyword">function</span> <span class="code__title">flickr_group_photos_views_plugins</span><span class="code__params">()</span> </span>{
<span class="code__variable">$plugin</span> = <span class="code__keyword">array</span>();
<span class="code__variable">$plugin</span>[<span class="code__string">'query'</span>][<span class="code__string">'flickr_group_photos_plugin_query'</span>] = <span class="code__keyword">array</span>(
<span class="code__string">'title'</span> =&gt; t(<span class="code__string">'Flickr Groups Query'</span>),
<span class="code__string">'help'</span> =&gt; t(<span class="code__string">'Flickr Groups query object.'</span>),
<span class="code__string">'handler'</span> =&gt; <span class="code__string">'flickr_group_photos_plugin_query'</span>,
);
<span class="code__keyword">return</span> <span class="code__variable">$plugin</span>;
}
</code>
</pre>
</div>
</div>
</div>
<!-- MOAR STUFF WAS HERE -->
</div>
</div>
</div>
</div>
<!-- MOAR STUFF WAS HERE -->
</article>
<article class="layout-article__article" >
<div class="layout-article__article-hero" >
<div class="article-hero" >
<div class="cover-image cover-image--with-gradient" >
<span ></span>
<div class="cover-image__content" >
<div class="u-layout-container" >
<div class="article-hero__content u-layout-content-grid" >
<span ></span>
<div class="article-hero__meta" >
<span class="article-hero__author" ><span >by</span> <span ><a class="link" href="/who-we-are/greg-dunlap">Greg Dunlap</a></span></span><span class="article-hero__date" >September 4, 2013</span>
</div>
<h1 class="article-hero__title" >Building Views Query Plugins, Part 2</h1>
</div>
</div><span ></span>
</div>
</div>
</div>
</div>
<div class="layout-article__article-content" id="content">
<div class="layout-article__article-content-lead" >
<div class="rich-text" >
<div class="rich-text__wrapper">
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>Welcome to the second installment of our three part series on writing Views query plugins! In part one, we talked about the kind of thought and design work that needs to be done before coding the plugin begins. In this part, we'll start coding our plugin and end up with a basic functioning example.</p>
</div>
</div>
</div>
</div>
</div>
<div class="layout-article__series u-layout-container" >
<div class="u-layout-content-grid" >
<div class="series-list" >
<div class="series-list__title" >
<span >Series</span> <a class="link" href="/articles/building-views-query-plugins-series">Building Views Query Plugins</a>
</div>
<ol class="series-list__items" >
<li >
<div class="series-list__inner" >
<div class="series-list__link" >
<a class="link" href="/articles/building-views-query-plugins-series/building-views-query-plugins">Building Views Query Plugins</a>
</div>
<div class="series-list__meta" >
<span >by Greg Dunlap</span> <span >on</span> <span >August 29, 2013</span>
</div>
</div>
</li>
<li >
<div class="series-list__inner" >
<div class="series-list__link" >
<a class="link is-active" href="/articles/building-views-query-plugins-series/building-views-query-plugins-part-2">Building Views Query Plugins, Part 2</a>
</div>
<div class="series-list__meta" >
<span >by Greg Dunlap</span> <span >on</span> <span >September 4, 2013</span>
</div>
</div>
</li>
</ol>
</div>
</div>
</div>
<div class="layout-article__article-content-body" >
<div class="rich-text" >
<div class="rich-text__wrapper">
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>While writing this article, I realized that creating a functional remote data integration for Views involves not only the query plugin, but also field plugins to expose that data to Views, and potentially filter or argument plugins to limit result sets. That's a lot of code to write, so lets get to it!</p>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<h2>Getting Started</h2>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>There's a joke about writing Views plugins - 10% of the time is spent copying and pasting code, 10% is spent changing class names and array keys, and 80% is spent finding the typo. While probably not strictly true, it does highlight the fact that when you're writing a Views plugin, naming is everything and a single typo in a class name can cause endless grief. In fact, I've actually moved away from a copy/paste paradigm for these plugins, instead building up all the structures by hand with the help of some snippets in my editor. It forces you to actually think through all the keys involved, and vastly reduces the time spent finding all the keys to replace, and the debugging time spent when you miss one somewhere.</p>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>There are a lot of steps here, and keep in mind that you will need to do them all in order to begin to actually use your plugin or see any results. This is one of the reasons that writing a plugin can be frustrating - you have to write a ton of very interdependent code before you can even start testing it.</p>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<h3>Step 1: Implement hook_views_api()</h3>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>All that we are doing here is declaring what version of Views we are coding to. Note that this is the only code that is going in our .module file, everything else is loaded on-demand through includes. This is what my hook implementation looks like and yours will be exactly the same, except of course using your own module's name instead of flickr_group_photos.</p>
</div>
</div>
<div class="u-layout-container rich-text__code">
<div class="rich-text__code__inner">
<div class="code">
<pre>
<code>
<span class="code__comment">/**
* Implementation of hook_views_api().
*/</span>
<span class="code__function"><span class="code__keyword">function</span> <span class="code__title">flickr_group_photos_views_api</span><span class="code__params">()</span> </span>{
<span class="code__keyword">return</span> <span class="code__keyword">array</span>(
<span class="code__string">'api'</span> =&gt; <span class="code__number">3.0</span>
);
}
</code>
</pre>
</div>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<h3>Step 2: Create a views.inc file</h3>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>Once hook_views_api() is implemented, Views will automatically look for a file named [module].views.inc in your module's home directory. Plugins, handlers, and other information are exposed through hooks implemented in this file.</p>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<h3>Step 3: Implement hook_views_plugins()</h3>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>The first thing we need to do is describe our plugin to views. This is done by implementing hook_views_plugin() and returning an array of the format $array[plugin_type][plugin_name]. The 'title' and 'help' keys pretty self-explanatory, and will be used in the Views UI and the plugin settings forms. However the 'handler' deserves some close attention. This is the name of the class that you will eventually create to manage queries to your remote service. It should be descriptive, and it should contain the name of the implementing module. We have chosen 'flickr_group_photos_plugin_query' here, and also used this as the plugin name in our array just for consistency. <em>Remember this name</em>, you'll be using it a lot in the future.</p>
</div>
</div>
<div class="u-layout-container">
<div class="u-layout-content-grid">
<p>For more details, check out the <a href="https://api.drupal.org/api/views/views.api.php/function/hook_views_plugins/7">API documentation for hook_views_plugins()</a>.</p>
</div>
</div>
<div class="u-layout-container rich-text__code">
<div class="rich-text__code__inner">
<div class="code">
<pre>
<code>
<span class="code__comment">/**
* Implementation of hook_views_plugins().
*/</span>
<span class="code__function"><span class="code__keyword">function</span> <span class="code__title">flickr_group_photos_views_plugins</span><span class="code__params">()</span> </span>{
<span class="code__variable">$plugin</span> = <span class="code__keyword">array</span>();
<span class="code__variable">$plugin</span>[<span class="code__string">'query'</span>][<span class="code__string">'flickr_group_photos_plugin_query'</span>] = <span class="code__keyword">array</span>(
<span class="code__string">'title'</span> =&gt; t(<span class="code__string">'Flickr Groups Query'</span>),
<span class="code__string">'help'</span> =&gt; t(<span class="code__string">'Flickr Groups query object.'</span>),
<span class="code__string">'handler'</span> =&gt; <span class="code__string">'flickr_group_photos_plugin_query'</span>,
);
<span class="code__keyword">return</span> <span class="code__variable">$plugin</span>;
}
</code>
</pre>
</div>
</div>
</div>
<!-- MOAR STUFF WAS HERE -->
</div>
</div>
</div>
</div>
<!-- MOAR STUFF WAS HERE -->
</article>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment