Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Block / Widget für letzte Postings, Artikel, Karten

Wenn man eine Webseite anbietet und auf dieser an irgendeiner Stelle eine jeweils aktuelle Auflistung einer bestimmten Anzahl von Kanal-Postings, Artikeln oder Karten anbieten, stellt man fest, diess es dafür kein Standard-Widget gibt.

Block

Es ist aber mit einem PHP-Block trotzdem machbar:

// lastpostings 0.7.2
// Hubzilla-Umgebung laden
require_once '<PFAD_ZUR_HUBZILLA-INSTALLATION>/boot.php'; // also z.B. /var/www/hubzilla/boot.php

// Anzahl der anzuzeigenden Postings
define('NUMOFPOSTS', 5);

// Postings oder Karten oder Artikel
define('ITEMTYPE', 0);   // 0 = Posting, 6 = Karte, 7 = Artikel

// Länge des angezeigten Auszugs
define('EXCERPT', 512);

// Kanal-ID und Kanalname
define('MYUID', <UID_DES_KANALS>);
define('CHANNAME', '<KANALNAME>'); // PFLICHTANGABE
// Bild-Anzeige: 0 = keine Bilder, 1 = unverändert (Default), 2 = skaliert (max. 380×256)
define('SHOWIMG', 1);

// Bilder im gerenderten HTML je nach SHOWIMG darstellen
function process_images($html) {
    if (SHOWIMG === 0) {
        // Bilder komplett entfernen
        return preg_replace('/<img\b[^>]*>/i', '', $html);
    }
    if (SHOWIMG === 2) {
        // Bilder skalieren: max. 380px breit, max. 256px hoch, Seitenverhältnis bleibt erhalten
        return preg_replace_callback(
            '/<img\b[^>]*>/i',
            function ($m) {
                $tag = $m[0];
                // Vorhandene width/height-Angaben entfernen, damit CSS greift
                $tag = preg_replace('/\s(width|height)\s*=\s*("[^"]*"|\'[^\']*\'|\S+)/i', '', $tag);
                // Skalierungs-Style einfügen
                if (preg_match('/\bstyle\s*=\s*("([^"]*)"|\'([^\']*)\')/i', $tag, $s)) {
                    $style = $s[2] . ' max-width:380px; max-height:256px; width:auto; height:auto;';
                    $tag = str_replace($s[0], 'style="' . $style . '"', $tag);
                } else {
                    $tag = preg_replace('/<img\b/i', '<img style="max-width:380px; max-height:256px; width:auto; height:auto;"', $tag);
                }
                return $tag;
            },
            $html
        );
    }
    // SHOWIMG === 1 (Default): unverändert
    return $html;
}

// Kanal-ID und -name ermitteln
$channel_id = isset($_SESSION['uid']) ? intval($_SESSION['uid']) : MYUID;
$channel_name = isset($a->channel['channel_name']) ? $a->channel['channel_name'] : CHANNAME;

// SQL-Abfrage: Nur eigene, sichtbare, öffentliche Postings
// allen anderen Kram rigoros aussortieren… vor allem die gelöschten Items
$sql = sprintf(
    "SELECT id, mid, uuid, llink, title, body, created FROM item
     WHERE uid = %d
     AND item_origin = 1
     AND item_deleted = 0
     AND item_unpublished = 0
     AND item_hidden = 0
     AND item_pending_remove = 0
     AND item_private = 0
     AND verb = 'Create'
     AND obj_type = 'Note'
     AND item_type = %d
     AND mimetype = 'text/bbcode'
     ORDER BY id DESC LIMIT %d",
    intval($channel_id),
    ITEMTYPE,
    NUMOFPOSTS
);

$result = q($sql);

// Ergebnisse verarbeiten für MySQL UND PostgreSQL
$items = [];
if (is_array($result)) {
    $items = $result;
} elseif ($result && property_exists($result, 'num_rows') && $result->num_rows > 0) {
    while ($item = $result->fetch()) {
        $items[] = $item;
    }
}

// Ausgabe
if (!empty($items)) {
    echo '<div class="container">';
    foreach ($items as $item) {
        $title = htmlspecialchars($item['title'] ?? '', ENT_QUOTES, 'UTF-8');

        // BBCode in HTML umwandeln und Bilder gemäß SHOWIMG darstellen
        $body = process_images(bbcode($item['body'] ?? ''));

        // Excerpt nach sichtbarem Text kürzen:
        // HTML-Tags (inkl. Attributwerte wie Bildpfade) zählen nicht ins Zeichenbudget.

        if (mb_strlen(strip_tags($body), 'UTF-8') > EXCERPT) {
            $summary = '';
            $visible = 0;   // Anzahl gezählter sichtbarer Zeichen
            $len  = mb_strlen($body, 'UTF-8');
            $i = 0;

            while ($i < $len) {
                $char = mb_substr($body, $i, 1, 'UTF-8');

                if ($char === '<') {
                    // Kompletten Tag übernehmen (zählt nicht ins Budget)
                    $tagEnd = mb_strpos($body, '>', $i, 'UTF-8');
                    if ($tagEnd === false) {
                        // kein schließendes '>' mehr → Tag nicht übernehmen, fertig
                        break;
                    }
                    $summary .= mb_substr($body, $i, $tagEnd - $i + 1, 'UTF-8');
                    $i = $tagEnd + 1;
                } else {
                    // Sichtbares Textzeichen: zählt ins Budget
                    $summary .= $char;
                    $visible++;
                    $i++;
                    if ($visible >= EXCERPT) {
                        break;
                    }
                }
            }

            $summary .= '…';
        } else {
            $summary = $body;
        }

        // Datum ins deutsche Format (TT.MM.JJJJ)
        $created = date('d.m.Y', strtotime($item['created']));

        // Weiterlesen-Link: <URL_DES_HUB>/channel/<KANALNAME>?mid=<UUID>
        $baseurl = z_root();
        $read_more_link = '<a href="' . htmlspecialchars($baseurl . '/channel/' . CHANNAME . '?mid=' . $item['uuid'], ENT_QUOTES, 'UTF-8') . '">..::Weiterlesen::..</a>';

        echo '<div class="border border-light rounded p-3 mb-3 w-100">';
        if ($title) {
            echo '<h5 class="mb-2">' . $title . '</h5>';
        }
        echo '<div class="text-end"><small class="text-muted">' . $created . '</small></div>';
        echo '<div class="mb-1">' . $summary . '</div>';
        echo $read_more_link;
        echo '</div>';
    }
    echo '</div>';
} else {
    echo '<p class="text-muted">Keine eigenen Beiträge gefunden.</p>';
}


