Sie sind auf Seite 1von 6

Building custom content panes (aka ctools content types) in

panels 3, and Drupal 7


Often on Drupal sites you need the ability to create re-usable panel panes for use on the site. Each panel pane
would need custom configuration, and could even be context aware (aware of were they are placed on the site).
This is where ctools content types comes in. Ctools content types are one type of plugin that the ctools module
provides. Out of the box, the ctools module provides a few content types to support core modules. These can be
found in the git repository: http://drupalcode.org/project/ctools.git/tree/refs/heads/7.x-1.x:/plugins/content_types

Advantages of ctools content types versus blocks


You do not need administer blocks permission (which is very risky for content authors to have)
Tight integration with panels and other panelizer. Using panelizer affords you the option of not giving away the
'administer panels' permission
Custom configuration edit forms to allow the panes to be re-usable and to make sense for your content authors
Developers can abstract away any complexity in code, leaving the content authors with only the job of adding
the pane and configuring it
Unfortunately there is not a lot of documentation around content types, so I will go through a simple example with
you.

Example implementation of ctools content type plugin


In this example I will go through creating a custom twitter timeline widget that can be configured to pull through a
selected user's tweets, and with an option for limiting the number displayed.

Step 1: Create a new custom m odule w ith this in the .m odule file:
/**
* Implements hook_ctools_plugin_directory().
*/
function examplemodule_ctools_plugin_directory($owner, $plugin_type) {
5.
if ($owner == 'ctools' && $plugin_type == 'content_types') {
return 'plugins/' . $plugin_type;
}
}
Where the name of my custom module is 'examplemodule'.
This lets ctools know that any file in the folder 'plugins/content_types/' should be parsed for content type plugins.
This also keeps your code really nice.

Step 2: Create the include file for the plugin


mkdir -p plugins/content_types
cd plugins/content_types
vim twitter_timeline.inc
Notice the directory structure matches what was declared in the .module file.

Step 3: Declare the plugin to ctools


$plugin = array(
'single' => TRUE,
'title' => t('Twitter timeline'),
'description' => t('Shows a twitter timeline with basic configuration
options.'),
5.
'category' => t('Social media'),

1 of 6

'edit form' => 'examplemodule_twitter_timeline_edit_form',


'render callback' => 'examplemodule_twitter_timeline_render',
'admin info' => 'examplemodule_twitter_timeline_admin_info',
'defaults' => array(
'username' => 'wiifm',
'tweets_to_show' => 5,
)

10.

);
This piece of code lets ctools know what functions to call, what argument defaults there are and so fourth. It should
be largely self explanatory. It also means that your pane will show up in panels now, as we can see from this
picture:

Step 4: Im plem enting adm in_info


Admin information is an optional function to implement that helps describe the pane when it is included on a
panel. I would recomment always implementing it so your content authors can always see at a glance what
configuration a particular pane has.
/**
* 'admin info' callback for panel pane.
*/
function examplemodule_twitter_timeline_admin_info($subtype, $conf, $contexts) {
5.
if (!empty($conf)) {
$block = new stdClass;
$block->title = $conf['override_title'] ? $conf['override_title_text'] : '';
$block->content = t('Showing @tweets_to_show tweets from
<em>@@username</em>.', array(
'@tweets_to_show' => $conf['tweets_to_show'],
10.
'@username' => $conf['username'],
));
return $block;
}
}
This is what the pane will look like after being configured

2 of 6

Step 5: Im plem enting the edit form


The heart of ctools content types is the ability to create simple configuration forms for your content authors so they
can easily create and edit panes. Edit forms use standard form API, so they are really easy to make
/**
* 'Edit form' callback for the content type.
*/
function examplemodule_twitter_timeline_edit_form($form, &$form_state) {
5.
$conf = $form_state['conf'];
$form['username'] = array(
'#title' => t('Twitter username'),
'#description' => t('The username of the twitter account in which to pull the
tweets from.'),
10.
'#type' => 'textfield',
'#default_value' => $conf['username'],
'#required' => TRUE,
);
$form['tweets_to_show'] = array(
'#title' => t('Number of tweets to show'),
'#description' => t('Used to control the number of tweets shown on the page
initially. Defaults to 5.'),
'#type' => 'select',
'#options' => drupal_map_assoc(range(3, 12)),
20.
'#default_value' => $conf['tweets_to_show'],
'#required' => TRUE,
);
15.

return $form;
25. }
In order to save the configuration back to the $conf storage for the pane, you will also need a submit handler
/**
* The submit form stores the data in $conf.
*/
function examplemodule_twitter_timeline_edit_form_submit($form, &$form_state) {
5.
foreach (array_keys($form_state['plugin']['defaults']) as $key) {
if (isset($form_state['values'][$key])) {
$form_state['conf'][$key] = $form_state['values'][$key];
}
}
10. }
There you have it, now you can configure the pane username, and the amount of tweets to show, all of which have
sane defaults and helpful descriptions for your content authors. This is what this step looks like:

3 of 6

Step 6: Im plem eting the render callback


This is the guts of the pane, and is responsible for producing markup to be rendered on the page. I have taken a
simplitest approach to this and have not used a theme function (and template), in reality I would encourage this as
well.
/**
* Run-time rendering of the body of the block (content type)
* See ctools_plugin_examples for more advanced info
*/
5. function examplemodule_twitter_timeline_render($subtype, $conf, $panel_args,
$context = NULL) {
$block = new stdClass();

10.

// initial content is blank


$block->title = '';
$block->content = '';
// Include twitter javascript - by linking to the external file.
drupal_add_js('//widgets.twimg.com/j/2/widget.js', 'external');

15.

20.

25.

30.

35.

// Add in the content


$block->content .= '
<script type="text/javascript">
var t = new TWTR.Widget({
version: 2,
type: "profile",
rpp: ' . check_plain($conf['tweets_to_show']) . ',
interval: 30000,
width: "300",
height: "300",
theme: {
shell: {
background: "#ededed",
color: "#6a6a6a"
},
tweets: {
background: "#fafafa",
color: "#6a6a6a",
links: "#6a6a6a"
}
},

4 of 6

40.

features: {
avatars: false,
hashtags: true,
scrollbar: false,
loop: true,
live: true,
behavior: "default"
}
});

45.
t.render().setUser("' . check_plain($conf['username']) . '").start();
</script>';
return $block;
50. }
Here is a sample panel page, with the twitter timelien pane on the right hand side

(http://www.pixelite.co.nz/sites/default/files/ctools-content-type-page-1.png)

And as you can imagine, it is relatively easy to add more panes onto the panel, here is another on the same page

5 of 6

(http://www.pixelite.co.nz/sites/default/files/ctools-content-type-page-2.png)

Full module download


I thought this post might be a bit code heavy, so I decided to include the full source of the module (http://dl.dropbox.com
/u/759954/pixelite/examplemodule.tar.gz) in case you want to download and install it yourself. Feel free to rename it, extend it,
do what you want with it.

Final thoughts
In this tutorial you have seen how easy it is to make a fully custom ctools content type plugin, from scratch. And
hopefully begin to see how this is more powerful then traditional blocks.
What are your experiences with ctools content types, and helpful advice for others? Did this tutorial help you at all?
Let me know in the comments.

Source
Ctools (http://drupal.org/project/ctools)

6 of 6

Das könnte Ihnen auch gefallen