Panels 3: Creating a custom layout in your theme

Last modified: September 14, 2009 - 17:08

A panel layout is a layout that can be used by the Panels module. You can add content to defined content areas within a panel. The Panels module comes with several layouts, but you can also create your own for your own module or theme. Here we will create a layout for a theme.

Before we start, first you have to successfully install Panels 3 (currently 6.x-3.0).

  1. The layouts which come with panels exist in files located at within the Panels module directory at plugins/layouts, for example, /sites/all/modules/panels/plugins/layouts.

    Copy one of the existing layout's folder to your site's theme directory to use as our template or outline which we will then rename, twocol for example. If your theme was named mytheme, the twocol folder would be copied to /sites/all/themes/mytheme/twocol.

    This folder contains four files. These files are:

    • twocol.png, a screenshot of the layout.
    • twocol.css, a stylesheet for the layout.
    • twocol.inc, contains only an implementation of hook_panels_layouts().
    • panels-twocol.tpl.php, the template file for the layout.
  2. We need to rename the files. We will be creating a simple layout with one row and two columns below, called onerowtwocols. Replace all the twocols names in the filenames with onerowtwocols. Don’t forget to also rename the folder to onerowtwocols.
  3. Now, we need to change our theme's info file, which in this example would exist in our root theme folder at /sites/all/themes/mytheme, called mytheme.info. We need to tell Drupal where the folder with the custom panel layouts for this theme will be located, by adding the following line to the bottom of the file:

    plugins[panels][layouts] = onerowtwocols

  4. Now let’s dive into the code of the layout, which is really simple. We will start with the ‘hardest’ file: onerowtwocols.inc. If you have ever used the Forms API (or the Schema API, or the menu system) before, you should recognize the way this file is built up. The file is very self-explanatory, but we will begin at the beginning:
    • The function name should be broken up into several smaller pieces and tied together using underscores like this: themename_layoutname_panels_layouts(). For our purpose this will become: mytheme_onerowtwocols_panels_layouts().
    • The internal name of layout should be $items['onerowtwocols']. If you have a feeling we’re starting to do the same thing over and over, you’re right, basically, we’re replacing every instance of twocols with our new name onerowtwocols.
    • The title will be displayed in Drupal, it is wrapped in the t() function which makes it translatable. We will use 'title' => t('One row, two columns'),.
    • The screenshot of the layout is next, it will be 'icon' => 'onerowtwocols.png',.
    • The theme will be the name of the template file without the .tpl.php extension, like this: 'theme' => 'onerowtwocols',. Starting to get bored yet?
    • The CSS: 'css' => 'onerowtwocols.css',.
    • In the panels array we will define the regions in which content can be placed once our layout is finished, just add a new item for each area, we will end up with this:
      'panels' => array(
      'top' => t('Top'),
      'left' => t('Left side'),
      'right' => t('Right side')
      ),

    This was the hard part, now let’s continue with the easy and fun part!

  5. Edit the screenshot the way you want to best represent your layout, make sure you keep the filesize (in pixels) of the original png file so it will look nice and clean in the Panels user interface.
  6. Now let’s start the actual layout part. Open onerowtwocols.tpl.php and take a moment to see how the two columns layout was set up. The little PHP snippets like print $content['left']; are used to define the area where content can be added. We will partly use the existing HTML and change some of our own. We will start at the outside and work our way in.
    • The outer div will almost stay the same, we will only change one class to our own:
      <div class="panel-display panel-1row2cols clear-block" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
      <!-- Our content goes here -->
      </div>

      The PHP snippet inside the div makes it possible to use CSS from the Panels user interface. We will leave it in, but it is better to only use CSS through a stylesheet to separate style from our PHP.
    • Next we will create two rows:
      <div class="panel-display panel-1row2cols clear-block" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
      <div class="panel-1row2cols-row clear-block"><!-- Our content goes here --></div>
      <div class="panel-1row2cols-row clear-block"><!-- Our content goes here --></div>
      </div>

      Because we will not set a fixed width and height we can give both rows the same class.
    • Now we will create the two columns in the bottom row:
      <div class="panel-display panel-1row2cols clear-block" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
      <div class="panel-1row2cols-row clear-block"><!-- Our content goes here --></div>
      <div class="panel-1row2cols-row clear-block">
      <div class="panel-1row2cols-left"><!-- Our content goes here --></div>
      <div class="panel-1row2cols-right"><!-- Our content goes here --></div>
      </div>
      </div>
    • Finally we will add our areas, using the names we used in the onerowtwocols.inc file:
      <div class="panel-display panel-1row2cols clear-block" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
      <div class="panel-1row2cols-row clear-block"><?php print $content['top']; ?></div>
      <div class="panel-1row2cols-row clear-block">
      <div class="panel-1row2cols-left"><?php print $content['left']; ?></div>
      <div class="panel-1row2cols-right"><?php print $content['right']; ?></div>
      </div>
      </div>
  7. This means there’s only one file left to edit, our css file. We will make the layout fit the area it will be in, so we won’t give any fixed widths:
    • The outer div and the rows will be 100%:
      .panel-1row2cols {
      width: 100%;
      }
      .panel-1row2cols-row{
      width: 100%;
      }
    • Our columns will float to the left and to the right:
      .panel-1row2cols-left {
      float: left;
      }
      .panel-1row2cols-right {
      float: right;
      }
  8. Finally we will have to make our layout ready for use, by clearing the cache so it will actually show up with the other layouts.
  9. Note one more very important thing though: if you have set the administration theme to another theme than the one in which you just created the layout, it will not be usable!
  10. Now go wild, create very complex layouts you can use with your panels!

