jberculo
jberculo

Reputation: 1113

Changing template inheritance order in Silverstripe

As per the documentation of Silverstripe, template inheritance is defined as follows:

  1. mysite (or other name given to site folder)
  2. module-specific themes (e.g. themes/simple_blog)
  3. themes (e.g. themes/simple)
  4. modules (e.g. blog)
  5. framework

Now I've got a site that has quite a few different themes. Well, "different" in that they have different names, but they still got an awful lot in common. Now I am putting all the common files in the /mysite/templates folder, but that means that if one of my themes needs a change in one of the templates, I need to remove that file from the common folder, and move it to ALL the different theme folders. In this way I end up with a lot of duplicate templates.

In my case it would be beneficial to change the inheritance order, causing the specific theme folder to take precedence over the /mysite folder. In such a way I could just copy the template that has to be changed to the theme folder and that theme one will use the changed one, while the rest keeps using the generic one in the /mysite folder:

  1. themes (e.g. themes/simple)
  2. module-specific themes (e.g. themes/simple_blog)
  3. mysite (or other name given to site folder)
  4. modules (e.g. blog)
  5. framework

It also seems to me to be the more obviuous way to do it, but I probably am missing some important point here. Nonetheless, would doing this be possible without hacking the core?

Upvotes: 3

Views: 495

Answers (2)

Shaun Cockerill
Shaun Cockerill

Reputation: 926

The question and the accepted answer are for SilverStripe 3, and should be referred to for queries relating to SilverStripe 3.x. The following refers to SilverStripe 4.

As SilverStripe 4 is currently the latest stable version and now sets theme inheritance instead of template inheritance, the question and answer may not be suitable for newer installations or up to date installations.

The best way to control inheritance in SilverStripe 4 is to ensure that the themes are configured in the correct order, and that the module inheritance is configured appropriately.

Your mysite/_config/theme.yml file typically declares the theme inheritance, and you should adjust this file to control theme inheritance appropriately. For modules, you need to specify the appropriate Before and After in your mycustommodule/_config/modules.yml file.

The following example is for a sile with both the mytheme and simple themes, a custom module without an _config/modules.yml file, and a vendor module without an _config/modules.yml file.

SilverStripe\View\SSViewer:
  themes:
    - 'mytheme'
    - 'simple'
    - '$default'

In this example, SSViewer::get_themes() will return those three items as an array in the same order: ['mytheme', 'simple', '$default]. When checking to see if a template exists, $default will then be replaced by the paths of all modules which define templates, in the same order as they appear in the manifest.

<?php
use SilverStripe\View\ThemeResourceLoader;

$templatePaths = ThemeResourceLoader::inst()->getThemePaths(SSViewer::get_themes());
$templatePaths === [
    'themes/mytheme',
    'themes/simple',
    'mycustommodule',
    'vendor/silverstripe/asset-admin',
    'vendor/silverstripe/campaign-admin',
    'vendor/silverstripe/reports',
    'vendor/silverstripe/siteconfig',
    // Some vendor modules may appear here...
    'vendor/othervendor/custommodule',
    'vendor/silverstripe/cms',
    'vendor/silverstripe/admin',
    'vendor/silverstripe/assets',
    'vendor/silverstripe/framework'
];

Upvotes: 2

Turnerj
Turnerj

Reputation: 4278

Template inheritance rendering seems to be managed by two classes predominantly, SSViewer (a core class for handling view rendering) and Controller (which all other controllers inherit from).

For view rendering, a SSViewer object can take an array in its constructor for template inheritance. This is important because the Controller class actually instantiates the SSViewer in a function called getViewer.

It is important to mention at this stage, a normal SilverStripe site you are normally inheriting from ContentController instead which overrides the getViewer of Controller. It won't really change too much of what you need to write but it is important depending how low-level you want this to apply.

For what you want to apply to pages in general, you would be looking at overriding getViewer in your Page_Controller. As for what specifically you would need to write, that is somewhat dependent on your entire site structure. I would imagine it would need to start off a little like this though:

public function getViewer($action) {
    $viewer = Parent::getViewer($action);
    $templates = $viewer->templates();

    //Do your processing that you need to here
    //Set it back via:
    //$viewer->setTemplateFile($type, $file);
    //Alternatively, you can create a new SSViewer object

    return $viewer;
}

It will be a bit of experimentation to work out what exactly you need to do for shuffling around the data though this was never going to be easy. Once you start heading down this path, you likely will find a number of edge cases where this may not work properly (eg. template includes).

Upvotes: 2

Related Questions