Community Documentation

Panels 3: Creating a custom layout in your theme

Last updated January 23, 2013. Created by libeco on June 18, 2009.
Edited by eddib, pfrenssen, betoscopio, Rick Hood. Log in to edit this page.

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.

  1. The layouts which come with panels exist in files located 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/layouts/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, except for panels-twocol.tpl.php, which must be renamed to onerowtwocols.tpl.php (i.e. also remove panels- from the name). 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:

    ; Panels layouts. You can place multiple layouts under the "layouts" folder.
    plugins[panels][layouts] = layouts
  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:
    • [see NOTE A below] 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!

    NOTE A: in later versions you do not need the function, but rather you will find a plugins array (in the .inc file) like this:

    $plugin = array(
      'title' => t('One row two columns'),
      'category' => t('onerowtwocols'),
      'icon' => 'onerowtwocols.png',
      'theme' => 'onerowtwocols',
      'css' => 'onerowtwocols.css',
      'regions' => array(
        'top' => t('Top'),
        'right' => t('Right side'),
        'left' => t('Left side')
      ),
    );

    ...so you just edit that array, more or less using instructions above (it is pretty obvious).
  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. Now go wild, create very complex layouts you can use with your panels! An example of a module implementing extra layouts is the Panels Extra Layouts module

Comments

Thank you!

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

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

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

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

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

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

thanks

your code helped me out

Thanks

Andy

4.1 point

4.1 point is old information. New version of panels don't need function, just edit $plugin array.

custom panels layouts .inc

Thanks for pointing this out, because I am running Panels 6x.3.9 and in my .inc file there is no mention of a function, only the $plugin array. I suppose that step is skipped in my Panels version, correct?

For multiple custom layouts I

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.

Thanks. Works.

FYI:

mycooltheme/layouts/crazylayout1
mycooltheme/layouts/crazylayout2

... are subfolders.