Beachte: Bei PHP-Blöcken, darf das Skript nicht von <?php und ?> eingerahmt werden!

Diesen Block kann jeden verwenden, sofern für den Kanal Code erlaubt ist (dies muss der Hub-Administrator tun).

Damit der Block auch auf bestimmte Hubzilla-Funktionen zugreifen und bestimmte Konstanten bzw. Variablen im Hubzilla-Kontext nutzen kann, wird der <PFAD_ZUR_HUBZILLA-INSTALLATION> (Zeile 4) benötigt. Der Betreiber/Administrator eines Hub kennt diesen Pfad. Ist man selbst nicht der Admin, muss man ohnehin den Administrator um die Freischaltung von Code bitten und dann kann man auch nach dem Pfad fragen. Wenn man ihm erklärt, wofür man ihn benötigt (gerne unter Verweis auf dieses Kapitel), sollte es kein Problem sein, ihn in Erfahrung zu bringen. Bei dieser Gelegenheit kann man auch nach der uid des eigenen Kanals fragen (er kann diese in der Admin-Oberfläche ➔ Kanäle nachschauen). Diese kann man dann in Zeile 16 eintragen: define('MYUID', <UID_DES_KANALS>;.

In Zeile 17 trägt man dann auch gleich den Kanalkurznamen (eingeschlossen in “Hochkommata”, also ’ ) eindefine('CHANNAME', '<KANALNAME>');.

Die Parameter in den Zeilen 16 und 17 sind aber in der Regel nicht von Belang und dienen und dazu, im Falle, dass diese Parameter nicht vom Skript festgestellt werden können, als Fallback. Hier kann man auch beliebige Werte eintragen.

In Zeile 7 kann man festlegen, wie viele Postings, Artikel oder Karten angezeigt werden: define('NUMOFPOSTS', 5);. Vorgabewert ist hier 5.

Zeile 10 ist dafür da, den Typ der anzuzeigenden Inhalte festzulegen (man kann entweder normale Postings = 0, Artikel = 7 oder Karten = 6 anzeigen lassen): define('ITEMTYPE', 0);.

Die Inhalte werden nicht vollständig angezeigt, sondern auf einen Auszug begrenzt. Die Anzahl der anzuzeigenden Zeichen legt man in Zeile 13 fest: define('EXCERPT', <ANZAHL_ANGEZEIGTER_ZEICHEN>);. Vergabewert ist hier 512. Bilder und eingebettete Elemente werden dabei nicht mitgezählt.

Über den Parameter “SHOWIMG” in Zeile 20 kann man schließlich festlegen, ob und wie eingebettete Bilder angezeigt werden: define('SHOWIMG', <BILDANZEIGE>);. Vorgabewert ist hier 1. Wählt man als Wert 0, werden Bilder nicht angezeigt, wählt man als Wert 1, werden Bilder unskaliert in Originalgröße dargestellt, den Wert 2 sorgt dafür, dass eingebettete Bilder auf eine Maximalgröße von 380 x 256 Pixel herunterskaliert angezeigt werden, sofern sie im Original größer sein sollten.

Beispiel mit drei Beiträgen (Postings), Auszugslänge 512 und skalierten Bildern.

Widget

Um die Anzeige auch für reine Nutzer verwendbar zu machen, habe ich auch ein Widget gebastelt. Es ist hier zu finden: pepes-widgets. Mein Widgets-Repo muss allerdings vom Administrator einmalig installiert werden.

Man kann es im PDL-Editor und in Webseiten-Layouts einsetzen:

[widget=Lastitems][/widget]

Die Parameter lassen sich über Variablen angeben.

[widget=Lastitems][var=count]5[/var][var=excerpt]512[/var][var=img]2[/var][var=itemtype]0[/var][/widget]

Wird ein Parameter nicht angegeben, so wird der Standardwert verwendet:

  • count – Anzahl der angezeigten Items (Standard: 5)
  • excerpt – Länge des Textauszugs in Zeichen (Standard: 512)
  • img – Bildanzeige: 0 = keine Anzeige, 1 = Original, 2 = skaliert auf max. 380×256 (Standard: 2)
  • itemtype – 0 = Postings, 6 = Karten, 7 = Artikel (Standard: 0)