Extension structures

TURBOPY uses a flat structure for extensions. Most things consist of these files. Depending on the extension type you usually only need a fraction of them. Check out this example structure:
  • ext/tPy_myExtension
    • tPy_myExtension.php
    •  tPy_myExtension.js
    •  templates.html
    •  view.php
    •  ext_frontend.php
The naming of tPy_myExtension.php and tPy_myExtension.js is important for autoloading mechanisms to work. Both files are expected to contain a class with the same name. In javascript this is usually an object literal with that name. The extension name should contain only one underscore, otherwise it will be treated as a subextension (details below). The name should also reflect the extension type - see the naming recommendations for reference.

templates.html may contain optional HTML templates for javascript templating for example. Will be parsed with php with regular inclusion and can therefore contain multilang setups for example.

view.php is for widget type extensions that are just included somewhere in your main template. Usually it contains mixed PHP / HTML.

ext_frontend.php is only needed for configuration of the extended frontend.


If you follow the naming conventions you can always autoload tPy_myExtension.php without including the file beforehand. So tPy_myExtension::dotThings() for example will just work. You can also enable methods of this class to be accessible with ajax. All you have to do is to add a tPy_conf() method in your class with a configuration like this:
class tPy_myExtension {

  static function tPy_conf() {
     return [
        'ajax_enabled_methods' => [
            'doThings' => true,

   static function doThings($age = 0, $name = '') {
      $age = tPy_sanitize::value($age, [
          'type' => 'INT', 
          'required' => true
      $name = tPy_sanitize::value($name, [
          'type' => 'STRING',
          'max' => 100, 'min' => 2
      if (tPy_sanitize::$error)
           return tPy::error(tPy_sanitize::$error['type']);
      return ['age' => $age, 'name' => $name];

Now you can access the method via ajax with tPy.ajax('tPy_myExtension::doThings')(50, 'John', function(result) { // do something }); for example.
More details on tPy.ajax can be found here.

Including clientside templates & javascript

If your extension uses HTML templates you usually include them in the bootstrap file pub/index.php. This way the templates are always accessible.
Note that you can also use tPy.loadFile() or the autoloading mechanism that is provided by width custom events like data-ondomload. The right choice depends on if you always or almost always need the file or if you only need them if a special content element was added for example. For the latter you should load the javascript via data-ondomload. Check out the tPc_comments example for more info. tPy.loadFile() is usually the best choice if you have to load additional files within your main script. More info on this topic can be found here.
HINT: If you use tPy::getClientIncludes(), data-donomload or tPy.loadFile() you can work with code injections from PHP since these files will be parsed as PHP regardless of their file extension. This is handy for example if you need multilanguage support for your site. The files will be minified and cached on production servers.

The view.php for widgets

So what is a "widget" you might ask. Bascially it is the same type of extension but we also may have view files that are directly included in your main template for example. They may contain mixed php and html and can also use data-ondomload techniques. The name "view.php" is recommended but you can name it as you wish or work with different view files. There is no built-in mechanism that relies on the filename.
HINT: Depending on the type of your extension you should follow the naming recommendations.
Using subextensions

For extensions that need more files and classes you can also nest deeper. That means that you can also create nested structures like this:
  • ext/tPy_myExtension
    •   sub
      •     tPy_myExtension_sub.php
      •     tPy_myExtension_sub.js

These "subextensions" are also supported by the autoloading mechanisms. So you can directly call tPy_myExtension_sub::method or use it with data-ondomload. This way you can organize more complex extensions. Note that only one "nesting level" is supported by the autoloading mechanisms. So tPy_myExtension_sub_sub would not work with autoloading. The trigger is the second underscore.
HINT: Small javascript extensions that are not directly related to another extension go into the js folder.