load_plugins(); $this->run_hooks('plugins_loaded'); // Load the settings $settings = $this->get_config(); $this->run_hooks('config_loaded', array(&$settings)); // Get request url and script url $url = ''; $request_url = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; $script_url = (isset($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : ''; // Get our url path and trim the / of the left and the right if ($request_url != $script_url) { $url = trim(preg_replace('/' . str_replace('/', '\/', str_replace('index.php', '', $script_url)) . '/', '', $request_url, 1), '/'); } $url = preg_replace('/\?.*/', '', $url); // Strip query string $this->run_hooks('request_url', array(&$url)); // Get the file path if ($url) { $file = $settings['content_dir'] . $url; } else { $file = $settings['content_dir'] . 'index'; } // Load the file if (is_dir($file)) { $file = $settings['content_dir'] . $url . '/index' . CONTENT_EXT; } else { $file .= CONTENT_EXT; } $this->run_hooks('before_load_content', array(&$file)); if (file_exists($file)) { $content = file_get_contents($file); } else { $this->run_hooks('before_404_load_content', array(&$file)); $content = file_get_contents($settings['content_dir'] . '404' . CONTENT_EXT); header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); $this->run_hooks('after_404_load_content', array(&$file, &$content)); } $this->run_hooks('after_load_content', array(&$file, &$content)); $meta = $this->read_file_meta($content); $this->run_hooks('file_meta', array(&$meta)); $this->run_hooks('before_parse_content', array(&$content)); $content = $this->parse_content($content); $this->run_hooks('after_parse_content', array(&$content)); $this->run_hooks('content_parsed', array(&$content)); // Depreciated @ v0.8 // Get all the pages $pages = $this->get_pages($settings['base_url'], $settings['pages_order_by'], $settings['pages_order'], $settings['excerpt_length']); $prev_page = array(); $current_page = array(); $next_page = array(); while ($current_page = current($pages)) { if ((isset($meta['title'])) && ($meta['title'] == $current_page['title'])) { break; } next($pages); } $prev_page = next($pages); prev($pages); $next_page = prev($pages); $this->run_hooks('get_pages', array(&$pages, &$current_page, &$prev_page, &$next_page)); // Load the theme $this->run_hooks('before_twig_register'); Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(THEMES_DIR . $settings['theme']); $twig = new Twig_Environment($loader, $settings['twig_config']); $twig->addExtension(new Twig_Extension_Debug()); $twig_vars = array( 'config' => $settings, 'base_dir' => rtrim(ROOT_DIR, '/'), 'base_url' => $settings['base_url'], 'theme_dir' => THEMES_DIR . $settings['theme'], 'theme_url' => $settings['base_url'] . '/' . basename(THEMES_DIR) . '/' . $settings['theme'], 'site_title' => $settings['site_title'], 'meta' => $meta, 'content' => $content, 'pages' => $pages, 'prev_page' => $prev_page, 'current_page' => $current_page, 'next_page' => $next_page, 'is_front_page' => $url ? false : true, ); $template = (isset($meta['template']) && $meta['template']) ? $meta['template'] : 'index'; $this->run_hooks('before_render', array(&$twig_vars, &$twig, &$template)); $output = $twig->render($template . '.html', $twig_vars); $this->run_hooks('after_render', array(&$output)); echo $output; } /** * Load any plugins */ protected function load_plugins() { $this->plugins = array(); $plugins = $this->get_files(PLUGINS_DIR, '.php'); if (!empty($plugins)) { foreach ($plugins as $plugin) { include_once($plugin); $plugin_name = preg_replace("/\\.[^.\\s]{3}$/", '', basename($plugin)); if (class_exists($plugin_name)) { $obj = new $plugin_name; $this->plugins[] = $obj; } } } } /** * Parses the content using Parsedown-extra * * @param string $content the raw txt content * @return string $content the Markdown formatted content */ protected function parse_content($content) { $content = preg_replace('#/\*.+?\*/#s', '', $content, 1); // Remove first comment (with meta) $content = str_replace('%base_url%', $this->base_url(), $content); $Parsedown = new ParsedownExtra(); $content= $Parsedown->text($content); return $content; } /** * Parses the file meta from the txt file header * * @param string $content the raw txt content * @return array $headers an array of meta values */ protected function read_file_meta($content) { $config = $this->config; $headers = array( 'title' => 'Title', 'description' => 'Description', 'author' => 'Author', 'date' => 'Date', 'robots' => 'Robots', 'template' => 'Template' ); // Add support for custom headers by hooking into the headers array $this->run_hooks('before_read_file_meta', array(&$headers)); foreach ($headers as $field => $regex) { if (preg_match('/^[ \t\/*#@]*' . preg_quote($regex, '/') . ':(.*)$/mi', $content, $match) && $match[1]) { $headers[$field] = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $match[1])); } else { $headers[$field] = ''; } } if (isset($headers['date'])) { $headers['date_formatted'] = utf8_encode(strftime($config['date_format'], strtotime($headers['date']))); } return $headers; } /** * Loads the config * * @return array $config an array of config values */ protected function get_config() { if (file_exists(CONFIG_DIR . 'config.php')) { $this->config = require(CONFIG_DIR . 'config.php'); } else if (file_exists(ROOT_DIR . 'config.php')) { // deprecated $this->config = require(ROOT_DIR . 'config.php'); } $defaults = array( 'site_title' => 'Pico', 'base_url' => $this->base_url(), 'theme' => 'default', 'date_format' => '%D %T', 'twig_config' => array('cache' => false, 'autoescape' => false, 'debug' => false), 'pages_order_by' => 'alpha', 'pages_order' => 'asc', 'excerpt_length' => 50, 'content_dir' => 'content-sample/', ); if (is_array($this->config)) { $this->config = array_merge($defaults, $this->config); } else { $this->config = $defaults; } return $this->config; } /** * Get a list of pages * * @param string $base_url the base URL of the site * @param string $order_by order by "alpha" or "date" * @param string $order order "asc" or "desc" * @return array $sorted_pages an array of pages */ protected function get_pages($base_url, $order_by = 'alpha', $order = 'asc', $excerpt_length = 50) { $config = $this->config; $pages = $this->get_files($config['content_dir'], CONTENT_EXT); $sorted_pages = array(); $date_id = 0; foreach ($pages as $key => $page) { // Skip 404 if (basename($page) == '404' . CONTENT_EXT) { unset($pages[$key]); continue; } // Ignore Emacs (and Nano) temp files if (in_array(substr($page, -1), array('~', '#'))) { unset($pages[$key]); continue; } // Get title and format $page $page_content = file_get_contents($page); $page_meta = $this->read_file_meta($page_content); $page_content = $this->parse_content($page_content); $url = str_replace($config['content_dir'], $base_url . '/', $page); $url = str_replace('index' . CONTENT_EXT, '', $url); $url = str_replace(CONTENT_EXT, '', $url); $data = array( 'title' => isset($page_meta['title']) ? $page_meta['title'] : '', 'url' => $url, 'author' => isset($page_meta['author']) ? $page_meta['author'] : '', 'date' => isset($page_meta['date']) ? $page_meta['date'] : '', 'date_formatted' => isset($page_meta['date']) ? utf8_encode(strftime($config['date_format'], strtotime($page_meta['date']))) : '', 'content' => $page_content, 'excerpt' => $this->limit_words(strip_tags($page_content), $excerpt_length), //this addition allows the 'description' meta to be picked up in content areas... specifically to replace 'excerpt' 'description' => isset($page_meta['description']) ? $page_meta['description'] : '', ); // Extend the data provided with each page by hooking into the data array $this->run_hooks('get_page_data', array(&$data, $page_meta)); if ($order_by == 'date' && isset($page_meta['date'])) { $sorted_pages[$page_meta['date'] . $date_id] = $data; $date_id++; } else { $sorted_pages[$page] = $data; } } if ($order == 'desc') { krsort($sorted_pages); } else { ksort($sorted_pages); } return $sorted_pages; } /** * Processes any hooks and runs them * * @param string $hook_id the ID of the hook * @param array $args optional arguments */ protected function run_hooks($hook_id, $args = array()) { if (!empty($this->plugins)) { foreach ($this->plugins as $plugin) { if (is_callable(array($plugin, $hook_id))) { call_user_func_array(array($plugin, $hook_id), $args); } } } } /** * Helper function to work out the base URL * * @return string the base url */ protected function base_url() { $config = $this->config; if (isset($config['base_url']) && $config['base_url']) { return $config['base_url']; } $url = ''; $request_url = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; $script_url = (isset($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : ''; if ($request_url != $script_url) { $url = trim(preg_replace('/' . str_replace('/', '\/', str_replace('index.php', '', $script_url)) . '/', '', $request_url, 1), '/'); } $protocol = $this->get_protocol(); return rtrim(str_replace($url, '', $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']), '/'); } /** * Tries to guess the server protocol. Used in base_url() * * @return string the current protocol */ protected function get_protocol() { $protocol = 'http'; if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' && $_SERVER['HTTPS'] != '') { $protocol = 'https'; } return $protocol; } /** * Helper function to recusively get all files in a directory * * @param string $directory start directory * @param string $ext optional limit to file extensions * @return array the matched files */ protected function get_files($directory, $ext = '') { $array_items = array(); if ($handle = opendir($directory)) { while (false !== ($file = readdir($handle))) { if (in_array(substr($file, -1), array('~', '#'))) { continue; } if (preg_match("/^(^\.)/", $file) === 0) { if (is_dir($directory . "/" . $file)) { $array_items = array_merge($array_items, $this->get_files($directory . "/" . $file, $ext)); } else { $file = $directory . "/" . $file; if (!$ext || strstr($file, $ext)) { $array_items[] = preg_replace("/\/\//si", "/", $file); } } } } closedir($handle); } return $array_items; } /** * Helper function to limit the words in a string * * @param string $string the given string * @param int $word_limit the number of words to limit to * @return string the limited string */ protected function limit_words($string, $word_limit) { $words = explode(' ', $string); $excerpt = trim(implode(' ', array_splice($words, 0, $word_limit))); if (count($words) > $word_limit) { $excerpt .= '…'; } return $excerpt; } }