Inheriting theme configurations in Grav

Grav's theme inheritance system is great, but how do you retain the configuration options of the parent theme?

Grav's documentation suggests just copying the parent theme's blueprints.yaml into your new theme if you want to retain the configuration options. But the problem here is that this breaks an aspect of your inheritance - if there's an update to the parent theme's configuration options, you will need to manually copy these over.

But there are actually two better ways to do this!

Extending

Theme blueprints can extend other theme blueprints, just like is commonly seen with page blueprints. So if you are inheriting from the default Quark theme, and you just want to add some more options to the bottom, you can just extend the theme's blueprint by adding the following to the top of your theme's blueprints.yaml.

extends@:
  type: blueprints
  context: themes://quark

The key here is to recognise that the file you want to extend is called blueprints.yaml and it lives in the themes://quark folder. Also, you should note that since you are extending the parent theme's blueprint, you also get the name, author, keywords, dependencies etc, from the parent theme, unless you redefine them later in your blueprint or you use unset-*@ (discussed later).

Importing

If you want greater control of where the configuration options get inserted, you need to use import@. This allows you to dynamically insert a form within another form by putting import@ where you would normally have fields. To get the same effect as extends@, but without the name etc being brought in, you can use:

...
form:
  import@:
    type: blueprints
    context: themes://quark

But importing the configuration options gives more control over the structure of the page, so you could for example import the parent theme's configuration into a separate tab:

...
form:
  fields:
    tabs:
      type: tabs
      fields:
        custom:
          type: tab
          title: "Your own configuration options"
          fields:
            ...
        base:
          type: tab
          title: "Quark's configuration options"
          import@:
            type: blueprints
            context: themes://quark

Overwriting options

Regardless of whether you use import@ or extends@, you can overwrite, update, and unset any of the configuration options. For example, the Quark theme has an option called grid-size, which is the maximum width of the theme and has options for "", grid-xl, grid-lg, and grid-md. If you wanted to add an option for grid-2x, you just address all of the keys that you need to change (in this case: fields, grid-size, options) and then add your own content to it.

...
form:
  import@:
    type: blueprints
    context: themes://quark
  fields:
    grid-size:
      options:
        grid-2x: "Even larger!"

The above snippet would retain all of the other options for grid-size (so you could still select grid-md if you want), but appends grid-2x to the list.

Advanced blueprint options

Grav has lots of really useful advanced blueprint features that let you do more than just add to previously defined form fields, and you can find more details in the Grav documentation.

The most useful options for modifying inherited blueprints are unset@, unset-*@, replace@, replace-*@, and ordering@.

Unset

If you want to completely remove the grid-size option from the configuration, you can use unset@ as follows:

form:
  fields:
    grid-size:
      unset@: true

If you want to keep the option, but you want to remove a property from it, you can use unset-*@. For example, if you want to remove the size property of grid-size because you don't want it to be small, you can use unset-size@:

form:
  fields:
    grid-size:
      unset-size@: true

Replace

You can also replace the previous definition with a new one. For example, if you want to make grid-size into a text field, you will want to replace@ it so that the field gets completely replaced by your new definition.

form:
  fields:
    grid-size:
      replace@: true
      type: text
      label: Grid size
      default: grid-2x

If you really like wide websites, you might want to cut the number of options down to just those that you might use, and you can do this with replace-options@: true. This will mean that only the previously defined options are removed, rather than the whole definition, and the options are replaced by the ones defined here.

form:
  fields:
    grid-size:
      replace-options@: true
      options:
        grid-lg: "Large"
        grid-xl: "Extra large"
        grid-2x: "Even larger!"

Ordering

You can also change the order that fields appear in using ordering@. For example, if you think that grid-size is super important and should be the first field in the configuration page, you can set ordering@: 0 to place it in the first position (we're counting from 0).

form:
  fields:
    grid-size:
      ordering@: 0

Similarly, if you want it to be the third field, just set ordering@: 2, and if you want to place it at the end, just set the ordering to a suitably high number.

Note: At the time of writing, the behaviour reported in the documentation differs from the actual behaviour. This article describes the actual behaviour as of June 2020. The documentation says that setting the ordering to -1 will place the field at the top, but it actually places it one up from the bottom.