Using links in frontend plugins

When it comes to links in frontend plugins, some pitfalls arise which circumvent other vital mechanisms like the “L” flag for multilingual websites and thus creates conflicts while using your extension within the TYPO3 framework. This article demonstrates how to use TYPO3's various API functions for link generation.

Intended Audience This tutorial is intended for all kinds of TYPO3 extension programmers who create frontend plugins or frontend related code using the TYPO3 framework. You should be able to create a basic frontend plugin by using the Extension Kickstarter and have a basic knowledge of how TypoScript works. Why links are so special Your first question probably is, why you should use special functions to create links in TYPO3 at all? Let's have a look at a manually created internal link:

$content = '<a href="index.php?id='.$GLOBALS['TSFE']->id.

    '&doTheMagic=1">Do it!</a>';

That piece of code will work like you expect it: It will jump to the current page and pass the parameter doTheMagic to your script. Great. Almost. Just imagine, you are running a multi-lingual website. The information about the currently selected language will usually be passed from page to page by adding the parameter &L=x to the URL where x is an integer value corresponding with the uid of the sys_language record. Now, if the visitor of your website clicks the magic button in your frontend plugin, the L flag won't be transmitted and the next page will be displayed with the default language, ignoring whatever language has been selected before. Okay, let's take that into account:

$content = '<a href="index.php?id='.$GLOBALS['TSFE']->id.

    '&L=' . intval (t3lib_div::_GP('L')).

    '&doTheMagic=1">Do it!</a>';

Now the L parameter will be added to your URL and the next page will be displayed in the correct language. Great. Almost, because what happens if there are parameters you don't know of?

Obey the rules

If you want to develop clean code within a framework like TYPO3, you have to obey some rules. In our example you have to use certain methods for creating links which might be not as straight-forward as creating the link yourself. But in return these methods will make sure that your code is compatible with other extensions and core functions. Recently a new extension called speakinguris has been published. It simulates static HTML files including folders and subfolders which results in nicely built locators like There are many extensions which have been programmed before speakinguris existed, but they are compatible with the new link style because they are using the TYPO3 API for creating links! The next section describes where you find these functions and how you use them correctly. The base of your frontend plugins At the same time Kasper Skårhøj put the idea of extensions for TYPO3 into reality, he delivered a PHP class which would serve as a basis for all upcoming frontend plugins. This class is called "pi_base", derived from "plugin base". Whenever you create a new frontend plugin with TYPO3's kickstarter wizard, you will find a working hello world example in the extension's directory. This sample code already uses pi_base and maybe you have been using it at some point without really taking notice of it. By the way - the file which contains the pibase is part of the CMS extension and located in typo3/sysext/cms/tslib/class.tslib_pibase.php. Have a look at this file right now, it is well commented and provides some vital features for your own plugins.

Different functions for different purposes

Besides many other nice functions (which could be explained in another tutorial), the tslib_pibase class holds some methods for creating links. The following table gives an overview of these functions with a little hint for their usage:

Function name



Returns a URL to a certain page within TYPO3 by passing the page id. This is useful for creating your own special links or action parameters in an HTML form.


Returns a whole HTML link (<a href="...">...</a>) pointing to a TYPO3 page by passing a page id and a label. This is the most basic way of creating internal links.


Returns a whole HTML link pointing to the current page. Usually you will need this for passing some additional parameters to your plugin.


Returns an HTML link to the current page while keeping currently set values in piVars. We'll discuss piVars later in this article.


Returns a URL to the current page while keeping currently set values in piVars. Use this instead of pi_linkTP_keepPIvars if you only need the URL, not the whole link.


Returns a link to a single display of a certain record. This function is rather special and has to do with the browsing functions in pi_base. We won't discuss that in this tutorial.

Simple linking

