Sunday, February 12, 2017

Ctools: custom context plugin

In previous post we created an access ctools plugin which can be used as a selection or visibility rule in panels. It's time to learn how to create another important custom plugin - a context. It provides additional information for a panel page. For example if you've put a node context to the page you will be able to use node properties as substitutions for a page title. Moreover you will be able to put node fields as panes to a page. By default ctools module provides useful contexts (node, user, taxonomy_term, entity etc) but you can define your own. Please, read first post of "Ctools custom plugins" series before continue reading this. There we've created a module integrated with ctools.

In this tutorial we will create a context plugin which will provide information about a server from superglobal php variable $_SERVER. As you remember for now we have an example_module with next file structure:
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
To create a context plugin we need to create contexts directory and put there a file with plugin definition. Let's start:

1. Create example_module/plugins/contexts/example_module.example_context_plugin.inc file:
<?php

/**
 * @file
 *
 * Plugin to provide a server_info context.
 */

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = [
  // Plugin title.
  'title' => t('Server info'),
  // Plugin description.
  'description' => t('Available information about a server.'),
  // A function that will return context.
  'context' => 'example_context_plugin',
  // Settings form callback.
  'edit form' => 'example_context_plugin_settings_form',
  // Default values for settings form.
  'defaults' => [
    'decode_request_uri' => FALSE,
  ],
  // Context keyword to use for
  // substitution in titles.
  'keyword' => 'server_info',
  // Context machine name.
  'context name' => 'server_info',
  // A function returns a list of
  // available values from a context.
  // By the way it can be just an array.
  'convert list' => 'example_context_plugin_get_convert_list',
  // A function gets data from a given
  // context and returns values defined
  // in 'convert list' property.
  'convert' => 'example_context_plugin_convert',
];

/**
 * Context callback.
 */
function example_context_plugin($empty, $data = NULL, $conf = FALSE) {
  // Create context object.
  $context = new ctools_context('server_info');

  // This property should contain file name where
  // plugin definition is placed.
  $context->plugin = 'example_module.example_context_plugin';

  if (empty($empty)) {
    // Define context data.
    $context->data = $_SERVER;

    // Decode property if selected.
    // Just for demonstration how to use
    // plugin settings.
    if (!empty($conf) && !empty($data['decode_request_uri'])) {
      $context->data['REQUEST_URI'] = urldecode($context->data['REQUEST_URI']);
    }
  }

  return $context;
}

/**
 * Returns available properties list.
 */
function example_context_plugin_get_convert_list() {
  $list = [];

  // Get all $_SERVER properties and return them.
  foreach ($_SERVER as $property_name => $property_value) {
    $list[$property_name] = t('$_SERVER["!name"]', [
      '!name' => $property_name,
    ]);
  }

  return $list;
}

/**
 * Returns property value by property type.
 */
function example_context_plugin_convert($context, $type) {
  // Return $_SERVER property value.
  return $context->data[$type];
}

/**
 * Settings form for server_info context.
 */
function example_context_plugin_settings_form($form, &$form_state) {
  // Demo setting.
  $form['decode_request_uri'] = [
    '#type' => 'checkbox',
    '#title' => t('Decode $_SERVER["REQUEST_URI"] value'),
    '#default_value' => $form_state['conf']['decode_request_uri'],
  ];

  return $form;
}

/**
 * Settings form submit.
 */
function example_context_plugin_settings_form_submit($form, &$form_state) {
  // Save submitted value.
  $form_state['conf']['decode_request_uri'] = $form_state['values']['decode_request_uri'];
}
Updated module structure looks like:
example_module
  |__ plugins
  |  |__ content_types
  |  |  |__ example_module.example_content_type_plugin.inc
  |  |__ access
  |  |  |__ example_module.example_access_plugin.inc
  |  |__ contexts
  |     |__ example_module.example_context_plugin.inc
  |__ example_module.info
  |__ example_module.module
2. Clear cache and set up Server info context for a panel page:

Newly created context

Plugin settings form

Available context properties

Let's test context and set up page title as %server_info:REQUEST_URI. By the way it's a node/%nid page on screeshot so to test it we should open a node view page (but you can set up this context to any panel page you want):

Page title will contain value from $_SERVER['REQUESTED_URI'] variable

Request uri as a page title

The last thing we have to test is an option "Decode $_SERVER["REQUEST_URI"] value". When it's checked uri will be decoded. Check this checkbox and open node view page with a query parameter such as "?test=parameter to decode" and update page. Browser will encode spaces in url and it will look like "?test=string%20to%20decode". But page title will contain original (decoded) value.

The above is true for:

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

5 comments:

  1. how can we use this context as a required in access plugins

    ReplyDelete

  2. Hello i am kavin, its my first occasion to commenting anyplace, when i read this piece of writing i thought i could also create comment due to this good post. facebook login facebook login

    ReplyDelete
  3. after enabling the module does it gets appears in the context list on the panel page?

    ReplyDelete
    Replies
    1. Yes, you will see the new context in a list.

      Delete