Skip to content

Commit f515191

Browse files
committed
1.0.0-beta.14
1 parent 53e5d32 commit f515191

6 files changed

Lines changed: 210 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1+
12
# Changelog
23

34
Dieses Changelog wird ab Version `1.0.0` neu geführt.
45

6+
## 1.0.0-beta.14 (08. Mai 2026)
7+
8+
**Neu:**
9+
- Legacy Meta-Integration: Meta-/SEO-Tags können jetzt zentral im Backend gepflegt werden (Seite "Legacy Meta Integration").
10+
- Sichere Validierung: Nur reine Meta-Tags und statisches HTML erlaubt, PHP/JS/Event-Handler werden blockiert.
11+
- Frontend-Ausgabe: Die gepflegten Meta-Tags werden im HTML-Head nach dem letzten <meta> Tag (Fallback: vor </head>) ausgegeben – nur in aktivierten Templates.
12+
- Ausgabe erfolgt über OUTPUT_FILTER Extension Point, Template-Check wie bei JSON-LD.
13+
- README.md um Abschnitt "Legacy Meta-Integration" erweitert.
14+
- Versionsnummer auf 1.0.0-beta.14 erhöht.
15+
16+
**Technik:**
17+
- Keine bestehenden Funktionen oder Ausgaben des AddOns beeinträchtigt.
18+
19+
**Hinweis:**
20+
- Die Funktion richtet sich an Entwickler/Redakteure, die alte SEO-/Meta-Tags übernehmen oder spezielle Meta-Informationen ergänzen möchten.
21+
522
## 1.0.0-beta.13 (07. Mai 2026)
623

724
**Artikel / LocalBusiness:**

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,28 @@ Das ist optional und nicht nötig, um die normale JSON-LD-Ausgabe für Website u
116116
- Branch-spezifische LocalBusiness-Daten pro Sprache
117117
- Ausgabe bereinigt leere Werte rekursiv (nur befüllte JSON-LD Felder)
118118

119-
## Mehrsprachigkeit
119+
120+
121+
122+
## Legacy Meta-Integration
123+
124+
Mit der Funktion **Legacy Meta-Integration** können alte oder zusätzliche Meta-/SEO-Tags zentral im Backend gepflegt werden. Diese werden – zusätzlich zur JSON-LD-Ausgabe – im HTML-Head nach dem letzten vorhandenen <meta> Tag ausgegeben (nur in den unter Einstellungen aktivierten Templates).
125+
126+
**Sicherheit:**
127+
- Es sind ausschließlich reine Meta-Tags und statisches HTML erlaubt. PHP, JavaScript, Event-Handler und unsichere Tags werden automatisch blockiert.
128+
- Die Eingabe erfolgt über ein eigenes Backend-Formular mit Validierung und CSRF-Schutz.
129+
130+
**Funktionsweise:**
131+
- Die gepflegten Meta-Tags werden im Frontend-Head nach dem letzten <meta> Tag eingefügt (Fallback: vor </head>).
132+
- Die Ausgabe erfolgt nur in Templates, die in den AddOn-Einstellungen aktiviert wurden.
133+
- Die Daten werden zentral in der REDAXO-Konfiguration gespeichert.
134+
135+
**Typische Anwendungsfälle:**
136+
- Migration alter SEO-/Meta-Tags aus früheren Systemen
137+
- Ergänzung spezieller Meta-Informationen, die nicht über REDAXO-Metainfo gepflegt werden
138+
139+
**Hinweis:**
140+
Die Funktion richtet sich an Entwickler und Redakteure, die volle Kontrolle über die Meta-Ausgabe benötigen, ohne die Templates direkt anpassen zu müssen.
120141

121142
Das AddOn ist auf Mehrsprachigkeit ausgelegt:
122143

boot.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@
5252
// Dynamisches URL-JSON-LD zusätzlich anhängen (falls vorhanden)
5353
$jsonLdOutput .= $dynamicJsonLdOutput;
5454

