In order to understand how to extend Flarum, first we need to understand a bit about how Flarum is built.

Be aware that Flarum uses some modern languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding.

Second, the backend exposes a public API which allows frontend clients to interface with your forum's data. This is built according to the JSON:API specification.

Finally, there is the default web interface which we call the frontend. This is a single-page application which consumes the API. It's built with a simple React-like framework called Mithril.js.

Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the backend, expose that data in the public API, and then display it and allow users to edit it on the frontend.

In order to extend Flarum, we will be using a concept called extenders. Extenders are declarative objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created).

Every extender is different. However, they will always look somewhat similar to this:

// Register a JavaScript and a CSS file to be delivered with the forum frontend(newExtend\Frontend('forum'))->js(__DIR__.'/forum-scripts.js')->css(__DIR__.'/forum-styles.css')

You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls.

To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). Everything you do in your extension should be done via extenders, because they are a guarantee we are giving to you that a future minor release of Flarum won't break your extension.

All of the extenders currently available to you from Flarum's core can be found in the Extend namespace. Extensions may also offer their own extenders.

Want to see an extender in action? The extend.php file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following:

For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the extend.php file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension!

Composer is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly.

As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice!

During development, you can work on your extensions locally and set up a Composer path repository to install your local copy. Create a new packages folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here:

composer config repositories.0 path "packages/*"

Now let's start building our first extension. Make a new folder inside packages for your extension called hello-world. We'll put two files in it: extend.php and composer.json. These files serve as the heart and soul of the extension.

The extend.php file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the Frontend extender that you had earlier.

name is the name of the Composer package in the format vendor/package.

You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using acme as your vendor name.

You should prefix the package part with flarum- to indicate that it’s a package specifically intended for use with Flarum.

description is a short one-sentence description of what the extension does.

type MUST be set to flarum-extension. This ensures that when someone "requires" your extension, it will be identified as such.

require contains a list of your extension's own dependencies.

You'll want to specify the version of Flarum that your extension is compatible with here.

This is also the place to list other Composer libraries your code needs to work.

Carefully choose the Flarum version

While Flarum is still in beta, we recommend that you declare compatibility both with the current and the upcoming beta version of Flarum:

"flarum/core": ">=0.1.0-beta.10 <0.1.0-beta.12"

This gives you time to update your extension for new features or changes in Flarum's core, without preventing users from upgrading to the latest Flarum release because your extension is not compatible.

To make this possible, we try to deprecate features for one beta cycle, before removing them for the next one, until we reach stable.
This gives you two months time to update.

autoload tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase.

extra.flarum-extension contains some Flarum-specific information, like your extension's display name and how its icon should look.

title is the display name of your extension.

icon is an object which defines your extension's icon. The name property is a Font Awesome icon class name. All other properties are used as the style attribute for your extension's icon.