Skip to content
risingisland edited this page Mar 14, 2026 · 1 revision

Welcome to the Dashboard wiki!

Dashboard Module Development Guide

Modules are self-contained PHP files dropped into the plugins/Dashboard/modules/ folder. This guide covers everything needed to create one.


Table of Contents

  1. File Structure
  2. Required File Header
  3. Security Guard
  4. Unique ID Scoping
  5. JavaScript
  6. Localisation (i18n)
  7. Full Minimal Example
  8. Publishing to the Module Store
  9. Quick Checklist

1. File Structure

A minimal module is a single PHP file. A module with language support adds a subfolder:

plugins/Dashboard/modules/
    mymodule.php          ← required
    mymodule/             ← optional, for lang files
        lang/
            en_US.php
            es_ES.php
            .htaccess     ← recommended to protect lang folder

2. Required File Header

Every module must begin with a PHP docblock header:

<?php
/**
 * Module Name: My Module
 * Module ID:   mymodule
 * Description: A short description of what this module does.
 * Version:     1.0
 * Default W:   4
 * Default H:   2
 */
Field Type Required Description
Module Name string Yes Human-readable display name shown in the module list.
Module ID string Yes Unique identifier. Must match the filename without .php. Lowercase, no spaces.
Description string Yes Short description shown in the Module Store.
Version string Yes Semantic version number, e.g. 1.0 or 2.1.3.
Default W int Yes Default grid column width (1–12). 12 = full width.
Default H int Yes Default grid row height.

3. Security Guard

Immediately after the header, add the IN_GS guard. This prevents the file from being accessed directly via URL:

if (!defined('IN_GS')) { die('You cannot load this page directly.'); }

4. Unique ID Scoping

Because multiple modules share the same page, CSS classes and element IDs can clash. Generate a unique ID prefix based on the module's file path:

$uid = 'mod_' . substr(md5(__FILE__), 0, 6);

Use this prefix throughout the module:

// CSS — scope all rules to the unique wrapper ID
#<?php echo $uid ?> .my-class { color: red; }

// HTML — apply uid as the outer wrapper's id
<div id="<?php echo $uid ?>">

// HTML — suffix element IDs to avoid clashes
<div id="<?php echo $uid ?>-chart">

// JavaScript — look up elements by scoped ID
document.getElementById("<?php echo $uid ?>-chart");

Note

Never use the Module ID as a DOM id. GridStack sets id="[ModuleID]" on the outer grid wrapper — reusing it will overwrite that element.


5. JavaScript

Modules are injected into the page after load, so DOMContentLoaded has already fired and will never trigger. Run code immediately or use setInterval.

Wrap all JavaScript in an IIFE to prevent global variable leakage:

<script>
(function() {

    var el = document.getElementById("<?php echo $uid ?>-output");

    function render() {
        el.textContent = new Date().toLocaleTimeString();
    }

    render();
    setInterval(render, 1000);

})();
</script>

Warning

Never use DOMContentLoaded inside a module — it will not fire because modules load after the page is already ready.


6. Localisation (i18n)

Modules can ship their own language files. The Dashboard plugin provides a helper function that loads the lang file and returns a retrieval function.

6.1 Calling the helper

// At the top of your module, after the IN_GS guard:
$i18n_m = dash_module_i18n('mymodule');

Then use it anywhere in the module:

// In PHP expressions
$label = $i18n_m('lang_Title');

// Inline in HTML
<?php echo $i18n_m('lang_Title'); ?>

// Inside a PHP array
'label' => $i18n_m('lang_Pages'),

6.2 Lang file format

Place lang files at plugins/Dashboard/modules/mymodule/lang/{locale}.php. The filename must match the locale code set in GS site settings, e.g. en_US.php:

<?php
// plugins/Dashboard/modules/mymodule/lang/en_US.php

$i18n = [
    'lang_Title'   => 'My Module',
    'lang_Empty'   => 'No items found.',
    'lang_Edit'    => 'Edit',
];

Note

The lang/ folder is optional. If no lang file exists or the locale is not found, the helper falls back to en_US.php automatically.

6.3 Protecting the lang folder

Add a .htaccess file inside mymodule/lang/ to prevent direct web access:

# plugins/Dashboard/modules/mymodule/lang/.htaccess
deny from all

Note

The Module Installer preserves .htaccess files when extracting from a zip, so this will be correctly installed alongside the lang files.


7. Full Minimal Example

<?php
/**
 * Module Name: Hello World
 * Module ID:   helloworld
 * Description: A minimal example module.
 * Version:     1.0
 * Default W:   4
 * Default H:   2
 */

if (!defined('IN_GS')) { die('You cannot load this page directly.'); }

$i18n_m = dash_module_i18n('helloworld');
$uid    = 'hw_' . substr(md5(__FILE__), 0, 6);
?>

<style>
#<?php echo $uid ?> .hw-box {
    padding: 12px;
    background: #f9f9f9;
    border-radius: 6px;
    font-size: 14px;
}
</style>

<div id="<?php echo $uid ?>">
    <h3><?php echo $i18n_m('lang_Title'); ?></h3>
    <div class="hw-box">
        <?php echo $i18n_m('lang_Greeting'); ?>
    </div>
</div>

8. Publishing to the Module Store

Modules are listed in a remote JSON database. For your module to be installable, the repository must follow this structure:

your-repo/
    mymodule.php        ← module entry point with valid header
    mymodule/           ← optional subfolder
        lang/
            en_US.php
            .htaccess

The installer identifies valid modules by looking for the Module ID header in top-level .php files. All files belonging to the module subfolder are extracted automatically, including lang files and .htaccess.

Note

Only GitHub repository URLs are accepted by the installer for security reasons.


9. Quick Checklist

  • Header block with all required fields
  • IN_GS security guard
  • Unique ID: $uid = 'abc_' . substr(md5(__FILE__), 0, 6)
  • All CSS scoped to #uid wrapper
  • All element IDs prefixed with $uid
  • JavaScript wrapped in an IIFE
  • No DOMContentLoaded listeners
  • i18n: $i18n_m = dash_module_i18n('mymodule') (if using lang files)
  • Lang files in mymodule/lang/{locale}.php
  • .htaccess in lang/ folder to block direct access