PHP Ergänzungen


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

Mitteilungsblatt des FGSUB


auf der Startseite eingebunden.

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>

nach oben

🔧 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 author um das Recht read_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.


nach oben

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/ oder http://fgsub.test/
  • Der Menüpunkt ist nur für Benutzer mit der Fähigkeit edit_pages sichtbar (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

nach oben

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.de als auch auf fgsub.test funktionieren.

Testseite


nach oben