====== pageindex Plugin ====== ---- plugin ---- description: Bulleted list of pages within a namespace author : Kite email : kite@puzzlers.org type : syntax lastupdate : 2021-03-17 compatible : depends : conflicts : similar : nstoc tags : navigation, menu, listing, namespace downloadurl: https://trello.com/1/cards/5d51a62cd417f934264631d5/attachments/5d51a760270fe1276a8bf0d0/download/pageindex.zip bugtracker : sourcerepo : donationurl: screenshot_img: ---- ===== Notes on this Updated Version (2021-03-17) ===== The download link above is for the version released on 2006-08-01. Below, I have added my 1.3 version, and I have also uploaded the code for //syntax.php// to github: https://gist.github.com/jeffmikels/2b1d0948ffdbed600418a2492a98cfeb/archive/b569f90ab7a4498c06e1a6f30dd6e7439597c74d.zip ===== Usage ===== You can use one of four tag styles: * ''%%~~PAGEINDEX=section:namespace;except1;except2,desc~~%%'' <- Lists the specified namespace, excludes //except1// and //except2//, sorts descending. * ''%%~~PAGEINDEX=section:namespace;except1;except2~~%%'' <- Lists the specified namespace, excludes //except1// and //except2//, sorts ascending. * ''%%~~PAGEINDEX=section:namespace~~%%'' <- Lists the specified namespace. * ''%%~~PAGEINDEX~~%%'' <- Lists the current namespace. I found that on the [[http://www.puzzlers.org/]] website, we have sections which get lots of pages over a short time and cross-referencing was a chore since some users aren't as wiki-oriented as others. Now I just add a tag to each page and they automatically update over time. The list will //never// include the current page, either, to reduce confusion. **NOTE:** To keep your index up to date, you might want to add %%~~NOCACHE~~%% to pages where you use it. ===== Installation ===== Put the following code into **lib/plugins/pageindex/syntax.php** in your DokuWiki site. Then you can add the tags above into any page you want a namespace index. ===== The Code ===== ==== Version 1.3 ==== * @based_on "externallink" plugin by Otto Vainio */ if(!defined('DOKU_INC')) { define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); } if(!defined('DOKU_PLUGIN')) { define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); } require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/search.php'); function search_list_index(&$data,$base,$file,$type,$lvl,$opts){ global $ID; //we do nothing with directories if($type == 'd') return false; if(preg_match('#\.txt$#',$file)){ //check ACL $id = pathID($file); if(auth_quickaclcheck($id) < AUTH_READ){ return false; } if($opts['ns'].":$id" <> $ID) { $data[] = array( 'id' => $opts['ns'].":$id", 'type' => $type, 'level' => $lvl ); } } return false; } /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_pageindex extends DokuWiki_Syntax_Plugin { /** * return some info */ function getInfo(){ return array( 'author' => 'Kite', 'email' => 'kite@puzzlers.org', 'date' => '2009-02-01', 'name' => 'Page Index', 'desc' => 'Presents an index list of files in the current namespace', 'url' => 'http://www.dokuwiki.org/plugin:pageindex', ); } /** * What kind of syntax are we? */ function getType(){ return 'substition'; } // Just before build in links function getSort(){ return 299; } /** * What about paragraphs? */ function getPType(){ return 'block'; } function connectTo($mode) { $this->Lexer->addSpecialPattern('~~PAGEINDEX[^~]*~~',$mode,'plugin_pageindex'); //$this->Lexer->addSpecialPattern('~~PAGEINDEX~~',$mode,'plugin_pageindex'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ $match = preg_replace("%~~PAGEINDEX(=(.*))?~~%", "\\2", $match); //echo "\n\t\n"; return $match; } /** * Create output */ function render($mode, &$renderer, $data) { if($mode == 'xhtml'){ $text=$this->_pageindex($renderer, $data); $renderer->doc .= $text; return true; } return false; } function _pageindex(&$renderer, $data) { global $conf; global $ID; //$renderer->doc .= "\n\n\n"; /* MODIFIED BY JEFF MIKELS TO CHANGE THE WAY THE PARAMETERS ARE HANDLED ~~PAGEINDEX[=namespace[;excluded-pages][,DESC]]~~ where excluded-pages are a semicolon-separated list of pages to exclude and DESC (case insensitive) will reverse the sort order of the rendered index */ $dataparams = explode(',', $data); $parameters = explode(';', $dataparams[0]); $ns = cleanID(getNS("$parameters[0]:dummy")); #fixme use appropriate function if(empty($ns)){ $ns = dirname(str_replace(':',DIRECTORY_SEPARATOR,$ID)); // 2007/12/30 Kite - use localized constant if($ns == '.') $ns =''; } //$ns = utf8_encodeFN(str_replace(':',DIRECTORY_SEPARATOR,$ns)); // 2007/12/30 Kite - use localized constant //$ns = utf8_encodeFN($ns); $search_data = array(); // Oct 3, 2006 renamed $data to $search_data for clarity $dir = $conf['datadir']. DIRECTORY_SEPARATOR .str_replace(':',DIRECTORY_SEPARATOR,$ns); // 2007/12/30 Kite - use localized constant $ns = str_replace(DIRECTORY_SEPARATOR,':',$ns); $renderer->doc .= "\n\n"; search($search_data, // results == renamed $data to $search_data $dir, // folder root 'search_list_index', // handler array('ns' => $ns) // options ); $checked = []; // Remove the items not wanted in the list if(is_array($parameters)) { $skipitems = array_slice($parameters, 1); foreach($search_data as $item) { $found = false; // Add ns if user didn't foreach($skipitems as $skip) { $skip = strpos($skip,":") ? $skip : "$ns:$skip"; if($item['id'] == $skip) { $found = true; break; } } if(!$found) { // Pass this one through $checked[] = $item; } else { //$renderer->doc .= "\n"; } } } // use the filtered data rather than $search_data if(count($checked)) { // sort properly if (!empty($dataparams[1]) && strtolower($dataparams[1]) == 'desc') { $checked = array_reverse($checked); } /* Option to use an HTML List */ $renderer->doc .= html_buildlist($checked, 'idx', 'html_list_index', 'html_li_index' ); /* Option to use the PageList plugin */ /* $pages = $checked; $pagelist =& plugin_load('helper', 'pagelist'); if (!$pagelist) return false; // failed to load plugin $pagelist->startList(); foreach ($pages as $page){ $pagelist->addPage($page); } $renderer->doc .= $pagelist->finishList(); */ } else { $renderer->doc .= "\n\t

