Skip to Content
RSSGrab the RSS feed! ->

How to create a panels style plugin

Creating panels styles can be very powerful. You can define certain styles for your client to choose from, so they can choose what type of display the panel pane will be like. This way you keep the workflow clean, your code under revision control, your themer gets to keep his sanity, and your concious stays clear.

This article assumes you know about running panels, and more or less what the nomenclature is. You should know also that panels now uses ctools, which is is primarily a set of APIs and tools to improve the developer experience.

So, what we'll be doing here is actually creating a ctools plugin, to implement a new panels style. Sorry if I'm confusing you already, don't worry, it's actually quite straight forward, we want to be able to do this:

... and then this:

OK, now to the meat of it. We'll call our module ctoolsplugins.

1. Create a new module, and tell ctools about our plugins

What you need is very basic, an info file and a module file. So far, nothing new.

1.1 Declare our dependencies

So we obviously need ctools module on our site, and well, the plugin wouldn't make much sense without panels and page_manager, so:

; $Id:
name = Ctools Plugins
description = Our custom ctools plugins
core = 6.x
dependencies[] = ctools
dependencies[] = panels
dependencies[] = page_manager
package = Chaos tool suite

1.2 Implement hook_ctools_plugin_directory to tell ctools about our plugins

In our module file, of course, we'll implement this function, that will check if ctools if looking for style plugins, and lets if so, it will let it know where ours are:

  * Implementation of hook_ctools_plugin_directory().
