Themes allow you to change Symbio's appearance. You'll find that the Symbio theming system is quite versatile, and because of this it might seem a little too complex at times. However, I'm sure every theme designer will get the hang of it quickly.

Anatomy of a Symbio theme

This section aims to give you a complete and structured view on Symbio themes.

A Symbio theme consists of 2 main parts: the source templates and the resources. The source templates are stored in the a subdirectory of themes, named after the theme, and the resources are in a subdirectory of img which has the same name. The resources are the files that need to be accessible by the user – i.e. graphics, stylesheets or even Flash animations or applets – whereas the source templates are only used internally; consequently, the source templates have a fixed structure, while the resources don't.

So basically, to create a Symbio theme, you need to create the two directories described above, and make sure you've got the files below (and preferably nothing else) in the template directory. Note that if you want to use any of the resources in the templates, you need to prefix the URL with <!resourceurl>. Furthermore, you can include the page title in any template by adding the <!title> tag.

The demo theme included in the Symbio package provides a good base from which you can start building your own theme. It's a minimalistic skeleton of just about any theme. Just copy it and start editing, and you'll have your own theme instantly.

Theme information: description.txt

Including this file is not mandatory, but it does make identification of themes easier for the user. What you put in it is entirely up to you. The contents are displayed in a popup window when the user requests them in the control panel. Please do not use HTML; it will be displayed as plain text.

Theme parameters: parameters.txt

width=500
height=300
helpwidth=400
helpheight=200

As of version 1.5, the sole use of this file is to set the dimensions of the two themable windows. Just have it contain 4 name=value pairs, each setting one of the dimensions, as shown in the example.

The main template: main.txt

<html>
<head>
<title><!title></title>
</head>

<body>
<h1><!title></h1>

<!iferror>
<!-- Described below -->
<!/iferror>

<!ifmoderation>
<!-- Described below -->
<!/ifmoderation>

<!ifpoll>
<!-- Described below -->
<!/ifpoll>

<!ifcomments>
<!-- Described below -->
<!/ifcomments>

<!ifnocomments>
<!-- Described below -->
<!/ifnocomments>

<!iflocked>
<!-- Described below -->
<!/iflocked>

<!ifform>
<!-- Described below -->
<!/ifform>
</body>
</html>

This template is used to build the main comment popup, holding the comment list and the form. Because it's pretty generic, there are several conditional tags. These are implemented as follows:

<!ifcondition>
<!-- Code that should be displayed if condition is true -->
<!/ifcondition>

Now for an overview of the available conditional tags, each with their internal tags, which further define the output.

An error occurs: <!iferror>

<!iferror>
<p><!errortext></p>
<!/iferror>

Everything between error tags will only be displayed when something goes wrong, e.g. the user doesn't fill out the form properly or writing to the comment file fails. The <!errortext> tag defines what exactly went wrong.

Moderation is enabled and user comments: <!ifmoderation>

<!ifmoderation>
<p><!moderationtext>
<!moderationreturntext></p>
<!/ifmoderation>

Since Symbio 1.7, the site owner may decide to approve every comment before publishing it. When this option is enabled, the code above is displayed right after the user posts a comment, and <!moderationtext> is replaced with a localized explanation of the moderation process. To provide the means to return to the comment list, a localized link text is available through <!moderationreturntext>; if you only want the URL, that's <!moderationreturnurl>.

List of comments: <!ifcomments> and <!ifnocomments>

<!ifnocomments>
<p><!nocommenstext></p>
<!/ifnocomments>

<!ifcomments>
<h2><!commentlisttitle></h2>
<!comments>
<!commentseparator><hr><!/commentseparator>
<p><!comment></p>

<p><!nametitle>: <!name><br>
<!emailtitle>:
  <!ifemail><a href="mailto:<!email>"><!clickhere></a><!/ifemail>
  <!ifnoemail><i><!notavailable></i><!/ifnoemail><br>
