Ctools access plugin creation for Panels


Some time ago we've learned how to develop ctools content type for Panels module. Now it’s time for the next plugin type for Ctools, namely - access plugin. Plugins of this type are some kind of rules depending on which Panels module decide whether to show or not show pane (the least structure unit of panel), to choose one or another version of panel to be displayed.

For example, lets make up the following task: we have a standard panel user_view, which overrides the standard user page display on Drupal.

We have the user A, who is watching the user B profile. If the user A has been registered on the site before the user B, he will see the certain set of fields, and if not - the other one. The task is somehow far from reality, but it is ok for the example.

Firstly, just like during work with Сtools content type, for the web developer it is necessary to call hook_ctools_plugin_directory() to indicate that we have ctools plugins of specific type in our module:

 * Implements hook_ctools_plugin_directory().
function access_example_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'ctools' && !empty($plugin_type)) {
   return "plugins/{$plugin_type}";

Then in module folder we need to create "plugins" folder and "access" folder inside of “plugins” folder. Create plugin file with the name "" inside of "access" folder. Write the access rule by array in this file:

 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
$plugin = array(
  // Plugin user-friendly name.
  'title' => t('Eldership rule'),
  // Plugin description.
  'description' => t('Controls access depends on eldership'),
  // Without required context plugin will now be shown in Panels UI.
  'required context' => array(new ctools_context_required(t('User'), 'user')),
  // Function which will allow or restrict access.
  'callback' => 'access_example_who_elder_access',
  // Plugin settings form.
  'settings form' => 'access_example_who_elder_access_settings_form',
  // Provides a summary descriptions depends on settings selected.
  'summary' => 'access_example_who_elder_access_summary',

Wouldn't you agree that comments to code are enough and no detailed description is required?

Three functions to implement are left:

The first one (the key 'settings form' in plugin array) describes the form of plugin settings. Here it is important that the elements of form (which are access settings as well in this case) are set in "settings" container. Otherwise, the entered data wouldn't be saved. In our case the setting form will contain a single checkbox:

 * Settings form for our access plugin.
function access_example_who_elder_access_settings_form(&$form, &$form_state, $conf) {
  $form['settings']['eldership'] = array(
    '#type' => 'checkbox',
    '#title' => t('Eldership'),
    '#description' => t('Will provide access if current user has been registered before user from context'),
    '#default_value' => !empty($conf['eldership']) ? TRUE : FALSE,
  return $form;

The form is going to be like that:

The second function (the key "summary" in plugin array) isn't obligatory while creating plugin, but it can improve usability as it lets to understand the current state of access rules settings without its opening.

 * Provide a summary description based on selected settings.
function access_example_who_elder_access_summary($conf, $context) {
  return !empty($conf['eldership']) ?
  t('Will grant access if current user has been registered earlier then context user') :
  t('Will grant access if current user has been registered later then context user');

Here you can see the result of implementation of the second function:

And the most important plugin function (the key "callback" in plugins array) is to control the access. If it returns TRUE, the access is permitted, if FALSE - not.

 * Check for access.
function access_example_who_elder_access($conf, $context) {
  global $user;
  // There should always be a context at this point, but this
  // is safe.
  if (empty($context[0]) || empty($context[0]->data)) {
    return FALSE;
  // We should ignore this access rule in case user is viewing his own profile.
  if ($user->uid == $context[0]->data->uid) {
    return TRUE;
  if ($user->created < $context[0]->data->created) {
    return TRUE;
  return FALSE;

Then it is necessary to clear cache and the newly created plugin will be available both in choosing rules of variant in panels and access rules to panes.

In additions to this blog we’ve added an archive with the module. Feel free to download it and to use as an example!

6 votes, Rating: 3.8

Read also


Drupal has transaction support starting from its 7th version. We will help you to learn how to use this functionality properly to achieve the desired result and not to get stumped


Apps is a module that can be looked at as a subsequent step in the evolution of...


The look of the login/registration form can now be changed using administration tool. This is possible with our Customize login form module.


In this article we will speak about Drupal core installation as a submodule. We will not dwell upon the very concept of a submodule here for long, nor try to consider its dis/advantages. What we...


At times, content importing appears to be the task which is far from trivial. Writing the import assignment out "from scratch" when aimed at covering each and every instance can't be practical,...

Need a quote? Let's discuss the project

Are you looking for someone to help you with your Drupal Web Development needs? Let’s get in touch and discuss the requirements of your project. We would love to hear from you.

Join the people who have already subscribed!

Want to be aware of important and interesting things happening? We will inform you about new blog posts on Drupal development, design, QA testing and more, as well news about Drupal events.

No charge. Unsubscribe anytime