This works`

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

Administration theme

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

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

i see it, but can't use it

it shows up in the node/$id/panel_content page and i can select it, but i can't put content in it. setting the admin theme to the theme i added the layout to is required.

c.hill

Theme must be enabled

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

Lifesaver

Thanks for this comment. This seemed to be my problem as well, the theme was not enabled (but active, because it was the default theme).

Baris Wanschers (@BarisW)
Drupal specialist

Can we change the point 9?

Point 9 is incorrect. Can we remove it please?

Calling main CSS theme

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.

Really thanks!

This small tutorial make my day, really thanks man!

Is cuma cá mhinice a théann tú ar strae; is é is tábhachtaí gurb áil leat do bhealach a aimsiú arís.
--
You HAVE to assume your visitor is a maniac serial killer, out to destroy your application. And you have to prevent it.

the code is not working am geeting the errors

there are no errors but i couldnt find the customized panel among other panels.........

are you sure you did all the

are you sure you did all the steps correctly?

check the hypens (-) and underscores (_) in the file names and in the file names declaration in the php array (custom panel layout name): file names should have hypens, but in the array, you should specify them with underscores (or the opposite? i dont rememer right now)

Is cuma cá mhinice a théann tú ar strae; is é is tábhachtaí gurb áil leat do bhealach a aimsiú arís.
--
You HAVE to assume your visitor is a maniac serial killer, out to destroy your application. And you have to prevent it.

Some observerations from my

Some observerations from my experience using Panels 6.x-3.3:

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().

There are no function at all in the .inc file.

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!

That was not true for me. I have another theme as administration theme and I only needed to clear cache to use my new layout.

Regarding function names in

Regarding function names in theming: in Panels 3.3+ we only have a $plugin array to work with now. It's pretty self-explanatory, but it would be nice to see this guide updated to reflect the changes!

i've faced same problem too

Yeah, in my drupal 6.16 installation with 6.x-3.5 Panels' version, there are no function at all in the .inc file. It would really nice to see the all the Drupal documentation updated to reflect the changes when they happen. If not, that documentation turns it out in a kind of a nightmare becoming much less useful and much more frightening to new people trying to learn Drupal.

How did you create the layout

Can someone help me with this please. Trying to create the layout but the instructions don't match - especially the .inc file instruction. Panels being such prominent module should have better documentation.

Solved

The .inc file instruction don't match for the version 3.5+. There are no functions to change - just change the relevant bits within $plugin array to match your layout name. The folder containing your files must have the same name as your layout but place it in yourtheme/layouts/yourpanellayout - v. important (as I discovered). BTW, I have separate Admin theme to site theme and have no problem.

function name

i'm not sure when this was changed, but in 3.7 there's no function declaration in your_layout.inc. Here's mine so far...untested:
<?php
// $Id: twocol_bricks.inc,v 1.1.2.3 2010/06/22 15:54:25 merlinofchaos Exp $

/**
* @file
* Implementation for the two column bricked layout
*/

// Plugin definition
$plugin = array(
'title' => t('Two column bricks 2'),
'category' => t('Columns: 2'),
'icon' => 'twocol_bricks2.png',
'theme' => 'theme1',
'css' => 'twocol_bricks2.css',
'panels' => array(
'top' => t('Top'),
'left_above' => t('Left above'),
'right_above' => t('Right above'),
'middle' => t('Middle'),
'left_below' => t('Left below'),
'right_below' => t('Right below'),
'bottom' => t('Bottom'),
),
);

The version that was current when this tutorial was written was 3.0. It looked like this:

<?php
// $Id: twocol_bricks.inc,v 1.1.2.1 2008/12/16 21:27:59 merlinofchaos Exp $

/**
* @file twocol_bricks.inc
*
* Implementation for the two column bricked layout
*/

/**
* Implementation of hook_panels_layouts().
*/
function panels_twocol_bricks_panels_layouts() {
$items['twocol_bricks'] = array(
'title' => t('Two column bricks'),
'icon' => 'twocol_bricks.png',
'theme' => 'panels_twocol_bricks',
'css' => 'twocol_bricks.css',
'panels' => array(
'top' => t('Top'),
'left_above' => t('Left above'),
'right_above' => t('Right above'),
'middle' => t('Middle'),
'left_below' => t('Left below'),
'right_below' => t('Right below'),
'bottom' => t('Bottom'),
),
);
return $items;
}

Great tutorial, just needs

Great tutorial, just needs setup of .inc file to be modified as stated above.

Also noticed that if for

Also noticed that if for example your layout is called twocol_650x330 then although the rest of the files (and the "theme" entry in the .inc file) will be twocol_650x330.inc, twocol_650x330.css etc, the .tpl file "must" be named twocol-650x330.tpl.php (with the _ replaced by -), took me a while to figure that out.

Thanks

Thanks!!! ;-)

In drupal 7

The panels array needs to become the regions array

Dress the empty pages of the modules Theme

Hello everyone,
To get a better idea.
Could someone show an example of its theme picture before and after the installation of custom panel?
Is this the solution to dress up the pages of empty modules theme?
I think privatmessag, notification, since usersrelationship tab uprofil Advenced profile of kit.
Thank you in advance for your help

panels custom layouts

Thanks for this. Will definitely look further into this and try it.

Is this technique to overcome the weaknesses of the GUI layout designer custom layout interface?

I have tried the GUI interface and have found that achieving any sort of accuracy very difficult and cumbersome, specifically fine tuning the position and size of individual panes.

thanks for great tutorial

Hi--I'm working in drupal 7 on localhost, not a coder but found the instructions very easy to follow. I'm trying to set up a panel with two right columns. However, I get this error message:
Warning: include(/Users/Sites/acquia-drupal/sites/all/themes/mysite/layouts/threecol_50_25_25_stacked/threecol-50-25-25-stacked.tpl.php) [function.include]: failed to open stream: No such file or directory in theme_render_template() (line 1234 of /Users/Sites/acquia-drupal/includes/theme.inc).

I would sure appreciate any help! Thank you.

Web Building and Design

had this problem too, fixed

had this problem too, fixed by using dashes (-) instead of underscores (_) in .tpl.php file name

bad explication

item four is confusing me... please explain better.

I followed the instructions of this link: http://activelamp.com/blog/advanced-drupal-theming-using-panels-part-1-e...

thks

I cannot make it work, can

I cannot make it work, can somebody please check if I made a mistage somewhere ... I don't get an error message

ls (this is a copy of zen/layouts/one_sidebar_first renamed)
custom-layout-admin.css  custom-layout-admin.tpl.php  custom-layout.css  custom_layout.inc  custom-layout.png  custom-layout.tpl.php

Structure:
sites/all/themes/FirstLayout/layouts/custom_layout

cat custom_layout.inc

<?php
/**
* Implements hook_panels_layouts().
*/
function firstlayout_custom_layout_panels_layouts() {
  $items['custom_layout'] = array(
    'title' => t('Zen Layout: Custom Layout'),
    'icon' => 'custom-layout.png',
    'theme' => 'zen_custom_layout',
    'admin theme' => 'zen_custom_layout_admin',
    'css' => 'custom-layout.css',
    'admin css' => 'custom-layout-admin.css',   
    'panels' => array(
      'content' => t('Content'),
      'sidebar_first' => t('First sidebar'),
    ),
  );

  return $items;
}

tail STARTERKIT.info

  ; Panels 3 layouts
plugins[panels][layouts] = layouts

If I understand correctly the new "custom layout" should be listed when I "change layout" inside the panels module correct?

please help me ... I am lost

How to implement in a module

1. Implement the following hook -

<?php
function MODULENAME_ctools_plugin_directory($module, $plugin) {
  return
'plugins/' . $plugin;
}
?>

You can change the name of the 'plugins' directory, but cannot change the following.

2. Next you create a folder inside the 'plugins' directory and call it 'layouts' <--don't change. Then place your custom layouts in that directory.

3. Your .inc file will look something like this

<?php
$plugin
= array(
   
'title' => t('LAYOUT TITLE'),
   
'icon' => 'ICON.png',
   
'css' => 'CSS_FILE.css',
   
'theme' => 'NAME OF TEMPLATE FILE W/O .tpl.php'
    'panels'
=> array(
     
'top' => t('Top'),
     
'top_left' => t('Top Left Column'),
     
'top_right' => t('Top Right Column'),
     
'middle' => t('Middle'),
     
'bottom' => t('Bottom')
  ),
);
?>

5. Panels will automatically scan your layouts folder for new layouts. DONT FORGET TO CLEAR THE CACHE. Your new layout will appear in the 'Miscellaneous' section when selecting a layout for your panel.

NOTE: If you look in the panels module plugins directory you can see how panels does it.

I've added a custom template per the above instructions, and when I am editing a Page after adding content I am able to see the custom template displayed in the panel Preview. Everything looks as it should. However, as soon as I save the Page, the panel content disappears. It is not visible in Preview or on the site. Any suggestions as to what I'm missing? Thanks.

1. Do you have a .tpl in your

1. Do you have a .tpl in your layout folder?
2. Is it named correctly? (I think there was some weird thing with using - or _ in the name of the tpl)
3. Have you cleared the cache?
4. Are you printing the $content varibale in your page.tpl.php?

Hi pwaterz, thanks for the

Hi pwaterz, thanks for the reply, but solved this by discovering that the name for the layout must be under 32 characters long. So, your folder and file names (.tpl, .css, .inc, etc) must adhere to that limit. Good to know!

Awesome good to know!

Awesome good to know!

Four Column

I made a four column layout with step-by-step post, hope it helps.
http://miss-hana.com/creating-a-custom-layout-for-panels-3-in-drupal-7/

Download the four column layout:
http://miss-hana.com/wp-content/uploads/2012/02/fourcol.zip

miss-hana.com | @hanamizuki

Use dashes in tpl.php

Just a reminder, since it's not totally clear: use dashes (-) not underscores(_) in your my-layout.tpl.php file name. Underscores seem to be okay to use elsewhere, just not in the file name of the tpl.php.

Thanks for a really helpful tutorial, and a number of helpful comments.

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 6.x, Drupal 7.x
Audience
Designers/themers
Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.