====== condition Plugin ====== ---- plugin ---- description: Render a block if a condition is fulfilled, user custom tests can be easily added author : Etienne Meleard email : etienne.meleard@free.fr type : Syntax lastupdate : 2017-11-30 compatible : depends : conflicts : similar : ifauth, showif, isauth, nodisp, ifauthex tags : condition if syntax securitywarning: partlyhidden downloadurl: https://github.com/gamma/dokuwiki-plugin-condition/zipball/master bugtracker : https://github.com/gamma/dokuwiki-plugin-condition/issues sourcerepo : https://github.com/gamma/dokuwiki-plugin-condition donationurl: ---- :!: Replace curly brackets string indices with square brackets in line 84 and 149 of ''plugins/condition/syntax.php'' if you run your webserver with PHP 8. ===== Description ===== The Syntax Plugin allows to parse a content only if a specific condition (or multiple condition) is fulfilled. Some basic tests are provided and users can add new tests just by implementing a file in the template directory. ===== Syntax ===== doku code or doku codedoku code ''[condition_list]'' is a set of ''[condition]'' records separated by logical operators ''%%(&&, and, ||, or, ^, xor for now)%%'', use of parenthesis is allowed, negation is achieved by using heading ''!'' ''%%(ex !foo=bar or !(a=b || c free) or a %%"%% delimited string (whitespaces, ) and > are then allowed) DokuWiki code can contain DokuWiki syntax but be careful with high-level syntax (containers, table ...) as there may be priority issue, bug reports are welcome... **It is now sure that using the plugin inside a table cell won't work, working on it now, any help is welcome...** Example: You are **connected**You must identify yourself to do something You are not a manager It's New Year's Eve You are in a local network not VIP (equivalent of not VIP) ... ===== Download and Installation ===== Search and install the plugin using the [[plugin:extension|Extension Manager]]. Refer to [[:Plugins]] on how to install plugins manually. * Latest Version: [[https://github.com/gamma/dokuwiki-plugin-condition/archive/master.zip]] (GitHub) * Old Version: [[http://dokuwiki.yent.eu/condition.zip]] ===== Sources ===== Attention: there is also a third-party source [[https://github.com/gamma/dokuwiki-plugin-condition|at GitHub]] ==== syntax.php ==== * * 2009/06/08 : Creation * 2009/06/09 : Drop of the multi-value tests / creation of tester class system * 2009/06/10 : Added tester class override to allow user to define custom tests * 2009/09/15 : Added better renderer handling with respect of conditions for TOC generation */ 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'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_condition extends DokuWiki_Syntax_Plugin { // To be used by _processblocks to mix the test results together var $allowedoperators = array('\&\&', '\|\|', '\^', 'and', 'or', 'xor'); // plus '!' specific operator // Allowed test operators, their behavior is defined in the tester class, they are just defined here for recognition during parsing var $allowedtests = array(); // Allowed test keys var $allowedkeys = array(); // To store the tester object private $tester = null; // return some info function getInfo() { return confToHash(dirname(__FILE__).'/INFO'); } /*function accepts($mode) { return true; } function getAllowedTypes() { return array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); // quick hack }*/ function getType() { return 'container';} function getPType() { return 'normal';} function getSort() { return 5; } // condition is top priority // Connect pattern to lexer function connectTo($mode){ $this->Lexer->addEntryPattern(')', $mode, 'plugin_condition'); } function postConnect() { $this->Lexer->addExitPattern('', 'plugin_condition'); } // Handle the match function handle($match, $state, $pos, Doku_Handler $handler) { if($state != DOKU_LEXER_UNMATCHED) return false; // Get allowed test operators $this->_loadtester(); if(!$this->tester) return array(array(), ''); $this->allowedtests = $this->tester->getops(); $this->allowedkeys = $this->tester->getkeys(); $blocks = array(); $content = ''; $this->_parse($match, $blocks, $content); return array($blocks, $content); } // extracts condition / content function _parse(&$match, &$b, &$ctn) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces $b = $this->_fetch_block($match, 0); if($match != '') $ctn = preg_replace('`\n+$`', '', preg_replace('`^\n+`', '', preg_replace('`^>`', '', $match))); return true; } // fetch a condition block from buffer function _fetch_block(&$match, $lvl=0) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces $instrs = array(); $continue = true; while(($match{0} != '>') && ($match != '') && (($lvl == 0) || ($match{0} != ')')) && $continue) { $i = array('type' => null, 'key' => '', 'test' => '', 'value' => '', 'next' => ''); if($this->_fetch_op($match, true)) { // ! heading equals block descending for first token $i['type'] = 'nblock'; $match = substr($match, 1); // remove heading ! $i['value'] = $this->_fetch_block($match, $lvl+1); }else if($this->_is_block($match)) { $i['type'] = 'block'; $match = substr($match, 1); // remove heading ( $i['value'] = $this->_fetch_block($match, $lvl+1); }else if($this->_is_key($match, $key)) { $i['type'] = 'test'; $i['key'] = $key; $match = substr($match, strlen($key)); // remove heading key if($this->_is_test($match, $test)) { $i['test'] = $test; $match = substr($match, strlen($test)); // remove heading test if(($v = $this->_fetch_value($match)) !== null) $i['value'] = $v; } }else $match = preg_replace('`^[^>\s\(]+`', '', $match); // here dummy stuff remains if($i['type']) { if(($op = $this->_fetch_op($match, false)) !== null) { $match = substr($match, strlen($op)); // remove heading op $i['next'] = $op; }else $continue = false; $instrs[] = $i; } } return $instrs; } // test if buffer starts with new sub-block function _is_block(&$match) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces return preg_match('`^\(`', $match); } // test if buffer starts with a key ref function _is_key(&$match, &$key) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces if(preg_match('`^([a-zA-Z0-9_-]+)`', $match, $r)) { if(preg_match('`^'.$this->_preg_build_alternative($this->allowedkeys).'$`', $r[1])) { $key = $r[1]; return true; } } return false; } // build a pcre alternative escaped test from array function _preg_build_alternative($choices) { //$choices = array_map(create_function('$e', 'return preg_replace(\'`([^a-zA-Z0-9])`\', \'\\\\\\\\$1\', $e);'), $choices); return '('.implode('|', $choices).')'; } // tells if buffer starts with a test operator function _is_test(&$match, &$test) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces if(preg_match('`^'.$this->_preg_build_alternative($this->allowedtests).'`', $match, $r)) { $test = $r[1]; return true; } return false; } // fetch value from buffer, handles value quoting function _fetch_value(&$match) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces if($match{0} == '"') { $match = substr($match, 1); $value = substr($match, 0, strpos($match, '"')); $match = substr($match, strlen($value) + 1); }else{ $psp = strpos($match, ')'); $wsp = strpos($match, ' '); $esp = strpos($match, '>'); $sp = 0; $bug = false; if(($wsp === false) && ($esp === false) && ($psp === false)) { return null; // BUG }else if(($wsp === false) && ($esp === false)) { $sp = $psp; }else if(($wsp === false) && ($psp === false)) { $sp = $esp; }else if(($psp === false) && ($esp === false)) { $sp = $wsp; }else if($wsp === false) { $sp = min($esp, $psp); }else if($esp === false) { $sp = min($wsp, $psp); }else if($psp === false) { $sp = min($esp, $wsp); }else $sp = min($wsp, $esp, $psp); $value = substr($match, 0, $sp); $match = substr($match, strlen($value)); } return $value; } // fetch a logic operator from buffer function _fetch_op(&$match, $head=false) { $match = preg_replace('`^\s+`', '', $match); // trim heading whitespaces $ops = $this->allowedoperators; if($head) $ops = array('!'); if(preg_match('`^'.$this->_preg_build_alternative($ops).'`', $match, $r)) return $r[1]; return null; } /** * Create output */ function render($mode, Doku_Renderer $renderer, $data) { global $INFO; if(count($data) != 2) return false; if($mode == 'xhtml') { global $ID; // prevent caching to ensure good user data detection for tests $renderer->info['cache'] = false; $blocks = $data[0]; $content = $data[1]; // parsing content for a statement $else = ''; if(strpos($content, '') !== false) { $i = explode('', $content); $content = $i[0]; $else = implode('', array_slice($i, 1)); } // Process condition blocks $bug = false; $this->_loadtester(); $ok = $this->_processblocks($blocks, $bug); // Render content if all went well $toc = $renderer->toc; if(!$bug) { $instr = p_get_instructions($ok ? $content : $else); foreach($instr as $instruction) { call_user_func_array(array(&$renderer, $instruction[0]), $instruction[1]); } } $renderer->toc = array_merge($toc, $renderer->toc); return true; } if($mode == 'metadata') { global $ID; // prevent caching to ensure good user data detection for tests $renderer->info['cache'] = false; $blocks = $data[0]; $content = $data[1]; // parsing content for a statement $else = ''; if(strpos($content, '') !== false) { $i = explode('', $content); $content = $i[0]; $else = implode('', array_slice($i, 1)); } // Process condition blocks $bug = false; $this->_loadtester(); $ok = $this->_processblocks($blocks, $bug); // Render content if all went well $metatoc = $renderer->meta['description']['tableofcontents']; if(!$bug) { $instr = p_get_instructions($ok ? $content : $else); foreach($instr as $instruction) { call_user_func_array(array(&$renderer, $instruction[0]), $instruction[1]); } } $renderer->meta['description']['tableofcontents'] = array_merge($metatoc, $renderer->meta['description']['tableofcontents']); return true; } return false; } // Strips the heading

