Ich habe schon länger Metaangaben für die Crawler von Twitter und Facebook hier im Blog, wenn ein einzelner Artikel aufgerufen wird. Damit kann ich *etwas* steuern, was diese Plattformen sich aus dem Inhalt des Artikels rausziehen und als Teaser verwenden, wenn eine Artikel-URL dort geteilt wird. Also welches Bild als Thumbnail genommen wird, welcher Titel und welche Beschreibung zum Beispiel.

Das Ganze ist relativ simpel, Facebook nutzt sein "OpenGraph" Protokoll und Twitter kann einen Teil der "OpenGraph" Angaben nutzen oder man nimmt gleich die Twitter Cards Schreibweise. Die Angaben sollten im head Bereich des Quelltextes stehen.

In der header.php meines Themes habe ich diesen Abschnitt (achtung, Spaghetticode-Alarm, munteres Durchmischen von php und html Abschnitten voraus - auf meiner To-Do Liste steht schon ewig, das mal zu konsolidieren und in eine saubere Funktion in der functions.php zu packen, oder es total WordPress-konform mit Hooks machen, die in das WP-head Zeugs eingreifen. *hust.):

(...)
< ?php if(is_singular()){
	$card_type = 'summary';
	$format = get_post_format();
	if( $format == 'image' ){
		$card_type = 'summary_large_image';
	}
?>
	<!-- Start Twitter Cards -->
	<meta name="twitter:card" content="<?php echo $card_type; ?/>" />
	<meta name="twitter:site" content="@webrocker" />
	<meta name="twitter:title" content="<?php the_title() ?/>" />
	<meta name="twitter:description" content="<?php echo og_meta_desc(); ?/>" />
 < ?php if( wbr_get_teaser_image($post) ){
	$img = wbr_get_teaser_image($post);
	echo '<meta name="twitter:image" content="' . $img['url']. '" />' ."\n";
	if(isset($img['alt']) && $img['alt']!=''){
		echo '<meta name="twitter:image:alt" content="' . $img['alt']. '" />' . "\n";
	}
?>
 
 < ?php } ?>
	<!-- End Twitter Cards -->
	<!-- Start Facebook Opengraph -->
	<meta property="og:type" content="article"/>
	<meta property="og:title" content="<?php the_title() ?/>"/>
	<meta property="og:site_name" content="Webrocker - Blog"/>
	<meta property="og:description" content="<?php echo og_meta_desc(); ?/>" />
	<meta property="og:url" content="<?php the_permalink() ?/>"/>
 < ?php if( $img ){ ?>
	<meta property="og:image" content="<?php echo $img['url'] ?/>"/>
 < ?php } ?>
	<!-- End Facebook Opengraph -->
(...)

Im Grunde also erstmal nichts Besonderes, es werden der Beitragstitel, der Link zum Beitrag, ein Bild und eine Beschreibung des Artikels den entsprechenden Meta-Tags der beiden Plattformen zugeordnet.

Weil Twitter verschiedene Arten von "Cards" anbietet, habe ich erstmal eine Abfrage, ob es sich bei dem momentanen Beitrag um einen mit Post-Format "image" handelt. Falls ja, möchte ich gerne eine bildlastigere Twitter-Card (summary_large_image) verwenden, ansonsten die kleinere "summary" card:

 < ?php if(is_singular()){
	$card_type = 'summary';
	$format = get_post_format();
	if( $format == 'image' ){
		$card_type = 'summary_large_image';
	}
?>
	<!-- Start Twitter Cards -->
	<meta name="twitter:card" content="<?php echo $card_type; ?/>" />
(...)

Für die Beschreibung habe ich mir eine Funktion geschrieben, die in der functions.php meines Themes wohnt, und deren Rückgabewert in die beiden "description" Metatags von Twitter und Facebook kommt:

(...)
<meta name="twitter:description" content="<?php echo og_meta_desc(); ?/>" />
(...)
<meta property="og:description" content="<?php echo og_meta_desc(); ?/>" />
(...)

Die Funktion ist noch Work-In-Progress; da ich so gut wie nie das WordPress-interne "Beschreibung"s-Feld nutze, hole ich mir mit der Funktion einen Auszug aus dem normalen Inhalt des Artikels, bereinigt um alle html-Tags und Zeilenumbrüche und gekürzt auf 200 Zeichen, und ggf. mit einer Ellipsis versehen, falls der Originaltext länger ist, als das Zeichen-Limit:

function og_meta_desc($limit=200) {
	 global $post;
	 $meta = strip_tags($post->post_content);
	 $meta = str_replace(array("\n", "\r", "\t", "&nbsp;"), ' ',$meta);
	 $meta = preg_replace('/\s+/',' ',$meta);
	 $meta = trim($meta);
	 if( mb_strlen($meta) > $limit-2 ){
	 	if( substr($meta,-1) != '.' ){
	 		$cut = strrpos($meta,' ');
	 	} else {
	 		$cut = $limit-2;
	 	}
	 	$meta = substr($meta, 0, $cut);
	 	$meta .= ' …';
	 }
	 return htmlspecialchars($meta);
 }

Der nächste Abschnitt ist für die Verwendung einer Bildvorschau zuständig, und auch hier nutze ich eine eigene Funktion, um an die benötigten Daten zu kommen:

 < ?php if( wbr_get_teaser_image($post) ){
	$img = wbr_get_teaser_image($post);
	echo '<meta name="twitter:image" content="' . $img['url']. '" />' ."\n";
	if(isset($img['alt']) && $img['alt']!=''){
		echo '<meta name="twitter:image:alt" content="' . $img['alt']. '" />' . "\n";
	}
?>
(...)
 < ?php if( $img ){ ?>
	<meta property="og:image" content="<?php echo $img['url'] ?/>"/>
 < ?php } ?>

Die Funktion macht eigentlich nichts anderes als zu schauen, ob es zu dem Artikel ein "Featured Image" gibt. Falls ja, wird die URL und ein evtl. vorhandener Alternativ-Text zum Bild zurück gegeben. Twitter bietet seit Kurzem die Möglichkeit, Alternativ-Texte anzugeben, seit heute habe ich diese Funktion dahingehend angepasst.
Ist kein "Featured Image" angegeben, kuckt die Funktion, ob im Inhalt des Artikels ein Bild angegeben ist, und gibt dessen URL zurück. Hier habe ich vor, das noch so umzubauen, dass das WordPress-interne Post-Attachment Zeug gecheckt wird, statt einfach nur zu kucken, ob ein Pfad zum Bild im Inhalt steht. Für den Moment bleibt es aber erstmal so :-). Wird kein Bild gefunden, dann wird ein Platzhalterbild verwendet. Da ich seit kurzem die Seite über https ausliefere, mache ich auch hier noch einen Check, ob die Bild-URL mit http angegeben wurde und passe sie auf https an:

function wbr_get_teaser_image($post){
	$postImage = false;
	// has the post a featured image?
	$featuredImageID = get_post_thumbnail_id($post->ID);
	if($featuredImageID){
		// url to image
		$featuredImageScr = wp_get_attachment_image_src($featuredImageID,'wbr-portrait');
		$postImage = array('url' => $featuredImageScr[0]);
		// alt text of image
		$alt_text = get_post_meta($featuredImageID , '_wp_attachment_image_alt', true);
		$postImage['alt'] = $alt_text;
	} else {
		// no, then look for the first image in post
		// @@TODO: use post_attachment?
		$first_img = '';
		ob_start();
		ob_end_clean();
		$output = preg_match_all('/<img .+src=[\'"]([^\'"]+)[\'"].*/>/i', $post->post_content, $matches);
		$first_img = $matches[1][0];
		if( empty($first_img) ){ //Defines a default image
			$first_img = 'https://www.webrocker.de/blog/wp-content/themes/wbr-theme/images/wbr-fb.png';
		} else {
			if(strpos($first_img,'https') === false){
				$first_img = str_replace('http','https',$first_img);
			}
		}
		$postImage = array('url'=>$first_img);
	}
	return $postImage;
}

Und schon klappt es mit den Twitter Cards und den Teasern innerhalb von Facebook, ganz ohne Plugin. (Ich habe nix gegen Plugins, und zugegebenermaßen sind die Funktionen in der functions.php ja quasi auch schon halbe Plugins, aber sich die Infos selbst so zusammenzuholen, wie man es braucht, macht einfach mehr Laune, als ein Plugin zu aktivieren und man lernt eine Menge, vor allem, wie es nicht klappt. ;-))

Und hey, Do It Yourself -- das ist doch mit der Hauptgrund, warum man hier in diesem Webgedöns rumrührt.