Translations
Info
All page names need to be in English.
en da  de  fr  it  ja  km  nl  ru  zh

Ts45min

From TYPO3Wiki
Jump to: navigation, search
Extension detail information
doc_tut_ts45
Learn the fundamentals of TypoScript in just 45 Minutes.
documentation state stable document state list
licence OCL
forgeproject
mailinglist
usergroups list of usergroups forAdmins, forBeginners, forIntermediates
author(s) Official Documentation
TER category doc
dependency

<< Back to Extension manuals page

[edit]


TypoScript in 45 Minutes

Extension Key: doc_tut_ts45

Language: en

Keywords: forAdmins, forBeginners, forIntermediates

Copyright 2008-2013, Documentation Team, <documentation@typo3.org>

This document is published under the Open Content License available from http://www.opencontent.org/opl.shtml

The content of this document is related to TYPO3 - a GNU/GPL CMS/Framework available from www.typo3.org

Official documentation

This document is included as part of the official TYPO3 documentation. It has been approved by the TYPO3 Documentation Team following a peer review process. The reader should expect the information in this document to be accurate - please report discrepancies to the Documentation Team (documentation@typo3.org). Official documents are kept up-to-date to the best of the Documentation Team's abilities.

Tutorial

This document is a Tutorial. Tutorials are designed to be step-by-step instructions specifically created to walk a beginner through a particular task from beginning to end. To facilitate effective learning, Tutorials provide examples to illustrate the subjects they cover. In addition, Tutorials provide guidance on how to avoid common pitfalls and highlight key concepts that should be remembered for future reference.

Introduction

About this document

This document is meant to give a short introduction to how TypoScript works and what TypoScript really is. It shall help to give a profound understanding of the code, instead of just supplying snippets for copying and pasting.

Feedback

For general questions about the documentation, write to documentation@typo3.org.

If you find an error in this manual, please file an issue in this manual's issue tracker.

Maintaining quality documentation is hard work and the Documentation Team is always looking for volunteers. If you feel like helping, please join the documentation mailing list (typo3.projects.documentation on lists.typo3.org).

TypoScript - a quick overview

Introduction

The goal of this introduction is not to leave you with the thought, "Finally, it's working!", but with the thought of, "Finally, I get it!" In other words, this introduction is designed to give you a comprehensive understanding of how TypoScript works.

A common TYPO3 workflow used by beginners is to try arbitrary properties to objects until things somehow begin to work. Actually understanding TypoScript however allows you to work more quickly and effectively, and working with TYPO3 becomes more productive and less of a strain. Troubleshooting is easier and time is saved by learning TypoScript properly. Otherwise you are dependent on luck and accident.

The goal of this introduction is not to have a running TYPO3 installation at the end, but to offer an explanation of why and how TypoScript works.

Backend configuration

TypoScript influences many aspects of a TYPO3 site:

TypoScript can be used in the TSconfig field of a backend user or a backend user group or in the TSconfig field of a page. It will then change the look and behavior of forms in the backend.

The frontend rendering in contrast is defined by the TypoScript in the TypoScript template. This document only covers frontend rendering and only with TypoScript in general.

Prerequisites

We assume that the reader has a TYPO3 system up and running and that the basic operations are known. The difference between pages and content elements will not be elaborated on here. We also assume that you know that the content of a page is put together by a combination of various content elements. Just to make sure, we point out the fact that these content elements are stored in the table tt_content. The database field "CType" defines which content element type we have. Depending on CType an appropriate mask is loaded.

For a better understanding of TYPO3 and TypoScript, it is helpful to study the database. The extension phpmyadmin enables easy access to the database from the backend, where the relationships between pages, tt_content and the backend can be studied. It should be understood that PID (Page ID) stands for the ID of a page while UID (Unique ID) stands for a unique record.

Why TypoScript?

Strictly speaking, TypoScript is a configuration language. We cannot program with it, but we can configure many aspects of a TYPO3 site very comprehensively. With TypoScript, we define the rendering of the website, including navigation, some fixed content, and how individual content elements are rendered on a page.

TYPO3 is a content management system that clearly separates content and design. TypoScript is the glue that joins these two together again. TypoScript reads content stored in the database, prepares it for display, and then renders it on the frontend.

To render a website, we only need to define what content to display and how it will be rendered.

  • The "what" is controlled by the backend - where pages and content are generated.
  • The "how" is controlled by TypoScript.

With TypoScript we define how the individual content elements are rendered in the frontend. For example, we use TypoScript to add a <div> tag to an element, or the <h1> tag to a headline.

The main template

The TypoScript code that is used to define how pages are rendered is located in the "main" template. In this template the root level flag is set.

Rootlevel.png

When the frontend renders a page, TYPO3 searches along the page tree to find a "main" template. Normally, there are additional templates besides the "main" template. How these templates work together is easy to see in the template analyzer. For now, we will assume we are only using the "main" template.

TypoScript syntax is very straight-forward. On the left side, objects and properties are defined. Properties are assigned values, and both objects and properties can contain other objects. Objects properties are defined using dot "." notation.

The term template

The term template has a duplicate meaning in TYPO3. On the one hand, there is the HTML template which serves as the skeletal structure in which the content will be rendered. On the other hand, there is the TypoScript template which can be created in the pages.

Common mistakes which can be made with TypoScript templates can look like this:

No template found.png

"No template found": This warning appears if no template having the root level flag enabled can be found in the page tree.

The page is not configured.png

"The page is not configured": This warning appears if the root level flag of a template in the page tree is enabled (so that this template is used), but no PAGE Object can be found.

The following code suffices to circumvent this warning:

TS TypoScript:
page = PAGE
page.10 = TEXT
page.10.value = Hello World

TypoScript is just an array

Internally, TypoScript is just stored in a PHP array. It is used and evaluated by various classes according to object types.

TS TypoScript:
page = PAGE
page.10 = TEXT
page.10.value = Hello World
page.10.stdWrap.wrap = <h2>|</h2>

will be converted to the following PHP array

PHP script:
$data['page'] = 'PAGE';
$data['page.']['10'] = 'TEXT';
$data['page.']['10.']['value'] = 'Hello World';
$data['page.']['10.']['stdWrap.']['wrap'] = '<h2>|</h2>';