Some problems here

Funkwarrior - September 1, 2009 - 10:49

After creating a new custom layout, I have this error after choosing it:

warning: include(./sites/all/themes/euroinox/tworowstwocols/tworowstwocols.tpl.php) [function.include]: failed to open stream: No such file or directory in /Users/funkwarrior/Sites/euroinox/includes/theme.inc on line 1020.
warning: include(./sites/all/themes/euroinox/tworowstwocols/tworowstwocols.tpl.php) [function.include]: failed to open stream: No such file or directory in /Users/funkwarrior/Sites/euroinox/includes/theme.inc on line 1020.
warning: include() [function.include]: Failed opening './sites/all/themes/euroinox/tworowstwocols/tworowstwocols.tpl.php' for inclusion (include_path='.:/Applications/MAMP/bin/php5/lib/php') in /Users/funkwarrior/Sites/euroinox/includes/theme.inc on line 1020.

what is happens??

Got it

i-sibbot - September 23, 2009 - 12:00

The file naming convention is wrong in the tut.

Your files should be named like so:

choosentitle.png
choosentitle.css
choosentitle.inc
choosentitle.tpl.php

having "panel-" anywhere in the name tells Drupal its part of the default panels hence the the error in theme.inc

Solution?

rcharamella - September 26, 2009 - 05:07

I'm having the same problem, did you find a solution?

Here's my error message:

    * warning: theme_render_template(./sites/all/themes/rnp/home_layout/home-layout.tpl.php) [function.theme-render-template]: failed to open stream: No such file or directory in d:\inetpub\rnp\beta\includes\theme.inc on line 1020.
    * warning: theme_render_template(./sites/all/themes/rnp/home_layout/home-layout.tpl.php) [function.theme-render-template]: failed to open stream: No such file or directory in d:\inetpub\rnp\beta\includes\theme.inc on line 1020.
    * warning: theme_render_template(./sites/all/themes/rnp/home_layout/home-layout.tpl.php) [function.theme-render-template]: failed to open stream: No such file or directory in d:\inetpub\rnp\beta\includes\theme.inc on line 1020.
    * warning: theme_render_template() [function.include]: Failed opening './sites/all/themes/rnp/home_layout/home-layout.tpl.php' for inclusion (include_path='.;c:\php4\pear') in d:\inetpub\rnp\beta\includes\theme.inc on line 1020.

