Markdown-Reader
BEAMREACTOR_PLUGINS
BeamReactor – Plugin Development Documentation #
> Version: 1.0
> Audience: Plugin developers for the BeamReactor CMS
> Scope: Architecture, conventions, security rules, APIs, SQL, JS, i18n
---
1. Philosophy & Core Principles #
BeamReactor is a centralized CMS developed and maintained for more than 22 years.
Fundamental rules:
- No PHP script can ever be called directly. Everything goes through the XDP engine (`index.php`).
- Plugins are isolated, non-colliding, and auto-loaded.
- Predictability, security, and performance outweigh convenience.
Coding Conventions (Mandatory) #
- Allman indentation style
- Boolean logic uses `!!0` and `!!1`
- Strict typing for functions and methods whenever possible
- Prefer single quotes
- Avoid constant PHP context switching (performance cost)
- Always close PHP tags (`?>`) unless outputting raw text/HTML/JSON/JS
- Plugins must never use `exit()` or `die()`
- Only `return` / control flow
---
2. Plugin Packaging & Lifecycle #
Plugins are:
- Managed by the BeamReactor package manager
- Loaded automatically by the engine
- Designed so multiple plugins may coexist on the same page without conflict
Naming discipline is therefore critical.
---
3. Standard Plugin Directory Structure #
/plugins/myplugin/
├── myplugin.php
├── conf/
│ ├── myplugin.conf.inc.php
│ └── myplugin.sitemap.json
├── doc/
│ ├── myplugin.md
│ └── myplugin.help.json
├── lib/
│ └── myplugin.lib.inc.php
├── locale/
│ ├── myplugin.en.inc.php
│ ├── myplugin.fr.inc.php
│ └── myplugin.de.inc.php
├── handlers/
│ └── myplugin.mod.php
├── css/
│ └── myplugin.css
├── js/
│ └── myplugin.js
├── ui/
│ └── button.png
├── sql/
│ └── myplugin.sql
├── tests/
│ └── myplugin.test.php
└── data/
└── cache/
---
4. Auto-loading Behavior (Engine) #
When a plugin is called via:
index.php?obj=oneliner.php
The engine automatically loads:
- Configuration
- Library
- Locale
/plugins/oneliner/conf/oneliner.conf.inc.php
/plugins/oneliner/oneliner.lib.inc.php
getlocale('oneliner')
?>
⚠️ Manual includes are forbidden for configs and libs.
The only allowed include:
include_once(getlocale('nom_du_plugin'));
?>
---
5. Plugin Main File (`myplugin.php`) #
Every plugin must begin with the BeamReactor guard (the only exit allowed):
// Ceci vérifie que nous sommes bien en contexte BeamReactor.
// C'est le SEUL exit autorisé dans le code d'un plugin.
if(!function_exists('frameheader')) die('forbidden');
Then, standard pattern:
if($obj=='plugin.php') frameheader($dialplugindisplay);
Notes:
- Locale must be loaded before `frameheader()` to avoid missing variable errors
- `frameheader('title', $headingLevel='h3', $noheader=false)` structures the UI
- H1 = page title (one per page)
- H2 = main sections
- H3+ = frames/widgets
- `framefooter()` closes a frame; not needed at page bottom (auto-close)
- Do not use `ob_flush(); flush();` without a preceding `ob_start()`
---
6. Configuration File (`conf/*.conf.inc.php`) #
if(!function_exists('frameheader')) return;
$basedatadisplay = 'yes';
$basedisplevel = MYPLUGIN_LEVEL_HIGHUSER;
$ftype = 1;
$is_public = 0;
?>
Security Levels #
- Levels are constants only
- Never hardcode numeric values
Standard suffixes:
- `_LEVEL_USER`
- `_LEVEL_HIGHUSER`
- `_LEVEL_MODERATOR`
- `_LEVEL_ADMIN`
- `_LEVEL_OVERMIND`
---
7. Internationalization (Locale Files) #
Location:
/plugins/myplugin/locale/myplugin.fr.inc.php
Example:
if(!function_exists('frameheader')) return;
$dialplugindisplay = 'Fabrique de spaghetti';
$dialplugincall = 'Spaghettisation';
$dialspaghetti[1] = 'Suivez le spaghetti';
?>
---
8. Global Runtime Configuration (`$cfg`) #
$cfg[0] // Base URL
$cfg[1] // Site name
$cfg[3] // Skins path
$cfg[4] // Data path
$cfg[17] // Max upload size
$cfg['obj']
$cfg['request_method']
?>
Use `BEAM_BASE_URL` in JavaScript instead of `$cfg[0]`.
---
9. CSS Rules #
- Plugins rely on core.css
- Never invent colors
- If a style is missing → propose adding it to `core.css`
---
10. Modules / Handlers (`*.mod.php`) #
- Endpoints only (JSON / XML / text)
- No UI
- Called as:
?obj=myplugin.mod
❌ Forbidden:
?obj=plugins/myplugin/handlers/myplugin.mod.php
---
11. Toast System #
Levels:
DEBUG, INFO, SUCCESS, WARNING, ERROR, CRITICAL
Example:
$toastId = Toast::add(
Toast::LEVEL_WARNING,
'Sécurisez votre compte',
'Activez la 2FA',
BASE_LEVEL_USER
);
?>
Broadcast toasts are persistent and reserved for emergencies.
---
12. Sanitizer (Critical) #
Replaces:
- `filter_var`
- `intval`
- `cleanhtml`
Allowed datatypes:
`Bool, Date, Email, Name, HTML, XML, UUID, URL, String, IP, Float, Arithmetic, Path, PHPsession, ...`
Usage:
use Beamreactor\Sanitizer\Parser;
$email = Parser::sanitize($_POST['email'], 'email');
$page = Parser::sanitize($_GET['page'], 'int') ?: 1;
?>
---
13. SQL Layer #
Rules:
- Always sanitize before SQL
- Never concatenate
- Always check results
use Beamreactor\Database\SQL;
$users = SQL::query(
"SELECT * FROM users WHERE level >= ?",
[$level]
);
?>
If SQL fails → empty array, no exception.
---
14. JavaScript Integration #
Global:
BEAM_BASE_URL
Dialogs:
alertWindow('Title', 'Message');
confirmWindow('Title', 'Question', {}, callback);
Inject JS via PHP:
$headdata .= "<script>...</script>";
$footdata .= "doSomething();";
?>
---
15. JS Translations #
$js_translations = [
'plugin' => [
'reply' => $dialemail[16]
]
];
setJavascriptLocale($js_translations);
?>
---
16. WYSIWYG Editor Example #
initRTE("javascript/images/", "javascript/includes/", "", true, "<?php echo $uniqueid; ?>");
var rte1 = new richTextEditor("htmlfeed");
rte1.html = <?php echo json_encode($content); ?>;
rte1.width = 800;
rte1.height = 400;
rte1.build();
---
17. Final Hard Rules (Read Twice) #
- ❌ No `require`, `include`, `require_once` for plugin internals
- ❌ No exit/die except BeamReactor guard at top
- ❌ No direct file calls
- ✅ Locale before header
- ✅ Sanitizer before SQL
- ✅ One archive = one plugin
---
BeamReactor is not permissive by accident. It is strict by design.