fof/split
A Flarum moderation extension that lets staff split selected posts from an existing discussion into a new thread. Choose the posts to move, set the new discussion's title and tags, and keep conversations organized without deleting or manually recreating content.
fof/split is a Flarum extension, not a standalone Laravel package — it uses Flarum's extension bootstrap (extend.php, listeners, migrations, assets) rather than a service provider. Treat it as a Laravel-adjacent package that plugs into the Illuminate components Flarum ships with.
Minimal install:
composer require fof/split
php flarum migrate
php flarum cache:clear
php flarum extension:enable fof/split
Where to look first:
composer.json → Flarum extra.flarum-extension block (name, icon, version constraints) — this tells you which Flarum versions the extension supports.extend.php → the actual wiring: routes, permission registrations, frontend asset bootstrapping, and any event listeners.js/src/forum/ → Mithril components that add the "Split" button to discussion/post controls.src/ → backend controller + domain logic for moving posts.First use case: as a moderator, open a discussion, select (or open the moderation dropdown on) one or more posts, choose Split, give the new discussion a title, and confirm. The selected posts become a new discussion; the extension handles the discussion creation, post reassignment, and (usually) a notification or activity entry for participants.
Day-to-day, developers rarely touch this package once installed — the touch points are admin-side permission grants and, occasionally, customizing the split workflow.
Permission-driven moderation flow. The split action should only appear for users whose group has the appropriate moderation permission (typically registered via $this->registerPermission() in extend.php). When building a custom moderation panel or admin dashboard, read this permission via Flarum's PermissionRepository/Gate rather than hard-coding group names.
Reassigning posts programmatically. If you need to split from a queued job or console command (e.g., a "clean up off-topic posts" routine), mimic what the extension's controller does:
Discussion with a title, user_id, and slug,discussion_id on the selected Post models,Discussion::last_post_id / last_posted_at / comment_count, andReuse the extension's service class directly if it's exposed, so you don't drift from its invariants.
Wrapping the split in a transaction. Because the operation touches multiple posts and two discussions, wrap it in DB::transaction() and consider ->lockForUpdate() on the source posts so concurrent moderation doesn't split the same post twice. Update the original discussion's denormalized counters in the same transaction.
Tagging integration. If flarum/tags is installed, decide whether the new discussion inherits the source discussion's tags. There is no universal default — check the extension's behavior and, if needed, apply tags in a listener after the split so a "Split from discussion X" tag convention is enforced in one place.
Hooking post-split behavior. Register an event listener (via Event::listen or the extension's dispatched domain event, if exposed) to:
Keep side effects out of the split controller itself — attach them in listeners so the extension stays upgradeable.
Frontend customization. The button is a Mithril component in js/src. To change label, icon, or placement, override via a frontend extender or fork the JS. For a custom modal (extra fields like "close original discussion?"), mirror the existing modal component and reuse the same API endpoint.
API usage. If you drive splits from a mobile client or integration, call the endpoint the controller registers (typically under /api/) with Flarum's CSRF token / cookie auth. Inspect the route name in extend.php before assuming the URL.
extra.flarum-extension.flarum-version in composer.json. Flarum's frontend (Mithril v1→v2) and backend APIs shift between minor versions; a loose constraint will bite you on upgrade. Always run php flarum info after touching the lockfile.composer update without php flarum migrate && php flarum cache:clear yields "button missing" reports that have nothing to do with the extension.Discussion::comment_count, last_post_id, last_posted_at, and participant lists are cached columns. Any non-UI path that moves posts must rebuild them, or the forum index will show stale reply counts. Discussion::refreshMetadata() (or equivalent) is your friend.number column. Posts carry a sequence number. After splitting, renumber both discussions if your theme or API consumers depend on contiguous numbering.Discussion::refreshParticipants()) in your listener.php flarum log:tail (or storage/logs/flarum-*.log) for backend failures; the split endpoint usually surfaces errors as 400/422 JSON — inspect the response body in the browser network panel rather than trusting the generic toast.Post/Discussion saved events filtered by the split marker. Avoid monkey-patching the controller; Flarum discourages it and it will break on the next release.$this->app->register(...) from a Laravel app — it only boots inside Flarum's extension runner. If you need split behavior inside a plain Laravel app, port the domain logic rather than depending on this package.How can I help you explore Laravel packages today?