Esempio n. 1
0
 /**
  * Constructor
  *
  * @param \Kanso\Database\Database $db (optional)
  */
 public function __construct($db = null)
 {
     # Save the database access instance locally
     $this->Database = !$db ? \Kanso\Kanso::getInstance()->Database : $db;
     # create a new query object
     $this->Query = new Query($this->Database);
 }
Esempio n. 2
0
 /**
  * Install Kanso
  *
  * This method will restore/install Kanso to it's default settings
  * If $asDefault is set to true, the current Kanso application
  * will be reistalled, otherwise it is installed from settings
  * found in Install.ini.php
  *
  * @param  boolean    $asDefault  Install default factory settings
  * @return boolean
  */
 public function installKanso($asDefault = false)
 {
     # Validate Kanso is NOT alread installed if this
     # is a fresh install
     if (!$asDefault) {
         # Validate installation
         if ($this->isInstalled) {
             throw new \Exception("Could not install, Kanso is already installed.");
         }
         $settings = new \Kanso\Config\Settings(true);
         $config = $settings->get();
     } else {
         $current = \Kanso\Kanso::getInstance()->Config;
         $defaults = \Kanso\Kanso::getInstance()->Settings->defaults;
         $userData = ['KANSO_OWNER_USERNAME' => $current['KANSO_OWNER_USERNAME'], 'KANSO_OWNER_EMAIL' => $current['KANSO_OWNER_EMAIL'], 'KANSO_OWNER_PASSWORD' => $current['KANSO_OWNER_PASSWORD'], 'host' => $current['host'], 'user' => $current['user'], 'password' => $current['password'], 'dbname' => $current['dbname'], 'table_prefix' => $current['table_prefix']];
         $config = array_merge($defaults, $userData);
     }
     $this->config = $config;
     # Do a test connection to the database to validate DB credentials are valid
     $this->DBConnect();
     # Install the Kanso database
     $this->installDB();
     # Save the config
     file_put_contents($this->KansoDir . '/Config.php', "<?php\nreturn\n" . var_export($config, true) . ";?>");
     # Delete the install file
     if (file_exists($this->KansoDir . '/Install.php')) {
         unlink($this->KansoDir . '/Install.php');
     }
     return true;
 }
Esempio n. 3
0
 /**
  * Create an output buffer from a template
  *
  * This function will include the functions from the Query
  * for use in templates
  *
  * @see \Kanso\Helper\ToolBox
  * @see \Kanso\MVC\ViewIncludes.php
  * @param string $template  Absolute path to template file
  */
 public function display($template)
 {
     $Kanso = \Kanso\Kanso::getInstance();
     $functions = $Kanso->Environment['KANSO_THEME_DIR'] . DIRECTORY_SEPARATOR . $Kanso->Config['KANSO_THEME_NAME'] . DIRECTORY_SEPARATOR . 'functions.php';
     if (file_exists($functions)) {
         require_once $functions;
     }
     require_once 'ViewIncludes.php';
     extract($this->data);
     ob_start();
     require_once $template;
     return ob_get_clean();
 }
Esempio n. 4
0
    private static function buildHome()
    {
        # Get a Kanso instance
        $Kanso = \Kanso\Kanso::getInstance();
        # Build the XML
        $xml = '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
	<channel>
		<title>' . $Kanso->Config['KANSO_SITE_TITLE'] . '</title>
		<atom:link href="' . $Kanso->Environment['HTTP_HOST'] . '/feed/" rel="self" type="application/rss+xml" />
		<link>' . $Kanso->Environment['HTTP_HOST'] . '</link>
		<description>' . $Kanso->Config['KANSO_SITE_DESCRIPTION'] . '</description>
		<lastBuildDate>Wed, 30 Dec 2015 05:43:12 +0000</lastBuildDate>
		<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<generator>http://kanso.pencilscoop.com</generator>';
        # Loop 2 posts
        $i = 0;
        while ($Kanso->Query->have_posts() && $i < 2) {
            $i++;
            $Kanso->Query->the_post();
            # Output the item
            $xml .= '
		<item>
			<title>' . $Kanso->Query->the_title() . '</title>
			<link>' . $Kanso->Query->the_permalink() . '</link>
			
			<pubDate>' . $Kanso->Query->the_time('D, d M Y H:i:s') . '</pubDate>
			<dc:creator>' . $Kanso->Query->the_author() . '</dc:creator>
			<category>' . $Kanso->Query->the_category() . '</category>
			<description>' . $Kanso->Query->the_excerpt() . '</description>
			<wfw:commentRss>' . $Kanso->Environment['REQUEST_URL'] . '</wfw:commentRss>
			<slash:comments>' . $Kanso->Query->comments_number() . '</slash:comments>
		</item>';
        }
        #Close the xml
        $xml .= '
	</channel>
</rss>';
        # Return the xml
        return $xml;
    }
