# Using modifyClass to change core behavior

**URL:** https://meta.discourse.org/t/using-modifyclass-to-change-core-behavior/262064
**Category:** Developer Guides
**Created:** [April 18, 2023, 10:24am UTC](https://meta.discourse.org/t/using-modifyclass-to-change-core-behavior/262064 "2023-04-18T10:24:36Z")
**Posts on this page:** 1
**Showing post:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [April 18, 2023, 10:24am UTC](https://meta.discourse.org/t/using-modifyclass-to-change-core-behavior/262064/1 "2023-04-18T10:24:37Z")

</div>

For advanced themes and plugins, Discourse offers the `modifyClass` system. This allows you to extend and override functionality in many of core’s javascript classes.

## When to use `modifyClass`

`modifyClass` should be a last resort, when your customization cannot be made via Discourse’s more stable customization APIs (e.g. plugin-api methods, plugin outlets, transformers).

Core’s code can change at any time. And therefore, customizations made via `modifyClass` could break at any time. When using this API, you should ensure that you have controls in place to catch those issues before they reach a production site. For example, you could add automated tests to the theme/plugin, or you could use a staging site to test incoming Discourse updates against your theme/plugin.

## Basic Usage

`api.modifyClass` can be used to modify the functions and properties of any class which is accessible via the Ember resolver. That includes Discourse’s routes, controllers, services and components.

`modifyClass` takes two arguments:

- `resolverName` (string) - construct this by using the type (e.g. component/controller/etc.), followed by a colon, followed by the (dasherized) filename name of the class. For example: `component:d-button`, `component:modal/login`, `controller:user`, `route:application`, etc.

- `callback` (function) - a function which receives the existing class definition, and then returns an extended version.

For example, to modify the `click()` action on d-button:

```js
api.modifyClass(
  "component:d-button",
  (Superclass) =>
    class extends Superclass {
      @action
      click() {
        console.log("button was clicked");
        super.click();
      }
    }
);

```

The `class extends ...` syntax mimics that of [JS child classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#inheritance). In general, any syntax/features supported by child classes can be applied here. That includes `super`, static properties/functions, and more.

However, there are some limitations. The `modifyClass` system only detects changes to the class’s JS `prototype`. Practically, that means:

- introducing or modifying a `constructor()` is not supported

- introducing or modifying class fields is not supported (although some decorated class fields, like `@tracked` can be used)

- simple class fields on the original implementation cannot be overridden in any way (although, as above, `@tracked` fields can be overridden by another `@tracked` field)

If you find yourself wanting to do these things, then your use-case may be better satisfied by making a PR to introduce new APIs in core (e.g. plugin outlets, transformers, or bespoke APIs).

## Upgrading Legacy Syntax

In the past, modifyClass was called using an object-literal syntax like this:

```js
// Outdated syntax - do not use
api.modifyClass("component:some-component", {
  someFunction() {
    const original = this._super();
    return original + " some change";
  }
  pluginId: "some-unique-id"
});

```

This syntax is no longer recommended, and has known bugs (e.g. overriding getters or `@actions`). Any code using this syntax should be updated to use the native-class syntax described above. In general, conversion can be done by:

1. removing `pluginId` - this is no longer required
2. Update to the modern native-class syntax described above
3. Test your changes

## Troubleshooting

### Class already initialized

When using modifyClass in an initializer, you may see this warning in the console:

> `Attempted to modify "{name}", but it was already initialized earlier in the boot process`

In theme/plugin development, there are two ways this error is normally introduced:

- **Adding a `lookup()` caused the error**

- **Adding a new `modifyClass` caused the error**

* * *

This document is version controlled - suggest changes [on github](https://github.com/discourse/discourse/blob/main/docs/developer-guides/docs/03-code-internals/15-modifyclass.md).

---

_[View the full topic](https://meta.discourse.org/t/using-modifyclass-to-change-core-behavior/262064)._
