Please note this is a quick draft from the top of my head, because the question came up so often, please add feedback if something is amiss.

If you want to create your own extension on your Flarum installation, you'll encounter the issue that your extension is not recognized if you simply create the directory under extensions. That is because composer doesn't know about it.

A common error message you will see is:

Fatal error: Uncaught exception 'ReflectionException' with message 'Class <YourClass> does not exist' in <SomePathToContainer> ...


This tutorial will explain how to set up your development environment to allow any extensions you work on to be picked up by composer.

This tutorial assumes you have installed composer globally and that you have access to ssh to run its commands.

Terminology

  • root/docroot - the install path of Flarum
  • workbench - the directory where your extensions for developing are located
  • package - the package as provided on packagist, with the name being a unique identifier, for instance flarum/core and hyn/guardian.
  • vendor - the author of the package, which is always the first part of a package name; flarum/core, hyn/guardian

The development directory

Create a directory directly under your docroot called workbench. This is the directory we will place your extensions under.

Update composer.json

Edit the composer.json of Flarum in the docroot and add under require the following:


    "repositories": [
        {
            "type": "path",
            "url": "workbench/*/"
        }
    ],

The composer json would now look like this:

{
    "name": "flarum/flarum",
    "description": "Delightfully simple forum software.",
    "type": "project",
    "keywords": ["forum", "discussion"],
    "homepage": "http://flarum.org",
    "license": "MIT",
    "authors": [
        {
            "name": "Toby Zerner",
            "email": "toby.zerner@gmail.com"
        },
        {
            "name": "Franz Liedke",
            "email": "franz@develophp.org"
        }
    ],
    "support": {
        "issues": "https://github.com/flarum/core/issues",
        "source": "https://github.com/flarum/flarum",
        "docs": "http://flarum.org/docs"
    },
    "require": {
        "flarum/core": "^0.1.0",
        "flarum/akismet": "^0.1.0",
        "flarum/approval": "^0.1.0",
        "flarum/auth-facebook": "^0.1.0",
        "flarum/auth-github": "^0.1.0",
        "flarum/auth-twitter": "^0.1.0",
        "flarum/bbcode": "^0.1.0",
        "flarum/emoji": "^0.1.0",
        "flarum/english": "^0.1.0",
        "flarum/flags": "^0.1.0",
        "flarum/likes": "^0.1.0",
        "flarum/lock": "^0.1.0",
        "flarum/markdown": "^0.1.0",
        "flarum/mentions": "^0.1.0",
        "flarum/pusher": "^0.1.0",
        "flarum/sticky": "^0.1.0",
        "flarum/subscriptions": "^0.1.0",
        "flarum/suspend": "^0.1.0",
        "flarum/tags": "^0.1.0"
    },
    "repositories": [
        {
            "type": "path",
            "url": "workbench/*/"
        }
    ],
    "require-dev": {
        "franzl/studio": "0.10.x@dev"
    },
    "config": {
        "preferred-install": "dist"
    },
    "minimum-stability": "beta"
}

Adding/creating your extension to the workbench

Existing extension

In case you already have an extension in git (github). Just go to the workbench directory with ssh and run the command to create a clone of your code:

git clone <repository>

This will automatically create a directory under workbench with the name of your repository (without the vendor name). Remember the package name in your composer.json file.

New extension

Create a new directory under workbench, make sure it follows all guidelines for an extension. Especially the composer.json file is now important for the repository-path method to work, the name specifies your package name, remember this!

Register the package in your Flarum

Now once again edit the composer.json in the docroot. If your package name is not mentioned under require, add it. The value should be *@dev. Now with ssh run composer update and you should see that your package is now symlinked from the workbench directory.

