Basic stuff

Environment variables

Session variables

Use:

$GLOBALS["TSFE"]->fe_user->setKey('ses', 'playerScore', $score);

to set a session variable which is bound to the session only. Change the first parameter 'ses' to 'user' to bind the variable to the user indefinitly.

Use:

$GLOBALS["TSFE"]->fe_user->getKey('ses', 'playerScore');

to retrieve the session variable.

Important: just setting the session variable is not enough! Use:

$GLOBALS['TSFE']->storeSessionData();

to actually make it all happen!

For performance reasons, you should not call the storeSessionData() function until the very end of your script (assuming that you're setting multiple session variables in your script).

Typo3 System Variables

[Say something about the context where you can use these variables]

$this->pi_getPageLink($GLOBALS["TSFE"]->id)
$this->piVars
$GLOBALS["TSFE"]->fe_user->user["username"];
$GLOBALS['TSFE']->fe_user->user["usergroup"]
$GLOBALS["TSFE"]->fe_user->user["uid"];

Changing the upload limits

If you want to allow your users to upload files larger than 10Mb, you'll have to change the Typo3 upload limits (which defaults to ~10Mb). In the following examples, we'll set the installation to a maximum of 100 Mb.

Of course, your php installation must also support this, so check the php.ini file for:

upload_max_filesize = 100M

In typo3conf/localconf.php, add:

$TYPO3_CONF_VARS["BE"]["maxFileSize"] = 100*1024;
$TCA['tt_content']['columns']['media']['config']['max_size'] = 100*1024;
$TCA['tt_content']['columns']['media']['config']['maxitems'] = 100;
$TCA['tt_content']['columns']['multimedia']['config']['max_size'] = 100*1024;
$TCA['tt_content']['columns']['multimedia']['config']['maxitems'] = 100;

Do not forget to flush the cache.

Building menus

Menus are created automatically in Typo3, based on the hierarchy of the pages. There are, however, two things you can do to influence the appearance of your menus:

  • You can exclude specific pages from the menu. You do this in the page header.
  • You can specify at which level in the page hierarchy the menu should start. You do this through typoscript, as shown below.

Typoscript property entryLevel explained

The entryLevel property specifies where the menu shows up in the page hierarchy. The default value is zero (0), which means that your menu appears on the home page.

What happens if explicitly set entryLevel to a higher (non default) value? Consider this example:

plugin.tx_automaketemplate_pi1 {
 
  elements {
 
    DIV.id.menu_example = 1
 
  }
}
 
temp.mainTemplate {
    # Feeding the content from the Auto-parser to the TEMPLATE cObject:
 
   # Substitute the ###menu### subpart with dynamic menu:  
   subparts.menu_example = HMENU 
   subparts.menu_example.entryLevel = 2
   subparts.menu_example.1 = TMENU
   subparts.menu_example.1 {
      NO.allWrap = <li> | </li>
      NO.stdWrap.htmlSpecialChars = 1
   }

This means that the menu_example will not be shown until the web user has navigated to a web page which is two levels below home - i.e. is a subsubpage of home.

From this subsubpage on, the menu will also be shown on even deeper levels.

Do NOT think of entryLevel as a property which specifies the subpages to include in the menu. Think of entryLevel as the anchor point for your menus.

Update 20060214

It seems as though adding a new template on a subpage (i.e. a page below the home page) “resets” the entryLevel-level to 0 - it looks as though the template says: “okay, the page I am on, is now level 0”.

Setting the target for your menu links

In the TypoScript Object Browser (accessible through “web > template”), find the “target” property for the various menu types. In this example, we set the target for the “sitemap/menu” content-type:

tt_content.menu.20.1.1.target = _self

Using custom made buttons instead of textual menu links

Yes, there is a graphical menu (GMENU in TypoScript), but it relies on some hard to install graphical libraries. Also, you cannot specify - to my admittedly scarce knowledge on this topic - any custom made buttons. This rules out a Typo3-driven icon bar, for instance. Or does it?

Well, you could of course use a static block of html code, which specifies the whole menu. But that would make it hard to register in which menu-section you are. So, displaying a depressed button or a selected icon, for instance, would have to rely on heavy javascripting.

There is another way.

Repress the text in the hyperlink of a menu item

TypoScript allows you to insert an image tag in each of your hyperlinks. It also lets you wrap the hyperlink in a html tag of your choice. What's more, you can also wrap your own html around other values, before or after the hyperlink. Here's an example:

1 = TMENU
1 { 
	NO {
		before.data = field:title
		before.wrap = <span class="menuItem_NO" id="|MenuItem_NO">             
 
		stdWrap.wrap = <img src="empty.gif" class="filler"/><span class="link">|</span>
		after.wrap = </span>
	}

This TypoScript code, applied to a site structure in Typo3, will yield in an html menu. Here's a snippet of example html code, where the Typo3 page title was “game”.

<span class="menuItem_NO" id="gameMenuItem_NO">
	<a href="index.php?id=48" onfocus="blurLink(this);">
		<img src="empty.gif" class="filler"/>
		<span class="link">game</span>
	</a>
</span>

Let's dig into the TypoScript. First, the title of the page, derived from field:title, is wrapped in the starting tag of a span element. The result is used in before.wrap, which is inserted before the actual hyperlink, as you can see in the html code.

The hyperlink, in turn, is wrapped around an image element, which is just there as filler to satisfy a certain browser from some obscure company in Redmond, Washington (this browser is called “MS Internet Explorer”).

And finally, because we have used an opening span tag, we also need a closing span tag. This span tag is added after the whole hyperlink wrap by using the TypoScript after.wrap = </span>.

Okay, but we promised you an image-based menu, such as a toolbar. So what is that text doing there? Well, that's where css comes to the rescue. Observe that the hyperlink text, “game” in our example, is wrapped in a span element of class “link”. Now let's use this css class to repress the text!

.link {display:none;}

As anybody with some knowledge of the stylesheet specifications will tell you, this will completely and utterly eradicate the span element, and all text within it, from your browser display.

Spice up your toolbar

Any cool toolbar has icons which can be in three states:

  • selected (button has been pressed)
  • being pointed at with the mouse cursor
  • just sitting there (unselected, no mouse cursor hovering above it)

So, let's add a little css to create these three states for our icons.

.menuItem_NO a, .menuItem_ACT a {float:left;width:80px;height:80px;}
#gameMenuItem_NO a {background-image:url('images/game.jpg');}
#gameMenuItem_NO a:hover {background-image:url('images/game_hover.jpg');}
#gameMenuItem_ACT a {background-image:url('images/game_selected.jpg');}

Why do we endow all these properties on the hyperlink (“a” element)? Well, all the other browsers happily let you hover over a floating span tag and have the background image changed. But not MS Internet Explorer.

Adding frontend users

Frontend users can only be added in sysFolders!

Div around your content instead of just paragraphs

Content is stored in the tt_content table. Configuring the wraps around your content is managed through the tt_content top level object, but it is exceptionally hard to find any information on this object.

The following was derived from mailing lists etc..

tt_content.stdWrap.wrap = <div class="box"> | </div> 

Wraps all content in div tags. Put this line right after your plugin.tx_automaketemplate_pi1 configuration.

Div around specific columns

In a default Typo3 setup, there are four content columns numbered 0 - 3. The following code allows you to wrap each Typo3 column in a specific class.

temp.customWrap < tt_content.stdWrap
temp.customWrap {
	# CASE is Typoscript language construct (cf. Switch in PHP)
	prepend = CASE
	prepend {
		# key.field: which values should be compared? (Here: the columns)
		key.field = colPos
		default = TEXT
		default.value = <div class="normal">
		1 = TEXT
		1.value = <div class="left">
		2 = TEXT
		2.value = <div class="right">
		3 = TEXT
		3.value = <div class="border">
	}
	append = CASE
	append {
		key.field = colPos
		default = TEXT
		default.value = </div>
		1 = TEXT
		1.value = </div>
		2 = TEXT
		2.value = </div>
		3 = TEXT
		3.value = </div>
	}
}
tt_content.stdWrap >
tt_content.stdWrap < temp.customWrap 

Note: it is also very hard to find a decent explanation of the typoscript language construct CASE.

Page specific content for subParts

Sometimes, you want template items to display the same content most of the time, and switch content only on a certain page or subsite.

Use typoscript constants in your template to set the content site-wide, then use the typoscript constants setup for specific pages to change the content for a specific page. E.g:

In the constants section:

payOff = helps you out <span class="pay_off2">on the web</span>

In the template:

subparts.pay_off = TEXT
subparts.pay_off.value = {$payOff}

On a specific page:

payOff = helps you out <span class="pay_off2">on e-learning</span>

ee_blog Extension

<BR/> wrap

By default, the ee_blog extension will use <br/> tags to wrap paragraphs. This is of course awful. Turn it off by setting content_stdWrap to false (0) in the ext_typoscript_setup.txt file for this extension:

content_stdWrap.br = 0

Strangely enough, you are required to change this setting in several places.

Photo album extension: goof_fotoboek

First, use Google's Picasa (www.picasa.com) to scale the images to the correct size (400 pixels, about 90% image quality). Then, upload the images to a dedicated directory, e.g. “holiday2005”.

On the server, issue the following command to ensure all files are displayed in the correct order:

rename P 20050305_P P*

This command prefixes all files with the date 20050305.

Rich Text Editor extension: rtehtmlarea

The rtehtmlarea plugin will not install properly under MS IE if you do not remove the old RTE (extension key rte) first. That's all folks.

Linking your website's css styles to the rtehtmlarea rich text editor

First of all, install the rtehtmlarea extension and set Default configuration settings to ”Advanced”. Otherwise your own PageTS configuration will be overruled!

Now, simply link your css style sheet (a *.css file) to the rtehtmlarea extension. Add the following code to the Page TSConfig of your root page (you can reach the proper input screen through 'page info'):

RTE.default.contentCSS = fileadmin/css/typography.css
RTE.default.useCSS = 1

All css rules which mention an element in their selector (e.g. div.myClass), are now available in the editor.

Warning: if you do not see the expected results, restart your browser. The rtehtmlarea text editor is a browser plugin after all, not a web page.

Example configuration

Here is an example configuration:

RTE.default.contentCSS = fileadmin/css/typography.css
RTE.default.useCSS = 1
RTE.default.showTagFreeClasses = 1
 
RTE.config.tt_content.bodytext.proc {
   allowedClasses=uitleg_begrip,H1, H2, H3, P, bodytext, authors
   denyTags=font, size
}
RTE.default.showButtons = *

Problems with tags being removed automatically

This was a tricky problem to tackle: you go to the html-edit mode, type in a tag, and save your text. And your tag is… gone!

Sources on the web, including the official documentation for rtehtmlarea, say that you can include the following code in the Page TSConfig of your root page:

RTE.default.proc.allowTags = table, ..., sdfield

(where the three dots stand for all the other allowed tags). This configuration is also automatically added to your Typo3 system, if you install the rtehtmlarea extension - judging by the code in the ext/rtehtmlarea/pageTSConfigFull.txt file.

This did not cut it for me, however. I had also tried to use the deprecated preserveTags, but that did not work either: my own tags kept getting stripped.

Well, it seems that the <span> and <div> tags, and probably some more, just get stripped anyway, regardless of what you specify in the allowTags configuration.

In fact, the only way to have your <span> tags survive a save-operation, is to link them to a class:

RTE.config.tt_content.bodytext.proc {
   allowedClasses=signalWord,H1, H2, H3, P, bodytext, authors
   denyTags=font, size
}

- where you also have a css entry:

span.signalWord {background-color:yellow;}

Now, if you select a text in the RTE, you'll see that you can select 'signalWord' in the combobox 'text'. This comes down to applying the css class 'signalWord' to the selected text. The RTE automatically inserts the <span> and </span> tags around the selected text, and it adds a class attribute to the span tag.

File browser extension: moc_filemanager

This extension is a bit tricky to install. Here are some points which merit your attention:

  • file permissions on the server for the mount point must be 777
  • relative path for the mount point is really an absolute path from your server root (not the webserver's document root, but the real root root) to the directory you want to mount. So:

/rootdir/mydir/dir_to_mount/ is wrong

''**rootdir/mydir/dir_to_mount **''is right
  • relative path must not start nor end with a slash (/)
  • deleting directories does not work under Windows

Frontend Editing Options for Everyone

If you think the Typo3 backend is too complicated or the interface is just not slick enough for most of your users, consider editing your website in the frontend. You can even let ordinary frontend users edit your site.

Pencils in the frontend: let your backend users edit in the frontend

Let's start with your backend users. If you want to make the frontend editing options available to your backend users, do the following.

In your template, add the following line:

page.config.admPanel = 1

This will make the admin panel available in all pages that rely on your template. If you're the admin user, you will now always get to see the admin panel. First, you have to log in to the backend. Now you will get to see the admin panel if you access the website through Typo3, for instance by choosing the magnifier-icon for a particular page (show option in page tree).

If you want to make the admin panel available to other backend users, use “Tools > Useradmin” and add the following typoscript code to the “Tsconfig” field:

admPanel {
  enable.edit = 1
  module.edit.forceDisplayFieldIcons = 1
  hide = 0
}

But what if you only want to display the pencils, but not the panel itself? Just change hide = 0 to hide = 1.

Permissions do not always translate into pencils, or how to avoid irrelevant pencils

If you do not want to give your users access to all page or content elements, simply deny them the access by setting the relevant “Explicitly allow/deny field values” in the backend, under “List” > “Globe”, where you can determine user- and usergroup settings.

The “denied” parts will still be shown with a pencil in the frontend, however. If you would like to not show a pencil for a certain content element, you have to resort to a trick: simply leave the “header” field empty.

Of course, if a user does not have any rights at all for a certain page, then no pencils will show up in the frontend.

Pencil not showing up?

If the content on a certain page is in fact derived from another page, then the user must have permissions for both pages. Otherwise, the pencil will not show up for this content.

Also, make sure that you make the “pencil-editable” page the top-level page in a db-mount! (Or else, give the user the same usergroup which has access rights to the pages above).

Frontend users editing the website: simulatebe extension

You can also let your ordinary frontend users edit the website. Just plug in the simulatebe extension. The documentation is a little terse, so here's some additional information on configuring this extension.

For this extension to work, you need to link a backend user to a frontend user account. So, first of all, go through the steps described above. Do not forget to add the backend user specific TS configuration.

Now, find the section in your template where the header is defined. Add the following code:

page.headerData.10 < plugin.tx_simulatebe_pi1

But pay close attention to the context. If you already have header data (which is extremely likely) you will not want to overwrite this. So, here's an example with some more context:

# Copying the content from TEMPLATE for <head>-section:
page.headerData.10  < temp.headTemplate
page.headerData.11 = TEXT
page.headerData.11.value= <script type="text/javascript" src="menu.js"></script>
page.headerData.12 < plugin.tx_simulatebe_pi1

As you can see, we have changed the dummy key “10” to “12”, because “10” was already taken (remember, typoscript is just a way of defining and filling PHP arrays).

Be aware that there are some issues with the simulatebe extension. I have a problem, for example, when I link a frontend user to a random, non-admin backend user. Whenever I log out of the frontend with this user, my admin backend user is logged out too! Even though it is not even linked to the front end user.

20051013: This issue mentioned above only pops up when you're using the same computer, and the same browser. In other words: it's a cookie issue. It should not stop you from using simulatebe extension.

Note of attention when using RTE

I haven't had time to confirm this, but I suspect that things go awry if the backend user is configured with another language than the default language of the site. In that case, the RTE is not shown.

phpMyAdmin under Windows

If you install Typo3 on a Windows machine, chances are that the newer versions of phpMyAdmin (starting with 2.5.6) do not work. If you try to run the module from within Typo3, you'll get an error message:

Error in init.php: Path to TYPO3 main dir could not be resolved correctly. 

Solving this is surprisingly easy. Go to the extension's installation directory. This is usually typo3\ext\phpmyadmin. Here, find the file conf.php, and replace line 13 (or somewhere near) with the following code (should be somewhere near line 13):

$MCONF['phpMyAdminSubDir'] = 'phpmyadmin-2.6.4-pl3/';

The replacement code has all undercast in the right hand side of the assignment.

So, in your directory structure, change the name of the folder to all undercast too. That's all folks!

Descriptive urls: realurl extension

Use the extension called realurl to have your Typo3 page titles used in the urls. E.g.:

http://greatcampsites.com/index.php?id=32

will be translated into for instance http://greatcampsites.com/france/

The Apache side of things

You are going to need the Apache mod_rewrite module for this to work. Once this module is installed, there are two ways to configure mod_rewrite for a website on Apache:

  • .htaccess (a file in the public_html or web root of the site)
  • httpd.conf (Apache's configuration file)

I have used the latter method. Here's an example:

<VirtualHost 213.193.214.124:80>
  ServerName campingbeurs.solin.nl
  ServerAlias www.campingbeurs.solin.nl
  DocumentRoot /home/solin/domains/campingbeurs.solin.nl/public_html
  ErrorLog /home/solin/domains/campingbeurs.solin.nl/logs/error_log
  CustomLog /home/solin/domains/campingbeurs.solin.nl/logs/access_log combined
  ScriptAlias /cgi-bin/ /home/solin/domains/campingbeurs.solin.nl/cgi-bin/
 
  ## Rewriting for realurl
  RewriteEngine On
  RewriteRule ^/(typo3|typo3temp|typo3conf|t3lib|tslib|fileadmin|uploads|showpic\.php)(/.*)?$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule ^/(.*)$ /index.php [L,E=ORIG_SCRIPT_NAME:/index.php]   
 
  <Directory /home/solin/domains/campingbeurs.solin.nl/public_html>  
    Options -Indexes IncludesNOEXEC FollowSymLinks          
  </Directory>
</VirtualHost>

Please refer to the realurl or Apache documentation to see what it all means exactly.

The Typo3 side of things

Put the following in your localconf.php file (you can edit this file with the Typo3 installation module, if you want to):

$TYPO3_CONF_VARS['FE']['addRootLineFields'].= ',tx_realurl_pathsegment,alias,nav_title,title';
 
$TYPO3_CONF_VARS['EXTCONF']['realurl'] = array(
   '_DEFAULT' => array(
       'init' => array(
           'enableCHashCache' => 1,
           'appendMissingSlash' => 'ifNotFile',
           'enableUrlDecodeCache' => 1,
           'enableUrlEncodeCache' => 1,
       ),
       'redirects' => array(),
       'preVars' => array(
           array(
               'GETvar' => 'no_cache',
               'valueMap' => array(
                   'nc' => 1,
               ),
               'noMatch' => 'bypass',
           ),
           array(
               'GETvar' => 'L',
               'valueMap' => array(
                   'dk' => '2',
                   'de' => '1',
               ),
               'noMatch' => 'bypass',
           ),
       ),
       'pagePath' => array(
           'type' => 'user',
           'userFunc' => 'EXT:realurl/class.tx_realurl_advanced.php:&tx_realurl_advanced->main',
           'spaceCharacter' => '_',
           'languageGetVar' => 'L',
           'expireDays' => 7,
           'rootpage_id' => 472,
       ),
       'fixedPostVars' => array(),
       'postVarSets' => array(
           '_DEFAULT' => array(
               // news archive parameters
               'archive' => array(
                   array(
                       'GETvar' => 'tx_ttnews[year]' ,
                       ),
                   array(
                       'GETvar' => 'tx_ttnews[month]' ,
                          'valueMap' => array(
                           'january' => '01',
                           'february' => '02',
                           'march' => '03',
                           'april' => '04',
                           'may' => '05',
                           'june' => '06',
                           'july' => '07',
                           'august' => '08',
                           'september' => '09',
                           'october' => '10',
                           'november' => '11',
                           'december' => '12',
                              )
                       ),
                   ),
               // news pagebrowser
               'browse' => array(
                   array(
                       'GETvar' => 'tx_ttnews[pointer]',
                       ),
                   ),
               // news categories
               'select_category' => array (
                   array(
                       'GETvar' => 'tx_ttnews[cat]',
                       ),
                   ),
               // news articles and searchwords
               'article' => array(
                   array(
                       'GETvar' => 'tx_ttnews[tt_news]',
                       'lookUpTable' => array(
                           'table' => 'tt_news',
                           'id_field' => 'uid',
                           'alias_field' => 'title',
                           'addWhereClause' => ' AND NOT deleted',
                           'useUniqueCache' => 1,
                           'useUniqueCache_conf' => array(
                               'strtolower' => 1,
                               'spaceCharacter' => '-',
                               ),
                           ),
                       ),
                   array(
                       'GETvar' => 'tx_ttnews[swords]',
                       ),
                   ),
               ),
           ),
       // configure filenames for different pagetypes
       'fileName' => array(
           'index' => array(
               'rss.xml' => array(
                   'keyValues' => array(
                       'type' => 100,
                   ),
               ),
               'rss091.xml' => array(
                   'keyValues' => array(
                       'type' => 101,
                    ),
               ),
               'rdf.xml' => array(
                   'keyValues' => array(
                       'type' => 102,
                   ),
               ),
               'print.html' => array(
                   'keyValues' => array(
                       'type' => 98,
                   ),
               ),
               'atom.xml' => array(
                   'keyValues' => array(
                       'type' => 103,
                   ),
               ),
           ),
       ),
   ),
);

Set the value for rootpage_id to your actual root page.

In your main template (i.e. the template for the root page), add this:

## Rewrite urls
config.simulateStaticDocuments = 0
config.baseURL = http://greatcampsites.com
config.tx_realurl_enable = 1
config.prefixLocalAnchors = all 

Please do not forget to mention the protocol (e.g. http) in config.baseURL, or things will go wrong!

Pitfalls

20061210

Not only do you need to mention the protocol, set the value for rootpage_id, but you also need to:

  • set: 'enableUrlDecodeCache' ⇒ 0, in localconf.php, in the array under the key init
  • set: 'firstHitPathCache' ⇒ 1, under pagePath

You will probably notice a performance decrease when you do not cache the url decoding mechanism, but on one of my clients' sites, I couldn't get realurl to perform decently. I just kept running into:

Error!
Reason: Segment "xxxx" was not a keyword for a postVarSet as expected!

Group and Redirect Visitors by Country: dmc_geoip

The extension dmc_geoip uses a visitor's ip-address to redirect the visitor to a subsite. This works well, and is pretty straightforward. Just include the following code in the page where the redirect should take place. This is usually your home page, or any other page where a language selector resides.

The code should be placed in the setup part of your TypoScript template.

modules.tx_dmc_geoip {
  country.rootpages {
    NL = 9
    FR = 11
    GB = 10
    US = 10    
    DE = 12
  }
 
  ## To disable the redirection, uncomment the following line (delete the "##") ~ Verwijder op de volgende regel de "##" om het doorsturen uit te schakelen
  ##redirect = 0
}

The extension maps the ip-address to a country code, using a database. The country code is used in the TypoScript to establish the redirect to a certain page. For instance, in the code above, all visitors from France (FR) are redirected to the page with the id “11”.

Gotchas

1. Do not forget to include this code in the page you're redirecting to (e.g. the root page of a subsite):

modules.tx_dmc_geoip {
  ## To disable the redirection, uncomment the following line (delete the "##") ~ Verwijder op de volgende regel de "##" om het doorsturen uit te schakelen
  redirect = 0
}

This code can be added to an extension template, which contains the same TypoScript for each subsite.

2. Make the redirecting page (e.g. your homepage) a non-cached page.

3. If you're using this extension in combination with realurl (pretty urls for typo3), be sure to set redirect = 0 on (the typoscript template of) the page where you redirect to. So:

  • Home page: redirect = 1 Here you redirect. E.g.: uk visitors go to /english * /english page: redirect = 0 =====Adding new products to so_featurematrix===== Use this query to get all criteria, with the categories in front: <code c> SELECT tx_sofeaturematrix_criteria.uid, tx_sofeaturematrix_categories.label, tx_sofeaturematrix_criteria.label FROM tx_sofeaturematrix_criteria, tx_sofeaturematrix_categories WHERE tx_sofeaturematrix_categories.uid = tx_sofeaturematrix_criteria.category </code>

Personal Tools