On evaluation, the object "PAGE" will be created first, and the parameter $data['page.'] will be assigned. The object "PAGE" will then search for all properties which define it. In this case, it will just find a numeric entry "10" which has to be evaluated. A new object "TEXT" with the parameter $data['page.']['10.'] will be created. The object "TEXT" knows the parameters "value" and "stdWrap". It will set the content of "value" accordingly. The parameters from "stdWrap" will be passed to the function stdWrap. (That's how "TEXT" is implemented. We will elaborate on stdWrap later). There the property 'wrap' is known, and the text "Hello world" will be inserted at the pipe (|) position and returned.

This relationship is important to understand the behavior of TypoScript in many cases. If, for example, the TypoScript is extended with the following line:

TS TypoScript:
page.10.myFunction = Magic!

this entry will be added to the PHP array:

PHP script:
$data['page.']['10.']['myFunction'] = 'Magic!';

However, the object TEXT does not know the property "myFunction". Consequently, the entry will have no effect.

No semantic error checking is done. If you define an object or properties, which do not exist, you will not see an error message. Instead the according lines of TypoScript just do not do anything. This should especially be considered whilst troubleshooting.

First steps

In the Setup field of the main template, the basic rendering is defined.

TypoScript essentially consists of objects which have certain properties. Some of these properties can accept other objects, others stand for certain functions or define the behavior of the object.

For rendering, the object PAGE is responsible.

TS TypoScript:
 # The object mypage is an object of type PAGE.
 mypage = PAGE
 
 # PAGE objects have the property typeNum (that defines the output rendering type).
 mypage.typeNum = 0
 
 # mypage has an object "10" of type TEXT.
 mypage.10 = TEXT
 
 # TEXT objects in turn have a property called "value" (its contents).
 mypage.10.value = Hello World

The PAGE on the one hand offers numerous properties "with names" (like typeNum). On the other hand it also has an endless number of numbered objects (a so-called content array). The names of these objects only consist of numbers and the objects will get sorted accordingly when they are rendered. First, the object with the smallest number will be rendered; at the end, the object with the biggest number. The order of the lines in the TypoScript template is irrelevant.

TS TypoScript:
 # Create a PAGE object.
 mypage = PAGE
 mypage.typeNum = 0
 
 mypage.30 = TEXT
 mypage.30.value = This gets rendered last.
 
 # Rendering would first output object number 10, then 20 and 30.
 # Object number 25 would logically be output between 20 and 30.
 mypage.20 = TEXT
 mypage.20.value = This is rendered in the middle.
 
 # This is the first output object.
 mypage.10 = TEXT
 mypage.10.value = This is rendered first.
 
 # Here we create a second PAGE object, which we can use for the print view.
 print = PAGE
 print.typeNum = 98
 print.10 = TEXT
 print.10.value = This is the print version.

Every entry is stored in a multidimensional PHP array. Every object and every property, therefore, is unique. We could define an arbitrary number of PAGE objects; however, the typeNum (output rendering type) has to be unique. For every typeNum, there can be only one PAGE object.

In the example, for the parameter typeNum = 98, a different output mode is created. By using typeNum, various output types can be defined. If typeNum is not set explicitly, it defaults to "0". Typically, typeNum = 0 is used for the HTML output. The request for HTML would be index.php?id=1, and index.php?id=1&type=98 for the print version. The value of &type defines, which PAGE object (according to its typeNum), is displayed. That is why it is possible to have print output, HTML output and even PDF output in one and the same TypoScript template. In doing so, configurations which are used in all of the views can be copied and changed just a little bit in the new object. (For example, we can copy the normal page content into the print view, but leave away the menu.)

Note: The output of these examples were both normal text. Especially with output formats like WML, the HTTP header should be changed. This is not covered here.

The previous example would look like this PHP array:

PHP script:
array(
	'mypage' => 'PAGE',	
	'mypage.' => array(
		'typeNum' => 0,
		'10' => 'TEXT',
		'10.' => array(
			'value' => 'This is rendered first.',
		),
		'20' => 'TEXT',
		'20.' => array(
			'value' => 'This is rendered in the middle.',
		),
		'30' => 'TEXT',
		'30.' => array(
			'value' => 'This gets rendered last.',
		)
	)
	'print' => 'PAGE',
	'print.' => array(
		'typeNum' => 98,
		'10' => 'TEXT',
		'10.' => array(
			'value' => 'This is the print version.',
		)
	)
)

Empty spaces at the start and end of values will be removed by TYPO3 automatically (using the trim() function of PHP).

With the "=" sign, we saw the basic assignment: a value is assigned.

TS TypoScript:
 # The object test is an object of type TEXT.
 # "=" means "set value".
 test = TEXT
 test.value = Holla
 
 # "<" means "copy object".
 # mypage.10 returns "Holla"
 mypage.10 < test
 
 # Change the copied object.
 # The change has no effect on mypage.10; it still returns "Holla".
 test.value = Hello world
 
 # "=<" means "create an object reference (link the object)".
 test.value = Holla
 mypage.10 =< test
 
 # Change the object which was referenced.
 # Changes DO have an effect on mypage.10.
 # mypage.10 will return "Hello world".
 test.value = Hello world

Object types are always written with capital letters; parameter and functions typically in camel case (first word lower case, next word starts with a capital letter, no space between words). There are some exceptions to this.

With the "." as a separator, functions and child objects are referenced and can be assigned values accordingly.

TS TypoScript:
mypage.10.stdWrap.wrap = <h1>|</h1>

Which objects, parameters, and functions exist, is documented in the TypoScript Reference (TSref).

If some objects are wrapped in each other, and many parameters are assigned, things can get more complicated.

TS TypoScript:
 mypage = PAGE
 mypage.typeNum = 0
 mypage.10 = TEXT
 mypage.10.value = Hello world
 mypage.10.stdWrap.typolink.parameter = http://www.typo3.org/
 mypage.10.stdWrap.typolink.additionalParams = &parameter=value
 
 # The function name "ATagParams" does not use the standardized
 # "camelCase".
 mypage.10.stdWrap.typolink.ATagParams = class="externalwebsite"
 mypage.10.stdWrap.typolink.extTarget = _blank
 mypage.10.stdWrap.typolink.title = The website of TYPO3
 mypage.10.stdWrap.postCObject = TEXT
 mypage.10.stdWrap.postCObject.value = This text also appears in the link text
 mypage.10.stdWrap.postCObject.stdWrap.wrap = |, because the postCObject is executed before the typolink function.

To keep it simple, curly brackets {} are allowed to define object levels. Note that the opening curly bracket always must be on the same line as the property, after which it is noted! Adding a line break in between (so that the opening bracket would be located in a new line) is not allowed. Parenthesis () are for writing text on more than one line. The above example can be rewritten as the following:

TS TypoScript:
 mypage = PAGE
 mypage {
 
   typeNum = 0
 
   10 = TEXT
   10 {
 
      value = Hello world
      stdWrap {
         typolink {
 
            parameter = http://www.typo3.org/
            additionalParams = &parameter=value
 
            # The function name "ATagParams" does not use the standardized
            # "camelCase".
            ATagParams = class="externalwebsite"
 
            extTarget = _blank
            title = The website of TYPO3
         }
 
         postCObject = TEXT
         postCObject {
 
            value = This text also appears in the link text
            stdWrap.wrap (
             |, because the postCObject is executed before the typolink function.
            )
         }
      }
   }
 }

Using this style of notation the danger of typographic errors is reduced and the script is easier to read. In addition, if we liked to rename mypage, we would only have to change the first two lines, instead of many more occurrences all over the entire script.

Reading content records

Note The following chapter serves as an example and for a better understanding of the background and relationships. The following scripts are from css_styled_content, and it's not necessary to write them by hand. If a content element has to be rendered totally differently, or you programmed an extension with new content elements, it will be necessary to understand the relationships.

We do not want to enter all content written in TypoScript - that would be tiresome, and we can't expect an editor to do that.

So, we create a TypoScript, which will gather the content automatically. The next example will create a page, on which for each content element on that page we will get displayed the headline of the content element and the text of the content element.

First, we create the PAGE object so there will be some rendering at all. In this PAGE object we will create the object CONTENT, which can be controlled with various TypoScript parameters. Inside it, we do the rendering of each content element using objects of the type TEXT":

TS TypoScript:
 page = PAGE
 page.typeNum = 0
 
 # The CONTENT object executes a database query and loads the content.
 page.10 = CONTENT
 page.10.table = tt_content
 page.10.select {
 
      # "sorting" is a column from the tt_content table, and 
      # keeps track of the sorting order, which was specified in
      # the backend.
      orderBy = sorting
 
      # Only select content from column "0" (the column called
      # "normal").
      where = colPos = 0
 }
 
 # For every result line from the database query (that means for every content
 # element) the renderObj is executed and the internal data array is filled
 # with the content. This ensures that we can call the .field property and we
 # get the according value.
 page.10.renderObj = COA
 page.10.renderObj {
 
   10 = TEXT
 
   # The field tt_content.header normally holds the headline.
   10.stdWrap.field = header
 
   10.stdWrap.wrap = <h1>|</h1>
 
   20 = TEXT
 
   # The field tt_content.bodytext holds the content text.
   20.stdWrap.field = bodytext
 
   20.stdWrap.wrap = <p>|</p>
 }

The object CONTENT executes an SQL query on the database. The query is controlled by the property "select". Here "select" defines that we want all records from the column 0 (which is the column "NORMAL" in the backend), and that the result will be sorted according to the field "sorting". If the property pidInList is not set or has been removed, the query will be limited to the current page only. For example, if the page with ID 100 is referenced, the CONTENT object will only return records from the page with pid=100.

The property renderObj defines how each record gets rendered. Therefore, it is defined as COA (Content Object Array), which can hold an arbitrary number of TypoScript objects. In this case, two TEXT objects are used, which will be rendered one after the other. Remember that the order of the rendering is not controlled by the order in TypoScript, but by the numbers with which they are defined. The TEXT object "10" will be created first and the TEXT object "20" will be rendered after it.

The challenge is to render all content elements like the web designer predetermined. Therefore, we have to create TypoScript definitions for every single database field (e.g. for images, image size, image position, on top, index, etc.).

The various content elements

Until now we only have rendering definitions for content elements containing text. But there are different kinds of content elements. If we want to render an image instead of a text, we have to choose different fields from tt_content, and also render them differently compared to standard text. The same applies to "text & images", "headline", etc.

The type of a content element is stored in the column tt_content.CType. In the following example, after having selected the content elements e.g. with a CONTENT object, we show that with the CASE object, we can differentiate how the individual content elements will get rendered.

TS TypoScript:
 page.10.renderObj = CASE
 page.10.renderObj {
 
   # The field CType will be used to differentiate.
   key.field = CType
 
   # The content type "headline" is stored internally as "header".
   header = TEXT
   header.stdWrap.field = header
   header.stdWrap.wrap = <h1>|</h1>
 
   # Text is used for the text content element.
   text = COA
   text {
 
     10 = TEXT
     # The field tt_content.header normally holds the headline.
     10.stdWrap.field = header
     10.stdWrap.wrap = <h1>|</h1>
 
     20 = TEXT
     # The field tt_content.bodytext holds the content text.
     20.stdWrap.field = bodytext
     20.stdWrap.wrap = <p>|</p>
 
   }
 
   # ... other definitions follow here ...
 }

For content elements of the type "headline" we render the content of the header field wrapped in <h1> tags. For content elements of the type "text" we render the headline and the content text.

css_styled_content

It would be tiresome to program this for every TYPO3 installation, because the elements are the same, or have very similar functionality. For this reason, TYPO3 offers "static templates". The current version comes with the TYPO3 system extension "css_styled_content". It has a meaningful definition for every existing type of content element.

The usage is comparably easy. The definitions are available as tt_content objects.

TS TypoScript:
page.10.renderObj < tt_content

This assignment also is the default configuration of the CONTENT object. If the static template "css_styled_content" is available, there is no need to explicitly set the parameter "renderObj".

So for every content element in TYPO3, there is a corresponding definition in css_styles_content. In the object browser, it would look like this:

Object browser tt content case.png

So it is comprehensible, which content element is configured in which way. If a content element has to be configured completely differently, then this can be done with tt_content.internal identifier of the content element. Here follows an example of how the standard properties of the header can be overwritten:

TS TypoScript:
 # Because TYPO3 saves everything in one big array, the properties that are not overwritten 
 # are preserved, and could result in strange behavior. That is why all old properties should be deleted.
 tt_content.header >
 
 # Every header will be rendered with h1 tags, independently from the properties in the content element.
 tt_content.header = TEXT
 tt_content.header.stdWrap.wrap = <h1>|</h1>
 tt_content.header.stdWrap.field = header

But, not only doesn't "renderObj" have to be recreated; the CONTENT object itself is also already defined in css_styled_content.

styles.content.get

TS TypoScript:
 # Our code so far starts like that:
 page.10 = CONTENT
 page.10.table = tt_content
 page.10.select {
 
     # Use the sorting of the backend. We could as well use another field like the date field or the header.
     orderBy = sorting
 
     # normal column
     where = colPos = 0
 }

Thanks to css_styled_content, it suffices to just write the following instead to achieve the same:

TS TypoScript:
 # This returns content from the "normal" column (colPos = 0).
 page.10 < styles.content.get

For the other columns there are according default definitions, as well:

TS TypoScript:
 # This returns content from the "left" column (colPos = 1).
 page.10 < styles.content.getLeft
 
 # This returns content from the "right" column (colPos = 2).
 page.10 < styles.content.getRight
 
 # This returns content from the "border" column (colPos = 3).
 page.10 < styles.content.getBorder

In css_styled_content, the border is internally defined as follows:

TS TypoScript:
 # The normal column is copied.
 styles.content.getBorder < styles.content.get
 
 # After that, colPos is altered.
 styles.content.getBorder.select.where = colPos=3

Create a menu

Until now, we learned how the page content is rendered; however, the page navigation is missing.

TYPO3 offers a special menu object called HMENU ("H" stands for hierarchical) to easily build different kinds of menus.

The menu should be built like a nested list:

XML / HTML:
<ul>
   <li>first level</li>
   <li>first level
       <ul>
           <li>second level</li>
       </ul>
   </li>
   <li>first level</li>
</ul>

In order to keep oversight, we create a new sysfolder and a new extension template. In here, we define a new object which we can add to the main template, later. In this way, we can define a diversity of objects separately from each other and use them for future projects easily. The extension template can be added in the main template with "include basis template".

Normally, these objects are defined as sub-objects of "lib". We could use any term that hasn't been assigned, yet.

TS TypoScript:
 lib.textmenu = HMENU
 lib.textmenu {
 
   # We define the first level as text menu.
   1 = TMENU
 
   # We define the normal state ("NO").
   1.NO = 1
   1.NO.allWrap = <li>|</li>
 
   # We define the active state ("ACT").
   1.ACT = 1
   1.ACT.wrapItemAndSub = <li>|</li>
 
   # Wrap the whole first level.
   1.wrap = <ul class="level1">|</ul>
 
   # The second and third level should be configured exactly
   # the same way.
   # In between the curly brackets, objects can be copied.
   # With the dot ".", we define that the object can be found
   # in the brackets.
   # With 2.wrap and 3.wrap we overwrite the wrap, which
   # was copied from 1.wrap.
   2 < .1
   2.wrap = <ul class="level2">|</ul>
   3 < .1
   3.wrap = <ul class="level3">|</ul>
 }

The object HMENU allows us to create a diversity of menus. The first menu level will be defined with the number "1", the second with the "2", etc. Naturally, it is not allowed to have missing numbers. (For example, if the third menu level is not defined, the fourth will not be rendered.)

For every menu level, an arbitrary menu object can be created, which does the rendering. Thus, it is for example possible to create a GMENU on the first level, and to use a TMENU for the 2nd and 3rd level.

On every menu level, we can configure various states for the single menu items - see menu items, e.g. NO = "normal", ACT = "pages in the root line" (means current page, the parent, grandparent, etc.) or CUR = "the current page". In doing so, pay special attention to the fact that aside the normal state ("NO"), every state has to be activated first (i.e. "ACT = 1").

Henceforth, we can use the menu and implement it in our page.

TS TypoScript:
page.5 < lib.textmenu

Insert content in a template

We now know how to render content, and how to build a menu; but we still do not have a real website, yet.

We could build a website with COAs, and create the complete HTML skeleton with TypoScript. However, this would be very complex, and prone to errors. If the HTML template file has been built by a template designer and is delivered completely done, it gets even more complicated, especially with slight changes in the layout, afterwards.

Therefore, we have the object TEMPLATE, with which we can parse an HTML template file, and insert the menu, content, and so on, at the right place into it.

TS TypoScript:
 page.10 = TEMPLATE
 page.10 {
  template = FILE
 
  # We load the HTML template file.
  template.file = fileadmin/test.tmpl
 
  # Text areas in the template file:
  # <!-- ###MENU### begin -->
  # Here is an example of content as placeholder. Everything which is
  # in between the markers will be replaced by the content of the
  # sub-parts, in this case by the menu.
  # <!-- ###MENU### end -->
 
  # Subparts are a pair of two markers (like "###MENU###" above).
  subparts {
    MENU < lib.textmenu
    CONTENT < styles.content.get
    COLUMNRIGHT < styles.content.getRight
  }
 
  # Marks are single markers. That is, there is no start and end marker; 
  # instead, the marker is replaced directly. ###LOGO### will 
  # be replaced by the logo.
  marks {
    LOGO = IMAGE
 
    # Use the graphic logo.gif.
    LOGO.file = fileadmin/templates/logo.gif
 
    # The logo links to the page with ID 1.
    LOGO.stdWrap.typolink.parameter = 1
  }
  workOnSubpart = DOCUMENT
 }

With the TEMPLATE object, TYPO3 offers a way to replace markers in an HTML template with content generated by TYPO3.

One marker is called a mark. Two markers with the same name (like ' and ' above) are called a subpart. When TYPO3 finds marks or subparts in the HTML template, it will replace them - and in case of subparts everything between them - with what you defined in the TypoScript template for the according mark or subpart. In this example, the subpart MENU will be replaced by the rendering of lib.textmenu.


An alternative to this solution could be the extension automaketemplate, with which it is possible to abandon markers, completely. Instead, it uses IDs as references, and thus allows better cooperation with the template designer.

Another alternative would be the extension templavoila. This extension provides a very visual user interface. This is not recommended for beginners, though.

Using css_styled_content

We already saw that we can write the definitions for the different content elements of TYPO3, ourselves. But css_styled_content relieves us of having to write them ourselves; it comes with more than 2000 lines of TypoScript code containing definitions for each type of content element.

It is rewarding - even if it doesn't seem to make sense in the beginning - to have a good look at TypoScript. In TYPO3, we have to be at the page, which has the TypoScript template with the TypoScript code in the Setup field. Then, in the module "Template", we choose "Template Analyzer" from the selector box on top of the window.

A list with active and integrated TypoScript templates appears. These are evaluated by TYPO3 from top to bottom, and joined together into one configuration array.

With a click on "EXT:css_styled_content/static/", the contents of that template will be displayed. First, the constants will appear, and then the setup TypoScript.

The extension css_styled_content will add HTML elements with many classes to the rendering of a page. They are used by TYPO3 to display things in a structured way, e.g. images at their selected position like next to text, the link to top, etc. This also has the advantage that it is not necessary to enter different classes by hand, if you want to modify the styling. It suffices to find out which HTML element has which class, and to add CSS styles for that class.

<div class="csc-textpic-imagewrap">...

The descriptions of the classes are simple and - once you got familiar with the TYPO3 internals - intuitive. All classes start with "csc"; this stands for "css_styled_content". In the example, this is followed by "textpic", which stands for the TypoScript element "textpic" (which is used to render content elements of the type "text & images"). "imagewrap" suggests that the DIV container wraps around an image.

What is happening in detail can be understood by making an empty page with only one element, and then checking out the generated source code of that page.

For example, headlines are normally enumerated so that the first headline can be handled specifically. For HTML tables, the classes "odd" and "even" are inserted so that it is easy to color table rows differently. In the same manner, the table columns can be handled individually.

For HTML purists, it means that many CSS classes will be inserted, which possibly are not needed for a certain site at all. One could get rid of those by overwriting the unneeded definitions of the css_styled_content extension. However, for beginners that is not recommended.

TypoScript objects

The TypoScript objects are implemented in TYPO3 by corresponding classes. For the various requirements while rendering a web page, there are various objects. These objects have a number of properties. For example, the object IMAGE has a method "border" and a method "titleText". In the TypoScript reference, we can look up what kind of value this object expects. For "border", the data type "integer" is expected. That means we can supply a number. Adding several functions to it in your TypoScript (e.g. "border.color = red") is therefore useless.

The object receives the parameter (as described above) in a PHP array (e.g. $conf['border.']['color']='red';). This array can contain an arbitrary number of entries. Only those entries which are referenced by the object will be used, though (e.g. $conf['border'] or $conf['titleText']).

In the case "titleText", the data type is "string /stdWrap". This means that both text (string) and a method of type stdWrap are allowed. Which properties stdWrap evaluates can be looked up in the section on stdWrap in TSref. Hence, we are allowed to augment the method "titleText" with various properties from stdWrap (e.g. "titleText.field = header"). In doing so, the value of titleText will be filled with standard text first, and afterwards the stdWrap functions are executed.

So, it is not necessary to guess, which object will get manipulated in that way; but, it suffices to look up this information in the TypoScript reference.

For the rendering of a web page, many more objects are used. The challenge is to combine all of them artfully.

In the section "Reading content records", we show how we can use the CONTENT object to execute a query on the database and return the content of a page. The object receives a list of content elements, which are rendered one after the other (normally in sorting order). Therefor, we use the object CASE to differentiate between the types of the elements (CType) and render them differently.

It is absolutely necessary to know the various TypoScript objects and functions.

Objects executing database queries

  • CONTENT offers the functionality to access arbitrary tables of TYPO3 internals. This does not just include tt_content, but also tables of extensions, and so on, can be referenced. The function "select" allows us to generate complex SQL queries.
  • RECORDS offers the functionality to reference specific data records. This is very helpful, if the same text has to be present on all pages. By using RECORDS, a single content element can be defined, which will be shown. Thus, an editor can edit the content without the need to copy the element numerous times. This object is also used, if the content element "insert record" is used.

In the following example, the email address from an address record is rendered and linked as email at the same time.

TS TypoScript:
  page.80 = RECORDS
  page.80 {
        source = 1
        tables = tt_address
        conf.tt_address = COA
        conf.tt_address {
                20 = TEXT
                20.stdWrap.field = email
                20.stdWrap.typolink.parameter.field = email
        }
  }
  • HMENU imports the page tree and offers comfortable ways to generate a menu of pages. Aside the menu which renders the page tree, there are some special menus, which allow various ways of usage. This object imports the internal structure for these menus. How a menu will be rendered depends on menu objects like TMENU (text menu) or GMENU (graphical menu). For every menu level, the object can be changed. Within a menu level, there are various menu items. For every item, we can define the differing states (NO = normal, ACT = active, etc.).

Objects rendering content

  • IMAGE for the rendering of an image.
TS TypoScript:
lib.logo = IMAGE
lib.logo {
  file = fileadmin/logo.gif
  file.width = 200
  stdWrap.typolink.parameter = 1
}

lib.logo holds the logo with a width of 200 pixel, and is linked with the page with PID 1.

  • TEXT is for the rendering of standard text or the content of fields. The TEXT object also offers stdWrap functionality with the property "stdWrap" ::
TS TypoScript:
lib.test1 = TEXT
lib.test1.stdWrap.field = uid
  • FILE imports the content of a file, directly.
  • TEMPLATE replaces markers in a template with content coming from TYPO3.
TS TypoScript:
page.10 = TEMPLATE
page.10 {
  template = FILE
  template.file = fileadmin/test.tmpl
  subparts {
    HELLO = TEXT
    HELLO.value = This line here replaces the content in between the markers ###HELLO### and ###HELLO### in the HTML template.
  }
  marks {
    Test = TEXT
    Test.value = The marker ###TEST### will be replaced with this text.
  }
  workOnSubpart = DOCUMENT
}
  • IMGTEXT allows us to generate images inline with text. It is used for the content element "text & images".
  • FORM generates an HTML form.

Further objects

  • CASE allows case differentiation. In css_styled_content, this object is used for rendering different objects according to their type.
  • COA (content object array) allows us to combine an arbitrary number of objects.
  • COA_INT is a COA object, but non cached. This element will be regenerated at each call. This is useful with time and date or user dependent data, for example.
  • LOAD_REGISTER / RESTORE_REGISTER objects allow us to fill the global array $GLOBALS['TSFE']->register[] with content. These objects return nothing. Single values and complete TypoScript objects can be used. In doing so, the register works as a stack: With every call, a further element is stacked. With RESTORE_REGISTER, the element on top can be removed.
  • USER and USER_INT are for user defined functions. Every plugin is such an object. USER_INT is the non cached variant.
  • IMG_RESOURCE is used by IMAGE. The resource is returned (the content), which normally is the SRC attribute of the IMG tag. If images are scaled, this object serves as a calculation basis for the new files, which are stored in the /typo3temp folder.
  • EDITPANEL - This object is inserted, if a backend user is logged in and the option "Display Edit Icons" is set in the frontend admin panel. If the admin panel is inserted, the pages will not be cached anymore. Icons for sorting order, editing, removing, and so on, will be shown.
  • GIFBUILDER is used for generating .gif files dynamically. Various texts and images can be combined and much more. The GIFBUILDER object itself again offers some objects, like TEXT or IMAGE, which are not related to the standard TEXT or IMAGE objects, respectively. While working with the GIFBUILDER, we have to watch out that we do not confuse the objects with one another.

We did not introduce all objects which exist in TypoScript, but we have named the most important ones.

TypoScript functions

TypoScript functions are used to change and adjust the output of content elements. The most popular function is the standard wrap, better known as stdWrap. Whether an object implements a certain function or not, is shown in TSref in the column "data type". Here is an extract of the cObject IMAGE from TSref:

Property Data type Description
file imgResource
imageLinkWrap ->imageLinkWrap
if ->if
altText
titleText
string/stdWrap

Example:(cObject).IMAGE

The first line in this example (property "file") tells us that "file" is of the data type "imgResource". This means that we can use the imgResource functions on the file property.

Sometimes functions are - for better recognition - marked with an arrow (like ->if).

If there are multiple entries separated by a slash, it means that you have various possibilities to use that element. In the example above, you can for example see this with "titleText" and "altText". Both can be either plain string or stdWrap. So, you can enter a plain string and do nothing more; or you can adjust and change your string by using stdWrap features on it; or you can leave the string empty all together and generate the content with stdWrap only.

Some important and frequently used functions are presented in the following subsections. This chapter is about introducing those functions, and where they can be used. All details, however, can be found in the section of TSref, and not here.

imgResource

The functions of the data type "imgResource" relate to modifications of pictures. The object IMAGE has the property "file", which is inherited from the data type "imgResource".

This, for example, allows an image to be resized:

TS TypoScript:
temp.myImage = IMAGE
temp.myImage {
 
        file = toplogo.gif
        file.width = 200
        file.height = 300
 
}

Enter maximum size (or minimum size):

TS TypoScript:
temp.myImage = IMAGE
temp.myImage {
 
        file = toplogo.gif
 
        # maximum size
        file.maxW = 200
        file.maxH = 300
 
        # minimum size
        file.minW = 100
        file.minH = 120
 
}

imgResource also provides direct access to a GraphicsMagick function:

TS TypoScript:
temp.myImage = IMAGE
temp.myImage {
 
        file = toplogo.gif
        file.params = -rotate 90
 
   }

One of the most common and best examples for the use of imgResource is the implementation of pictures dynamically from the Media field in the page properties. This has the advantage that editors can change the pictures without using TypoScript. This allows us to have changing header images for different areas of a website with a few lines of TypoScript.

TS TypoScript:
temp.dynamicHeader = IMAGE
temp.dynamicHeader { 
        file {
 
                # Define the path to the images.
                import = uploads/media/
 
                import {
 
                        # If there are no images on this page, search recursively
                        # down the page tree.
                        data = level:-1, slide
 
                        # Enter the field, in which the image is defined.
                        field = media
 
                        # Define which of the images will be displayed,
                        # in this case, the first it encounters.
                        listNum = 0
 
                }
        }
}

The path "uploads/media/" is the location of the files, which are inserted in the "files" section. You find it inside the page properties on the tab "Resources". The TypoScript in the brackets of "import" completely consists of stdWrap functions, which are used to define from where and which image will be imported. Finally, stdWrap returns the file name of the image, which will then be imported from the import path (uploads/media).

imageLinkWrap

With "imageLinkWrap", we can wrap the image with a link to the PHP script "typo3/sysext/frontend/Classes/Controller/ShowImageController.php". The script will open the image in a new window with predefined parameters like window background, image size, etc. This function can be used to create "click-to-enlarge" functionality. (A small image (thumbnail) is clicked to open a new window and show the image in its original size.)

TS TypoScript:
temp.myImage = IMAGE
temp.myImage {
 
	 file = toplogo.gif
 
        imageLinkWrap = 1
        imageLinkWrap {
 
                # Activate ImageLinkWrap.
                enable = 1
 
                # Define the body tag for the new window.
                bodyTag = <body class="ImageOriginal">
 
                # Wrap the image. (Close the window, if it is clicked.)
                wrap = &lt;a href="javascript:close();"&gt; | </a>
 
                # Width of the image (m allows proportional scaling).
                width = 800m
 
                # Height of the image.
                height = 600
 
                # Create a new window for the image.
                JSwindow = 1
 
                # Open a new window for every image (instead of using the same window).
                JSwindow.newWindow = 1
 
                # Padding for the new window.
                JSwindow.expand = 17,20
        }
 
}

numRows

In TypoScript, there are not only big mighty functions, but also small mighty functions. An example is the function numRows, which has the sole purpose to return the number of lines of a SELECT query. Just like the object CONTENT, numRows uses the select function. The query is generated similarly in both cases. The difference is only whether the number of lines or the actual content of those lines is returned.

In cooperation with the "if" function, it is possible to generate some nice stuff. An example is a stylesheet for the content of the right column in the backend, which is only used if there actually also is some content in the column.

TS TypoScript:
temp.headerdata = TEXT
temp.headerdata {
        value = <link rel="stylesheet" type="text/css" href="fileadmin/templates/rightColumn.css">
 
        # If the select returns at least one line, insert the stylesheet.
        stdWrap.if.isTrue.numRows { 
 
                # Check if this page
                pidInList = this
 
                # has content in table tt_content,
                table = tt_content
 
                # which belongs in the right column (the column with "colPos=2").
                select.where = colPos=2  
        }
}
 
# Copy temp.headerdata in page.headerData.66 (and overwrite page.headerData.66).
page.headerData.66 < temp.headerdata

Or, use another template, if there is content in the right column:

TS TypoScript:
# A COA (content object array) allows us to merge many objects.
temp.maintemplate= COA
temp.maintemplate {
 
        # 10 will only be embedded, if the "if" statement returns "true".
        10 = COA
        10 {
                # We use a copy of the select from css_styled_content.
                if.isTrue.numRows < styles.content.getRight
 
                10 = TEMPLATE
                10 { 
                        template = FILE
                        template.file = fileadmin/templates/template-2column.html
                }
        }
 
        # 20 will only be embedded, if the "if" statement returns "true".
        20 = COA
        20 {
                if.isFalse.numRows < styles.content.getRight
                10 = TEMPLATE
                10 {     
                        template = FILE
                        template.file = fileadmin/templates/template.html
                }
        }
}

select

The function "select" generates an SQL SELECT query, which is used to read records from the database. The select function automatically checks whether the records might be "hidden", or "deleted", or if they have a "start and end date". If pidInList is used (meaning a list of pages is rendered), the function also checks if the current user is allowed to see all records.

With the help of the select function, it is possible to show the content of a page on all pages. For example:

TS TypoScript:
 temp.leftContent = CONTENT
 temp.leftContent {
 
     table = tt_content
     select {
 
         # The page with ID = 123 is the source.
         pidInList = 123
 
         # Sorting is like in the backend.
         orderBy = sorting
 
         # Only select the content of the left column.
         where = colPos=1
 
         # Define the field with the language ID in tt_content.
         languageField = sys_language_uid
     }
 }
 
 # Replace the mark ###LEFT### with the output of temp.leftContent.
 marks.LEFT < temp.leftContent

split

The split function can be used to split given data at a predefined character, and process the single pieces afterwards. At every iteration, the current index key "SPLIT-COUNT" is stored (starting with 0).

By using "split", we could, for example, read a table field and wrap every single line with a certain code (e.g. generate a HTML table, which can be used to show the same content on more than one page):

TS TypoScript:
  20 = TEXT 
 
  # The content of the field "bodytext" is imported (from $cObj->data-array).
  20.stdWrap.field = bodytext 
  20.stdWrap.split { 
 
    # The separation character is defined (char = 10 is the newline character).
    token.char = 10 
 
    # We define which element will be used.
    # By using optionSplit, we can distinguish between elements.
    # Corresponding elements with the numbers must be defined!
    # For the rendering the numbers 1 and 2 are used in alternation.
    # In this example, the classes "odd" and "even" are used, so we
    # can style a table in zebra style.
    cObjNum = |*|1||2|*|
 
    # The first element is defined (which is referenced by cObjNum).
    # The content is imported using stdWrap->current.
    1.current = 1
 
    # The element is wrapped.
    1.wrap = <TR class="odd"><TD> | </TD></TR>
 
    # The 2nd element is determined and wrapped.
    2.current = 1
    2.wrap = <TR class="even"><TD> | </TD></TR>
  }
 
  # A general wrap to create valid table markup
  20.stdWrap.wrap = <TABLE width="368"> | </TABLE>

if

The perhaps most difficult TYPO3 function is the "if" function, because every programmer, who is familiar with if functions from somewhere else, instinctively misuses it. Therefore, we have some examples to show, how it works correctly.

Generally, the if function returns "true", if all conditions are fulfilled. This resembles a boolean AND combination. If "false" should be returned in that case, we can use the "negate" option to negate the result (like a !(true)).

TS TypoScript:
10 = TEXT
10 {
 
    # Content of the TEXT object.
    value = The L parameter is passed as GET variable.
 
    # Results in "true" and leads to rendering the upper value, if the 
    # GET/POST parameter is passed with a value, which is not 0.
    stdWrap.if.isTrue.data = GP:L
}

With the use of "if", it is also possible to compare values. For this purpose, we use the parameter "if.value".

TS TypoScript:
10 = TEXT
10 {
 
    # WARNING: This value resembles the value of the TEXT object, not that of the "if"!
    value = 3 is bigger than 2.
 
    # Compare parameter of the "if" function.
    stdWrap.if.value = 2
 
    # Please note: The sorting order is "backwards",
    # returning the sentence, "3 isGreaterThan 2".
    stdWrap.if.isGreaterThan = 3
}

Because the properties of the "if" function implement stdWrap functions, all kinds of variables can be compared.

TS TypoScript:
10 = TEXT
10 {
    # Value of the TEXT object.
    value = The record can be shown, because the starting date has passed.
 
    # Condition of the if clause (number of seconds since January 1st, 1970).
    stdWrap.if.value.data = date:U
 
    # Condition backwards again: Start time isLessThan date:U.
    stdWrap.if.isLessThan.field = starttime
}

typolink

typolink is the TYPO3 function, which allows us to generate all kinds of links. If possible, one should use this function to generate links, because these will be "registered" in TYPO3. This is a prerequisite, for example, for realURL, which will generate search engine friendly paths; or for the anti-spam protection on email addresses. So, if you feel the urge to use <a href="..."> - don't!

The functionality of typolink is basically very easy. typolink links the specified text according to the defined parameters. One example:

TS TypoScript:
 temp.link = TEXT
 temp.link {
 
     # This is the defined text.
     value = Example link
 
     # Here comes the typolink function.
     stdWrap.typolink {
 
         # This is the destination of the link,
         parameter = http://www.example.com/
 
         # with a target ("_blank" opens a new window),
         extTarget = _blank
 
         # and add a class to the link so we can style it.
         ATagParams = class="linkclass"
     }
 }

The example above will generate this HTML code:

<a class="linkclass" target="_blank" href="http://www.example.com/">Example link</a>

typolink in some way almost works like a wrap: The content which is defined for example by value, will be wrapped by the HTML anchor tag. If no content is defined, it will be generated automatically: With a link to a page, the page title will be used. With an external URL, the URL will be shown.

One can shorten this example, because the "parameter" tag from the typolink function does some of the thinking for you. Here, the short example will generate exactly the same HTML code.

TS TypoScript:
 temp.link2 = TEXT
 temp.link2 {
 
     # Again the defined text.
     value = Example link
 
     # the parameter with the summary of the parameters of the first
     # example (explanation follows below).
     stdWrap.typolink.parameter = www.example.com _blank linkclass
 }

The "parameter" part from the typolink function analyzes the entry on specific characters, and converts the respective sections. Initially, the parameter entry will be separated at the blank spaces.

If in the first part then a dot "." is found (if the case may be in before a slash "/"), an external link will be generated. If the dot "." is found after a slash "/", a file link is generated. If an "@" is found, an e mail link will be generated. If an integer is found, like "51", an internal link to the page with the ID "51" will be generated. If a leading hash "#" is found, a certain content element will be linked (for example, for a link to the content element with the id #234 on the current page. In order to link to the page with ID 51 and content element #234, one would use 51#234).

The second part of the parameter describes the destination of the link. Normally, this would be - like in the first example - defined by extTarget (for external links) or target (for internal links); but, it can be overwritten by using a second parameter.

The third part will be converted to a class attribute for the link.

If only a class attribute is needed, but no target, one has to fill the target part anyway, because the class has to be at the third place. To do that we can use the minus sign "-" instead of a target. The line would then be the following:

TS TypoScript:
stdWrap.typolink.parameter = www.example.com - linkclass

With the usage of the typolink function and the target attribute, it is also possible to open links in JavaScript popups.

TS TypoScript:
temp.link = TEXT
temp.link {
 
     # The link text.
     value = Open a popup window.
 
     stdWrap.typolink {
          # First parameter is the page ID of the target page,
          # second parameter is the size of the popup window.
          parameter = 10 500x400
 
          # The title attribute of the link.
          title = Click here to open a popup window.
 
          # The parameters of the popup window.
          JSwindow_params = menubar=0, scrollbars=0, toolbar=0, resizable=1
 
     }
}

It is important to note that many of the properties of typolink are of the type stdWrap. This means that values can be calculated, or read out of the database.

TS TypoScript:
lib.stdheader >
lib.stdheader = TEXT
lib.stdheader.stdWrap {
   field = header
   typolink.parameter.field = header_link
   wrap = <h2>|</h2>
}

Here the first line removes the default settings from css_styled_content. Then the headline will be displayed, and a link will be placed with a destination, which is defined in the field "header_link".

encapsLines

encapsLines is short for "encapsulate lines". This TypoScript function allows us to define how single lines in the content are wrapped. For example, if nothing is defined, a <p> or a <div> will wrap the element. Another example would be to automatically replace all <b> tags with <strong> tags.

A simple example:

In the RTE we have a text with the following HTML code:

XML / HTML:
 A simple text without anything special.
 &nbsp;
 <div class="myclass">Some text with a wrapping div tag.</div>

In TypoScript we have this:

TS TypoScript:
encapsLines {
       # Define which tags will be seen as wrappers.
       encapsTagList = div,p
 
       # Lines, which are not already encapsulated with a tag from 
       # encapsTagList, will be wrapped with <p> tags.     
       wrapNonWrappedLines = <p>|</p>
 
       # Replace all DIV tags with P tags.
       remapTag.DIV = P
 
       # If a line is empty, insert an empty space.
       innerStdWrap_all.ifEmpty = &nbsp;
}

The result will look like this in HTML code:

XML / HTML:
 <p>A simple text without anything special.</p>
 <p>&nbsp;</p>
 <p class="myclass">Some text with a wrapping div tag.</p>;

With most TYPO3 projects, the following code will not be necessary. But in the extension "css_styled_content", some settings are defined with this function, which can be changed, if needed. So here follows an example from the standard configuration of "css_styled_content" to clarify its functionality.

TS TypoScript:
lib.parseFunc_RTE {
 
        nonTypoTagStdWrap.encapsLines {
 
               # Wrapping tags.
               encapsTagList = div,p,pre,h1,h2,h3,h4,h5,h6
 
               # Convert all DIV tags to P tags.
               remapTag.DIV = P
 
               # Wrap all lines, which are not wrapped at all, with the P tag.
               nonWrappedTag = P
 
               # Add a space to all empty lines.
               innerStdWrap_all.ifBlank = &nbsp;
 
               # Here the - infamous - class "bodytext" is added.
               addAttributes.P.class = bodytext
 
               # Use addAttributes, if no other attribute is set.
               addAttributes.P.class.setOnly = blank
       }
}

Comparing the first example with the second, you might notice that apparently there are two parameters, which do the same thing: firstly, "wrapNonWrappedLines"; and secondly, "nonWrappedTag". The difference is that "nonWrappedTag" can be extended by "addAttributes", whereas for "wrapNonWrappedLines" you need to specify exactly one complete wrapping tag. If you have lines, which are already wrapped in <p class="foo">|</p> and "wrapNonWrappedLines" is defined as <p>|</p>, the result would be an inconsistent mixture of P tags with and without classes, instead of one consistent wrap.

To demonstrate it clearly: To get rid of the mostly annoying class="bodytext", you don't need to do more than to insert the following line:

TS TypoScript:
lib.parseFunc_RTE.nonTypoTagStdWrap.encapsLines.addAttributes.P.class >

filelink

With the function "filelink" we can generate - as the name suggests - a link to a file. While doing so, not just a link to the file is being generated, but "filelink" also allows us to add an icon and display the file size.

TS TypoScript:
temp.example = TEXT
temp.example {
 
	# Link description and file name at the same time.
	value = my_image.png
 
        stdWrap.filelink {
 
		# Path to the file.
     		path = fileadmin/images/
 
		# The file should have an icon.
     		icon = 1
 
		# The icon will be wrapped.
     		icon.wrap = <span class="icon">|</span>
 
		# The icon should be linked to the file, as well.
     		icon_link = 1
 
		# Instead of the symbol for the file type, the file 
                # will be displayed as an icon, if it is of type .png or .gif.
     		icon_image_ext_list = png,gif
 
		# The size will be displayed as well.
     		size = 1
 
		# Wraps the file size (with regard to the empty spaces).
     		size.noTrimWrap = | (| bytes) |
 
		# Rendering of the file size will be done in bytes.
     		size.bytes = 1
 
		# Abbreviations for the various filesize units
     		size.bytes.labels =  | K| M| G
 
		# Wrap for the whole element.
     		stdWrap.wrap = <div class="filelink">|</div>
        }
}

parseFunc

This function parses the main part of the content, i.e., the content which has been entered in the Rich Text Editor. The function is responsible for the fact that the content is not rendered exactly as it was entered in the RTE. Some default parsing rules are implemented in "css_styled_content"; a part of them has already been explained in the encapsLines chapter. If we liked to change how TYPO3 wraps something, most of the time this can be done with a parseFunc instruction. We could also use parseFunc to search and replace a certain string.

In the following example, every occurrence of "COMP" is replaced by "My company name".

TS TypoScript:
page.stdWrap.parseFunc.short {
 COMP = My company name
 }

The various possibilities of changing the default behavior can be found by using the TypoScript object browser. All possibilities of how parseFunc can alter the rendering can be found here: parseFunc.

tags

The function "tags" is used in combination with parseFunc to define custom tags. For example, in the extension "css_styled_content", a custom tag <LINK> is defined to create simple links.

TS TypoScript:
tags {
        # Here the name of the new tag is defined.
        link = TEXT
 
        # Here is how the tag is processed and parsed.
        link.stdWrap {
                current = 1
                typolink {
 
                        parameter.data = parameters:allParams
 
                        extTarget = {$styles.content.links.extTarget}
 
                        target = {$styles.content.links.target}
 
                }
 
                parseFunc.constants = 1
        }
}

This function is especially useful, if a certain type of element is used by the editors very often, and we would like to make things easier for them. We are able to provide a way that the editors do not have to format things manually every time. Instead they can just enter the tag, and the formatting is done automatically.

HTMLparser

The HTML parser defines how content is processed. Normally, it is used as a subfunction of parseFunc. For example, we could define that all links will be set with an absolute value (for example, for a newsletter):

TS TypoScript:
page.stdWrap.HTMLparser = 1
page.stdWrap.HTMLparser {
        keepNonMatchedTags = 1
 
	# Here we define the domain, which will be placed in front
        # of the relative path.
        tags.a.fixAttrib.href.prefixRelPathWith = http://www.example.com/
 
	# All links without a target should have the target "_blank".
        tags.a.fixAttrib.target.default = _blank
}

The function HTMLparser is extremely mighty, because every content can be altered before it is rendered. E.g. links are internally stored as follows: <link http://www.typo3.org/>Linktext</link>. We can also define custom tags. Custom tags can be defined in all fields - also in headlines -, on which a parser has been defined.

The following example allows the <u> tag in headlines. To do that the default definition from "css_styled_content" will be altered: The function htmlSpecialChars will be deactivated, so the <u> remains untouched. Thereafter, the parseFunc function is used, and defined that aside the tag "u", no other tags will be allowed. Thus, all tags apart from the <u> will be removed.

TS TypoScript:
# In the headline the <u> tag shall be allowed.
# Apart from that all elements have to be parsed as usual.
lib.stdheader.10.setCurrent.htmlSpecialChars = 0
lib.stdheader.10.setCurrent.parseFunc {
  allowTags = u
  denyTags = *
  constants = 1
  nonTypoTagStdWrap.HTMLparser = 1
  nonTypoTagStdWrap.HTMLparser {
    keepNonMatchedTags = 1
    htmlSpecialChars = 2
    allowTags = u
    removeTags = *
  }
}

This example once again shows how important the stdWrap function actually is. The function setCurrent is of Type string /stdWrap, and thus allows the usage of parseFunc.

Using stdWrap correctly

The function stdWrap includes a wide variety of functions and parameters. Some are trivial, the uses of others are hard to find. Here, we will commit ourselves to the basic principles, and highlight a few special functions and properties.

The stdWrap property can only be used with an object, if it is explicitly defined for that object in the TypoScript reference. For example the cObjects have a property "stdWrap", which is of the type "stdWrap" and offers stdWrap functionality. If we have a property of another type, e.g. of the type "wrap", then this property does not have stdWrap properties. By default, either a property named "stdWrap" of type stdWrap is presented, or a property offers stdWrap, for example "string /stdWrap".

TS TypoScript:
 10 = IMAGE
 10.stdWrap.typolink...
 
 20 = TEXT
 20.value = Hello World
 20.stdWrap.typolink...

These objects have a property "stdWrap" of type "stdWrap".

Heed the order

An important limitation should be highlighted:

Note: The single functions are executed in the order specified by the TypoScript reference!

If we did not pay attention to this fact, the results might easily look different from what we expected.

TS TypoScript:
 10 = TEXT
 10.stdWrap.field = header # assuming the header contains "typo3" (small case characters)
 10.stdWrap.wrap = <strong>|</strong>
 10.stdWrap.case = upper

This results in the following:

XML / HTML:
 <strong>TYPO3</strong>

The following happens in this example: First, the value of the TEXT object is imported from the field "header". We know that the TypoScript configuration is stored in an array. The sorting in this array is not necessarily the same as the sorting in our TypoScript. Instead, the sorting in the array is constrained by definitions of the ordering of stdWrap. This order is mirrored by the TypoScript reference.

After a short look into the TSref it should be clear that, first, "field" is processed, thereafter "case", and in the end, "wrap". This order is the reason, why the words of the tag "strong" themselves are not uppercased.

Modify the order

There are basically two ways to obtain another execution order of the stdWrap functions: First you can use stdWrap recursively. Second you can use the stdWrap property "orderedStdWrap" to conveniently provide a custom order.

Because the stdWrap function can be called recursively, it is possible to change the execution order.

The function "prioriCalc" permits easy mathematical expressions. If set to 1, the content is calculated; however, the calculations are done from left to right (no mathematical precedence like "*" before "+", etc.). The following example looks, as if the content of field "width" gets 20 added to it.

TS TypoScript:
 10 = TEXT
 10.stdWrap.field = width   # Assumption: "width" is 100
 10.stdWrap.wrap = |+20
 10.stdWrap.prioriCalc = 1

But this is not the case! The result which will be rendered is: "100+20". The function "prioriCalc" is executed before the function wrap, and thus only calculates the result of "field" - the expression "100". In order to get the result we anticipated, we have to make sure that "field" and "wrap" are executed before "prioriCalc". This can be achieved by using the following expression:

TS TypoScript:
 10 = TEXT
 10.stdWrap.field = width   # Assumption: "width" is 100
 10.stdWrap.stdWrap.wrap = |+20
 10.stdWrap.prioriCalc = 1

We do not use "wrap" directly, but use it nested inside another stdWrap. The stdWrap function is executed after "field", but before "prioriCalc", thus "100+20" is wrapped, and after that the function "prioriCalc" is executed, resulting in the value "120".

With orderedStdWrap you can do the same, but more conveniently.

TS TypoScript:
 10 = TEXT
 10.orderedStdWrap {
       10.field = width   # Assumption: "width" is 100
       20.wrap = |+20
       30.prioriCalc = 1
 }

Using orderedStdWrap we can execute multiple stdWrap functions in a freely selectable order without having to nest them inside other stdWrap calls. The execution order inside orderedStdWrap is just defined by the numbers you provide. The result will again be "120".

The data type

While TypoScripting, it is crucial to know what kind of data type we are handling. Especially with stdWrap, we have noticed that people sometimes try to combine functions arbitrarily, until the anticipated result is finally achieved by accident.

Only if the stdWrap functionality is mentioned explicitly, the stdWrap functions like field, data, or typolink can actually be used.

Check the TypoScript reference, if you are unsure!

Multilanguage functionality

stdWrap offers a property "lang", with which it is possible to translate simple texts which are implemented on a page via TypoScript.

TS TypoScript:
 10 = TEXT
 10.value = Imprint
 10.stdWrap.lang.de = Impressum
 10.stdWrap.typolink.parameter = 10

However, texts like these are hard to translate by external editors. Especially with unknown languages, this can become a challenge.

For this case, it is best to handle the translations with constants. These can be placed together at a specific place, and implemented into TypoScript.

TS TypoScript:
 # Constants
 text.imprint = Imprint
 text.de.imprint = Impressum
 
 # Setup
 10 = TEXT
 10.value = {$text.imprint}
 10.stdWrap.lang.de = {$text.de.imprint}
 10.stdWrap.typolink.parameter = 10

This way, the place of the translation is not depending on the TypoScript configuration of the item.

cObject

The parameter "cObject" can be used to replace content with a TypoScript object. This can be a COA, a plugin, or a text, as in this example:

TS TypoScript:
 10.typolink.title.cObject = TEXT
 10.typolink.title.cObject.value = Imprint
 10.typolink.title.cObject.stdWrap.lang.de = Impressum

Outlook

The manual is still maintained in the wiki. Changes made there will regularly be merged into this manual. If you want to change something, use the wiki page at http://wiki.typo3.org/Ts45min . If you think you found a bug and want to report it, use the issue tracker at http://forge.typo3.org/projects/typo3cms-doc-typoscript-45-minutes/issues.