• ResourcesTutorials
  • Understanding templating in Flarum when you come from a different background

While having a chat with a few people including @dsgnr and @Davis on Gitter I realized that the JavaScript MVC nature of Flarum can be hard for people coming from other forums or WP to understand, in particular when it gets to editing "templates". There is simply no such thing here ?

So I wrote an article on my blog where I try to explain the differences: <https://blog.clarkwinkelmann.com/2016/08/flarum-templating>

Here's a copy of the conclusion:

  • The visual interface of Flarum is a JavaScript MVC application powered by Mithril
  • It talks to a PHP application which just sends data as JSON, not as HTML
  • The PHP application does uses Views, but only to render the JavaScript application
  • The JavaScript Views are organised as Components, which are placed in a hierarchical way on the page
  • To change how something looks like, you have to edit the Component responsible for it
  • You can add new Components as child of existing ones

Any suggestion to improve my article is welcome ?

    2 years later

    clarkwinkelmann Damn how everything is difficult, I always went on such frameworks as WP for me it is impossible to understand how to change the design for this forum.
    Maybe you should make a video example, for example how to change the location of a button or text.

    And since I really like the engine, it is obviously cooler than all the others.
    I already learned this composer when I came here and understood how easy it is to update or delete components.

      Pirat I already made a few videos that show some of those concepts, there's a discussion about those you've probably found. I'll try to make new videos in December or next year 😉

        clarkwinkelmann I watched one video where you did something with the registration I did not understand 🙂

        clarkwinkelmann It turns out the template can not be changed, he himself creates

        I noticed that all files are in the assets folder, it caches the template, is it possible to disable it to see the location of errors?

          Pirat I have trouble understanding what you're saying here.

          Are you talking about javascript and the absence of a sourcemap ?

          Files in assets are a compiled version of each extension's javascript files, themselves compiled from their source files via gulp (will be replaced by webpack in beta8). You can usually guess the source file from the import names in the compiled files. Beta8 will have sourcemaps which should help locating the source code from the compiled code.

            Pirat If I can disable them I can see errors in js and css

            Are you seeing errors in the browser console ? What are you trying to do ? Are you working on an extension ?

            EDIT: in case this helps, these files are always created by Flarum. Turning debug mode should reduce how much they get compressed/obfuscated. If debug mode is turned on they will also not be cached and be created again on every request.

              clarkwinkelmann I am trying to change the template to rearrange one part to another place
              I usually do everything in the browser and then change the code.
              I feel so comfortable

                Pirat are we taling about JS or CSS ?

                You can add your custom CSS to the "Custom LESS" section of your admin dashboard and it will be added everytime the CSS is re-generated.

                For javascript you'd need to edit core files, but that's highly discouraged because your changes will be overwritten on next installations/updates. The only official and supported way to extend javascript is via an extension.

                  clarkwinkelmann Here is an example: take a piece of search code

                  \flarum\core\js\forum\src\components\Search.js

                   return (
                    <div className={'Search ' + classList({
                      open: this.value() && this.hasFocus,
                      focused: this.hasFocus,
                      active: !!currentSearch,
                      loading: !!this.loadingSources
                    })}>
                      <div className="Search-input">
                        <input className="FormControl"
                          type="search"
                          placeholder={extractText(app.translator.trans('core.forum.header.search_placeholder'))}
                          value={this.value()}
                          oninput={m.withAttr('value', this.value)}
                          onfocus={() => this.hasFocus = true}
                          onblur={() => this.hasFocus = false}/>
                        {this.loadingSources
                          ? LoadingIndicator.component({size: 'tiny', className: 'Button Button--icon Button--link'})
                          : currentSearch
                            ? <button className="Search-clear Button Button--icon Button--link" onclick={this.clear.bind(this)}>{icon('times-circle')}</button>
                            : ''}
                      </div>
                      <ul className="Dropdown-menu Search-results">
                        {this.value() && this.hasFocus
                          ? this.sources.map(source => source.view(this.value()))
                          : ''}
                      </ul>
                    </div>
                  );

                  forum-1acc9977.js

                  return m(
                  'div',
                  { className: 'Search ' + classList({
                  open: this.value() && this.hasFocus,
                  focused: this.hasFocus,
                  active: !!currentSearch,
                  loading: !!this.loadingSources
                  }) },
                  m(
                  'div',
                  { className: 'Search-input' },
                  m('input', { className: 'FormControl',
                  type: 'search',
                  placeholder: extractText(app.translator.trans('core.forum.header.search_placeholder')),
                  value: this.value(),
                  oninput: m.withAttr('value', this.value),
                  onfocus: function onfocus() {
                  return _this2.hasFocus = true;
                  },
                  onblur: function onblur() {
                  return _this2.hasFocus = false;
                  } }),
                  this.loadingSources ? LoadingIndicator.component({ size: 'tiny', className: 'Button Button--icon Button--link' }) : currentSearch ? m(
                  'button',
                  { className: 'Search-clear Button Button--icon Button--link', onclick: this.clear.bind(this) },
                  icon('times-circle')
                  ) : ''
                  ),
                  m(

                  As you can see it is the same
                  I want the browser to show the original code

                  it did not help me 'debug' => true,

                    clarkwinkelmann And here is the CSS file
                    flarum\core\less\lib\Search.less

                    .Search-input {
                    overflow: hidden;
                    color: @muted-color;
                    &:before {
                    .fa();
                    content: @fa-var-search;
                    float: left;
                    margin-right: -36px;
                    width: 36px;
                    font-size: 14px;
                    text-align: center;
                    position: relative;
                    padding: 7px 0;
                    line-height: 1.5;
                    pointer-events: none;
                    }

                    \assets\admin-665fa4bb.css

                    .Search-input{overflow:hidden;color:#667c99}.Search-input:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f002";float:left;margin-right:-36px;width:36px;font-size:14px;text-align:center;position

                    It is very uncomfortable

                    Pirat there are 3 steps from source file to asset file in javascript extensions and core:

                    • Source code (under <extension or core>/js/<forum|admin>/src)
                    • Dist file (under <extension or core>/js/<forum|admin>/dist, compiled from the source code with gulp by the developer)
                    • Asset file (under <flarum path>/assets, compiled by Flarum at run time from all dist files from all extensions)

                    If you want your manual changes to be applied you need to run gulp to create the dist files again or edit the dist files directly. Again, I don't recommend doing either of these as your changes won't be permanent.

                      clarkwinkelmann The main problem, of course, is changing the template, but how to change it if it is written in javascript
                      Personally, I almost often changed php and html for me to change the javascript template is how to program. I guess I'll have to learn javascript

                      In Russia, php is not a programming language
                      For us, this is the same as html

                      Here's how it's done in PhpBB for contrast.

                      styles/yourthemename/template <-- the view files ( HTML ).
                      styles/yourthemename/theme <-- the CSS.

                      If you make another theme, it automatically pulls all the .html files from prosilver unless you have one in the template folder, so you don't have to 'fork' the default prosilver theme entirely, which is great for maintainability.

                      They're using the twig templating system from symfony which is easy enough to understand with a quick glance.

                      PhpBB however has no real ajax going on and is absolutely not a single page style app like this.
                      Not that you couldn't have a similar setup for a setup that uses javascript to dump written HTML on the screen, with some performance penalty for the sake of lowering the bar for theme creators.

                      That would take a lot of refactoring and rethinking though.