1<?php 2 3use dokuwiki\Extension\SyntaxPlugin; 4use dokuwiki\Logger; 5 6/** 7 * DokuWiki Syntax Plugin Backlinks. 8 * 9 * Shows a list of pages that link back to a given page. 10 * 11 * Syntax: {{backlinks>[pagename][#filterNS|!#filterNS]}} 12 * 13 * [pagename] - a valid wiki pagename or a . for the current page 14 * [filterNS] - a valid,absolute namespace name, optionally prepended with ! to exclude 15 * 16 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 17 * @author Michael Klier <chi@chimeric.de> 18 * @author Mark C. Prins <mprins@users.sf.net> 19 */ 20 21/** 22 * All DokuWiki plugins to extend the parser/rendering mechanism 23 * need to inherit from this class. 24 */ 25class syntax_plugin_backlinks extends SyntaxPlugin 26{ 27 /** 28 * Syntax Type. 29 * 30 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php. 31 * 32 * @see DokuWiki_Syntax_Plugin::getType() 33 */ 34 public function getType(): string 35 { 36 return 'substition'; 37 } 38 39 /** 40 * @see DokuWiki_Syntax_Plugin::getPType() 41 */ 42 public function getPType(): string 43 { 44 return 'block'; 45 } 46 47 /** 48 * @see Doku_Parser_Mode::getSort() 49 */ 50 public function getSort(): int 51 { 52 return 304; 53 } 54 55 /** 56 * Connect pattern to lexer. 57 * 58 * @see Doku_Parser_Mode::connectTo() 59 */ 60 public function connectTo($mode): void 61 { 62 $this->Lexer->addSpecialPattern('\{\{backlinks>.+?\}\}', $mode, 'plugin_backlinks'); 63 } 64 65 /** 66 * Handler to prepare matched data for the rendering process. 67 * 68 * @see DokuWiki_Syntax_Plugin::handle() 69 */ 70 public function handle($match, $state, $pos, Doku_Handler $handler): array 71 { 72 // strip {{backlinks> from start and }} from end 73 $match = substr($match, 12, -2); 74 75 $includeNS = ''; 76 if (strstr($match, "#")) { 77 $includeNS = substr(strstr($match, "#", false), 1); 78 $match = strstr($match, "#", true); 79 } 80 81 return ([$match, $includeNS]); 82 } 83 84 /** 85 * Handles the actual output creation. 86 * 87 * @see DokuWiki_Syntax_Plugin::render() 88 */ 89 public function render($format, Doku_Renderer $renderer, $data): bool 90 { 91 global $lang; 92 global $INFO; 93 global $ID; 94 95 $id = $ID; 96 // If it's a sidebar, get the original id. 97 if ($INFO != null) { 98 $id = $INFO['id']; 99 } 100 $match = $data[0]; 101 $match = ($match == '.') ? $id : $match; 102 if (strstr($match, ".:")) { 103 resolve_pageid(getNS($id), $match, $exists); 104 } 105 106 if ($format == 'xhtml') { 107 $renderer->info['cache'] = false; 108 109 $backlinks = ft_backlinks($match); 110 111 Logger::debug("backlinks: all backlinks to: $match", $backlinks); 112 113 $renderer->doc .= '<div id="plugin__backlinks">' . "\n"; 114 115 $filterNS = $data[1]; 116 if (!empty($backlinks) && !empty($filterNS)) { 117 if (stripos($filterNS, "!", 0) === 0) { 118 $filterNS = substr($filterNS, 1); 119 Logger::debug("backlinks: excluding all of namespace: $filterNS"); 120 $backlinks = array_filter( 121 $backlinks, 122 static fn($ns) => stripos($ns, $filterNS, 0) !== 0 123 ); 124 } else { 125 Logger::debug("backlinks: including namespace: $filterNS only"); 126 $backlinks = array_filter( 127 $backlinks, 128 static fn($ns) => stripos($ns, (string) $filterNS, 0) === 0 129 ); 130 } 131 } 132 133 Logger::debug("backlinks: all backlinks to be rendered", $backlinks); 134 135 if (!empty($backlinks)) { 136 $renderer->doc .= '<ul class="idx">'; 137 138 foreach ($backlinks as $backlink) { 139 $name = p_get_metadata($backlink, 'title'); 140 if (empty($name)) { 141 $name = $backlink; 142 } 143 $renderer->doc .= '<li><div class="li">'; 144 $renderer->doc .= html_wikilink(':' . $backlink, $name); 145 $renderer->doc .= '</div></li>' . "\n"; 146 } 147 148 $renderer->doc .= '</ul>' . "\n"; 149 } else { 150 $renderer->doc .= "<strong>Plugin Backlinks: " . $lang['nothingfound'] . "</strong>" . "\n"; 151 } 152 153 $renderer->doc .= '</div>' . "\n"; 154 155 return true; 156 } 157 return false; 158 } 159} 160