Chapter 4. Styling XOOPS and Creating a Theme from 960

This chapter mainly deals with how to add more styles to your themes. We will continue to use the theme you converted in Chapter 3. Also, we will discuss how to create a theme from the 960 CSS Framework for XOOPS (found online at http://code.google.com/p/insraq/source/browse/#svn%2Ftrunk%2F960) to save you time and coding.

More on Styling XOOPS

If you find an existing XOOPS theme and open the style.css file for that theme, you will find lots of CSS definitions. If the file is not well commented, though, you can hardly decipher what they actually do. It is the same when you write your own CSS file: if you do not follow a certain procedure, you will confuse others (and maybe even yourself).

There are lots of ways to categorize the definitions. I will introduce a method that I use when I am writing XOOPS themes.

Global Style

These definitions regard general tags, like body, a, img, h1-h6, etc. They will be used extensively on every page. Only include those styles that are applicable to every page (for example, if you want a link on a specific page to be red, do not write color: red; here).

Theme-Specific Style

These definitions are usually CSS definitions used by theme.html (for example, header, content, footer, slideshow, block, and so on). These styles are not used by XOOPS by default; they are used by your theme.

Warning

I originally used some general naming conventions like “nav” and “menu”. Then I found out that this may cause conflict between theme style (your style.css) and module style (some module-specific styles defined by module developers).

It is best to add a prefix to these names, like “inspire10-nav” and “inspire10-menu”. This way, even though we have longer names, there will be fewer conflicts and more distinction.

XOOPS System Template Style

These definitions are used by the XOOPS system template and are supposed to be used by modules—for example, the System menus and User menus. Others include very detailed table style definitions and form definitions. (Strictly speaking, forms are not really in this category, but for convenience, we will include them here.)

Dealing with XOOPS Template Style

Global style and theme-specific style are not XOOPS-specific, meaning that you should write them by the time you finish your XHTML and CSS templates. To include them in your theme, simply copy and paste.

The XOOPS system template style (referred to as required style therein) is generally not defined in your original template, but is required by XOOPS. This is what you need to work on.

XOOPS has many historical versions. Each version might have different requirements for required styles. I will introduce the common ones and leave those that are rarely used for you to discover on your own later.

#MainMenu

This group of style definitions is used by the system module on the main menu (usually used as the navigation menu). They are all under #mainmenu ID, and have different classes:

style.css (excerpt)
#mainmenu {}
#mainmenu a {
    display: block;
}
#mainmenu a:hover {}
#mainmenu a:active, #mainmenu a.current {}
#mainmenu a:visited {}
#mainmenu a.menuTop  {}
#mainmenu a.menuMain {}
#mainmenu a.menuSub {
    padding: 0 0 0 10px;
}
#mainmenu a.menuSub:hover  {}
#mainmenu a.maincurrent {}

Above is the necessary definition. As you can see, I only added two definitions (a and a.menuSub) and left the others blank. The display: block; is used to make the menu item displayed in the block, and the definition in #mainmenu a.menuSub is used to differentiate subitems from main items. I added a 10px left padding to achieve this.

#Usermenu

usermenu is quite similar to mainmenu, except that there is no “subitem” in usermenu:

style.css (excerpt)
#usermenu {}
#usermenu a {
    display: block;
}
#usermenu a:hover  {}
#usermenu a:active, #usermenu a.current {}
#usermenu a:visited {}
#usermenu a.menuTop {}
#usermenu a.highlight {}

Table and Cells

This is the most complex part. XOOPS has a complicated definition of table style, and different modules might use themes differently. I always try to maintain a minimum definition that works well in most situations, and let the modules set their styles. But the problem remains unsolved:

style.css (excerpt)
table {
    width:100%;
    margin: .5em 0 1em 0;
    border-collapse: collapse;
}

th {
    font-weight: bold;
    text-align: center;
    vertical-align : middle;
    background: #e7eef7;
    padding: 5px;
}

tr {
    border: 1px solid #eee;
}

td {
    padding: 5px;
}

.outer {
    border-collapse: collapse;
    padding: 5px;
}

.head {
    font-weight: bold;
    vertical-align: top;
    background: #f8f8f8;
}

.even {
    padding: 5px;
    border: 1px solid #eee;
}

.odd {
    padding: 5px;
    border: 1px solid #eee;
    background: #e7eef7;
}

The above code is the style I use in the 960 CSS framework for XOOPS. I make a lot of assumptions about styles here. The border of the table is #eeeeee, and for th (which defines a style for table headers) and .head (which defines a style for the head class), I add a background to differentiate them. I also add a padding of 5px to td (which defines a style for standard table cells) and additional classes.

I do it this way because I think table definitions should not be the focus of theme design, and shouldn’t bother designers so much. When I first designed for XOOPS, I was quite confused by those table definitions. They seemed too overwhelmed with details. Even if you do not define style for most of the selectors, you will be fine.

