Die ID des ersten Bildes eines WordPress-Beitrags ermitteln

Ich stand gestern vor dem Problem, wie ich aus einem Beitrag in WordPress die ID des ersten Bildes ermitteln kann, um damit weiterzuarbeiten. Wie ich das Problem letztlich gelöst habe, zeige ich euch hier.

Das Problem

Ich erstelle gerade ein WordPress-Theme, in dem alle Beiträge vom Typ „Galerie“ und „Bild“ auf einer Übersichtsseite dargestellt werden sollen – quasi als Portfolio-Übersicht. Hierbei soll ein Bild aus der Galerie oder aus dem Bild-Beitrag als Thumbnail dargestellt werden und auf die Einzelansicht verlinken. Wie das erste Bild aus einer Galerie geholt werden kann, habe ich bereits in einem älteren Beitrag beschrieben. Es gibt allerdings keine Funktion, um alle Bilder eines Beitrags zu ermitteln.

Die Lösung

Nach ein bisschen Suchen bin ich auf einen Beitrag bei CSS-Tricks gestoßen, in dem der Beitragsinhalt mit einem regulären Ausdruck nach Bildern durchsucht und die URL herausgezogen wird. Als Ergebnis der Funktion wird die URL des ersten Bildes zurückgegeben.

Die von mir leicht angepasste Funktion, um die URL des ersten Bildes eines Beitrags zu ermitteln, sieht so aus:

