Most people that are initially developing with Grav either modify the default Antimatter theme directly, or copy-and-rename it, providing a separate theme to modify. Each of these approaches have their own issues.
By modifying the base theme directly, any theme update will potentially overwrite changes made. By copying the theme, the theme will not be overridden, but updates and fixes to the core theme, have to be manually merged over to the copied theme.
There is a much simpler, and much more maintainable method however: Theme Inheritance.
Power of Streams
Grav makes extensive use of PHP Streams throughout it's architecture to allow locations of assets and resources to be customizable, and also to provide powerful override capabilities. The most obvious usage of these streams are utilized can be observed in our configuration system. You can override system options, with user provided YAML files, and you can override those with environment-based configuration files.
Streams are also used in themes to tell Grav where to look for Twig templates as well as CSS and JavaScript assets. Implementing the streams is as simple as adding a few lines to a YAML file.
Create Your New Theme
Let's walk through a simple example.
- Create a new folder:
user/themes/mytheme
to house your new theme. - Create a new theme YAML file:
/user/themes/mytheme/mytheme.yaml
with the following content:streams: schemes: theme: type: ReadOnlyStream prefixes: '': - user/themes/mytheme - user/themes/antimatter
- Change your default theme to use your new mytheme by editing the
pages: theme:
option in youruser/config/system.yaml
configuration file:pages: theme: mytheme
You have now created a new theme called mytheme and set up the streams so that it will first look in the mytheme theme first, then try antimatter. So in essence, Antimatter is the base-theme for this new theme.
Make a CSS Modification
The most common modification type involves adding custom CSS styling. The default antimatter theme already supports the ability to use a css/custom.css
file, so all that is needed to be done is to provide one:
mytheme
├── css
│ └── custom.css
└── mytheme.yaml
In this theme we'll put a quick override to ensure things are working as expected:
body a { color: #f00; }
If you reload your browser pointing at your Grav installation, you should see the links all in an awfully-bright hue of red:
If you view the source you will see the proof is in the pudding!
<link href="/user/themes/antimatter/css-compiled/nucleus.css" type="text/css" rel="stylesheet" />
<link href="/user/themes/antimatter/css-compiled/template.css" type="text/css" rel="stylesheet" />
<link href="/user/themes/mytheme/css/custom.css" type="text/css" rel="stylesheet" />
<link href="/user/themes/antimatter/css/font-awesome.min.css" type="text/css" rel="stylesheet" />
<link href="/user/themes/antimatter/css/slidebars.min.css" type="text/css" rel="stylesheet" />
See how all the regular CSS files come from the antimatter theme, while the new custom.css
is being loaded automatically from mytheme.
Make a Template Modification
The purpose of creating your own theme is so that you can make modifications as you need them. For example, perhaps you want to modify the main navigation to add a couple of static links to the end of it. All you need to do is provide an updated version of the templates/partials/navigation.html.twig
file. So create the 'templates/partials` folder structure, and copy over the original template from antimatter:
mytheme
├── mytheme.yaml
└── templates
└── partials
└── navigation.html.twig
Then edit the navigation.html.twig
file and add your customizations. In this case we are simply going to add a link to the getgrav.org site at the end of our normal links:
...
<ul class="navigation">
{% if config.themes.antimatter.dropdown.enabled %}
{{ _self.loop(pages) }}
{% else %}
{% for page in pages.children %}
{% if page.visible %}
{% set current_page = (page.active or page.activeChild) ? 'active' : '' %}
<li class="{{ current_page }}">
<a href="{{ page.url }}">
{% if page.header.icon %}<i class="fa fa-{{ page.header.icon }}"></i>{% endif %}
{{ page.menu }}
</a>
</li>
{% endif %}
{% endfor %}
{% endif %}
<li><a href="http://getgrav.org">GetGrav.org</a></li>
</ul>
Save the file and reload the page. You should see your changes in action:
Advanced Customization
If you want to add a new JavaScript feature for example, you will probably need to add the .js
file to your theme, and also copy-over and modify the templates/partials/base.html.twig
file so you can reference it with the other JavaScript files.
If you wish to make more extensive CSS customizations that go beyond a simple custom.css
file, you may wish to copy over the entire scss/
folder and make your changes there, compiling the resulting CSS into a local css-compiled/
folder.
You can of course customize any part of the original base-theme, just be aware the more you customize, and the more you override, the more that your custom theme will diverge from the base theme that it is inheriting.
If there comes a point where you really don't want to rely on the base theme, you can just copy over the missing elements from Antimatter and remove the stream from the YAML.