xref: /plugin/socialcards/action.php (revision e0737b20e11626c0820b95618333f1e92802bee4)
1fdb4710bSMark Prins<?php
289906951SMark 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
19ae2f5c78SMark Prins
20*e0737b20SMark Prinsif (!defined('DOKU_INC')){
2189906951SMark Prins	die();
22*e0737b20SMark Prins}
23*e0737b20SMark Prinsif (!defined('DOKU_PLUGIN')) {
2489906951SMark Prins	define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
25*e0737b20SMark Prins}
26fdb4710bSMark Prins
27fdb4710bSMark Prinsrequire_once DOKU_PLUGIN . 'action.php';
28ae2f5c78SMark Prins/**
29ae2f5c78SMark Prins * DokuWiki Plugin socialcards (Action Component).
30ae2f5c78SMark Prins *
31ae2f5c78SMark Prins * @license BSD license
32ae2f5c78SMark Prins * @author  Mark C. Prins <mprins@users.sf.net>
33ae2f5c78SMark Prins */
34fdb4710bSMark Prinsclass action_plugin_socialcards extends DokuWiki_Action_Plugin {
35fdb4710bSMark Prins
36ae2f5c78SMark Prins	/**
37ae2f5c78SMark Prins	 * Register our callback for the TPL_METAHEADER_OUTPUT event.
38ae2f5c78SMark Prins	 *
39ae2f5c78SMark Prins	 * @param $controller Doku_Event_Handler
40ae2f5c78SMark Prins	 * @see DokuWiki_Action_Plugin::register()
41ae2f5c78SMark Prins	 */
42ae2f5c78SMark Prins	public function register(Doku_Event_Handler $controller) {
4389906951SMark Prins		$controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this,
4489906951SMark Prins				'handle_tpl_metaheader_output');
45fdb4710bSMark Prins	}
46fdb4710bSMark Prins
47fdb4710bSMark Prins	/**
4889906951SMark Prins	 * Retrieve metadata and add to the head of the page using appropriate meta
49156465eeSMark Prins	 * tags unless the page does not exist.
5089906951SMark Prins	 *
5189906951SMark Prins	 * @global string $ID page id
5289906951SMark Prins	 * @global array $conf global wiki configuration
5389906951SMark Prins	 * @global array $INFO
54fdb4710bSMark Prins	 * @param Doku_Event $event the DokuWiki event. $event->data is a two-dimensional
55fdb4710bSMark Prins	 *             array of all meta headers. The keys are meta, link and script.
5689906951SMark Prins	 * @param unknown_type $param the parameters passed to register_hook when this
5789906951SMark Prins	 *             handler was registered
5889906951SMark Prins	 *
5989906951SMark Prins	 * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
60fdb4710bSMark Prins	 */
61fdb4710bSMark Prins	public function handle_tpl_metaheader_output(Doku_Event &$event, $param) {
6289906951SMark Prins		global $ID, $conf, $INFO;
63fdb4710bSMark Prins
64*e0737b20SMark Prins		if (!page_exists($ID)) { return; }
65156465eeSMark Prins
66fdb4710bSMark Prins		// twitter card, see https://dev.twitter.com/docs/cards
6789906951SMark Prins		$event->data['meta'][] = array('name' => 'twitter:card',
6889906951SMark Prins				'content' => "summary",);
6989906951SMark Prins		$event->data['meta'][] = array('name' => 'twitter:url',
7089906951SMark Prins				'content' => wl($ID, '', true),);
7189906951SMark Prins		$event->data['meta'][] = array('name' => 'twitter:title',
7289906951SMark Prins				'content' => p_get_metadata($ID, 'title', true),);
73aeb704feSMark Prins		$desc = p_get_metadata($ID, 'description', true);
74aeb704feSMark Prins		if (!empty($desc)) {
7589906951SMark Prins			$desc = str_replace("\n", " ", $desc['abstract']);
76fc03d0b3SMark Prins			$event->data['meta'][] = array('name' => 'twitter:description',
7789906951SMark Prins					'content' => $desc,);
78fc03d0b3SMark Prins		}
7989906951SMark Prins		$event->data['meta'][] = array('name' => 'twitter:site',
8089906951SMark Prins				'content' => $this->getConf('twitterName'),);
81fdb4710bSMark Prins		//twitter:site:id
82*e0737b20SMark Prins		if ($this->getConf('twitterUserName') != '') {
8389906951SMark Prins			$event->data['meta'][] = array('name' => 'twitter:creator',
84*e0737b20SMark Prins				'content' => $this->getConf('twitterUserName'),);
85*e0737b20SMark Prins		}
86fdb4710bSMark Prins		//twitter:creator:id
87*e0737b20SMark Prins		$event->data['meta'][] = array('name' => 'twitter:image:src',
8889906951SMark Prins				'content' => $this->getImage(),);
8989906951SMark Prins
9089906951SMark Prins		// opengraph, see http://ogp.me/
9189906951SMark Prins		//
9289906951SMark Prins		// to make this work properly the template should be modified adding the
9389906951SMark Prins		// namespaces for a (x)html 4 template make html tag:
9489906951SMark Prins		//
9589906951SMark Prins		// <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="nl" lang="nl"
9689906951SMark Prins		//		xmlns:og="http://ogp.me/ns#" xmlns:fb="http://ogp.me/ns/fb#"
9789906951SMark Prins		//		xmlns:article="http://ogp.me/ns/article#" xmlns:place="http://ogp.me/ns/place#">
9889906951SMark Prins		//
9989906951SMark Prins		// and for a (x)html 5 template make head tag:
10089906951SMark Prins		//
10189906951SMark 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#">
10289906951SMark Prins
10389906951SMark Prins		// og namespace http://ogp.me/ns#
10489906951SMark Prins		$event->data['meta'][] = array('property' => 'og:locale',
10589906951SMark Prins				'content' => $this->getConf('languageTerritory'),);
10689906951SMark Prins		$event->data['meta'][] = array('property' => 'og:site_name',
10789906951SMark Prins				'content' => $conf['title'],);
10889906951SMark Prins		$event->data['meta'][] = array('property' => 'og:url',
10989906951SMark Prins				'content' => wl($ID, '', true),);
11089906951SMark Prins		$event->data['meta'][] = array('property' => 'og:title',
11189906951SMark Prins				'content' => p_get_metadata($ID, 'title', true),);
11289906951SMark Prins		if (!empty($desc)) {
11389906951SMark Prins			$event->data['meta'][] = array('property' => 'og:description',
11489906951SMark Prins					'content' => $desc,);
115fdb4710bSMark Prins		}
11689906951SMark Prins		$event->data['meta'][] = array('property' => 'og:type',
11789906951SMark Prins				'content' => "article",);
11889906951SMark Prins		$event->data['meta'][] = array('property' => 'og:image',
11989906951SMark Prins				'content' => $this->getImage(),);
12089906951SMark Prins
12189906951SMark Prins		// article namespace http://ogp.me/ns/article#
12289906951SMark Prins		$_dates = p_get_metadata($ID, 'date', true);
12389906951SMark Prins		$event->data['meta'][] = array('property' => 'article:published_time',
12489906951SMark Prins				'content' => dformat($_dates['created']),);
12589906951SMark Prins		$event->data['meta'][] = array('property' => 'article:modified_time',
12689906951SMark Prins				'content' => dformat($_dates['modified']),);
12789906951SMark Prins		$event->data['meta'][] = array('property' => 'article:author',
12889906951SMark Prins				'content' => $INFO['editor'],);
12989906951SMark Prins		// $event->data['meta'][] = array('property' => 'article:author','content' => p_get_metadata($ID,'creator',true),);
13089906951SMark Prins		// $event->data['meta'][] = array('property' => 'article:author','content' => p_get_metadata($ID,'user',true),);
13189906951SMark Prins		$_subject = p_get_metadata($ID, 'subject', true);
13289906951SMark Prins		if (!empty($_subject)) {
13389906951SMark Prins			if (!is_array($_subject)) {
13489906951SMark Prins				$_subject = array($_subject);
13589906951SMark Prins			}
13689906951SMark Prins			foreach ($_subject as $tag) {
13789906951SMark Prins				$event->data['meta'][] = array('property' => 'article:tag',
13889906951SMark Prins						'content' => $tag,);
13989906951SMark Prins			}
14089906951SMark Prins		}
14189906951SMark Prins
14289906951SMark Prins		// place namespace http://ogp.me/ns/place#
14389906951SMark Prins		$geotags = p_get_metadata($ID, 'geo', true);
14489906951SMark Prins		$lat = $geotags['lat'];
14589906951SMark Prins		$lon = $geotags['lon'];
14689906951SMark Prins		if (!(empty($lat) && empty($lon))) {
14789906951SMark Prins			$event->data['meta'][] = array('property' => 'place:location:latitude',
14889906951SMark Prins					'content' => $lat,);
14989906951SMark Prins			$event->data['meta'][] = array('property' => 'place:location:longitude',
15089906951SMark Prins					'content' => $lon,);
151ae2f5c78SMark Prins			// place:location:altitude (string) Altitude of location, facebook wants feet...
15289906951SMark Prins		}
15389906951SMark Prins
154ae2f5c78SMark Prins		/* these are not valid for the GeoPoint type..
155ae2f5c78SMark Prins
15689906951SMark Prins		$region=$geotags['region'];
15789906951SMark Prins		$country=$geotags['country'];
15889906951SMark Prins		$placename=$geotags['placename'];
15989906951SMark Prins		if (!empty($region))    {$event->data['meta'][] = array('property' => 'place:location:region',		'content' => $region,);}
16089906951SMark Prins		if (!empty($placename)) {$event->data['meta'][] = array('property' => 'place:location:locality',	'content' => $placename,);}
16189906951SMark Prins		if (!empty($country))   {$event->data['meta'][] = array('property' => 'place:location:country-name','content' => $country,);}
16289906951SMark Prins		*/
16389906951SMark Prins
16489906951SMark Prins		// optional facebook app ID
16589906951SMark Prins		$appId = $this->getConf('fbAppId');
16689906951SMark Prins		if (!empty($appId)) {
16789906951SMark Prins			$event->data['meta'][] = array('property' => 'fb:app_id',
16889906951SMark Prins					'content' => $appId,);
16989906951SMark Prins		}
17089906951SMark Prins	}
17189906951SMark Prins
17289906951SMark Prins	/**
17389906951SMark Prins	 * Gets the canonical image path for this page.
17489906951SMark Prins	 *
17589906951SMark Prins	 * @global string $ID page id
17689906951SMark Prins	 * @return string the url to the image to use for this page
17789906951SMark Prins	 */
17889906951SMark Prins	private function getImage() {
17989906951SMark Prins		global $ID;
18089906951SMark Prins		$rel = p_get_metadata($ID, 'relation', true);
18189906951SMark Prins		$img = $rel['firstimage'];
182ae2f5c78SMark Prins
183ae2f5c78SMark Prins		if (empty($img)) {
18493bf3c56SMark Prins			$img = $this->getConf('fallbackImage');
18593bf3c56SMark Prins			if (substr($img, 0, 4 ) === "http") {
186ae2f5c78SMark Prins				// don't use ml() as this results in a HTTP redirect after hitting the wiki
18793bf3c56SMark Prins				return $img;
18893bf3c56SMark Prins			}
18993bf3c56SMark Prins		}
190ae2f5c78SMark Prins
191ae2f5c78SMark Prins		return ml($img, array(), true, '&amp;', true);
19289906951SMark Prins	}
19389906951SMark Prins
194fdb4710bSMark Prins}
195