Markdown Reader
Beamreactor Widgets Guide
BeamReactor Widgets - Quick Reference #
Definition #
Widget = raw HTML/CSS/JS output, NO BeamReactor UI wrapping (no headers/footers/menus)
Widgets are Plugin Sub-Elements #
A widget is not a standalone entity. It is a sub-element of its parent plugin,
and lives inside the plugin's widget/ subdirectory:
plugins/pluginname/
pluginname.php # main plugin file
conf/pluginname.conf.inc.php
lib/pluginname.lib.inc.php
locale/pluginname.fr.inc.php
widget/
pluginname.widget.php # widget entry point
The widget entry point delegates to the plugin's main file using a sentinel value:
<?php
$_saved_obj = $obj;
$obj = 'widget';
include_once('plugins/pluginname/pluginname.php');
$obj = $_saved_obj;
The plugin's main file adapts its output based on $obj:
if($obj == 'pluginname.php') frameheader($dialplugindisplay);
// when $obj == 'widget': render bare output, no shell
Existing Widgets Without a Parent Plugin #
Some widgets in the codebase (automated_bans, general_latency, general_performance, etc.)
currently live in the old top-level widgets/ directory and have no parent plugin.
Two valid approaches for these:
Option A — Absorb into a related plugin
If the widget is a display face for data owned by an existing plugin (e.g. blogs_tagcloud
belongs conceptually to blogs), move it into that plugin's widget/ subdirectory.
Option B — Create a widget-only plugin
If the widget has no natural parent, create a minimal plugin that acts as its host:
plugins/general_latency/
conf/general_latency.conf.inc.php
widget/
general_latency.widget.php # self-contained, no main plugin file needed
The plugin exists solely to own the widget's conf and provide a clean namespace.
No pluginname.php is required if there is no full-UI mode.
The top-level widgets/ directory has no place in the new architecture.
Use Cases #
- Embed in external sites (iframe/fetch)
- Data syndication ("share our content")
- Internal components (xdpplugin:// links in DTA docs)
- Embedding a plugin's functionality inside a page without the BeamReactor shell
Rules #
FORBIDDEN:
<html>,<head>,<body>tags- Headers, footers, navigation
- Hardcoded colors (use CSS vars only:
var(--primary, #fallback)) - Global JS variables
- Parent DOM manipulation
REQUIRED:
- Scope CSS to unique class (
.widget-name) - IIFE wrapper for JS
- All calls via XDP (never direct include)
- Sanitize all params
Why XDP? #
Security, stats, cache, audit, revocation = data sovereignty
Example Widget Code #
<?php
$slug = $_GET['slug'] ?? 'default';
$items = SQL::query("SELECT * FROM faq WHERE slug=?", [$slug], ['string']);
?>
<div class="faq-widget">
<?php foreach($items as $item): ?>
<div class="faq-item"><?= htmlspecialchars($item['text']) ?></div>
<?php endforeach; ?>
</div>
<style>
.faq-widget { color: var(--text, #333); }
</style>
<script>(function(){ /* scoped code */ })();</script>
Usage #
Embedded in a PHP page/doc:
<?php include(ROOT_DIR.'/plugins/pluginname/pluginname.php'); ?>
Via HTTP (no BeamReactor shell):
index.php?obj=pluginname.widget
External (third-party sites):
<iframe src="https://site.com/index.php?obj=widgetname.widget¶m=val"></iframe>
<!-- OR via fetch -->
<div id="target"></div>
<script>
fetch('https://site.com/index.php?obj=widgetname.widget¶m=val')
.then(r => r.text())
.then(html => document.getElementById('target').innerHTML = html);
</script>
Best Practices #
✅ Semantic HTML, scoped CSS, validated params, fallback content
❌ Global vars, hardcoded styles, direct file access, parent manipulation