Vergiss Photoshop — So kannst du mit PHP Bilder generieren!

Julian Lang
Julian Lang

07. Apr, 2022 | 10 Min. Lesezeit

Eine Funktion die man gerne übersieht dabei gibt es so viele nützliche Einsatzmöglichkeiten. Du kannst zum Beispiel deine Open Graph Bilder damit dynamisch generieren oder automatische Beitragsbilder erzeugen, um deinem Blog ein professionelles „Image“ zu verpassen ????

Table of Content SVG Icon Inhaltsverzeichnis

    Ich zeige dir jetzt hier anhand des erstgenannten Praxisbeispiels wie man das macht. Dieser Beitrag ist Teil einer Serie, deren Code sich teilweise ergänzt. Schau dir deshalb unbedingt die anderen Teile (weiter unten) an.

    Jetzt lernst du wie du tolle Open Graph Bilder (das Vorschaubild, wenn du einen Beitrag auf Facebook teilst) mit PHP erstellst, wenn du keine Lust mehr auf Unsplash, Pexels und Co hast.

    Als Erstes: Ein WordPress Redirect basteln

    Wir brauchen einen Link für das Open Graph Bild. Dafür erstellen wir jetzt einen WordPress Redirect. Das bedeuetet wir definieren einen Slug, der wenn aufgerufen eine bestimmte Aktion ausführt. Wir könnten z.b. ein Template damit einbinden. Machen wir aber nicht. Wir geben stattdessen ein Bild aus. Dazu aber später mehr.

    Der Slug /blog-ogimage/ soll uns das Bild erstellen. Alles was nach dem Slug kommt können wir abfangen und benutzen. In diesem Fall möchten wir eigentlich nur die Post ID weitergeben.

    Haben wir also einen Beitrag mit der Post ID: 34 können wir das OG Bild so erhalten: /blog-ogimage/34

    Wie das genau funktioniert siehst du hier.

    add_action('init', 'rewrite_rule' );
    function rewrite_rule() {
            add_rewrite_rule( 'blog-ogimage/([a-z0-9-]+)[/]?$', 'index.php?blog-ogimage=$matches[1]', 'top' );
    }

    Damit sagen wir WordPress, das er darauf achten soll ob jemand oder etwas den Slug /blog-ogimage/xx aufruft.

    Zusätzlich müssen wir WordPress noch mitteilen das der Slug eine der erlaubten query_vars ist.

    add_filter( 'query_vars', 'whitelist' );
    public static function whitelist($query_vars) {
        $query_vars[] = 'blog-ogimage';
        return $query_vars;
    }

    Wichtig: Du musst jetzt einmal deine Permalinks neu abspeichern, damit WordPress den Redirect ausführt.

    WordPress achtet ab jetzt darauf ob jemand den Slug /blog-ogimage/ aufruft und erlaubt sogar noch, das alles was danach kommt, weitergegeben wird.

    Der Handler: das passiert wenn jemand den rewrite aufruft

    Wir möchten, das ein Bild ausgegeben wird, das dynamisch basierend auf den Beitragsinfos generiert wird. Dazu müssen wir erst die Post ID erhalten, die wir in der URL mitgeben. in unserem Beispiel die 34.

    add_action( 'template_redirect', 'handler');
    function handler($template) {
        // Wenn keine query_var gesetzt ist dann mache gar nix!
        if (!get_query_var('blog-ogimage')) {
            return;
        }
        // Ansonsten ziehen wir die mitgebene Post ID ab und speichern Sie in $post_id
        $post_id = (int) get_query_var('blog-ogimage');
        // wir geben den Post Titel aus.
        echo get_the_title($post_id);
    }

    Schreibe diese 3 Bausteine in deine functions.php und rufe dann https://deine-webseite.de/blog-ogimage/34 auf. (Die 34 muss natürlich eine bei dir bestehende Post ID sein).

    Dann öffnet sich eine Seite und zeigt dir den Post Titel an. Damit können wir arbeiten. Wir haben nun die Info um welchen Post es sich handelt, dessen OG Bild wir erstellen möchten.

    Das Bild: Wie du mit PHP ein Bild generierst

    Das fertige OG Bild, generiert mit PHP

    Wir möchten:

    1. Die Beitrags Kategorie ausgeben (Allgemein)
    2. Den Beitragstitel ausgeben
    3. Die Beitragstags ausgeben (ogimage, php)
    4. Das Beitragsdatum ausgeben (06.04.2022)
    5. Den Autor inklusive Gravatar
    6. Unser Logo oben rechts positionieren

    Erstelle dir in einem Grafikprogramm deiner Wahl zuerst ein Blanko-Hintergrundbild das uns als Canvas dienen wird.

    Ein Blanko Hintergrundbild

    Wenn du konkret wie hier im Tutorial ein Facebook OG-Bild machen möchtest, lege deinen Canvas mit 1200 Pixel auf 630 Pixel an.

    1. Exportiere dein Blanko Canvas-Bild und lege es in deinem Theme Ordner unter /assets/images/bg-ogimage-blank.pngab.
    2. Lege ebenfalls dein Logo im selben Ordner ab logo.png

    Lade dir die Schriftarten von Google Fonts herunter, die du auf dem Bild verwenden möchtest

    Wir verwenden die Schriftart ‚Poppins‘ mit den Schnitten: Light, Medium, SemiBold und Bold.

    Lade dir die Schriftarten als TTF (.ttf) von Google Fonts herunter und lege sie ebenfalls in deinen Theme Ordner unter /assets/fonts/Poppins-Light.ttf usw. ab.

    Die Post Informationen für das Bild aufbereiten.

    Weiter oben haben wir in der handler() Funktion bereits erfolgreich die Post ID über den Slug erhalten. Wir müssen jetzt die benötigten Informationen, die auf das Bild gerendert werden sollen aufbereiten.

    Das Post Objekt erhalten

    if ( is_int($post_id) && '' !== trim($post_id) ) {
        $post = get_post($post_id);
        if ( empty($post) OR 0 === $post_id ) {
            return;
        }
    }

    Wir müssen sicherstellen, das die übergebene Post ID nicht ‚leer‘ ist und eine Ganzzahl ist. Wenn das der Fall ist holen wir das Post Objekt und überprüfen ob wir ein Post Objekt erhalten haben.

    Den Post Titel erhalten und zweizeilig umwandeln

    $title = $post->post_title;
    // Wir müssen den Post Titel kappen, da wir ca 4 Wörter pro Zeile haben können.
    $title_words = explode(' ', $title);
    $title_first_line = $title_words[0].' '.$title_words[1].' '.$title_words[2].' '.$title_words[3];
    $title_second_line = $title_words[4].' '.$title_words[5].' '.$title_words[6].' '.$title_words[7];
    // Wenn der Titel länger als 8 Wörter ist, fügen wir noch ein "..." hinten an.
    if ( count($title_words) > 8 ) {
        $title_second_line .= ' ...';
    }

    Leider unterstützt imagettftext() keine automatischen Zeilenumbrüche, deshalb muss der Post Titel von uns manuell aufgeteilt werden.

    explode() erstellt ein Array aus dem Post Titel String und wir fügen jeweils 4 Wörter in die beiden neuen Variablen $title_first_line und $title_second_line

    Zusätzlich schneiden wir den Post Titel noch ab, falls er länger als 8 Wörter sein sollte.

    Die Post Kategorien erhalten und in einen String umwandeln

    // Die Post Kategorien
    $post_categories = get_the_terms( $post_id, 'category' );
    if ( ! empty( $post_categories ) && ! is_wp_error( $post_categories ) ) {
        $categories = wp_list_pluck( $post_categories, 'name' );
    }
    // Wandelt die Post Kategorien in einen String um und macht den Text hochgestellt.
    $post_categories = strtoupper(implode(', ', $categories));

    Die Post Schlagwörter erhalten und in einen String umwandeln

    // Die Post Tags
    $post_tags = get_the_terms( $post_id, 'post_tag' );
    if ( ! empty( $post_tags ) && ! is_wp_error( $post_tags ) ) {
        $tags = wp_list_pluck( $post_tags, 'name' );
    }
    // Wandelt die Post Tags in einen String um.
    $post_tags = implode(', ', $tags);
    // Wir überprüfen ob der Titel Ein- oder Zweizeilig ist und passen die Y-Koordinate der Post Tags Positon an.
    $post_tags_y = 340;
    if ( '' === trim($title_second_line) ) {
        $post_tags_y = 280;
    }

    Gleiches Prinzip wie bei den Post Kategorien. Die Besonderheit ist hier, das wir überprüfen ob der Post Titel Ein- oder Zweizeilig ist. Sollte er nur Einzeilig sein, müssen wir die Höhe der Post Tags anders definieren.

    Das passiert über die Variable $post_tags_y

    Ist der Post Titel nur Einzeilig, setzen wir die Position der Post Tags auf 280 anstelle 340.

    Das Post Datum und den Post Autor erhalten

    // Das Post Datum erhalten.
    $post_date = get_the_date('d.m.Y');
    // Den Post Autor erhalten.
    $post_author = get_user_by('ID', $post->post_author);
    $author_display_name = $post_author->display_name;
    // Avatar in (40px x 40px) erhalten.
    $author_avatar_url = get_avatar_url($post->post_author, ['size' => 40]);

    Wir benötigen jetzt nur noch das Post Datum, die Autor Informationen und die URL des Avatars.

    Wir haben alle Informationen die wir brauchen und können jetzt kreativ werden.

    Klicken Sie auf den unteren Button, um den Inhalt von giphy.com zu laden.

    Inhalt laden

    via GIPHY

    Das Bild mit PHP zusammensetzen und ausgeben

    // Der Post existiert, generiere das Bild.
    header("Content-Type: image/png");
        
    // Blanko Hintergrundbild Url (1200px x 630px)
    $blank_background_url = get_stylesheet_directory() . '/assets/images/bg-ogimage-blank.png';
    // Logo Url
    $logo_url = get_stylesheet_directory() . '/assets/images/logo.png';
    // Erstellt den Canvas basierend auf dem Blanko Hintergrundbild (ein PNG).
    $im = imagecreatefrompng($blank_background_url) or die("Cannot Initialize new GD image stream");
    // Erstellt das Logo (70px x 70px) und platziert es dem Canvas im rechten oberen Eck.
    $logo = imagecreatefrompng($logo_url);
    imagecopy($im, $logo, 1060, 40, 0, 0, 70, 70);
    // Erstellt das Author Gravatar Bild und platziert es neben dem Datum.
    $author_avatar = imagecreatefrompng($author_avatar_url);
    imagecopy($im, $author_avatar, 390, 457, 0, 0, 40, 40);
    // Definiere die benötigten Farben für die Texte
    $emphasis_color = imagecolorallocate($im, 2, 1, 22);
    $purple = imagecolorallocate($im, 12, 9, 96);
    // Lade die gewünschten Schriftarten & Schnitte. Müssen TTF sein.
    $poppins_light = get_stylesheet_directory() . '/assets/fonts/Poppins-Light.ttf';
    $poppins_medium = get_stylesheet_directory() . '/assets/fonts/Poppins-Medium.ttf';
    $poppins_semibold = get_stylesheet_directory() . '/assets/fonts/Poppins-SemiBold.ttf';
    $poppins_bold = get_stylesheet_directory() . '/assets/fonts/Poppins-Bold.ttf';
    // Schreibt die Post Kategorien auf den Canvas.
    imagettftext($im, 14, 0, 130, 150, $purple, $poppins_semibold, $post_categories);
    // Schreibt den Post Titel auf den Canvas
    imagettftext($im, 32, 0, 130, 220, $emphasis_color, $poppins_bold, $title_first_line);
    imagettftext($im, 32, 0, 130, 280, $emphasis_color, $poppins_bold, $title_second_line);
    // Schreibt die Post Schlagwörter auf den Canvas. $post_tags_y Position haben wir weiter oben definiert.
    imagettftext($im, 22, 0, 130, $post_tags_y, $purple, $poppins_light, $post_tags);
    // Schreibt das Post Datum auf den Canvas.
    imagettftext($im, 12, 0, 130, 482, $emphasis_color, $poppins_medium, $post_date);
    // Schreibt Autor Info auf den Canvas
    imagettftext($im, 10, 0, 260, 482, $emphasis_color, $poppins_medium, 'geschrieben von');
    imagettftext($im, 10, 0, 450, 482, $emphasis_color, $poppins_bold, $author_display_name);
    imagepng($im);
    // Zerstört die geladenen Bilder
    imagedestroy($im);
    imagedestroy($logo);
    exit;

    Ich hoffe die Kommentare sind bereits selbsterklärend, wenn nicht kannst du dir jetzt hier noch die Informationen zu den verwendeten GD- und Image-Funktionen durchlesen.

    imagecreatefrompng()

    Erzeugt ein neues Bild aus einer Datei oder URL und akzeptiert einen Parameter (den Pfad zu dem Bild). In diesem Fall unser Blanko Hintergrundbild. mehr lesen

    imagecopy()

    Kopiert einen Bildausschnitt. Du kannst ein weiteres Bild mit imagecreatefrompng() nehmen und dann mit imagecopy() einen bestimmten Ausschnitt auf eine bestimmte Position setzen. In unserem Fall setzen wir das Logo in die rechte obere Ecke. mehr lesen

    imagecolorallocate()

    Stellt eine Farbe für das Bild bereit. Definiere den Canvas und die gewünschte Farbe in rgb. mehr lesen

    imagettftext()

    Schreibt Text ins Bild unter Verwendung von True-Type-Schriftarten. mehr lesen

    imagepng()

    Gibt ein PNG Bild im Browser aus. mehr lesen

    imagedestroy()

    Gibt den belegten Speicher wieder frei. mehr lesen

    Live-Ergebnis

    Das automatisch generierte OG Bild für diesen Beitrag kannst du dir hier ansehen: OG für diesen Beitrag öffnen.

    Zusammenfassung

    Hier nochmal der komplette Code, den du in deine functions.php oder anderweitig in dein Theme oder Plugin integrieren kannst. Denke daran, nach dem Einfügen nochmal deine Permalinks abzuspeichern, damit der Redirect funktioniert.

    function rewrite_rule() {
        add_rewrite_rule( 'blog-ogimage/([a-z0-9-]+)[/]?$', 'index.php?blog-ogimage=$matches[1]', 'top' );
    }
    add_action('init', 'rewrite_rule' );
    function whitelist($query_vars) {
        $query_vars[] = 'blog-ogimage';
        return $query_vars;
    }
    add_filter( 'query_vars', 'whitelist' );
    function handler($template) {
        if (!get_query_var('blog-ogimage')) {
            return;
        }
        $post_id = (int) get_query_var('blog-ogimage');
        
        if ( is_int($post_id) && '' !== trim($post_id) ) {
            $post = get_post($post_id);
            if ( empty($post) OR 0 === $post_id ) {
                return;
            }
        }
        $title = $post->post_title;
        $title_words = explode(' ', $title);
        $title_first_line = $title_words[0].' '.$title_words[1].' '.$title_words[2].' '.$title_words[3];
        $title_second_line = $title_words[4].' '.$title_words[5].' '.$title_words[6].' '.$title_words[7];
        if ( count($title_words) > 8 ) {
            $title_second_line .= ' ...';
        }
        $post_categories = get_the_terms( $post_id, 'category' );
        if ( ! empty( $post_categories ) && ! is_wp_error( $post_categories ) ) {
            $categories = wp_list_pluck( $post_categories, 'name' );
        }
        $post_categories = strtoupper(implode(', ', $categories));
        $post_tags = get_the_terms( $post_id, 'post_tag' );
        if ( ! empty( $post_tags ) && ! is_wp_error( $post_tags ) ) {
            $tags = wp_list_pluck( $post_tags, 'name' );
        }
        $post_tags = implode(', ', $tags);
        $post_tags_y = 340;
        if ( '' === trim($title_second_line) ) {
            $post_tags_y = 280;
        }
        $post_date = get_the_date('d.m.Y');
        $post_author = get_user_by('ID', $post->post_author);
        $author_display_name = $post_author->display_name;
        $author_avatar_url = get_avatar_url($post->post_author, ['size' => 40]);
        
        
              
        header("Content-Type: image/png");
            
        $blank_background_url = get_stylesheet_directory() . '/assets/images/bg-ogimage-blank.png';
        $logo_url = get_stylesheet_directory() . '/assets/images/logo.png';
        $im = imagecreatefrompng($blank_background_url) or die("Cannot Initialize new GD image stream");
        $logo = imagecreatefrompng($logo_url);
        imagecopy($im, $logo, 1060, 40, 0, 0, 70, 70);
        $author_avatar = imagecreatefrompng($author_avatar_url);
        imagecopy($im, $author_avatar, 390, 457, 0, 0, 40, 40);
        
        $emphasis_color = imagecolorallocate($im, 2, 1, 22);
        $purple = imagecolorallocate($im, 12, 9, 96);
        $poppins_light = get_stylesheet_directory() . '/assets/fonts/Poppins-Light.ttf';
        $poppins_medium = get_stylesheet_directory() . '/assets/fonts/Poppins-Medium.ttf';
        $poppins_semibold = get_stylesheet_directory() . '/assets/fonts/Poppins-SemiBold.ttf';
        $poppins_bold = get_stylesheet_directory() . '/assets/fonts/Poppins-Bold.ttf';
        
        imagettftext($im, 14, 0, 130, 150, $purple, $poppins_semibold, $post_categories);
        imagettftext($im, 32, 0, 130, 220, $emphasis_color, $poppins_bold, $title_first_line);
        imagettftext($im, 32, 0, 130, 280, $emphasis_color, $poppins_bold, $title_second_line);
        imagettftext($im, 22, 0, 130, $post_tags_y, $purple, $poppins_light, $post_tags);
        imagettftext($im, 12, 0, 130, 482, $emphasis_color, $poppins_medium, $post_date);
        imagettftext($im, 10, 0, 260, 482, $emphasis_color, $poppins_medium, 'geschrieben von');
        imagettftext($im, 10, 0, 450, 482, $emphasis_color, $poppins_bold, $author_display_name);
        imagepng($im);
        imagedestroy($im);
        imagedestroy($logo);
        exit;
        
    }
    add_action( 'template_redirect', 'handler' );

    PHP-Klasse

    Falls du nicht so gerne mit Funktionen arbeitest, gibt es das Ganze auch einmal als PHP-Klasse, die du dir so kopieren kannst:

    if ( class_exists( 'PhpOgImage' ) ) {
    	new PhpOgImage();
    }
    class PhpOgImage {
        public function __construct()
        {
           add_action('init', [$this, 'rewrite_rule'] );
           add_filter( 'query_vars', [$this, 'whitelist'] );
           add_action( 'template_redirect', [$this, 'handler'] );
        }
        public static function rewrite_rule() {
            add_rewrite_rule( 'blog-ogimage/([a-z0-9-]+)[/]?$', 'index.php?blog-ogimage=$matches[1]', 'top' );
        }
        public static function whitelist($query_vars) {
            $query_vars[] = 'blog-ogimage';
            return $query_vars;
        }
        public static function handler($template) {
            if (!get_query_var('blog-ogimage')) {
                return;
            }
            $post_id = (int) get_query_var('blog-ogimage');
            if ( is_int($post_id) && '' !== trim($post_id) ) {
                $post = get_post($post_id);
                if ( empty($post) OR 0 === $post_id ) {
                    return;
                }
            }
            $title = $post->post_title;
            $title_words = explode(' ', $title);
            $title_first_line = $title_words[0].' '.$title_words[1].' '.$title_words[2].' '.$title_words[3];
            $title_second_line = $title_words[4].' '.$title_words[5].' '.$title_words[6].' '.$title_words[7];
            if ( count($title_words) > 8 ) {
                $title_second_line .= ' ...';
            }
            $post_categories = get_the_terms( $post_id, 'category' );
            if ( ! empty( $post_categories ) && ! is_wp_error( $post_categories ) ) {
                $categories = wp_list_pluck( $post_categories, 'name' );
            }
            $post_categories = strtoupper(implode(', ', $categories));
            $post_tags = get_the_terms( $post_id, 'post_tag' );
            if ( ! empty( $post_tags ) && ! is_wp_error( $post_tags ) ) {
                $tags = wp_list_pluck( $post_tags, 'name' );
            }
            $post_tags = implode(', ', $tags);
            $post_tags_y = 340;
            if ( '' === trim($title_second_line) ) {
                $post_tags_y = 280;
            }
            $post_date = get_the_date('d.m.Y');
            $post_author = get_user_by('ID', $post->post_author);
            $author_display_name = $post_author->display_name;
            $author_avatar_url = get_avatar_url($post->post_author, ['size' => 40]);
            
            header("Content-Type: image/png");
                
            $blank_background_url = get_stylesheet_directory() . '/assets/images/bg-ogimage-blank.png';
            $logo_url = get_stylesheet_directory() . '/assets/images/logo.png';
            $im = imagecreatefrompng($blank_background_url) or die("Cannot Initialize new GD image stream");
            $logo = imagecreatefrompng($logo_url);
            imagecopy($im, $logo, 1060, 40, 0, 0, 70, 70);
            $author_avatar = imagecreatefrompng($author_avatar_url);
            imagecopy($im, $author_avatar, 390, 457, 0, 0, 40, 40);
            
            $emphasis_color = imagecolorallocate($im, 2, 1, 22);
            $purple = imagecolorallocate($im, 12, 9, 96);
            $poppins_light = get_stylesheet_directory() . '/assets/fonts/Poppins-Light.ttf';
            $poppins_medium = get_stylesheet_directory() . '/assets/fonts/Poppins-Medium.ttf';
            $poppins_semibold = get_stylesheet_directory() . '/assets/fonts/Poppins-SemiBold.ttf';
            $poppins_bold = get_stylesheet_directory() . '/assets/fonts/Poppins-Bold.ttf';
            
            imagettftext($im, 14, 0, 130, 150, $purple, $poppins_semibold, $post_categories);
            imagettftext($im, 32, 0, 130, 220, $emphasis_color, $poppins_bold, $title_first_line);
            imagettftext($im, 32, 0, 130, 280, $emphasis_color, $poppins_bold, $title_second_line);
            imagettftext($im, 22, 0, 130, $post_tags_y, $purple, $poppins_light, $post_tags);
            imagettftext($im, 12, 0, 130, 482, $emphasis_color, $poppins_medium, $post_date);
            imagettftext($im, 10, 0, 260, 482, $emphasis_color, $poppins_medium, 'geschrieben von');
            imagettftext($im, 10, 0, 450, 482, $emphasis_color, $poppins_bold, $author_display_name);
            imagepng($im);
            imagedestroy($im);
            imagedestroy($logo);
            exit;
        }
    }

    geschrieben von

    Autor Avatar
    Julian Lang

    ist PHP / WordPress Entwickler. Arbeitet außerdem als Allrounder bei docrelations.de und entwickelt zwei coole Projekte: jadento.de | lifeisabinge.com

    Schreibe einen Kommentar

    © 2015 - 2022 | Julian Lang Webentwickler | WordPress Entwickler | Webdesigner in Bayreuth und Umgebung