1fdb4710bSMark Prins<?php 2*89906951SMark Prins 3635a5e2dSMark Prins/* 4fdb4710bSMark Prins * Copyright (c) 2013 Mark C. Prins <mprins@users.sf.net> 5fdb4710bSMark Prins * 6fdb4710bSMark Prins * Permission to use, copy, modify, and distribute this software for any 7fdb4710bSMark Prins * purpose with or without fee is hereby granted, provided that the above 8fdb4710bSMark Prins * copyright notice and this permission notice appear in all copies. 9fdb4710bSMark Prins * 10fdb4710bSMark Prins * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11fdb4710bSMark Prins * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12fdb4710bSMark Prins * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13fdb4710bSMark Prins * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14fdb4710bSMark Prins * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15fdb4710bSMark Prins * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16fdb4710bSMark Prins * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17635a5e2dSMark Prins */ 18635a5e2dSMark Prins 19635a5e2dSMark Prins/** 20*89906951SMark Prins * DokuWiki Plugin socialcards (Action Component). 21fdb4710bSMark Prins * 22635a5e2dSMark Prins * @license BSD license 23fdb4710bSMark Prins * @author Mark C. Prins <mprins@users.sf.net> 24fdb4710bSMark Prins */ 25*89906951SMark Prinsif (!defined('DOKU_INC')) 26*89906951SMark Prins die(); 27*89906951SMark Prinsif (!defined('DOKU_PLUGIN')) 28*89906951SMark Prins define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 29fdb4710bSMark Prins 30fdb4710bSMark Prinsrequire_once DOKU_PLUGIN . 'action.php'; 31fdb4710bSMark Prins 32fdb4710bSMark Prinsclass action_plugin_socialcards extends DokuWiki_Action_Plugin { 33fdb4710bSMark Prins 34fdb4710bSMark Prins public function register(Doku_Event_Handler &$controller) { 35*89906951SMark Prins $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 36*89906951SMark Prins 'handle_tpl_metaheader_output'); 37fdb4710bSMark Prins } 38fdb4710bSMark Prins 39fdb4710bSMark Prins /** 40*89906951SMark Prins * Retrieve metadata and add to the head of the page using appropriate meta 41*89906951SMark Prins * tags. 42*89906951SMark Prins * 43*89906951SMark Prins * @global string $ID page id 44*89906951SMark Prins * @global array $conf global wiki configuration 45*89906951SMark Prins * @global array $INFO 46fdb4710bSMark Prins * @param Doku_Event $event the DokuWiki event. $event->data is a two-dimensional 47fdb4710bSMark Prins * array of all meta headers. The keys are meta, link and script. 48*89906951SMark Prins * @param unknown_type $param the parameters passed to register_hook when this 49*89906951SMark Prins * handler was registered 50*89906951SMark Prins * 51*89906951SMark Prins * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output 52fdb4710bSMark Prins */ 53fdb4710bSMark Prins public function handle_tpl_metaheader_output(Doku_Event &$event, $param) { 54*89906951SMark Prins global $ID, $conf, $INFO; 55fdb4710bSMark Prins 56fdb4710bSMark Prins // twitter card, see https://dev.twitter.com/docs/cards 57*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:card', 58*89906951SMark Prins 'content' => "summary",); 59*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:url', 60*89906951SMark Prins 'content' => wl($ID, '', true),); 61*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:title', 62*89906951SMark Prins 'content' => p_get_metadata($ID, 'title', true),); 63aeb704feSMark Prins $desc = p_get_metadata($ID, 'description', true); 64aeb704feSMark Prins if (!empty($desc)) { 65*89906951SMark Prins $desc = str_replace("\n", " ", $desc['abstract']); 66fc03d0b3SMark Prins $event->data['meta'][] = array('name' => 'twitter:description', 67*89906951SMark Prins 'content' => $desc,); 68fc03d0b3SMark Prins } 69*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:site', 70*89906951SMark Prins 'content' => $this->getConf('twitterName'),); 71fdb4710bSMark Prins //twitter:site:id 72*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:creator', 73*89906951SMark Prins 'content' => $this->getConf('twitterName'),); 74fdb4710bSMark Prins //twitter:creator:id 75*89906951SMark Prins $event->data['meta'][] = array('name' => 'twitter:image', 76*89906951SMark Prins 'content' => $this->getImage(),); 77*89906951SMark Prins 78*89906951SMark Prins // opengraph, see http://ogp.me/ 79*89906951SMark Prins // 80*89906951SMark Prins // to make this work properly the template should be modified adding the 81*89906951SMark Prins // namespaces for a (x)html 4 template make html tag: 82*89906951SMark Prins // 83*89906951SMark Prins // <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="nl" lang="nl" 84*89906951SMark Prins // xmlns:og="http://ogp.me/ns#" xmlns:fb="http://ogp.me/ns/fb#" 85*89906951SMark Prins // xmlns:article="http://ogp.me/ns/article#" xmlns:place="http://ogp.me/ns/place#"> 86*89906951SMark Prins // 87*89906951SMark Prins // and for a (x)html 5 template make head tag: 88*89906951SMark Prins // 89*89906951SMark Prins // <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article# place: http://ogp.me/ns/place#"> 90*89906951SMark Prins 91*89906951SMark Prins // og namespace http://ogp.me/ns# 92*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:locale', 93*89906951SMark Prins 'content' => $this->getConf('languageTerritory'),); 94*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:site_name', 95*89906951SMark Prins 'content' => $conf['title'],); 96*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:url', 97*89906951SMark Prins 'content' => wl($ID, '', true),); 98*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:title', 99*89906951SMark Prins 'content' => p_get_metadata($ID, 'title', true),); 100*89906951SMark Prins if (!empty($desc)) { 101*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:description', 102*89906951SMark Prins 'content' => $desc,); 103fdb4710bSMark Prins } 104*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:type', 105*89906951SMark Prins 'content' => "article",); 106*89906951SMark Prins $event->data['meta'][] = array('property' => 'og:image', 107*89906951SMark Prins 'content' => $this->getImage(),); 108*89906951SMark Prins 109*89906951SMark Prins // article namespace http://ogp.me/ns/article# 110*89906951SMark Prins $_dates = p_get_metadata($ID, 'date', true); 111*89906951SMark Prins $event->data['meta'][] = array('property' => 'article:published_time', 112*89906951SMark Prins 'content' => dformat($_dates['created']),); 113*89906951SMark Prins $event->data['meta'][] = array('property' => 'article:modified_time', 114*89906951SMark Prins 'content' => dformat($_dates['modified']),); 115*89906951SMark Prins $event->data['meta'][] = array('property' => 'article:author', 116*89906951SMark Prins 'content' => $INFO['editor'],); 117*89906951SMark Prins //$event->data['meta'][] = array('property' => 'article:author','content' => p_get_metadata($ID,'creator',true),); 118*89906951SMark Prins //$event->data['meta'][] = array('property' => 'article:author','content' => p_get_metadata($ID,'user',true),); 119*89906951SMark Prins $_subject = p_get_metadata($ID, 'subject', true); 120*89906951SMark Prins if (!empty($_subject)) { 121*89906951SMark Prins if (!is_array($_subject)) { 122*89906951SMark Prins $_subject = array($_subject); 123*89906951SMark Prins } 124*89906951SMark Prins foreach ($_subject as $tag) { 125*89906951SMark Prins $event->data['meta'][] = array('property' => 'article:tag', 126*89906951SMark Prins 'content' => $tag,); 127*89906951SMark Prins } 128*89906951SMark Prins } 129*89906951SMark Prins 130*89906951SMark Prins // place namespace http://ogp.me/ns/place# 131*89906951SMark Prins $geotags = p_get_metadata($ID, 'geo', true); 132*89906951SMark Prins $lat = $geotags['lat']; 133*89906951SMark Prins $lon = $geotags['lon']; 134*89906951SMark Prins if (!(empty($lat) && empty($lon))) { 135*89906951SMark Prins $event->data['meta'][] = array('property' => 'place:location:latitude', 136*89906951SMark Prins 'content' => $lat,); 137*89906951SMark Prins $event->data['meta'][] = array('property' => 'place:location:longitude', 138*89906951SMark Prins 'content' => $lon,); 139*89906951SMark Prins } 140*89906951SMark Prins 141*89906951SMark Prins /* these may not be valid.. 142*89906951SMark Prins $region=$geotags['region']; 143*89906951SMark Prins $country=$geotags['country']; 144*89906951SMark Prins $placename=$geotags['placename']; 145*89906951SMark Prins if (!empty($region)) {$event->data['meta'][] = array('property' => 'place:location:region', 'content' => $region,);} 146*89906951SMark Prins if (!empty($placename)) {$event->data['meta'][] = array('property' => 'place:location:locality', 'content' => $placename,);} 147*89906951SMark Prins if (!empty($country)) {$event->data['meta'][] = array('property' => 'place:location:country-name','content' => $country,);} 148*89906951SMark Prins */ 149*89906951SMark Prins 150*89906951SMark Prins // optional facebook app ID 151*89906951SMark Prins $appId = $this->getConf('fbAppId'); 152*89906951SMark Prins if (!empty($appId)) { 153*89906951SMark Prins $event->data['meta'][] = array('property' => 'fb:app_id', 154*89906951SMark Prins 'content' => $appId,); 155*89906951SMark Prins } 156*89906951SMark Prins } 157*89906951SMark Prins 158*89906951SMark Prins /** 159*89906951SMark Prins * Gets the canonical image path for this page. 160*89906951SMark Prins * 161*89906951SMark Prins * @global string $ID page id 162*89906951SMark Prins * @return string the url to the image to use for this page 163*89906951SMark Prins */ 164*89906951SMark Prins private function getImage() { 165*89906951SMark Prins global $ID; 166*89906951SMark Prins $rel = p_get_metadata($ID, 'relation', true); 167*89906951SMark Prins $img = $rel['firstimage']; 168*89906951SMark Prins if (!empty($img)) { 169*89906951SMark Prins return ml($img, array(), true, '&', true); 170*89906951SMark Prins } else { 171*89906951SMark Prins return $this->getConf('fallbackImage'); 172*89906951SMark Prins } 173*89906951SMark Prins } 174*89906951SMark Prins 175fdb4710bSMark Prins} 176