<!urltitle>:
  <!ifurl><a href="<!url>" target="_blank"><!clickhere></a><!/ifurl>
  <!ifnourl><i><!notavailable></i><!/ifnourl><br>
<!datetitle>: <!date></p>
<!/comments>
<!/ifcomments>

The former is only displayed when comments have already been posted, while the latter does the exact opposite.

The <!ifnocomments> part is the easiest: you merely output <!nocommentstext> if desired.

As for the <!ifcomments> part, this one's called into action when the list of posted comments needs to be built. The <!commentlisttitle> tag is replaced with the title (from the language file).
The actual comment list is built by repeating everything between <!comments> and <!/comments>. The part between <!commentseparator> and <!/commentseparator> is inserted between the comments. Insert the actual comment the user entered with the <!comment> tag. The <!name>, <!email> and <!url> tags are replaced with the user's personal information.
If you are familiar with CSS, you can change the appearance of a replaced bad word in the output by styling the i.badword class; if you don't style it, it will be in italics, since it's regular italic text and the badword class doesn't exist.
Because the commenters don't have to enter their e-mail address and homepage URL if they don't want to, you have to define an alternate structure for when those fields aren't available. This is done using the conditional structures <!ifemail> vs. <!ifnoemail> and <!ifurl> vs. <!ifnourl>; in both cases, exactly one of both parts is inserted for every comment.
To insert the date when the comment was posted, use the <!date> tag.
For internationalization purposes, you are encouraged to use the <!nametitle>, <!emailtitle>, <!urltitle>, <!commenttitle> and <!datetitle> tags instead of the actual words Name, E-mail, … where applicable. The same goes for <!notavailable> instead of Not available and <!clickhere> instead of Click here.

The commenting form: <!ifform> and <!iflocked>

<!iflocked>
<p><!lockedtext></p>
<!/iflocked>

<!ifbanned>
<p><!bannedtext></p>
<!/ifbanned>

<!ifform>
<h2><!formtitle></h2>
<!beginform>
<p><!formnametitle>: <input type="text" name="name" value="<!formname>"><br>
<!formemailtitle>: <input type="text" name="email" value="<!formemail>"><br>
<!formurltitle>: <input type="text" name="url" value="<!formurl>"><br>
<!formcommenttitle>: <textarea name="comment"></textarea></p>
<p><input type="button" onclick="addTag('b');" value="B" title="<!buttontextb>">
<input type="button" onclick="addTag('i');" value="I" title="<!buttontexti>">
<input type="button" onclick="addTag('u');" value="U" title="<!buttontextu>">
<input type="button" onclick="addTag('s');" value="S" title="<!buttontexts>">
<input type="button" onclick="addHyperlink();" value="A" title="<!buttontexta>">
<input type="button" onclick="openHelp();" value="?" title="<!buttontexthelp>"></p>
<p><input type="submit" value="<!buttontextpost>"></p>
<!endform>
<!/ifform>

In case the article has been locked, the code for <!iflocked> is displayed. You can use <!lockedtext> to add the default text for this situation. If the article isn't locked, but the user's IP is banned, a similar construction using <!ifbanned> and <!bannedtext> is used.

In most cases however, the commenting form will be inserted. The code for it must be between <!ifform> and <!/ifform>. Next, we're going to look into the rest of the code for the form.

First of all, the form code has to contain the <!beginform> and <!endform> tag, which will be replaced with the HTML code that indicate the start and end of a form. Make sure you put the former somewhere at the start of the form, and the latter somewhere at the end.

Next, you've got three single-line inputs: name, email and url. Their values are remembered, so you need to include the initial value with the <!formname>, <!formemail> and <!formurl> tags. There's also the textarea where the user enters his comments, named comment. This one has no initial value.
For internationalization purposes, the title of each of these fields is preferably inserted using the following tags: <!formnametitle>, <!formemailtitle>, <!formurltitle> and <!formcommenttitle>.