55+
// Legacy-Meta-Daten ausgeben (nach letztem <meta ...> im <head>)
56+
$legacyMeta = trim(rex_config::get('jsonld_manager', 'legacy_meta_raw', ''));
57+
if ($legacyMeta !== '') {
58+
// Nur ausgeben, wenn Template erlaubt ist (wie bei JSON-LD)
59+
if (function_exists('jsonld_is_template_output_allowed') && jsonld_is_template_output_allowed($article)) {
60+
// Suche alle <meta ...> im <head>
61+
$headStart = stripos($content, '<head');
62+
$headEnd = stripos($content, '</head>');
63+
if ($headStart !== false && $headEnd !== false && $headEnd > $headStart) {
64+
$headContent = substr($content, $headStart, $headEnd - $headStart);
65+
// Finde alle <meta ...> Tags
66+
preg_match_all('/<meta[^>]*>/i', $headContent, $metaMatches, PREG_OFFSET_CAPTURE);
67+
if (!empty($metaMatches[0])) {
68+
$lastMeta = end($metaMatches[0]);
69+
$insertPos = $headStart + $lastMeta[1] + strlen($lastMeta[0]);
70+
$content = substr($content, 0, $insertPos) . "\n" . $legacyMeta . "\n" . substr($content, $insertPos);
71+
} else {
72+
// Kein <meta> gefunden, vor </head> einfügen
73+
$content = str_replace('</head>', $legacyMeta . "\n</head>", $content);
74+
}
75+
} else {
76+
// Kein <head> gefunden, vor </head> einfügen
77+
$content = str_replace('</head>', $legacyMeta . "\n</head>", $content);
78+
}
79+
}
80+
}
5581
if (!empty($jsonLdOutput)) {
5682
$content = str_replace('</head>', $jsonLdOutput . '</head>', $content);
5783
}

package.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package: jsonld_manager
2-
version: '1.0.0-beta.13'
2+
version: '1.0.0-beta.14'
33
author: 'Friends Of REDAXO'
44
supportpage: https://github.com/FriendsOfREDAXO/jsonld_manager
55

@@ -27,7 +27,7 @@ page:
2727
title: LocalBusiness Schema
2828
subPath: pages/global_localbusiness.php
2929
info:
30-
title: 'Info'
30+
title: Info
3131
itemclass: pull-right
3232
subpages:
3333
help:
@@ -42,7 +42,13 @@ page:
4242
settings:
4343
title: Einstellungen
4444
itemclass: pull-right
45-
subPath: pages/settings.php
45+
subpages:
46+
setting:
47+
title: Einstellungen
48+
subPath: pages/settings.php
49+
legacy-integration:
50+
title: Legacy Meta Integration
51+
subPath: pages/setting_legacy_meta_integration.php
4652

