Written by Jordanlev and 12345j.
How to convert a free template into a Concrete5 theme, from start to finish
The basic tutorial for making a concrete5 theme is a good start when you want to customize a template for your site. But if you want to convert a theme and package it up for the marketplace, there are many more steps and details involved. This tutorial will show you how to convert a free template into a Concrete5 theme, from selecting the right kind of template all the way to packaging it up for the marketplace.
Where to Find Templates
The following sites have a wide variety of free templates to choose from:
Choosing a Good Template
The kind of layout that a template has can make a big difference on how easy or difficult (or even possible) it is to convert it to a Concrete5 theme. The golden rule in selecting a template is that is should be *flexible* enough to accomodate a variety of layouts and content. The power of Concrete5 lies in its ability to put any kind of content on any kind of page via the block system – but this means that your theme must be flexible enough to work with any kind of content being placed anywhere on the page. Here are some specific things to look for when choosing a template:
Is it a blog template or a generic site template?
A majority of the free templates you will find on the internet were designed with blogs in mind. Blogs are much more “templateable” because they all generally follow the same structure: main content area contains a list of items with a title, author, date, excerpt, tags and a link to comments; sidebar contains a search box, a list of categories, and a list of links. Concrete5, however, is more of a general-purpose CMS and the majority of the sites built on it are probably not blogs. It is okay to use a blog template as the basis for a Concrete5 theme, but keep in mind that many of the little design details (such as smaller font size for entry sub-headings, or different background colors for tag listings) will not come into play on a concrete5 site because most concrete5 sites are not blogs. Hence, you want to choose a template that will look good with general content in it – not content that is formatted as a series of blog posts with headings, authors, dates, tags, comments, etc. Example: http://www.oswd.org/design/preview/id/3697 – this template is very basic and could be used for any kind of site without modification. Example: http://www.freecsstemplates.org/preview/indication/ – this template is designed for a blog. It will still work as a concrete5 theme, but keep in mind that the light blue / green bar underneath each section will NOT appear on any concrete5 site. If you think that this bar is an essential part of the template's design, then it is probably not worth converting this one. But if you think the overall design will still look good without this bar, then it will definitely work as a concrete5 theme. Many templates have built in search bar, which won't work with concrete5. See below under custom templates to learn how to make it work. Example: http://www.freecsstemplates.org/preview/conjuction/ – this template is also designed for a blog. Notice the “scratch lines” underneath each heading. This might be considered an essential part of the design and hence this template might not be a good one to convert to concrete5. If you look at the html, you'll see that the scratch lines are a background image applies to the ”.post .meta” class – that is, content inside an element whose class is “meta”, which is itself inside another element whose class is “post”. There is no way a user of your theme will go through the trouble to code their content this way (assuming they even know how, which you shouldn't).
Is the navigation menu an unordered list (<ul>/<li>)?
Concrete5's Auto-Nav block outputs an unordered list (<ul>/<li> tags) for the navigation menu. You will want to make sure that the template you choose has its navigation menus coded the same way, otherwise it will not work with concrete5. Example: http://www.oswd.org/design/preview/id/3699 – this template's menu is a series of <a> tags inside a <div>. It will not work out-of-the-box with concrete5's auto-nav block. Example: http://www.oswd.org/design/preview/id/3698 – this template's menu is a series of <li> tags inside a <ul>. It WILL work properly with concrete5's auto-nav block.
Is the navigation menu comprised of text only?
Some templates use images for their navigation menus. However, a concrete5 theme needs to be flexible enough to handle any number of pages and any page names, which means the navigation menu must work with only text. Example: http://opensourcetemplates.org/templates/preview/organic-paper/index.html – this template's menu contains images of feathers, which will not work in concrete5. Example: http://opensourcetemplates.org/preview/green-hosting/ – this template's menu contains only text, so it will work with concrete5.
Does the site title area contain enough space for a long name?
Some templates have the site title constrained to a relatively narrow fixed-width area. Since you don't know how long or short someone's site title will be, this will be a problem because the text can wrap in weird ways or get cut off. Example: http://www.freecsstemplates.org/preview/woodenly/ – The title (“Woodenly”) is constrained in the red box. A title that is longer than a dozen or so characters will extend outside the box. Example: http://www.freecsstemplates.org/preview/nourish/ – The title (“Nourish”) has the entire width of the page to expand to, so it would be better as a concrete5 theme.
Are primary images implemented as <img> tags (not background images)?
Some templates have areas in their header that are intended for large images. If these images are implemented as background-images in CSS, then there is no way to change them via concrete5's block system. This is another situation that may or may not be suitable for a concrete5 theme – you will need to use your judgement. Example: http://www.freecsstemplates.org/preview/yosemite/ – the image of the lake is a CSS background-image, and hence cannot be changed. This might still make a suitable c5 theme, but it will be less flexible than a theme in which the image can be swapped out via an image block. Example: http://www.freecsstemplates.org/previews/terrafirma2/ – the image of the mountains is an actual <img> tag in the html (as opposed to a background-image in the CSS), so we can easily replace it by making it an area in the template. with <img> tage you can also use custom attributes. While this requires more work initially to set up, it offers more flexibility. You can read more about these here. http://www.concrete5.org/documentation/general-topics/attributes/ and how to use them in this context. https://www.concrete5.org/community/forums/customizing_c5/background-image-page-attribute/
Are background images flexible enough to work with different layouts?
Most templates utilize background images throughout their design. However, some background images are not symmetrical and will not work with different layout page types. For example, if the designer made a background image that had a line down the middle, this would work perfectly for a two column layout, but not so much for left/right sidebar and full layouts. These are usually called in the css, which is not changeable by the end user without ftp and image editing.
Are boxes styled generally?
Some templates style their sidebar boxes (and other boxes through the page) using very specific CSS rules (for example, a background image applied to an <h2> element). This will make it very difficult to work as a concrete5 theme because you cannot guarantee that a certain class will be applied. In these cases it may make sense to make it a new area that you can add content to. You can also provide instructions on how to style them and what to apply, but still don't know if the user will add the correct type of content. Additionally, some blocks may be styled in such a way that they are never called. for example, it a template calls for #container .meta-title, then you may want to change that to #container h5, so that users can add it.
Development Environment
- You will need a development environment on your computer to build and test the theme. If you don't already have this set up, I highly recommend “WAMP” on Windows, or “MAMP” on Mac OS X. WAMP: http://www.wampserver.com/en/ MAMP: http://www.mamp.info/en/index.html
- Download and install Concrete5 (even if you already have a version of concrete5 set up from another site, it would be best to start with a clean install just so you don't accidentally cause problems with your other site and so customizations you may have made to the other site don't interfere with these themes.) It is also important to use a clean install as if you are planning on submitting to the marketplace then that is what the theme will be tested against, so you can see the problems others have.
- When installing concrete5, be sure to leave the “Install Sample Content” checkbox checked – having sample content on the page will make it much easier to see how your theme will look with actual content in it, and allow you to see what the core team will see.
- Create More sample content: Once the site is up and running, log in and add some blocks to the home page: Add a search box to the sidebar, add a form to the sidebar (with a few sample questions and answers), and add a survey to the sidebar. Then add the Guestbook block to the bottom of the main content area. These blocks are very common and you will want to be sure that they look okay when your theme is installed. These blocks are also easy to template, so you can see your changes easily without having to add a block.
- Install Firebug. If you're a web developer and don't use firebug yet, well it's time to start! This tool is absolutely essential when trying to diagnose html / css layout issues, and also lets you quickly make changes to a page's html or css to see what effect it will have, without having to constantly reload. http://getfirebug.com/ and instructions at http://www.kristarella.com/2009/02/04/how-to-use-firebug-for-css/
Install the Template
- Once you've decided on a template, download it and unzip it.
- Move it into the “themes” directory of your local development site.
- Make sure the files from the template are all contained inside a folder (whose name is the name of the theme).
- Make sure all images that came with the template are in a sub-folder called “images” (e.g.
SITEROOT/themes/your_theme/images
) - If your theme name has spaces in it, replace the spaces with underscores for the containing folder's name. For example, if your theme's name is “Clean Red Theme”, the folder name would be “clean_red_theme”. It is often a good idea to prefix theme_ to this, so you can differentiate between themes and packages. The name would then be theme_clean_red_theme.
Thumbnail and Description
The thumbnail and description files will be shown to users in the “Pages and Themes” section of the dashboard.
- Create a thumbnail image of the theme by taking a screenshot of the preview page (where you downloaded the template from), resizing it to 120px wide by 90px high, and saving it as a PNG file called “thumbnail.png”. Save this image into the folder for your theme.
- Create a description file by creating a new text file, putting the theme name on the first line, and the theme description on the second line (usually the templates you download will have a name and description in the comments of the index.html file – you can copy them from there, or write your own if you think you can describe it better). Save this file as “description.txt” into the folder for your theme.
Stylesheet
- Rename the .css file that came with the template to “main.css” (this is not required by concrete5, but will make the rest of the steps in this tutorial much easier).
- Make sure that any image references are *NOT* surrounded by quotes. For example, if you see something like this:
body { background: #FFFFFF url('images/img01.gif') repeat-x left top; }
You will want to change it to this:
body { background: #FFFFFF url(images/img01.gif) repeat-x left top; }
If you don't do this, the call to “$this→getStyleSheet('main.css')” (which happens in a later step in the tutorial) will not work.
- Create a new stylesheet called “typography.css”, and move font styles for basic html elements into it. This will make it so that text is displayed in the WYSIWYG editor the same as it is displayed on the page (because the WYSIWYG editor [“TinyMCE”] only looks for a stylesheet called “typography.css”, not “main.css”).
- Only move the following properties (and only when they're in the elements listed below this list)
- color
- font
- font-family
- font-style
- font-variant
- font-weight
- font-size
- line-height
- word-spacing
- letter-spacing
- text-decoration
- text-transform
- text-align
- text-indent
- text-shadow
- Only move properties listed above when they're in the following elements:
- body
- a
- a:hover
- ul
- li
- ol
- p
- address
- pre
- h1
- h2
- h3
- h4
- h5
- h6
- div
- blockquote
- cite
For example, if you have something like this in your main.css file:
body { margin: 0; padding: 0; background: #F7F7F7 url(images/img01.jpg) repeat-x left top; font-family: Arial, Helvetica, sans-serif; font-size: 12px; color: #787878; }
You would put the following in typography.css:
body { font-family: Arial, Helvetica, sans-serif; font-size: 12px; color: #787878; }
And that would leave you with this in main.css:
body { margin: 0; padding: 0; background: #F7F7F7 url(images/img01.jpg) repeat-x left top; }
Create Default Page Type
Rename the “index.html” file to “default.php” – the template is now a concrete5 page type (“page type” is concrete5's word for template). You may actually want to trim down extra content from index.html first, so it is easier to identify text areas.
HTML Head
Replace everything inside the <head> element with these three lines:
<?php Loader::element('header_required'); ?> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('main.css'); ?>" /> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('typography.css'); ?>" />
For example, if the head of your template looked like this:
<head> <meta name="keywords" content="" /> <meta name="description" content="" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Republic by Free CSS Templates</title> <link href="style.css" rel="stylesheet" type="text/css" media="screen" /> </head>
You would replace it with this:
<head> <?php Loader::element('header_required'); ?> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('main.css'); ?>" /> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('typography.css'); ?>" /> </head>
Note that we're using “$this→getStyleSheet()” instead of “$this→getThemePath()” – this is what allows concrete5's “theme customizations” to work (which we will look at in more detail later on in the tutorial). However, one potential side-effect of this is that any url's in the stylesheet that are surrounded by quotes will not work – so make sure you're removed those.
Site Name
If the template displays the site name or title in the <body>, replace that name/title with the following code:
<a href="<?php echo DIR_REL?>/"><?php $block = Block::getByName('My_Site_Name'); if($block && $block->bID) $block->display(); else echo SITE;?> </a>
Which will call the scrapbook area content. Note that this is NOT for the <title> element in the html <head> – that is already taken care of with the Loader::element('header_required')
from the previous step. Also note that most blog templates have both a title AND a tagline/slogan (because Wordpress has both a title and tagline field in its admin interface), but since concrete5 doesn't allow you to set a tagline/slogan, you should remove it (and whatever html elements are enclosing it so that it doesn't cause weird spacing issues). If you really want the tagline in there, you can put an Area in its place, but this usually isn't worth the trouble because most blocks will output too much HTML, which will in turn mess up the layout by putting too much space around the tagline (even the plain old “Content” block will output <p> tags).
Content Areas
Identify the editable areas of the template and replace the sample content with Areas:
- This takes some thought, because different templates will have different areas. There are no definitive rules as to which areas you must have on each page, but it is standard practice for concrete5 page types to at least have a 'Main' area, a 'Sidebar' area, and a 'Header Nav' (navigation menu) area. Other standard areas are 'Header' (usually for a banner image) and 'Footer' (for extended content at the bottom of the page – e.g. Twitter/Facebook links, links to related content, etc. – NOT for the copyright notice). If it's appropriate for the template you're converting, you can add more areas to your page type template than these – but try to use these names first (where it makes sense).
- Note that when someone installs Concrete5 and checks the “install sample content” checkbox, the sample content is in 4 areas: 'Main', 'Sidebar', 'Header Nav', and 'Header'. If you're building a theme for the marketplace, it would be a good idea to have these areas in your page type template so that people trying out different themes will be able to see how this sample content looks in each one as they switch back and forth. You might have to leave out the 'Header' area because some templates just don't have banner images, but 99% of all templates do have primary content ('Main' area), a sidebar ('Sidebar' area), and a navigation menu ('Header Nav' area), so you'll want to be sure you've included at least those three in your page type template.
- When figuring out where exactly to put your areas in the template, keep in mind that while most templates have several pieces of sample content in each portion of the page, we are going to replace all of the sample content in each portion with a single concrete5 area (and then users will put multiple blocks representing each portion of the content into that area). In other words, each portion of sample content in the template would wind up being a concrete5 block, but as theme designers we're not actually putting the blocks into the theme – we're just putting in the areas (which the users will subsequently put their own blocks into).
Primary Content
- For the primary content area, if the template html looked like this:
<div id="content"> <div class="post"> <h2 class="title"><a href="#">Welcome to Republic </a></h2> <p class="meta"><span class="date">September 10, 2009</span><span class="posted">Posted by <a href="#">Someone</a></span></p> <div style="clear: both;"> </div> <div class="entry"> <p>This is <strong>Republic </strong>, a free, fully standards-compliant CSS template designed by FreeCssTemplates<a href="http://www.nodethirtythree.com/"></a> for <a href="http://www.freecsstemplates.org/">Free CSS Templates</a>. This free template is released under a <a href="http://creativecommons.org/licenses/by/2.5/">Creative Commons Attributions 2.5</a> license, so youíre pretty much free to do whatever you want with it (even use it commercially) provided you keep the links in the footer intact. Aside from that, have fun with it :)</p> <p>Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum ipsum. Proin imperdiet est. Phasellus dapibus semper urna. Pellentesque ornare, orci in felis. Donec ut ante. In id eros. Suspendisse lacus turpis, cursus egestas at sem.</p> <p class="links"><a href="#">Read More</a> | <a href="#">Comments</a></p> </div> </div> <div class="post"> <h2 class="title"gt;<a href="#">Lorem ipsum sed aliquam</a></h2> <p class="meta"><span class="date">September 10, 2009</span><span class="posted">Posted by <a href="#">Someone</a></span></p> <div style="clear: both;"> </div> <div class="entry"> <p>Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer. Donec ipsum. Proin imperdiet est. Phasellus <a href="#">dapibus semper urna</a>. Pellentesque ornare, orci in consectetuer hendrerit, urna elit eleifend nunc, ut consectetuer nisl felis ac diam. Etiam non felis. Donec ut ante. In id eros. Suspendisse lacus turpis, cursus egestas at sem. Mauris quam enim, molestie in, rhoncus ut, lobortis a, est.</p> <p class="links"><a href="#">Read More</a> | <a href="#">Comments</a></p> </div> </div> <div class="post"> <h2 class="title"><a href="#">Consecteteur hendrerit </a></h2> <p class="meta"><span class="date">September 10, 2009</span><span class="posted">Posted by <a href="#">Someone</a></span></p> <div style="clear: both;"> </div> <div class="entry"> <p>Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer. Donec ipsum. Proin imperdiet est. Phasellus <a href="#">dapibus semper urna</a>. Pellentesque ornare, orci in consectetuer hendrerit, urna elit eleifend nunc, ut consectetuer nisl felis ac diam. Etiam non felis. Donec ut ante. In id eros. Suspendisse lacus turpis, cursus egestas at sem. Mauris quam enim, molestie in, rhoncus ut, lobortis a, est.</p> <p class="links"><a href="#">Read More</a> | <a href="#">Comments</a></p> </div> </div> <div style="clear: both;"> </div> </div>
you would replace all of that with this code:
<div id="content"> <?php $a = new Area('Main'); $a->display($c); ?> <div style="clear: both;"> </div> </div>
Note that we took out all of the <div class=“post”> elements, but left the surrounding <div id=“content”> tags because they are essential for the structure of the page and have nothing to do with the actual content inside. We also left the “clearing div” element (<div style=“clear: both;”> </div>) at the end because it is important to the layout of the area as a whole. On the other hand, we did not keep the clearing divs inside each piece of sample content, because they're specific to that content and are not required for the layout of the page as a whole (although if for some reason they were essential to the page layout, you could include them via the “block wrapper” functionality – see below).
Sidebar
For the sidebar, take a look at how each item is coded in the template's html. Many sidebars are actually lists of elements – an unordered list (<ul>/<ul>), or a series of <div> elements – which are styled by the CSS to look a certain way. We want to make sure that the sidebar will be displayed properly regardless of which blocks the user adds, so we need to tell concrete5 to wrap each block's html with those elements. We can do this by setting a “block wrapper” for the area. For example, if the sidebar is coded in the html like this:
<div id="sidebar"> <ul> <li> <div id="search" > <form method="get" action="#"> <div> <input type="text" name="s" id="search-text" value="" /> <input type="submit" id="search-submit" value="GO" /> </div> </form> </div> <div style="clear: both;"> </div> </li> <li> <h2>Aliquam tempus</h2> <p>Mauris vitae nisl nec metus placerat perdiet est. Phasellus dapibus semper consectetuer hendrerit.</p> </li> <li> <h2>Categories</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </li> <li> <h2>Blogroll</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </li> <li> <h2>Archives</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </li> </ul> </div>
we would replace it with this code:
<div id="sidebar"> <ul> <?php $a = new Area('Sidebar'); $a->setBlockWrapperStart('<li>'); $a->setBlockWrapperEnd('</li>'); $a->display($c); ?> </ul> </div>
If the sidebar is coded as a series of div's, like this:
<div id="sidebar"> <div> <h2>Aliquam tempus</h2> <p>Mauris vitae nisl nec metus placerat perdiet est. Phasellus dapibus semper consectetuer hendrerit.</p> </div> <div> <h2>Categories</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </div> <div> <h2>Blogroll</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </div> <div> <h2>Archives</h2> <ul> <li><a href="#">Aliquam libero</a></li> <li><a href="#">Consectetuer adipiscing elit</a></li> <li><a href="#">Metus aliquam pellentesque</a></li> <li><a href="#">Suspendisse iaculis mauris</a></li> <li><a href="#">Urnanet non molestie semper</a></li> <li><a href="#">Proin gravida orci porttitor</a></li> </ul> </div> </div>
We would replace it with this code:
<div id="sidebar"> <?php $a = new Area('Sidebar'); $a->setBlockWrapperStart('<div>'); $a->setBlockWrapperEnd('</div>'); $a->display($c); ?> </div>
Finally, you may have a template that doesn't require blocks to be surrounded by tags at all, in which case you just leave out the “set block wrapper” calls, like this:
<div id="sidebar"> <?php $a = new Area('Sidebar'); $a->display($c); ?> </div>
How can you tell whether or not the sidebar requires sidebar blocks to be surrounded by tags or not? A good way to guess is to see how consistent the surrounding tags of the sample content are. If every single portion of sidebar content has the same surrounding tags, then chances are they will be needed in your page type template as well. You can also test out whether or not this is the case by re-downloading the original template and opening it in your browser, then messing around with the index.html file (e.g. remove some surrounding tags in the sidebar) and reloading it – did the contents of the sidebar stay contained in the sidebar area of the page, or did they jump around or look “wrong” somehow?
Navigation Menu
Assuming the template implemented its navigation menu as an unordered list, it is very easy to convert it to our concrete5 page type by replacing with a 'Header Nav' area. For example, if the template html looked like this:
<div id="menu"> <ul> <li class="current_page_item"><a href="#">Home</a></li> <li><a href="#">Blog</a></li> <li><a href="#">Photos</a></li> <li><a href="#">About</a></li> <li><a href="#">Links</a></li> <li><a href="#">Contact</a></li> </ul> </div>
We replace it with this:
<div id="menu"> <?php $a = new Area('Header Nav'); $a->setBlockLimit(1); $a->display($c); ?> </div>
Now when an auto-nav block is placed there and the “Header Menu” custom template is chosen, it will automatically output the necessary <ul>/<li> tags. Note that we use the “$a→setBlockLimit(1);” call to prevent users from adding more than 1 block to this area, because doing so would most likely mess up the layout.
Note that the auto-nav block outputs <li class=“nav-selected”> for the currently-active page, which is probably different than the class used by the template (for example, the above sample uses <li class=“current_page_item”>). So you will want to find where this selector is in the main.css file and change it – for example, if the css was this:
#menu li.current_page_item { background: url(images/bg06.jpg) no-repeat; }
you would simply change it to this:
#menu li.nav-selected { background: url(images/bg06.jpg) no-repeat; }
Navigation Menu (Alternate Method)
Putting a 'Header Nav' area on the page will work, but it might not be ideal because the navigation menu is normally an essential part of the layout, and we don't want it to be optional. If the user is starting with a fresh site and has sample content installed, this isn't a problem because the sample content already contains an auto-nav block (using the “Header Menu” custom template) in the 'Header Nav' area. But if this were not the case, then the header nav area might be empty and the user would then have to add the auto-nav block (and choose the “Header Menu” custom template) on every page, or add it to the page type defaults. By “hard-coding” the auto-nav block into the page type template, we save users from the trouble of having to add the auto-nav block themselves. The downside to this method is that the end-user will not be able to remove the auto-nav block or change its options – so they can't swap it out for a different navigation block (e.g. superfish dropdown menu). There is no best answer to this question – you will have to decide for yourself based on what you think works best for the design of your theme.
To hard-code the auto-nav block, replace the navigation menu code in your page type template with this:
<div id="menu"> <?php $bt_nav = BlockType::getByHandle('autonav'); $bt_nav->controller->displayPages = 'top'; $bt_nav->controller->orderBy = 'display_asc'; $bt_nav->controller->displaySubPages = 'none'; $bt_nav->render('templates/header_menu'); ?> </div>
This code specifies that the auto-nav block only shows top-level pages (because most templates don't have styles for drop-down or multi-level menus), and uses the custom 'header_menu' template that is included with the auto-nav block (so that it outputs the <ul>/<li> tags properly). If you want to set the block automatically but not with a template, simple use this code instead
<div id="menu"> <?php $bt_nav = BlockType::getByHandle('autonav'); $bt_nav->controller->displayPages = 'top'; $bt_nav->controller->orderBy = 'display_asc'; $bt_nav->controller->displaySubPages = 'none'; $bt_nav->render('view'); ?> </div>
Navigation with scrapbook
If you want to create a new navigation menu in the global scrapbook and hardcode that into the template then create a new autonav scrapbook block called menu (change this if you want) and call it with
<?php $block = Block::getByName('menu'); if($block && $block->bID) $block->display(); ?>
If you change the name of the scrapbook area then you need to change it in the above code as well.
Banner Image
Many templates include a large banner image at the top of the page. This presents a challenge for themes that will be put on the marketplace because we want to allow users a choice of keeping the default banner image (which usually is chosen by the template author to go well with the rest of the design) or replacing it with their own image. Concrete5 doesn't provide a way to distribute default content with a theme, but we can fake it by putting code in our page type template that checks whether or not a block exists – if no block exists, then display the default image, but if a block does exist, then display that instead. To do so, find the banner image element in your template (if it exists) – for example:
<div id="banner"> <img src="images/img01.jpg" width="600" height="100" alt="" /> </div>
and replace it with this:
<div id="banner"> <?php $a = new Area('Header'); if (($a->getTotalBlocksInArea($c) > 0) || ($c->isEditMode())) { $a->setBlockLimit(1); $a->display($c); } else { ?> <img src="<?php print $this->getThemePath(); ?>/images/img01.jpg" width="600" height="100" alt="" /> <?php } ?> </div>
Some things to note:
- As with the navigation menu area, we are setting the block limit of this area to 1 so that the user cannot add more than a single block to it (because doing so would mess up the layout).
- The “if” statement says to only show the area if it contains at least 1 block OR if we're in edit mode (otherwise the user would never have a chance to replace the default image!).
- Most banner images are designed to be a specific width and height. To restrict the dimensions of any image the user adds, put this rule in your main.css stylesheet:
#banner img { width: 600px; height: 100px; }
Replace “banner” with the name of the div that surrounds the image in your template (if your template doesn't have a wrapping div, add one yourself). And of course replace the width and height values with the width and height of the default banner image that came with the template.
Small issues
many templates from freecsstemplates.com will include a rule called text-transform: uppercase, or something with text-transform. When submitting a theme to the c5 marketplace you will most likely want to remove this, as you want the user to be able to decide. You may also want to remove lines about hr, as this will ultimately confuse users.
Other Images
For any images in the template other than the banner, you will need to decide if you want them to stay hard-coded or if they should be editable content areas. There is no right or wrong answer – it depends on the specific design of the template you're converting.
For images that you want to hard-code into the template, you will need replace their “src” attribute with a concrete5 path function ($this→getThemePath). For example, if the image was in the template html like this:
<img src="images/image05.jpg" height="50" width="50" alt="" />
you would replace it with this:
<img src="<?php print $this->getThemePath(); ?>/images/img05.jpg" width="50" height="50" alt="" />
Note that there is probably no slash before the word “images” in your template, but you need one for the concrete5 theme. If your template image had a path that doesn't include the “images” directory, you need to add that (because we put all of our theme images inside a folder called “images”).
For images that you want to make editable content areas, simply replace the <img> element with concrete5 area code:
<?php $a = new Area('Image 1'); //Or whatever you want to call it $a->display($c); ?>
Extended Bottom
Some templates have an extended content box at the bottom of the page – above the copyright notice but below the main content and sidebar areas. This extended content box is for miscellaneous things like twitter/facebook links, related content, and secondary navigation, and often they are styled differently from the rest of the page. If this is the case, you will want to make sure this specially-styled box does not appear when there's no content in it (because many people don't utilize these extended content boxes). Example: http://www.freecsstemplates.org/preview/terrafirma2/ (notice the black box at the bottom with the “Aliquam sit amet veroeros” title – if the user doesn't put content in here, an empty black box will show up at the bottom of the page.
We can achieve this in a similar fashion as the default banner image. For example, if our template html looks like this:
<div id="footer-bar" class="two-cols"> <div class="col1"> <h2>Aliquam sit amet veroeros</h2> <p>Faucibus non sit amet elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer placerat, dui sed posuere molestie, urna sapien porta purus, vel sodales ante erat sed arcu. Nunc semper, diam ut blandit elementum, ipsum purus vestibulum quam, sit amet auctor est ut risus. Maecenas sed dolore.</p> </div> <div class="col2"> <ul> <li><a href="#">Faucibus non sit amet elit nulla</a></li> <li><a href="#">Consectetur adipiscing elit integer</a></li> <li><a href="#">Placerat dui sed posuere molestie</a></li> <li><a href="#">Urna sapien porta purus vel</a></li> </ul> </div> <div class="clearfix"> </div> </div>
we would replace it with this code:
<?php $a1 = new Area('Footer Left'); $a2 = new Area('Footer Right'); $block_count = $a1->getTotalBlocksInArea($c) + $a2->getTotalBlocksInArea($c); if ($block_count > 0 || $c->isEditMode()) { ?> <div id="footer-bar" class="two-cols"> <div class="col1"> <?php $a1->display($c); ?> </div> <div class="col2"> <?php $a2->display($c); ?> </div> <div class="clearfix"> </div> </div> <?php } ?>
The “if” statement is checking that there's at least one block in either of the bottom areas OR that we're in edit mode (otherwise the end-user would never have a chance to add content!).
Copyright Notice
You probably do NOT want to replace all of the the copyright notice at the bottom of the page with an editable area, for two reasons:
- We usually want to output the copyright year automatically with php code, for example:
© <?php print date('Y') . ' ' . SITE; ?>
- Most free templates have a stipulation that you give credit to the original author and link back to their site. If this is the case, we do not want to make it easy for the end-user to remove this (the template author was nice enough to give it away for free, after all). What you want to replace with the above code is only the copyright 2010 your site, not template designed by nicedesigns.com.
Concrete5 Footer
You always want to add this piece of code to the bottom of your page type template (just above the closing </body> tag):
<?php Loader::element('footer_required'); ?>
This code outputs the Tracking Code javascript that users enter via the dashboard (e.g. Google Analytics)
Install and Test
We're finally ready to see what our converted template looks like as a concrete5 theme! Activate this theme (log in to your development site, go to the dashboard, click “Pages and Themes” on the left sidebar, find your new theme in the list, click the “Activate” button), then change the home page to use this theme (return to website, click “Edit Page” in the toolbar, click “Design” in the toolbar, choose your new theme, click “Save”, click “Exit Edit Mode” in the toolbar). Have a close look at the layout of this page (if you didn't install sample content, you should add some blocks to every area so you can see what it looks like with content on the page). Make any modifications that are needed in the stylesheet (Firebug will be very helpful in tracking down issues).
Fix Concrete5 Toolbar
Depending on how the template was designed, it is possible that the Concrete5 toolbar interferes with the layout when you are logged in (e.g. it pushes down some portions of the page but not others). This happens because your template's stylesheet and concrete5's admin stylesheet are both trying to style the body element. The solution is to change your template's stylesheet so that it applies the body style to a wrapper div instead.
- Add the wrapper div to the page type template by adding
<div class=“c5wrapper”>
just after the opening <body> tag, and</div>
just before the closing </body> tag. - In your main.css stylesheet, change “body {” to ”.c5wrapper {”.
Adjusting For Edit Mode
when you're converting a c5 theme sometimes edit mode will cause objects to overlap and make it hard to add content. If you want to adjust for this, add this to your body. From
<body>
to
<body <?php if ($c->isEditMode()) { ?> class="editmode" <?php } ?>>
You can then call the class .editmode {} in your css to adjust an object in edit mode. You may also want to use .ccm-add-block which will target the add block dialogue, or .ccm-area to target the content area. You may need to use !important here. These will get wrapped in your container divs, so you would target it with
.editmode #menu .ccm-add-block {}
to target the menu div add block dialogue.
Header and Footer Elements
Once we've made sure that the default page type template looks okay (and tweaked styles as needed), we'll want to make it more reusable by splitting up the header and footer into separate files (called “elements” in concrete5). Doing this will make it easier to create more page types in the following step, because if any changes need to be made to the header or footer, we can make them in one file instead of having to duplicate the change in all of our page type templates.
Deciding which portion of the template constitutes the header and footer takes some thought. You want to identify the aspects of the layout that will be exactly the same across all pages of the site, regardless of whether there's 1 column vs. 2 columns, left sidebar vs. right sidebar, etc. Also, to avoid unmatched html tags, it is best to balance any opening tags that appear in the header element with closing tags in the footer element (for example, if the <body> and <div class=“c5wrapper”> tags are in the header element, you want the ”</div>” and ”</body>” tags in the footer element).
The html <head> element ALWAYS goes in the header element, along with the opening <body> tag (and <div class=“c5wrapper”> tag if you have one). Usually, the site name/title, banner image, and top-level navigation will go in the header element as well (but not always, depending on how your template html is structured). The Loader::element('footer_required'); call, and the closing </body> and </html> tags ALWAYS go in the footer element, and the copyright notice usually goes in the footer as well.
For example, if our template looks like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php Loader::element('header_required'); ?> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('main.css'); ?>" /> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('typography.css'); ?>" /> </head> <body> <div class="c5wrapper"> <div id="wrapper"> <div id="header"> <div id="logo"> <h1><a href="<?php print DIR_REL; ?>/"><?php print SITE; ?></a></h1> </div> </div> <div id="menu"> <?php $a = new Area('Header Nav'); $a->setBlockLimit(1); $a->display($c); ?> </div> <div id="page"> <div id="page-bgtop"> <div id="page-bgbtm"> <div id="content"> <?php $a = new Area('Main'); $a->display($c); ?> <div style="clear: both;"> </div> </div> <div id="sidebar"> <?php $a = new Area('Sidebar'); $a->setBlockWrapperStart('<li>'); $a->setBlockWrapperEnd('</li>'); $a->display($c); ?> </div> <div style="clear: both;"> </div> </div> </div> </div> </div><!-- end #wrapper --> <div id="footer"> <p>© <?php print date('Y') . ' ' . SITE; ?>. Design by <a href="http://www.freecsstemplates.org/">Free CSS Templates</a>.</p> </div> </div><!-- end .c5wrapper --> </body> </html>
We would put this portion into the header element:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php Loader::element('header_required'); ?> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('main.css'); ?>" /> <link rel="stylesheet" type="text/css" href="<?php print $this->getStyleSheet('typography.css'); ?>" /> </head> <body> <div class="c5wrapper"> <div id="wrapper"> <div id="header"> <div id="logo"> <h1><a href="<?php print DIR_REL; ?>/"><?php print SITE; ?></a></h1> </div> </div> <div id="menu"> <?php $a = new Area('Header Nav'); $a->setBlockLimit(1); $a->display($c); ?> </div>
We would put this portion into the footer element:
</div><!-- end #wrapper --> <div id="footer"> <p>© <?php print date('Y') . ' ' . SITE; ?>. Design by <a href="http://www.freecsstemplates.org/">Free CSS Templates</a>.</p> </div> </div><!-- end .c5wrapper --> </body> </html>
And we would leave this portion in the default.php page type template file:
<div id="page"> <div id="page-bgtop"> <div id="page-bgbtm"> <div id="content"> <?php $a = new Area('Main'); $a->display($c); ?> <div style="clear: both;"> </div> </div> <div id="sidebar"> <?php $a = new Area('Sidebar'); $a->setBlockWrapperStart('<li>'); $a->setBlockWrapperEnd('</li>'); $a->display($c); ?> </div> <div style="clear: both;"> </div> </div> </div> </div>
Note that we added an html comment (e.g. ”<!– end #wrapper –>”) to the closing tags in the footer element so that we can tell which opening tag they match in the header element.
Here are the specific steps involved:
- Create a new directory in your theme folder called “elements” (so it will be
SITEROOT/themes/YOUR_THEME_NAME/elements/
) - Copy the portion of your template that you've decided will be the header element and paste it in at the end of the new “elements/header.php” file.
- Copy the portion of your template that you've decided will be the footer element and paste it in at the end of the new “elements/footer.php” file.
- Back in the default.php file, delete the code you just copied, and replace it with this:
<?php $this->inc('elements/footer.php'); ?>
Your default.php file should now look something like this:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); $this->inc('elements/header.php'); ?> ...CONTENT... <?php $this->inc('elements/footer.php'); ?>
More Page Types
It is recommended that themes submitted to the marketplace have a few different page types – usually a “left sidebar”, a “right sidebar”, and a “full” layout will suffice. To create these other page types, simply copy the default.php file and rename it “left_sidebar.php”. Tweak CSS (if it was floated left, float it right; vice-versa, and watch out for left-right paddings)
Single Page Template
Single page templates are needed in all themes. To create one, duplicate default.php and rename it view.php, and open it. Then replace
<?php $a = new Area('Main'); $a->display($c); ?>
with
<?php print $innerContent; ?>
and save it.
Overriding Core Blocks
Since core css is often loaded after theme css, it can be a problem to override styling of core blocks without using custom templates. While this may seem like a hard thing to do, it is actually remarkably easy.
The !important declaration in css causes an element to override other declarations of it later. To link into this, include !important after you're declaration but before the semicolon, like this.
.contentByLine { color: #fff !important; }
this would cause the posts by line in guestbook to become white.
Using Custom Templates with Search block
Many css templates will have a built in search from block with some styling. This search from will not work with concrete5 though, so you need to create a custom template. To add a custom template, create a new folder inside root/blocks (or inside root/packages/theme_name/blocks if it is a packaged theme). Then create a new folder called search, and inside that one called templates. Then cocpy the view.php from the search block inside this folder and give it a descriptive name. I often use the format theme_name_location_block.php with location being the place on the page, and block the blocks name. You then need to tweak the .php file and the css file to change the look. This is probably mostly with css, so you may want to transfer the css to the custom template.
Enabling Style Picker
When editing a content block in c5 there is a dropdown that says styles. To allow output content in one of these styles, you need to add classes to typography.css. Just by adding a rule for .button, users can then output text with that class applied with one click, no custom templates.
Enable CSS Customization
Css customization is very important in themes, it allows the end user much more control. Right now concrete5 only supports background color customization and color customization, so don't waste time on other things. You can define a customizable area with the code
/* customize_body */
you need a start and end code though, so you'd end up with
body { /* customize_body */ color: #444; /* customize_body */ }
you can add a customize miscellaneous at the end of your stylesheet to allow further customization.
Package It Up
Uninstall the Theme
For most themes you don't have to add any extra logic to get them to uninstall correctly. If you theme has code that copies over files, then you need some more logic
public function uninstall() { // uninstall added code here- use this space to delete files or copy them over $do_uninstall = parent::uninstall(); //let the package controller finish up the uninstall } </code php> ==== Package Directory ==== theme_cool_theme blocks new_block_name (this is an installable block, put the contents of this blocks folder inside here) existing_block templates existing_block_template.php icon.png controller.php themes cool_theme (this is where your unpackaged theme content goes without its outer directory) thumbnail.png default.php view.php description.txt elements header.php footer.php note that existing_block_template.php will override only the view.php. If you wanted to override more files, you'd call it existing_block_template as a folder and put the php/css files inside there with the same names as in the block. ==== Package Controller ==== The Basic controller.php file will look like this. **I have put asterisks around what you need to edit.** You should delete these when making your package. <code php> <?php defined('C5_EXECUTE') or die(_("Access Denied.")); class *ThemeMyCoolThemePackage* extends Package { protected $pkgHandle = '*theme_my_cool_theme*'; protected $appVersionRequired = '*5.1*'; protected $pkgVersion = '*1.0*'; public function getPackageDescription() { return t("*Installs My cool theme, an awesome Concrete5 theme*"); } public function getPackageName() { return t("*My Cool Theme*"); } public function install() { $pkg = parent::install(); // install block PageTheme::add('*my_cool_theme*', $pkg); } }
Lets go through what this means.
ThemeMyCoolThemePackage
This is the name of your outer directory, with new words in caps. You then add Package after it because it is a package to lwt c5 know it can install it. So if your outer directory was named theme_awesome then this would by ThemeAwesomePackage
theme_my_cool_theme
this is the outer directory of your theme, nothing fancy. So for this package the outer directory would by theme_my_cool_theme
5.1
this is the version of c5 that your package needs to one- change 5.1 to whatever is required
1.0
this is the version of your package, it will be 1.0 initially but then will need to be changed for future updates
Installs My cool theme, an awesome Concrete5 theme
what you want the description to be on the add functionality page.
My Cool Theme
what you want the title to be on the add functionality page.
my_cool_theme
the name of the directory inside the themes folder
so this theme would look like this
theme_my_cool_theme icon.png controller.php themes my_cool_theme themecontents
Marketplace Icon
When Submitting to the marketplace you need to have a file called icon.png that resides in the root of your package directory. Generally this is a screenshot of your header in a square. To use this image for the marketplace, you need to resize the image to 97*97 pixels and then Give it 4px rounded corners.
Changelog
The change log lets your users know what edits take place In various version. I generally count by .o.1 for small updates/minor bug fixes, .1 for medium changes, and 1.0 for major changes (like a complete overhaul). I say what has changed in the changelog. You should also update the changelog on your manage item page.
License
If you are converting a theme then it will most likely have a license. If you go to the page where you downloaded the template it should tell you what the license is. You need to specify this in your theme submission. If you are using a converted theme you should also put the address that you downloaded the theme in your comments box on the manage item page. If it is your own theme, you can decide which. Some Basic licenses are
- creative commons: this is what most converted themes are. It requires you to keep a link in the footer, but nowhere else.
- Open Source: User can change everything, without attribution
- C5 marketplace license: Look in the marketplace for this one
In general I use Open Source for themes that I made/designed that I'm giving away, creative commons for converted templates, and marketplace license for paid themes.
Extending the Theme
Because a theme is technically a package that installs a theme and not a theme, you can also perform normal tasks in the controller.php. The above is just a guideline. Themes can, for instance, have libraries and events that run in them. An example of this is http://www.concrete5.org/marketplace/themes/mobilize/, which runs an event which processes a library. In this way, on install of a theme you could modify config/site_theme_paths.php to display error and 404 pages with your theme installed.
Browser Testing
Concrete5 asks for compatibility with various browsers when submitting to the marketplace. I find that if I don't have the neccessary environment at hand, a good tool is adobe browserlab to see your site in various browsers. If you are using html4/xhtml and css2 and below, you may not need to do this, just internet explorer 6. If you are using html5 and or css3 though, you should definitely test it. You should also test paid themes, as you are obligated to support them.
Submit To Marketplace
Go to the concrete5.org website, and then hover over developers. Then look for the link on the dropdown that says submit to marketplace. Scroll to the bottom where it says send us what you've got and click on it. You'll then be taken to a form submission page where you fill in your package details. Submission type is theme, then input your themes handle (outer directory name), short and long description, and if you have a demo input that. You definitely want to put in some pictures of your theme too. If it is a free theme in the message on purchase box you probably want to say something like thanks for downloading, I'd love it if you left a review, if you want to donate heres my paypal kind of thing. For a paid theme you probably want to ask them to leave a review and heres my email. You then choose the skill level (probably beginner) and fill in version history (changelog), Documentation, roadmap (planned features), license, etc etc. Then click submit once you are done and a group of your peers will review it and hopefully approve it. If you are given feedback, you should try to fix the issue within the week, and learn from your mistakes.