function hannover_get_first_image_from_post_content() {
    global $post;
    $first_img = '';
    $output = preg_match( '/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post->post_content, $matches );
    if ( ! empty( $matches[1] ) ) {
        $first_img = $matches[1];
    }

    return $first_img;
}

Zuerst holen wir uns das Objekt des aktuellen Beitrags und deklarieren eine leere Variable $first_img. Im Anschluss suchen wir mit der preg_match()-Funktion nach dem ersten Vorkommen eines img-Tags im Beitragsinhalt, der unter $post->post_content verfügbar ist und speichern den Treffer in der $matches-Variable. Nun prüfen wir, ob der Array-Schlüssel 1 einen Wert enthält – hier wird die URL gespeichert. Wenn das der Fall ist, weisen wir diesen Wert der Variable $first_img zu und geben sie im Anschluss zurück.

Diese URL bringt uns aber noch nicht sehr viel, weil wir nicht davon ausgehen können, dass das Bild im Beitrag als Thumbnail eingebunden wurde. Wir müssen also an die ID des Bildes kommen, damit wir es in einer beliebigen Größe ausgeben können. Außerdem wollen wir auch den Fall behandeln, dass aus irgendeinem Grund kein Bild eingebunden ist. In diesem Fall soll ein Bild angezeigt werden, das zu dem Beitrag hochgeladen wurde.

Dieser komplette Teil sieht so aus:

function hannover_first_image_from_post( $size, $post ) {
    $first_img_url = hannover_get_first_image_from_post_content();
    $pattern       = '/-\d+x\d+(\.\w{3,4}$)/i';
    $first_img_url = preg_replace( $pattern, '${1}', $first_img_url );
    $first_img_id  = attachment_url_to_postid( $first_img_url );
    if ( $first_img_id == 0 ) {
        $attachments = get_children( array(
            'post_parent'    => $post->ID,
            'post_status'    => 'inherit',
            'post_type'      => 'attachment',
            'post_mime_type' => 'image',
            'order'          => 'ASC',
            'orderby'        => 'menu_order',
        ) );
        $first_img   = array_shift( $attachments );
        $img_tag     = wp_get_attachment_image( $first_img->ID, $size );
    } else {
        $img_tag = wp_get_attachment_image( $first_img_id, $size );
    }
    echo $img_tag;
}

Seit WordPress 4.2 gibt es die Funktion attachment_url_to_postid(), mit der WordPress versucht, die ID der übergebenen Bild-URL zu ermitteln. Das funktioniert aber nur, wenn die URL der vollen Bildgröße übergeben wird, also ohne den Anhang -300x500 oder ähnliches. Doch genau diesen Teil werden wir höchstwahrscheinlich an der URL aus dem hannover_get_first_image_from_post_content()-Aufruf vorfinden.

Wir müssen also nach dem Ermitteln der ersten URL zuerst diesen Teil entfernen. Dafür nutzen wir den regulären Ausdruck /-\d+x\d+(\.\w{3,4}$)/, der am Ende des übergebenen Strings nach dem Muster -Zahl(en)xZahl(en).Buchstaben(3-4) sucht. Die Dateiendung und der Punkt werden in Klammerng geschrieben, da wir diese ja brauchen und nicht wie den anderen Teil komplett entfernen möchten. In der nächsten Zeile setzen wir den Ausdruck in preg_replace() ein und ersetzen den Treffer nur mit der Dateiendung. So wird aus http://exapmle.com/bild-name-300x500.jpg die gesuchte URL http://exapmle.com/bild-name.jpg. Diese können wir dann an attachment_url_to_postid() übergeben.

Wenn WordPress kein Bild zu der URL finden kann oder gar keine URL vorhanden ist, weil kein Bild in den Beitrag eingefügt wurde, dann ist das Ergebnis des attachment_url_to_postid()-Aufrufs 0. Für diesen Fall holen wir uns mit der get_children()-Funktion die Bilder, die zu dem Beitrag hochgeladen wurden, nehmen davon via array_shift() das erste und kommen mit wp_get_attachment_image() an das img-Tag mit der entsprechenden Größe.

Wenn dagegen von WordPress eine ID zu der URL gefunden wurde, dann übergeben wir diese zusammen mit der gesuchten Größe an wp_get_attachment_image(). Am Ende geben wir das Tag mit dem Bild aus.

Dieser Code berücksichtigt nicht den Fall, dass weder ein Bild in den Beitrag eingefügt noch dazu hochgeladen wurde – aber das ist für meinen Anwendungsfall verschmerzbar 🙂

Wenn ihr Tipps und Verbesserungsvorschläge habt, gerne in die Kommentare, dann passe ich den Code an.

Das könnte auch interessant sein

2 Kommentare zu »Die ID des ersten Bildes eines WordPress-Beitrags ermitteln«

  1. Martin

    Hallo Florian,

    es geht noch schneller: die ID aus dem class-Attribut des Bildes auslesen. Der zu suchende Klassennamen hat den Aufbau wp-image-{ID}. Er wird automatisch eingefügt, wenn das Bild manuell im Editor eingebaut wird.

    In meinen Plugins "Quick Featured Images" und "Recent Posts Widget With Thumbnails" (beide im WP-Repository zu finden) setze ich die Abfrage nach dieser ID ein, bevor es bei erfolglosem Ergebnis weitergeht mit dem von dir beschriebenen Ansatz. Mit einer Suche nach dem Funktionsnamen get_first_content_image_id findest du den kompletten Code.

    Bei get_children() kannst du mit dem Parameter 'numberposts' => 1 die Abfrage auf genau ein einziges Ergebnis begrenzen. Die Abfrage wird dann abgebrochen und das erste gefundene Bild in einem Array mit einem einzigen Element zurückgegeben. Dein weiterer Code bleibt davon unbeeinflusst.

    Galerien können auch mit dem ids-Attribut im [gallery]-Shortcode gebaut werden. Diese Möglichkeit ist in deinem Code nicht zu finden. Ein Ansatz, der im kostenpflichtigen Plugin "Quick Featured Images Pro" eingesetzt wird, wäre:

    function get_first_wp_gallery_image_id ( $post_id, $content ) {
    	// try to find a gallery and pick its first image
    	preg_match( '/\[gallery[^\]]*ids="(\d+)[^\]]*\]/i', $content, $found_id );
    	// if first image id found: check whether is image
    	if ( $found_id ) {
    		$img_id = absint( $found_id[ 1 ] );
    		// if is image: return its id
    		if ( wp_get_attachment_image_src( $img_id ) ) {
    			return $img_id;
    		}
    	} // if(found_id)
    		
    	// if nothing found: return 0
    	return 0;
    }
    Antworten
    1. Florian

      Hi Martin,

      zuerst: Ich habe die Code-Schnipsel deines Kommentars mal mit entsprechenden Tags ausgezeichnet, hoffe, das ist okay 🙂

      Vielen Dank für die Denkanstöße! An den Klassennamen hatte ich tatsächlich auch gedacht, dann habe ich aber die URL als sichere Quelle gewählt (theoretisch könnte der Klassenname ja aus irgendeinem Grund angepasst werden). Das mit dem Einsatz von numberposts ist eine gute Idee, werde ich nutzen.
      Zur Galerie: Hier in dem Beitrag sollte es nur um ein normales Bild gehen, da ich das für Galerien bereits beschrieben habe – in dem Beitrag ist auch die Funktion eingefügt, die ich dafür nutze.

      Viele Grüße
      Florian

      Antworten

Schreibe einen Kommentar zu Florian Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.