Esempio n. 5
0
 /**
  * Constructor
  *
  * @param array $settings (optional)
  */
 public function __construct($settings = null)
 {
     # Set the default settings
     if ($settings) {
         $this->settings = $settings;
     } else {
         $this->settings = \Kanso\Kanso::getInstance()->Config;
     }
     # Establish a DB connection
     $this->Connect();
     # Clear the parameters
     $this->parameters = [];
     # Set the table prefix
     $this->tablePrefix = $this->settings['table_prefix'];
 }
Esempio n. 6
0
 *		RewriteCond %{REQUEST_METHOD} =GET
 *	    RewriteRule ^Kanso/.*$ index.php?$1
 *
 * </IfModule>
 *
 * A sample htaccess file is included in Kanso's 
 * installation package.
 */
# Set the value error reporting configuration to E_ALL
# on PHP's ini
# Remove this if you don't want php to output runtime
# errors to HTTP client.
ini_set('display_errors', 1);
# Set the error_reporting directive at runtime
# Remove this if you don't want php to output runtime
# errors to HTTP client.
error_reporting(E_ALL);
# Set the default timezone. Adjust to your own timezone
# if desired
date_default_timezone_set('America/New_York');
# Require Kanso's main class file
require_once 'Kanso/Kanso.php';
# Register Kanso's auto-loader
# This should be removed if you are using Composer's autoloader
\Kanso\Kanso::registerAutoloader();
# Create a new Kanso object
$Kanso = new Kanso\Kanso();
# Any customizations should go here - i.e
# after Kanso's instantiation but before any dispatching.
# Initialize and run Kanso
$Kanso->run();
Esempio n. 7
0
 /**
  * Log client out
  *
  * This is responsible for logging a client out of the 
  * admin panel.
  *
  */
 private function logClientOut()
 {
     # Fire the event
     \Kanso\Events::fire('logout', $this->user);
     # Clear the session
     \Kanso\Kanso::getInstance()->Session->clear();
 }
Esempio n. 8
0
function adminAllUsers()
{
    return \Kanso\Kanso::getInstance()->Database->Builder()->SELECT("*")->FROM('users')->FIND_ALL();
}
Esempio n. 9
0
 /**
  * Change a comments status
  *
  * @return bool
  */
 private function actionComments($status)
 {
     # Validate the user is logged in
     if (!$this->isLoggedIn) {
         return false;
     }
     # Grab the user's row from the session
     $user = \Kanso\Kanso::getInstance()->Session->get('KANSO_ADMIN_DATA');
     # Validate the user is an admin
     if ($user['role'] !== 'administrator') {
         return false;
     }
     # Filter and sanitize the POST variables
     $postVars = $this->GUMP->sanitize($this->postVars);
     $this->GUMP->validation_rules(['comment_ids' => 'required']);
     $this->GUMP->filter_rules(['comment_ids' => 'trim|sanitize_string']);
     $validated_data = $this->GUMP->run($postVars);
     if ($validated_data) {
         $comment_ids = array_map('intval', explode(',', $validated_data['comment_ids']));
         if (empty($comment_ids)) {
             return false;
         }
         foreach ($comment_ids as $id) {
             if (!\Kanso\Comments\CommentManager::status($id, $status)) {
                 return false;
             }
         }
         return true;
     }
     return false;
 }
Esempio n. 10
0
 /**
  * Regenerate the ajax token
  *
  * @return boolean
  */
 public function regenerateToken()
 {
     # Generate the keys
     $keys = Token::generate();
     $keys = ['kanso_public_key' => $keys['key'], 'kanso_public_salt' => $keys['salt'], 'kanso_keys_time' => time()];
     # Save to the session
     $this->putMultiple($keys);
     # If the user is logged in, save the keys to their admin
     # data as well
     $adminData = $this->get('KANSO_ADMIN_DATA');
     if (!empty($adminData)) {
         $id = $adminData['id'];
         \Kanso\Kanso::getInstance()->Database()->Builder()->UPDATE('users')->SET($keys)->WHERE('id', '=', $id)->QUERY();
         $this->put('KANSO_ADMIN_DATA', array_merge($adminData, $keys));
     }
     return true;
 }