Now for the layout buttons. Let me start off by saying including these is not mandatory, but users might prefer having them handy. The JavaScript actions to add the appropriate tags are addTag('b');, addTag('i');, addTag('u');, addTag('s'); and addHyperlink();. Don't worry about the function names – they're predefined. Tooltip text for the buttons, for internationalization, is available through the following tags: <!buttontextb>, <!buttontexti>, <!buttontextu>, <!buttontexts> and <!buttontexta>.

You will also have to allow users to open the help popup, by linking to the openHelp(); JavaScript function. The label or tooltip text for this button is <!buttontexthelp>.

Finally, don't forget to provide the means to actually submit the form. Label or tooltip text for the submit button is available as <!buttontextpost>.

Note that the name of the form will always be cform, so if you wish to add form-related JavaScript code, you can.

Also, do not bother to implement a script that disables submitting the same data several times (i.e. by double-clicking the submit button). Symbio checks this natively.

The poll: <!ifpoll>

<!ifpoll>
<h2><!polltitle></h2>

<!ifpollresults>
  <p><i><!pollquestion></i>
  (<!pollvotestitle>: <!polltotalvotes>)</p>
  
  <!ifpollsecret>
  <p><!pollsecrettext></p>
  <!/ifpollsecret>
  
  <!ifpollpublic>
    <!ifpollvotes>
      <p><!pollanswer>
        <!pollanswerseparator><br><!/pollanswerseparator>
        <!pollanswertext>: <!pollvotestitle>:
        <!pollanswervotes> (<!pollanswerpercentage>%)
        
        <!ifpollanswervotes><img src="<!resourceurl>/poll-foreground.gif"
        width="<!pollanswerpercentageof200>"
        height="8"><img src="<!resourceurl>/poll-background.gif"
        width="<!pollanswerpercentageof200complement>"
        height="8"><!/ifpollanswervotes>
        
        <!ifpollanswerallvotes><img src="<!resourceurl>/poll-foreground.gif"
        width="200" height="8"><!/ifpollanswerallvotes>
        
        <!ifpollanswernovotes><img src="<!resourceurl>/poll-background.gif"
        width="200" height="8"><!/ifpollanswernovotes>
      <!/pollanswer></p>
    <!/ifpollvotes>
  
    <!ifpollnovotes>
    <p><!pollnovotestext></p>
    <!/ifpollnovotes>
  <!/ifpollpublic>
  
  <!ifpolllocked>
  <p><!polllockedtext></p>
  <!/ifpolllocked>
<!/ifpollresults>

<!ifpollquestion>
  <p><i><!pollquestion></i>
  <!ifpollresultslink>[<a
  href="<!pollresultslinkurl>"><!pollresultslinktext></a>]<!/ifpollresultslink></p>
  <p><!pollanswer>
    <!pollanswerseparator><br><!/pollanswerseparator>
    <a href="<!pollanswerurl>"><!pollanswertext></a>
  <!/pollanswer></p>
  <!ifpollresultsnolink><p><!pollsecrettext></p><!/ifpollresultsnolink>
<!/ifpollquestion>
<!/ifpoll>

As of version 1.5, Symbio supports themable polls. There's quite a lot to display about a poll, be it possible answers, textual or graphical results, simple error messages, etc. Consequently, the template code related to polls will be quite extensive. But not to worry, I'll guide you through the entire theming process.

First of all, not all articles have polls. Therefore, any code between <!ifpoll> and <!/ifpoll> is only used when a poll is actually appended to the article. A localized title for the poll is available through the <!polltitle> tag.

Next up is a main separation of the code between the poll tags: the code between <!ifpollquestion> and <!/ifpollquestion> is displayed when the user hasn't voted yet, so it simply asks the poll question, whereas the code between <!ifpollresults> and <!/ifpollresults> displays the poll results, meaning the user has already voted in that particular poll.

