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-configto^3.0.0. - Set
flarum-tsconfigto^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
textattribute 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/Tagbecomesext: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/coreno longer works. It was previously only allowed for the compat API.The
useExtensionswebpack 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
SearchModalcomponent. - The
flarum/forum/components/Searchcomponent 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/GlobalSearchsourceItemsmethod. - Custom global search sources should now implement the
GlobalSearchSourceinterface 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/SearchStateclass 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
Adminextender, then they will be automatically picked up. - If your settings/permissions are too custom to be added through the
Admin.settingandAdmin.permissionextenders, then you can useAdmin.generalIndexItemsto 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.extensionDatahas been renamed toapp.registry, but you should now use theAdminextender 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.sidebarhas been removed, use theIndexSidebarcomponent instead.IndexPage.prototype.navItemshas been moved toIndexSidebar.prototype.navItems.IndexPage.prototype.sidebarItemshas been moved toIndexSidebar.prototype.items.IndexPage.prototype.currentTaghas been moved toapp.currentTag.- The
UploadImageButtoncomponent 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 thecommonnamespace. - The
FieldSetcomponent has been refactored. - The
avatarandiconhelpers have been refactored to newAvatarandIconcomponents. Which now allows you to extend them to modify their behavior. - The
Modalcomponent has been split intoModalandFormModal. TheModalcomponent is now a simple modal that can be used for any content, while theFormModalcomponent is a modal that is specifically designed for forms. app.extensionDatahas been removed. You must now use theAdminextender to register settings, permissions and custom extension pages.
Notable
- All forum pages now use the same page structure through the new
PageStructurecomponent. You should use this component in your extension if you are creating a new forum page. - A
HeaderDropdowncomponent has been added which is used for theNotificationsDropdownandFlagsDropdownyour component should extend that instead of theNotificationsDropdown. Along with it has been also added the following components:HeaderListandHeaderListItem. - A
DetailedDropdownItemhas been added. Checkout theSubsriptionsDropdowncomponent to see how it is used. - A
Noticescomponent has been added that allows you to easily add global alerts above the hero. - A
Footercomponent has been added that allows you to easily add content to the footer. - A
Formcomponent 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
FormGroupcomponent 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\TranslatorInterfacehas been introduced, it is recommended to use instead of eitherIlluminate\Contracts\Translation\TranslatororSymfony\Contracts\Translation\TranslatorInterface.
Dependencies
Main packages
Breaking
In composer.json:
- Set
flarum/corepackage requirement to^2.0.0-beta. - Set other
flarum/*packages to*. - If you have a
phprequirement, make sure it is not below^8.2. - If you have
blomstra/gdpras a requirement, change it to"flarum/gdpr": "*".
Carbon 3
Breaking
- Flarum 2.0 upgrades Carbon to version 3.
diffInmethods 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
$datesproperty on models has been removed. You should now use the$castsproperty 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
stringtotext, 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
NullAdapterhas been removed. You may instead use theInMemoryFilesystemAdapter.The
Localadapter has been removed. You should use theLocalFilesystemAdapterinstead.The
FilesystemAdapterconstructor 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, andAbstractDeleteControllerhave been removed. - The
AbstractSerializerhas been removed. - The
ApiControllerandApiSerializerextenders have been removed. - The
Savingare 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
JsonApiclass if you wish to execute logic from an existing endpoint internally instead. - The
flarum.forum.discussions.sortmapsingleton has been removed. Instead, you can define anascendingAliasanddescendingAliason your addedSortColumnsorts. - The
showdiscussion endpoint no longer includes thepostsrelationship, so anyposts.*relation includes or eager loads added to that endpoint must be removed. You can move those to thelistposts 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 extendAbstractSearcherinstead (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\Queryhave been moved toFlarum\Search. The classes withinFlarum\Filterhave been moved toFlarum\Search\Filter. TheFilterStateclass has been removed, you should use theSearchStateclass 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, andwhenPgsqlmethods 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-supportkey in yourcomposer.jsonto 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-modeand@config-colored-headervariables 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-headervariable 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
Themeextender and equivalent CSS code[data-theme=your-scheme].
Email Notifications
Breaking
- The
getEmailViewmethod of theFlarum\Notification\MailableInterfaceinterface has been renamed togetEmailViews getEmailViewsnow requires you to return bothtextandhtmlviews 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\AlertableInterfaceinterface in order them to be sent as alerts. This allows for email-only notifications for example. - The
staudenmeir/eloquent-eager-limitpackage has been removed. If you are using theStaudenmeir\EloquentEagerLimit\HasEagerLimittrait in any of your models, you can simply remove it as it is native to Laravel now.
Notable
- The
Frontendextender now allows passing extra attributes and classes that will be added to the roothtmltag, through theextraDocumentAttributesandextraDocumentClassesmethods. - 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@maintoflarum/framework/.github/workflows/[email protected].