I'm perfectly fine with creating Chaos Tools content types for use in Panels, but I've always used single => TRUE.

I've looked through the docs, but still can't quite seem to grok how to utilise subtypes. None of the examples shipped with Chaos Tools seem to use them (they also all implement single => TRUE, and a quick grep of the Chaos Tools directory only shows the Custom Content type using subtypes, and it only appears to use it for including the export functionality (unless I'm reading it wrong - which is likely).


1 Answer 1


It's a good question, and some further information can be found in the ctools help file context-content.html

The CTools pluggable content system provides various pieces of content as discrete bits of data that can be added to other applications, such as Panels or Dashboard via the UI. Whatever the content is added to stores the configuration for that individual piece of content, and provides this to the content.

Each content type plugin will be contained in a .inc file, with subsidiary files, if necessary, in or near the same directory. Each content type consists of some information and one or more subtypes, which all use the same renderer. Subtypes are considered to be instances of the type. For example, the 'views' content type would have each view in the system as a subtype. Many content types will have exactly one subtype.

Also, in ctools_content_get_subtypes

Get all of the individual subtypes provided by a given content type. This would be all of the blocks for the block type, or all of the views for the view type.

So in a sense, the subtypes are individual instances of that type, such as individual Views or Blocks, or custom content instances, that use the same rendering functions as the parent content type.

For example, you can see in ctools_content_process

// If a subtype plugin exists, try to use it. Otherwise assume single.
if (function_exists($function_base . 'content_types')) {
  $plugin['content types'] = $function_base . 'content_types';

In the example of the block content type, this function returns the content types, or sub types for that plugin.

 * Return all block content types available.
 * Modules wanting to make special adjustments the way that CTools handles their blocks
 * can implement an extension to the hook_block() family, where the function name is
 * of the form "$module . '_ctools_block_info'".
function ctools_block_content_type_content_types() {
  $types = array();
  foreach (module_implements('block_info') as $module) {
    $module_blocks = module_invoke($module, 'block_info');
    if ($module_blocks) {
      foreach ($module_blocks as $delta => $block) {
        $info = _ctools_block_content_type_content_type($module, $delta, $block);
        // this check means modules can remove their blocks; particularly useful
        // if they offer the block some other way (like we do for views)
        if ($info) {
          $types["$module-$delta"] = $info;
  return $types;

Lastly one more example for good measure from the views_content content type plugin

 * Return all content types available.
function views_content_views_content_type_content_types($plugin) {
  $types = array();
  // It can be fairly intensive to calculate this, so let's cache this in the
  // cache_views table. The nice thing there is that if views ever change, that
  // table will always be cleared. Except for the occasional default view, so
  // we must use the Views caching functions in order to respect Views caching
  // settings.
  $data = views_cache_get('views_content_all', TRUE);
  if (!empty($data->data)) {
    $types = $data->data;

  if (empty($types)) {
    $views = views_get_all_views();

    foreach ($views as $view) {
      if (empty($view->disabled)) {
        $types[$view->name] = _views_content_views_content_type($view);

    views_cache_set('views_content_all', $types, TRUE);

  return $types;

In this case _views_content_views_content_type returns

function _views_content_views_content_type($view) {
  $title = $view->get_human_name();

  $icon = 'icon_views_page_legacy.png';

  return array(
    'view' => $view->name, 
    'title' => $title, 
    'icon' => $icon, 
    'description' => filter_xss_admin($view->description), 
    'category' => t('Views'),

  • 1
    Interesting...I wonder then if a subtype's relationship to a ctools plugin is analogous with a core field instance's relationship to a field definition - perhaps that drove the design decision
    – Clive
    Jul 4, 2013 at 8:37
  • Thanks for the answer - but as I mentioned, I've already looked through the docs, and they don't actually answer the question :( I should probably have changed the title somewhat - I understand what they are, but not how to implement them myself :)
    – Chapabu
    Jul 4, 2013 at 8:39
  • @David - but please have an upvote anyway :-)
    – Chapabu
    Jul 4, 2013 at 8:39
  • @Chapabu thanks :-) , I've included some additional information on how the block subtypes are returned with ctools_block_content_type_content_types perhaps the example helps to clarify a little more there. Jul 4, 2013 at 8:57
  • 1
    Thanks David - I've only just opened the bounty, so I'll let it run for a few more days. But it looks promising for you ;-)
    – Chapabu
    Jul 4, 2013 at 9:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.