1<?php 2/** 3 * DokuWiki Plugin pageredirect (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Elan Ruusamäe <glen@delfi.ee> 7 * @author David Lorentsen <zyberdog@quakenet.org> 8 */ 9 10use dokuwiki\File\PageResolver; 11 12// must be run within Dokuwiki 13if(!defined('DOKU_INC')) die(); 14 15class syntax_plugin_pageredirect extends DokuWiki_Syntax_Plugin { 16 /** 17 * @return string Syntax mode type 18 */ 19 public function getType() { 20 return 'substition'; 21 } 22 23 /** 24 * @return string Paragraph type 25 */ 26 public function getPType() { 27 return 'block'; 28 } 29 30 /** 31 * @return int Sort order - Low numbers go before high numbers 32 */ 33 public function getSort() { 34 return 1; 35 } 36 37 /** 38 * Connect lookup pattern to lexer. 39 * 40 * @param string $mode Parser mode 41 */ 42 public function connectTo($mode) { 43 // NOTE: each document is surrounted with \n by dokuwiki parser 44 // so it's safe to use \n in the pattern 45 // this fixes creole greedyness: 46 // https://github.com/glensc/dokuwiki-plugin-pageredirect/issues/18#issuecomment-249386268 47 $this->Lexer->addSpecialPattern('(?:~~REDIRECT>.+?~~|\n#(?i:redirect) [^\r\n]+)', $mode, 'plugin_pageredirect'); 48 } 49 50 /** 51 * Handler to prepare matched data for the rendering process 52 * 53 * This function can only pass data to render() via its return value 54 * render() may be not be run during the object's current life. 55 * 56 * Usually you should only need the $match param. 57 * 58 * @param string $match The text matched by the patterns 59 * @param int $state The lexer state for the match 60 * @param int $pos The character position of the matched text 61 * @param Doku_Handler $handler Reference to the Doku_Handler object 62 * @return array Return an array with all data you want to use in render 63 */ 64 public function handle($match, $state, $pos, Doku_Handler $handler) { 65 // strip leading "\n" from creole-compatible pattern 66 $match = trim($match); 67 68 // extract target page from match pattern 69 if($match[0] == '#') { 70 # #REDIRECT PAGE 71 $id = substr($match, 10); 72 } else { 73 # ~~REDIRECT>PAGE~~ 74 $id = substr($match, 11, -2); 75 } 76 $id = trim($id); 77 78 $is_external = preg_match('#^https?://#i', $id); 79 80 // resolve and clean the $id if it is not external 81 if(!$is_external) { 82 global $ID; 83 if (class_exists('dokuwiki\File\PageResolver')) { 84 $resolver = new PageResolver($ID); 85 $id = $resolver->resolveId($id); 86 } else { 87 $exists = null; 88 resolve_pageid(getNS($ID), $id, $exists); 89 } 90 } 91 92 return array($id, $is_external); 93 } 94 95 /** 96 * Handles the actual output creation. 97 * 98 * The function must not assume any other of the classes methods have been run 99 * during the object's current life. The only reliable data it receives are its 100 * parameters. 101 * 102 * The function should always check for the given output format and return false 103 * when a format isn't supported. 104 * 105 * $renderer contains a reference to the renderer object which is 106 * currently handling the rendering. You need to use it for writing 107 * the output. How this is done depends on the renderer used (specified 108 * by $format 109 * 110 * The contents of the $data array depends on what the handler() function above 111 * created 112 * 113 * @param string $format output format being rendered 114 * @param Doku_Renderer $renderer reference to the current renderer object 115 * @param array $data data created by handler() 116 * @return boolean return true if rendered correctly 117 */ 118 public function render($format, Doku_Renderer $renderer, $data) { 119 if($format == 'xhtml') { 120 // add prepared note about redirection 121 $renderer->doc .= $this->redirect_message($data); 122 123 // hook into the post render event to allow the page to be redirected 124 global $EVENT_HANDLER; 125 /** @var action_plugin_pageredirect $action */ 126 $action = plugin_load('action', 'pageredirect'); 127 $EVENT_HANDLER->register_hook('TPL_ACT_RENDER', 'AFTER', $action, 'handle_dokuwiki_started'); 128 129 return true; 130 } 131 132 if($format == 'metadata') { 133 // add redirection to metadata 134 $renderer->meta['relation']['isreplacedby'] = $data; 135 if (!$data[1]) { 136 $page = preg_split("/\?|#/", $data[0])[0]; 137 $renderer->meta['relation']['references'][$page] = page_exists($page); 138 } 139 140 return true; 141 } 142 143 return false; 144 } 145 146 /** 147 * Create redirection message html 148 * 149 * @param string $page 150 * @return string 151 */ 152 private function redirect_message($metadata) { 153 list($page, $is_external) = $metadata; 154 if(!$is_external) { 155 $link = html_wikilink($page); 156 } else { 157 $link = '<a href="' . hsc($page) . '" class="urlextern">' . hsc($page) . '</a>'; 158 } 159 160 // prepare message here instead of in render 161 $message = '<div class="noteredirect">' . sprintf($this->getLang('redirect_to'), $link) . '</div>'; 162 163 return $message; 164 } 165} 166