TypoScript syntax

A first example

As already mentioned, TypoScript is commonly used to map values to a hierarchy - a tree of objects. This object tree is a central concept used in the TYPO3 CMS. The branches of the tree are indicated with periods "." – a syntax which can also be found in some languages such as JavaScript and conveys the idea of defining objects and their properties. The equal sign "=" is used for assigning values or objects types and not, as you might suppose, to compare values.

Example 3.4. Abstract example of defining an object and assigning a property

1objectName = 2ObjectType
objectName.3propertyName = value



The example above demonstrates how an object is defined and how a value is assigned to a property.

1

The object name identifies the new object and can be freely chosen. It must consist of a combination of the following characters: A-Z, a-z, 0-9

2

An object must be of a specific type. Which types are available depends on the context where the TypoScript code is used. We'll have a closer look at these contexts, soon.

3

Values can be assigned to the properties of an object by referring to the property's name. Which properties exist, depends on the object type.

Too abstract? Then let's be more specific and have a look at a real world example:

Example 3.5. Definition of a "Text" content object

myText = Text
myText.value = "Hello world!"


In these two lines we define a new object called myText which is of the type Text and assign the value Hello world! to the a property called value.

Objects can be easily be grouped into branches of the object tree. Consider the following illustration:

Figure 3.1. A simple object tree

A simple object tree



The following TypoScript would be neccessary to created the above tree:

Example 3.6. TS code for the simple object tree

library.boilerplates.greeting = Text
library.boilerplates.greeting.value = "Hello world"
library.boilerplates.footnote = Text
library.boilerplates.footnote.value = "©2007 by the TYPO3 guys"


Basic syntax

TypoScript is parsed in a very simple way; line by line. This means that each line normally contains three parts based on the following formula:

[object path] [operator] [value]

  • The object path is a single object name or a path to that object, defined by several object names separated by periods "."

  • An operator is one of the following: "=", "<", ">", "=<". They are described later in this section.

  • The value can be one of the following:

    • a literal string enclosed by single or double quotes. Single- and double quotes as well as the backslash and the dollar sign must be escaped with a backslash sign. Examples: "Hello world" or "and I said \"Hello world\""

    • a number. Example: 23

    • a constant, written in all UPPERCASE. Examples: BLUE or MY_SPECIAL_CONSTANT

    • an object type, written in UpperCamelCase. Examples: Text or HierarchicalMenu

    • a variable or a combination of literals and variables. Example: "Hello $name, nice to meet you!" (the concept of variables will be explained in a later section)

In the following example, myObject is defined as a HTML content object and the property value is set:

Example 3.7. A simple HTML content object

myObject = HTML
myObject.value = "<div>some HTML code</div>"


Figure 3.2. The resulting object tree

The resulting object tree


Confinements: {} signs

The curly braces are used to assign many object properties in a simple way at once. It's called a confinement or nesting of properties.

Example 3.8. Confinements

   # This definition ...
somePerson = Person
somePerson.firstName = "John"
somePerson.lastName = "Doe"
somePerson.address.street = "Rigensgade"
somePerson.address.city = "København"

   # ... can be nicer structured with confinements:
somePerson = Person
somePerson {
   firstName = "John"
   lastName = "Doe"
   address {
      street = "Rigensgade"
      city = "København"
   }
} 


"=" operator

In general, the "=" operator is used to assign values. As already mentioned, values can be literals, numbers, constants, object types or variables. If a value already exists, it will be overwritten.

Here are a few examples for each option:

Example 3.9. Assigning values

   # Assigning object types:
myObject = HTML
someTextObject = Text
aSpecialObject = SomeSpecializedContentObjectType

   # Assigning literals
someTextObject.value = "Hello world!"
myObject.value = "   <- three spaces here"
myObject.value = "Say \"hello\" to the world."
xy.fileLocation = "c:\\mystuff\\things\\files\\cmd.exe"
coffeeObject.espressoExtractionDuration = 25

   # Assigning constants
someTextObject.value = HELLO_WORLD_MESSAGE

   # Assigning variables
someTextObject.value = $message


">" operator

The ">" operator is used to unset whole objects or single properties:

Example 3.10. Unsetting objects and properties

library.myObject = HTML
library.myObject.value = "<strong>Hello world!</strong>"

library.anotherObject = Text
library.anotherObject.value = "Hi there"

library.myObject >
library.anotherObject.value >


The above example results in the following object tree:

Figure 3.3. The resulting object tree

The resulting object tree


"<" operator

The "<" operator is used to copy one object or a whole object branch to another. The whole object is copied (ie. cloned) - both, value and properties - and it overrides any existing objects and values at the target position.

Example 3.11. Copying objects

myObject = HTML
myObject.value = "<div>HTML code</div>"

myOtherObject < myObject


In the above example the result is two independent sets of objects and their property which are exactly the same (duplicates). However they are not references to each other but independent copies:

Figure 3.4. Copied objects in the object tree

Copied objects in the object tree


It is common practice to copy objects, using them as a kind of template or boilerplate and then modifying only specific properties:

Example 3.12. Copying branches, overriding single properties

library.aLotOfObjects {
   oneObject = SomeType
   oneObject.firstProperty = "John"
   oneObject.subObject.secondProperty = "Doe"

   secondObject < .oneObject
}

myObject < library.aLotOfObjects
myObject.secondObject.firstProperty = "Johannes"


Note the different way of referring to an object for the secondObject: the .oneObject refers to an object called oneObject in the same branch or level of the tree. An alternative would have been to write:

   secondObject < library.aLotOfObjects.oneObject

In any case, the resulting object tree would look like this:

Figure 3.5. Object tree after copy operations

Object tree after copy operations


"=<" operator

The "=<" operator is used to reference to an object or a whole object branch. The whole object is not copied but only referenced.

Example 3.13. Referencing objects

myObject = HTML
myObject.value = "<div>HTML code</div>"

myOtherObject =< myObject


In the above example the result is two independent object names refering to the identical object instance:

Figure 3.6. Referenced objects in the object tree

Referenced objects in the object tree


Let's see what happens if we take the example of the copy-operator and just use references instead:

Example 3.14. Referencing branches, overriding properties

library.aLotOfObjects {
   oneObject = SomeType
   oneObject.firstProperty = "John"
   oneObject.subObject.secondProperty = "Doe"

   secondObject =< .oneObject
}

myObject =< library.aLotOfObjects
myObject.secondObject.firstProperty = "Johannes"


The resulting object tree looks quite different:

Figure 3.7. Object tree after referencing operations

Object tree after referencing operations


"<<" operator

The "<<" operator

A powerful feature of TYPO3's TypoScript engine is the ability to process property values. Processors allow you to transform strings, add or combine information from elsewhere in the system or pass the current value to arbitrary user functions which take further action, depending on the content.

Probably the most popular processor function is the wrap() method. It pre- and appends a string to the property value:

Example 3.15. Using the wrap() value processor

myObject = Text
myObject.value = "I am so strong!"
myObject.value << 1.wrap("<strong>", "</strong>")


The rendered output of this Text object looks like this:

<strong>I am so strong!</strong>

The value property of the Text object has been processed by the wrap() function before it was displayed on the website. Please note, that the processor does not modify the original property – a second turn will deliver the exact same result.

Processors are called like functions in a programming language. In fact, a processor function is directly related to a PHP function of the same name which accepts (almost) the same arguments. Which arguments are expected, depends on the processor function (you find all details in the TypoScript Reference).

A good thing about processor functions is that you can run them in a chain: The first processor gets the original value and passes the processed value to the next processor which processes it and ...

Well, another good thing about processor functions is that all value processors are available for any property.

But before we wax lyrical about processors, let's add another function. The crop() processor takes (at least) two arguments: to which length a string should be cropped and if a string should be appended.

Example 3.16. Two processors in a chain

myObject = Text
myObject.value = "I am so strong!"
myObject.value << 1.crop(8, "...")
myObject.value << 2.wrap("<strong>", "</strong>")


And here is the result:

<strong>I am so ...</strong>

The order in which the processor functions are called is determined by the numerical index (1 and 2 in the above example). Of course you can run a wrap() function then a crop() function, then a wrap() function again and so on. There are a big variety of processors available which you can run multiple times in any order and medium-skilled PHP developers can easily create new ones in a few minutes. And of course you can use variables as arguments for processor functions.

The following example configures a Text object which announces whether the current page has sub pages or not. It uses two new processor functions: an if function which takes a condition as an argument an returns either the value of the second or third argument if the condition was true or not. And a hasSubPages function which returns TRUE if the current page has sub pages:

Example 3.17. Has sub pages or not

yesHasSubPagesMessage = Text
yesHasSubPagesMessage.value = "Yes, this page has sub pages."

myObject = Text
myObject.$yesMessage < yesHasSubPagesMessage
myObject.value << 1.if(hasSubPages(), $yesMessage, "No, this page has no sub pages."


This code surely could have been simplified - but we wanted to demonstrate the use of variables again. As you can see, the property value can even be processed if no value has been assigned earlier.

As already mentioned, you are not restricted to using the built-in processors of the CMS package but can create your own processors. The only requirement is that your public processor method accepts the subject (ie. the value to be processed) as the first argument and returns a string as the result. Once you have programmed your own processor, just call it by specifying the component and method name as seen in the next example:

Example 3.18. Calling user-defined processors

myObject = Text
myObject.value = "Creating processors is easy!"
myObject.value << 1.F3_MyPackage_MyProcessors->translate("spanish")


The expected output of this TypoScript object is something like ¡Crear procesadores es facil! - provided that you wrote a processor which is capable of translating text.

[Tip]Tip

The best way to learn how easy it is to create your own processors is browsing through the code of the functions provided by the CMS package. Just check out the class F3_CMS_TypoScript_Processors.

[Note]Note

If you don't specify a component name but only refer to the processor method name, the component name Processors will be used, preceeded by the currently defined default namespace (you'll get an introduction to namespaces in just a few sections). Of course you can use namespaces instead of specifying the whole component name (1.myNamespace:translate("spanish") instead of 1.F3_MyPackage_MyProcessors->translate("spanish")).

