Go forth and tabbify with Quicktabs 3.0 for Drupal 7
The Quicktabs module now has a stable release on two Drupal 6 branches (that's right, it never had a stable D6 release until a few weeks ago :-/) and on two D7 branches. The 7.x-3.x branch represents a complete rewrite of the module, providing much greater flexibility in what can be done with it.
Quicktabs 3.0 for Drupal 7 uses ctools for plugin management and provides two types of plugins: renderer and content plugins. The renderer plugins provided with the module are jQuery UI Tabs, jQuery UI Accordion, and classic Quicktabs, which is essentially the original "homegrown" tabs mechanism, including ajax support*. Content plugins are for providing different "things" that can be output as tab content, e.g. blocks, views, nodes, other Quicktabs instances. One new content plugin that's provided is the menu callback plugin, which allows you to specify any Drupal path and have that displayed as the content of a tab.
So an obvious way that developers can extend Quicktabs is to write plugins for it, and I've been pleased to hear of some interesting plugins already in the works. However, there is another important way in which Quicktabs is now far more flexible than it ever was before and that's in the way that you can programmatically build a Quicktabs instance. You could do this to a certain extent in previous versions, but the 7.x-3.x branch allows you to shove basically whatever you want into a Quicktabs instance.
A neat example of this is if your page design calls for having the current node's comments as one of a set of tabs (the other tabs might be views of content related to the node or whatever). So you can implement hook_page_alter(), where you'll get the entire page array, grab the comments out of it, and smoosh them into a Quicktabs instance. Like this:
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #FF8000">/**<br> * Implements hook_page_alter().<br> */<br></span><span style="color: #007700">function </span><span style="color: #0000BB">my_module_page_alter</span><span style="color: #007700">(&</span><span style="color: #0000BB">$data</span><span style="color: #007700">) {<br> if (isset(</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content'</span><span style="color: #007700">][</span><span style="color: #DD0000">'system_main'</span><span style="color: #007700">][</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">])) {<br> </span><span style="color: #0000BB">$nids </span><span style="color: #007700">= </span><span style="color: #0000BB">element_children</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content'</span><span style="color: #007700">][</span><span style="color: #DD0000">'system_main'</span><span style="color: #007700">][</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">]);<br> </span><span style="color: #0000BB">$nid </span><span style="color: #007700">= </span><span style="color: #0000BB">$nids</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">];<br> </span><span style="color: #FF8000">// We'll place the node comments inside a quicktabs block.<br> </span><span style="color: #0000BB">$comments </span><span style="color: #007700">= </span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content'</span><span style="color: #007700">][</span><span style="color: #DD0000">'system_main'</span><span style="color: #007700">][</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">][</span><span style="color: #0000BB">$nid</span><span style="color: #007700">][</span><span style="color: #DD0000">'comments'</span><span style="color: #007700">];<br> unset(</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content'</span><span style="color: #007700">][</span><span style="color: #DD0000">'system_main'</span><span style="color: #007700">][</span><span style="color: #DD0000">'nodes'</span><span style="color: #007700">][</span><span style="color: #0000BB">$nid</span><span style="color: #007700">][</span><span style="color: #DD0000">'comments'</span><span style="color: #007700">]);<br> </span><span style="color: #0000BB">$overrides </span><span style="color: #007700">= array(</span><span style="color: #DD0000">'ajax' </span><span style="color: #007700">=> </span><span style="color: #0000BB">0</span><span style="color: #007700">, </span><span style="color: #DD0000">'style' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'nostyle'</span><span style="color: #007700">); </span><span style="color: #FF8000">// Override some of the settings for the QT instance.<br> </span><span style="color: #0000BB">$custom_tabs </span><span style="color: #007700">= array(<br> array(<br> </span><span style="color: #DD0000">'title' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'Comments'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'contents' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$comments</span><span style="color: #007700">, </span><span style="color: #FF8000">// Custom tabs must have a contents property.<br> </span><span style="color: #DD0000">'weight' </span><span style="color: #007700">=> </span><span style="color: #0000BB">0<br> </span><span style="color: #007700">)<br> );<br> </span><span style="color: #FF8000">// Our 'node_activities' Quicktabs instance has just one tab, we're going to<br> // add a second tab to it, containing the node comments.<br> </span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content'</span><span style="color: #007700">][</span><span style="color: #DD0000">'qt_activities'</span><span style="color: #007700">] = array(<br> </span><span style="color: #DD0000">'content' </span><span style="color: #007700">=> </span><span style="color: #0000BB">quicktabs_build_quicktabs</span><span style="color: #007700">(</span><span style="color: #DD0000">'node_activities'</span><span style="color: #007700">, </span><span style="color: #0000BB">$overrides</span><span style="color: #007700">, </span><span style="color: #0000BB">$custom_tabs</span><span style="color: #007700">),<br> </span><span style="color: #DD0000">'#weight' </span><span style="color: #007700">=> </span><span style="color: #0000BB">99</span><span style="color: #007700">,<br> );<br> }<br>}<br></span><span style="color: #0000BB">?></span></span>
And the result:
The documentation for the quicktabs_build_quicktabs() function explains the parameters it takes:
* @param name. The machine name of the Quicktabs instance to build - if a name
* is passed that does not correspond to an existing instance, then it is taken
* to be a completely custom instance and is built from only the custom tabs
* that are passed in.
*
* @param overrides. Options that will override the options of the Quicktabs
* instance from the database, or if no existing instance is being used, these
* will override the default options. Possible keys are 'style', 'hide_empty_tabs',
* ajax', 'default_tab', 'renderer', 'title'.
*
* @param custom_tabs. An array representing custom tab contents, which will be
* appended to the Quicktabs instance from the database, or if no existing instance
* is being used, the custom tabs will be the entire contents. An example custom_tabs
* array would be array(array('title' => 'custom', 'contents' => array('#markup' =>
* t('Some markup'), 'weight' => 5));
Essentially, you can take advantage of this function to rearrange parts of a render array into tabbed content or create tabbed content from scratch.
As with the 6.x-3.x version, Quicktabs instances are fully exportable as features components. Go forth and tabbify!
*jQuery UI Tabs provides an ajax option but it's actually quite inflexible and I felt it wasn't what we needed so I spent some time trying to make Tabs work with the new Ajax framework in core, i.e. suppressing its ajax behaviour in favour of the more flexible functionality in core's ajax framework. I came up against a bit of a brick wall in that endeavour - see http://drupal.org/node/1108978.