4753
requires:
4854
php: '>=8.3'
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
/**
3+
* JSON-LD Manager - Legacy Meta Integration
4+
*
5+
* Integration alter Meta-/SEO-Daten (z.B. aus Metainfo, alten AddOns, etc.)
6+
*
7+
* @package JsonldManager
8+
*/
9+
10+
$csrfToken = rex_csrf_token::factory('jsonld_manager_legacy_meta');
11+
$csrfTokenField = $csrfToken->getHiddenField();
12+
13+
$func = rex_request('func', 'string', '');
14+
15+
// Verarbeitung (optional: hier kann später Logik ergänzt werden)
16+
if ($func === 'save_legacy_meta') {
17+
if (!$csrfToken->isValid()) {
18+
echo rex_view::error('Sicherheitsprüfung fehlgeschlagen (CSRF). Bitte Seite neu laden.');
19+
} else {
20+
$legacyMeta = rex_post('legacy_meta', 'string', '');
21+
// Prüfung auf "bösen" Code, aber Meta-Tags sind immer erlaubt
22+
$metaTagPattern = '/^\s*<meta\s/i';
23+
$lines = preg_split('/\r?\n/', $legacyMeta);
24+
$badFound = false;
25+
foreach ($lines as $line) {
26+
$trimmed = trim($line);
27+
if ($trimmed === '' || preg_match($metaTagPattern, $trimmed)) {
28+
continue; // Meta-Tags und leere Zeilen immer erlauben
29+
}
30+
$badPatterns = [
31+
'/<\s*\?(php)?/i', // PHP-Tags
32+
'/<\s*script/i', // JS-Script-Tag
33+
'/javascript:/i', // JS-URI
34+
'/(<|\s)on[a-z]+\s*=/i', // Event-Handler wie onclick, onload (nur als Attribut)
35+
'/<\s*iframe/i', // iframe
36+
'/<\s*object/i', // object
37+
'/<\s*embed/i', // embed
38+
'/<\s*applet/i', // applet
39+
];
40+
foreach ($badPatterns as $pattern) {
41+
if (preg_match($pattern, $trimmed)) {
42+
$badFound = true;
43+
break 2;
44+
}
45+
}
46+
}
47+
if ($badFound) {
48+
echo rex_view::error('Dein Eintrag enthält unerlaubten Code (PHP, JavaScript, Event-Handler oder unsichere HTML-Tags). Bitte nur reine Meta-Tags oder statisches HTML verwenden!');
49+
} else {
50+
rex_config::set('jsonld_manager', 'legacy_meta_raw', $legacyMeta);
51+
echo rex_view::success('Legacy Meta-Daten wurden gespeichert.');
52+
}
53+
}
54+
}
55+
56+
// Vorbelegung aus Config
57+
$legacyMeta = rex_config::get('jsonld_manager', 'legacy_meta_raw', '');
58+
59+
60+
ob_start();
61+
?>
62+
<form method="post" action="" id="jsonld-legacy-meta-form">
63+
<div class="row">
64+
<div class="col-md-7">
65+
<input type="hidden" name="func" value="save_legacy_meta">
66+
<?= $csrfTokenField ?>
67+
<div class="panel panel-primary">
68+
<header class="panel-heading">
69+
<h1 class="panel-title">Legacy Meta-Daten</h1>
70+
</header>
71+
<div class="panel-body">
72+
<textarea name="legacy_meta" class="form-control" rows="18" style="font-family:monospace; min-height:350px;" placeholder="Hier können alte Meta-/SEO-Daten eingefügt werden..."><?= htmlspecialchars($legacyMeta) ?></textarea>
73+
</div>
74+
</div>
75+
</div>
76+
<div class="col-md-5">
77+
<div class="panel panel-info">
78+
<header class="panel-heading">
79+
<h1 class="panel-title">Info & Hinweise</h1>
80+
</header>
81+
<div class="panel-body">
82+
<p>
83+
<strong>Legacy Meta-Integration:</strong><br>
84+
Hier kannst du weitere Meta-Informationen eintragen. Diese werden in den zugewiesenen Templates für die JSON-LD-Ausgabe nach dem letzten im Quellcode gefundenen Meta-Tag ausgegeben.<br><br>
85+
An dieser Stelle ist keine Verwendung von PHP oder JavaScript möglich, da die Daten direkt in den HTML-Head ausgegeben werden. Es können also nur reine HTML-Meta-Tags oder andere statische HTML-Elemente verwendet werden.<br><br>
86+
<hr>
87+
<em>Hinweis:</em> Diese Funktion ist ein Hilfswerkzeug für Entwickler und Redakteure, die alte SEO-/Meta-Daten übernehmen möchten.
88+
</p>
89+
</div>
90+
</div>
91+
</div>
92+
</div>
93+
<div class="rex-form-panel-footer" style="padding: 12px; background: rgba(0,0,0,.28); border-top: 1px solid rgba(255,255,255,.08); display: flex; justify-content: flex-end; align-items: center;">
94+
<button type="submit" class="btn btn-apply" form="jsonld-legacy-meta-form">Speichern</button>
95+
</div>
96+
</form>
97+
<?php
98+
$content = ob_get_clean();
99+
$fragment = new rex_fragment();
100+
$fragment->setVar('title', 'Legacy Meta Integration', false);
101+
$fragment->setVar('body', $content, false);
102+
echo $fragment->parse('core/page/section.php');

pages/settings.php

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,19 @@
124124
ob_start();
125125
?>
126126