Another problem is that different module designers will use different markup for their modules. For example, some will use <th> as a table header, while others use <th class="header">. So my current approach is to define a set of minimum styles. But a better way to tackle this would be for the XOOPS community to work out a standard for module templates. If all the designers and developers followed this standard, differing markup would no longer be a problem.

Smarty: I Want to Know More

XOOPS provides a lot of Smarty variables to help designers achieve their goals. Here, I’ve made a list of the commonly used Smarty variables according to my experience over the past few years. I’ve categorized them for easy reference.

Header Tags

<{$xoops_charset}>

Output the character set information (e.g., “iso-8859-1”, “UTF-8”).

<{$xoops_langcode}>

Output content language (e.g., “DE”, “EN”).

<{$xoops_meta_keywords}>

Output the keyword list from the Meta/Footer settings.

<{$xoops_meta_description}>

Output the meta tag site description.

<{$meta_copyright}>

Output the meta tag copyright text.

<{$meta_robots}>

Output the W3C robot meta tag info.

<{$meta_rating}>

Output the meta tag rating information.

<{$xoops_js}>

Output XOOPS JavaScript.

<{$xoops_module_header}>

Output the module header. Usually, the module’s own JavaScript will be outputted. Details will be explained later.

XOOPS General

<{$xoops_sitename}>

Output the site name.

<{$xoops_slogan}>

Output the site slogan.

<{$xoops_pagetitle}>

Output the page title.

<{$xoops_theme}>

Output theme’s name in directory “/themes/” (e.g., “default”, “suico”).

<{$xoops_dirname}>

Output the name of the current module directory. If no module is displayed, this value is set to “system”.

<{$xoops_themecss}>

