Hiding empty Panels panes
James Williams
If you're using Panels to display dynamic content, you might want to dynamically check whether to display the panes based on what will be shown. For example, if there is no content to show in a certain pane, you probably don't want the pane to show at all.
You may especially want to do this if your theme will do anything ugly, or just unnecessarily conspicuous, with any HTML that is wrapping empty content.
By default, the Panels / Page Manager UI doesn't provide any kind of 'hide panel if contents are empty' functionality. So here's an example of how you could do it.
Our basic idea is to use PHP to check if the content is empty. To start, click the configure icon (the little cog) in the top-right of your pane in the Panel content admin screen, and select to Add new rule under the Visibility rules part of the menu that appears. (see screenshot)
On the first screen that then appears in the popup, choose 'PHP Code', then on the following screen give your rule a useful name, such as 'Only show if the contents are not empty'. Now for the important bit.
We need to enter some PHP code that will check to see whether the pane's content will be empty or not. Now this will depend on what the pane is actually rendering. Unfortunately, we can't get at the pane content itself yet, since visibility rules are checked before rendering happens*. Essentially, we need to get hold of the content that the pane would get hold of, and check that the output will not be empty.
So for example, if our pane would render a view, we need to load and execute it; or if our pane might render a field from a node, we need to load the node (and potentially render it too, though in this example, to save time, we'll assume that's not necessary). We would then check our content isn't empty, and return TRUE
, otherwise FALSE
.
If the page is loading its data from an argument or a (panels/CTools) context, we can use the $contexts
variable. A node object would be at $contexts['argument_nid_1']->data
. Here is an example that checks that a node's field is not empty:
/* In the panel I took this example from, $contexts['argument_nid_1'] is the
node object, taken from the arguments/context of the panel. We then get at
this to check if the field that our panel content type would show is empty or
not. You can debug this nicely using the Devel module with a dsm($contexts) here. */
// Checks for content in the field field_myfield.
if (isset($contexts['argument_nid_1']->data->field_myfield)) {
$field = $contexts['argument_nid_1']->data->field_myfield;
if (is_null($field)) {
return FALSE;
}
if (is_array($field)) {
foreach ($field as $key => $val) {
if (is_array($val)) {
$field[$key] = array_filter($val);
}
}
$field = array_filter($field);
return count($field);
}
if (is_string($field) && trim($field) == '') {
return FALSE;
}
if ($field) {
return TRUE;
}
return FALSE;
}
Note that we mustn't include the <?php ?>
tags in the visibility rule input box. The visibility rule can be saved once the PHP is entered. Then update and save your panel page.
Of course, we could check for other things to determine whether our pane shows. Maybe hide the pane if the field it displays is a certain value, or check other for complex access.
*Potentially, if we're using a custom Panels content type, we might be able to call a function within that content type that does a proper check on whatever will be rendered. I have come across a MODULENAME_CONTENTTYPENAME_visibility_check()
function in some Panels content types that might do this for us. Drop a comment below if you get this working, or find a better way. Another alternative method could be to simply check the pane's output in a preprocess function. This would then guarantee us what would actually get rendered (since it happens after rendering), but doing the check first will of course avoid unnecessary and expensive rendering.