and trailing

added by p_render xhtml to acheive inline behavior function _stripp($data) { $data = preg_replace('`^\s*]*>\s*`', '', $data); $data = preg_replace('`\s*]*>\s*$`', '', $data); return $data; } // evaluates the logical result from a set of blocks function _processblocks($b, &$bug) { for($i=0; $i_processblocks($b[$i]['value'], $bug); if($b[$i]['type'] == 'nblock') $b[$i]['r'] = !$b[$i]['r']; }else{ $b[$i]['r'] = $this->_evaluate($b[$i], $bug); } } if(!count($b)) $bug = true; // no condition in block if($bug) return false; // assemble conditions /* CUSTOMISATION : * You can add custom mixing operators here, don't forget to add them to * the "allowedoperators" list at the top of this file */ $r = $b[0]['r']; for($i=1; $itester) { $bug = true; return false; } return $this->tester->run($b, $bug); } // tries to load user defined tester, then base tester if previous failed function _loadtester() { global $conf; $this->tester = null; include_once(DOKU_PLUGIN.'condition/base_tester.php'); if(@file_exists(DOKU_INC.'lib/tpl/'.$conf['template'].'/condition_plugin_custom_tester.php')) { include_once(DOKU_INC.'lib/tpl/'.$conf['template'].'/condition_plugin_custom_tester.php'); if(class_exists('condition_plugin_custom_tester')) { $this->tester = new condition_plugin_custom_tester(); } } if(!$this->tester) { if(class_exists('condition_plugin_base_tester')) { $this->tester = new condition_plugin_base_tester(); } } } } //class ?>
==== base_tester.php ==== /condition_plugin_custom_tester.php * MUST implements this class * * To add a custom test in condition_plugin_custom_tester you just have to add a method like : * * function test_dummy($b, &$bug, $lop=false) { if($lop) return array(); return true; } * this test will react to of * * or * * function test_IP($b, &$bug, $lop=false) { * if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?', '\~\='); // pcre regexp list of allowed test operators * $ip = clientIP(true); * if(!$b['test'] || ($b['test'] == '') || !$b['value'] || ($b['value'] == '') || ($ip == '0.0.0.0')) { * $bug = true; * return false; * } * switch($b['test']) { * case '=' : * case 'eq' : * case '==' : * return ($ip == $b['value']); break; * case '!=' : * case 'ne' : * case 'neq' : * return ($ip != $b['value']); break; * case '~=' : // such new test operators must be added in syntax.php * return (strpos($ip, $b['value']) !== false); break; * default: // non allowed operators for the test must lead to a bug flag raise * $bug = true; * return false; * } * } * this test will react to */ class condition_plugin_base_tester { function __construct() {} // Wrapper for all tests function run($b, &$bug) { if(method_exists($this, 'test_'.$b['key'])) { return call_user_func(array($this, 'test_'.$b['key']), $b, $bug); } $bug = true; return false; } // Get allowed keys function getkeys() { $keys = array(); foreach(get_class_methods($this) as $m) { if(preg_match('`^test_(.+)$`', $m, $r)) $keys[] = $r[1]; } return $keys; } // Get test operators function getops() { $ops = array(); foreach($this->getkeys() as $m) $ops = array_merge($ops, call_user_func(array($this, 'test_'.$m), null, $dummy, true)); return array_unique($ops); } // Tests follows // ------------- // user based tests function test_user($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?'); $rh = isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : ''; if(!$b['test'] || ($b['test'] == '')) return ($rh && ($rh != '')); switch($b['test']) { case '=' : case 'eq' : case '==' : return $rh == $b['value']; break; case '!=' : case 'ne' : case 'neq' : return $rh != $b['value']; break; default: $bug = true; return false; } } function test_group($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?'); global $INFO; $grps = isset($INFO['userinfo']) ? $INFO['userinfo']['grps'] : array(); if(!$b['test'] || ($b['test'] == '')) return (count($grps) != 0); switch($b['test']) { case '=' : case 'eq' : case '==' : if(!$b['value'] || ($b['value'] == '')) return (count($grps) == 0); return in_array($b['value'], $grps); break; case '!=' : case 'ne' : case 'neq' : if(!$b['value'] || ($b['value'] == '')) return (count($grps) != 0); return !in_array($b['value'], $grps); break; default: $bug = true; return false; } } // namespace based tests function test_nsread($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?'); if(!$b['test'] || ($b['test'] == '')) { $bug = true; return false; } if(!$b['value'] || ($b['value'] == '')) $b['value'] = '.'; switch($b['test']) { case '=' : case 'eq' : case '==' : return (auth_quickaclcheck($b['value']) >= AUTH_READ); break; case '!=' : case 'ne' : case 'neq' : return (auth_quickaclcheck($b['value']) < AUTH_READ); break; default: $bug = true; return false; } } function test_nsedit($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?'); if(!$b['test'] || ($b['test'] == '')) { $bug = true; return false; } if(!$b['value'] || ($b['value'] == '')) $b['value'] = '.'; switch($b['test']) { case '=' : case 'eq' : case '==' : return (auth_quickaclcheck($b['value']) >= AUTH_EDIT); break; case '!=' : case 'ne' : case 'neq' : return (auth_quickaclcheck($b['value']) < AUTH_EDIT); break; default: $bug = true; return false; } } // time based tests function test_time($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?', '\<\=?', 'lt', '\>\=?', 'gt'); global $INFO; if(!$b['test'] || ($b['test'] == '') || !$b['value'] || ($b['value'] == '')) { $bug = true; return false; } switch($b['test']) { case '=' : case 'eq' : case '==' : return $this->_bt_cmptimeandstr($b['value']); break; case '!=' : case 'ne' : case 'neq' : return !$this->_bt_cmptimeandstr($b['value']); break; case '<' : case 'lt' : $t = time(); return ($t < $this->_bt_strtotime($b['value'], $t)); break; case '>' : case 'gt' : $t = time(); return ($t > $this->_bt_strtotime($b['value'], $t)); break; case '<=' : $t = time(); return ($t <= $this->_bt_strtotime($b['value'], $t)); break; case '>=' : $t = time(); return ($t >= $this->_bt_strtotime($b['value'], $t)); break; default: $bug = true; return false; } } function _bt_strtotime($value, $default) { if(preg_match('`^([0-9]{4})(-|/)([0-9]{2})(-|/)([0-9]{2})(\s+([0-9]{2}):([0-9]{2})(:([0-9]{2}))?)?$`', $value, $reg)) $value = mktime($reg[7], $reg[8], $reg[10], $reg[3], $reg[5], $reg[1]); // YYYY(-|/)MM(-|/)DD (HH:II(:SS)?)? if(preg_match('`^(([0-9]{2}):([0-9]{2})(:([0-9]{2}))?\s+)?([0-9]{4})(-|/)([0-9]{2})(-|/)([0-9]{2})$`', $value, $reg)) $value = mktime($reg[2], $reg[3], $reg[5], $reg[8], $reg[10], $reg[6]); // (HH:II(:SS)?)? YYYY(-|/)MM(-|/)DD if(preg_match('`^([0-9]{2})(-|/)([0-9]{2})(-|/)([0-9]{4})(\s+([0-9]{2}):([0-9]{2})(:([0-9]{2}))?)?$`', $value, $reg)) $value = mktime($reg[7], $reg[8], $reg[10], $reg[3], $reg[1], $reg[5]); // DD(-|/)MM(-|/)YYYY (HH:II(:SS)?)? if(preg_match('`^(([0-9]{2}):([0-9]{2})(:([0-9]{2}))?\s+)?([0-9]{2})(-|/)([0-9]{2})(-|/)([0-9]{4})$`', $value, $reg)) $value = mktime($reg[2], $reg[3], $reg[5], $reg[8], $reg[6], $reg[10]); // (HH:II(:SS)?)? DD(-|/)MM(-|/)YYYY if(!is_numeric($value)) $value = $default; return $value; } function _bt_cmptimeandstr($str) { $matched = false; $t = time(); $time = array('y' => date('Y', $t), 'm' => date('m', $t), 'd' => date('d', $t), 'h' => date('H', $t), 'i' => date('i', $t), 's' => date('s', $t)); $d = array('y' => '', 'm' => '', 'd' => '', 'h' => '', 'i' => '', 's' => ''); // full date y, m and d, time is optionnal if(preg_match('`^([0-9]{4})(-|/)([0-9]{2})(-|/)([0-9]{2})(\s+([0-9]{2}):([0-9]{2})(:([0-9]{2}))?)?$`', $str, $reg)) { $d = array('y' => $reg[1], 'm' => $reg[3], 'd' => $reg[5], 'h' => $reg[7], 'i' => $reg[8], 's' => $reg[10]); // YYYY(-|/)MM(-|/)DD (HH:II(:SS)?)? $matched = true; } if(preg_match('`^(([0-9]{2}):([0-9]{2})(:([0-9]{2}))?\s+)?([0-9]{4})(-|/)([0-9]{2})(-|/)([0-9]{2})$`', $str, $reg)) { $d = array('y' => $reg[6], 'm' => $reg[8], 'd' => $reg[10], 'h' => $reg[2], 'i' => $reg[3], 's' => $reg[5]); // (HH:II(:SS)?)? YYYY(-|/)MM(-|/)DD $matched = true; } if(preg_match('`^([0-9]{2})(-|/)([0-9]{2})(-|/)([0-9]{4})(\s+([0-9]{2}):([0-9]{2})(:([0-9]{2}))?)?$`', $str, $reg)) { $d = array('y' => $reg[5], 'm' => $reg[3], 'd' => $reg[1], 'h' => $reg[7], 'i' => $reg[8], 's' => $reg[10]); // DD(-|/)MM(-|/)YYYY (HH:II(:SS)?)? $matched = true; } if(preg_match('`^(([0-9]{2}):([0-9]{2})(:([0-9]{2}))?\s+)?([0-9]{2})(-|/)([0-9]{2})(-|/)([0-9]{4})$`', $str, $reg)) { $d = array('y' => $reg[10], 'm' => $reg[8], 'd' => $reg[6], 'h' => $reg[2], 'i' => $reg[3], 's' => $reg[5]); // (HH:II(:SS)?)? DD(-|/)MM(-|/)YYYY $matched = true; } // only month and year if(preg_match('`^([0-9]{2})(-|/)([0-9]{4})$`', $str, $reg)) { $d = array('y' => $reg[3], 'm' => $reg[1], 'd' => '', 'h' => '', 'i' => '', 's' => ''); $matched = true; } if(preg_match('`^([0-9]{4})(-|/)([0-9]{2})$`', $str, $reg)) { $d = array('y' => $reg[1], 'm' => $reg[3], 'd' => '', 'h' => '', 'i' => '', 's' => ''); $matched = true; } // only year if(preg_match('`^([0-9]{4})$`', $str, $reg)) { $d = array('y' => $reg[1], 'm' => '', 'd' => '', 'h' => '', 'i' => '', 's' => ''); $matched = true; } // full time hours, minutes (opt) and seconds (opt) // 11 : 11h // 11:30 : 11h30min // 11:30:27 : 11h30min27sec if(preg_match('`^([0-9]{2})(:([0-9]{2})(:([0-9]{2}))?)?$`', $str, $reg)) { $d = array('y' => '', 'm' => '', 'd' => '', 'h' => $reg[7], 'i' => $reg[8], 's' => $reg[10]); // YYYY(-|/)MM(-|/)DD (HH:II(:SS)?)? $matched = true; } // custom datetime format : (XX(XX)?i\s?)+ if(preg_match('`^[0-9]{2}([0-9]{2})?\s?[ymdhis](\s?[0-9]{2}([0-9]{2})?\s?[ymdhis])*$`', $str, $reg)) { while(preg_match('`^(([0-9]{2}([0-9]{2})?)\s?([ymdhis]))`', $str, $reg)) { $v = $reg[2]; $i = $reg[4]; $str = substr($str, strlen($reg[1])); if(($i != 'y') || (strlen($v) == 4)) $d[$i] = $v; } $matched = true; } if(!$matched) return false; $same = true; foreach($time as $k => $v) if(($d[$k] != '') && ($d[$k] != $v)) $same = false; return $same; } // test IP function test_IP($b, &$bug, $lop=false) { if($lop) return array('\=\=?', 'eq', '\!\=', 'neq?', '\~\='); $ip = clientIP(true); if(!$b['test'] || ($b['test'] == '') || !$b['value'] || ($b['value'] == '') || ($ip == '0.0.0.0')) { $bug = true; return false; } switch($b['test']) { case '=' : case 'eq' : case '==' : return ($ip == $b['value']); break; case '!=' : case 'ne' : case 'neq' : return ($ip != $b['value']); break; case '~=' : return (strpos($ip, $b['value']) !== false); break; default: $bug = true; return false; } } } ?> ==== How can I implement some other tests? ==== You must create the //condition_plugin_custom_tester.php// in your template directory and start with this base: To add the test with the key "foo" just add the test method: function test_foo($b, &$bug, $lop=false) { if($lop) return array('\=\=?', '\!\=', '\:'); // list of accepted test operators, pcre style regexp // Here we accept test operators : =, ==, !=, : switch($b['test']) { case '=' : case '==' : return ($b['value'] == 'bar'); break; case '!=' : return ($b['value'] != 'bar'); break; case ':' : // ... default : $bug = true; return false; } } So that test can be used as: foo = barfoo != bar foo = barfoo != bar foo = barfoo != bar ... If your test don't take a parameter you can define it as follows: function test_foo($b, &$bug, $lop=false) { if($lop) return array(); // no test operators global $ID; return preg_match('`^([^\:]+\:)?bar(\:[^\:]+)?$`', $ID); } This test is valid if "bar" is a parent namespace of the page: Page is under "bar" namespace ==== TODO ==== * Allow multiple user custom test files (plugin style)? * Ensure this works well with top-level containers * clean-up and simplify code (mainly reduce calls to preg_replace/match) because it is a bit slow... ==== While discussion isn't working ==== I installed Condition in our production wiki, version 2009-02-14 running on RedHat Enterprise Linux ES 4.0u6 with PHP 4.3.9, and the plugin doesn't seem to work in that environment. Basically, the wiki breaks down immediately after installation and no pages are rendered at all, even before using Condition in any page. Removing the plugin (manually from the file system) restored functionality. I tested the plugin in a CentOS 5.5/PHP 5.1.6 environment before adding it to our production wiki and it worked without problems. Is there a known problem with older DokuWiki and/or PHP versions? > Dunno, can you get apache's error log ? There could be some hints about the bug in it. ==== PHP Errors after saving a changed page with conditions ==== I get the following warnings on all pages with conditions: Warning: array_merge() [function.array-merge]: Argument #1 is not an array in /hp/ab/ac/va/www/Wiki/lib/plugins/condition/syntax.php on line 261 Warning: array_merge() [function.array-merge]: Argument #2 is not an array in /hp/ab/ac/va/www/Wiki/lib/plugins/condition/syntax.php on line 261 Warning: Cannot modify header information - headers already sent by (output started at /hp/ab/ac/va/www/Wiki/lib/plugins/condition/syntax.php:261) in /hp/ab/ac/va/www/Wiki/inc/common.php on line 1543 The page is actually saved correctly. It obviously happens when the changed page is to be rendered. Is this a known issue? //2010-10-06 [[rainer@doerrer.net|Rainer]]// This error exists in %%~~NOTOC~~%% pages. For fixed: into syntax.php search 261 line and add condition before: if (is_array( $renderer->meta['description']['tableofcontents'])) //2010-11-22 [[zefir-cs@ukr.net|Zefir]]// :!: I have the same error, but this code doesn´t solve the problem. If I use the condition-plugin some where in the page all headings get lost for the TOC up to the line where you use the condition plugin. The next heading is used as first heading. If no heading is left, filename is used. //2011-07-03 anonymous// :!: The plugin **does not** work with my installation. I traced the [[https://github.com/gamma/dokuwiki-plugin-condition/issues/1|issue in github]]. //2014-09-23 11:01 [[user>cinlloc|cinlloc]] //