There are no documents to show.

\n"; } } // _pageindex() } // syntax_plugin_pageindex
==== Version 1.2 ==== * @based_on "externallink" plugin by Otto Vainio */ if(!defined('DOKU_INC')) { define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); } if(!defined('DOKU_PLUGIN')) { define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); } require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/search.php'); function search_list_index(&$data,$base,$file,$type,$lvl,$opts){ global $ID; //we do nothing with directories if($type == 'd') return false; if(preg_match('#\.txt$#',$file)){ //check ACL $id = pathID($file); if(auth_quickaclcheck($id) < AUTH_READ){ return false; } if($opts['ns'].":$id" <> $ID) { $data[] = array( 'id' => $opts['ns'].":$id", 'type' => $type, 'level' => $lvl ); } } return false; } /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_pageindex extends DokuWiki_Syntax_Plugin { /** * return some info */ function getInfo(){ return array( 'author' => 'Kite', 'email' => 'kite@puzzlers.org', 'date' => '2009-02-01', 'name' => 'Page Index', 'desc' => 'Presents an index list of files in the current namespace', 'url' => 'http://www.dokuwiki.org/plugin:pageindex', ); } /** * What kind of syntax are we? */ function getType(){ return 'substition'; } // Just before build in links function getSort(){ return 299; } /** * What about paragraphs? */ function getPType(){ return 'block'; } function connectTo($mode) { $this->Lexer->addSpecialPattern('~~PAGEINDEX[^~]*~~',$mode,'plugin_pageindex'); //$this->Lexer->addSpecialPattern('~~PAGEINDEX~~',$mode,'plugin_pageindex'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ $match = preg_replace("%~~PAGEINDEX(=(.*))?~~%", "\\2", $match); //echo "\n\t\n"; return $match; } /** * Create output */ function render($mode, &$renderer, $data) { if($mode == 'xhtml'){ $text=$this->_pageindex($renderer, $data); $renderer->doc .= $text; return true; } return false; } function _pageindex(&$renderer, $data) { global $conf; global $ID; //$renderer->doc .= "\n\n\n"; $parameters = split(';', $data); $ns = cleanID(getNS("$parameters[0]:dummy")); #fixme use appropriate function if(empty($ns)){ $ns = dirname(str_replace(':',DIRECTORY_SEPARATOR,$ID)); // 2007/12/30 Kite - use localized constant if($ns == '.') $ns =''; } //$ns = utf8_encodeFN(str_replace(':',DIRECTORY_SEPARATOR,$ns)); // 2007/12/30 Kite - use localized constant //$ns = utf8_encodeFN($ns); $search_data = array(); // Oct 3, 2006 renamed $data to $search_data for clarity $dir = $conf['datadir']. DIRECTORY_SEPARATOR .str_replace(':',DIRECTORY_SEPARATOR,$ns); // 2007/12/30 Kite - use localized constant $ns = str_replace(DIRECTORY_SEPARATOR,':',$ns); $renderer->doc .= "\n\n"; search($search_data, // results == renamed $data to $search_data $dir, // folder root 'search_list_index', // handler array('ns' => $ns)); // options // Remove the items not wanted in the list if(is_array($parameters)) { $skipitems = array_slice($parameters, 1); foreach($search_data as $item) { $found = false; // Add ns if user didn't foreach($skipitems as $skip) { $skip = strpos($skip,":") ? $skip : "$ns:$skip"; if($item['id'] == $skip) { $found = true; break; } } if(!$found) { // Pass this one through $checked[] = $item; } else { //$renderer->doc .= "\n"; } } } if(count($checked)) { // use the filtered data rather than $search_data /* Option to use an HTML List */ $renderer->doc .= html_buildlist($checked, 'idx', 'html_list_index', 'html_li_index'); /* Option to use the PageList plugin */ /* $pages = $checked; $pagelist =& plugin_load('helper', 'pagelist'); if (!$pagelist) return false; // failed to load plugin $pagelist->startList(); foreach ($pages as $page){ $pagelist->addPage($page); } $renderer->doc .= $pagelist->finishList(); */ } else { $renderer->doc .= "\n\t

