- Darstellung des Mitteilungsblattes
- Erweiterte Leserechte („privat“) für Autoren
- Admin-Menüpunkt: Direkter Link zum internen Bereich
- Interne Links root-relativ
Darstellung des Mitteilungsblattes auf der Startseite
Diese Seite dokumentiert die technische Umsetzung der Anzeige des aktuellen Mitteilungsblattes auf der Startseite von fgsub.de.
Funktionsweise
- Auf der Seite
/der_verein/downloads/wird regelmäßig eine Liste neuer Mitteilungsblätter in Form einer unsortierten Liste (<ul>) gepflegt. - Die Startseite lädt per JavaScript den Inhalt dieser Seite und extrahiert die ersten
<li>-Einträge unterhalb der Überschrift<h4>Mitteilungsblatt des FGSUB</h4>. - Links neben dem Text wird ein statisches Deckblatt-Bild eingeblendet (
m-deckblatt.png, 250 px hoch). - So viele Listeneinträge wie in die Höhe von 250px passen, werden nebeneinander dargestellt. Falls ein Eintrag abgeschnitten werden muss, wird der letzte sichtbare mit
[...]beendet. - Darunter erscheint ein Hinweis-Link zur vollständigen Downloadseite.
Position im Theme
Die Datei mitteilungsblatt.php liegt im Verzeichnis wp-content/themes/live-wire-child/parts/ und wird z. B. per Shortcode auf der Startseite eingebunden.Mitteilungsblatt des FGSUB
Quelltext
<section id="mitteilungsblatt-startseite" class="box_grau">
<h4>Mitteilungsblatt des FGSUB</h4>
<div id="mitteilungsblatt-vorschau"></div>
</section>
<script>
document.addEventListener("DOMContentLoaded", function () {
fetch("/der_verein/downloads/")
.then((response) => response.text())
.then((html) => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const h4 = Array.from(doc.querySelectorAll("h4")).find((el) =>
el.textContent.includes("Mitteilungsblatt")
);
if (!h4) return;
const list = h4.nextElementSibling;
if (!list || list.tagName !== "UL") return;
const lis = Array.from(list.querySelectorAll("li"));
const container = document.getElementById("mitteilungsblatt-vorschau");
const block = document.createElement("div");
block.className = "mitteilungsblatt-block";
const image = document.createElement("img");
image.className = "mitteilungsblatt-bild";
image.src = "/wp-content/hp-data/m-deckblatt.png";
image.alt = "Mitteilungsblatt Deckblatt";
image.style.height = "250px";
block.appendChild(image);
const textWrapper = document.createElement("div");
textWrapper.className = "mitteilungsblatt-text";
textWrapper.style.fontSize = "0.9em";
const temp = document.createElement("div");
temp.style.position = "absolute";
temp.style.visibility = "hidden";
temp.style.width = "40em";
temp.style.fontSize = "0.9em";
temp.style.lineHeight = "1.4em";
temp.style.maxHeight = "250px";
temp.style.overflow = "hidden";
temp.style.display = "block";
document.body.appendChild(temp);
let collected = "";
let lastValid = "";
for (let i = 0; i < lis.length; i++) {
const next = collected + (collected ? '<br><br>' : '') + lis[i].innerHTML;
temp.innerHTML = next;
if (temp.scrollHeight > 250) {
collected = lastValid + " [...]";
break;
}
collected = next;
lastValid = collected;
}
document.body.removeChild(temp);
textWrapper.innerHTML = collected;
block.appendChild(textWrapper);
container.appendChild(block);
const link = document.createElement("div");
link.className = "mitteilungsblatt-hinweis";
link.innerHTML = `Weitere Ausgaben finden Sie unter <a href="/der_verein/downloads/">Über uns / Downloads</a>.`;
container.appendChild(link);
})
.catch((error) =>
console.error("Fehler beim Laden der Mitteilungsblätter:", error)
);
});
</script>
🔧 Erweiterte Leserechte („privat“) für Autoren
Mit folgendem Code ist die functions.php unseres Child-Themes ergänzt, um Autoren das Lesen privater Seiten zu erlauben (bei uns sind die Dokumentationsseiten so formatiert):
function fgsub_allow_authors_to_read_private_pages() {
$role = get_role( 'author' );
if ( $role && !$role->has_cap('read_private_pages') ) {
$role->add_cap( 'read_private_pages' );
}
}
add_action( 'init', 'fgsub_allow_authors_to_read_private_pages' ); 🔍 Was das macht:
- Erweitert die Autorenrolle
authorum das Rechtread_private_pages. - Autoren können dadurch private Seiten lesen, aber keine neuen Seiten erstellen oder bearbeiten.
🧪 Rückgängig machen
Entfernen der Änderung:
function fgsub_remove_authors_private_page_access() {
$role = get_role( 'author' );
if ( $role && $role->has_cap('read_private_pages') ) {
$role->remove_cap( 'read_private_pages' );
}
}
add_action( 'init', 'fgsub_remove_authors_private_page_access' ); 🧠 Hinweis:
Der Code wirkt direkt nach dem Einfügen. Ein Login der Benutzer ist danach erneut nötig, damit die neuen Rechte greifen.
🔧 Admin-Menüpunkt: Direkter Link zum internen Bereich
Mit diesem Code wird im WordPress-Adminmenü ein neuer Menüpunkt „technische Doku“ eingefügt. Beim Klick öffnet sich die Seite /nur-fuer-staff/. Er ist über das Plugin Snippets eingefügt.
📄 Code-Snippet:
function fgsub_adminlink_internbereich() {
add_menu_page(
'Dokumentationen und Anleitungen', // Seiten-Titel (optional, erscheint bei Callback-Nutzung)
'technische Doku', // Text im Admin-Menü
'edit_pages', // Mindestrolle: Redakteure und höher
site_url( '/nur-fuer-staff/' ), // Direktlink zur Seite (funktioniert lokal und live)
'', // Kein Callback nötig, da nur externer Link
'dashicons-admin-page', // Optionales Icon im Menü
80 // Position im Menü (z. B. unter „Beiträge“)
);
}
add_action( 'admin_menu', 'fgsub_adminlink_internbereich' ); 🧩 Technischer Hinweis:
site_url()erzeugt die korrekte URL für die aktuelle Umgebung – z. B.https://www.fgsub.de/oderhttp://fgsub.test/- Der Menüpunkt ist nur für Benutzer mit der Fähigkeit
edit_pagessichtbar (Redakteure und Admins) - Es ist kein eigener Seiteninhalt im Adminbereich nötig, daher bleibt das Callback-Feld leer
✅ Ergebnis:
- Ein neuer Menüpunkt „technische Doku“ erscheint im WordPress-Backend
- Beim Klick öffnet sich
/nur-fuer-staff/in der gleichen Umgebung – live oder lokal
Interne Links root-relativ
Um die Test- und Live-Umgebung (fgsub.test / fgsub.de)
parallel nutzbar zu machen, werden interne Links im Beitrags- und Seiteninhalt
(root-relative) umgeschrieben. So funktionieren alle Links in beiden Umgebungen ohne Anpassung.
Realisiert mit dem Snippet-Plugin.
Snippet
/**
* fgsub – Interne Links root-relativ
* Macht interne absolute Links (fgsub.de oder fgsub.test) root-relativ.
* Gilt nur für Beitrags-/Seiteninhalte und Text-Widgets.
*/
function fgsub_make_internal_links_root_relative( $content ) {
if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || is_feed() ) {
return $content;
}
if ( ! is_string( $content ) || $content === '' ) {
return $content;
}
$host = parse_url( home_url(), PHP_URL_HOST );
if ( ! $host ) {
return $content; // failsafe
}
$charset = get_bloginfo( 'charset' ) ?: 'UTF-8';
$html = '<meta http-equiv="Content-Type" content="text/html; charset=' . esc_attr($charset) . '"><div id="fgs-wrap">' . $content . '</div>';
$prev = libxml_use_internal_errors( true );
$doc = new DOMDocument();
if ( ! @$doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD ) ) {
libxml_clear_errors();
libxml_use_internal_errors( $prev );
return $content;
}
$xp = new DOMXPath( $doc );
$as = $xp->query( '//*[@id="fgs-wrap"]//a[@href]' );
foreach ( $as as $a ) {
$href = $a->getAttribute( 'href' );
if ( $href === '' || $href[0] === '#' ) continue;
if ( preg_match( '#^(mailto:|tel:|javascript:|data:)#i', $href ) ) continue;
$parts = @parse_url( $href );
if ( empty( $parts['host'] ) && empty( $parts['scheme'] ) ) continue;
if ( ! empty( $parts['host'] ) && strcasecmp( $parts['host'], $host ) !== 0 ) continue;
if ( ! empty( $parts['scheme'] ) && ! preg_match( '#^https?$#i', $parts['scheme'] ) ) continue;
$path = isset( $parts['path'] ) ? $parts['path'] : '/';
if ( preg_match( '#^/(wp-admin|wp-login\.php|wp-json)(/|$)#i', $path ) ) continue;
if ( preg_match( '#^/(wp-content|wp-includes)(/|$)#i', $path ) ) continue;
$rel = $path;
if ( ! empty( $parts['query'] ) ) $rel .= '?' . $parts['query'];
if ( ! empty( $parts['fragment'] ) ) $rel .= '#' . $parts['fragment'];
$a->setAttribute( 'href', $rel );
}
$out = '';
$wrap = $doc->getElementById( 'fgs-wrap' );
if ( $wrap ) {
foreach ( $wrap->childNodes as $child ) {
$out .= $doc->saveHTML( $child );
}
}
libxml_clear_errors();
libxml_use_internal_errors( $prev );
return $out !== '' ? $out : $content;
}
add_filter( 'the_content', 'fgsub_make_internal_links_root_relative', 20 );
add_filter( 'widget_text_content', 'fgsub_make_internal_links_root_relative', 20 );
Hinweise
- Wirkt nur auf Beitrags-/Seiteninhalte und Text-Widgets.
- Menüs, Skripte und Plugin-Links bleiben weiterhin absolut (z. B.
https://www.fgsub.de). - Externe Links, E-Mail-Links, Anker und technische Pfade (
/wp-admin,/wp-login.php,/wp-json,/wp-content,/wp-includes) bleiben unverändert. - Bei Problemen fällt die Funktion automatisch auf den Original-Content zurück („failsafe“).
- So ist sichergestellt, dass Beiträge/Seiten sowohl auf
fgsub.deals auch auffgsub.testfunktionieren.



