This page documents every key accepted by sculpin_kernel.yml – the file that configures Sculpin’s bundles, the pieces of functionality the kernel wires up before it can read a single source file.
A site’s day-to-day behaviour (titles, permalink patterns for a single post, taxonomy values) lives in front matter or in sculpin_site.yml instead. Sculpin itself is a static site generator built on PHP and Symfony components.
This reference covers the Sculpin 3.x series, the current stable line as of the sculpin/sculpin release history. A 4.0 alpha exists but is not covered here.
File location and role
Sculpin expects a fixed project layout. sculpin_kernel.yml sits in app/config alongside the site metadata files:
|-- app/
| |-- SculpinKernel.php # Custom Sculpin kernel
| `-- config/
| |-- sculpin_kernel.yml # Sculpin's configuration (optional)
| |-- sculpin_site.yml # Site meta data
| `-- sculpin_site_${env}.yml # Env specific meta data
|-- output_${env}/ # Env specific generated files
|-- source/ # Files that get read and compiled
`-- composer.json # Dependencies
sculpin_kernel.yml versus sculpin_site.yml
Both files sit in app/config, but they answer different questions.
| File | Answers | Environment-aware? |
|---|---|---|
sculpin_site.yml |
What is true about the site itself: title, base URL, custom variables for templates | Yes, via a matching sculpin_site_${env}.yml that is merged in with an imports directive |
sculpin_kernel.yml |
Which bundles are configured and how: permalink strategy, ignored files, themes, content types, services | Yes: app/config/sculpin_kernel_${env}.yml is loaded instead of sculpin_kernel.yml when it exists for the active environment. Only one of the two is ever loaded, never both |
The distinction matters because bundle configuration, in Sculpin’s own words, is „where very advanced configuration will happen for things that are not controllable by content in the source/ folder“ (Configuration).
Before either file is read, Sculpin loads its own built-in defaults (the source of the default posts type further down this page). Source in code: AbstractKernel::registerContainerConfiguration().
Registering a bundle first
A key only does something in sculpin_kernel.yml if the bundle that defines it has been registered. Registration happens in PHP, not YAML, in app/SculpinKernel.php:
<?php
use Mavimo\Sculpin\Bundle\RedirectBundle\SculpinRedirectBundle;
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
class SculpinKernel extends AbstractKernel
{
protected function getAdditionalSculpinBundles(): array
{
return [
SculpinRedirectBundle::class,
];
}
}
Return the class name as a string, never an instance and never a keyed array (Extending Sculpin: Configuration). Sculpin’s own core bundles (the ones behind the sculpin, sculpin_theme and sculpin_content_types keys below) are registered by default and need no such entry.
Top-level keys
| Key | Provided by | Purpose |
|---|---|---|
sculpin |
Sculpin core bundle | Permalink strategy, source/output directories, ignored/excluded/raw file patterns |
sculpin_theme |
Theme bundle | Named theme to load from source/themes |
sculpin_content_types |
Content Types bundle | Definition of posts and any custom content type |
services |
Symfony’s service container | Ad hoc service and event-subscriber registration |
sculpin_<name> |
Third-party bundles | Bundle-specific settings, see below |
The sculpin key
This is the core bundle’s own namespace.
- permalink
- The default permalink pattern applied to every source unless overridden in its own front matter.
- ignore
- An array of glob-style patterns for files that should never be read as sources at all.
- exclude
- An array of glob-style patterns for files that, like
ignore, never become sources, but with one difference: when a matched file changes, Sculpin marks every other source as changed too, forcing a full regeneration. Useful for a shared file (a Sass partial, a data file) that several pages depend on without being a source itself. - raw
- An array of glob-style patterns for files that should be read as sources but copied through unprocessed, skipping Markdown, Textile or Twig handling.
- source_dir
- Where Sculpin reads sources from. Defaults to
%sculpin.project_dir%/source. - output_dir
- Where the generated site is written. Defaults to
%sculpin.project_dir%/output_%kernel.environment%, so adevbuild and aprodbuild never collide.
sculpin:
permalink: pretty
sculpin:
ignore: ["**/*~"]
Source in code: the schema for all six keys is SculpinBundle’s Configuration class. The ignore / exclude / raw behaviour described above is implemented in FilesystemDataSource::refresh(), wired up with services.xml.
Permalink styles
| Style | Behaviour | Example |
|---|---|---|
none |
Uses the source pathname as-is | source/about.html becomes about.html |
date |
Turns a leading date in the filename into folders | source/2014-04-10-article.html becomes 2014/04/10/article.html |
pretty |
Appends index.html so the URL has no extension |
source/about.html becomes about/index.html |
A permalink can also be a custom pattern built from tags:
| Tag | Meaning |
|---|---|
:year |
Four-digit year |
:yr |
Two-digit year |
:month |
Two-digit month |
:mo |
Month without leading zero |
:day |
Two-digit day |
:dy |
Day without leading zero |
:title |
Slugified title |
:slug_title |
Slug, or slugified title if no slug is set |
:filename |
The source filename |
:slug_filename |
Slug, or filename if no slug is set |
:basename |
Filename without extension |
:basename_real |
Filename including extension |
:folder |
The subfolder a source lives in, if any (type folders such as _posts are stripped) |
sculpin:
permalink: blog/:year/:month/:day/:slug_title
A trailing slash in the pattern produces a trailing slash in the generated URL as well as an index.html file on disk. Source: Configuration. All three fixed styles and every tag substitution above are implemented in one place: SourcePermalinkFactory::generatePermalinkPathname(), the single best starting point for tracing exactly how a given source ends up at a given URL.
The sculpin_theme key
Themes bundle layouts, views and assets under source/themes. Support for this bundle has been stable since early 2014 but is still documented as experimental, so treat the API as subject to change.
- theme
- The
vendor/namepath of the theme to load, resolved undersource/themes. - directory
- The base directory themes are resolved from. Defaults to
%sculpin.source_dir%/%sculpin_theme.project_dir%and rarely needs to change.
sculpin_theme:
theme: myApp/myTheme
Asset resolution checks source/ first, then the theme directory, then any parent theme declared in a theme.yml file inside the theme folder itself (parent: 'myApp/parentTheme'). Template code reaches theme assets with the theme_path() Twig helper, for example {{ theme_path("css/style.css") }}. Source: Themes.
Source in code: both keys are declared in ThemeBundle’s Configuration class, and the theme.yml / parent lookup happens in ThemeRegistry::findActiveTheme().
The sculpin_content_types key
Each top-level key under sculpin_content_types names a content type. posts is the one built-in type, enabled for every project by default:
sculpin_content_types:
posts:
type: path
path: _posts
permalink: pretty
taxonomies:
- tags
- categories
Override only what you need to change, for example the permalink:
sculpin_content_types:
posts:
permalink: blog/:year/:month/:day/:filename/
or disable the type outright:
sculpin_content_types:
posts:
enabled: false
Source: Posts. This exact block, verbatim, is Sculpin’s own built-in default, loaded before your project’s sculpin_kernel.yml and overridden by anything you place under sculpin_content_types.posts: SculpinBundle/Resources/config/kernel.yml.
A key from an older Sculpin version, sculpin_posts, still exists as a bundle but now does nothing except fail: any use of it raises an InvalidConfigurationException pointing at sculpin_content_types instead. If a tutorial or blog post you find while researching this still refers to sculpin_posts, it predates that change. Source in code: SculpinPostsExtension::load().
Type configuration keys
- singular_name
- The singular form of the type name. Defaults to a singularised version of the type name.
- type
- Either
path(sources are located by directory) ormeta(sources are located by a front matter value). - path
- Used when
type: path. The directory to scan, relative tosource/. Defaults to the type name with an underscore prefix, so a type namedtalksdefaults to_talks. - meta_key
- Used when
type: meta. The front matter key checked on every source. Defaults totype. - meta
- Used when
type: meta. The value that front matter key must hold to match this type. Defaults to the singularised type name. - publish_drafts
- Whether draft sources of this type are published. Defaults to
falsein theprodenvironment andtrueotherwise. - layout
- The default layout template for this type. Defaults to the singularised type name.
- permalink
- The default permalink pattern for this type.
- enabled
- Whether the type is active at all. Defaults to
true. - taxonomies
- A list of taxonomy names (such as
tags) to generate proxy data providers and index pages for. Each entry can also be an array with astrategieslist, though this is not covered by the official documentation.
Source: Custom Types. The full schema for these nine keys is declared in ContentTypesBundle’s Configuration class. Every default mentioned above (the _<type> path, the type meta key, the environment-dependent publish_drafts, the singular-name fallback for layout) is applied in SculpinContentTypesExtension::load().
Generating the YAML with content:create
The content:create command writes out a starting configuration block plus placeholder templates:
vendor/bin/sculpin content:create -b -t tags projects
produces:
sculpin_content_types:
projects:
type: path
path: _projects
singular_name: project
layout: project
enabled: true
permalink: projects/:title
taxonomies:
- tags
The command prints this block to the console; it still has to be copied into sculpin_kernel.yml by hand. Source: Custom Types.
What a content type produces
Given a type named projects, the bundle wires up, among other things, a projects data provider (with next_project / previous_project metadata on each item), a projects_tags taxonomy data provider, and a projects_tag_index generator that creates one page per tag. Source: Custom Types. The data provider and, inside the taxonomies loop, the per-taxonomy provider and index generator are both built in SculpinContentTypesExtension::load().
The services key
Because sculpin_kernel.yml is loaded by Symfony’s dependency injection container, it accepts a plain services section like any Symfony application config, not only the bundle-specific keys above. This is how a project registers its own event subscribers without writing a full bundle:
services:
skip_sources:
class: SculpinTools\SkipSources
arguments:
- ["components/*", "_css/*", "_js/*"]
tags:
- { name: kernel.event_subscriber }
The kernel.event_subscriber tag makes Symfony call the class’s getSubscribedEvents() method and register it for whichever Sculpin lifecycle events it listens for. Source: How to make Sculpin skip certain sources, Matthias Noback.
A services block does not have to live inside sculpin_kernel.yml at all. If a file named app/config/sculpin_services.yml exists, Sculpin loads it automatically, before sculpin_kernel.yml and with no imports directive needed, which is a convenient place to keep service definitions separate from bundle configuration. Source in code: AbstractKernel::buildContainer().
Bundles can define their own dependency injection tags for the same services key. The CommonMark bundle, for instance, lets a project register an extension class under its own tag:
services:
league.commonmark.tablextension:
class: League\CommonMark\Extension\Table\TableExtension
tags:
- { name: sculpin_commonmark.extension }
Source: sculpin-commonmark-bundle.
Third-party bundle namespaces
Once a bundle is registered in SculpinKernel.php, it typically exposes its own top-level key in sculpin_kernel.yml. A few published examples:
| Bundle | Key | Notable options |
|---|---|---|
| sculpin-less-bundle | sculpin_less |
extensions, files (a files whitelist takes precedence over the extensions whitelist) |
| sculpin-scss-bundle | sculpin_scss |
formatter_class (defaults to the compressed scssphp formatter), extensions, files |
| sculpin-commonmark-bundle | none of its own; extended through services |
Exposes services such as sculpin_commonmark.environment and the sculpin_commonmark.extension tag |
Example for the SCSS bundle:
sculpin_scss:
formatter_class: 'Leafo\ScssPhp\Formatter\Compressed'
extensions: ["scss"]
files: ["assets/css/style.scss"]
All three bundles also rely on the core sculpin.ignore key to keep their unprocessed source files (partials, imports) out of the generated site:
sculpin:
ignore: ["assets/css/_imports/"]
A composite example
Pulling the namespaces above into one file:
sculpin:
permalink: pretty
ignore: ["**/*~", "assets/css/_imports/"]
sculpin_theme:
theme: myApp/myTheme
sculpin_content_types:
posts:
permalink: blog/:year/:month/:day/:filename/
projects:
type: path
path: _projects
singular_name: project
layout: project
permalink: projects/:title
taxonomies:
- tags
sculpin_scss:
extensions: ["scss"]
files: ["assets/css/style.scss"]
services:
skip_sources:
class: SculpinTools\SkipSources
arguments:
- ["components/*"]
tags:
- { name: kernel.event_subscriber }
Where to look in the source
A quick map from each fact on this page to the exact class or file that implements it, all pinned to commit bff3efa of sculpin/sculpin so the line numbers stay accurate:
| Topic | Class / file | Lines |
|---|---|---|
sculpin schema |
SculpinBundle Configuration | 27-39 |
ignore / exclude / raw behaviour |
FilesystemDataSource | 132-185 |
| Permalink styles and tags | SourcePermalinkFactory | 81-163 |
sculpin_kernel.yml / sculpin_kernel_${env}.yml load order, sculpin_services.yml autoload |
AbstractKernel | 88-97, 122-126 |
sculpin_theme schema |
ThemeBundle Configuration | 27-40 |
| Theme parent inheritance | ThemeRegistry | 59-82 |
Built-in default posts type |
SculpinBundle/Resources/config/kernel.yml | 1-8 |
sculpin_content_types schema |
ContentTypesBundle Configuration | 38-84 |
| Content type defaults and wiring | SculpinContentTypesExtension | 44-268 |
Legacy sculpin_posts key (now an error) |
SculpinPostsExtension | 28-39 |
The src/Sculpin/Bundle directory is the fastest way to explore further: every bundle mentioned on this page, and several not covered here (Markdown, Pagination, Twig, Textile), follows the same pattern of a DependencyInjection/Configuration.php for the YAML schema and an Extension.php for what that configuration actually does.
Sources
- Configuration — sculpin.io
- Basic Project — sculpin.io
- Themes — sculpin.io
- Content Types: Posts — sculpin.io
- Content Types: Custom Types — sculpin.io
- Extending Sculpin: Configuration — sculpin.io
- Extending Sculpin: Creating Bundles — sculpin.io
- Extending Sculpin: Community Extensions — sculpin.io
- sculpin-less-bundle — bcremer, GitHub
- sculpin-scss-bundle — devworks, GitHub
- sculpin-commonmark-bundle — bcremer, GitHub
- sculpin/sculpin source code (commit
bff3efa) — sculpin, GitHub - How to make Sculpin skip certain sources — Matthias Noback
- Releases: sculpin/sculpin — sculpin, GitHub
License
This document is © Robert Wetzlmayr and licensed under Creative Commons Attribution-ShareAlike 4.0 International. Reuse, adaptation and redistribution are welcome, including commercially, as long as attribution is given and any adapted version carries the same license. Sculpin itself, and the bundles referenced above, remain under their own MIT licenses; this notice covers the text and structure of this page only, not the software it describes.