127-
<div class="row">
128-
<div class="col-md-6">
129-
130-
<form method="post" action="" class="form-horizontal" id="jsonld-settings-form">
127+
128+
<form method="post" action="" class="form-horizontal" id="jsonld-settings-form">
129+
<div class="row">
130+
<div class="col-md-6">
131131
<input type="hidden" name="func" value="update_settings">
132132
<input type="hidden" name="domain_id" value="<?= $activeDomainId ?>">
133133
<?= $csrfTokenField ?>
134-
135134
<!-- Grundeinstellungen Panel -->
136135
<div class="panel panel-primary">
137136
<header class="panel-heading">
138137
<h1 class="panel-title">Grundeinstellungen</h1>
139138
</header>
140139
<div class="panel-body">
141-
142140
<div class="form-group">
143141
<label class="col-sm-4 control-label">Automatische Ausgabe</label>
144142
<div class="col-sm-8">
@@ -151,7 +149,6 @@
151149
<small class="help-block">Wenn aktiviert, wird JSON-LD automatisch über Extension Points in das Template eingebunden.</small>
152150
</div>
153151
</div>
154-
155152
<div class="form-group">
156153
<label class="col-sm-4 control-label">Performance</label>
157154
<div class="col-sm-8">
@@ -162,7 +159,6 @@
162159
</label>
163160
</div>
164161
<small class="help-block">Verbessert die Performance durch Zwischenspeicherung der generierten JSON-LD Strukturen.</small>
165-
166162
<!-- Cache löschen Button -->
167163
<div style="margin-top: 10px;">
168164
<a href="<?= rex_url::currentBackendPage(['func' => 'clear_cache'] + $csrfToken->getUrlParams()) ?>"
@@ -173,7 +169,6 @@ class="btn btn-primary btn-sm"
173169
</div>
174170
</div>
175171
</div>
176-
177172
<div class="form-group">
178173
<label class="col-sm-4 control-label">Validierung</label>
179174
<div class="col-sm-8">
@@ -186,7 +181,6 @@ class="btn btn-primary btn-sm"
186181
<small class="help-block">Validiert JSON-LD vor der Ausgabe und zertifiziert Syntax-Konformität.</small>
187182
</div>
188183
</div>
189-
190184
<div class="form-group">
191185
<label class="col-sm-4 control-label">Debug-Modus</label>
192186
<div class="col-sm-8">
@@ -199,56 +193,44 @@ class="btn btn-primary btn-sm"
199193
<small class="help-block">Wenn aktiviert, werden detaillierte Debug-Ausgaben als JSON-LD Overlay im Frontend angezeigt.</small>
200194
</div>
201195
</div>
202-
203196
</div>
204197
</div>
205-
206-
</div>
207-
208-
<div class="col-md-6">
209-
210-
<!-- Domain-Auswahl (nur bei Multi-Domain) -->
211-
<?php if (DomainConfig::isMultiDomain()): ?>
212-
<div class="panel panel-info">
213-
<header class="panel-heading">
214-
<h1 class="panel-title">Domain-Konfiguration</h1>
215-
</header>
216-
<div class="panel-body">
217-
<?= DomainConfig::renderDomainSelect($activeDomainId) ?>
218-
<p class="help-block">Wählen Sie die Domain aus, für die Sie die Einstellungen konfigurieren möchten. Jede Domain wird separat verwaltet.</p>
219-
</div>
220198
</div>
221-
<?php endif; ?>
222-
223-
<!-- Template-Integration Panel -->
224-
<div class="panel panel-default">
225-
<header class="panel-heading">
226-
<h1 class="panel-title">Template-Integration</h1>
227-
</header>
228-
<div class="panel-body">
229-
230-
<div class="form-group">
231-
<label class="col-sm-12 control-label">Templates für JSON-LD</label>
232-
<div class="col-sm-12">
233-
<select multiple name="template_ids[]" class="form-control selectpicker" data-live-search="true" data-size="10" size="8" id="jsonld-template-select">
234-
<?= $templateOptions ?>
235-
</select>
236-
<small class="help-block">Wählen Sie die Templates aus, in denen JSON-LD automatisch ausgegeben werden soll.</small>
199+
<div class="col-md-6">
200+
<!-- Domain-Auswahl (nur bei Multi-Domain) -->
201+
<?php if (DomainConfig::isMultiDomain()): ?>
202+
<div class="panel panel-info">
203+
<header class="panel-heading">
204+
<h1 class="panel-title">Domain-Konfiguration</h1>
205+
</header>
206+
<div class="panel-body">
207+
<?= DomainConfig::renderDomainSelect($activeDomainId) ?>
208+
<p class="help-block">Wählen Sie die Domain aus, für die Sie die Einstellungen konfigurieren möchten. Jede Domain wird separat verwaltet.</p>
209+
</div>
210+
</div>
211+
<?php endif; ?>
212+
<!-- Template-Integration Panel -->
213+
<div class="panel panel-default">
214+
<header class="panel-heading">
215+
<h1 class="panel-title">Template-Integration</h1>
216+
</header>
217+
<div class="panel-body">
218+
<div class="form-group">
219+
<div class="col-sm-12">
220+
<label for="jsonld-template-select" class="control-label" style="font-weight:600; margin-bottom:8px;">Templates für JSON-LD</label>
221+
<select multiple name="template_ids[]" class="form-control selectpicker" data-live-search="true" data-size="10" size="8" id="jsonld-template-select" style="margin-bottom:8px;">
222+
<?= $templateOptions ?>
223+
</select>
224+
<small class="help-block">Wählen Sie die Templates aus, in denen JSON-LD automatisch ausgegeben werden soll.</small>
225+
</div>
237226
</div>
238227
</div>
239-
240228
</div>
241229
</div>
242-
243230
</div>
244-
</div>
245-
246-
<div class="panel-footer text-right">
247-
<button type="submit" class="btn btn-apply" form="jsonld-settings-form">
248-
Speichern
249-
</button>
250-
</div>
251-
231+
<div class="rex-form-panel-footer" style="padding: 12px; background: rgba(0,0,0,.28); border-top: 1px solid rgba(255,255,255,.08); display: flex; justify-content: flex-end; align-items: center;">
232+
<button type="submit" class="btn btn-apply" form="jsonld-settings-form">Speichern</button>
233+
</div>
252234
</form>
253235

254236
<?php

0 commit comments

Comments
 (0)