Esempio n. 11
0
 /**
  * Clear the entire cache or a single file
  *
  * @param  string    $url    A valid permalink wildcard (optional)
  * @return bool
  */
 public function clearCache($url = false)
 {
     if ($url) {
         $name = substr($url, strrpos($url, '/') + 1);
         $name = \Kanso\Utility\Str::slugFilter(preg_replace("/\\..+/", '', $name));
         $file = \Kanso\Kanso::getInstance()->Environment['KANSO_DIR'] . DIRECTORY_SEPARATOR . 'Cache' . DIRECTORY_SEPARATOR . 'Library' . DIRECTORY_SEPARATOR . $name . '.html';
         if (file_exists($file) && is_file($file)) {
             return unlink($file);
         }
     } else {
         $files = glob(\Kanso\Kanso::getInstance()->Environment['KANSO_DIR'] . DIRECTORY_SEPARATOR . 'Cache' . DIRECTORY_SEPARATOR . 'Library' . DIRECTORY_SEPARATOR . '*');
         foreach ($files as $file) {
             if (is_file($file)) {
                 if (!unlink($file)) {
                     return false;
                 }
             }
         }
         return true;
     }
     return false;
 }
Esempio n. 12
0
 /**
  * Change the status of an existing comment
  *
  * @param  int       $commentID    Comment ID to change
  * @param  string    $status       The status to be set
  * @return bool   
  */
 public static function status($commentID, $status)
 {
     # Validate that a kanso instance has been called
     if (is_null(self::$Kanso)) {
         self::$Kanso = \Kanso\Kanso::getInstance();
     }
     # Get a new Query builder
     $Query = self::$Kanso->Database()->Builder();
     # Validate the status is allowed
     $statuses = ['approved', 'spam', 'deleted', 'pending'];
     if (!in_array($status, $statuses)) {
         return false;
     }
     # Get the comment row from the database
     $commentRow = $Query->SELECT('*')->FROM('comments')->where('id', '=', (int) $commentID)->FIND();
     # Validate the row exists
     if (!$commentRow) {
         return false;
     }
     # Change and save the status
     $Query->UPDATE('comments')->SET(['status' => $status])->WHERE('id', '=', (int) $commentID)->QUERY();
     return true;
 }
Esempio n. 13
0
 /**
  * Remove a slug from Kanso's author pages configuration (used internally)
  *
  * @param  string    $slug    The slug to be removed
  */
 private function removeAuthorSlug($slug)
 {
     # Get the config
     $slugs = \Kanso\Kanso::getInstance()->Config['KANSO_AUTHOR_SLUGS'];
     # Remove the slug
     foreach ($slugs as $i => $configSlug) {
         if ($configSlug === $slug) {
             unset($slugs[$i]);
         }
     }
     \Kanso\Kanso::getInstance()->Settings->put('KANSO_AUTHOR_SLUGS', array_values($slugs));
 }
