Skip to Navigation

Extending Panels in Drupal

Printer-friendly version

Panels is one of those Drupal modules that engenders a range of feelings around here.  Some people love it -- interface configurable layout! -- and some hate it -- difficult to manage .5em gutters.  But it, and Chaos Tools which it is based on, provide a great deal of useful functionality.  The problem is there is very little documentation on how to extend it beyond what's distributed in code.  The basics of extending Panels/CTools is pretty easy, you just implement the hook_ctools_plugin_directory to tell it where to look for your files, e.g.

function MODULE_ctools_plugin_directory($module, $plugin)
{
	if ($module == 'ctools' && !empty($plugin))
	{
		return 'plugins/' . $plugin;
	}
}

This presupposes you have a directory under your module named 'plugins.'  Inside that directory you can have various other directories corresponding to additional extensions, namely 'access,' 'arguments,' 'content_types,' 'contexts' and 'relationships.'  As you might expect 'access' contains access extensions, 'arguments' contains arguments, 'contexts' contain CTools contexts, 'relationships' contains relationships and 'content_types' contains outputs that can be placed into panes. They all follow the same sort of pattern, there is an initial hook that is composed something like MODULE_CONTEXT_ctools_contexts (e.g. for a module called foo which exposes a context called Bar it would be foo_bar_ctools_contexts) which returns an array with various configuration options. 

Content types tend to be very helpful because you can write custom outputs and they can be knowledgable about CTools contexts (nodes, taxonomy terms, users, etc.) and you can be quaranteed that those contexts will be passed in and not have to worry about testing for them.  To create a custom content_type you would have your directory set up like the following:

module
     / plugins
          / content_types
               / foo
                    / bar.inc

And in bar.inc you'd have the following:

/**
 * Callback function to supply a list of content types.
 */
function module_bar_ctools_content_types() {
	return array(
		'single' => TRUE,
		'title' => t('Bar output'),
		'icon' => 'icon_node.png',
		'description' => t('The bar of the foo.'),
		'required context' => new ctools_context_required(t('Node'), 'node'),
		'category' => t('Node'),
	);
}

/**
 * Render the custom content type.
 */
function module_bar_content_type_render($subtype, $conf, $panel_args, $context) {
	// If we don't have a context return no value
	if (empty($context) || empty($context->data))
	{
		return;
	}

	// Build the content type block.
	$block = new stdClass();
	$block->module  = 'bar';
	$block->title   = t('My title');
	$block->content = 'I can put anything here';
	$block->delta   = $node->nid;

	return $block;
}

/**
 * Returns an edit form for custom type settings.
 */
function module_bar_content_type_edit_form(&$form, &$form_state) {
	// provide a blank form so we have a place to have context setting.
}

/**
 * Returns the administrative title for a type.
 */
function module_bar_content_type_admin_title($subtype, $conf, $context) {
	return t('"@s" bar', array('@s' => $context->identifier));
}

This is a pretty simple example, but it has most of the required hooks to make a new content_type.  The first hook,  module_bar_ctools_content_types, returns the content_type definition; basically the title and description, whether it requires a context to be present and of what type (the example above requires that the CTools page has a node context either from an argument or fixed context) and which tab it should appear in; in this case the 'Node' tab.

If you require a context you need a configuration screen in order to set which context(s) to pass to the content_type.  The module_bar_content_type_edit_form hook tells CTools that we need a configuration form which will contain settings for the contexts to send to the content_type.  Since we aren't using anything other than the context no other form elements are required.  If you wanted other configuration this function would return a Drupal form array to be rendered.  If there were additional configuration you would also implement the _validate and _submit hooks, so you'd have module_bar_content_type_edit_form_validate and module_bar_content_type_edit_form_submit following the normal Drupal form submission rules.  The data for the content_type configuration is stored in $form_state['conf'] which is stored by CTools and put into the $conf variable for the _render hook.

That brings us to module_bar_content_type_render.  The variables passed in are pretty straightforward, $conf is any configuration exposed by module_bar_content_type_edit_form, $panel_args is an array of arguments parsed by the Page, and $context is the CTools context that is passed to the content_type (i.e. the node, user, term, etc.).  From there the return looks like an object form of the typicaly block output. 

 

Comments

Columns to rows...

I'm devising a panel that uses the 3 column 33/34/33 stacked layout and was trying to add multiple pictures in a row instead of a column. Using the bottom region for this, I am only able to get dispay in a column, but was wondering how can I change it to a row? Do I need to update the theme or can this be configured? I've checked the Contact Center but still can't find the answer I'm looking for.

Thanks!

  Just fill out the Your

  Just fill out the Your name: field, no?

so ...

how do I not post as Anonymous?
-Oscar

Panels is awesome

Especially if you marry it with Grid960 or Blueprint SS Frameworks.
I was under the impression that in the info hook, if you're providing layouts, or styles for Panels, you're test for the directory should be:
 

function MODULE_ctools_plugin_directory {
if ($module == 'panels' && !empty($plugin))
{
return 'plugins/' . $plugin;
}
}

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

Mollom CAPTCHA (play audio CAPTCHA)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.