En vous promenant sur Beamreactor, nous stockons votre IP 48h pour des raisons de sécurité.

Markdown-Reader

Wissensdatenbank › BeamReactor_Widgets_Guide

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&param=val"></iframe>

<!-- OR via fetch -->
<div id="target"></div>
<script>
fetch('https://site.com/index.php?obj=widgetname.widget&param=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

de en fr