The poll question code isn't too complicated. <!pollquestion> is replaced with the question the site owner asks, and any code between <!pollanswer> and <!/pollanswer> is repeated for every poll answer, replacing <!pollanswertext> with the actual answer, and <!pollanswerurl> with the URL the user is sent to when he desires to vote for that answer. If you wish to put anything between two answers, just put that between <!pollanswerseparator> and <!/pollanswerseparator>.
As of Symbio 1.7, users can see the results of a poll without voting. To account for this in your code, there are two new conditional structures: <!ifpollresultslink> and <!ifpollresultsnolink>. In <!ifpollresultslink>, you link the string <!pollresultslinktext> to the URL <!pollresultslinkurl>. The only tag supported in <!ifpollresultsnolink>, for now, is <!pollsecrettext>, which is also displayed when the user has just voted in a poll with secret results.

In the results code, you'll need to let the user know the total number of votes, with the <!polltotalvotes> tag; give that number a nice title by putting <!pollvotestitle> in front of it.
The rest of the code is actually very similar to the question code, but there are a few extra tags. You've also got the <!pollquestion> tag at your disposal, and similarly, the <!pollanswercode>, along with separators, is nicely repeated. Only this time, <!pollanswertext> is not accompanied by <!pollanswerurl>. Instead, you can request the number of votes for an answer through <!pollanswervotes>. If you want to find out the percentage that makes, there's <!pollanswerpercentage>.
Now for a few special features… First of all, <!pollanswerpercentageofnumber> calculates the percentage of that number. This can be really useful if you want to make the results graphical. Also, if you want to express the percentage of the voters that didn't vote for the answer in question, use <!pollanswerpercentagecomplement>; similarly, you can request <!pollanswerpercentageofnumbercomplement>.
All of this should be enclosed in <!ifpollanswervotes> and <!/ifpollanswervotes>. Why? Because it's possible that some answers have no votes, or that one of the answers has received all the users' votes. And we wouldn't want to ignore those special situations, so we're going to put them between <!ifpollanswernovotes> and <!/ifpollanswernovotes>, and <!ifpollanswerallvotes> and <!/ifpollanswerallvotes>.

Now all we need to do is account for special situations. First of all, it's possible that a poll has received no votes yet. Therefore, we need two distinct situations: the code described above is placed between <!ifpollvotes> and <!/ifpollvotes>, and we create a new section, holding <!pollnovotestext>, between <!ifpollnovotes> and <!/ifpollnovotes>. Another thing that might happen is that the poll results are secret. For this, we distinguish <!ifpollpublic> and <!/ifpollpublic>, and <!ifpollsecret> and <!/ifpollsecret>, holding <!pollsecrettext>. And finally, the site owner may have locked the poll. In this case, we use <!ifpolllocked> and <!/ifpolllocked>, holding <!polllockedtext>

And that concludes the poll code! Congratulations, you made it through!

The help template: help.txt

<html>
<head>
<title><!title></title>
</head>

<body>
<h1><!title></h1>

<h2><!smileystitle></h2>
<!smileys>
<!-- Described below -->
<!/smileys>

<h2><!tagstitle></h2>
<!tags>
<!-- Described below -->
<!/tags>

<!ifstats>
<h2><!statstitle></h2>
<!-- Described below -->
<!/ifstats>

</body>
</html>

This template consists of 3 main sections, namely the smiley list, the layout tag list and the statistics. We will deal with each section separately.

The smiley list

<h2><!smileystitle></h2>
<table>
<!smileys>

<!smiley>
<tr><td>
<!smileyimage>
<!smileycodes>
<!smileycodeseparator> <!smileyor> <!/smileycodeseparator>
<tt><!smileycode></tt>
<!/smileycodes>
</td>
<!/smiley>

<!smiley>
<td>
<!smileyimage>
<!smileycodes>
<!smileycodeseparator> <!smileyor> <!/smileycodeseparator>
<tt><!smileycode></tt>
<!/smileycodes>
</td></tr>
<!/smiley>

<!/smileys>
</table>

This is the most complicated part. Because the number of available smileys and codes varies, an abstract structure has to be defined. The construction above defines a simple table with two identically designed columns, of which each row holds a smiley image, followed by the available codes for that smiley.