Let's start with the easy ones. I'll just give you an example for each of the first three functions. Note that these are very simplistic, non real-world examples and not all parameters of the pi_base methods are discussed here. Again: Have a look into the sources, all the parameters are explained there.


   1:     // Link to the parent page and if there is none, link to

    // the current page instead:

   3:if (intval($GLOBALS['TSFE']->page['pid'])) {

   4:     $label = 'parent page';

   5:     $id = $GLOBALS['TSFE']->page['pid'];

} else {

   7:     $label = 'this page';

   8:     $id = $GLOBALS['TSFE']->id;


  11:     // Create the link and a sample form:

  12:$link = $this->pi_getPageLink($id)

  13:$out = '

  14:     <form action="'.$link.'">

  15:         <input type="submit" value="' . $label . '" />


  17: ';


   1:     // Prepare the trick:

   2:$label = 'Do the magic on a different page';

   3:$id = 43; // The magic page

   4:$params = array (

   5:     'doTheMagic' => 1


   7:     // Create the link:

   8:$out = $this->pi_linkToPage($label, $id, '', $params);


1:     // Get prepared:

   2:$counter = intval (t3lib_div::_GP('tx_myext_counter'));

   3:$label = 'Increase by 1';

   4:$params = array (

   5:     'tx_myext_counter' => $counter + 1,

   6:     'tx_myext_mood' => t3lib_div::_GP('tx_myext_mood'),


   8:     // Create the link:

   9:$out = 'The current value is ' . $counter;

$out .= $this->pi_linkTP ($label, $params)

Side note: In some examples I used the function t3lib_div::_GP() which returns GET and POST variables. If you don't know about the class t3lib_div yet, have a look at it's file in the t3lib/ directory. It contains a great collection of useful functions which make a TYPO3 coder's day easier.

Lazy linking

While these three functions are quite self-explanatory, the remaining two need further examination (I'll skip pi_list_linkSingle which belongs to the list view / single view functions pibase). They do something with the so called piVars, but what are piVars then?

As you have seen in the last example (pi_linkTP), a GET (or POST) variable called tx_myext_mood has been added to the URL parameters although we didn't touch it. This variable might be passed to our script from somewhere else and we now have to take care that we don't lose it while we're linking to our own page.

But why do we have to take care of tx_myext_mood while the type parameter is handled automatically? Well, that is because some parameters might be registered with the linkVars TypoScript directive (see <link http: documentation document-library core-documentation doc_core_tsref current>TSref for details) and tx_myext_mood obviously isn't.

Wouldn't it be great if we could register a certain set of parameters (ie. variables) which we use in our extension and they are passed to our script each time we link to it? That's what the piVars are for.


Actually piVars is only an array in the pi_base class which we can use in our frontend plugin (because it is inherited from pi_base). Let's fill it with some important information:

$this->piVars['mood'] = 'great';

$this->piVars['boardingSkillLevel'] = 'neverSeenSnow';

Now, if you use the link functions with ...keepPIvars in their name, you won't have to take care of these values – they are just passed with each link you create:

$out = pi_linkTP_keepPIvars ('link to myself');

will generate a link like this:

<a href="index.php?id=3&tx_myext[mood]=great&tx_myext[boardingSkillLevel]=neverSeenSnow">link to myself</a>

... and if you changed your mood in the meantime, just modify the parameter:

$out = pi_linkTP_keepPIvars ('link to myself',

array ('mood'=>'overwhelmed', 'boardingSkillLevel' => null));

<a href="index.php?id=3&tx_myext[mood]=overwhelmed>link to myself</a>

Play around with this concept and especially have a look at the sample code the kickstarter wizard creates for you.

Special kinds of ...

Maybe you have seen a URL on a TYPO3 which looks much fancier than the default index.php?id=4&L=3 way. The good news is that you don't have to take care of the as long as you use the pibase link methods (or typolink in tslib_cObj directly). But nevertheless I'll give you a hint where to find out more about the different URL/URI styles.

Example URI

What's that?

This TYPO3's default URI style

You get this type of URIs if you enable the simulateStaticDocuments option. Find out more about simulateStatic in the TS reference:

<link http: documentation document-library>

Although they never produced a sound, they are called speaking URIs and are available in TYPO3 from version 3.6.0 and up. You'll need the extension speakinguris or realurl:

<link http: documentation document-library speakinguris>

<link http: documentation document-library speakinguris realurl><link http: documentation document-library realurl>

Conclusion Although it seemed annoying having to use certain functions for link generation, it is indispensable for a proper integration of your extension into the TYPO3 framework. It even turns out that it can make your life easier because it takes care of your link parameters automatically. Last but not least, using the pibase linking functions is a pre-requisite for using fancy URI styles like those from the Speaking URI extension.

Further reading

Coding Guidelines
Extdeveval Thanks I'd like to thank Sacha Vorbeck who graciously offered some sponsorship for me writing this article and René Fritz who took the time reading this article and sharing his fresh experiences from the TYPO3 book. About the author Robert Lemke is an active member of the TYPO3 developer community and founding member of the TYPO3 Association. He lives in Lüneburg / Germany together with Heike, his lovely girl-friend and Vibiemme, their espresso-machine.