and here's the code in home_layout.inc:

function rnp_home_layout_panels_layouts() {
  $items['home_layout'] = array(
    'title' => t('Home Layout'),
    'icon' => 'home_layout.png',
    'theme' => 'home_layout',
    'css' => 'home_layout.css',
    'panels' => array(
      'top' => t('Top'),
    ),
  );

  return $items;
}

Any help would be greatly appreciated.

Tried clearing cache

ryivhnn - September 28, 2009 - 07:27

Tried clearing cache (?q=admin/settings/performance) again?

Thank you!

animammal - September 23, 2009 - 11:32

This is probably a stupid question but...

If we are coping a layout folder from panels>plugins>layouts to our theme shouldn't the change in theme.info point to the copied layout instead of the original one or am I missing something?

Also, you suggest a specific name for the new layout "onerowtwocols". Is this name a Drupal/Panels recognized standard or can we make the name something else entirely like earwax... I'm guessing the latter.

Despite two very minor uncertainties, this is an EXCELLENT tutorial for a beginner like me. It gives gives insight to how Drupal and Panels work behind the scenes.

cheers!

Trouble with a custom panels layout and a sub-theme

cmorgan - October 2, 2009 - 16:54

I struggled for a half hour getting this to work with my theme, a sub theme. After noticing the comment about the template php file name and fixing that issue, I tried moving it to the parent theme and the custom layout showed up. So, I can't seem to get the custom layout to work for my sub theme but I'm not sure why not or how to debug the issue. Ideas?

Currently in the same situation

zeropaper - October 13, 2009 - 14:11

