flarum/approval
Flarum Approval adds an approval queue that holds posts and discussions from new or untrusted users until a moderator approves them. It includes permission controls and pending-content review, helping communities keep spam and unwanted posts from appearing immediately. Requires Flarum.
Flarum's framework is a monorepo (flarum/framework) that ships flarum/core plus a set of supporting packages (flarum/php, flarum/testing). It runs on Illuminate components — container, support, validation, events, filesystem — but is not a Laravel application, so treat it as a package you extend rather than an app you edit.
Install:
composer require flarum/core:^2.0.1
First places to look, in order:
extend.php — the single extension entry point. Every integration you write is expressed as a list of extenders here.vendor/flarum/core/src/Extend/ — the extenders are the actual API surface. Reading Routes.php, Frontend.php, Api.php, Settings.php tells you more than any docs page.vendor/flarum/core/src/Api/Serializer/ and Api/Controller/ — the JSON:API layer you'll be extending for nearly any feature.config.php (or a .env + config.php pair) — database, url, and debug flags.First useful case: build one small extension that adds a JSON:API endpoint, a migration, and a setting — that touches routing, the container, persistence, and config in one pass, and is the shape 80% of real work takes.
// extend.php
return [
new Extend\Routes('api')
->get('/acme/things', 'acme.things.index', Controller\ListThingsController::class),
(new Extend\Migrations())->add(__DIR__.'/migrations'),
(new Extend\Settings())->serializeToForum('acme.enabled', 'acme.enabled', 'boolVal'),
];
Extender composition. Extenders are plain objects returned from extend.php. Group them by concern (routes, frontend, permissions, serializers) rather than by file; the resolver flattens them, so ordering only matters for same-type extenders where later wins.
Register your own container bindings with Extend\ServiceProvider and a normal Laravel ServiceProvider. This is the escape hatch for anything the extender API doesn't cover:
(new Extend\ServiceProvider())->register(AcmeServiceProvider::class)
API work. Extend AbstractSerializeController and a Serializer subclass, then:
(new Extend\ApiSerializer(PostSerializer::class))->attributes(...) to add fields,(new Extend\ApiController(ShowDiscussionController::class))->addInclude('user') to change eager-loading,(new Extend\Model(User::class))->belongsTo('acmeProfile', ...) for relations.Remember JSON:API output is permission-filtered — adding an attribute is not enough, $serializer->can() gating is what keeps it safe.
Permissions and settings belong in extenders, not controllers:
(new Extend\Permission())->permission('acme.moderate');
(new Extend\Settings())->default('acme.limit', 10);
Frontend integration in v2 is TypeScript + a modern bundler. Use (new Extend\Frontend('forum'))->js(__DIR__.'/js/dist/forum.js')->css(...), and (new Extend\Locales(__DIR__.'/locale')) for translations. Assets are compiled at build time, not on request — plan a build step in CI or a composer script hook.
Testing. flarum/testing gives you a bootable app with in-memory SQLite and a JSON:API request harness. Prefer full request tests over unit tests for serializers and controllers; the container wiring is where regressions hide.
Embedding in a Laravel host. If you're pulling Illuminate components from Flarum's dependency tree into a Laravel app, namespace collisions and duplicate container instances are the norm. Isolate by using Flarum's container only inside its boot path, and don't rely on Laravel's app() helpers resolving Flarum bindings.
extend.php without php flarum cache:clear produces genuinely confusing behaviour — old routes, stale permissions. Make this the first step of every debugging session.php flarum (migrate, cache:clear, assets:publish, settings:set, extension:*). Don't paste Laravel commands from tutorials.CHANGELOG.md, which reads as a patch-level release: expect bugfixes and dependency bumps rather than API changes. Upgrading from 2.0.0 should be low-risk, but pin ^2.0.1 and re-run composer update plus asset rebuild, since frontend asset hashes change per release — a stale assets/ directory against new core code is a classic mixed-version failure.composer.json PSR-4 mapping; after adding one, composer dump-autoload in the Flarum root, not the extension directory.php flarum migrate explicitly in deploy scripts instead of hoping boot handles it.belongsTo added to Discussion affects every query on the site — be deliberate about with() defaults versus on-demand includes.config.php, and watch storage/logs/. Flarum swallows fatal errors behind a friendly 500 page by default, which makes a silent extend.php type error look like a blank screen.composer why-not flarum/core 2.0.1 before assuming a code problem.vendor/. In a monorepo-tracked framework this feels tempting for one-line fixes; it will be silently reverted on the next composer install and any bug report against it is unreproducible.Extend\Event for domain events, Extend\Middleware for request-level concerns, Extend\Assets for build artifacts, and a custom extender (Extend\ExtenderInterface) if you're registering the same resource more than twice.How can I help you explore Laravel packages today?