function ctoolsplugins_ctools_plugin_directory($module, $plugin) {
  if (
$module == 'panels' && $plugin == 'styles') {
'plugins/' . $plugin;

2. Prepare our file structure for the plugins, and create our plugin file.

This image is pretty self explanatory:

We'll call our plugin 'collapsible', so we create inside ctoolsplugins/plugins/styles/ a file called

3. Implement our style plugin in

3.1 Define your style goals and necessities.

OK, Here you should think about what you are going to do with the plugin.

  • Is it just for markup?
  • Will you be offering different options?
  • Will you be implementing javascript on it?

In our case, we'll take the opportunity, to teach you another thing that ctools has, the collapsible div utility. So our style will basically convert any panels pane, into a collapsible panels pane:

And because we are friendly developers (or like not to be ever bothered after developing it), we'll give the user a chance to configure if they want the pane to start opened or closed. That means an extra settings form, so we can have this:

3.2 Imlement hook_panels_style_info

The naming is very important here, it should be modulename_stylename_panels_style. You basically return an array, defining your style:

* @file
* Definition of the 'collapsible' panel style.

* Implementation of hook_panels_style_info().
function ctoolsplugins_collapsible_panels_styles() {
  return array(
'title' => t('Collapsible div'),
'description' => t('Display the pane in a collapsible div.'),
'render pane' => 'ctoolsplugins_collapsible_style_render_pane',
'pane settings form' => 'ctoolsplugins_collapsible_style_settings_form',

'title' and 'description' are pretty self explanatory.
'render pane' specifies the theme function we'll be providing for rendering the pane. Watch the naming convention.
'pane settings form' specifies the callback function which provides the extra settings form, that we'll be using for our start up options. Watch the naming convention.

3.3 Define the settings form callback.

The name of the function will be what you specified in 'pane settings form' earlier. Just provide a new array inside $form, for each configuration you want the user to specify. See the FAPI documentation for reference.

* Settings form callback.
function ctoolsplugins_collapsible_style_settings_form($style_settings) {
$form['collapsed'] = array(
'#type' => 'select',
'#title' => t('Startup behaviour'),
'#options' => array(
0 => t('Start opened'),
1 => t('Start collapsed'),
'#default_value' => (isset($style_settings['collapsed'])) ? $style_settings['collapsed'] : 'opened',
'#description' => t('Choose whether you want the pane to start collapsed or opened'),


This is pretty straight forward, in our case we provide two options, one to start opened and one to start collapsed. If collapsed is chosen, the value will be 1.

3.4 Define the render callback function.

The name of the function will be what you previously specified in 'render pane'. This is just a theme function, and where you have the chance of altering what will be shown to the user when viewing the page.

* Render callback.
* @ingroup themeable
function theme_ctoolsplugins_collapsible_style_render_pane($content, $pane, $display) {
$style_settings = $pane->style['settings']; // good idea for readability of code if you have a ton of settings
$start_settings = $style_settings['collapsed']; // we can do this be cause the only values possible are 0 or 1

$pane_content = $content->content;

  if (
$content->title) {
$pane_title = '<h2 class="pane-title">'. $content->title .'</h2>';

// theme('ctools_collapsible', $handle, $content, $collapsed);
$result = theme('ctools_collapsible', $pane_title, $pane_content, $start_settings);

// if we don't have a pane title, we just print out the content as normaly, since there's no handle
else {
$result = $pane_content;


Important to note here, is that our user's specified settings are inside $pane->style['settings']. In this example we check if there's a title available, and if so we implement the ctools_collapsible theme function to get our collapsible panes. Other wise we don't have a handle, and we just return the content as normal.

And that is it. Hope you found the article useful, and if you'd like me to write up some more articles about writing plugins for panels/ctools, drop a comment with your question/suggestion!

UPDATE:You can also provide a style plugin in your theme, as shown in this fine tutorial.

ctoolsplugins.tar.gz1.3 KB

16 responses to this article.


Funciona de maravilla!

Funciona de maravilla! Gracias por hacer este post tan claro, brindando el paso a una goleada para los nuevitos! Peter de b&b Venecia


Thank you for writing this,

Thank you for writing this, it's saved me a ton of time in figuring this out myself. One minor correction, in step 1.2, I think you're if statement shoudl be the following, to prevent loading the plugin for some other module who might also use plugins names 'styles'

if ($plugin == 'styles') {

should be

if ('panels' == $module && 'styles' == $plugin) {


Excelent point Oscar, I have

Excelent point Oscar, I have updated the code in the post, thanks for pointing this out, and glad to hear it saved you time!


One thing I learned, is for

One thing I learned, is for your style to be available as a region style, you need to define a 'render panel' function, for it to be available as a style for a single pane, defined a 'render pane' function.


I just tried this and now I

I just tried this and now I can't access the panels dashboard. I get the WSOD.


The WSOD is most likely an

The WSOD is most likely an indication that php is runing out of memory on your server. This has nothing to do with what is explained here, but rather a problem with your server's configuration.
Check out this link about what could be causing this: , but I find that most of the cases this is fixed by increasing memory_limit in your server's php.ini file.


Tried the above module in D7,

Tried the above module in D7, but no dice. It shows up in the styles menu, but the field never gets collapsed upon viewing it.


This post ranks high in

This post ranks high in Google for Drupal Panels Tabs, but it applies to D6. The following patch at d.o will get you tabs in Panels for Drupal 7 - vertical tabs by default, but also horizontal tabs will be enabled as an option if you also have the field group module enabled.

Tabs style plugin: Vertical Tabs in core! (for Drupal 7)

Field Group Module:


My partner and I absolutely

My partner and I absolutely love your blog
and find nearly all of your post's to be what precisely I'm looking for.
Do you offer guest writers to write content for you?

I wouldn't mind publishing a post or elaborating on a lot of
the subjects you write about here. Again, awesome website!


Luxury villas in the Greek

Luxury villas in the Greek Isles really are
a dream holiday pick, not only in summer time, but also in spring as well as fall when the sun isn't so strong,
but the azure Aegean and Ionian Seas still sparkle against sandy shorelines and
reflect off pure white houses. To many, Andalucia is interchangeable with
the Costa del Sol, the aptly called sunshine shore per year with
increased hours of sun than just about any other vacation area.
Lodging merely including GBP36fee.


Your post is good. I like

Your post is good. I like style of your writing. So I got pleasure reading it. Thanks a lot!


Thatt iss really interesting,

Thatt iss really interesting, You're a very skilled blogger.
I've joined ylur feed and stay upp for searching for extra of your great post.
Also, I've shared your web site in my social networks


Its like you read my mind!

Its like you read my mind! You seem to know so much about this,
like you wrote the book in it or something.
I think that you can do with a few pics to drive the message home a little bit, but instead of that, this is
wonderful blog. A fantastic read. I'll certainly be


If we can look at the things

If we can look at the things in life we regret having done, maybe we can understand that other
people are entitled to make mistakes, even when those mistakes
hurt us. It is through the facial appearance, the quality of the clothings worn, and the luminosity and
colours of the aura of the soul that the degree of evolution of
the soul may be determined. The acai berries must be
loaded into baskets and onto boats soon after picking.
It will also take away the redness and inflammation like Lavender
and Chamomile. Older people need half-dozen to fifteen micrograms of B12
each day ( the RDA is just a couple of.


Water: A dish of water should

Water: A dish of water should always be available for both drinking
and soaking (for smaller snakes). They are soft and
spring Mattress , Palm fiber flexibility Bed Cushion and furniture as software.

Food and Drug Administration (FDA) and the United States Department of
Agriculture (USDA) have the mandate to monitor peanuts and field corn for aflatoxin content and
have the power to mandate a recall on any food or feed that has
a high level of aflatoxins.


That is very kind of you to

That is very kind of you to write this share for us, thanks a lot

Post new comment

The content of this field is kept private and will not be shown publicly.
By submitting this form, you accept the Mollom privacy policy.