Panel layout basics to free you from Core's block
Like everything in Drupal, there is a slight learning curve when you make the leap to using Panels for your Drupal sitebuilding. This article aims to give you a brief and broad introduction to theming practices used when using Panels and its popular helper modules as your main site-building tools.
In the beginning, there were blocks. Blocks and theme regions were the preferred way to lay out a Drupal site. Then, to offer more power and exportable block placement, the Context module became a popular choice. This was helped by the popularity of the Omega base theme and its dependence on the Context module.
However, now a combination of Panels, Page Manager, Panelizer, and Fieldable Panel Panes are becomming the new standard for placing content around your site. Distributions like Panopoly and Panels Everywhere even go as far as to replace Drupal 7's core block module with this suite of modules.
Much of the theming work that was involved in creating a Drupal site has moved from being primarily located in the Drupal theme itself to being located in custom modules and more compatimentalized blocks of CSS. This can be a challenge to manage if you are used to working just with the theme layer, so let's take a look at what's involved.
Why use panels?
Panels lets you create layouts which have regions where you can add almost any piece of Drupal content based on advanced contexts.
Drupal's native block system limits what you can do with content and only lets you use paths, content types and user roles to tell content where it should display (unless you start digging into PHP code).
Another drawback to Drupal's native block system is that it tends to encourage you to use the theme's code to contextually choose which layouts you want to use in different parts of your site. PHP template files with complicated names (e.g. node--article--foo.tpl.php) are needed to contextually change which layouts get used. While Panels itself doesn't solve this problem, a cTools module often used in conjunction with Panels called Page Manager does.
Panel content, contexts and styles
Panels allows you to add different pieces of content via panes. Panes are similar to blocks in that you can drag and drop them from one panel region to another. However with Panels you are not limited to just content defined as a block. The Panels UI gives you access to almost all content defined in Drupal by default.
Panel contexts allow you to manage complex display rules, keeping these rules out of your theme layer.
When you theme a pane, it is important it looks good in any region you think the client might use it. Both regions and panes have a styles button in the Panel content UI. Clicking this button will allow you to add custom styles to your pane. With styles you can change the markup and classes applied to your plane.
Creating Panel Layouts
A panel layout gets its start in an .inc file in either your module or theme. The .inc file specifies regions and a .tpl file that maps out where you want your regions to show this. This works very much like a Drupal theme's .info file and page.tpl.php file in the way it specifies and places regions. In fact, distributions like Panels Everywhere use panel layouts to replace page.tpl. Once you build your layout (more below), you can use different layouts in different parts of your site. With the Panelizer module you can give your clients the option to choose different layouts for each new page they add.
If you want panels to recognize your layouts and styles you need to tell your theme or your Drupal module about them (they can go in either). I prefer to put my layouts and styles in a seperate module so they are more reusable/pluggable later, however there are some benefits to adding styles and layouts to your theme, such as being able to more easily reuse/integrate SASS variables and mixins into your layouts and styles.
Declare Layouts/Styles in a module.
Declaring your layout (or style) is pretty simple. We're going to create a layout called 'my layout'. They are declared in your custom module as ctools plugins, so follow a standard convention for declaration.
function yourmodule_ctools_plugin_directory($owner, $plugin_type) {
// Create a 'plugins' folder in your module then put .inc files in there.
if ($owner == 'panels' && $plugin_type == 'layouts') {
return "plugins/$plugin_type";
}
if ($owner == 'panels' && $plugin_type == 'styles') {
return "plugins/$plugin_type";
}
}
You should then create a directory for your plugin under module_name/plugins/layouts/my_layout.
Declare Layouts/Styles in theme.
If you want to skip the whole custom module thing and do it right in your theme, then in your theme.info file add the following lines:
; Panels layouts. You can place multiple layouts under the "layouts" folder.
plugins[panels][layouts] = layouts
; Panels Styles. You can place multiple styles under the "styles" folder.
plugins[panels][styles] = styles
Then create a folder for your layout in mytheme/layouts/my_layout
Then you need to add your layout definition. This is the metadata about your layout that panels needs in order to load it on the settings page.
Lets call this my_layout.inc.
<?php
$plugin = array(
'title' => t('Content with Sidebar'),
'category' => t('Layout Category'),
'icon' => 'my_layout.png',
'theme' => 'my_layout', // this matches up with your tpl file
'css' => 'my_layout.css',
'regions' => array(
'feature' => t('Feature'),
'content' => t('Content'),
'sidebar' => t('Sidebar'),
),
);
Then create your actual layout template (e.g. my-layout.tpl.php) as you would normally do with a Drupal template tpl.php file.
Note: The underscore in plugin definition is converted to a dash in the template file name (as per Drupal conventions).
You can then print your regions out in a .tpl file using whatever markup you would like. You can even use Zengrids or Singularity if you have regions that need to be laid out in a grid.
In my_template.tpl.php:
<div class="feature">
<?php print $content['feature']; ?>
</div>
<!-- Add your wrapper divs here -->
<?php print $content['content']; ?>
<?php print $content['sidebar']; ?>
That's it! Now your layout will appear in the list of options when chosing a Panel's layout.