There are no documents to show.

\n"; } } // _pageindex() } // syntax_plugin_pageindex
==== Version 1 ==== * @based_on "externallink" plugin by Otto Vainio */ if(!defined('DOKU_INC')) { define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); } if(!defined('DOKU_PLUGIN')) { define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); } require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/search.php'); function search_list_index(&$data,$base,$file,$type,$lvl,$opts){ global $ID; //we do nothing with directories if($type == 'd') return false; if(preg_match('#\.txt$#',$file)){ //check ACL $id = pathID($file); if(auth_quickaclcheck($id) < AUTH_READ){ return false; } if($opts['ns'].":$id" <> $ID) { $data[] = array( 'id' => $opts['ns'].":$id", 'type' => $type, 'level' => $lvl ); } } return false; } /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_pageindex extends DokuWiki_Syntax_Plugin { /** * return some info */ function getInfo(){ return array( 'author' => 'Kite', 'email' => 'kite@puzzlers.org', 'date' => '2006-08-01', 'name' => 'Page Index', 'desc' => 'Presents an index list of files in the current namespace', 'url' => 'http://www.dokuwiki.org/plugin:pageindex', ); } /** * What kind of syntax are we? */ function getType(){ return 'substition'; } // Just before build in links function getSort(){ return 299; } /** * What about paragraphs? */ function getPType(){ return 'block'; } function connectTo($mode) { $this->Lexer->addSpecialPattern('~~PAGEINDEX[^~]*~~',$mode,'plugin_pageindex'); //$this->Lexer->addSpecialPattern('~~PAGEINDEX~~',$mode,'plugin_pageindex'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ $match = preg_replace("%~~PAGEINDEX(=(.*))?~~%", "\\2", $match); //echo "\n\t\n"; return $match; } /** * Create output */ function render($mode, &$renderer, $data) { if($mode == 'xhtml'){ $text=$this->_pageindex($renderer, $data); $renderer->doc .= $text; return true; } return false; } function _pageindex(&$renderer, $data) { global $conf; global $ID; //$renderer->doc .= "\n\n\n"; // New Oct 3, 2006 -- begin $parameters = split(';', $data); // New Oct 3, 2006 -- end $ns = cleanID(getNS("$data:dummy")); #fixme use appropriate function if(empty($ns)){ $ns = dirname(str_replace(':',DIRECTORY_SEPARATOR,$ID)); // 2007/12/30 Kite - use localized constant if($ns == '.') $ns =''; } //$ns = utf8_encodeFN(str_replace(':',DIRECTORY_SEPARATOR,$ns)); // 2007/12/30 Kite - use localized constant //$ns = utf8_encodeFN($ns); $search_data = array(); // Oct 3, 2006 renamed $data to $search_data for clarity $dir = $conf['datadir']. DIRECTORY_SEPARATOR .str_replace(':',DIRECTORY_SEPARATOR,$ns); // 2007/12/30 Kite - use localized constant $ns = str_replace(DIRECTORY_SEPARATOR,':',$ns); $renderer->doc .= "\n\n"; search($search_data, // results == renamed $data to $search_data $dir, // folder root 'search_list_index', // handler array('ns' => $ns)); // options // New Oct 3, 2006 -- begin // Remove the items not wanted in the list if(is_array($parameters)) { $skipitems = array_slice($parameters, 1); foreach($search_data as $item) { $found = false; foreach($skipitems as $skip) { // Suggested fix: ensures the current namespace $skip = strpos($skip,":") ? $skip : "$ns:$skip"; // Add ns if user didn't if($item['id'] == $skip) { $found = true; break; } } if(!$found) { // Pass this one through $checked[] = $item; } else { //$renderer->doc .= "\n"; } } } if(count($checked)) { // use the filtered data rather than $search_data $renderer->doc .= html_buildlist($checked, 'idx', 'html_list_index', 'html_li_index'); } else { $renderer->doc .= "\n\t