Esempio n. 14
0
 /**
  * Parse the current query
  * 
  * @return array
  */
 private function executeQuery()
 {
     $Query = \Kanso\Kanso::getInstance()->Database()->Builder();
     $Query->SELECT("posts.*");
     $Query->FROM($this->QueryVars['FROM']);
     if (!empty($this->QueryVars['AND_WHERE'])) {
         foreach ($this->QueryVars['AND_WHERE'] as $condition) {
             if ($condition['op'] === 'LIKE') {
                 $condition['val'] = '%' . str_replace('%', '', $condition['val']) . '%';
             }
             $Query->AND_WHERE($condition['field'], $condition['op'], $condition['val']);
         }
     }
     if (!empty($this->QueryVars['OR_WHERE'])) {
         foreach ($this->QueryVars['OR_WHERE'] as $condition) {
             if ($condition['op'] === 'LIKE') {
                 $condition['val'] = '%' . str_replace('%', '', $condition['val']) . '%';
             }
             $Query->OR_WHERE($condition['field'], $condition['op'], $condition['val']);
         }
     }
     $Query->LEFT_JOIN_ON('users', 'users.id = posts.author_id');
     $Query->LEFT_JOIN_ON('comments', 'comments.post_id = posts.id');
     $Query->LEFT_JOIN_ON('categories', 'posts.category_id = categories.id');
     $Query->LEFT_JOIN_ON('tags_to_posts', 'posts.id = tags_to_posts.post_id');
     $Query->LEFT_JOIN_ON('tags', 'tags.id = tags_to_posts.tag_id');
     $Query->GROUP_BY('posts.id');
     if (!empty($this->QueryVars['ORDER_BY'])) {
         $Query->ORDER_BY($this->QueryVars['ORDER_BY'][0], $this->QueryVars['ORDER_BY'][1]);
     }
     if (!empty($this->QueryVars['LIMIT'])) {
         if (isset($this->QueryVars['LIMIT'][1])) {
             $Query->LIMIT($this->QueryVars['LIMIT'][0], $this->QueryVars['LIMIT'][1]);
         } else {
             $Query->LIMIT($this->QueryVars['LIMIT'][0]);
         }
     }
     $articles = $Query->FIND_ALL();
     $aticleObjs = [];
     if (!empty($articles)) {
         foreach ($articles as $row) {
             $aticleObjs[] = new \Kanso\Articles\Article($row);
         }
     }
     return $aticleObjs;
 }
Esempio n. 15
0
 /**
  * Finalize response headers
  *
  * This prepares the response and returns an array
  * of [status, headers, body]. This array is passed to Kanso's runner
  *
  * @return array[int status, array headers, string body]
  */
 public function finalize()
 {
     $Kanso = \Kanso\Kanso::getInstance();
     if ($Kanso->Config()['KANSO_USE_CDN'] && !$Kanso->is_admin) {
         $cdnFilter = new \Kanso\CDN\CDN($Kanso->Environment['HTTP_HOST'], $Kanso->Config['KASNO_CDN_URL'], $this->body);
         $this->body = $cdnFilter->filter();
         $this->length = strlen($this->body);
     }
     $this->addheaders('Content-length', $this->length);
     if (in_array($this->status, [204, 304])) {
         $this->headers->remove('Content-Type');
         $this->headers->remove('Content-Length');
         $this->setBody('');
     }
     return [$this->status, $this->headers, $this->body];
 }
Esempio n. 16
0
 /**
  * Fetch GET and POST request data
  *
  * This method returns a union of GET and POST data as a key-value array, or the value
  * of the array key if requested; if the array key does not exist, false is returned,
  * unless there is a default value specified.
  *
  * @param  string            $key (optional)
  * @return array|mixed|false
  */
 public function fetch($key = null)
 {
     $env = \Kanso\Kanso::getInstance()->Environment();
     if (!$this->isGet()) {
         if ($key) {
             if (isset($_POST[$key])) {
                 return $_POST[$key];
             }
             return false;
         }
         return array_merge($_POST, $_FILES);
     } else {
         $GETinfo = array_merge(parse_url(rtrim($env['HTTP_HOST'] . $env['REQUEST_URI'], '/')), pathinfo(rtrim($env['HTTP_HOST'] . $env['REQUEST_URI'], '/')));
         $GETinfo['page'] = 0;
         preg_match_all("/page\\/(\\d+)/", $env['REQUEST_URI'], $page);
         if (isset($page[1][0]) && !empty($page[1][0])) {
             $GETinfo['page'] = (int) $page[1][0];
         }
         if ($GETinfo['page'] === 1) {
             $GETinfo['page'] = 0;
         }
         if ($key) {
             if (isset($GETinfo[$key])) {
                 return $GETinfo[$key];
             }
             return false;
         }
         return $GETinfo;
     }
     return false;
 }