Issues

  • If you already had your package in the composer.json and an entry exists in the vendor folder for your package, make sure you delete that vendor subfolder before running composer update in the last step.

    Great tutorial, luceos! Thank you!

    2 months later
    5 days later

    hi
    on "composer update" its deleting my local repository

      sanjays its deleting my local repository

      Are you referring to the vendor or extension folder? Please be more specific.

        @luceos
        I am also getting same error as
        'ReflectionException' with message 'Class Cit\Tracker\Listeners\AddFootPrintJs does not exist'
        i follow the given guideline for extension develop till hello world , its work fine

        I tried to build stand ways as mention by flagrow with same directory structure

        extensions
        cit-tracker
        assets
        js
        cittracker.js
        src

        Listeners
        AddFootPrintJs.php


            bootstrap.php       
            composer.json

        I have also added

        require
        "cit/cit-tracker": "*@dev" in root composer.json

        "repositories": [
                {
                    "type": "path",
                    "url": "extensions/cit-tracker/"
                }
            ],

        i also keep namespace as same for
        namespace Cit\Tracker =>> boostrap.php ,
        namespace Cit\Tracker\Listeners ==> AddFootPrintJs.php

        But after composer update its removed the directory
        please correct me if i am wrong some where
        thanks for quick reply

        This is the
        composer.json

        {
            "name": "cit/cit-tracker",
            "description": "Configure Tracker!",
            "type": "flarum-extension",
            "require": {
                "flarum/core": "^0.1.0-beta.3"
            },
            "extra": {
                "flarum-extension": {
                    "title": "CIT Tracker",
                    "icon": {
                        "name": "line-chart",
                        "backgroundColor": "#01a6cb",
                        "color": "#ffffff"
                    }
                }
            },
            "autoload": {
                "psr-4": {
                    "Cit\\Tracker\\": "src/"
                }
            }
        }

        Your repository should be in another directory, not in extensions. A symlink will be added by composer pointing from the directory set in the "path" "url" value to the extensions directory.

        The directory structure in the base of your Flarum installation:

        • extensions
        • vendor
        • workbench
          • cit-tracker
          • composer.json

        Now add in the composer.json of Flarum:

        "repositories": [
                {
                    "type": "path",
                    "url": "workbench/*/"
                }
            ],

        The rest looks ok. If pointing composer with the path directive to your extensions directory it will remove that directory if you already had your extension in there before.

          a month later

          luceos what is the content in the composer.json inside workbench? you do not need that right? just need composer.json under my real package, in sanjays' case: inside cti-tracker?

            franklingu Correct, you need only create a "workbench" (name it as you please) type folder in the root directory of your flarum install, and then point to it in your flarum's composer.json as the tutorial indicates. Everything else is handled for you.

            The "root" (flarum) composer holds the repositories - path reference to workbench/*/*. Inside your workbench you will create a directory with a unique name (don't use vendor/package). Inside the extension directory you do need to have a composer to help identify the package name to the root composer file.

            So:

            /composer.json - repositories[path] configured
            /workbench/my-awesome-package/ -- your package git repository
            /workbench/my-awesome-package/composer.json - [name=franklingu/some-extension]

            Composer scans all workbench directories then and simply identifies whether a package with that name exists there.

            9 months later

            @luceos What is the equvilant of flarum/composer-installer it seems like that package got removed?

              SteveAzz it's no longer in use, simply remove it from your composer file. It was dropped in b4 or 5 I think.

              So how do I mange to create the symlink? It keeps failing and just copying the file.

              2 months later

              If you develop on windows you should use an absolute path to the workbench. Otherwise the extension doesn't get discovered.

                  "repositories": [
                      {
                          "type": "path",
                          "url": "C:/xampp/htdocs/flarum/workbench/*"
                      }
                  ],
              a month later

              Thanks for this awesome post! I think your instructions should be added to the documentation. I really had no idea how to start off. Cheers!

              6 months later

              Thanks for the explanation. I feel this should be added to the official tutorial too.

              In case you don't want to run composer update, you can just run composer require yourExtName:*@dev to just add the extension.

              luceos Register the package in your Flarum

              Now once again edit the composer.json in the docroot. If your package name is not mentioned under require, add it. The value should be *@dev. Now with ssh run composer update and you should see that your package is now symlinked from the workbench directory.

              Where it says "The value should be *@dev", what value exactly? Composer is not able to find a simple "Hello World" app, and I suspect it's probably because I don't know what value should be *@dev.