Wednesday, February 15, 2017

Ctools: custom relationships plugin

Relationships plugins are "bridge" between existing context (that is already set up in a panel) and a context which you want to get from existing one. Let's say your panel contains "Node" context and you want to get a node author (user from node:uid property). To do that you can just set up "Node author" relationship in a panel (under a "contexts" tab) and that's all. That's why relationships plugins are so important - they provide easy way for getting context from existing contexts. Please have a look at this post before continue reading - there is described how to create module integrated with ctools API which allows us to define own plugins.

As you remember we've created a custom server_info context plugin that provides information from $_SERVER superglobal php variable. All that you can grab from that context are strings. Ctools comes with a simple context plugin string. It provides three ways of string representation: html_safe, raw and uppercase_words_html_safe. In this tutorial we will create a relationship plugin that will convert a string from server_info to a string context.

Let's add new plugin to our existing example_module which for now 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.example_context_plugin.node_status.inc
  |  |__ arguments
  |     |__ example_module.example_argument_plugin.inc
  |__ example_module.info
  |__ example_module.module
1. Create file example_module/plugins/arguments/example_module.example_argument_plugin.inc:
<?php


/**
 * @file
 *
 * Plugin to provide a string relationship from 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('String from "Server info" context'),
  // Plugin description.
  'description' => t('Adds a string context from existing server_info context.'),
  // Keyword.
  'keyword' => 'string_from_server_info',
  // We want to create string context from server_info context.
  // It means that server_info has to be already set up into
  // a panel page. So server_info context is required for
  // this relationship.
  'required context' => new ctools_context_required(t('Server info'), 'server_info'),
  // Context builder function.
  'context' => 'example_relationship_plugin',
  // Settings form. We will provide a property from
  // server_info context we want to present as string context.
  'edit form' => 'example_relationship_plugin_settings_form',
  // Default values for settings form.
  'defaults' => [
    'server_info_property' => 'HTTP_HOST',
  ],
];

/**
 * Return a new context based on an existing context.
 */
function example_relationship_plugin($context = NULL, $conf) {
  $string_context = NULL;

  // If empty it wants a generic, unfilled context, which is just NULL.
  if (empty($context->data)) {
    $string_context = ctools_context_create_empty('string', NULL);
  }
  else {
    if (!empty($conf['server_info_property'])) {
      // Create the new string context from server_info parent context.
      $string_context = ctools_context_create('string', $context->data[$conf['server_info_property']]);
    }
  }

  return $string_context;
}

/**
 * Settings form for the relationship.
 */
function example_relationship_plugin_settings_form($form, $form_state) {
  $conf = $form_state['conf'];
  $keys = array_keys($_SERVER);

  $form['server_info_property'] = [
    '#required' => TRUE,
    '#type' => 'select',
    '#title' => t('"Server info" property'),
    '#options' => array_combine($keys, $keys),
    '#default_value' => $conf['server_info_property'],
  ];

  return $form;
}

/**
 * Configuration form submit.
 */
function example_relationship_plugin_settings_form_submit($form, &$form_state) {
  foreach ($form_state['plugin']['defaults'] as $key => $default) {
    $form_state['conf'][$key] = $form_state['values'][$key];
  }
}
Module structure:
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.example_context_plugin.node_status.inc
  |  |__ arguments
  |  |  |__ example_module.example_argument_plugin.inc
  |  |__ relationships
  |     |__ example_module.example_relationship_plugin.inc
  |__ example_module.info
  |__ example_module.module
2. Clear cache. After that you will see a new relationship on panel settings page under contexts tab (please note that you need to set up server_info context first before be able to set up a relationship based on server_info):

New relationship is available for this panel

3. Set up newly created relationship:

Choose a value from server_info context you want to represent as a string context

4. At this point you will see additional context on a panel - "String from 'Server info' context".

A string context available from server_info context

5. It means you can use, for example, %string_from_server_info:uppercase_words_html_safe token as a substitution for a page title. Let's try to set up title as "%server_info:HTTP_HOST : %string_from_server_info:uppercase_words_html_safe" and see what will happen:

Set up page title from contexts values

My host is "drpual.loc" so page title looks like "drupal.loc : Drupal.loc" where first part (before ":") is a value grabbed from server_info context and second part is a value from string_from_server_info context in "uppercase_words_html_safe" format.

Page title consists of context and relationship values

The above is true for:

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


No comments:

Post a Comment