Hi, need some help to use custom helpers in child theme

NodeBB Development
  • Hello,

    I need to customize links in my custom child template with a helper like :

    //in my template file : 
    <span data-apt="{function.obfuscate, someUrl}" />

    I found some solutions on old topics but nothing in the documentation.

    My first attempt was to use the app load hook:

    // in the plugin.json file 
    { "hook": "static:app.load", "method": "init" },
    // in library.js
    const benchpress = require.main.require('benchpressjs');
    library.init =  async function (params) {
    	app = params.app;
    	const middleware = params.middleware;
    	benchpress.registerHelper('obfuscate', function(data){
    		// custom code
                    return 'mycustomcode';

    My second attempt with a simple module and a require :

    // in helpers.js
    (function (factory) {
    	if (typeof module === 'object' && module.exports) {
    	} else {
    		require(['benchpress'], factory);
    })(function (Benchpress) {
    	Benchpress.registerHelper('obfuscate', function (data) {
    			return 'my-custom-result';
    //in library.js

    And the pretty empty output trace for Benchpress object:

    benchpress {
       "helpers": {},
       "cache": {},
       "globals": {
          "true": true,
          "false": false

    Have you an idea ? A better way to add and use helpers ?


  • The helper has to be registered both on the client side and the server side.

  • @PitaJ I see that in an other topic. It needs only this line in plugin.json :

    scripts : "./helpers.js" in plugin.json

    If the client registration is missing, at least it should work on first load... I miss the point here.

  • I have added some traces on the Benchpress object :

      precompile: [Function: precompile] {
        isNative: true,
        defaults: { minify: false, unsafe: false, native: true }
      __express: [Function: __express],
      evaluate: [Function: evaluate],
      compileRender: [Function: compileRender],
      compileParse: [Function: compileParse],
      runtime: [Function: runtime],
      helpers: {
        __escape: [Function: identity],
        displayMenuItem: [Function: displayMenuItem],
        buildMetaTag: [Function: buildMetaTag],
        buildLinkTag: [Function: buildLinkTag],
        stringify: [Function: stringify],
        escape: [Function: escape],
        stripTags: [Function: stripTags],
        generateCategoryBackground: [Function: generateCategoryBackground],
        generateChildrenCategories: [Function: generateChildrenCategories],
        generateTopicClass: [Function: generateTopicClass],
        membershipBtn: [Function: membershipBtn],
        spawnPrivilegeStates: [Function: spawnPrivilegeStates],
        localeToHTML: [Function: localeToHTML],
        renderTopicImage: [Function: renderTopicImage],
        renderDigestAvatar: [Function: renderDigestAvatar],
        userAgentIcons: [Function: userAgentIcons],
        buildAvatar: [Function: buildAvatar],
        register: [Function: register],
        logger: [Function: logger],
        obfuscate: [Function: obfuscate]
      registerHelper: [Function: registerHelper],
      cache: {},
      globals: { true: true, false: false },
      setGlobal: [Function: setGlobal],
      addGlobals: [Function: addGlobals],
      flush: [Function: flush],
      render: [Function: render],
      parse: [Function: parse],
      registerLoader: [Function: registerLoader]

    My two custom helper functions, logger and obfuscate, are visible, but the result template still show {function.obfuscate, 'testUrl'} .

  • I have found the problem, it was a bad theme declaration. My child theme was not encapsulate in

    (function(module) {

    Unfortunately, now i have a new probleme. It seems not possible to concatenate var in helper parameter like this :

    {function.myHelper, {config.relative_path}/user/{posts.user.userslug}}
    {function.myHelper, config.relative_path + '/user' + posts.user.userslug}

    Any idea ?

  • Yeah that isn't possible. Instead you'll need to pass the individual values in as arguments and perform the concatenation in the helper itself.

    BTW, I recommend you use the new helper syntax. It's easier to reason about.


  • yes, it's the solution i have chosen. Thx !

Suggested Topics

  • 5 Votes
    6 Posts

    If you are going to store a lot of stuff I would use ./src/cacheCreate to create my own, ./src/cache is for a few stuff that never changes like the list of categories etc. If you put a lot of your own stuff in there like urls for link-previews it will negatively effect the performance. For stuff like that just create your own lru cache.

  • 0 Votes
    10 Posts

    I've got the point. Thanks for all the help.

  • 1 Votes
    5 Posts

    Um.... ok.

    How did you come to this conclusion?

  • 0 Votes
    2 Posts

    Hmm, idk, some parts of the code could use better adherence to a style for consistency, and it may encourage new contributors.

    I feel like styles are largely based on opinion though. And in situations where a style does help, such as avoiding confusing/ambiguous expressions, NodeBB rarely suffers from these problems.

    I am against tabs though. I hate them. Used to love them, but after using spaces, i can never go back. (I really really hate semicolons too.)

  • 0 Votes
    28 Posts

    @julian I see. Well I'm trying to basically port Vanilla's plugin to Nodebb, but I'm not sure if I'll be able to so it'd be cool if you devs had some official, simpler solution like it.

    Vanilla's is really easy. You give it the url for your registration and login page, and a url where it expects JSON to return for a users name, email, etc if they're logged in. If they're logged in, it creates a Vanilla forum user for them if one doesn't already exist. If they already on, it just logs them in normally as if they typed in their username and password on the Vanilla forums.
    So no matter what auth system you use, you can use your own API to output the JSON it wants, so long as the client-id and secret key supplied matches up as well. I have my own accounts system and it took me like <1 hour to read the documentation for how to set it up with Vanilla's and do a custom implementation.
    Reading the oauth plugins on the other hand, I'm rather clueless on what I need to do to make it work for my own, and what I need on my own site's end of things. Like looking at the BNET plugin, I can't figure out what "clientID: process.env.BNET_ID" and "clientSecret: process.env.BNET_SECRET" are, among other things. It's just too in depth for something that should be simpler.

    edit: Actually I see what the process.env are. They're user environment variables. But well, still, the oauth sso is way more complicated than I think a lot of people will want.
    Like if I want to replace the profile, I'd rather that have a separate plugin replacing the profile. Not part of the OAuth implementation. I imagine I can just cut that out while forking, but still. I wish there was something as simple as Vanilla's JSONP SSO.

    And as I look through more, I'm not seeing why authorizationURL, tokenURL, clientID, clientSecret can't just be on settings pages instead of constants, with an oauth/oauth2 radial.