This guide assumes intermediate PHP knowledge. If you do not know PHP and want to make NamelessMC modules, we highly recommend you learn the basics first - rather than jumping right into this.
Below is an example of how most NamelessMC modules are laid out in terms of files, not including any extra folders (Such as classes/
) you may use for your own organization.
- modules/
- DemoModule/
- init.php
- module.php
- hooks/
- <hook classes>
- includes/
- admin_widgets/
- <widget settings files>
- endpoints/
- <EndpointBase classes>
- pages/
- <frontend page files>
- panel/
- <StaffCP page files>
- widgets/
- <WidgetBase classes>
- custom/
- templates/
- DefaultRevamp/
- DemoModule/
- <frontend Smarty files>
All modules require at least one file to work, named init.php
.
This file must be placed in modules/<your module name>/init.php
.
Each time a page loads, NamelessMC will detect this file and execute the code inside of it automatically.
It is recommended to separate your init.php
file and your module's main class, most people make the main class in a file called module.php
.
In your init.php
file, you must create a new instance of your module's main class, which must extend the Module
class.
<?php
// Demo module by Aberdeener
// init.php file
require_once ROOT_PATH . '/modules/DemoModule/module.php';
$module = new Demo_Module();
<?php
// Demo module by Aberdeener
// module.php file
class Demo_Module extends Module {
public function __construct() {
$name = 'Demo Module';
$author = 'Aberdeener';
$module_version = '0.0.1';
$nameless_version = '2.0.0-pr13';
parent::__construct($this, $name, $author, $module_version, $nameless_version);
}
public function onInstall() {}
public function onUninstall() {}
public function onEnable() {}
public function onDisable() {}
public function onPageLoad($user, $pages, $cache, $smarty, $navs, $widgets, $template) {}
public function getDebugInfo(): array {
return [];
}
}
You will notice that when your module's main class extends the Module
class, it is required to have some functions in it.
These functions are as follow:
onInstall();
onUninstall();
onEnable();
onDisable();
onPageLoad();
getDebugInfo();
Their names are fairly understandable, they will each be called when that action happens.
Obviously, most of your module's core code will be in the onPageLoad();
function, as that is called every time a page is loaded.
In your module's constructor, this is where you will want to:
onPageLoad();
function (Endpoints, Queries, etc)In the onPageLoad();
function, you will want to:
Util::loadEndpoints($path, $endpoints);
function in the Util
class)More detail about your module's constructor:
Module
class, and pass:
$this
)2.0.0-prX
where X
is the pre-release number), this is used to warn users if they have modules which may not work with their version of NamelessMC.More detail about the onPageLoad();
function:
$user
the currently logged in user.$pages
instance of Pages
class - same one you used to add pages in the constructor.$cache
instance of the Cache
class. See the Cache
section below for more information.$smarty
instance of the Smarty template engine - usually not touched or used by modules.$navs
array of instances of the Navigation
class. See the Navigation
section below for more information.$widgets
instance of Widgets
class. See the Widgets
section below for more information.$template
instance of template main class which extends TemplateBase
. Rarely used, defaults to null
. Used more by pages than modules.Note: All of these classes are located in /core/classes/
under the exact same name if you would like to learn more about them, as not all of their functions are listed here.
Queries
Most functions in this class are deprecated, you should use the DB class directly.
DB
class to get and set data in the NamelessMC database.update($table, $id, $fields);
getWhere($table, $where);
DB
getInstance();
insert($table, $fields);
$table
using $fields
as a column => value
map.$fields
must be an array in the following format:// Column name => value
$fields = array(
'wiki_title' => 'First Wiki Article!',
'wiki_content' => 'Greetings, everyone!',
'wiki_author' => $user->data()->id
);
Cache
setCache($name);
$cache
file. Useful for organizing data into different files, rather than one file for all information.isCached($key);
$key
is cached in the current file (whatever was last set as the cache via setCache($name);
).retrieve($key);
$key
in the current cache file, or null
if it does not exist.store($key, $value, $expiration = 0);
$value
object with the key $key
and sets it to expire in $expiration
seconds in the current cache file.$expiration
is not provided, it will never expire.Pages
add($module, $url, $file, $name = '', $widgets = false);
$module
($module
is the name of your module, not an instance of it), with path of $url
, and the file $file
($file
is a path to the PHP file which will be executed when a user visits your page).$name
is optional, but recommended so your page can be recognized easier in lists of pages.$widgets
is a boolean value whether Widgets
can be present/enabled on this page.Navigation
onPageLoad();
as an array of $navs
, this let's your module add links to pages to navigation sections.$navs[0]
top navigation bar on frontend.$navs[1]
user dropdown on frontend.$navs[2]
StaffCP nav sidebar.add($name, $title, $link, $location = 'top', $target = null, $order = 10, $icon = '');
Language
get($file, $term);
$term
in the specified language file $file
.$term
is not in the $file
, it will try to find it in the EnglishUK file (as this is the default language used by NamelessMC developers. If it is not in the EnglishUK file, it will return "Term $term not set"
.set($file, $term, $value);
$term
in $file
to $value
.Widgets
add($widget);
$widget
to the widget system.$widget
must be an instance of a class which extends the WidgetBase
class.getPages($name);
$name
is enabled on.Endpoints
add($endpoint);
$widgets->add($widget);
, $endpoint
must be an instance of a class which extends EndpointBase
.handle($request, $api);
EndpointBase
thats route matches $request
(Example request/route: userInfo
), and execute()
s it, passing $api
for an easily accessible instance of the v2 API class Nameless2API
.PermissionHandler
registerPermissions($section, $permissions);
$section
section. $section
is used to separate permissions into different groups in StaffCP. Feel free to make $section
the name of your module, or set it to $language->get('moderator', 'staff_cp')
so your permissions fit in with all default permissions.$permissions
must be an array in the following format:// Permission value => Friendly title
$permissions = array(
'demo_module.add_user' => 'Add user',
'demo_module.delete_user' => 'Delete user'
);
User
$user
.data();
nl2_users
with the id
of the current $user
.$user->data()->username
hasPermission($permission);
$user
has the $permission
.HookHandler
registerEvent($event, $description, $params = array());
$event
with description $description
and params as $params
.$params
is defined, it must be an array in the following format:// Param name => Param description
$params = array(
'user_id' => 'ID of the user to ban.',
'reason' => 'Reason to display to banned user.'
);
registerHook($event, $hook);
$event
(created in registerEvent();
function).$hook
must be a string in the following format (as per call_user_func requirements):
ClassName::staticMethod
executeEvent($event, $params = null);
$event
, and passes $params
as parameters to the function.Util
loadEndpoints($path, $endpoints);
$path
must be a string which directly points to a folder where your module's endpoints are located.$endpoints
is the global instance of the Endpoints
class<?php
// Demo module by Aberdeener
// module.php file
class Demo_Module extends Module {
protected
$_language,
$_queries;
public function __construct($language, $queries) {
$name = 'Demo Module';
$author = 'Aberdeener';
$module_version = '0.0.2';
$nameless_version = '2.0.0-pr13';
parent::__construct($this, $name, $author, $module_version, $nameless_version);
$this->_language = $language;
$this->_queries = $queries;
}
public function onInstall() {
$queries = $this->_queries;
if (!count($queries->tableExists('wiki_articles'))) {
$queries->createTable('wiki_articles', "`id` INT(11) NOT NULL AUTO_INCREMENT, `content` VARCHAR(102) NOT NULL, `user_id` INT(11) NOT NULL", "");
}
if (!count($queries->tableExists('wiki_user_stats'))) {
$queries->createTable('wiki_user_stats', "`id` INT(11) NOT NULL AUTO_INCREMENT, `user_id` INT(11) NOT NULL, `wiki_articles` INT(11) NOT NULL", "");
}
}
public function onUninstall() {}
public function onEnable() {}
public function onDisable() {}
public onPageLoad($user, $pages, $cache, $smarty, $navs, $widgets, $template) {
PermissionHandler::registerPermissions('Demo Module', array(
'demo_module.view_wiki' => 'View the wiki',
'demo_module.create_wiki_page' => 'Create wiki page',
'demo_module.delete_wiki_page' => 'Delete wiki page',
));
$pages->add('Demo Module', '/wiki', 'pages/wiki.php');
$pages->add('Demo Module', '/panel/wiki', 'pages/panel/wiki.php');
$cache->setCache('navbar_order');
if(!$cache->isCached('wiki_order')) {
$order = 3;
$cache->store('wiki_order', $order);
} else {
$order = $cache->retrieve('wiki_order');
}
$cache->setCache('navbar_icons');
if(!$cache->isCached('wiki_icon')) {
$icon = 'fa fas-book';
$cache->store('wiki_order', $icon);
} else {
$icon = $cache->retrieve('wiki_icon');
}
$language = $this->_language;
// Add a page to the top navigation bar
$navs[0]->add('wiki', $language->get('wiki', 'wiki'), URL::build('/wiki'), 'top', null, $order, $icon);
if ($user->hasPermission('demo_module.create_wiki_page')) {
// Add page to StaffCP side panel
$navs[2]->add('create_wiki', $language->get('wiki', 'create_wiki'), URL::build('/wiki/create'));
}
require_once ROOT_PATH . '/modules/DemoModule/widgets/DemoWidget.php';
$widget_pages = $widgets->getPages('Demo Widget');
$demo_widget = new Demo_Widget($widget_pages);
$widgets->add($demo_widget);
$queries = $this->_queries;
$wiki_article_count = count($queries->getWhere('wiki_articles', array('user_id', '=', $user->data()->id)));
$fields = array(
'user_id' => $user->data()->id,
'wiki_articles' => $wiki_article_count
);
DB::getInstance()->insert('wiki_user_stats', $fields);
}
public function getDebugInfo(): array {
return [];
}
}
if (defined('FRONT_END'))
if (defined('BACK_END'))
Pages
class to create all of the StaffCP pages you'd like in your module's constructorNavigation
class to add your pages to the StaffCP navigation sidebar ($mod_nav
/$nav[2]
)