Sunday, February 5, 2017

Ctools: custom access plugin

Last time we've learned how to create custom ctools content type plugin. In that post we've already created a module example_module where we defined the plugin. This time we will learn how to create custom ctools access plugin. This type of ctools plugins can be used as a selection rule for a panel variant or as a visibility rule for a panel pane. Please, read previous post before continue reading this. There is described how to create a module and integrate it with ctools.

Let's say we have a node/%node panel page where are placed "Powered by Drupal" and "Node being viewed" panes.

Node view panel page with "Powered by Drupal" and "Node being viewed" panes

And we want first panel pane be shown only if node title equals some specific string. For example "Test article". Well, for this case we have to create an access plugin and apply it to the panel pane. Let's start.

For now if you remember we have an example_module with next structure:
example_module
  |__ plugins
  |  |__ content_types
  |     |__ example_module.example_content_type_plugin.inc
  |__ example_module.info
  |__ example_module.module
1. Create file example_module/plugins/access/example_module.example_access_plugin.inc:
<?php

/**
 * @file
 * File with access plugin definition.
 */

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = [
  // Plugin title.
  'title' => t('Example access rule'),
  // Plugin description.
  'description' => t('Example access rule'),
  // Access rule callback. This function has to return
  // TRUE of FALSE.
  'callback' => 'example_access_plugin',
  // A required context for this pane. If there is no required
  // context on a panel page than you will not be able to apply
  // this access rule to a pane or page variant. In this example
  // we need a 'Node' context.
  'required context' => new ctools_context_required(t('Node'), 'node'),
  // Settings form constructor callback. If you need custom submit/validate
  // callback you can define it by 'settings form submit' and
  // 'settings form validate' properties.
  'settings form' => 'example_access_plugin_settings_form',
  // Default values for edit form inputs.
  'default' => [
    'example_option' => 'example_value',
  ],
  // Summary callback. Returns plugin summary text which is visible
  // in drop-down setting menu of a pane.
  'summary' => 'example_access_plugin_summary',
];

/**
 * Settings form a pane.
 */
function example_access_plugin_settings_form(array $form, array $form_state, $conf) {
  // Please note that all custom form elements
  // should be placed in 'settings' array.
  $form['settings']['example_option'] = [
    '#type' => 'textfield',
    '#title' => t('Example text option'),
    '#default_value' => $conf['example_option'],
    '#required' => TRUE,
  ];

  return $form;
}

/**
 * Access rule callback.
 */
function example_access_plugin($conf, $context) {
  $access = FALSE;

  // Variable $context contains a context grabbed by a panel page.
  // In this case it contains a node object in a 'data' property.
  if (!empty($context->data)) {
    $node_from_context = $context->data;

    // Access will be granted only if node title equals a string
    // set up in settings form.
    $access = $node_from_context->title == $conf['example_option'];
  }

  return $access;
}

/**
 * Summary callback.
 */
function example_access_plugin_summary($conf, $context) {
  return t('Example access plugin');
}
Now our module structure looks like:
example_module
  |__ plugins
  |  |__ content_types
  |  |  |__ example_module.example_content_type_plugin.inc
  |  |__ access
  |     |__ example_module.example_access_plugin.inc
  |__ example_module.info
  |__ example_module.module
2. Clear cache. Apply newly created access rule for the 'Node being viewed' pane in node view panel page:

Set up visibility rule for a pane

Select 'Example access rule'

Set up string to match with a node title

It's time to test our access plugin. Create a node with title "Test" and look at it's page. There will be no "Powered by Drupal" widget because node title doesn't equal "Test article":

Node view page without "Powered by Drupal" widget

And now edit node and change title to "Test article". See what will happen:

Node view page with "Powered by Drupal" widget

Access plugin works correctly.

P.S.
As you could notice there is a little difference between content_type and access plugin definition:

  • 'edit form' VS 'settings form' properties.
  • 'defaults' VS 'default' properties.
  • you have to define custom inputs for access plugin settings form inside 'settings' array. At the same time there is no so strict rule for defining settings inputs for content type plugin.
  • in a form callback for content type plugins configuration is available in $form_state variable, but for access plugins it isn't there. It available in an extra variable $conf.


The above is true for:

  • Ctools: 7.x-1.12
  • Panels: 7.x-3.8

Key notes:

No comments:

Post a Comment