There are no documents to show.

\n"; } // New Oct 3, 2006 -- end // if(count($search_data)) { // renamed $data to $search_data // $renderer->doc .= html_buildlist($search_data, // 'idx', // 'html_list_index', // 'html_li_index'); // } else { // $renderer->doc .= "\n\t

There are no documents to show.

\n"; // } //$renderer->doc .= "\n\n"; } // _pageindex() } // syntax_plugin_pageindex
===== Updates ===== ==== March 17, 2021 ==== I added another option to the pageindex code to change the page sorting of the generated indexes. You can now write your pageindex code like this: %%~~pageindex=namespace;except1;except2,desc~~%% to get all the pages in //namespace// other than //except1// or //except2// and sort the results in descending alphabetical order. \\ ==== Oct 3, 2006 ==== I added a bit of code into the "meat" function that performs a neat bit for me. I want to use a syntax of "show me everything //except one or two//. That is, I have a default "start" or "index" page that has no real content except a %%~~pageindex~~%% macro. I want to show all the pages //except// that start page from other pages. Now I can use: %%~~pageindex=namespace;except1;except2~~%% to get all the pages in //namespace// other than //except1// or //except2//. \\ ==== Dec 30, 2007 ==== I changed references to '/' to DIRECTORY_SEPARATOR per the 'possible bug' comment below. \\ ===== Discussion ===== **Listing of subNamespace** I need also a listing of the namespace under the current namespace. How i have to modify the code? Can you show me an example. Thanks, Johann. *** syntax.php 2006/12/16 19:27:01 1.1 --- syntax.php 2006/12/16 19:37:06 *************** *** 21,27 **** function search_list_index(&$data,$base,$file,$type,$lvl,$opts){ global $ID; //we do nothing with directories ! if($type == 'd') return false; if(preg_match('#\.txt$#',$file)){ //check ACL $id = pathID($file); --- 21,35 ---- function search_list_index(&$data,$base,$file,$type,$lvl,$opts){ global $ID; //we do nothing with directories ! if($type == 'd') { ! $id = pathID($file); ! if($opts['ns'].":$id" <> $ID) { ! $data[] = array( ! 'id' => $opts['ns'].":$id", ! 'type' => $type, ! 'level' => $lvl ); ! } ! } if(preg_match('#\.txt$#',$file)){ //check ACL $id = pathID($file); ---- **Possible bug?** Thanks for the plugin, it's very handy. But I have to say I guess I found a bug. If working on Windows (I test my websites on Windows but host them on Linux/FreeBSD then) the hard-coded slashes in the code (I mean like that: /) cause the bug. Windows puts backslashes in directory path and the plugin, quite contrary, adds slashes. It works OK until no arguments are specified (just ~~PAGEINDEX~~), but if something like ~~PAGEINDEX=dev;sidebar~~ is tried then it starts telling there are no documents to index. Please replace ALL hard-coded slashes to something platform-independent. Regards, Webmaster. //2007/12/30// I've altered the lines with '/' constants to use the DIRECTORY_SEPARATOR constant so paths should now be more platform independent. \\ ---- ==== User Comments ==== We had to replace the line // New Oct 3, 2006 -- end $ns = cleanID(getNS("$data:dummy")); with // New Oct 3, 2006 -- end $ns = cleanID(getNS("{$parameters[0]}:dummy")); to make the exclude function work. We also had to specify the full pagename including namespace: prefix to actually exclude the page. RĂ¼diger Marwein / Roland Eckert / [[http://21torr.com|21torr.com]] > **Solution to last thing above**\\ > One way to avoid having to prefix the name space, is to add one line to the $skipitems loop.\\ > Before snippet: > foreach($skipitems as $skip) { if($item['id'] == $skip) { $found = true; break; > After snippet: > foreach($skipitems as $skip) { $skip = strpos($skip,":") ? $skip : "$ns:$skip"; // Add ns if user didn't if($item['id'] == $skip) { $found = true; break; > Henrik Andreasson. ---- Bug: after copying the script from the page above I got a PHP error on my next "save page" click. I had to remove the ''?>'' part of the last line of the script and it functioned since. It is reported here about this problem in general: [[:wiki:development#php_closing_tags]] - Stephen (stephen-dot-leedle-at-gmx-dot-de) ---- I prefer the [[plugin:pagelist|pagelist plugin]] for rendering. It's easy to add : Just replace theses lines : $renderer->doc .= html_buildlist($checked, 'idx', 'html_list_index', 'html_li_index'); by $pages = $checked; $pagelist =& plugin_load('helper', 'pagelist'); if (!$pagelist) return false; // failed to load plugin $pagelist->startList(); foreach ($pages as $page){ $pagelist->addPage($page); } $renderer->doc .= $pagelist->finishList(); You can set flags too with $pagelist->setFlags(array("nouser", "desc")); // Just after $pagelist->startList(); I don't know why, but it don't work with "tag" and "comments" flags. Any idea ? (I have both plugins installed) --- //[[jeanmichel.lacroix@gmail.com|Jean-Michel]] 2008-03-02 18:26// ------------- :!: Possible bug I really like this plugin, but I think I've found a bug. When I create a new page in a namespace, it doesn't appear on the list created by the plugin, but if I make a preview of the page it does appear. May it be a problem of refreshing? //[[digna.gonzalezotero@gmail.com|Ayla]] 2008-04-06 18:40// try to to a ~~NOCACHE~~ on the page with the ~~PAGEINDEX~~ . Every Page is cached in plain-HTML for a given time if not modified or with that tag. ---------------- :!: It's not a bug, it's a feature If you use some templates that make a sitemap on the right or on the left ... beware of redefinition of function search_list_index() workaround is vi regexp in the pasted syntax.php : :%s/search_list_index/search_list_index_whateveryouwant/g ---------------- :!: Possible bug: No unicode (cyrillics, for example) support. ---------------- :!: Possible bug: Not obeying config:hidepages.