HTML Logo by World Wide Web Consortium (www.w3.org). Click to learn more about our commitment to accessibility and standards.

ocPortal Tutorial: Tempcode programming

Written by Chris Graham, ocProducts
Tempcode is ocPortal's template programming language. On the simplest level, it provides a substitution mechanism so that parameters and global symbols (like the current user's username, or the time) can be inserted into a template. It also serves as a complete programming language with a powerful set of control mechanisms.


Philosophy

Most templating languages will try to either:
  • use XML, to add programming constructs into the mark-up itself
  • allow PHP code, or an abstraction of PHP code, to run within the templates

Our approach is distinctly different, as we uphold four strong principles:
  • templates should be editable in an HTML editor without Tempcode being broken (although the HTML editor at this time must be able to support 'fragments of HTML')
  • templates should not contain code on the same level as PHP, for security reasons (a theme should not be able to delete files, for instance)
  • there should be a very clear separation of role between templates and code; code should not be put into templates simply because it is convenient, as this muddies the architecture, causing maintenance issues
  • templates should not 'execute': Tempcode should act as a filter/token-placer for output, reshaping output, rather than intertwining code with it. This is again, an architectural issue

Due to our design principles, Tempcode is a very unusual language, with a very simple syntax.

Advanced philosophy (experts only)

For those interested in 'programming language semantics', Tempcode is neither a functional or imperative language, but has aspects of both. A functional language essentially is focused on output being controlled by a complex mathematical expression. An imperative language essentially is focused on output being controlled by a sequence of commands. With Tempcode, output is focused on the stream of text coming from a template, and the composition of these streams; 'symbols' and 'directives' can control, manipulate and add to the stream, but they are more like embedded functional-language function-chains and control-tags than imperative code. Sequences of commands can be simulated by placing symbols and directives next to each other in the output stream and using variable manipulation features to bridge data across the portions of the output stream.

Popular template languages such as 'Velocity' or 'Smarty' are able (and often used) to function in a similar sense to this, but their language design is imperative at core, and the result simply is just far less elegant. Tempcode just 'feels right', with its clean syntax and PHP-separation, whilst other languages look literally like conventional programming code has been added inside the template in an ad-hoc way (even if the full programming syntax has been simplified a bit).

Syntax

Tempcode provides four constructs other than the plain text of the template itself:
  • Parameters: {PARAMETER} where PARAMETER is a code-name of something that was actually passed to the template
  • Language strings: {!STRING,<parameters>...} where STRING is a real language string from a loaded language file (e.g. Banner code could use strings from banners.ini, but most other code could not; global.ini contains strings usable anywhere)
  • Symbols: {$SYMBOL,<parameters>...} where SYMBOL is a real symbol ocPortal supports. Embedding a symbol is like making a function call or running a command in the complex place, or a substitution in the simple case
  • Directives: {+START,DIRECTIVE,<parameters>...}...{+END,DIRECTIVE} where DIRECTIVE is a real directive ocPortal supports. Directives essentially wrap portions of the template, controlling that portion; they are generally used for types of condition checking (e.g. IF) or loop. There are also directives like {+IMPLODE,<parameters>...} that do not wrap, but work outside the normal "string manipulation" bounds that symbols do

