How to Write a Custom Ctools Access Plugin Based on the Value of a Boolean Field
I had the delightful task at work of determining the visibility of a view (in a node variant) based on the value of a boolean field. But it got better! Said boolean field was not on the node that was being viewed, it was on a node that referenced the node being viewed. But wait! It gets better! The referenced node was an organic group, and those references work differently then a usual entity reference! Confused yet? The actual purpose of the exercise was to allow a content manager to control the widget without having to touch the actual panel variant. This prevents confusion on their part, and also the possibility of the page layout being accidentally destroyed. If they want the widget on their page, they check a box.If they don't want it, leave the box unchecked. Simple enough.
First things first: you have to let ctools know that there is a plugin to use. In your custom module (or in my case, in the relevant feature) .module, you need something like this:
1
2
3
4
5
6
7
8
9
10
/**
* Implements hook_ctools_plugin_directory().
*
* It simply tells panels where to look for the .inc file that
* defines various args, contexts and content_types.
*/
function my_feature_ctools_plugin_directory($module, $plugin) {
if ($module == 'ctools' && !empty($plugin)) {
return "plugins/$plugin"; }
}
Then in your feature (or custom module), create the directory, so you have a my_feature/plugins/access folder structure.
In the access folder, create a new .inc file. For the purposes of this exercise, the field we are using to determine visibility will be called field_widget, so I would call my file field_widget.inc.
You have to start by defining the plugin, so:
1
2
3
4
5
6
7
8
9
10
11
12
/**
* Plugins are described by creating a $plugin array which will
* be used by the system that includes the file.
*/
$plugin = array(
'title' => t('Node: Widget'),
'description' => t('Only displays this pane if the Widget field on the related Home Page for this Organic Group is set to On.'),
'callback' => 'my_feature_field_widget_ctools_access_check',
'default' => array('field_widget' => 1),
'summary' => 'my_feature_field_widget_ctools_access_summary',
'required context' => new ctools_context_required(t('Node'), 'node'),
);
Now write the callback:
1
2
3
4
5
6
7
8
9
10
11
/**
* Custom callback defined by 'callback' in the $plugin array.
*
* Check for access.
*/
function my_feature_field_widget_ctools_access_check($conf, $context) {
// If for some unknown reason that $context isn't set, return false.
if (empty($context) || empty($context->data)) {
return FALSE;
}
Because the field is *not* on the node that is currently being viewed, we have to identify the correct home page node.1
2
3
4
5
6
// Identify the home page node for the current organic group.
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'division_home')
->fieldCondition('og_division_home_division_ref', 'target_id', $context->data->nid);
$result = $query->execute();
Now we have to load the node, to access the field_widget value.
1
2
$home_page_nid = current($result['node'])->nid;
$home_page_node = node_load($home_page_nid);
Here is where we check the value of field_widget. Being a boolean, if the value is 0, that means the boolean is not checked, and we want to hide the pane.
1
2
3
4
5
6
7
// If the home page widget field is not checked, hide the pane.
if (!$home_page_node->field_widget[LANGUAGE_NONE][0]['value']) {
}
//Otherwise, show the pane.
return TRUE;
}
Here is the whole kit and caboodle:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* Plugins are described by creating a $plugin array which will
* be used by the system that includes the file.
*/
$plugin = array(
'title' => t('Node: Widget'),
'description' => t('Only displays this pane if the Widget field on
the related Home Page for this Organic Group is set to On.'),
'callback' => 'my_feature_field_widget_ctools_access_check',
'default' => array('field_widget' => 1),
'summary' => 'my_feature_field_widget_ctools_access_summary',
'required context' => new ctools_context_required(t('Node'), 'node'),
);
/**
* Custom callback defined by 'callback' in the $plugin array.
*
* Check for access.
*/
function my_feature_field_widget_ctools_access_check($conf, $context) {
// If for some unknown reason that $context isn't set, return false.
if (empty($context) || empty($context->data)) {
return FALSE;
}
// Identify the home page node for the current organic group.
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'division_home')
->fieldCondition('og_division_home_division_ref', 'target_id', $context->data->nid);
$result = $query->execute();
$home_page_nid = current($result['node'])->nid;
$home_page_node = node_load($home_page_nid);
// If the home page widget field is not checked, hide the pane.
if (!$home_page_node->field_widget[LANGUAGE_NONE][0]['value']) {
}
// Otherwise, show the pane.
return TRUE;
}
And there you have it. :)
Tags: Drupal PlanetDrupal