2049 else return false; |
2049 else return false; |
2050 } |
2050 } |
2051 |
2051 |
2052 /** |
2052 /** |
2053 * Fetches the contents of both sidebars. |
2053 * Fetches the contents of both sidebars. |
2054 * @return array - key 0 is left, key 1 is right |
2054 * @return array - key 0 is left, key 1 is right, key 2 is the HTML that makes up an empty sidebar |
2055 * @example list($left, $right) = $template->fetch_sidebar(); |
2055 * @example list($left, $right) = $template->fetch_sidebar(); |
2056 */ |
2056 */ |
2057 |
2057 |
2058 function fetch_sidebar() |
2058 function fetch_sidebar() |
2059 { |
2059 { |
2060 global $db, $session, $paths, $template, $plugins; // Common objects |
2060 global $db, $session, $paths, $template, $plugins; // Common objects |
2061 global $cache; |
2061 |
2062 |
2062 // first, check the cache |
|
2063 if ( $result = $this->fetch_cached_sidebar() ) |
|
2064 { |
|
2065 return $result; |
|
2066 } |
|
2067 |
|
2068 profiler_log('Started sidebar parsing'); |
|
2069 |
|
2070 // init our block contents |
2063 $left = ''; |
2071 $left = ''; |
2064 $right = ''; |
2072 $right = ''; |
2065 |
2073 $min = ''; |
2066 // check the cache |
2074 |
2067 if ( !$session->user_logged_in && $data = $cache->fetch('anon_sidebar') ) |
2075 // also might want the links block |
2068 { |
|
2069 if ( @$data['_theme_'] === $this->theme ) |
|
2070 { |
|
2071 unset($data['_theme_']); |
|
2072 foreach ( $data as &$md ) |
|
2073 { |
|
2074 $md = str_replace('$USERNAME$', $session->username, $md); |
|
2075 $md = str_replace('$PAGEID$', $paths->page, $md); |
|
2076 $md = str_replace('$MAIN_PAGE$', getConfig('main_page'), $md); |
|
2077 } |
|
2078 return $data; |
|
2079 } |
|
2080 } |
|
2081 |
|
2082 if ( !$this->fetch_block('Links') ) |
2076 if ( !$this->fetch_block('Links') ) |
2083 $this->initLinksWidget(); |
2077 $this->initLinksWidget(); |
2084 |
2078 |
2085 $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" |
2079 // templates to work with |
2086 . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); |
|
2087 if(!$q) $db->_die('The sidebar text data could not be selected.'); |
|
2088 |
|
2089 $vars = $this->extract_vars('elements.tpl'); |
2080 $vars = $this->extract_vars('elements.tpl'); |
2090 |
2081 |
2091 if(isset($vars['sidebar_top'])) |
2082 // sidebar_top and sidebar_bottom are HTML that is prepended/appended to sidebar content. Themes can |
|
2083 // choose whether or not to display a sidebar depending on whether the sidebar is empty ( $left == $min ) |
|
2084 // or not using the sidebar_left and sidebar_right template booleans (the oxygen theme does this). |
|
2085 if ( isset($vars['sidebar_top']) ) |
2092 { |
2086 { |
2093 $top = $this->parse($vars['sidebar_top']); |
2087 $top = $this->parse($vars['sidebar_top']); |
2094 $left .= $top; |
2088 $left .= $top; |
2095 $right .= $top; |
2089 $right .= $top; |
2096 } |
2090 $min .= $top; |
2097 |
2091 } |
2098 while($row = $db->fetchrow()) |
2092 |
2099 { |
2093 // grab the blocks from the DB |
2100 switch($row['block_type']) |
2094 $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" |
2101 { |
2095 . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); |
2102 case BLOCK_WIKIFORMAT: |
2096 if ( !$q ) |
2103 default: |
2097 $db->_die('The sidebar text data could not be selected.'); |
2104 $parser = $this->makeParserText($vars['sidebar_section']); |
2098 |
2105 $c = RenderMan::render($row['block_content']); |
2099 // explicitly specify $q in case a plugin or PHP block makes a query |
2106 break; |
2100 while ( $row = $db->fetchrow($q) ) |
2107 case BLOCK_TEMPLATEFORMAT: |
2101 { |
2108 $parser = $this->makeParserText($vars['sidebar_section']); |
2102 // format the block |
2109 $c = $this->tplWikiFormat($row['block_content']); |
2103 $block_content = $this->format_sidebar_block($row, $vars, $parser); |
2110 break; |
2104 |
2111 case BLOCK_HTML: |
|
2112 $parser = $this->makeParserText($vars['sidebar_section_raw']); |
|
2113 $c = $row['block_content']; |
|
2114 break; |
|
2115 case BLOCK_PHP: |
|
2116 $parser = $this->makeParserText($vars['sidebar_section_raw']); |
|
2117 ob_start(); |
|
2118 @eval($row['block_content']); |
|
2119 $c = ob_get_contents(); |
|
2120 ob_end_clean(); |
|
2121 break; |
|
2122 case BLOCK_PLUGIN: |
|
2123 $parser = $this->makeParserText('{CONTENT}'); |
|
2124 $c = '<!-- PLUGIN -->' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? |
|
2125 $this->fetch_block($row['block_content']) : |
|
2126 // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. |
|
2127 ''; |
|
2128 break; |
|
2129 } |
|
2130 // is there a {restrict} or {hideif} block? |
2105 // is there a {restrict} or {hideif} block? |
2131 if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $c, $match) ) |
2106 if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $block_content, $match) ) |
2132 { |
2107 { |
2133 // we have one, check the condition |
2108 // we have one, check the condition |
2134 $type =& $match[1]; |
2109 $type =& $match[1]; |
2135 $cond =& $match[2]; |
2110 $cond =& $match[2]; |
2136 $result = $this->process_condition($cond); |
2111 $result = $this->process_condition($cond); |
2138 { |
2113 { |
2139 // throw out this block, it's hidden for whatever reason by the sidebar script |
2114 // throw out this block, it's hidden for whatever reason by the sidebar script |
2140 continue; |
2115 continue; |
2141 } |
2116 } |
2142 // didn't get a match, so hide the conditional logic |
2117 // didn't get a match, so hide the conditional logic |
2143 $c = str_replace_once($match[0], '', $c); |
2118 // FIXME: this needs to be verbose about syntax errors |
2144 } |
2119 $block_content = str_replace_once($match[0], '', $block_content); |
2145 |
2120 } |
2146 $parser->assign_vars(Array( 'TITLE'=>$this->tplWikiFormat($row['block_name']), 'CONTENT'=>$c )); |
2121 |
2147 $run = $parser->run(); |
2122 // if we made it here, this block definitely needs to be displayed. send it to the |
|
2123 // parser (set by format_sidebar_block) and decide where to append it (but not in that order ;)) |
|
2124 $appender = false; |
|
2125 |
|
2126 if ( $row['sidebar_id'] == SIDEBAR_LEFT ) |
|
2127 { |
|
2128 $appender =& $left; |
|
2129 } |
|
2130 else if ( $row['sidebar_id'] == SIDEBAR_RIGHT ) |
|
2131 { |
|
2132 $appender =& $right; |
|
2133 } |
|
2134 else |
|
2135 { |
|
2136 // uhoh, block_id isn't valid. maybe a plugin wants to put this block somewhere else? |
|
2137 $code = $plugins->setHook('sidebar_block_id'); |
|
2138 foreach ( $code as $cmd ) |
|
2139 { |
|
2140 eval($cmd); |
|
2141 } |
|
2142 // if $appender wasn't set by a plugin, don't parse this block to save some CPU cycles |
|
2143 if ( !$appender ) |
|
2144 { |
|
2145 continue; |
|
2146 } |
|
2147 } |
|
2148 |
|
2149 // assign variables to parser |
|
2150 $block_name = $this->tplWikiFormat($row['block_name']); |
|
2151 $parser->assign_vars(array( |
|
2152 // be nice and format the title (FIXME, does this use a lot of CPU time? still needs l10n in some cases though) |
|
2153 'TITLE' => $block_name, |
|
2154 'CONTENT' => $block_content |
|
2155 )); |
|
2156 $parsed = $parser->run(); |
|
2157 |
|
2158 // plugins are parsed earlier due to the way disabled/missing plugins that add sidebar blocks are |
|
2159 // handled, so the {TITLE} var won't be replaced until now. this allows completely eliminating a |
|
2160 // block if it's not available |
2148 if ( $row['block_type'] == BLOCK_PLUGIN ) |
2161 if ( $row['block_type'] == BLOCK_PLUGIN ) |
2149 { |
2162 { |
2150 $run = str_replace('{TITLE}', $this->tplWikiFormat($row['block_name']), $run); |
2163 $parsed = str_replace('{TITLE}', $block_name, $parsed); |
2151 } |
2164 } |
2152 if ($row['sidebar_id'] == SIDEBAR_LEFT ) $left .= $run; |
2165 |
2153 elseif($row['sidebar_id'] == SIDEBAR_RIGHT) $right .= $run; |
2166 // done parsing - append and continue |
2154 unset($parser); |
2167 $appender .= $parsed; |
2155 } |
2168 |
2156 $db->free_result(); |
2169 // we're done with this - unset it because it's a reference and we don't want it overwritten. |
|
2170 // also free the parser to get some RAM back |
|
2171 unset($appender, $parser); |
|
2172 } |
|
2173 |
|
2174 // lastly, append any footer HTML |
2157 if(isset($vars['sidebar_bottom'])) |
2175 if(isset($vars['sidebar_bottom'])) |
2158 { |
2176 { |
2159 $bottom = $this->parse($vars['sidebar_bottom']); |
2177 $bottom = $this->parse($vars['sidebar_bottom']); |
2160 $left .= $bottom; |
2178 $left .= $bottom; |
2161 $right .= $bottom; |
2179 $right .= $bottom; |
2162 } |
2180 $min .= $bottom; |
2163 $min = ''; |
2181 } |
2164 if(isset($vars['sidebar_top'])) |
2182 |
2165 { |
2183 $return = array($left, $right, $min); |
2166 $min .= $top; |
2184 |
2167 } |
2185 // allow any plugins to append what they want to the return |
2168 if(isset($vars['sidebar_bottom'])) |
2186 $code = $plugins->setHook('sidebar_fetch_return'); |
2169 { |
2187 foreach ( $code as $cmd ) |
2170 $min .= $bottom; |
2188 { |
2171 } |
2189 eval($cmd); |
2172 $return = Array($left, $right, $min); |
2190 } |
2173 if ( getConfig('cache_thumbs') == '1' && !$session->user_logged_in ) |
2191 |
2174 { |
2192 // cache the result if appropriate |
2175 $cachestore = enano_json_encode($return); |
2193 $this->cache_compiled_sidebar($return); |
2176 $cachestore = str_replace($session->username, '$USERNAME$', $cachestore); |
2194 |
2177 $cachestore = str_replace($paths->page, '$PAGEID$', $cachestore); |
2195 profiler_log('Finished sidebar parsing'); |
2178 $cachestore = str_replace('__STATICLINK__', $paths->page, $cachestore); |
2196 |
2179 $cachestore = str_replace('__MAINPAGELINK__', '$MAIN_PAGE$', $cachestore); |
|
2180 $cachestore = enano_json_decode($cachestore); |
|
2181 $cachestore['_theme_'] = $this->theme; |
|
2182 $cache->store('anon_sidebar', $cachestore, 10); |
|
2183 |
|
2184 foreach ( $return as &$el ) |
|
2185 { |
|
2186 $el = str_replace('__STATICLINK__', $paths->page, $el); |
|
2187 } |
|
2188 } |
|
2189 return $return; |
2197 return $return; |
|
2198 } |
|
2199 |
|
2200 /** |
|
2201 * Runs the appropriate formatting routine on a sidebar row. |
|
2202 * @param array Row in sidebar table |
|
2203 * @param array Template variable set from elements.tpl |
|
2204 * @param null Pass by reference, will be filled with the parser according to the block's type (sidebar_section or sidebar_section_raw) |
|
2205 * @return string HTML + directives like {restrict} or {hideif} |
|
2206 */ |
|
2207 |
|
2208 function format_sidebar_block($row, $vars, &$parser) |
|
2209 { |
|
2210 // import globals in case a PHP block wants to call the Enano API |
|
2211 global $db, $session, $paths, $template, $plugins; // Common objects |
|
2212 |
|
2213 $parser = null; |
|
2214 |
|
2215 switch($row['block_type']) |
|
2216 { |
|
2217 case BLOCK_WIKIFORMAT: |
|
2218 $parser = $this->makeParserText($vars['sidebar_section']); |
|
2219 $c = RenderMan::render($row['block_content']); |
|
2220 break; |
|
2221 |
|
2222 case BLOCK_TEMPLATEFORMAT: |
|
2223 $parser = $this->makeParserText($vars['sidebar_section']); |
|
2224 $c = $this->tplWikiFormat($row['block_content']); |
|
2225 break; |
|
2226 |
|
2227 case BLOCK_HTML: |
|
2228 $parser = $this->makeParserText($vars['sidebar_section_raw']); |
|
2229 $c = $row['block_content']; |
|
2230 break; |
|
2231 |
|
2232 case BLOCK_PHP: |
|
2233 // PHP blocks need to be sent directly to eval() |
|
2234 $parser = $this->makeParserText($vars['sidebar_section_raw']); |
|
2235 ob_start(); |
|
2236 @eval($row['block_content']); |
|
2237 $c = ob_get_contents(); |
|
2238 ob_end_clean(); |
|
2239 break; |
|
2240 |
|
2241 case BLOCK_PLUGIN: |
|
2242 $parser = $this->makeParserText('{CONTENT}'); |
|
2243 $c = '<!-- PLUGIN -->' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? |
|
2244 $this->fetch_block($row['block_content']) : |
|
2245 // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. |
|
2246 ''; |
|
2247 break; |
|
2248 default: |
|
2249 // unknown block type - can a plugin handle it? |
|
2250 $code = $plugins->setHook('format_sidebar_block'); |
|
2251 foreach ( $code as $cmd ) |
|
2252 { |
|
2253 eval($cmd); |
|
2254 } |
|
2255 if ( !isset($c) ) |
|
2256 { |
|
2257 // default to wiki formatting (this was going to be straight HTML but this is done for backwards compatibility reasons) |
|
2258 $c = RenderMan::render($row['block_content']); |
|
2259 } |
|
2260 if ( !$parser ) |
|
2261 { |
|
2262 // no parser defined, use the "raw" section by default (plugins are more likely to want raw content |
|
2263 // rather than a list of links, and they can set the parser to use sidebar_section if they want) |
|
2264 $parser = $this->makeParserText($vars['sidebar_section_raw']); |
|
2265 } |
|
2266 |
|
2267 break; |
|
2268 } |
|
2269 |
|
2270 return $c; |
|
2271 } |
|
2272 |
|
2273 /** |
|
2274 * Returns the list of things that should not be cached (sorry, I was listening to "The Thing That Should Not Be" by Metallica when I |
|
2275 * wrote this routine. You should get a copy of Master of Puppets, it's a damn good album.) |
|
2276 * @return array |
|
2277 */ |
|
2278 |
|
2279 function get_cache_replacements() |
|
2280 { |
|
2281 global $db, $session, $paths, $template, $plugins; // Common objects |
|
2282 |
|
2283 return array( |
|
2284 '$LOGIN_LINK$' => $this->tpl_strings['LOGIN_LINK'], |
|
2285 '$MAIN_PAGE$' => $this->tpl_strings['MAIN_PAGE'], |
|
2286 '$USERNAME$' => $session->username |
|
2287 ); |
|
2288 } |
|
2289 |
|
2290 /** |
|
2291 * Attempts to load a cached compiled sidebar. |
|
2292 * @return array Same format as fetch_sidebar() |
|
2293 */ |
|
2294 |
|
2295 function fetch_cached_sidebar() |
|
2296 { |
|
2297 global $db, $session, $paths, $template, $plugins; // Common objects |
|
2298 global $cache; |
|
2299 |
|
2300 $cached = false; |
|
2301 if ( ($result = $cache->fetch('anon_sidebar')) && !$session->user_logged_in ) |
|
2302 { |
|
2303 if ( isset($result[$this->theme]) ) |
|
2304 { |
|
2305 $cached = $result[$this->theme]; |
|
2306 } |
|
2307 } |
|
2308 |
|
2309 // if we haven't been able to fetch yet, see if a plugin wants to give us something |
|
2310 if ( !$cached ) |
|
2311 { |
|
2312 $code = $plugins->setHook('fetch_cached_sidebar'); |
|
2313 foreach ( $code as $cmd ) |
|
2314 { |
|
2315 eval($cmd); |
|
2316 } |
|
2317 } |
|
2318 |
|
2319 if ( is_array($cached) ) |
|
2320 { |
|
2321 // fetch certain variables that can't be stored in the cache and quickly substitute |
|
2322 $replace = $this->get_cache_replacements(); |
|
2323 foreach ( $cached as &$val ) |
|
2324 { |
|
2325 $val = strtr($val, $replace); |
|
2326 } |
|
2327 |
|
2328 // done processing, send it back |
|
2329 return $cached; |
|
2330 } |
|
2331 |
|
2332 return false; |
|
2333 } |
|
2334 |
|
2335 /** |
|
2336 * Caches a completely compiled sidebar, if appropriate |
|
2337 * @param array Effectively, return from fetch_sidebar() |
|
2338 */ |
|
2339 |
|
2340 function cache_compiled_sidebar($sidebar) |
|
2341 { |
|
2342 global $db, $session, $paths, $template, $plugins; // Common objects |
|
2343 global $cache; |
|
2344 |
|
2345 // check if conditions are right |
|
2346 if ( !$session->user_logged_in && getConfig('cache_thumbs') === '1' ) |
|
2347 { |
|
2348 // load any existing cache to make sure other themes' cached sidebars aren't discarded |
|
2349 $cached = ( $_ = $cache->fetch('anon_sidebar') ) ? $_ : array(); |
|
2350 |
|
2351 // replace variables |
|
2352 $replace = array_flip($this->get_cache_replacements()); |
|
2353 |
|
2354 foreach ( $sidebar as &$section ) |
|
2355 { |
|
2356 $section = strtr($section, $replace); |
|
2357 } |
|
2358 |
|
2359 // compile |
|
2360 $cached[$this->theme] = $sidebar; |
|
2361 |
|
2362 // store |
|
2363 $cache->store('anon_sidebar', $cached, 15); |
|
2364 } |
2190 } |
2365 } |
2191 |
2366 |
2192 function initLinksWidget() |
2367 function initLinksWidget() |
2193 { |
2368 { |
2194 global $db, $session, $paths, $template, $plugins; // Common objects |
2369 global $db, $session, $paths, $template, $plugins; // Common objects |