Any Tempcode construct may be escaped (made to fit in an encoding scheme, such as HTML or  URLs, such that special text characters do not interact with that encoding scheme in an insecure/corrupting way) by escaping filters with ease, just by placing the symbol associated with the mode of escaping before the closing '}'. The following escaping filters are provided:
  1. * HTML   (or = if you are 100% sure you want the data escaping, even if it comes from something that might already be in HTML)
       (e.g. Hello & Goodbye  →  Hello &amp; Goodbye)
  2. ; Between single quotes
       (e.g. Who's here  →  Who\'s here)
  3. # Between double quotes
       (e.g. She said, 'Hello'  →  She said, \'Hello\')
  4. ~ Where new lines are not allowed
       (text is drawn up to reside on a single line)
  5. @ Comcode
       (e.g. Use the \[url] tag  →  Use the \\\[url] tag)
  6. ' CSS
       (anything that isn't a part of a very constrained non-string value is stripped)
  7. / Special Javascript SGML-issue
       (e.g. print('</p>');  →  print('<\/p'))
  8. ^ Where new lines become '\n'
       (multiple lines drawn together with \n as a separator)
  9. & URL parameters   (or . if you don't want extra ocPortal URL escaping to happen)
       (e.g. a&b  →  a%26b)
  10. | Javascript IDs
       (e.g. This is a -terrible- ID  →  This__is__a____terrible____ID)
  11. % Strict codenames
       (e.g. ThiSThiS   but  This is  –> [[hack attack]] triggered)
You can also use - to indicate that a symbol should not be pre-processed, which is very occasionally useful if you want to stop something like a block being preloaded if it is buried under a Tempcode IF directive and hence doesn't always run. Stopping pre-processing will stop any Javascript or CSS dependencies being called up, however.

It is absolutely crucial that Tempcode programmers use the proper escaping. Without it, all kinds of insecurities and unreliabilities can develop. About 50% of parameters in the default ocPortal templates actually use HTML escaping so that plain text placed inside a template does not interfere with the HTML structure itself and displays literally.

The Tempcode tree

Templates are composed together into a tree structure, and then the tree structure is output. This is discussed in further detail in the 'site structure' tutorial.

Placing theme images

To insert an image into your template, use ocPortal's image parameter: {$IMG,codename}. Replace codename with the image code for the image you want to use. This will turn into the image's URL. Be aware that this does not insert any HTML for you, so to use it fully:

Code

<img src="{$IMG,page/delete}" alt="Delete This" title="Delete This" />
This would insert the image http://www.mywebsite.com/themes/default/images/page/EN/delete.png into your page.

The advantage to using the ocPortal code instead of hand coding the image is two-fold. First, you'll notice that it is able to automatically detect the theme and language that is currently in use (in this case, the default theme and English). Secondly, if you ever move the image, you don't have to edit every page that ever used it to point to the new location. You can edit images from within the themes management screen (go to the "Styles" section of the Admin Zone, then the "Themes" icon).

Numbers and logic

Tempcode is an entirely string based language. It does, however, provide significant logic and number functionality, which is made possible by conversion from text as symbols require. Numbers are read directly, and should not contain any special formatting other than the British English decimal point (.) symbol. 'True' is encoded as '1' and 'False' is encoded as '0'.

Symbols

Notes

If a symbol is missing important parameters, it generally is skipped.

Some of the more advanced symbols are not fully laid-out, but they are all defined in sources/symbols.php in an obvious way, so advanced users can read this file.

You are very unlikely to ever want to use rows in red, as they are intended for use by core ocPortal code.

Tempcode does not have explicit data-types, everything is text. However we may interpret the text in symbols as follows:
  • Tempcode number: the text is assumed to be a number written as a normal decimal string (e.g. 12345)
  • Tempcode boolean: the text is assumed to be 0 (meaning false) or 1 (meaning true)

General

Symbol name / example Purpose
(blank) Place a comment. E.g.... {$,this is a comment}
{$RAND} A random number between 0 and 32000
{$SET_RAND,a,b,c} A random choice from the given parameters
{$CYCLE,cyclename,a,b,c} Cycle through parameters in a sequence (intended for use across template calls to create, for example, striping effects). The first parameter is the name of the cycle, and the following parameters are the parameters of the cycle. The pointer for the named cycle will move forward/around each time the cycle symbol is referenced (e.g. {$CYCLE,mycycle,a,b,c,d} would produce "a" the first time it's called, "b" the next, "c" next, then "d", then back to "a" again). If you only provide one parameter then the cycles current index is returned. If only two parameters are provided then the second parameter is split up by commas; this is useful for programming cycles on a higher level (e.g. for making chequered patterns using floats).
{$RESET_CYCLE,cyclename} Reset a named cycle sequence.
{$MAILTO} Get an obfuscated "mailto: " string (obfuscated to make it hard for e-mail scavengers to detect)
{$HONEYPOT_LINK} If a Project Honeypot script is installed, this will insert a link to it, using a different method for different page names to increase the likeliness of a bot snag.
{$INSERT_SPAMMER_BLACKHOLE} If spammer blackholes are enabled, this inserts a field into a form to create the blackhole. Blackholes allow automatic detection and banning of would-be spammers.
{$CSS_DIMENSION_REDUCE,30px,2} Reduce a CSS dimension by a certain number of px. If the input is not in px, no function is performed and the output stays as the input.
{$BETA_CSS_PROPERTY,<css rule>} Adds browser vendor prefixes to a CSS rule that is not widely supported yet. This effectively marks the CSS rule out, and theoretically allows new ocPortal versions to alter how that rule is handled without direct changes to your theme CSS.
{$REQUIRE_JAVASCRIPT,javascript_example} Include a Javascript file in the output stream
{$FACILITATE_AJAX_BLOCK_CALL,block code,differing parameters} This symbol generates a string parameter suitable for the ocPortal Javascript call_block function, which is used to make an AJAX call to load up a block and overwrite the contents of a specific div with it. Calling this symbol has the side-effects of triggering an include of ocPortal's AJAX code, and setting up a permission so that the server-side AJAX handler knows that the current session is authorised to load up this pattern of block. The symbol is best used by example -- see how it is currently used by code.
{$REQUIRE_CSS,css_example} Include a CSS file in the output stream
{$URLISE_LANG,string,http://example.com/,This is a tooltip,1} Wrap a URL into a specially encoded string (usually this is a reference to a language string). The last parameter is '1' if the link should go to a new window.
{$SPECIAL_CLICK_TO_EDIT} Get a message, appropriate to the user's web browser, saying how to do the 'magic keypress' (the Javascript detected keypress ocPortal uses to perform special functions like calling up the theme image editor)
{$ANCHOR,anchorname} Place a named HTML anchor (intended for use from in Comcode)
{$CSS_TEMPCODE} Get the Tempcode for all the CSS includes for this page
{$PAGE_TITLE} Get the currently set page title/td>
{$SET_TITLE,xxx} Set the current page title (affects things like the <title&rt;
{$EXTRA_HEAD} Get the contents of this global Tempcode variable (used by some parts of the system to inject extra markup)
{$EXTRA_FOOT} Get the contents of this global Tempcode variable (used by some parts of the system to inject extra markup)
{$JS_TEMPCODE} Get the Tempcode for all the JS includes for this page


Format conversion and obfuscation

Symbol name / example Purpose
{$ESCAPE,what_to_escape,optional_escaping_type} Perform escaping on the first parameter. Uses the same escaping as integrated template escaping, except a numeric constant (defined in the second parameter) is used to determine the escaping, rather than special characters (see sources/tempcode.php for a list of all the constants). Defaults to HTML escaping.
{$OBFUSCATE,to_obfuscate} Obfuscate a string to make it harder for e-mail scavengers
{$FIX_ID,something to make an ID} Perform escaping similar to ID escaping (convert an arbitrary string into something that can be used as an XML ID (e.g. "*" becomes "_star_").
{$STRIP_TAGS,<strong>example</strong>} Remove HTML from some text
{$ENTITY_DECODE,this &amp; that} Decode XML or HTML entities, so that written-out XML turns into actual parsed XML
{$TRUNCATE_LEFT,something long,5,1,0,0,0.2} Truncate a string, keeping what's on the left as priority. First parameter is the text to truncate. Second parameter is the truncation length. Optional third parameter is a binary value for whether to show a tooltip. Optional fourth parameter is a binary value for whether the input text is already in HTML format (output text is always in HTML format). Optional fifth parameter is a binary value for whether the length desired should be based on readable characters rather than XHTML characters. Optional sixth parameter is a decimal fraction (e.g. 0.2) that represents the tolerance that can be used to preserve grammar (paragraphs and sentence).
{$TRUNCATE_RIGHT,something long,5,1,0,0,0.2} As above, truncating to keep what's on the right as priority.
{$TRUNCATE_SPREAD,something long,5,1,0,0,0.2} As above, truncating to keep an equal left/right portion.
{$TRUNCATE_EXPAND,something long,5,1,0,0,0.2} As above, with any truncated text going underneath an expander.
{$ALTERNATOR_TRUNCATED,something long,5,if truncated,if not truncated,1} A complex symbol to allow alternation between situations when something would and would not become truncated.
{$PARAGRAPH,something} Add a paragraph around the contents, but only if it does not already contain any block-level elements. This is needed to combine valid (X)HTML for arbitrary Comcode insertion with the desire to have neat semantics and automatic margining.
{$CLEAN_FILE_SIZE,10000} Convert a number of bytes into a nice clean human readable file size.
{$TRIM, abc } Trim any textual or XHTML white-space from the given string.


Users, Members, and Usergroups

Symbol name / example Purpose
{$USER} The Member-ID of the current user
{$IS_GUEST} Whether the current user is a Guest
{$USERNAME,2} The username of the current user / given user (optionally takes a member ID, otherwise assumes the current user)
{$AVATAR,2} The member's avatar (optionally takes a member ID, else assumes current user)
{$MEMBER_EMAIL,2} The member's email address (optionally takes a member ID, else assumes current user)
{$PHOTO,2} The member's photo (optionally takes a member ID, else assumes current user)
{$MEMBER_PROFILE_URL,2} The member's profile URK (optionally takes a member ID, else assumes current user)
{$OCF_MEMBER_HTML,2} The member's information box (optionally takes a member ID, else assumes current user)
{$OCF_RANK_IMAGE,2} The member's rank images in composed HTML format (optionally takes a member ID, else assumes current user)
{$IS_IN_GROUP,1-3} Find whether the current member is in a usergroup (parameters together constitute an [concept]ocFilter[/concept] list, except if the last is primary or secondary then this specifies that the check be limited to checking such usergroup membership).
{$CPF_VALUE,Some Custom Field} Find the value of a custom profile field (pass in the ID number of a custom profile field, which can be found from the URL of where you to edit it -- or pass in the human-readable name of the field; if you pass a name it can also interpret translated/Comcode text fields properly). If you pass a second parameter, it will specify the member ID to use (if not passed, it will default to the current member).


Date and time

Symbol name / example Purpose
{$DATE_AND_TIME} The formatted current date and time (may take optional parameters, not discussed here)
{$DATE} The formatted current date (may take optional parameters, not discussed here)
{$TIME} The formatted time (may take optional parameters, not discussed here)
{$SECONDS_PERIOD,12345} Show the number of hours/minutes/seconds in a given period of seconds
{$FROM_TIMESTAMP,%d %B %Y,123456780} Converts a time-stamp to a formatted date/time (optional first parameter is a strftime-style date/time formatting string, optional second parameter is a timestamp). If no parameters given it will simply return the current timestamp.
{$TO_TIMESTAMP,April 1st 2009} Converts a formatted date/time to a timestamp via auto-recognition (first parameter is a timestamp). If no parameters given it will simply return the current timestamp.
{$MAKE_RELATIVE_DATE,123456789} Converts a timestamp into a textually described relative time (e.g. "10 minutes" [ago]).
{$TIME_PERIOD,1234} Converts a number of seconds into a textually described time period (e.g. "10 minutes").


Catalogues

Symbol name / example Purpose
{$CATALOGUE_ENTRY_BACKREFS,123} Get a comma-separated list of IDs of catalogue entries that reference the given catalogue entry. A second parameter may be given, which is a limit on how many to return. A third parameter may be set as the name of a content type if the backrefs should be resolved to linked content entries (for the case where the linkage is via custom fields rather than a pure catalogue). A fourth parameter of the rating type code may be given if sort-by-rating is needed (highest rated first).
{$CATALOGUE_ENTRY_FIELD_VALUE,123,0} Get the value of a field in a specific catalogue entry (example would be 1st field in entry #123).
{$CATALOGUE_ENTRY_FIELD_VALUE_PLAIN,123,0} As per CATALOGUE_ENTRY_FIELD_VALUE, but without any display processing on the value.
{$CATALOGUE_ENTRY_FOR,download,3} Get the ID of the auto-maintained catalogue entry bound to the given content entry, i.e. where the content entries custom fields are stored. This can then be used with the CATALOGUE_ENTRY_FIELD_VALUE symbol (above) or the CATALOGUE_ENTRY_ALL_FIELD_VALUES symbol (below).
{$CATALOGUE_ENTRY_ALL_FIELD_VALUES,123} Show a field-map view of all fields in the entry. You can also pass in a second param with the value '1' if you want raw field rows, rather than a table (useful for adding field-map data into an existing table).


eCommerce

Symbol name / example Purpose
{$CURRENCY,123,USD} Do a currency conversion / Get the currency (first parameter is a number for the amount in the site's default currency, second parameter is the source currency, optional third parameter is the target currency [defaults to the site currency])
{$CURRENCY_SYMBOL} Get the nice currency symbol for the site's default currency


Environmental querying

Symbol name / example Purpose
{$_GET,page} Extract the requested script GET parameter
{$QUERY_STRING} Extract all requested script parameters (the 'query string', i.e. part of the URL after "?")
{$_POST,title} Extract the requested script POST parameter
{$ZONE} The zone the user is in
{$PAGE} The page the user is in
{$CANONICAL_URL} Get the canonical URL (for search engines)
{$SELF_URL,0,0,0,a=b} Get URL to current screen. You don't need to give any parameters, but if you do: the first is whether to go to the website home page if you are at where you're at due to a form post, the second is whether to included posted parameters as parameters in the URL, the first is whether to avoid the short URL facility, and further parameters are additional URL parameters.
{$META_DATA,created} Fetch a defined dublin core meta data property (by code name), relating to the current content
{$REFRESH} HTML code for a site refresh, if one is in progress
{$FEEDS} HTML code for RSS/Atom feeds
{$RUNNING_SCRIPT,index} Find whether an entry script is running
{$MATCH_KEY_MATCH,_WILD:downloads:misc} Whether the given match-key matches the current URL
{$MOBILE} Whether a Smartphone (for example) is being used. ocPortal is designed to be pretty good at detecting this, but if you need to specify additional user agent strings you can make a text_custom/pdas.txt file with mobileuseragentsubstring=0|1 lines in it (e.g. iphone=1 for iPhone to be detected as mobile, and ipad=0 for iPad to not be detected as mobile). If you want to detect smartphones in CSS we suggest you either use this symbol (which the default theme uses) or if you prefer use CSS media queries inside your CSS files to create override rules
{$THEME} The user's current theme
{$JS_ON} Whether Javascript is enabled (Tempcode boolean)
{$LANG} The user's current language
{$BROWSER_UA} The user's browser, based on their user-agent string
{$OS} The user's OS, based on their user-agent string
{$DEV_MODE} Whether development mode is on (adds in extra errors, to pick up on coding standard violations)
{$NO_SAFE_MODE} Detect if PHP safe mode isn't on the server
{$IS_FRIEND,2,3} Detect if the second parameter/member ID (or current member if no second parameter) has befriended the first parameter/member ID.
{$BROWSER_MATCHES,wysiwyg} Find whether the current browser matches a named property / has a feature. Possible properties: wysiwyg, windows, mac, linux, mobile, opera, ie, ie8, ie8+, ie9, ie9+, gecko, konqueror, safari (covers Google Chrome also), ios, android, bot
{$USER_AGENT} The user-agent string of the current user
{$TIMEZONE} The server timezone
{$HTTP_STATUS_CODE} Find the HTTP status code (e.g. 404) for the current request, usually 200
{$BROWSER,wysiwyg,You have WYSIWYG,You do not have WYSIWYG} Conditionally chooses between two input strings, based on a browser property (see above for a list of properties). First parameter is the property, second and third are the conditional strings.
{$GEOLOCATE,12.45.67.89} Find the/a user's ISO country-code (optionally takes an IP address, otherwise defaults to current user's IP)
{$FORCE_PREVIEWS} Find whether the user has forced previews to show
{$PREVIEW_URL} Find the URL to perform a preview for the form on the current screen
{$CURRENTLY_INVISIBLE} Whether the current user is set to be invisible
{$CAN_SPELLCHECK} Whether spellchecking is possible
{$PREVIEW_VALIDATION} Whether validation is done upon previewing, by default
{$SESSION} Get the session ID for the current member
{$VERSION_NUMBER} Get the ocPortal version number
{$CHARSET} Get the character set
{$HEADER_TEXT} Get the header text (put in the page title)
{$SHOW_HEADER} Whether the header will be shown
{$SHOW_FOOTER} Whether the footer will be shown
{$WIDE} Whether the side panels will be shown
{$WIDE_HIGH} Whether the side panels, header, and footer, will be shown
{$LOGO_URL} The logo URL for the current zone
{$HAS_SU} Whether the current user is allowed to use the Switch User feature
{$STAFF_ACTIONS} A drop-down of contextual actions for the current screen
{$HELPER_PANEL_TUTORIAL} The helper panel's tutorial
{$HELPER_PANEL_PIC} The helper panel's picture
{$HELPER_PANEL_HTML} The helper panel's HTML
{$HELPER_PANEL_TEXT} The helper panel's text
{$MESSAGES_TOP} Attached messages, for prominent display
{$MESSAGES_BOTTOM} Attached messages, for less prominent display
{$LATE_MESSAGES} Attached messages that happened after output started (after main page generation). These will usually be errors relating to the output process itself.
{$BREADCRUMBS} The breadcrumbs
{$FORUM_CONTEXT} The ID of the forum currently within, or blank


Placement, and general ocPortal interfacing

Symbol name / example Purpose
{$FIND_SCRIPT} Find the URL to a named ocPortal entry script (e.g. 'dload')
{$FIND_SCRIPT_NOHTTP} Find the URL to a named ocPortal entry script (e.g. 'dload'), but as a relative URL to domain name root
{$IMG,bottom} Find a named theme image code's URL (takes the theme image code). Note that this gets the image URL, it does not write the HTML out for an image element based upon it (you need to do that yourself).
{$IMG_WIDTH,bottom} Find the width of the theme image/URL (particularly useful for making web pages render faster). Uses the persistent cache to remember values, if possible.
{$IMG_HEIGHT,bottom} Find the height of the theme image/URL (particularly useful for making web pages render faster). Uses the persistent cache to remember values, if possible.
{$KEEP,0,1} Stuff to append to an ocPortal URL for 'keep parameter' passing (ocPortal passes any parameters between screens if their names start 'keep_', and this symbol enables that). The first parameter should be '1' if you need to place this directly on the front of a URL. The second parameter should '1' if you need to always attach a session ID (i.e. if you are creating a link that might be used somewhere outside the current cookie context, e.g. to feed into a download manager)
{$KEEP_INDEX,0,1} As above, except this includes index.php as well as the parameters. It is rarely useful
{$BLOCK,block=main_search,zone=site} Place a block into the template. Takes any number of parameters (but at least 1 for the block name), each of which defines a block parameter and its value. Parameters must include the block name, which is encoded against the special reserved name 'block'. For example: {$BLOCK,block=main_news,filter=1\,2\,3}
{$LOAD_PAGE,about,site} Load a page into a template (first parameter is the page name, optional second parameter is the zone name which defaults to the current zone)
{$RATING,downloads,3} Show a content type's rating. The first parameter is the content-type's code (usually the page name it's viewed from, e.g. downloads) and the second parameter is the ID for the resource.
{$VIEWS,download_downloads,download_views,3} Show how many views a content type has had. The first parameter is the table to read from, the second parameter is the name of the field (it must contain 'views' -- the code will not allow arbitrary field calling for security reasons) the third parameter is the ID for the resource.
{$LOAD_PANEL,panel_left,site} Load a panel-page into a template (first parameter is the page name, optional second parameter is the zone name which defaults to the current zone)
{$PAGE_LINK,site:about} Link to a page, using [concept]page link[/concept] syntax (e.g. "_SELF:pagename:type:1")
{$ADDON_INSTALLED,galleries} Find whether an addon is installed (first parameter is the code-name of the addon)
{$AWARD_ID,2} Find the content ID assigned to the given award
{$NOTIFICATIONS_ENABLED,download,3} Find whether notifications are enabled for something


ocPortal configuration querying

Symbol name / example Purpose
{$SITE_NAME} The site name
{$HEADER_TEXT} The header text of the current screen, taken from current zone's setting unless content is being viewed specifies it
{$ZONE_HEADER_TEXT} The header text of the current zone
{$COPYRIGHT} The site copyright
{$STAFF_ADDRESS_PURE} The staff address, without obfuscation
{$STAFF_ADDRESS} The obfuscated staff address
{$DOMAIN} The domain name of the site
{$SITE_SCOPE} The site scope
{$BOARD_PREFIX} The forum base URL
{$BASE_URL} The base URL to the installation
{$CUSTOM_BASE_URL} The base URL to custom data in the installation (usually the same as BASE_URL)
{$BASE_URL_NOHTTP} / {$CUSTOM_BASE_URL_NOHTTP} The base URL to the installation, but just the path, no protocol or domain name. This is useful in JS files (which cache as strings, not Tempcode) because it doesn't cause JS security errors when HTTPS and HTTP variants of a site are both in action.
{$SSW} Whether Sunday is the start of the week (Tempcode boolean)
{$VALID_FILE_TYPES} Get a comma-separated list of valid file types
{$INLINE_STATS} Whether to show view/download counts inside the public visible website (Tempcode boolean)


ocPortal permission querying

Permission checks are useful if you want to show screen contents in a way that somehow reflects your configured permission scheme.
These are advanced symbols, and mirror ocPortal's internal API. The parameters are not discussed here, but you may find them from looking at the code.

Symbol name / example Purpose
{$IS_STAFF,2} Is the current user / given user staff (optionally give it a member ID else works on current member, returns Tempcode boolean)
{$IS_ADMIN,2} Is the current user / given user a super admin (optionally give it a member ID else works on current member, returns Tempcode boolean)
{$HAS_PRIVILEGE,submit_midrange_content} Member has a privilege (returns Tempcode boolean)
{$HAS_ZONE_ACCESS,adminzone} Member has access to a zone (returns Tempcode boolean)
{$HAS_PAGE_ACCESS,admin_stats,adminzone} Member has access to a page (but NOT necessarily the zone it is in) (returns Tempcode boolean)
{$HAS_ACTUAL_PAGE_ACCESS,admin_stats,adminzone} Member has access to a page and its zone (returns Tempcode boolean)
{$HAS_CATEGORY_ACCESS,downloads,3} Member has access to a category (returns Tempcode boolean)
{$HAS_ATTACHMENT_ACCESS,3} Member has access to an attachment (returns Tempcode boolean)
{$HAS_SUBMIT_PERMISSION,mid} Member has the specified kind of submit permission (returns Tempcode boolean)
{$HAS_DELETE_PERMISSION,mid} Member has the specified kind of delete permission (returns Tempcode boolean)
{$HAS_EDIT_PERMISSION,mid} Member has the specified kind of edit permission (returns Tempcode boolean)


ocPortal interfacing, specific/advanced features

Symbol name / example Purpose
{$TOTAL_POINTS,3} Get the total points the specified member has
{$POINTS_USED,3} Get the total points the specified member has used (spent).
{$AVAILABLE_POINTS,3} Get the total points in the specified member's account; some of these will probably have been spent already
{$FLAGRANT} Place the active flagrant text
{$OCF} Whether OCF is being used (returns Tempcode boolean)
{$HAS_FORUM,General Chat} Whether a forum is available (returns Tempcode boolean)
{$VERSION} The major version of ocPortal being used
{$USER_OVERIDE} The Member-ID of the Account being viewed (e.g. if you're staff looking in somebody else's Account then this would find the member ID, otherwise it is your own member ID
{$MANAGEMENT_NAVIGATION} The management navigation menu
{$COOKIE_PATH} Get the cookie save path
{$COOKIE_DOMAIN} Get the cookie save domain
{$IS_A_COOKIE_LOGIN} Find if a cookie login is active
{$BANNER,some_banner_type} Display a banner of specific type (first parameter is the banner type, second is an optional binary value for whether the banners should be limited to only internal banners)
{$ATTACHMENT_DOWNLOADS,3} Find how many downloads an attachment has had (first parameter is the ID number of an attachment)
{$COMMENT_COUNT,downloads,3} Find the number of comments made for a resource (first parameter is the resource type code, second parameter is the resource ID)
{$DOCUMENT_HELP} Get the URL to the help for the current screen (will be blank if there is none)
{$IMAGE_WIDTH,http://example.com/pic.png} Find the width of an image
{$IMAGE_HEIGHT,http://example.com/pic.png} Find the height of the image
{$THUMBNAIL,http://example.com/pic.png,40x60,galleries} Generate a thumbnail URL from another image URL


Thumbnail generation

The {$THUMBNAIL} tag is actually much more sophisticated and powerful than described above. It's full syntax is as follows…

Usage: {$THUMBNAIL,source_image,widthxheight,output_dir,filename,fallback_image,type,where,background,only_make_smaller}
where:
  • source_image is the URL to the full image
  • widthxheight is the desired width/height for the thumbnail. For types (see below) of width or height or crop you can omit either of the width or height for automatically calculated proportionality (e.g. x20 for just a height). If you specify both for crop it crops to the exact specified box rather than to the implied proportional box.
  • output_dir is the name of a directory under ocPortal's "uploads" directory
  • filename is the name of the thumbnail filename. If not provided it will be automatically chosen based on the source_image and an articulation of the thumbnail settings
  • fallback_image is the URL to the image to use if no thumbnail could be generated. If not provided the source_image will be used
  • type is either:
    • "width" for an image which is stretched to the given width and a height in proportion to that
    • "height" for an image which is stretched to the given height and a width in proportion to that
    • "crop" for an image which has been shrunk until one of its dimensions matched that given and the rest has been chopped off
    • "pad" for an image which has been shrunk until it completely fits within the given dimensions, and then padded out
    • "pad_vert_crop_vert" for an image that may only have cropping or padding done above/below and therefore gets stretched to force that to be the case
    • "pad_horiz_crop_horiz" for an image that may only have cropping or padding done left/right and therefore gets stretched to force that to be the case
  • The "where" argument is not needed for "width" or "height" type thumbnails. For "crop" & "pad" types it is where to crop/pad:
    • "start"
    • "end"
    • "both" (assuming bottom-to-top and right-to-left)
    • If the "where" option is ommitted for cropped thumbnails then it will be centred. For padded thumbnails it will resize the image to get rid of any need for padding (ie. "padding none").
  • For "pad" types the background is used to pad the image:
    • a hex code for a specific color (with alpha)
    • or, "none" for no padding (ie. the image dimensions are not those given, but will fit inside them).
    • or, if the option is omitted for padded thumbnails then the average color of the image is used.
  • only_make_smaller can be set to "1" if the image should not be resized at all if it is already smaller than the requested thumbnail size

Logic

Note that all logic symbols return Tempcode boolean values (except ?). This makes them suitable for nesting with each other, or using with the 'IF' directive.
Understanding of these symbols requires an understanding of basic boolean operations but they are fairly intuitive (e.g. 'AND' will return true if all its parameters are true).

Symbol name / example Purpose
{$?,1,shows if true,shows if not true} Do an inline IF test, outputting the second parameter if the first evaluates to true and the third (optional parameter) if it does not
{$NOT,1} Boolean NOT (pass in one Tempcode boolean to get the opposite boolean out)
{$OR,1,1} Boolean OR (pass in any number of Tempcode booleans to check that one is true)
{$NOR,1,1} Boolean NOR (this is the same as {$NOT,{$OR,...}})
{$XOR,1,1} Boolean XOR (pass in two Tempcode booleans to check that just one of them is true but not both of them)
{$NAND,1,1} Boolean NAND (this is the same as {$NOT,{$AND,...}})
{$AND,1,1} Boolean AND (pass in any number of Tempcode booleans to check they are all true)
{$EQ,a,b} Test for string equality (pass in any number of strings to check they are all the same)
{$NEQ,a,b} Test for string inequality (this is the same as {$NOT,{$EQ,...}})
{$LT,1,2} Test for numerical less-than inequality (pass in a Tempcode number)
{$GT,1,2} Test for numerical greater-than inequality (pass in a Tempcode number)
{$IS_EMPTY,this obviously is not blank} Find whether a string is blank
{$IS_NON_EMPTY,this obviously is not blank} Find whether a string is not blank


Arithmetic

Symbol name / example Purpose
{$NEGATE,3} Negate a number
{$MULT,3,3} Multiply two numbers
{$ROUND,3.2} Round a number
{$MAX,3,4} Find the maximum between two numbers
{$MIN,3,4} Find the minimum between two numbers
{$MOD,3} Make the given number positive (e.g. -3 becomes 3, 3 becomes 3)
{$REM,10,3} Find the remainder if the first number is divided by the second
{$DIV,10,3} Divide two numbers
{$SUBTRACT,4,3} Perform a subtraction
{$ADD,4,3} Add two numbers


String manipulation

Symbol name / example Purpose
{$REPLACE,exemplar,something,this is exemplar} Do a string replace (three parameters: what's being replaced, what's being replaced with, what's being replaced in)
{$AT,something,3} Extract a string character (first parameter is the string, second parameter is the index of the character to get counting from 0)
{$STRPOS,something,hi} Find the position of a string sub-string (first parameter is the search string, second parameter is the substring, returns Tempcode number)
{$IN_STR,something,in} Find whether a sub-string is in a string (first parameter is the search string, second parameter is the substring, returns Tempcode boolean
{$SUBSTR_COUNT,abacus,a} Find how many times a substring appears (first parameter is the search string, second parameter is the substring, returns Tempcode number)
{$SUBSTR,something,2,2} Extract a string sub-string (first parameter is the string, second parameter is the index of where to extract from, third parameter is the extraction length)
{$LENGTH,something} Find the length of a string (give it a string, returns a Tempcode number)
{$PAD_LEFT,12,4,0} Pad something out on the left. This example produces 0012
{$PAD_RIGHT,12,4,0} Pad something out on the right. This example produces 1200
{$WCASE,A b C} Convert string to word case
{$LCASE,A b C} Convert string to lower case
{$UCASE,A b C} Convert string to upper case
{$WORDWRAP,blah blah blah,4,<br />,1} Word-wrap a string (first parameter is the string, second parameter is the maximum line length, optional third parameter is the divider string which defaults to an HTML line-break, optional fourth parameter is a binary value specifying whether to force hard cuts)
{$PREG_MATCH,\d,1 2 3} See if something matches a regular expression (first parameter is the regexp, second parameter is the subject string)
{$PREG_REPLACE,\d,a,1 2 3} Perform a regular expression replace (first parameter is the regexp, second parameter is the replacement string, third parameter is the subject string)
{$REVERSE,a\,b\,c} Reverse a comma-separated list
{$COMMA_LIST_GET,a=1\,b=2,a} Find a value from a comma-separated list.
{$COMMA_LIST_SET,a=1\,b=2,a,2} Set a value in a comma-separated list.
{$NUMBER_FORMAT,1234} Make a number (integer) look nice, with commas etc (takes a Tempcode number)
{$FLOAT_FORMAT,1234.5678} Make a decimal number look nice, with commas etc, to 2 decimal places (takes a Tempcode number)
{$TEMPCODE,{$USER}} Evaluates the given parameter as Tempcode (takes a string). This is useful for very rare situations where you want to write in symbols as parameters to Comcode tags where the parameter is treated as a plain-string. This is only useful in Comcode, when typing Tempcode you can nest Tempcode constructs almost however you like.
{$COMCODE,[b]Comcode[/b]} Evaluates the given parameter as Comcode (takes a string). This is useful in conjunction with the above (TEMPCODE), as anything passed into a symbol won't be evaluated as Comcode.


Tempcode variables

You can store and retrieve values in Tempcode variables. These work across templates, and also work in any-order due to the ocPortal Tempcode pre-processor (i.e. something can be SET after the GET for it).

Symbol name / example Purpose
{$ISSET,test} Find whether a Tempcode variable is set (give it the name of a variable, returns Tempcode boolean)
{$INIT,test,1} Initialise a Tempcode variable to a value, but only if it is not yet set (give it the name of a variable, and a value, returns nothing)
{$SET,test,1} Set a Tempcode variable to a value (give it the name of a variable, and a value, returns nothing). Bear in mind that the ocPortal Tempcode-preprocessor will likely cause your code to run once in every code branch before it outputs (meaning even code inside IF directives that never are true will still pre-process), and once again as it outputs. So always reinitialise your variables in your template to make sure they are not dirty from the pre-processing stage. This behaviour may seem strange, but it is necessary for performance, comprehensive caching, and reasons of ocPortal needing conditionless output foresight.
{$SET_NOPREEVAL,test,1} As above, but with no pre-processing.
{$GET,test} Get the value of a Tempcode variable (give it the name of a variable, returns the value)
{$THEME_WIZARD_COLOR,#RRGGBB,name,equation} Sets a theme wizard colour that can be retrieved from name as a Tempcode variable. The equation is actually ignored during Tempcode evaluation but is picked up by the Theme Wizard.
{$INC,test} Increment a Tempcode variable (give it the name of a variable, returns nothing)
{$DEC,test} Decrement a Tempcode variable (give it the name of a variable, returns nothing)


Directives

Directive name Purpose
BOX These allow the 'standard box' layout convention to be used without duplicating a lot of HTML in different templates. CSS could never provide this itself, as the box 'styling' actually involves a large chunk of complex structure.
The parameters to the directive are (all may be blank or left out):
  1. the title (blank means no title is used)
  2. the type of the table (there will be a template, STANDARDBOX_<type> for any valid type code; the default is 'default'). default and accordion come as standard.
  3. the CSS width
  4. '|' separated list of options (meaning dependant upon templates interpretation)
  5. '|' separated list of meta information (key|value|key|value|...) (e.g. Name|Allen|Gender|Male|Country|USA)
  6. '|' separated list of link information (linkhtml|...) (e.g. <a href="http://ocportal.com">ocPortal</a>|<a href="http://ocproducts.com">ocProducts</a>)
  7. the links added to the top left of the box (Defaults to false)
CSS_INHERIT Include another theme's CSS into your CSS file, so you only need to specify differences. The parameters are: CSS file name, theme name, seed colour [optional]. The contents of the directive should be left blank.
IN_ARRAY See if something is contained in an array
INCLUDE Include a template in another and pass parameters (this makes a template very much like a function in a conventional programming language)
WHILE Do a loop until the Tempcode boolean used as the directive parameter evaluates to false.
LOOP Do a loop over a list of map arrays. This is a very complex directive, and not used much in default templates. If has support for automatic columnisation and sorting. In the content, references to [tt]loop_key[/tt] and [tt]loop_var[/tt] can be used, to refer to the current iteration's key and value, respectively. If the array is multidimensional, parameters can be used with the names of the keys in the second-level array in the current iteration. You can also pass in a comma-separated list of numbers to loop over.
IF_PASSED/IF_NON_PASSED Find if a named parameter was passed (Do not encase the parameter with {})
IF_PASSED_AND_TRUE/IF_NON_PASSED_OR_FALSE Find if a named parameter was passed and it's truth state (useful for robust optional boolean parameters that default to false)
IF_EMPTY/IF_NON_EMPTY Find if some Tempcode evaluates to empty. This is extremely useful, as it allows you to, for example, now show a table if it has no rows passed in. From a programming point of view, it allows us to avoid making new templates and improve accessibility compliance.
IF_ARRAY_EMPTY/IF_ARRAY_NON_EMPTY Find if an array is empty.
IF_ADJACENT/IF_NON_ADJACENT This allows templates to be context dependant. For example, if a template starts of using a <li> tag to make a list, but someone wants to change it to simply put '|' characters between entries, then IF_ADJACENT could be used so as to not add a '|' at the start of the first entry in the lit.
IF This simply tests a condition. This condition is often generated by nesting symbols together. For example, {+START,IF,{$EQ,{A},{B}}}...{+END}
OF This is a non-wrapping directive that extracts a string from an array at a certain array position.
IMPLODE This is a non-wrapping directive that turns an array into a string by placing a separator between each element.
COUNT Find the number of elements in an array.
SET Like the SET symbol, but sets with surrounded block of code rather than the second parameter.
RECONTEXTUALISE_IDS Prefixes all the IDs contained within (prefix is given as the first parameter). Reassociates form labels correctly. This directive is useful if you need to have the same form on an HTML page more than once.
PARAM_INFO Shows all parameters in the current scope. Very useful for debugging what goes into a template. Use without and directive contents like, {+START,PARAM_INFO}{+END}
FRACTIONAL_EDITABLE Used to make a string of some content editable inline (usually, the title as shown in the index).
IF_IN_ARRAY,example,PASSED_IN_ARRAY,output if it is Output something if something is in an array. This only works with arrays passed into templates. First parameter is a string to check for, second parameter is the name of an array, third parameter is what to output.
IF_NOT_IN_ARRAY,example,PASSED_IN_ARRAY,output if it is not Opposite of IF_IN_ARRAY


Examples

The most important directives are:
  • IF_NON_EMPTY
  • IF_EMPTY
  • IF

IF_NON_EMPTY

This directive is commonly used when a box or explanation needs placing around something, unless that something happens to be blank (empty).
For example, the following is a fairly typical thing to see in a template:

Code

{+START,IF_NON_EMPTY,{DOWNLOADS}}
   <p>We have the following downloads:</p>
   {DOWNLOADS}
{+END}

The IF_NON_EMPTY template evaluates {DOWNLOADS}, to see if it is blank. If it is not blank, the contents of the directive is output, otherwise nothing happens.
As you can see from this example, we need to check for emptyness so we don't show a boxed message about downloads that refers to nothingness.

IF_EMPTY

An alternative approach to the above example is to include a special message upon emptyness, rather than skipping over. We might do this if the content being displayed is critical and thus the emptyness must be explicitly acknowledged:

Code

<p>We have the following downloads:</p>
{DOWNLOADS}
{+START,IF_EMPTY,{DOWNLOADS}}
   <p class="nothing_here">(none)</p>
{+END}

Note here how we are displaying {DOWNLOADS} even if it is empty. Obviously if it is empty, nothing would display, so we can get away with it. If we were being pedantic we might have wrote the following:

Code

<p>We have the following downloads:</p>
{+START,IF_NON_EMPTY,{DOWNLOADS}}
   {DOWNLOADS}
{+END}
{+START,IF_EMPTY,{DOWNLOADS}}
   <p class="nothing_here">(none)</p>
{+END}
and arguably this does better demonstrate what we're trying to do, even though the behaviour is the same (ignoring invisible differences in HTML white-space).

It's often useful to be a bit clever with the emptyness-checking directives. For example:

Code

<p>We have the following downloads and images:</p>
{DOWNLOADS}
{IMAGES}
{+START,IF_EMPTY,{DOWNLOADS}{IMAGES}}
   <p class="nothing_here">(none)</p>
{+END}

In this example, the directive checks if the {DOWNLOADS}{IMAGES} is blank, which is exactly the same as checking if they are both blank (because blank next to blank is still just blank).

IF

The 'IF' directive allows particular complex calculations to be done. For a simple example, we can replicate the trick in the last example in a more formal way:

Code

<p>We have the following downloads and images:</p>
{DOWNLOADS}
{IMAGES}
{+START,IF,{$AND,{$IS_EMPTY,{DOWNLOADS}},{$IS_EMPTY,{IMAGES}}}}
   <p class="nothing_here">(none)</p>
{+END}

This checks to see if "DOWNLOADS is empty and IMAGES is empty".

Tempcode uses what is called a "prefix notation", and is similar to the way you write mathematical functions. For example, in common maths:

Code

f(a,b)
is how you would write "evaluate function 'f' with parameters 'a' and 'b'.
In the similar Tempcode notation you would write (assuming 'A' and 'B' are template parameters and 'F' is a real Tempcode symbol):

Code

{$F,{A},{B}}

Here's another 'IF' directive showing a more complex computation:

Code

{+START,IF,{$LT,{ADD_DATE_RAW},{$SUBTRACT,{$FROM_TIMESTAMP},86400}}}
   <p>This content on {$SITE_NAME} is more than one day old.</p>
{+END}

Background: a unix timestamp is a common measurement of time on computers- it represents the number of seconds since 1970 and because of its nature as a simple decimal number, is very useful for performing arithmetic.
This example checks to see if ADD_DATE_RAW is less than the current unix timestamp minus 86400. 86400 is the number of seconds in a day, so in other words the example checks to see if ADD_DATE_RAW is at least a day in the past. Because ADD_DATE_RAW is often passed into templates that display content, it checks to see if the content is at least a day old.

I threw {$SITE_NAME} into the example just to demonstrate symbols are not only for use in IF directives- this one is being used to perform a simple placement of the website name. All symbols do is compute results, so those results might be used for further computations as parameters to computational symbols (such as 'SUBTRACT'), or they might be passed into a directive, or they might be simply output. It merely depends on where they are placed.

Tempcode is extremely powerful, and hopefully now you can see how symbols, directives, and parameters, can come together to allow great things to happen!

See tempcode_test.tpl for more examples on how to use symbols and directives.

GUIDs

There is a design issue that comes to us when we design template structure… do we re-use templates so that editing is easier, load is decreased, and consistency is raised; or do we allow maximum customisation of different aspects of the system by not re-using templates?
We have tended to stick to a middle ground between these extremes, and re-used templates when the usage pattern was almost identical. For example, almost all of ocPortal uses the same form field templates, but Wiki+ posts use different templates to forum posts. However, there are still places where we re-use templates in situations that sites may wish to develop in separate directions.

The solution to this is to make use of the GUID each template usage is given when it is used.
Each 'do_template' call in ocPortal, which loads up a template, passes in a parameter, '_GUID'. The GUIDs may then be used along with tempcode directives to control what the template outputs.
The template editor has special support for the GUIDs, showing what GUIDs a template is used with and providing links to view the code associated with each GUID. It also provides a feature to automatically insert an 'IF' directive that differentiates against one of the GUIDs to provide a place to put output that will only be shown for it.

If you enter the template editor from the 'Template tree' screen then you will be told the GUID that was used by the node in the tree that you selected.

Concepts

symbol
A special element that may be inserted into
parameter
A parameter to a template; only parameters that the code calling the template supports may be used
directive
A tool used to surround an area of a template between a START and an END, to apply something to it (such as only using it conditionally)
variable
Two uses: 1) Either of a parameter, symbol, directive or language string reference. 2) A named piece of memory used by Tempcode symbols that manipulate variables.

See also