We’ve recently been working on updating Discourse’s header from the legacy ‘widget’ rendering system to modern Glimmer components. This change is now available in Discourse core behind the glimmer header mode
site setting.
Approximate Timeline
(very rough estimates - subject to change in either direction)
Q1 2024:
-
core implementation finished & enabled on Meta
-
upgrade advice published; console deprecation messages enabled
-
work begins to update all official and third-party plugins/themes
Q2 2024:
-
start enabling new header implementation by default
-
official and third-party themes/plugins are ready for the upgrade
-
Deprecation messages start triggering an admin warning banner for any remaining issues
Q3 2024:
-
Announcement topic posted for wider visibility: Preparing your community for behind-the-scenes header changes
-
w/c 5th August 2024 (v3.4.0.beta1): new header enabled for all sites by default. It will still be possible for admins to switch back to the old header by toggling the ‘glimmer header mode’ site setting.
-
w/c 2nd September 2024: final removal of feature flag and legacy code
What Does it Mean for Me?
If your plugin or theme uses any ‘widget’ APIs to customize the header, those will need to be updated for compatibility with the new header.
How Do I Try the New Header?
In the latest version of Discourse, the new header is automatically enabled when all your themes/plugins are compatible.
If your themes/plugins are not compatible, then the legacy header will still be used, and a warning will be printed to the console alongside the existing deprecation messages. A warning banner will also be shown to admins in the UI.
In the unlikely event that this automatic system does not work as expected, you can temporarily override this ‘automatic feature flag’ via the glimmer header mode
site setting. If you do that, please let us know the reason in this topic.
Do I Need to Update My Plugin/Theme?
To determine whether your customization needs to be updated, check if it uses decorateWidget
, changeWidgetSetting
, reopenWidget
or attachWidgetAction
on any of these widgets:
- header
- site-header
- header-contents
- header-buttons
- user-status-bubble
- sidebar-toggle
- header-icons
- header-topic-info
- header-notifications
- home-logo
- user-dropdown
or uses one of these plugin API methods:
addToHeaderIcons
addHeaderPanel
All of these things will now cause deprecation messages to be printed to the console. Deprecation IDs are:
discourse.add-header-panel
discourse.header-widget-overrides
If you use more than one theme in your instance, be sure to check all of them.
Admin notice
As of June 20, 2024, we’ve enabled the admin notice for the deprecations above.
If your instance was deployed after this date and your instance’s current plugins, theme, or theme components triggers one of the deprecation warnings, the following message will be displayed only for the admins*:
This message is just to alert the admins that they need to take action soon to modernize the affected customizations: the old customizations will still work until we remove the legacy codebase.
What Are the Replacements?
Each theme/plugin is different, but here is some guidance for the most common use cases:
addToHeaderIcons
For custom header icons, we recommend removing your code and installing the official Custom Header Links (Icons) Theme Component. If that doesn’t meet your requirements, see below for information for details on the required code changes:
The addToHeaderIcons
plugin API has been deprecated in favor of the new headerIcons
API. It exists to allow adding, removing, or re-ordering of icons in the header. It requires a Component to be passed.
The component can be passed as so:
Before | After |
---|---|
api.addToHeaderIcons(“widget-foo”) | api.headerIcons.add(“foo”, FooIcon) |
api.decorateWidget(“header-icons:before”, () => return helper.h(“div”, “widget-foo”)) | api.headerIcons.add(“foo”, FooIcon, { before: “search” }) |
api.decorateWidget(“header-icons:after”, () => return helper.h(“div”, “widget-foo”)) | api.headerIcons.add(“foo”, FooComponent, { after: “search” }) |
This example uses Ember’s Template Tag Format (gjs) to define a component inline and pass it to the headerButtons.add API:
// .../discourse/api-initializers/add-my-button.gjs
import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("1.0", (api) => {
api.headerIcons.add("some-unique-name", <template>
<li><DButton class="icon btn-flat" @href="/u" @icon="address-book" /></li>
</template>);
});
Or for a dropdown, you could use <DMenu
instead of <DButton
:
import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";
import DMenu from "float-kit/components/d-menu";
export default apiInitializer("1.0", (api) => {
api.headerIcons.add("some-unique-name", <template>
<li>
<DMenu class="icon btn-flat" @icon="address-book">
<DButton @translatedLabel="User 1" @href="/u/user1" />
<DButton @translatedLabel="User 2" @href="/u/user2" />
<DButton @translatedLabel="User 3" @href="/u/user3" />
</DMenu>
</li>
</template>);
});
Example upgrade commits:
decorateWidget("header-buttons:*")
For custom header links, we recommend removing your code and installing the official Custom Header Links Theme Component. If that doesn’t meet your requirements, see below for information for details on the required code changes:
The header-buttons
widget has been deprecated and we have introduced a headerButtons
plugin API. It exists to allow adding, removing, or re-ordering of buttons in the header. It requires a Component to be passed.
Before | After |
---|---|
api.decorateWidget(“header-buttons:before”) | api.headerButtons(“button-name”, ButtonComponent, { before: “auth” }) |
api.decorateWidget(“header-buttons:after”) | api.headerButtons(“button-name”, ButtonComponent, { after: “auth” }) |
changeWidgetSetting(...)
for the header widgets
The most common uses of
changeWidgetSetting
can be achieved using these theme components:If these don’t fit your use-case, read on…
Some customizations on the header widgets were using the changeWidgetSetting
API.
Although, there is no direct replacement for customizations like the one above, due to how the Glimmer components fields work, we introduced a new plugin API on Discourse 3.3.0.beta3 to handle some of these cases.
registerValueTransformer
can be used to override values that were tagged in the source code as overridable, this is a similar approach to how plugin outlets work.
We already added two transformers for the use cases we found to be common in our source code base:
-
home-logo-href
: can be used to override the URL in the home logo anchor. See the sectionhome-logo
below for examples. -
header-notifications-avatar-size
: can be used to change the size of the image fetched to the user avatar in the header. Example:
The code below:
api.changeWidgetSetting(
"header-notifications",
"avatarSize",
settings.header_avatars_size
);
Would be converted to:
api.registerValueTransformer(
"header-notifications-avatar-size",
() => settings.header_avatars_size
);
These transformers need to be added to the Discourse source code. If you need a different one, please let us know posting your use case below.
More details about the new value transformer APIs can be found here.
home-logo
We have introduced a home-logo
plugin outlet in replacement of home-logo:before
or home-logo:after
widget decorations. You can utilize the automatic __before
and __after
naming in your connector file to specify where your custom content should be placed.
More details on before/after connector file naming can be found here.
Before | After |
---|---|
api.decorateWidget(“home-logo:before”) | Move content to /connectors/home-logo__before |
api.decorateWidget(“header-buttons:after”) | Move content to /connectors/home-logo__after ) |
Altering the home-logo anchor URL:
A very common need is altering the URL the home-logo
links to. We introduced the home-logo-href
value transformer to address this. Examples:
-
to change the link to a static URL
api.registerValueTransformer("home-logo-href", () => "https://example.com");
-
to return a dynamic URL based on the current user
api.registerValueTransformer("home-logo-href", () => { const currentUser = api.getCurrentUser(); return `https://example.com/${currentUser.username}`; });
-
to return a URL based on a theme-component setting
api.registerValueTransformer("home-logo-href", () => { return settings.example_logo_url_setting; });
What about other customizations?
If your customization cannot be achieved using CSS, PluginOutlets, or the new APIs we’ve introduced, please let us know by creating a new dev topic to discuss.
How do I update a theme/plugin to support both old and new header?
All the new APIs and plugin outlets listed in this document are supported on both the new and the old header. So you only need to make one update to your theme/plugin now, and users will be ready for the switch.