Inserts the style.css file (e.g., “http://www.xoops.org/themes/default/style.css”).

<{xoImgUrl}>

This is the XOOPS resource locator. It is often used if you want to link to an image or a CSS. Detailed usage will be explained throughout the book.

<{$xoops_url}> or <{xoAppUrl}>

Output the site URL (e.g., “http://www.xoops.org”), without the final slash.

<{$xoops_banner}>

Display banners.

<{$xoops_contents}>

Display the news and other content.

<{$xoops_footer}>

Display the footer.

<{$xoops_requesturi}>

Request URL provided by XOOPS (e.g., /modules/news/article.php?storyid=1).

<{$xoops_isadmin}>

Test if the visitor is Administrator—return TRUE if yes.

<{$xoops_isuser}>

Test if the visitor is a logged in user—return TRUE if yes.

<{$xoops_userid}>

User ID of the member.

<{$xoops_uname}>

Username for the member.

Smarty Flow Control

<{if $smarty_variable}>
...
<{elseif}>
...
<{else}>
...
<{/if}>

The if-else control.

<{foreach item=block from=$xoBlocks.canvas_left}>
<{/foreach}>

The foreach loop.

There is also a foreachq, described next.

<{foreachq item=block from=$xoBlocks.canvas_left}>
...
<{/foreach}>

Note that the closing tag is <{/foreach}> instead of <{/foreachq}>.

Include and Assign

<{include file=PATH}> or <{includeq file=PATH}>

Used to include a file in theme.html; the difference is that the latter is more efficient (but less secure).

<{assign var=NAME value=SOME_VALUE}>

Assign a value to a Smarty variable. For example:

<{assign var=theme_name value=$xoTheme->folderName}>
<{assign var=theme_name value=$xoTheme->folderName|cat:'/tpl'}>

Then you could use:

<{includeq file="$theme_name/tpl.html"}>

This would include XOOPS/themes/yourtheme_tpl.html or XOOPS/themes/tpl/yourtheme_tpl.html.

More on Smarty: Tricks and Examples

Module-Based Navigation

Now suppose you have a typical site navigation markup:

<ul class="nav">
    <li class="current"><a href="#">Home</a></li>
    <li><a href="#">News</a></li>
    <li><a href="#">Forum</a></li>
    <li><a href="#">Blogs</a></li>
    <li><a href="#">Contact</a></li>
</ul>

You want the navigation panel to tell the visitor which section of the website they are currently in. The most common way is to add a current class to the current item. Then you can style the class in your CSS file.

The trick is to add a current class to the current item. How does one achieve that in XOOPS? It’s easy:

<ul class="nav">
    <li<{if $xoops_dirname == "system"}> class="current"<{/if}>>
        <a href="#">Home</a>
    </li>
    <li<{if $xoops_dirname == "news"}> class="current"<{/if}>>
        <a href="#">News</a>
    </li>
    <li<{if $xoops_dirname == "forum"}> class="current"<{/if}>>
        <a href="#">Forum</a>
    </li>
    <li<{if $xoops_dirname == "xpress"}> class="current"<{/if}>>
        <a href="#">Blogs</a>
    </li>
    <li<{if $xoops_dirname == "contact"}> class="current"<{/if}>>
        <a href="#">Contact</a>
    </li>
</ul>

As mentioned earlier, $xoops_dirname outputs the current module directory name. Suppose you are using News module; the corresponding directory name is news. So we can use an if clause in Smarty to test whether $xoops_dirname equals the current module name. If yes, then we add a current class.

What About a Block Without a Title?

Usually, a block consists of a block title and block content. However, for some blocks, you may think the block title is meaningless and you probably do not want to display it. Take a look at our previous markup. If the block does not have a block title, the output will look like this:

<div class="title"><h2></h2></div>
<div class="entry">This is the block content</div>

This does not look nice. If you define some style for the title, it will simply give a blank result.

A better way to handle this is to only show the markup for the block title when the block has a title:

<{if $block.title}>
    <div class="title"><h2></h2></div>
<{/if}>
<div class="entry">This is the block content</div>

Use the above markup, and if a block has no title (i.e., the block title is empty), the output will look like this:

<div class="entry">This is the block content</div>

The markup for a block title will not be output.

Custom Block Filter

This sounds like rocket science, but it really isn’t. This trick follows the previous workaround. Suppose you want to have a special markup or style for some specific blocks—for example, the Search block. You have two choices. The first is the block anywhere technique, which will be covered in Chapter 7. This is fairly complex and is suitable for a situation in which your whole website is made of custom-designed blocks.

The second choice is to create a custom block filter. This is easy, and applies to situations in which you only have one or two custom-designed blocks.

To illustrate, look at the original code for blocks:

<{foreach item=block from=$xoBlocks.page_topcenter}>
<div class="title"><h2><{$block.title}></h2></div>
<div class="entry"><{$block.content}></div>
<{/foreach}>

A block filter is simply an if clause:

<{foreach item=block from=$xoBlocks.page_topcenter}>
    <{if $block.title == "Search"}>
        <div class="block-search">
    <{else}>
        <div class="block-general">
    <{/if}>
        <div class="title"><h2><{$block.title}></h2></div>
        <div class="entry"><{$block.content}></div>
    </div>
<{/foreach}>

With the above code, if the block title is "Search", then we will apply a block-search class to the block, and then apply the block-general class.

To add more than one filter, use an if-elseif clause:

<{foreach item=block from=$xoBlocks.page_topcenter}>
    <{if $block.title == "Search"}>
        <div class="block-search">
    <{elseif $block.title == "Welcome"}>
        <div class="block-welcome">
    <{elseif}>
        <div class="block-general">
    <{/if}>
        <div class="title"><h2><{$block.title}></h2></div>
        <div class="entry"><{$block.content}></div>
    </div>
<{/foreach}>

Blocks can be filtered not only by names, but also by ids, a technique which is less commonly used:

<{foreach item=block from=$xoBlocks.page_topcenter}>
    <{if $block.id == 5}>
        <div class="block-search">
    <{elseif $block.id == 6}>
        <div class="block-welcome">
    <{elseif}>
        <div class="block-general">
    <{/if}>
        <div class="title"><h2><{$block.title}></h2></div>
        <div class="entry"><{$block.content}></div>
    </div>
<{/foreach}>

“What is my block ID?” you may ask.

The ID of a block can be found out in the following way: edit a block, and in the address bar of your browser, you will see a URL like this:

http://example.com/modules/system/admin.php?fct=blocksadmin&op=edit&bid=1

The bid part of the query string is your block ID.

Create a Theme with 960

To create a theme from scratch takes a lot of time, which is why the concept of a framework is so handy. There are two types of framework, and both have their pros and cons. One is very rigid and strict, with lots of rules and conventions. The learning curve is very steep, but once you master it, you can write very concise and beautiful code.

Another type is loosely organized. It provides lots of functions to help your design. But even if you don’t follow all of the conventions, it’s fine. The learning curve is flat, but you’ll probably need to write more code than with the first type.

When I first decided to create a theme framework for XOOPS, there were already many other good frameworks. (One of the most famous is Morphogenesis, created by Chris (kris_fr in the forums). It is very powerful, concentrating on the file structure and functions. It does have some documentation, but is a little difficult for beginners.)

I decided to create a theme framework that focuses on design itself. I did not provide a lot of functions within it. The framework includes a theme.html to set home page structure using the 960 CSS Framework; some CSS files with definitions necessary to create a theme; and some other must-have JavaScript libraries.

To create a theme with 960, just copy the folder, rename it, and it’s done!

Then, open theme.html and you can see that the home page structure is written in 960, which assumes a width of 960 pixels and provides a grid system based on frequently used dimensions. If you are familiar with this system, you can easily modify it. If not, just leave it there, because the default grid layout will work 90% of the time.

The next step is to add some selectors in theme.html and add the corresponding styles to style.css. Your style definitions should be added in the /* Theme Specific Style */ section. Assuming you are already used to designing in CSS, you will have no trouble dealing with rest of the stuff in the template—it’s just like designing pure XHTML and CSS templates, except for some Smarty syntax. If the syntax throws you at all, refer back to Chapter 2.

Get Designing for XOOPS now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.