Let's go over the tags. <!smileys> denotes the start of the smiley area, terminated by <!/smileys>. This portion of code will be repeated until no more smileys need to be displayed. In this case, the area simply holds a table row.

Inside that area there are several blocks of code, each of which are delimited by <!smiley> and <!/smiley>. These are consecutively filled in with smiley definitions, one per block. In this case, every block is a table cell.

Each smiley definition consists of a smiley image, inserted with <!smileyimage>, and the available codes for that smiley, between <!smileycodes> and <!/smileycodes>.

To separate the codes, the word "or" is available in the language of the user, via the <!smileyor> tag, but you can also define your own separator. Eitherway, place it between <!smileycodeseparator> and <!/smileycodeseparator>.

And voila, you've got yourself a smiley list!

Note that all code enclosed in <!smileys> must also be enclosed in <!smiley> (yes, singular this time), or else it will be ignored. This is why <tr> and </tr> must be inside the smiley blocks.

The layout tag list

<h2><!tagstitle></h2>
<!tags>
<p><tt><!taginputb></tt> <!tagwillresult> <!tagresultb><br>
<tt><!taginputi></tt> <!tagwillresult> <!tagresulti><br>
<tt><!taginputu></tt> <!tagwillresult> <!tagresultu><br>
<tt><!taginputs></tt> <!tagwillresult> <!tagresults><br>
<tt><!taginputa></tt> <!tagwillresult> <!tagresulta></p>
<!/tags>

This section's a lot easier since the only thing you need to do is explain 5 layout codes. The easiest way to do this is shown above. <!taginputx> holds the full code of the input example for each tag, including the example text, while <!tagresultx> is replaced with the output. The text "will result in" is available in the user's language through the <!tagwillresult> tag.

Don't forget to place your code between <!tags> and <!/tags>, to inform Symbio of the beginning and end of the tag list.

The statistics

<!ifstats>
<h2><!statstitle><h2>

<h3><!topcommenterstitle></h3>
<!topcommenter>
<p><!iftie>--<!/iftie>
<!ifnotie><!topcommenterposition>.<!/ifnotie>
<!topcommentername>
[<!topcommenterscomments>: <!topcommentercommentcount>]</p>
<!/topcommenter>

<h3><!statsnumberstitle></h3>
<!statistic>
<p><!statisticname>: <!statisticvalue></p>
<!/statistic>
<!/ifstats>

All code between <!ifstats> and <!/ifstats> is only displayed when statistics are available. The only reason why statistics would not be available is because no comments have been posted, but we have to account for it.

The <!statstitle> tag obviously stands for the title of the statistics section. Then come the two main sections of the statistics, namely the list of top commenters and some interesting numbers.

First, let's look at the top commenters. Insert the title for that section with <!topcommenterstitle>. The actual list is formed by repeating the code between <!topcommenter> and <!/topcommenter>. Insert the commenter's name using <!topcommentername>. The number of comments he or she posted is represented by <!topcommentercommentcount>, and the title for that information is <!topcommenterscomments>; note that you can also use that tag as the title of the column and such. Finally, <!topcommenterposition> stands for the commenter's rank. Sometimes, multiple commenters have posted the same number of comments, and you can enter separate code for this case between <!iftie> and <!/iftie>; if the commenter's comment count differs from the preceding one, on the other hand, the code between <!ifnotie> and <!/ifnotie> is inserted.

And finally, the numbers… To style this list of name/value pairs, you just provide the code that needs to be repeated for each pair, between <!statistic> and <!/statistic>. The <!statisticname> tag will obviously be replaced with a description of the information being displayed, and <!statisticvalue> with the actual information. And to give this section a nice title, there's the <!statsnumberstitle> tag.

Notes

Got a question?

If any part of this documentation isn't entirely clear, don't hesitate to contact support.

Send in your themes

The Symbio site will soon have a nice listing of available themes, but for now, please send in your themes via e-mail. Be sure to make a compressed archive, as I am keen on my bandwidth.