Explaining Panels: An Overview for Drupal Developers
An overview of Drupal’s Panels module, submodules and supporting projects for developers.
In my time as a Drupal developer I've had plenty of long—and sometimes heated—conversations about Panels module. Is it good? Is it too complex? Does it make a site faster or slower? Those are all fine questions to debate; after first agreeing what is Panels?
First, when people talk about "Panels" there are numerous submodules and supporting projects they might be referring to as well. To understand where the lines are drawn between the modules I like to look at which existing Drupal concepts each module augments.
Panels module is a User Interface on top of
I suspect the common introduction to Panels is something like:
It's very easy to get overwhelmed by the number of options, buttons and links. So let's start simpler: a two column layout.
The code needed to declare that this two column layout exists at all is really small. Browse around the directory declaring it. There is not much there. An info array tells us most importantly that we have left and right regions.
'regions' => array(
'left' => t('Left side'),
'right' => t('Right side')
And there's a template file that prints the left and right regions.
<div class="panel-display panel-2col clearfix" if="" print="">>
<div class="panel-panel panel-col-first">
<div class="inside"><?php print $content['left']; ??></div>
<div class="panel-panel panel-col-last">
<div class="inside"><?php print $content['right']; ??></div>
The simplicity of this layout plugin (aside from its love for divs and css classes) makes it easy to forget that it is an abstraction layer on top of the
theme(). When most Drupalers think about the theme system, they think about the complexity.
Not many people in the world completely understand this diagram. Source:http://john.albin.net/drupal/arrays-of-doom
At the heart of this complexity, is the simple idea that you use
hook_theme() to tell Drupal that there's a type of thing that you would like to print in the future (like a two column layout). And that thing will require some variables (like ‘left' and ‘right'). Then at any time
theme() can be asked to print a two column layout and all that it needs is to be told are the values of ‘left' and ‘right'.
So how do we figure out what is actually supposed to go in ‘left' and ‘right'? Panels answers that question in a way that is fundamentally different from nearly all Drupal Core usages of
theme(). Core's node module uses
hook_theme() to say "Hey, in the future I'm going to ask to you print a ‘node' and I'll give you is a variable called ‘node'". And what it really means is "Oh, yeah, and I'm going to need a ton of preprocessing to derive some variables that can actually be printed in a template." When that Panels layout plugin says "I really only need ‘left' and ‘right'", it can do so because Panels has a separate subsystem for building up those variables.
If you wanted Core to print a node into two columns then you would likely rely on preprocessing and template overrides to figure out what goes where inside
theme(‘node'). Panels can take a node and follow instructions for splitting it into ‘left' and ‘right' before calling
This somewhat academic distinction opens up a different mental model for developers. Core encourages you to think "I'm rendering a node and I'll alter and override what that means once I start doing it." Panels encourages you to think "I know I want a two column layout and here is the configuration to split up this node accordingly." In an upcoming blog post I will explain why I prefer the second way of thinking.
Page Manager is a UI on top of
The response you get when visiting a URL on a Drupal site is determined largely by
hook_menu(). When you go to the user register page you see a registration form because the user module told
hook_menu() that a registration form belonged there. Other stuff may appear in Blocks in sidebars, footer and headers that are outside the knowledge of
hook_menu() primarily controls the main response that shows up in the "content" region of
If you're on a music website that has a Taxonomy term of "Jazz" you might see a listing of every node on the site tagged in Jazz. That's what taxonomy module tells
hook_menu() to put in the response for a taxonomy term page. On the other hand, if I were running a music website I would probably want my page for Jazz to be a little more customized than a simple listing of everything on the site tagged in Jazz. Let's step up the complexity just a little and imagine that the term pages for music genres should separately group musical artists, albums and songs.
Here the distinction between Panels and Page Manager becomes cloudy. Page Manager tells Drupal "I know taxonomy module told you how term pages look, but I am overriding that. Use this Panels configuration instead." Page Manager changes the way Drupal responds to existing paths as well as telling Drupal about new ones.
Panels is not even necessary to use Page Manager. Out of the box, Page Manager gives you the option to override existing URL paths just to change the HTTP response code (for that rare case where you want
node/%node to respond with a 403 for anonymous users but don't want to use the node access system). There are even other modules like Contextual Adminstration https://www.drupal.org/project/context_admin which use Page Manager to add more administrative options.
To go over that Jazz use case one more time, Page Manager:
- Overrides the normal ‘list all nodes' behavior declared by Taxonomy module.
- Replaces it with a package of Panels configuration which
- Declares the layout it wants
- Contains instructions for populating the regions of that layout based on the given "context" (the taxonomy term "Jazz")
Panels Everywhere is a UI alternative to page.tpl.php and Blocks UI
I just mentioned above that Page Manager is the way to control the the "content" region inside
page.tpl.php. Panels Everywhere is meant to entirely replace your typical page.tpl.php customizations and the Block configurations that feed that file.
The Core block system encourages a "global" mindset.
This block will show up on every page except those the pages whose URL paths match a certain pattern.
Blocks can also be restricted by user role.
This model implicitly asks you to think "all of my Blocks are going to show up all of the time except for when I tell them not to show up." You can simultaneously think in the inverse of "this Block will never show up except for this one page." That model can put too much in the site builder's head at once; especially when there is another way to change what happens at this global, Block level. With Core's tools you can always override page.tpl.php with something like page--front.tpl.php. That template can change the overall markup of the front page as well as change what regions will actually print their Blocks. Now you have another independent paradigm to keep in mind when asking yourself "should I expect this block to print?"
Panels Everywhere allows for those two concepts to be united. Decide on your layout first and then pull in the contents of the layout regions. Core will load Blocks even if an override of
page.tpl.php has nowhere to print them.
With Panels Everywhere, just like Core, you will have to figure out if a given element should be controlled by main page response (
hook_menu()/Page Manager) or if the element is a more global decoration (Blocks/Panels Everywhere). An advantage of the Panels Everywhere / Page Manager combo is that the same workflows and concepts apply in both places.
Mini Panels is a UI on top of individual Blocks
If Panels Everywhere is a way to replace Core's mechanism for organizing and displaying existing Blocks, Mini Panels is a way to add more individual Blocks. If you are writing a new Block with Core you will need a few pieces. You will need a machine name like "online" for the user module's "Who's online" block that lists currently logged in users, and you might need a configuration form for something like the number of users to show.
And you will need to write a function to actually render the HTML.
Mini Panels allows you to accomplish those same concepts with less new code or no code at all. Mini Panels is perhaps the purest implementation of Panels in that it contains just the base concepts of Panels. You pick a layout plugin which is how the Mini Panel will actually render.
You configure the Panes that go in that layout.
And, if necessary, you provide a "Context" like a node that can inform those Panes.
Once built, those Mini Panels can be placed with the Core Block system. They can be placed inside of any other layer of Panels: Page Manager, Panels Everywhere, Panelizer, and other Mini Panels. There is even a module to allow Mini Panels to be used as a field formatter for Entity Reference fields and a Row Plugin for Views results.
Their flexibility makes Mini Panels the utility module of the Panels suite. Often when working with more hand-written code it is common to hear one developer say to another, "take that section of code and refactor it out into its own function/class." That refactoring provides reusability, encapsulation and readability. Refactoring a Panels configuration often results in making more Mini Panels to get all of those same benefits.
Panelizer is a (replacement) UI on top of View Modes
Panelizer became famous/infamous in the Drupal community for the way it allows editors to make per-node overrides to Page Manager variants (which again almost always contain Panels configurations). Forget about that part for a moment.
Panelizer has expanded its scope and is now best understood as a UI on top of View Modes. When you enable Panelizer it will give you a giant grid of checkboxes.
Drupal is big on giant grids of checkboxes. Check some of those boxes and now the teaser view mode for a node type is controlled by Panels. You can now write a custom layout plugin specifically for the design component that you want to use with article teasers. The Panels UI is used to place fields in the regions of your newly defined layout.
If you Panelize an article teaser view mode and you use Page Manager plus Panels to control the article listing URL and Panels Everywhere to control the global level then you'll have three layers of Panels. Yes, you can do that.
Of course Panelizer still does have that per-node override functionality. For any view mode (or the Page Manager level) on any node (and other entity types too!) you can make a one-off Panels configuration that will live in your database. Allowing per-node configuration is the part that makes Panelizer controversial. I'll save my opinion on the pros and cons of this usage for another blog post. When evaluating Panelizer, be sure to separate that question from the simpler question of whether you want one Panels configuration (which you can featurize) to control the rendering of an article teaser. In this sense, Panelizer replaces the work you might otherwise do in
node--[node-type]--[view-mode].tpl.php or on this configuration screen from Core.
Bringing it all together
Building a site with Drupal often gets compared to assembling a Lego kit. We take prefabricated pieces and assemble them to a completed work. That task is a lot easier to do when the boundaries of each piece are understood by the builders. By choosing modules from the Panels suite to be the mechanism of rendering more and more of our pieces, Palantiri (the plural form of Palantir) are able to more quickly understand how the page is constructed. The often difficult task of learning to use one module in the Panels suite makes the others far easier to understand.
In my next blog post I will highlight how we use Panels in conjunction with the static prototypes produced by our design team.
Missed our webinar on Workbench for Drupal 8?