xref: /template/ad-hominem/my_template.php (revision 4095125c884dd51c8686cb5c1316901b5b6c2de0)
1<?php
2/**
3 * Overwriting DokuWiki template functions
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Sascha Leib <sascha@leib.be>
7 * @author     Andreas Gohr <andi@splitbrain.org>
8 */
9
10use dokuwiki\Extension\Event;
11use dokuwiki\File\PageResolver;
12
13/**
14 * Print the specific HTML meta headers
15 *
16 * Overrides the original version by modifying the headers and the way it is printed
17 *
18 * @author Sascha Leib <sascha@leib.be>
19 * @author Andreas Gohr <andi@splitbrain.org>
20 *
21 * @triggers TPL_METAHEADER_OUTPUT
22 * @param  bool $alt Should feeds and alternative format links be added?
23 * @return bool
24 */
25function my_metaheaders($alt = true) {
26    global $ID;
27    global $REV;
28    global $INFO;
29    global $JSINFO;
30    global $ACT;
31    global $QUERY;
32    global $lang;
33    global $conf;
34    global $updateVersion;
35    /** @var Input $INPUT */
36    global $INPUT;
37
38    // prepare the head array
39    $head = array();
40
41    // prepare seed for js and css
42    $tseed   = $updateVersion;
43    $depends = getConfigFiles('main');
44    $depends[] = DOKU_CONF."tpl/".$conf['template']."/style.ini";
45    foreach($depends as $f) $tseed .= @filemtime($f);
46    $tseed   = md5($tseed);
47
48	// Open Graph information
49	$meta = p_get_metadata($ID);
50	if ($meta['title'] !== null) {
51		$head['meta'][] = array('property' => 'og:title', 'content' => tpl_pagetitle($ID, true));
52		$head['meta'][] = array('property' => 'og:site_name ', 'content' => $conf['title']);
53		$head['meta'][] = array('property' => 'og:type', 'content' => 'website');
54		$head['meta'][] = array('property' => 'og:url', 'content' => wl($ID, '', true, '&'));
55
56		$parts = explode("\n", $meta['description']['abstract']);
57		$head['meta'][] = array('property' => 'og:description', 'content' => $parts[2]);
58
59		// Bing insists in a non-og description:
60		$head['meta'][] = array('property' => 'description', 'content' => $parts[2]);
61	}
62
63    // the usual stuff
64    $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki');
65    if(actionOK('search')) {
66        $head['link'][] = array(
67            'rel' => 'search', 'type'=> 'application/opensearchdescription+xml',
68            'href'=> DOKU_BASE.'lib/exe/opensearch.php', 'title'=> $conf['title']
69        );
70    }
71
72    $head['link'][] = array('rel'=> 'start', 'href'=> DOKU_BASE);
73    if(actionOK('index')) {
74        $head['link'][] = array(
75            'rel'  => 'contents', 'href'=> wl($ID, 'do=index', false, '&'),
76            'title'=> $lang['btn_index']
77        );
78    }
79
80    if (actionOK('manifest')) {
81        $head['link'][] = array('rel'=> 'manifest', 'href'=> DOKU_BASE.'lib/exe/manifest.php');
82    }
83
84    $styleUtil = new \dokuwiki\StyleUtils();
85    $styleIni = $styleUtil->cssStyleini();
86    $replacements = $styleIni['replacements'];
87    if (!empty($replacements['__theme_color__'])) {
88        $head['meta'][] = array('name' => 'theme-color', 'content' => $replacements['__theme_color__']);
89    }
90
91    if($alt) {
92        if(actionOK('rss')) {
93            $head['link'][] = array(
94                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
95                'title'=> $lang['btn_recent'], 'href'=> DOKU_BASE.'feed.php'
96            );
97            $head['link'][] = array(
98                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
99                'title'=> $lang['currentns'],
100                'href' => DOKU_BASE.'feed.php?mode=list&ns='.(isset($INFO) ? $INFO['namespace'] : '')
101            );
102        }
103        if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']) {
104            $head['link'][] = array(
105                'rel'  => 'edit',
106                'title'=> $lang['btn_edit'],
107                'href' => wl($ID, 'do=edit', false, '&')
108            );
109        }
110
111        if(actionOK('rss') && $ACT == 'search') {
112            $head['link'][] = array(
113                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
114                'title'=> $lang['searchresult'],
115                'href' => DOKU_BASE.'feed.php?mode=search&q='.$QUERY
116            );
117        }
118
119        if(actionOK('export_xhtml')) {
120            $head['link'][] = array(
121                'rel' => 'alternate', 'type'=> 'text/html', 'title'=> $lang['plainhtml'],
122                'href'=> exportlink($ID, 'xhtml', '', false, '&')
123            );
124        }
125
126        if(actionOK('export_raw')) {
127            $head['link'][] = array(
128                'rel' => 'alternate', 'type'=> 'text/plain', 'title'=> $lang['wikimarkup'],
129                'href'=> exportlink($ID, 'raw', '', false, '&')
130            );
131        }
132    }
133
134    // setup robot tags apropriate for different modes
135    if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
136        if($INFO['exists']) {
137            //delay indexing:
138            if((time() - $INFO['lastmod']) >= $conf['indexdelay'] && !isHiddenPage($ID) ) {
139                $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
140            } else {
141                $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
142            }
143            $canonicalUrl = wl($ID, '', true, '&');
144            if ($ID == $conf['start']) {
145                $canonicalUrl = DOKU_URL;
146            }
147            $head['link'][] = array('rel'=> 'canonical', 'href'=> $canonicalUrl);
148        } else {
149            $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,follow');
150        }
151    } elseif(defined('DOKU_MEDIADETAIL')) {
152        $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
153    } else {
154        $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
155    }
156
157    // set metadata
158    if($ACT == 'show' || $ACT == 'export_xhtml') {
159        // keywords (explicit or implicit)
160        if(!empty($INFO['meta']['subject'])) {
161            $head['meta'][] = array('name'=> 'keywords', 'content'=> join(',', $INFO['meta']['subject']));
162        } else {
163            $head['meta'][] = array('name'=> 'keywords', 'content'=> str_replace(':', ',', $ID));
164        }
165    }
166
167    // load stylesheets
168    $head['link'][] = array(
169        'rel' => 'stylesheet',
170        'href'=> DOKU_BASE . 'lib/exe/css.php?t='.rawurlencode($conf['template']).'&tseed='.$tseed
171    );
172
173    $script = "var NS='".(isset($INFO)?$INFO['namespace']:'')."';\n\t\t";
174    if($conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
175        $script .= "var SIG=".toolbar_signature().";\n\t\t";
176    }
177
178    if($conf['basedir']) {
179        $script .= 'var BASEDIR="'.$conf['basedir']."\";\n\t\t";
180    }
181
182    jsinfo();
183    $script .= 'var JSINFO = ' . json_encode($JSINFO).';';
184    $head['script'][] = array('_data'=> $script);
185
186    // load jquery
187    $jquery = getCdnUrls();
188    foreach($jquery as $src) {
189        $head['script'][] = array(
190            /* 'charset' => 'utf-8', -- obsolete */
191            '_data' => '',
192            'src' => $src,
193        ) + ($conf['defer_js'] ? [ 'defer' => 'defer'] : []);
194    }
195
196    // load our javascript dispatcher
197    $head['script'][] = array(
198        /* 'charset'=> 'utf-8', -- obsolete */
199		'_data'=> '',
200        'src' => DOKU_BASE . 'lib/exe/js.php'.'?t='.rawurlencode($conf['template']).'&tseed='.$tseed,
201    ) + ($conf['defer_js'] ? [ 'defer' => 'defer'] : []);
202
203    // trigger event here
204    Event::createAndTrigger('TPL_METAHEADER_OUTPUT', $head, '_my_metaheaders_action', true);
205    return true;
206}
207
208/**
209 * prints the array build by my_metaheaders
210 *
211 * Overrides the original version by adding a tab before each line for neater HTML code
212 *
213 * @author Sascha Leib <sascha@leib.be>
214 * @author Andreas Gohr <andi@splitbrain.org>
215 *
216 * @param array $data
217 */
218function _my_metaheaders_action($data) {
219    foreach($data as $tag => $inst) {
220        foreach($inst as $attr) {
221            if ( empty($attr) ) { continue; }
222            echo "\t<", $tag, ' ', buildAttributes($attr);
223            if(isset($attr['_data']) || $tag == 'script') {
224                if($tag == 'script' && $attr['_data'])
225                    $attr['_data'] = "/*<![CDATA[*/".
226                        $attr['_data'].
227                        "\n/*!]]>*/";
228
229                echo '>', $attr['_data'], '</', $tag, '>';
230            } else {
231                echo '/>';
232            }
233            echo "\n";
234        }
235    }
236}
237
238/**
239 * get a link to the homepage.
240 *
241 * wraps the original wl() function to allow overriding in the options
242 *
243 * @author Sascha Leib <sascha@leib.be>
244 *
245 * @returns string (link)
246 */
247function my_homelink() {
248    global $conf;
249
250	$hl = trim(tpl_getConf('homelink'));
251
252	if ( $hl !== '' ) {
253		return $hl;
254	} else {
255		return wl(); // default homelink
256	}
257}
258
259/**
260 * Print the breadcrumbs trace
261 *
262 * Cleanup of the original code to create neater and more accessible HTML
263 *
264 * @author Sascha Leib <sascha@leib.be>
265 * @author Andreas Gohr <andi@splitbrain.org>
266 *
267 * @param string $prefix inserted before each line
268 *
269 * @return void
270 */
271function my_breadcrumbs($prefix = '') {
272    global $lang;
273    global $conf;
274
275    //check if enabled
276    if(!$conf['breadcrumbs']) return false;
277
278    $crumbs = breadcrumbs(); //setup crumb trace
279
280	/* begin listing */
281	echo $prefix . "<nav id=\"navBreadCrumbs\">\n";
282	echo $prefix . "\t<h4>" . $lang['breadcrumb'] . "</h4>\n";
283	echo $prefix . "\t<ol reversed>\n";
284
285    $last = count($crumbs);
286    $i    = 0;
287    foreach($crumbs as $id => $name) {
288        $i++;
289		echo $prefix . "\t\t<li" . ($i == $last ? ' class="current"' : '') . '><bdi>' . tpl_link(wl($id), hsc($name), '', true) .  "</bdi></li>\n";
290    }
291	echo $prefix . "\t</ol>\n";
292	echo $prefix . "</nav>\n";
293}
294
295/**
296 * Hierarchical breadcrumbs
297 *
298 * Cleanup of the original code to create neater and more accessible HTML
299 *
300 * @author Sascha Leib <sascha@leib.be>
301 * @author Andreas Gohr <andi@splitbrain.org>
302 * @author Nigel McNie <oracle.shinoda@gmail.com>
303 * @author Sean Coates <sean@caedmon.net>
304 * @author <fredrik@averpil.com>
305 *
306 * @param  string $prefix to be added before each line
307 *
308 */
309function my_youarehere($prefix = '') {
310    global $conf;
311    global $ID;
312    global $lang;
313
314    // check if enabled
315    if(!$conf['youarehere']) return false;
316
317    $parts = explode(':', $ID);
318    $count = count($parts);
319	$isdir = ( $parts[$count-1] == $conf['start']);
320
321	$hl = trim(tpl_getConf('homelink'));
322
323	echo $prefix . "<nav id=\"navYouAreHere\">\n";
324	echo $prefix . "\t<h4>" . $lang['youarehere'] . "</h4>\n";
325	echo $prefix . "\t<ol>\n";
326
327    // always print the startpage
328	if ( $hl !== '' ) {
329		echo $prefix . "\t\t<li class=\"home\">" . tpl_link( $hl, htmlentities(tpl_getLang('homepage')), ' title="' . htmlentities(tpl_getLang('homepage')) . '"', true) . "</li>\n";
330		echo $prefix . "\t\t<li>" . tpl_pagelink(':'.$conf['start'], null, true) . "</li>\n";
331	} else {
332		echo $prefix . "\t\t<li class=\"home\">" . tpl_pagelink(':'.$conf['start'], null, true) . "</li>\n";
333	}
334
335    // print intermediate namespace links
336    $page = '';
337    for($i = 0; $i < $count - 1; $i++) {
338        $part = $parts[$i];
339        $page .= $part . ':';
340
341		if ($i == $count-2 && $isdir)  break; // Skip last if it is an index page
342
343		echo $prefix . "\t\t<li>" . tpl_pagelink($page, null, true) . "</li>\n";
344    }
345
346    // chould the current page be included in the listing?
347	$trail = tpl_getConf('navtrail');
348
349	if ($trail !== 'none' && $trail !== '') {
350
351		echo $prefix . "\t\t<li class=\"current\">";
352		if ($trail == 'text') {
353			echo tpl_pagetitle($page . $parts[$count-1], true);
354		} else if ($trail == 'link') {
355			echo tpl_pagelink($page . $parts[$count-1], null, true);
356		}
357		echo "</li>\n";
358	}
359
360	echo $prefix . "\t</ol>\n";
361	echo $prefix . "</nav>\n";
362}
363
364/**
365 * My implementation of the basic userinfo (in the global banner)
366 *
367 *
368 * @author Sascha Leib <sascha@leib.be>
369 *
370 * @param  string $prefix to be added before each line
371 *
372 * @return void
373 */
374function my_userinfo($prefix = '') {
375    global $lang;
376    global $INPUT;
377
378	// add login/logout button:
379	$items = (new \dokuwiki\Menu\UserMenu())->getItems();
380	foreach($items as $it) {
381		$typ = $it->getType();
382
383		if ($typ === 'profile') { // special case for user profile:
384
385			echo $prefix . '<li class="action profile"><span class="sronly">' . $lang['loggedinas'] .
386				' </span><a href="' . htmlentities($it->getLink()) . '" title="' . $it->getTitle() . '">' .
387				userlink() . "</a></li>\n";
388
389		} else {
390
391			echo $prefix . "<li class=\"action $typ\"><a href=\"" . htmlentities($it->getLink()) .
392				'" title="' . $it->getTitle() . '">' . ($typ === 'profile'? userlink() : $it->getLabel() ) .
393				"</a></li>\n";
394		}
395	}
396}
397
398/**
399 *Inserts a cleaner version of the TOC
400 *
401 * This is an update of the original function that renders the TOC directly.
402 *
403 * @author Sascha Leib <sascha@leib.be>
404 * @author Andreas Gohr <andi@splitbrain.org>
405 *
406 * @param  string $prefix to be added before each line
407 *
408 * @return void
409 */
410function my_toc($prefix = '') {
411    global $TOC;
412    global $ACT;
413    global $ID;
414    global $REV;
415    global $INFO;
416    global $conf;
417    global $lang;
418    $toc = array();
419
420    if(is_array($TOC)) {
421        // if a TOC was prepared in global scope, always use it
422        $toc = $TOC;
423    } elseif(($ACT == 'show' || substr($ACT, 0, 6) == 'export') && !$REV && $INFO['exists']) {
424        // get TOC from metadata, render if neccessary
425        $meta = p_get_metadata($ID, '', METADATA_RENDER_USING_CACHE);
426        if(isset($meta['internal']['toc'])) {
427            $tocok = $meta['internal']['toc'];
428        } else {
429            $tocok = true;
430        }
431        $toc = isset($meta['description']['tableofcontents']) ? $meta['description']['tableofcontents'] : null;
432        if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']) {
433            $toc = array();
434        }
435    } elseif($ACT == 'admin') {
436        // try to load admin plugin TOC
437        /** @var $plugin AdminPlugin */
438        if ($plugin = plugin_getRequestAdminPlugin()) {
439            $toc = $plugin->getTOC();
440            $TOC = $toc; // avoid later rebuild
441        }
442    }
443
444	/* Build the hierarchical list of headline links: */
445	if (count($toc) >= intval($conf['tocminheads'])) {
446		echo $prefix . "<aside id=\"toc\" class=\"toggle hide\">\n";
447		echo $prefix . "\t<h3 class=\"tg_button\" title=\"" . htmlentities($lang['toc']) . '"><span>' . htmlentities($lang['toc']) . "</span></h3>\n" . $prefix . "\t<div class=\"tg_content\">";
448		$level = intval("0");
449		foreach($toc as $it) {
450
451			$nl = intval($it['level']);
452			$cp = ($nl <=> $level);
453
454			if ($cp > 0) {
455				echo "\n" . $prefix . str_repeat("\t", $level*2 + 2) . "<ol>\n";
456			} else if ($cp < 0) {
457				echo "\n" . $prefix . str_repeat("\t", $level*2) . "</ol></li>\n";
458			} else {
459				echo "</li>\n";
460			}
461
462			$href = $it['link'] . ( $it['hid'] == '' ? '' : '#' . $it['hid'] );
463
464			echo $prefix . str_repeat("\t", $nl*2 + 1) . '<li><a href="' . $href . '">' . htmlentities($it['title']) . "</a>";
465			$level = $nl;
466		}
467
468		for ($i = $level-1; $i > 0; $i--) {
469			echo "</li>\n" . $prefix . str_repeat("\t", $i*2 + 1) . "</ol>";
470		}
471
472		echo "</li>\n" . $prefix . "\t\t</ol>\n" . $prefix . "\t</div>\n" . $prefix . "</aside>\n";
473	}
474}
475
476/**
477 * Print last change date
478 *
479 * @author Sascha Leib <sascha@leib.be>
480 *
481 * @param  string $prefix to be added before each line
482 *
483 * @return void
484 */
485function my_lastchange($prefix = '') {
486
487    global $lang;
488    global $INFO;
489
490	$format = '%Y-%m-%dT%T%z';	/* e.g. 2021-21-05T16:45:12+02:00 */
491
492	$date = $INFO['lastmod'];
493
494	echo $prefix . '<bdi>' . $lang['lastmod'] . "</bdi>\n";
495	echo $prefix . '<time datetime="' . strftime($format, $date) . '">' . dformat($date) . "</time>\n";
496
497	/* user name for last change (is this really interesting to the visitor?) */
498	/* echo $prefix .'<span class="editorname" tabindex="0">' . $lang['by'] . ' <bdi>' . editorinfo($INFO['editor']) . "</bdi></span>\n"; */
499}
500
501/**
502 * Returns a description list of the metatags of the current image
503 *
504 * @return string html of description list
505 */
506function my_img_meta($prefix = '') {
507    global $lang;
508
509	$format = '%Y-%m-%dT%T%z';	/* e.g. 2021-21-05T16:45:12+02:00 */
510
511    $tags = tpl_get_img_meta();
512
513    foreach($tags as $tag) {
514        $label = $lang[$tag['langkey']];
515        if(!$label) $label = $tag['langkey'] . ':';
516
517        echo $prefix . '<tr><th>'.$label.'</th><td>';
518        if ($tag['type'] == 'date') {
519            echo '<time datetime="' . strftime($format, $tag['value']) . '">' . dformat($tag['value']) . '</time>';
520        } else {
521            echo hsc($tag['value']);
522        }
523        echo "</td></tr>\n";
524    }
525}
526
527/**
528 * Creates the Site logo image link
529 *
530 */
531function my_sitelogo() {
532    global $conf;
533
534	// get logo either out of the template images folder or data/media folder
535	$logoSize = array();
536	$logo = tpl_getMediaFile(array(':logo.svg', ':wiki:logo.svg', ':logo.png', ':wiki:logo.png', 'images/sitelogo.svg'), false, $logoSize);
537	tpl_link( my_homelink(),
538		'<img src="'.$logo.'" ' . $logoSize[3] . ' alt="' . htmlentities($conf['title']) . '" />', 'accesskey="h" title="[H]" class="logo"');
539}
540
541/**
542 * Creates the various favicon and similar links:
543 *
544 * @param  string $color overwrite the theme color.
545 *
546 * @return null
547 */
548function my_favicons($color = null) {
549
550	$logoSize = array();
551
552	// Theme color:
553	if ($color == null) {
554
555		/* get the style config */
556		$styleUtil = new \dokuwiki\StyleUtils();
557		$styleIni = $styleUtil->cssStyleini();
558		$replacements = $styleIni['replacements'];
559		$color = $replacements['__theme_color__'];
560
561		if ($color== null) { $color = '#2b73b7'; }
562	}
563	echo "\t<meta name=\"theme-color\" content=\"" . $color . "\" />\n";
564
565	// get the favicon:
566	$link = tpl_getMediaFile(array(':favicon.ico', ':favicon.png', ':favicon.svg', ':wiki:favicon.ico', ':wiki:favicon.png', ':wiki:favicon.svg'), false, $logoSize);
567	echo "\t<link rel=\"icon\" href=\"" . $link . "\" />\n";
568
569	// Apple Touch Icon
570	$logoSize = array();
571	$link = tpl_getMediaFile(array(':apple-touch-icon.png', ':wiki:apple-touch-icon.png', 'images/apple-touch-icon.png'), false, $logoSize);
572	echo "\t<link rel=\"apple-touch-icon\" href=\"" . $link . "\" />\n";
573
574}
575
576/**
577 * inserts the Cookies banner, if appropriate.
578 * This is based on Michal Koutny’s "cookielaw" plugin
579 *
580 * @param  string $prefix to be added before each line
581 */
582function my_cookiebanner($prefix = '') {
583
584	// get the configuration settings:
585	$msg = tpl_getConf('cookiemsg', '(no message configured)');
586	$position = tpl_getConf('cookiepos', 'bottom');
587	$link = tpl_getConf('cookielink', 'about:cookies');
588
589	// if the cookie is already set or position is set to hide, do nothing.
590	if ( isset($_COOKIE['cookielaw']) or $position == 'hide') {
591		return;
592	}
593
594	// output the HTML code:
595	echo $prefix . "<div id=\"cookiebanner\" class=\"cb_" . $position . "\">\n";
596	echo $prefix . "\t<p class=\"cb_info\"><span class=\"cb_icon\"></span>\n";
597	echo $prefix . "\t\t<span class=\"cb_msg\">". $msg . "</span>\r";
598	echo $prefix . "\t</p>\n";
599	echo $prefix . "\t<p class=\"cb_action\">\n";
600	echo $prefix . "\t\t<button>" . hsc(tpl_getLang('cookie_consent')) . "</button>\n";
601	echo $prefix . "\t\t";
602	if ( substr($link, 0, 7) == 'http://' || substr($link, 0, 8) == 'https://') {
603		echo '<a href="' . $link . '" target="_blank">' . hsc(tpl_getLang('cookie_linktext')) . '</a>';
604	} else {
605		tpl_pagelink($link, tpl_getLang('cookie_linktext'));
606	}
607	echo $prefix . "\n\t</p>\n" . $prefix . "</div>\n";
608
609}
610