From The Document Foundation Wiki

    We currently use Silverstripe for some of our Website infrastructure.

    Setting up a local development environment

    These instructions describe setting up a local development environment for Silverstripe on Linux using the Pod Manager tool (Podman). Podman allows running containers without a daemon and without root privileges. Podman is compatible with Docker. The information is adapted from Podman's rootless tutorial.

    Install podman, podman-compose, slirp4netns, fuse-overlayfs and crun.

    Make sure you are using v2 cgroups. Consult documentation for your Linux distribution of choice regarding this topic.

    Create the subuid and subgid files:

    sudo touch /etc/sub{u,g}id
    sudo usermod --add-subuids 10000-75535 $(whoami)
    sudo usermod --add-subgids 10000-75535 $(whoami)

    Create the configuration to use crun as the OCI (Open Container Initiative) runtime:

    mkdir ~/.config/containers && echo 'runtime = "crun"' >> ~/.config/containers/containers.conf

    Give the command:

    podman info --debug

    Verify that you see

    • CgroupVersion: v2
    • OCIRuntime: name: crun
    • GraphDriverName: overlay

    Create docker-compose.yml:

    version: '3.0'
        image: brettt89/silverstripe-web:latest
          - ./silverstripe:/var/www/html
          - "8080:80"
          - mariadb
        restart: "no"
        image: wodby/mariadb:latest
          MYSQL_DATABASE: silverstripe
          MYSQL_USER: silverstripe
          MYSQL_PASSWORD: password
          MYSQL_ROOT_PASSWORD: password
          - ./mariadbdata:/var/lib/mysql
          - ./override.cnf:/etc/mysql/conf.d/override.cnf
          - "3306:3306"
        restart: "no"

    The volume declarations map local directories and files to locations inside the containers.

    In the directory with the docker-compose-yml:

    mkdir mariadbdata silverstripe

    Note: SS_DATABASE_SERVER="mariadb" matches the name of the database service in docker-compose.yml

    Change into the silverstripe directory and grab composer:

    curl -O

    In the directory with docker-compose.yml, give this command to create and start the containers:

    podman-compose up -d

    Show the running containers:

    podman ps

    Copy the Silverstripe container ID from the output of the previous command and enter the container like so:

    podman exec -t -i <container_id> /bin/bash
    su www-data -s /bin/bash
    php /var/www/html/composer.phar create-project silverstripe/installer libreoffice

    Exit container with Ctrl + P + Q.

    Create a file called .env in the directory silverstripe/libreoffice:


    Build the Silverstripe database by navigating to this address in your web browser: http://localhost:8080/libreoffice/dev/build

    Now you can access your local site at http://localhost:8080/libreoffice/ and the admin interface at http://localhost:8080/libreoffice/admin/

    To stop the containers:

    podman-compose stop silverstripe mariadb

    To start them again:

    podman-compose start silverstripe mariadb

    For help:

    podman-compose --help

    The container data is stored under ~/.local/share/containers/

    Working on the theme

    Theme structure

    Silverstripe supports having multiple themes per site. If there is no need for this, everything is a bit simpler and the directory structure can be laid out like so:


    The file app/_config/theme.yml can simply have this content:

    Name: libreoffice
        - '$public'
        - '$default'

    Every time you modify one of the .yml files or create new .ss files, you need to flush the cache by visiting http://localhost:8080/libreoffice/public/?flush

    Page types

    You can have many page types. You can name them anything you like and Silverstripe associates the model, controller and view files based on the naming.

    • app/src/MyCoolPage.php is conventionally the model, having things like database field definitions and functions that can be used in templates.
    • app/src/MyCoolPageController.php is the controller and does stuff that has to do with requests such as database queries, form submission and authentication.
    • app/templates/ is the view, the template associated with the page type.

    The page types typically extend the Page and PageController classes.

    Every time you create a new page type, you have to rebuild the database. You can rebuild the database and flush the cache at the same time by visiting http://localhost:8080/libreoffice/dev/build?flush

    You can change the type of a certain page in the admin editor view by clicking on the Settings tab and using the Page type dropdown.

    Page types are explained in the Silverstripe lessons The holder/page pattern and Working with multiple templates.


    Silverstripe uses its own templating language instead of plain old PHP. This makes things a bit more complicated and you have to be careful to skip outdated information, when doing web searches.

    Some common things:

    • <% include Header %> will make Silverstripe look for inside the app/templates/Includes directory and include its contents to be rendered
    • $Layout will include the contents of app/templates/Layout/ If there is no separate layout file for the extended page type, it will include the contents of app/templates/Layout/

    Including assets

    Instead of putting your CSS and JS includes inside the .ss files, it is advised to use the Requirements class inside the page controller.

    In the page controller you would have:

    use SilverStripe\CMS\Controllers\ContentController;
    use SilverStripe\View\Requirements;
    // ... skip to the class contents
    protected function init()
        // Uncomment this to include JS inside the <head> element instead of the <body>:
        // Requirements::set_write_js_to_body(false);

    There are some things that you must include in the .ss files themselves. In these cases, you benefit from using the baseURL variable to preserve portability regarding paths. Example:

    <link rel="shortcut icon" href="{$baseURL}images/favicon.ico" />

    Note that this time public/ is left out of the path.

    Creating custom content fields

    Silverstripe does not have functionality for creating new fields inside the admin interface unlike some other CMS applications. Everything has to be done through a somewhat tedious process of editing files and rebuilding the database. This is explained in a Silverstripe lesson.

    An example of an imaginary app/src/MyCoolPage.php defining custom fields:

    // Needed for the admin form inputs
    use SilverStripe\Forms\DateField;
    use SilverStripe\Forms\TextareaField;
    use SilverStripe\Forms\TextField;
    use Page;    
    class MyCoolPage extends Page 
        // Define the fields as 'name' => 'data type in the db'
        private static $db = [
            'Date' => 'Date',
            'Teaser' => 'Text',
            'Author' => 'Varchar',
        // Render the form inputs in the admin.
        // You can optionally label the inputs and also add a longer description.
        // The optional last argument (in this case 'Content') for the create function means "put this before an existing field"
        public function getCMSFields()
            $fields = parent::getCMSFields();
            $fields->addFieldToTab('Root.Main', DateField::create('Date','Date of article'), 'Content');
            $fields->addFieldToTab('Root.Main', TextareaField::create('Teaser')
                ->setDescription('This is the summary that appears on the article list page.'),
            $fields->addFieldToTab('Root.Main', TextField::create('Author','Author of article'),'Content');
            return $fields;

    After rebuilding the dabase, you would be able to use the fields in the admin and include their contents via the .ss files by referring to them by their name such as $Teaser.