Comments

When a line starts with "//" or "#" it is considered a comment which means that the line is totally ignored in the parsing process.

Example 3.19. Comments

// This is a comment
myObject = HTML
myObject.value = "<div>some HTML code</div>"
# This line is also a comment


A block of comment is indicated by enclosing it into "/*" and "*/". Anything within that comment block will be ignored.

Example 3.20. Comment blocks

/* This is a comment
 ... and this line is within that comment which ...
 ends here: */
myObject = HTML
myObject.value = "<div>some HTML code</div>"


Variables

In some cases it is handy to access a placeholder instead of writing down a whole object definition multiple times. Imagine you're working with boilerplates, some of them are regular Text objects others might be literals, and now you want to create a new object which combines these premade chunks of text. One option to do that is using variables:

Example 3.21. Using variables

boilerplates.helloMessage = Text
boilerplates.helloMessage.value = "Hello you!"

myObject = Text
myObject.$hello < boilerplates.helloMessage
myObject.$goodbye = "Goodbye, see you soon!"
myObject.value = "$hello<br />Nice that you\'re here again.<br />$goodbye"


After parsing and transforming the above TypoScript code into PHP objects, the value of myObject would be "Hello you!<br />Nice that you\'re here again.<br />Goodbye, see you soon!".

As you can see in the example, you create a variable just as if it was a property, but with the difference that you prepend it with a dollar sign "$". You are free to choose any name for your variables as long as you only use characters and numbers.

There are two different usages in the above code: the variable $hello contains a Text object which was copied from the object path boilerplates.helloMessage. The second variable $goodbye is not an object, but contains a literal string. Both are combined into a new string for the myObject.value property. That means: you can assign objects just as well as literals or numbers to your variables and concatenate them to a string. The rule however is that objects must be TypoScript Content Objects which can be rendered as content (contrary to simple TypoScript Objects which are mainly used for storing configuration).

The scope of variables is restricted to the TypoScript object they have been defined in. The following code illustrates how variables can be accessed – and how not:

Example 3.22. The scope of variables

someObjects {
   firstObject = Text
   firstObject.$message = "Hey, I\'m the first object."
   firstObject.value = $message

   secondObject = Text

      # This doesn't work because $message is out of scope:
   secondObject.value = $message

      # This doesn't work either:
   secondObject.value = firstObject.$message

      # But this is a way to get the message of the firstObject:
   secondObject.$secondMessage < someObjects.firstObject
   secondObject.value = $secondMessage

      # However, this code does not lead to the expected result:
   secondObject.$secondMessage < someObjects.firstObject.value
   secondObject.value = $secondMessage

      # Variables can be used within single- and double quotes,
      # but the dollar sign always has to be escaped:
   thirdObject = Text
   thirdObject.$product = "Mountainbike"
   thirdObject.$price = "1500"
   thirdObject.value = "You just bought a $product for \$ $price."
   thirdObject.value = 'You just bought a $product for \$ $price."

}


Constants

Namespaces

The object types which were used in the previous examples exist as real PHP classes, therefore TypoScripts maps TypoScript objects to real PHP objects which have the same properties like the TypoScript objects. The names of these object types, for example Text or HTML are mapped to class names (more precisely: component names). The Typoscript Object called Text is represented by a class with the full name F3_CMS_TypoScript_Text.

The reason why this mapping works is that a default namespace has been defined for the TypoScript object types. In the TYPO3 CMS the default namespace is F3_CMS_TypoScript but it is possible to define additional namespaces in order to use TypoScript object types which are not available in the CMS package. It is even possible to define a different default namespace.

Consider a package CoolForms which provides a new kind of TypoScript object implemented by a class called F3_CoolForms_TypoScript_Form. The following TypoScript code would use that new object type by declaring a new namespace:

Example 3.23. Using namespaces

namespace: forms = F3_CoolForms_TypoScript


lib.someTextObject = Text
lib.someTextObject.value = "Hello, this is a regular Text object."

lib.someFormObject = forms:Form
lib.someFormObject.fields.1 = forms:InputField
lib.someFormObject.fields.1.label = "Your name"


Conditions

The future concept for conditions is still to be discussed.

Includes

You can also add include instructions to your TypoScript code to externalize certain parts or the whole TypoScript code. Here is an example for an include instruction:

Example 3.24. Include instruction

include: source = "FILE: mytyposcript.txt"


We'll have to discuss how a TypoScript include has to look like as soon as the concept for the Resource Manager is settled.