# Cecil 9.25.0: plugins and a reworked extension mechanism

[Cecil 9.25.0](https://github.com/Cecilapp/Cecil/releases/tag/9.25.0) reworks how Cecil is [extended](/documentation/developers/extend/) with PHP: extensions are declared the same way, can be bundled in a **plugin**, react to **build events**, and are easier to ship with a theme.

### Unified configuration

Page generators, Twig extensions, output post-processors, event subscribers and plugins are now [declared the same way](/documentation/developers/extend/#configuration), as a map indexed by name:

```yaml
pages:
  generators:
    Database: { class: MySite\Generator\Database, priority: 35 }
    Redirect: false # disables a built-in generator
output:
  postprocessors:
    MyProcessor: MySite\PostProcessor\MyProcessor # default priority (100)
```

Built-in extensions are named too: they can be disabled, or moved with a new priority, by their name.

An extension that cannot be loaded (unknown class, wrong interface, invalid option) is skipped and the error is logged. To make the build fail instead, enable the strict mode:

```yaml
extensions:
  strict: true
```

### Plugins

A [plugin](/documentation/developers/extend/#plugins) is a single entry point that registers a set of extensions (generators, Twig extensions, post-processors, event subscribers and listeners) and default options:

```php
class ExamplePlugin extends AbstractPlugin
{
    public function register(Registry $registry): void
    {
        $registry
            ->config(['example' => ['feed' => ['limit' => 10]]])
            ->twigExtension(Twig\ExampleExtension::class)
            ->generator(Generator\Feed::class, priority: 35)
            ->subscriber(SearchIndex::class);
    }
}
```

```yaml
extensions:
  plugins:
    Example: Example\ExamplePlugin
```

It's the recommended way to ship extensions with a theme: declared in the theme `config.yml`, the plugin is enabled with the theme, with no other configuration. The site configuration can still override its options, and disable or move its extensions by name.

### Build events

Cecil now dispatches [events](/documentation/developers/extend/#build-events) during the build: before and after the build and each step, and at each step of the life cycle of a page (`page.created`, `page.converted`, `page.rendered` and `page.saved`). Listen to them with an event subscriber to create a search index, notify a service, or modify the output of pages:

```yaml
extensions:
  subscribers:
    SearchIndex: MySite\SearchIndex
```

### Autoloading

Custom classes are [autoloaded](/documentation/developers/extend/#autoloading) from the `extensions` directory of the site **or of a theme**, the file path matching the namespace (e.g.: `MySite\Generator\Database` → `extensions/MySite/Generator/Database.php`). You can also:

- declare [PSR-4](https://www.php-fig.org/psr/psr-4/) mappings with `extensions.autoload`;
- install third-party libraries with Composer in the `extensions` directory: `extensions/vendor/autoload.php` is loaded automatically, even with the Cecil phar.

### Markdown converter and parser

The Markdown [converter](/documentation/developers/extend/#markdown-converter) (`pages.converter`) and [parser](/documentation/developers/extend/#markdown-parser) (`pages.body.parser`) can now be replaced by your own classes, for example to add your own Markdown syntax.

### New `new:extension` command

The [`new:extension`](/documentation/commands/new-extension/) command creates the skeleton of an extension (generator, Twig extension, post-processor, event subscriber or plugin), and displays the configuration to enable it:

```bash
cecil new:extension --type=plugin --name=Plugin --namespace=MySite
```

### Examples

- The [_Paper_](https://github.com/Cecilapp/theme-paper) theme now registers its Twig extension with a plugin.
- The [example theme](https://github.com/Cecilapp/theme-example) ships a small plugin: a reading time Twig filter.
- The [plugin example](https://github.com/Cecilapp/plugin-example) is a component theme shipping a plugin with a generator, a Twig extension, a post-processor and an event subscriber.

### Deprecations

Existing configurations still work, with a deprecation warning. They will not be supported in Cecil 10:

- Indexing extensions by priority (e.g.: `35: MySite\Generator\Database`) or by position (a list): use a name instead (`Database: { class: MySite\Generator\Database, priority: 35 }`).
- Using the `Cecil\` namespace for custom classes: it's now reserved, use your own namespace (e.g.: `MySite\` or the name of your theme).
- In Cecil 10, the strict mode will be enabled by default.

See the [Extend Cecil documentation](/documentation/developers/extend/) for more details, and [update Cecil](/download/#update) to get this release.
