Skip to content

NodeBB Plugins

Discussion regarding NodeBB Plugin development.

1.8k Topics 15.0k Posts
Most Voted Plugins

Subcategories


  • Have a question about building a plugin? Ask here
    424 Topics
    2k Posts
    barisB

    https://community.nodebb.org/post/88242 I think this answers your question. Let me know if it doesn't work.

  • Need a plugin developed? Ask here!
    222 Topics
    1k Posts
    barisB

    Plugin doesn't show usernames if they set their status to offline AFAIK

  • [nodebb-plugin-poll] Poll plugin

    187
    14 Votes
    187 Posts
    142k Views
    dave1904D

    @phenomlab thanks!

  • 7 Votes
    24 Posts
    5k Views
    crazycellsC

    @baris said in [nodebb-plugin-osm-map] OpenStreetMap based map to locate users:

    Version 2.2.0 of this plugin is compatible with 3.2.0 and up.

    thank you 🙏

  • 12 Votes
    40 Posts
    18k Views
    LEVI HAVIVL

    I thought about it,
    It's not that complicated at all.
    The question is what kind of meeting are we going for...
    About a big meeting, with screen sharing, moderators, etc.
    Or you go for a type of personal meeting, like the original idea, that there is such a button in the chat, of a conversation, and then it's like a WhatsApp conversation, where you just see each other... That's it, without extensive options...

    @julian what are you saying?

  • 0 Votes
    3 Posts
    176 Views
    LEVI HAVIVL

    Oh!
    Thanks for the comment,
    In the meantime, I found a plugin that defines this, and on the server side I simply launch a socket, which is sent to the plugin, and then the plugin sends the notification.

  • [nodebb-plugin-adsense] Google Adsense

    82
    6 Votes
    82 Posts
    59k Views
    barisB

    This plugin is updated to work with 3.2.x and up. It also uses widgets now instead of hardcoded ad areas so it is possible to place an ad wherever there is widget area in the theme.

    @omega I've added /ads.txt support into the plugin.
    25311c03-f012-4298-969d-ef0d7b0edc74-image.png

    This only applies if the forum is hosted on the root domain, if you have another CMS on your root domain you need to handle it there. The adsense verification can be done with the custom head tab in the ACP if nodebb is on the root domain.

  • 5 Votes
    26 Posts
    2k Views
    B

    @DownPW change 6M to 150M or 200M

  • nodebb-plugin-topic-noindex

    3
    3 Votes
    3 Posts
    381 Views
    barisB

    @crazycells that's correct

  • 37 Votes
    302 Posts
    247k Views
    barisB

    @Hope33 when you activate shoutbox and rebuild restart it should add a new route at yourforum.com/shoutbox you can also drag and drop it as a widget on a page.

  • Re-render component without refreshing page

    2
    0 Votes
    2 Posts
    167 Views
    barisB

    If you want to re-render something client side you can use

    const html = await app.parseAndTranslate('path/to/template', 'blockName', data);

    Where block name is the name used in the tpl file for a loop like {{{ each topics }}} and then once the render is done you can replace the html with jquery $('#some-target').html(html);.

    If you search core code you will see many uses of app.parseAndTranslate to update the DOM.

  • LDAP Plugin

    30
    0 Votes
    30 Posts
    2k Views
    phenomlabP

    I found this listed in the NPM registry
    https://github.com/Chrischenny/nodebb-plugin-node-ldap-ad

    Can't get it to work though - crashes NodeBB every time.

    EDIT - working now - I had the one amended by @baris still installed, so removed and all good from the stability perspective. Doesn't seem to work with AD though - at least, not for me - investigating.

  • 0 Votes
    22 Posts
    1k Views
    phenomlabP

    @baris Thanks

  • 18 Votes
    356 Posts
    271k Views
    Gliding9426G

    Forgot to mention that if i open that URL from the browser window I get the expected result in the JSON, the response contains

    "isAdmin": true, "isLoggedIn": true,

    It looks like if the browser does the request in the page via the javascript, could not access the cookies and so it gets a "logged out" json (but i tested on clean ms edge with no cookie blocking)

    Ps: i could not edit the other post because of a weird issue, I'm going to open another post to ask if this is intended behavior

  • 7 Votes
    136 Posts
    42k Views
    DownPWD

    @DownPW said in [nodebb-plugin-ns-embed] NS Embed:

    I search dailymotion rules for this plugin.

    I've tested this but doesn't work

    Dailymotion
    Watch

    (?:<a.*?)?(?:https?:\\/\\/)?(?:www\\.)?dailymotion\\.com\\/video\\/([a-zA-Z0-9_-]{4,11})(?:.*?\\/a>)?

    Replace

    <div class='embed-wrapper'><div class='embed-container'><iframe src='//www.dailymotion.com/embed/video/$1' frameborder='0' allowfullscreen></iframe></div></div>

    Anyone ?

  • 0 Votes
    5 Posts
    227 Views
    oplik0O

    If you need to use v1.x, the latest release is v1.19.12
    You can find upgrade instructions here: https://docs.nodebb.org/configuring/upgrade/
    Follow the "via release branches" part and use the v1.x branch.

    However, if you can upgrade to v3 or at least v2 that would probably be preferable, since they'll be supported for longer (v2 will get security fixes until August 2025. source) in addition to offering quite a few new features.

  • This topic is deleted!

    1
    0 Votes
    1 Posts
    30 Views
  • 0 Votes
    6 Posts
    632 Views
    murcsM

    @DownPW said in [nodebb-widget-board-stats] discrepancy to dashboard count:

    any news @murcs ?

    i just digged a little deeper for you: „our“ /var/www/nodebb/node_modules/nodebb-widget-board-stats/library.js looks like this

    'use strict'; const async = require('async'); const nconf = module.parent.require('nconf'); const db = require.main.require('./src/database'); const user = require.main.require('./src/user'); const utils = require.main.require('./src/utils'); const socketPlugins = require.main.require('./src/socket.io/plugins'); const socketRooms = require.main.require('./src/socket.io/admin/rooms'); let app; const Widget = module.exports; Widget.init = function (params, callback) { app = params.app; callback(); }; socketPlugins.boardStats = {}; socketPlugins.boardStats.get = function (socket, tid, callback) { getWidgetData(callback); }; function addDots(text) { return String(text).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.'); }; function getWidgetData(callback) { async.parallel({ global: function (next) { db.getObjectFields('global', ['topicCount', 'postCount', 'userCount'], next); }, latestUser: getLatestUser, activeUsers: getActiveUsers, onlineUsers: Widget.updateAndGetOnlineUsers, activeWithin24h: function (next) { var now = Date.now(); db.sortedSetCount('users:online', now - 86400000, '+inf', next); }, }, function (err, results) { if (err) { return callback(err); } var data = { within24h: results.activeWithin24h, count: addDots(results.onlineUsers.onlineCount + results.onlineUsers.guestCount), members: addDots(results.onlineUsers.onlineCount), guests: addDots(results.onlineUsers.guestCount), list: joinUsers(results.activeUsers), posts: addDots(results.global.postCount ? results.global.postCount : 0), topics: addDots(results.global.topicCount ? results.global.topicCount : 0), registered: addDots(results.global.userCount ? results.global.userCount : 0), latest: joinUsers(results.latestUser), relative_path: nconf.get('relative_path'), mostUsers: { date: (new Date(parseInt(results.onlineUsers.timestamp, 10))).toDateString(), total: results.onlineUsers.total, }, }; callback(null, data); }); } function getActiveUsers(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:online', 0, 19, next); }, function (uids, next) { user.getUsersFields(uids, ['username', 'userslug', 'status'], next); }, ], function (err, data) { if (err) { return callback(err); } data = data.filter(function (a) { return a.status === 'online'; }); callback(err, data); }); } function getLatestUser(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:joindate', 0, 0, next); }, function (uids, next) { user.getUsersWithFields(uids, ['username', 'userslug'], 0, next); }, ], callback); } function joinUsers(usersData) { var str = []; for (var i = 0, ii = usersData.length; i < ii; i++) { str.push('<a href="' + nconf.get('relative_path') + '/user/' + usersData[i].userslug + '">' + usersData[i].username + '</a>'); } return str.join(', '); } Widget.updateAndGetOnlineUsers = function (callback) { callback = typeof callback === 'function' ? callback : function () {}; async.waterfall([ function (next) { next(null, socketRooms.getLocalStats().onlineRegisteredCount); }, function (onlineCount, next) { socketRooms.getTotalGuestCount(function (err, guestCount) { if (err) { return next(err); } next(null, { onlineCount: parseInt(onlineCount, 10), guestCount: parseInt(guestCount, 10), }); }); }, function (users, next) { db.getObjectFields('plugin:widget-board-stats', ['total', 'timestamp'], function (err, data) { if (err) { return next(err); } var totalUsers = users.onlineCount + users.guestCount; data.timestamp = data.timestamp || Date.now(); if (parseInt(data.total || 0, 10) <= totalUsers) { data.timestamp = Date.now(); data.total = totalUsers; db.setObject('plugin:widget-board-stats', data); } data.onlineCount = users.onlineCount; data.guestCount = users.guestCount; return next(null, data); }); }, ], callback); }; Widget.renderWidget = function (widget, callback) { getWidgetData(function (err, data) { if (err) { return callback(err); } app.render('widgets/board-stats', data, function (err, html) { if (err) { return callback(err); } widget.html = html; callback(null, widget); }); }); }; Widget.defineWidgets = function (widgets, callback) { var widget = { widget: 'board-stats', name: 'Board Stats', description: 'Classical board stats widget in real-time.', content: 'admin/board-stats', }; app.render(widget.content, {}, function (err, html) { widget.content = html; widgets.push(widget); callback(err, widgets); }); };

    which corresponds with our localized version of /var/www/nodebb/node_modules/nodebb-widget-board-stats/public/templates/widgets/board-stats.tpl

    <div component="widget/board-stats" class="widget-board-stats" style="border: 1px solid #999"> <h3 style="background: #666; font-size: 15px; font-weight: 500">Folgende Nutzende sind gerade online: <a href="{config.relative_path}/users?section=online">[komplette Liste]</a></h3> <p> Davon sind aktuell <strong component="widget/board-stats/count">{count}</strong> Nutzende aktiv (<strong component="widget/board-stats/members">{members}</strong> Registrierte + <strong component="widget/board-stats/guests">{guests}</strong>G&auml;ste).<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/list">{list}</span> <span style="display: block; line-height: 0.5em" >&nbsp;</span> In den letzten 24 Stunden waren <strong component="widget/board-stats/within24h">{within24h}</strong> verschiedene Nutzende eingeloggt. </p> <h3 style="background: #666; font-size: 15px; font-weight: 500">Forum-Statistik</h3> <p> Unsere aktiven registrierten Mitglieder haben <strong component="widget/board-stats/posts">{posts}</strong> Beitr&auml;ge zu <strong component="widget/board-stats/topics">{topics}</strong> Themen verfasst &ndash;<strong component="widget/board-stats/registered">{registered}</strong> Mitglieder sind bei <em>schoenen-dunk.de</em> registriert.<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/latest">{latest}</span> ist unser neuestes Mitglied.&nbsp;Herzlich Willkommen!<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> Am {mostUsers.date} waren <strong>{mostUsers.total}</strong> Nutzende gleichzeitig online. </p> </div>

    well.  i hope this helps a bit.

    ober!schöne grüße,
    m.

  • 0 Votes
    1 Posts
    92 Views
    R

    As title, But its work on dev mode. how could I solve the problem.

  • 0 Votes
    5 Posts
    800 Views
    呆呆笨笨

    可以参考 https://nomad.justdoless.cn

  • 0 Votes
    5 Posts
    882 Views
    呆呆笨笨

    可以参考 nomad.justdoless.cn

  • 11 Votes
    74 Posts
    16k Views
    phenomlabP

    @baris thanks for this. Really appreciated. We'll wait for 3.2.0 to drop.