Esempio n. 17
0
 private function getAllArticles()
 {
     # Get the Kanso Query builder
     $Query = \Kanso\Kanso::getInstance()->Query;
     # Get the Kanso SQL builder
     $SQL = \Kanso\Kanso::getInstance()->Database->Builder();
     # Select the posts
     $SQL->SELECT('posts.*')->FROM('posts');
     # Apply basic joins for queries
     $SQL->LEFT_JOIN_ON('users', 'users.id = posts.author_id');
     $SQL->LEFT_JOIN_ON('comments', 'comments.post_id = posts.id');
     $SQL->LEFT_JOIN_ON('categories', 'posts.category_id = categories.id');
     $SQL->LEFT_JOIN_ON('tags_to_posts', 'posts.id = tags_to_posts.post_id');
     $SQL->LEFT_JOIN_ON('tags', 'tags.id = tags_to_posts.tag_id');
     $SQL->GROUP_BY('posts.id');
     # Find the articles
     $articles = $SQL->FIND_ALL();
     # Pre validate there are actually some articles to process
     if (empty($articles)) {
         return [];
     }
     # Add full joins as keys
     foreach ($articles as $i => $row) {
         $articles[$i]['tags'] = $SQL->SELECT('tags.*')->FROM('tags_to_posts')->LEFT_JOIN_ON('tags', 'tags.id = tags_to_posts.tag_id')->WHERE('tags_to_posts.post_id', '=', (int) $row['id'])->FIND_ALL();
         $articles[$i]['category'] = $SQL->SELECT('*')->FROM('categories')->WHERE('id', '=', (int) $row['category_id'])->FIND();
         $articles[$i]['author'] = $SQL->SELECT('*')->FROM('users')->WHERE('id', '=', (int) $row['author_id'])->FIND();
         $articles[$i]['excerpt'] = urldecode($row['excerpt']);
     }
     return $articles;
 }
Esempio n. 18
0
 private function getCategoryByName($category_name)
 {
     $key = $this->cacheKey(__FUNCTION__, func_get_args(), func_num_args());
     if ($this->cacheHas($key)) {
         return $this->cacheGet($key);
     }
     return $this->cachePut($key, \Kanso\Kanso::getInstance()->Database()->Builder()->SELECT('*')->FROM('categories')->WHERE('name', '=', $category_name)->ROW());
 }
Esempio n. 19
0
 public function delete()
 {
     # If this is an unsaved article return;
     if ($this->row['id'] !== null) {
         return;
     }
     return \Kanso\Kanso::getInstance()->Bookkeeper->delete($this->row['id']);
 }
Esempio n. 20
0
 /**
  * Update a post's permalink
  */
 private function updatePostPermalink($id)
 {
     $query = \Kanso\Kanso::getInstance()->Database->Builder();
     # Get the entry
     $post = $this->existing($id);
     # Loop through the articles and update the slug and permalink
     if ($post) {
         $newSlug = $this->titleToSlug($post->title, $post->category['slug'], $post->author['slug'], $post->created, $post->type);
         $query->UPDATE('posts')->SET(['slug' => $newSlug])->WHERE('id', '=', (int) $post->id)->QUERY();
     }
 }
Esempio n. 21
0
 /**
  * Convert a directory into a url
  *
  * @param   string      $dirname
  * @param   string
  */
 public static function dirToURL($dirname)
 {
     $env = \Kanso\Kanso::getInstance()->Environment();
     return str_replace($env['DOCUMENT_ROOT'], $env['HTTP_HOST'], $dirname);
 }
Esempio n. 22
0
 /**
  * Render the admin page
  */
 private function renderPage()
 {
     # Convert the page request to lowercase
     $this->pageRequest = strtolower($this->pageRequest);
     # Render the page with variables
     $vars = ['ADMIN_PAGE_TYPE' => $this->pageRequest, 'ADMIN_WRITER_ENTRY' => $this->writerEntry];
     \Kanso\Kanso::getInstance()->render(\Kanso\Kanso::getInstance()->Environment['KANSO_ADMIN_DIR'] . DIRECTORY_SEPARATOR . 'Admin.php', $vars);
 }