I'm currently building a theme based on ninesixty and I'm facing the same problem. I guess will put my layouts within a module to fix that (wich isn't such a big deal).
As a side not, I think I'll publish the module I'm doing, it should also comes with some imagecache presets.

web is my playground

sub-theme problems

testertesters - November 8, 2009 - 13:44

I have the same problem. My custom panels layouts don't show up when added to my sub-theme. Did you ever solve this?

solved

testertesters - November 8, 2009 - 14:06

I managed to figure this out - this post was very useful: http://drupal.org/node/427192#comment-2136602

the key was to prefix my function with my theme name as described in that post

sub-theme and custom layout

testertesters - November 8, 2009 - 21:52

just to elaborate how I got this working:

in my sub-theme folder i have this structure:

/plugins
/plugins/layouts
/plugins/layouts/front
/plugins/layouts/front/front.css
/plugins/layouts/front/front.inc
/plugins/layouts/front/front.png
/plugins/layouts/front/front.tpl.php

/plugins/styles
/plugins/styles/navigation.inc

<?php
/* $Id: front.css $ */

.panel-front {
   
width:980px;
/*  overflow: hidden;  */
}

.
panel-front .two-thirds {
 
float: left;
 
width: 650px;
}

.
panel-front .inside {
 
margin: 0;
 
padding: 0;
}

.
panel-front .three-in-two-thirds {
 
float: left;
 
width: 210px;
}

.
panel-front .one-third {
 
float: left;
 
width: 320px;
}

.
panel-front .floatright {
   
float:right;
}

.
panel-front .leftmargin {
   
margin-left:10px;
}

.
panel-front .panel-separator {
 
margin:0px 0px 0px 0px;
   
padding: 0px 0px 10px 0px;
}
?>

<?php
// $Id: front.inc,v 1.1.2.1 2008/12/16 21:27:58 $

/**
* Implementation of hook_panels_layouts().
*/
function THEMENAME_front_panels_layouts() {
 
$items['front'] = array(
   
'title' => t('front'),
   
'icon' => 'front.png',
   
'theme' => 'front',
   
'css' => 'front.css',
   
'panels' => array(
     
'topleft' => t('Top left'),
     
'bottomleft' => t('Bottom left'),
     
'bottomcenter' => t('Bottom center'),
     
'bottomright' => t('Bottom right'),
     
'right' => t('Right side')
     ),
  );

  return
$items;
}
?>

<div class="panel-display panel-front clear-block" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
  <div class="panel-panel two-thirds">
<div class="panel-panel">
    <div class="inside"><?php print $content['topleft']; ?></div>
</div>
<div class="clear-block"></div>
<div class="panel-panel three-in-two-thirds">
    <div class="inside"><?php print $content['bottomleft']; ?></div>
</div>
<div class="panel-panel three-in-two-thirds leftmargin">
    <div class="inside"><?php print $content['bottomcenter']; ?></div>
</div>
<div class="panel-panel three-in-two-thirds leftmargin">
    <div class="inside"><?php print $content['bottomright']; ?></div>
</div>
  </div>

  <div class="panel-panel one-third floatright">
    <div class="inside"><?php print $content['right']; ?></div>
  </div>
</div>

<?php
// $Id: navigation.inc,v 1.1.2.1 2009/07/15 22:12:19 Exp $

/**
* @file
* Definition of the 'front' panel style.
*/

// ---------------------------------------------------------------------------
// Panels hooks.

/**
* Implementation of hook_panels_style_info().
*/
function THEMENAME_navigation_panels_styles() {
  return array(
   
'title' => t('Small navigation'),
   
'description' => t('Display primary links navigation'),
   
'render pane' => 'navigation_style_render_pane',
  );
}

// ---------------------------------------------------------------------------
// Panels style plugin callbacks.

/**
* Render callback.
*
* @ingroup themeable
*/
function theme_navigation_style_render_pane($content, $pane, $display) {
  return
$content->content;
}
?>

and finally, in my sub-themes info file (THEMENAME.info):
plugins[panels][layouts] = plugins/layouts
plugins[panels][styles] = plugins/styles

For multiple custom layouts I

lelizondob - October 3, 2009 - 08:48

For multiple custom layouts I think the step 3 could be wrong. The author suggests you use in your theme.info file the name of your layout but this won't work for multiple layouts. I needed to have the following structure in my theme's folder in order to make it work:

mycooltheme
mycooltheme/layouts
mycooltheme/layouts/crazylayout1
mycooltheme/layouts/crazylayout2

The author suggest to add:

plugins[panels][layouts] = crazylayout1

Then in my mycooltheme.info all I needed to do was add:

plugins[panels][layouts] = layouts

Since layouts it's the name of the container folder for my custom layouts.

-- Please confirm this to modify the book page.

Luis

Thanks.

omo - November 12, 2009 - 13:13

Thanks. Works.

FYI:

mycooltheme/layouts/crazylayout1
mycooltheme/layouts/crazylayout2

... are subfolders.

This works`

bstoppel - November 16, 2009 - 21:24

I put my custom layouts in a subfolder much like Luis suggests. It works.

Administration theme

testertesters - October 26, 2009 - 19:38

9. Note one more very important thing though: if you have set the administration theme to another theme than the one in which you just created the layout, it will not be usable!

Great to know this — but what do I do then, when I have a different admin theme than my front-end theme?

not seeing this

ultimike - December 1, 2009 - 15:56

I'm not having a problem seeing my custom layouts when using a different theme as my admin theme.

I have a custom theme to which I added a custom panel layout and I'm using Garland as the admin them. When I'm in the Panels admin area, I see my custom layout as expected.

I'm not sure #9 is still an issue - at least not for me.

-mike

----- Check out the Florida Drupal Users Group
----- http://groups.drupal.org/florida

Theme must be enabled

fuerst - November 10, 2009 - 12:29

Besides clearing cache make sure your theme used for the panel created content is marked as enabled at the Themes admin page /admin/build/themes. Drupal has a bug which sometimes disables a Theme (even the default one). CTools/Panels seems to just stop displaying the page in this case resulting in a white page displayed to the user. See also http://drupal.org/node/440206#comment-1836926

Calling main CSS theme

koffer - November 27, 2009 - 06:05

I all ready create this panel theme example, great!

If you want to call the css of main theme, just use:

'css' => '../style.css',

The name of css is the name of theme css.

 
 

Drupal is a registered trademark of Dries Buytaert.