PageSourceSearch

https://docs.flarum.org/assets/js/bb237684.35f06155.js

js flarum.org collected 2026-09-24 18:16:23 UTC 6,932 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkflarum_docs=globalThis.webpackChunkflarum_docs||[]).push([[7301],{5745(e,n,s){s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>x,frontMatter:()=>r,metadata:()=>t,toc:()=>l});const t=JSON.parse('{"id":"extend/extending-extensions","title":"Extending Extensions","description":"Flarum extensions aren\'t just for adding features to core: extensions can extend other extensions!","source":"@site/docs/extend/extending-extensions.md","sourceDirName":"extend","slug":"/extend/extending-extensions","permalink":"/extend/extending-extensions","draft":false,"unlisted":false,"editUrl":"https://github.com/flarum/docs/tree/main/docs/extend/extending-extensions.md","tags":[],"version":"current","frontMatter":{},"sidebar":"extendSidebar","previous":{"title":"Database","permalink":"/extend/database"},"next":{"title":"Extensibility","permalink":"/extend/extensibility"}}');var i=s(4848),o=s(8453);const r={},a="Extending Extensions",d={},l=[{value:"Dependencies",id:"dependencies",level:2},{value:"Optional Dependencies",id:"optional-dependencies",level:2},{value:"Importing from Extensions",id:"importing-from-extensions",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"extending-extensions",children:"Extending Extensions"})}),"\n",(0,i.jsx)(n.p,{children:"Flarum extensions aren't just for adding features to core: extensions can extend other extensions!"}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["To learn how to make your extension extensible, see the ",(0,i.jsx)(n.a,{href:"/extend/extensibility",children:"relevant documentation"})]})}),"\n",(0,i.jsx)(n.h2,{id:"dependencies",children:"Dependencies"}),"\n",(0,i.jsx)(n.p,{children:"If your extension relies on another extension, you'll want to ensure that:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"The other extension is installed and enabled before yours can be."}),"\n",(0,i.jsx)(n.li,{children:"The other extension can't be disabled while yours is enabled."}),"\n",(0,i.jsx)(n.li,{children:"The other extension is booted before your extension."}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Flarum makes this very easy: just add the other extension to your extension's ",(0,i.jsx)(n.code,{children:"composer.json"}),"'s ",(0,i.jsx)(n.code,{children:"require"})," section."]}),"\n",(0,i.jsxs)(n.p,{children:["For example, if you were building a new theme for the Flarum Tags extension, your ",(0,i.jsx)(n.code,{children:"composer.json"})," would look like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n  // ...\n  "require": {\n    "flarum/core": "^2.0",  // Since all extensions need to require core.\n    "flarum/tags": "*"  // This tells Flarum to treat tags as a dependency of your extension.\n  },\n  // ...\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"optional-dependencies",children:"Optional Dependencies"}),"\n",(0,i.jsx)(n.p,{children:'Sometimes, extension A might want to extend extension B only if extension B is enabled.\nIn this case, we call B an "Optional Dependency" of A.\nFor instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled.'}),"\n",(0,i.jsxs)(n.p,{children:["The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the ",(0,i.jsx)(n.code,{children:"flarum.extensions"})," global object. For instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:"if ('some-extension-id' in flarum.extensions) {\n    // do something\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In the backend, you'll need to inject an instance of ",(0,i.jsx)(n.code,{children:"Flarum\\Extension\\ExtensionManager"}),", and use its ",(0,i.jsx)(n.code,{children:"isEnabled()"})," method. For instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",children:"<?php\n\nuse Flarum\\Extension\\ExtensionManager;\n\nclass SomeClass {\n    public function __construct(ExtensionManager $extensions)\n    {\n        $this->extensions = $extensions;\n    }\n\n    public function someMethod()\n    {\n        if ($this->extensions->
1isEnabled('some-extension-id')) {\n            // do something.\n        }\n    }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies.\nYou can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the ",(0,i.jsx)(n.code,{children:"extra.flarum-extension.optional-dependencies"})," key of your composer.json."]}),"\n",(0,i.jsx)(n.p,{children:"For instance:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n  // ...\n  "extra": {\n    "flarum-extension": {\n      "optional-dependencies": [\n        "flarum/tags"\n      ]\n    }\n  },\n  // ...\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"importing-from-extensions",children:"Importing from Extensions"}),"\n",(0,i.jsxs)(n.p,{children:["In the backend, you can import the classes you need via regular PHP ",(0,i.jsx)(n.code,{children:"use"})," statements:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",children:"<?php\n\nuse Flarum\\Tags\\Tag;\n\nclass SomeClass\n{\n    public function someMethod()\n    {\n        return new Tag();  // This is not the correct way to instantiate models, it's just here for example of importing.\n    }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Note that if you're importing from an optional dependency which might not be installed, you'll need to check that the class in question exists via the ",(0,i.jsx)(n.code,{children:"class_exists"})," function."]}),"\n",(0,i.jsxs)(n.p,{children:["In the frontend, you can import any modules exported by other extensions via the ",(0,i.jsx)(n.code,{children:"ext:vendor/extension/.../module"})," syntax. For instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import Tag from 'ext:flarum/tags/common/models/Tag';\n"})})]})}function x(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453(e,n,s){s.d(n,{R:()=>r,x:()=>a});var t=s(6540);const i={},o=t.createContext(i);function r(e){const n=t.useContext(o);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.