Esempio n. 23
0
 /**
  * Build the sitemap
  *
  * @param  array    $articles       Articles pulled from the databse
  * @param  array    $tags    	    Tags pulled from the databse
  * @param  array    $categories     Categories pulled from the databse
  * @param  array    $authors        Authors pulled from the databse
  * @param  string   $websiteBase    Website base url
  */
 public static function buildSiteMap()
 {
     # Get a Kanso instance
     $Kanso = \Kanso\Kanso::getInstance();
     # Get a new Query Builder
     $Query = $Kanso->Database()->Builder();
     # Get required data from the database
     $articles = $Query->SELECT('*')->FROM('posts')->WHERE('status', '=', 'published')->FIND_ALL();
     $tags = [];
     $categories = [];
     $authors = [];
     $websiteBase = $Kanso->Environment['HTTP_HOST'];
     # Only load the tags if tags are being routed
     if ($Kanso->Config['KANSO_ROUTE_TAGS']) {
         $tags = $Query->SELECT('*')->FROM('tags')->WHERE('id', '!=', 1)->FIND_ALL();
     }
     # Only load the categories if categories are being routed
     if ($Kanso->Config['KANSO_ROUTE_CATEGORIES']) {
         $categories = $Query->SELECT('*')->FROM('categories')->WHERE('id', '!=', 1)->FIND_ALL();
     }
     # Only load the authors if authors are being routed
     if ($Kanso->Config['KANSO_ROUTE_AUTHORS']) {
         $authors = $Query->SELECT('*')->FROM('users')->WHERE('status', '=', 'confirmed')->FIND_ALL();
     }
     $now = date("Y-m-d", time());
     $now .= 'T' . date("H:i:sP", time());
     $XML = "";
     $XML .= '<?xml version="1.0" encoding="UTF-8"?>' . "\n\t";
     $XML .= '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n\t\t";
     $XML .= '<url>' . "\n\t\t";
     $XML .= '<loc>' . $websiteBase . '</loc>' . "\n\t\t\t";
     $XML .= '<lastmod>' . $now . '</lastmod>' . "\n\t\t\t";
     $XML .= '<changefreq>daily</changefreq>' . "\n\t\t\t";
     $XML .= '<priority>1.0</priority>' . "\n\t\t";
     $XML .= '</url>' . "\n\t";
     foreach ($articles as $page) {
         $mod = date("Y-m-d", $page['modified']);
         $mod .= 'T' . date("H:i:sP", $page['modified']);
         $XML .= '<url>' . "\n\t\t";
         $XML .= '<loc>' . $websiteBase . '/' . $page["slug"] . '</loc>' . "\n\t\t";
         $XML .= '<lastmod>' . $mod . '</lastmod>' . "\n\t\t";
         $XML .= '<changefreq>monthly</changefreq>' . "\n\t\t";
         $XML .= '<priority>0.6</priority>' . "\n\t";
         $XML .= '</url>' . "\n\t";
     }
     foreach ($tags as $tag) {
         $XML .= '<url>' . "\n\t\t";
         $XML .= '<loc>' . $websiteBase . '/tag/' . $tag['slug'] . '/</loc>' . "\n\t\t";
         $XML .= '<lastmod>' . $now . '</lastmod>' . "\n\t\t";
         $XML .= '<changefreq>monthly</changefreq>' . "\n\t\t";
         $XML .= '<priority>0.3</priority>' . "\n\t";
         $XML .= '</url>' . "\n\t";
     }
     foreach ($categories as $category) {
         $XML .= '<url>' . "\n\t\t";
         $XML .= '<loc>' . $websiteBase . '/category/' . $category['slug'] . '/</loc>' . "\n\t\t";
         $XML .= '<lastmod>' . $now . '</lastmod>' . "\n\t\t";
         $XML .= '<changefreq>monthly</changefreq>' . "\n\t\t";
         $XML .= '<priority>0.3</priority>' . "\n\t";
         $XML .= '</url>' . "\n\t";
     }
     foreach ($authors as $author) {
         $XML .= '<url>' . "\n\t\t";
         $XML .= '<loc>' . $websiteBase . '/author/' . $author['slug'] . '/</loc>' . "\n\t\t";
         $XML .= '<lastmod>' . $now . '</lastmod>' . "\n\t\t";
         $XML .= '<changefreq>monthly</changefreq>' . "\n\t\t";
         $XML .= '<priority>0.3</priority>' . "\n\t";
         $XML .= '</url>' . "\n\t";
     }
     $XML .= '<url>' . "\n\t\t";
     $XML .= '<loc>' . $websiteBase . '/search</loc>' . "\n\t\t";
     $XML .= '<lastmod>' . $now . '</lastmod>' . "\n\t\t";
     $XML .= '<changefreq>monthly</changefreq>' . "\n\t\t";
     $XML .= '<priority>0.3</priority>' . "\n\t";
     $XML .= '</url>' . "\n\t";
     $XML .= '</urlset>';
     return $XML;
 }