Updating For 2.0
Flarum 2.0 is a major release that includes a number of breaking changes and new features. This guide will help you update your extension to be compatible with Flarum 2.0 and take advantage of the new additions.
If you need help applying these changes or using new features, please start a discussion on the community forum.
Upgrade Automation
You can use the Flarum CLI to automate as much of the upgrade steps as possible:
Keep in mind the following information about the upgrade command:
- The process goes through multiple steps, each step points to the related documentation, and provides helpful tips.
- After each step, the changes are committed to Git so that you can always review the changes commit by commit.
- Mistakes can and will be made, after every step is finished you can view the changes made and make any necessary adjustments.
- Most of the steps should require little to no manual adjustments, except for the following:
- Adapt to accessing/extending lazy loaded Flarum modules. (Can require some amount of manual changes)
- Prepare for JSON:API changes. (100% manual changes requires)
- Search & Filter API changes. (Can require some amount of manual changes)
Installation
The upgrader is just another command of the @flarum/cli
npm package.
npm install -g @flarum/cli@3
v3 of the CLI is only compatible with v2.x of Flarum, if you wish to continue using the CLI for both v1.x and v2.x of Flarum, you can install them together. Read more about it here.
Usage
Now to use, simply run the following command:
fl upgrade 2.0
Before you use the automated upgrade command, make sure to read the entire upgrade guide at least once to understand the changes.
Frontend
Dependencies
Breaking
In package.json
:
- Set
flarum-webpack-config
to^3.0.0
. - Set
flarum-tsconfig
to^2.0.0
.
Mithril 2.2
Breaking
- Flarum 2.0 upgrades Mithril to version 2.2. This version introduces one breaking change that may affect your extension. Mithril no longer sets a
text
attribute on vnodes, instead it uses a child with the tag#
. So to extract text from a vnode, use theextractText()
utility instead.
Export Registry
2.0 introduces a new concept called the Export Registry. This is a central place where exports from core and extensions are automatically registered. This allows extensions to easily extend modules from other extensions without those extensions needing to explicitly support it. This also allows lazy loading of modules, which can improve performance.
Compat API
Breaking
- The compat API has been removed, for most extensions this should not be a problem. If you are using the compat API to allow other extensions to extend your modules, you can drop it and instead just make sure all your modules are imported to be automatically registered. For example, tags in 1.x used the compat API to expose its modules. In 2.0 insuring the modules are imported is enough.
Importing Modules
Breaking
Importing from extensions must now be done using a
ext:
prefix. This means that any imports you are currently making from bundled extensions will need to be updated. For example,flarum/tags/common/models/Tag
becomesext:flarum/tags/common/models/Tag
. This also means you can import from any other extension, not just bundled ones, using the same syntax ofext:vendor/extension/common/...
.// Before
import Tag from 'flarum/tags/common/models/Tag';
// After
import Tag from 'ext:flarum/tags/common/models/Tag';Importing from
@flarum/core
no longer works. It was previously only allowed for the compat API.The
useExtensions
webpack option has been removed, use the import format explained above to import using the export registry instead.Some flarum modules are now lazy loaded, such as
LogInModal
. You have to make sure they have been loaded before using them, or you can trigger the loading yourself. See the Code Splitting documentation for more information.
Read more about the export registry and how to use it in the Export Registry documentation.
Familiarize yourself with the new Code Splitting feature to lazy load modules and improve overall performance.
Forum Search
Breaking
- The forum search UI has been refactored to use a new
SearchModal
component. - The
flarum/forum/components/Search
component is no longer the global search component, it can still be used for custom search purposes. - Custom global search sources should be registered in
flarum/forum/components/GlobalSearch
sourceItems
method. - Custom global search sources should now implement the
GlobalSearchSource
interface instead ofSearchSource
, see https://github.com/flarum/framework/blob/2.x/framework/core/js/src/common/components/AbstractSearch.tsx#L26-L69. - The
flarum/forum/states/SearchState
class has been moved toflarum/common/states/SearchState
.
Admin Search
Notable
- The admin dashboard now has a search feature, as long as you register your settings/permissions using the
Admin
extender, then they will be automatically picked up. - If your settings/permissions are too custom to be added through the
Admin.setting
andAdmin.permission
extenders, then you can useAdmin.generalIndexItems
to add custom search index entries.
Locale
Breaking
HTML tags used within translations must be simple tags, without attributes. For example, if you have a locale with the value:
my_locale_key: "You can read about a <a href='{basic_impl_link}'>basic queue</a> implementation or a <a href='{adv_impl_link}'>more advanced</a> one."
You must change this to:
my_locale_key: "You can read about a <basic_impl_link>basic queue</basic_impl_link> implementation or a <adv_impl_link>more advanced</adv_impl_link> one."
With the following code in your JavaScript:
app.translator.trans('acme.my_locale_key', {
basic_impl_link: <a href="https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting" />,
adv_impl_link: <a href="https://discuss.flarum.org/d/21873-redis-sessions-cache-queues" />,
})Tags used within translations such as
<strong>
were previously auto provided as parameters
Miscellaneous
There have been many changes to the core frontend codebase, including renamed or moved methods/components, new methods/components, and more. It might help to look directly at the JavaScript diffs to see what has changed. But here are some notable changes.
Breaking
app.extensionData
has been renamed toapp.registry
, but you should now use theAdmin
extender instead.- Some extension initializers have been renamed to be more uniform, if you are checking for initializer existence with
app.initializers.has('...')
you should update the name accordingly. IndexPage.prototype.sidebar
has been removed, use theIndexSidebar
component instead.IndexPage.prototype.navItems
has been moved toIndexSidebar.prototype.navItems
.IndexPage.prototype.sidebarItems
has been moved toIndexSidebar.prototype.items
.IndexPage.prototype.currentTag
has been moved toapp.currentTag
.- The
UploadImageButton
component has been refactored to allow using it in different contexts. An admin setting definition has also been added to allow you to use an upload setting directly. Additionally, the component has been moved to thecommon
namespace. - The
FieldSet
component has been refactored. - The
avatar
andicon
helpers have been refactored to newAvatar
andIcon
components. Which now allows you to extend them to modify their behavior. - The
Modal
component has been split intoModal
andFormModal
. TheModal
component is now a simple modal that can be used for any content, while theFormModal
component is a modal that is specifically designed for forms. app.extensionData
has been removed. You must now use theAdmin
extender to register settings, permissions and custom extension pages.
Notable
- All forum pages now use the same page structure through the new
PageStructure
component. You should use this component in your extension if you are creating a new forum page. - A
HeaderDropdown
component has been added which is used for theNotificationsDropdown
andFlagsDropdown
your component should extend that instead of theNotificationsDropdown
. Along with it has been also added the following components:HeaderList
andHeaderListItem
. - A
DetailedDropdownItem
has been added. Checkout theSubsriptionsDropdown
component to see how it is used. - A
Notices
component has been added that allows you to easily add global alerts above the hero. - A
Footer
component has been added that allows you to easily add content to the footer. - A
Form
component has been added to ensure consistent styling across forms. You should use this component in your extension if you are creating a form. - An API for frontend gambits has been introduced, checkout the full documentation.
- A
FormGroup
component has been added that allows you to add any supported type of input similar to the admin panel's settings registration. checkout the documentation for more details.
Backend
PHP 8.2
Breaking
- The entire codebase has been updated to use/require PHP 8.2 as a minimum, and with it come more strict types. This is not a breaking change for most extensions. But you should still update your extension's code accordingly and check for any potential issues or deprecated code.
Notable
- A new
Flarum\Locale\TranslatorInterface
has been introduced, it is recommended to use instead of eitherIlluminate\Contracts\Translation\Translator
orSymfony\Contracts\Translation\TranslatorInterface
.
Dependencies
Main packages
Breaking
In composer.json
:
- Set
flarum/core
package requirement to^2.0.0-beta
. - Set other
flarum/*
packages to*
. - If you have a
php
requirement, make sure it is not below^8.2
. - If you have
blomstra/gdpr
as a requirement, change it to"flarum/gdpr": "*"
.
Carbon 3
Breaking
- Flarum 2.0 upgrades Carbon to version 3.
diffIn
methods now return floats instead of integers and can return negative values to indicate time direction. This is the most significant breaking change in Carbon 3. If you are using any of these methods, you should update your code to handle floats and negative values.
Other changes can be found in the Carbon 3 change log.
Symfony (updated from 5.x to 7.x)
Notable
- Flarum 2.0 upgrades Symfony components to version 6. Most extensions will not need to make any changes.
Laravel (updated from 8.x to 11.x)
Flarum 2.0 uses Laravel 11 components, depending on your extension you may need to adapt your code. Here are some notable highlights.
Breaking
- The
$dates
property on models has been removed. You should now use the$casts
property instead as such:protected $casts = [
'example_at' => 'datetime',
]; - When changing columns in migrations, you must always include the entirety of the column definition. For example, if you are changing a nullable column from
string
totext
, you must include the->nullable()
method in the new column definition. You will have to update your migrations accordingly. (https://laravel.com/docs/11.x/upgrade#modifying-columns)
For more details, see the Laravel 9, Laravel 10 and Laravel 11 upgrade guides.
Flysystem (updated from 1.x to 3.x)
Flarum 2.0 upgrades Flysystem to version 3. Most extensions will not need to make any changes, unless you are using/declaring a Flysystem adapter.
Breaking
The
NullAdapter
has been removed. You may instead use theInMemoryFilesystemAdapter
.The
Local
adapter has been removed. You should use theLocalFilesystemAdapter
instead.The
FilesystemAdapter
constructor now takes as a second argument the adapter instance, if you are using the Flarum filesystem driver interface you don't need to make any changes. If you are using Flysystem directly, you will need to pass the adapter instance as a second argument.// Before
new FilesystemAdapter(new Filesystem(new LocalAdapter($path)));
// After
$adapter = new LocalFilesystemAdapter($path);
new FilesystemAdapter(new Filesystem($adapter), $adapter);Some filesystem methods have been renamed and others have been removed.
For more details, read the Flysystem 1.x to V2 & V3 upgrade guide. Additionally, you can see the Flysystem V2 & V3 new features.
Swift Mailer has been replaced with Symfony Mailer
Breaking
- If your extension defines a new mail driver, you will need to update your code to use the new Symfony Mailer API.
Checkout the Symfony Mailer documentation for more details.
Intervention Image v3
Breaking
The Intervention Image library (intervention/image
) has been updated to version 3. If your extension makes any image manipulations, you should check the Intervention Image v3 upgrade guide for the breaking changes and adjust your code accordingly.
You may also check out the core pull request that updated the library here.
JSON:API
Flarum 2.0 completely refactors the JSON:API implementation. The way resource CRUD operations, serialization and extending other resources is done has completely changed.
Breaking
- The
AbstractSerializeController
,AbstractShowController
,AbstractCreateController
,AbstractUpdateController
, andAbstractDeleteController
have been removed. - The
AbstractSerializer
has been removed. - The
ApiController
andApiSerializer
extenders have been removed. - The
Saving
are dispatched after the validation process instead of before. - The various validators have been removed. This includes the
DiscussionValidator
,PostValidator
,TagValidator
,SuspendValidator
,GroupValidator
,UserValidator
. - Many command handlers have been removed. Use the
JsonApi
class if you wish to execute logic from an existing endpoint internally instead. - The
flarum.forum.discussions.sortmap
singleton has been removed. Instead, you can define anascendingAlias
anddescendingAlias
on your addedSortColumn
sorts. - The
show
discussion endpoint no longer includes theposts
relationship, so anyposts.*
relation includes or eager loads added to that endpoint must be removed. You can move those to thelist
posts endpoint if you are not already doing the same on that endpoint.
Replacing the deleted classes is the new AbstractResource
and AbstractDatabaseResource
classes. We recommend looking at a comparison between the bundled extensions (like tags) from 1.x to 2.x to have a better understanding of the changes:
- Tags 1.x: https://github.com/flarum/framework/blob/1.x/extensions/tags
- Tags 2.x: https://github.com/flarum/framework/blob/2.x/extensions/tags
Read about the full extent of the new introduced implementation and its usage in the JSON:API section.
Checkout our guide to upgrading the JSON:API layer from 1.x to 2.x, which provides concrete examples for different scenarios.
Notable
- We now do not recommend adding default includes to endpoints. Instead it is preferable to add what relations you need included in the payloads of individual requests. This improves the performance of the forum.
Search/Filter system
The search system has been refactored to allow for more flexibility and extensibility, and to further simplify things, the separate concept of filtering has been removed.
Breaking
- The old system decided between using the model filterer and the model searcher based on whether a search query
filter[q]
was provided. The new system does not have filterers anymore, but the distinction is still present, the only difference is that the default database search driver is always used when no search query is provided. - If you have a class extending
AbstractFilterer
(a filterer) you should now extendAbstractSearcher
instead (a searcher). If you already have a searcher for the same model, you can remove the filterer. Filters can be assigned to the searcher class. - Gambits have been removed from the backend. There are only filters now per model searcher. The concept of gambits has been moved to the frontend instead. See the search documentation gambits section for more details.
- Some namespaces have been changed or removed. The classes within
Flarum\Query
have been moved toFlarum\Search
. The classes withinFlarum\Filter
have been moved toFlarum\Search\Filter
. TheFilterState
class has been removed, you should use theSearchState
class instead. - The database search state now returns an Eloquent query builder instead of a database query builder.
Notable
- A new search driver API has been introduced. Checkout the search documentation for more details on how to use it.
- You can now get the total search result count from
SearchResults
. - You can now replace an existing filter implementation.
SQLite/PostgreSQL
Notable
- Flarum 2.0 introduces support for SQLite and PostgreSQL databases. If your extension uses any database-specific queries, you should ensure they are compatible with these databases.
- You can use the new
whenMysql
,whenSqlite
, andwhenPgsql
methods on the query builder to run database-specific queries. - You should ensure your extension is explicit about whether it supports SQLite and PostgreSQL. You can use the
database-support
key in yourcomposer.json
to specify this.
Checkout the database documentation for more details.
LESS Preprocessing
Breaking
- The LESS code has been refactored to use more vanilla CSS instead of LESS conditionals and variables.
The dark mode switch has been refactored to a color scheme setting that takes effect purely through CSS variables. You should away from using LESS variables as much as possible and instead use the equivalent CSS variables. To add more color schemes.
The
@config-dark-mode
and@config-colored-header
variables have been removed. Instead, you can use the[data-theme^=dark]
and[data-colored-header=true]
CSS selectors respectively.// before
& when (@config-dark-mode) {
background: black;
}
// after
[data-theme^=dark] & {
background: black;
}The
@config-colored-header
variable has been removed. Instead, you can use the[data-colored-header=true]
CSS selector.// before
& when (@config-colored-header = true) {
background: @primary-color;
}
// after
[data-colored-header=true] & {
background: var(--primary-color);
}
Notable
- New high contrast color schemes have been added.
- You can register more color schemes through the new frontend
Theme
extender and equivalent CSS code[data-theme=your-scheme]
.
Email Notifications
Breaking
- The
getEmailView
method of theFlarum\Notification\MailableInterface
interface has been renamed togetEmailViews
getEmailViews
now requires you to return bothtext
andhtml
views for your email notification.
Checkout this example from the mentions extension:
- Blueprint class: https://github.com/flarum/framework/blob/2.x/extensions/mentions/src/Notification/PostMentionedBlueprint.php#L43-L49
- HTML view: https://github.com/flarum/framework/blob/2.x/extensions/mentions/views/emails/html/postMentioned.blade.php
- Text view: https://github.com/flarum/framework/blob/2.x/extensions/mentions/views/emails/plain/postMentioned.blade.php
Miscellaneous
Breaking
- The
(Extend\Notification)->type()
extender no longer accepts a serializer as second argument. - Notification Blueprints must now implement the
Flarum\Notification\AlertableInterface
interface in order them to be sent as alerts. This allows for email-only notifications for example. - The
staudenmeir/eloquent-eager-limit
package has been removed. If you are using theStaudenmeir\EloquentEagerLimit\HasEagerLimit
trait in any of your models, you can simply remove it as it is native to Laravel now.
Notable
- The
Frontend
extender now allows passing extra attributes and classes that will be added to the roothtml
tag, through theextraDocumentAttributes
andextraDocumentClasses
methods. - When preparing data in tests, you should use the model class name instead of the table name, this will ensure the factory of the model is used and basic data is autofilled for you.
Infrastructure
Reusable GitHub Workflows
Breaking
- The reusable GitHub workflows must be updated to use target the ones from the 2.x branch. For example, you must change
flarum/framework/.github/workflows/REUSABLE_backend.yml@main
toflarum/framework/.github/workflows/[email protected]
.