Edit on GitHub
Jump to docs navigation

Extending Bolt / Bolt Extensions

Note: You are currently reading the documentation for Bolt 4.0. Looking for the documentation for Bolt 5.2 instead?

Introduction

A Bolt extension is actually a composer package, that has a few specific properties that make it recognizable as such. In practice, this means you can develop a Bolt extension just like you would a 'normal' Composer package.

Developing an extension usually is done in the following steps:

  • Create a git repository, and make a local clone
  • Submit it to Packagist
  • Set it up so you can work with it in your local development environment, and Bolt recognizes it
  • Work on the extension, until it's Done™.
  • Add the required attributes to the extension's composer.json. And add a nice screenshot for good measure.
  • Tag a release on Github / Gitlab / Bitbucket, and see it show up on the Extensions site.

Alternatively, you can start working on your extension as a project extension (described here), and then convert it to a standalone extension at a convenient time. It works pretty much the same, so you can pick whatever suits your workflow best.

Create a git repository

You probably already know how to do this. You can create a git repository at Github, which is most often used, but Gitlab or Bitbucket will work just as well. You can now make a clone of that repository, on your local development environment. Make sure to clone this repository outside of the project you're working on. It might seem tempting to simply clone it into your vendor/ folder, but that will not work.

Note: This chapter assumes you'll be using Studio to work on Extensions locally, but you're free to use another method, if you prefer. Using Studio is explained below.

Something like this works well:

.
├── my-awesome-extension/
│   ├── config/
│   ├── src/
│   ├── templates/
│   ├── LICENSE
│   ├── README.md
│   └── composer.json
└── myprojectname/
    ├── bin/
    ├── config/
    ├── public_html/
    ├── src/
    ├── var/
    ├── vendor/
    ├── LICENSE
    ├── README.md
    ├── composer.json
    ├── symfony.lock
    └── …

This way you'll set it up so you can work on your project and the extension, and they will interfere with eachother as little as possible.

Tip: You might notice that the structure of the folders that hold the extension and the Bolt project are quite similar. This is no coincidence: Both with Bolt and Extensions alike, we follow the default Symfony project structure as much as feasible.

To get a headstart, you can also clone the reference-extension, and use that as a starting point.

As a bare minimum, your new git repository should contain an Extension.php, a composer.json and a .gitignore file.

Create a file src/Extension.php, like this:

<?php

namespace BobDenOtter\MyAwesomeExtension;

use Bolt\Extension\BaseExtension;

class Extension extends BaseExtension
{
    public function getName(): string
    {
        return 'My Awesome Extension';
    }
}

Create a composer.json, like this:

{
    "name": "bobdenotter/my-awesome-extension",
    "description": "Put a nice and succinct description of your extension here.",
    "type": "bolt-extension",
    "license": "MIT",
    "authors": [
        {
            "name": "YourNameHere",
            "email": "youremail@acme.com"
        }
    ],
    "require": {
        "php": ">=7.1.3",
        "twig/twig": "^2.12 | ^3.0"
    },
    "require-dev": {
        "bolt/core": "^4.0.0"
    },
    "autoload": {
        "psr-4": {
            "BobDenOtter\\MyAwesomeExtension\\": "src/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "extra": {
        "entrypoint": "BobDenOtter\\MyAwesomeExtension\\Extension"
    }
}

Make sure the "name" is set correctly. This is often the same as the last part of where it's hosted at Github or Gitlab, but it doesn't have to be. In fact, it's the vendow name plus the project name. The vendor name is mandatory and should be unique to your projects. The namespaces used in the autoload/psr-4 and extra/entrypoint attributes should also be unique, and match the name. The notation is different, though: the name must be snake-case (lowercase only, hyphens allowed), whilst the namespace must be CamelCase.

Note: You can determine the namespace yourself, but the de facto standard is to have it as a "vendor namespace", followed by a "project namespace". Later on you'll use this exact namespace in your PHP code.

The type is set to bolt-extension. This will make Bolt, Packagist and the Extensions site recognize it as a proper Bolt extension.

To prevent clutter in your repo, you should also add a .gitignore file:

### Platfom-specific files
.DS_Store
thumbs.db
Vagrantfile
.vagrant*
.idea
.vscode/*
appveyor.yaml

### Local files
vendor/
composer.lock
var/

Next, commit these files to git, and push the changes to the remote git repository.

Submit to Packagist

The next step is to submit your package to Packagist, the Composer packages repository. This might seem early to do, but it's a required step, if you're going to be using Studio (in the next step).

After you've committed your files to git, go to packagist.org. Log in using an existing account, connect with your Github account, or create a new one. After you've done this, you can submit a new package. Simply fill out the full URL of your git repository, and click the button.

If all went well, you can confirm the next step, and you'll now have published your extension-to-be on Packagist. If it didn't go through, Packagist will most likely tell you why it didn't, enabling you to fix the error and to try again.

Note: You're submitting our package to Packagist already, but it won't show up on the Bolt Extension website until you've tagged a release in your git repository.

Set it up locally

Normally, you can install a Bolt extension by running composer req foo/bar, but if you're planning on developing an extension, that's not the best way to go. If you do, the extension will 'forget' it's a git repository, and every time you'll run composer update, you will overwrite your local changes.

You can solve this by using path repositories in your composer.json, but in practice this can be quite a hassle. In this chapter we'll use Studio to do the heavy lifting for us.

You can install Studio using the instructions on their git repository. After installation, you can add your extension-to-be to your project, by running studio load ../my-awesome-extension from your project root:

$ studio load ../my-awesome-extension

 [OK] Packages matching the path ../my-awesome-extension will now be loaded by Composer.

Now, Composer will treat our local repository as a common Composer package. Install it using composer req bobdenotter/my-awesome-extension.

$ composer req bobdenotter/my-awesome-extension:dev-master

Using version dev-master for bobdenotter/my-awesome-extension
./composer.json has been updated
[Studio] Loading path ../my-awesome-extension
…
Package operations: 1 install, 0 updates, 0 removals
  - Installing bobdenotter/my-awesome-extension (dev-master): Source already present
…
Executing script cache:clear [OK]
Executing script assets:install public [OK]
Executing script bolt:copy-assets [OK]

Obviously, you should tweak the two commands above to match your set up, using the correct path and package name. Note the additional :dev-master in the command below. This explicitly instructs composer to install the master branch, which is then picked up by Studio to work on in parallel.

Note: If you get a message like this:

  [InvalidArgumentException]
  Could not find a matching version of package foo/bar-qux. Check the package 
  spelling, your version constraint and that the package is available in a stability 
  which matches your minimum-stability (dev).

Then you might have been too quick. It usually takes a few minutes for Composer to index the package, and make it available. Just try it again after a minute or two.

After you've installed the local extension, you can verify that Bolt recognizes it correctly, by running the following:

$ bin/console extensions:list

 Currently installed extensions:
 ------------------------------------------ --------------------------
  Class                                      Extension name
 ------------------------------------------ --------------------------
  …                                          …
  BobDenOtter\MyAwesomeExtension\Extension   My Awesome Extension
 ------------------------------------------ --------------------------

Work on the extension

This is the obvious part. You now have a working set up, and you can work on your extension, until you feel it's ready for release. In the following chapters you can read about the BaseExtension, BaseWidget, and the other things you can do with Bolt Extensions.



Edit this page on GitHub
Couldn't find what you were looking for? We are happy to help you in the forum, on Slack or on Github.