/**
  * Builds the sitemap and writes it into a xml file.
  * 
  * ATTENTION PLUGIN DEVELOPERS! DONT CALL THIS METHOD DIRECTLY!
  * The method is probably not available, since it is only loaded when needed.
  * Use do_action("sm_rebuild"); if you want to rebuild the sitemap.
  * Please refer to the documentation.txt for more details.
  *
  * @since 3.0
  * @access public
  * @author Arne Brachhold <himself [at] arnebrachhold [dot] de>
  * @return array An array with messages such as failed writes etc.
  */
 function BuildSitemap()
 {
     global $nxtdb, $posts, $nxt_version;
     $this->Initate();
     if ($this->GetOption("b_memory") != '') {
         @ini_set("memory_limit", $this->GetOption("b_memory"));
     }
     if ($this->GetOption("b_time") != -1) {
         @set_time_limit($this->GetOption("b_time"));
     }
     //This object saves the status information of the script directly to the database
     $status = new GoogleSitemapGeneratorStatus();
     //Other plugins can detect if the building process is active
     $this->_isActive = true;
     //$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
     //Debug mode?
     $debug = $this->GetOption("b_debug");
     if ($this->GetOption("b_xml")) {
         $fileName = $this->GetXmlPath();
         $status->StartXml($this->GetXmlPath(), $this->GetXmlUrl());
         if ($this->IsFileWritable($fileName)) {
             $this->_fileHandle = fopen($fileName, "w");
             if (!$this->_fileHandle) {
                 $status->EndXml(false, "Not openable");
             }
         } else {
             $status->EndXml(false, "not writable");
         }
     }
     //Write gzipped sitemap file
     if ($this->IsGzipEnabled()) {
         $fileName = $this->GetZipPath();
         $status->StartZip($this->GetZipPath(), $this->GetZipUrl());
         if ($this->IsFileWritable($fileName)) {
             $this->_fileZipHandle = gzopen($fileName, "w1");
             if (!$this->_fileZipHandle) {
                 $status->EndZip(false, "Not openable");
             }
         } else {
             $status->EndZip(false, "not writable");
         }
     }
     if (!$this->_fileHandle && !$this->_fileZipHandle) {
         $status->End();
         return;
     }
     //Content of the XML file
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));
     $styleSheet = $this->GetDefaultStyle() && $this->GetOption('b_style_default') === true ? $this->GetDefaultStyle() : $this->GetOption('b_style');
     if (!empty($styleSheet)) {
         $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $styleSheet . '"?' . '>'));
     }
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"nxtclass/" . get_bloginfo('version') . "\""));
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
     //All comments as an asso. Array (postID=>commentCount)
     $comments = $this->GetOption("b_prio_provider") != "" ? $this->GetComments() : array();
     //Full number of comments
     $commentCount = count($comments) > 0 ? $this->GetCommentCount($comments) : 0;
     if ($debug && $this->GetOption("b_prio_provider") != "") {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));
     }
     //Go XML!
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<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">'));
     $home = get_bloginfo('url');
     $homePid = 0;
     // Load qTranslate settings
     require_once "sitemap-qtranslate.php";
     $qt = qt_settings();
     //Add the home page (WITH a slash!)
     if ($this->GetOption("in_home")) {
         if ('page' == get_option('show_on_front') && get_option('page_on_front')) {
             $pageOnFront = get_option('page_on_front');
             $p = get_page($pageOnFront);
             if ($p) {
                 $homePid = $p->ID;
                 if (!$qt["enabled"]) {
                     $this->AddUrl(trailingslashit($home), $this->GetTimestampFromMySql($p->post_modified_gmt && $p->post_modified_gmt != '0000-00-00 00:00:00' ? $p->post_modified_gmt : $p->post_date_gmt), $this->GetOption("cf_home"), $this->GetOption("pr_home"));
                 }
                 qt_permalink($qt, trailingslashit($home), null, $p->post_modified_gmt && $p->post_modified_gmt != '0000-00-00 00:00:00' ? $p->post_modified_gmt : $p->post_date_gmt, $this->GetOption("cf_home"), $this->GetOption("pr_home"), $this);
             }
         } else {
             if (!$qt["enabled"]) {
                 $this->AddUrl(trailingslashit($home), $this->GetTimestampFromMySql(get_lastpostmodified('GMT')), $this->GetOption("cf_home"), $this->GetOption("pr_home"));
             }
             qt_permalink($qt, trailingslashit($home), null, get_lastpostmodified('GMT'), $this->GetOption("cf_home"), $this->GetOption("pr_home"), $this);
         }
     }
     //Add the posts
     if ($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
         }
         //Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
         $nxtCompat = floatval($nxt_version) < 2.1;
         $excludes = $this->GetOption('b_exclude');
         //Excluded posts and pages (user enetered ID)
         $exclCats = $this->GetOption("b_exclude_cats");
         // Excluded cats
         if ($exclCats && count($exclCats) > 0 && $this->IsTaxonomySupported()) {
             $excludedCatPosts = get_objects_in_term($exclCats, "category");
             // Get all posts in excl. cats. Unforttunately this also gives us pages, revisions and so on...
             //Remove the pages, revisions etc from the exclude by category list, because they are always in the uncategorized one.
             if (count($excludedCatPosts) > 0) {
                 $exclPages = $nxtdb->get_col("SELECT ID FROM `" . $nxtdb->posts . "` WHERE post_type!='post' AND ID IN ('" . implode("','", $excludedCatPosts) . "')");
                 $exclPages = array_map('intval', $exclPages);
                 //Remove the pages from the exlusion list before
                 if (count($exclPages) > 0) {
                     $excludedCatPosts = array_diff($excludedCatPosts, $exclPages);
                 }
                 //Merge the category exclusion list with the users one
                 if (count($excludedCatPosts) > 0) {
                     $excludes = array_merge($excludes, $excludedCatPosts);
                 }
             }
         }
         $contentStmt = '';
         if ($qt["enabled"]) {
             $contentStmt .= ', post_content ';
         }
         $postPageStmt = '';
         $inSubPages = $this->GetOption('in_posts_sub') === true;
         if ($inSubPages && $this->GetOption('in_posts') === true) {
             $pageDivider = '<!--nextpage-->';
             $postPageStmt = ", (character_length(`post_content`)  - character_length(REPLACE(`post_content`, '{$pageDivider}', ''))) / " . strlen($pageDivider) . " as postPages";
         }
         $sql = "SELECT `ID`, `post_author`, `post_date`, `post_date_gmt`, `post_status`, `post_name`, `post_modified`, `post_modified_gmt`, `post_parent`, `post_type` {$postPageStmt} {$contentStmt} FROM `" . $nxtdb->posts . "` WHERE ";
         $where = '(';
         if ($this->GetOption('in_posts')) {
             //nxt < 2.1: posts are post_status = publish
             //nxt >= 2.1: post_type must be 'post', no date check required because future posts are post_status='future'
             if ($nxtCompat) {
                 $where .= "(post_status = 'publish' AND post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "')";
             } else {
                 if ($this->IsCustomPostTypesSupported() && count($this->GetOption('in_customtypes')) > 0) {
                     $where .= " (post_status = 'publish' AND (post_type in ('','post'";
                     foreach ($this->GetOption('in_customtypes') as $customType) {
                         $where .= ",'{$customType}'";
                     }
                     $where .= "))) ";
                 } else {
                     $where .= " (post_status = 'publish' AND (post_type = 'post' OR post_type = '')) ";
                 }
             }
         }
         if ($this->GetOption('in_pages')) {
             if ($this->GetOption('in_posts')) {
                 $where .= " OR ";
             }
             if ($nxtCompat) {
                 //nxt < 2.1: posts have post_status = published, pages have post_status = static
                 $where .= " post_status='static' ";
             } else {
                 //nxt >= 2.1: posts have post_type = 'post' and pages have post_type = 'page'. Both must be published.
                 $where .= " (post_status = 'publish' AND post_type = 'page') ";
             }
         }
         $where .= ") ";
         if (is_array($excludes) && count($excludes) > 0) {
             $where .= " AND ID NOT IN ('" . implode("','", $excludes) . "')";
         }
         $where .= " AND post_password='' ORDER BY post_modified DESC";
         $sql .= $where;
         if ($this->GetOption("b_max_posts") > 0) {
             $sql .= " LIMIT 0," . $this->GetOption("b_max_posts");
         }
         $postCount = intval($nxtdb->get_var("SELECT COUNT(*) AS cnt FROM `" . $nxtdb->posts . "` WHERE " . $where, 0, 0));
         //Create a new connection because we are using mysql_unbuffered_query and don't want to disturb the nxt connection
         //Safe Mode for other plugins which use mysql_query() without a connection handler and will destroy our resultset :(
         $con = $postRes = null;
         //In 2.2, a bug which prevented additional DB connections was fixed
         if (floatval($nxt_version) < 2.2) {
             $this->SetOption("b_safemode", true);
         }
         if ($this->GetOption("b_safemode") === true) {
             $postRes = mysql_query($sql, $nxtdb->dbh);
             if (!$postRes) {
                 trigger_error("MySQL query failed: " . mysql_error(), E_USER_NOTICE);
                 //E_USER_NOTICE will be displayed on our debug mode
                 return;
             }
         } else {
             $con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD, true);
             if (!$con) {
                 trigger_error("MySQL Connection failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
             if (!mysql_select_db(DB_NAME, $con)) {
                 trigger_error("MySQL DB Select failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
             $postRes = mysql_unbuffered_query($sql, $con);
             if (!$postRes) {
                 trigger_error("MySQL unbuffered query failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
         }
         if ($postRes) {
             //#type $prioProvider GoogleSitemapGeneratorPrioProviderBase
             $prioProvider = NULL;
             if ($this->GetOption("b_prio_provider") != '') {
                 $providerClass = $this->GetOption('b_prio_provider');
                 $prioProvider = new $providerClass($commentCount, $postCount);
             }
             //$posts is used by Alex King's Popularity Contest plugin
             //if($posts == null || !is_array($posts)) {
             //	$posts = &$postRes;
             //}
             $z = 1;
             $zz = 1;
             //Default priorities
             $default_prio_posts = $this->GetOption('pr_posts');
             $default_prio_pages = $this->GetOption('pr_pages');
             //Change frequencies
             $cf_pages = $this->GetOption('cf_pages');
             $cf_posts = $this->GetOption('cf_posts');
             $minPrio = $this->GetOption('pr_posts_min');
             //Cycle through all posts and add them
             while ($post = mysql_fetch_object($postRes)) {
                 //Fill the cache with our DB result. Since it's incomplete (no text-content for example), we will clean it later.
                 $cache = array(&$post);
                 update_post_cache($cache);
                 //Set the current working post for other plugins which depend on "the loop"
                 $GLOBALS['post'] =& $post;
                 $permalink = get_permalink($post->ID);
                 if ($permalink != $home && $post->ID != $homePid) {
                     $isPage = false;
                     if ($nxtCompat) {
                         $isPage = $post->post_status == 'static';
                     } else {
                         $isPage = $post->post_type == 'page';
                     }
                     //Default Priority if auto calc is disabled
                     $prio = 0;
                     if ($isPage) {
                         //Priority for static pages
                         $prio = $default_prio_pages;
                     } else {
                         //Priority for normal posts
                         $prio = $default_prio_posts;
                     }
                     //If priority calc. is enabled, calculate (but only for posts, not pages)!
                     if ($prioProvider !== null && !$isPage) {
                         //Comment count for this post
                         $cmtcnt = isset($comments[$post->ID]) ? $comments[$post->ID] : 0;
                         $prio = $prioProvider->GetPostPriority($post->ID, $cmtcnt, $post);
                         if ($debug) {
                             $this->AddElement(new GoogleSitemapGeneratorDebugEntry('Debug: Priority report of postID ' . $post->ID . ': Comments: ' . $cmtcnt . ' of ' . $commentCount . ' = ' . $prio . ' points'));
                         }
                     }
                     if (!$isPage && $minPrio > 0 && $prio < $minPrio) {
                         $prio = $minPrio;
                     }
                     //Add it
                     if (!$qt["enabled"]) {
                         $this->AddUrl($permalink, $this->GetTimestampFromMySql($post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ? $post->post_modified_gmt : $post->post_date_gmt), $isPage ? $cf_pages : $cf_posts, $prio);
                     }
                     qt_permalink($qt, $permalink, $post->post_content, $post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ? $post->post_modified_gmt : $post->post_date_gmt, $isPage ? $cf_pages : $cf_posts, $prio, $this);
                     if ($inSubPages) {
                         $subPage = '';
                         for ($p = 1; $p <= $post->postPages; $p++) {
                             if (get_option('permalink_structure') == '') {
                                 $subPage = $permalink . '&amp;page=' . ($p + 1);
                             } else {
                                 $subPage = trailingslashit($permalink) . user_trailingslashit($p + 1, 'single_paged');
                             }
                             if (!$qt["enabled"]) {
                                 $this->AddUrl($subPage, $this->GetTimestampFromMySql($post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ? $post->post_modified_gmt : $post->post_date_gmt), $isPage ? $cf_pages : $cf_posts, $prio);
                             }
                             //qt_permalink($qt, $subPage, $post->post_content, ($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:$post->post_date_gmt), ($isPage?$cf_pages:$cf_posts), $prio, $this);
                         }
                     }
                 }
                 //Update the status every 100 posts and at the end.
                 //If the script breaks because of memory or time limit,
                 //we have a "last reponded" value which can be compared to the server settings
                 if ($zz == 100 || $z == $postCount) {
                     $status->SaveStep($z);
                     $zz = 0;
                 } else {
                     $zz++;
                 }
                 $z++;
                 //Clean cache because it's incomplete
                 if (version_compare($nxt_version, "2.5", ">=")) {
                     //nxt 2.5 makes a mysql query for every clean_post_cache to clear the child cache
                     //so I've copied the function here until a patch arrives...
                     nxt_cache_delete($post->ID, 'posts');
                     nxt_cache_delete($post->ID, 'post_meta');
                     clean_object_term_cache($post->ID, 'post');
                 } else {
                     clean_post_cache($post->ID);
                 }
             }
             unset($postRes);
             unset($prioProvider);
             if ($this->GetOption("b_safemode") !== true && $con) {
                 mysql_close($con);
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Postings"));
         }
     }
     //Add the cats
     if ($this->GetOption("in_cats")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Cats"));
         }
         $exclCats = $this->GetOption("b_exclude_cats");
         // Excluded cats
         if ($exclCats == null) {
             $exclCats = array();
         }
         if (!$this->IsTaxonomySupported()) {
             $catsRes = $nxtdb->get_results("\r\n\t\t\t\t\t\t\tSELECT\r\n\t\t\t\t\t\t\t\tc.cat_ID AS ID,\r\n\t\t\t\t\t\t\t\tMAX(p.post_modified_gmt) AS last_mod\r\n\t\t\t\t\t\t\tFROM\r\n\t\t\t\t\t\t\t\t`" . $nxtdb->categories . "` c,\r\n\t\t\t\t\t\t\t\t`" . $nxtdb->post2cat . "` pc,\r\n\t\t\t\t\t\t\t\t`" . $nxtdb->posts . "` p\r\n\t\t\t\t\t\t\tWHERE\r\n\t\t\t\t\t\t\t\tpc.category_id = c.cat_ID\r\n\t\t\t\t\t\t\t\tAND p.ID = pc.post_id\r\n\t\t\t\t\t\t\t\tAND p.post_status = 'publish'\r\n\t\t\t\t\t\t\t\tAND p.post_type='post'\r\n\t\t\t\t\t\t\tGROUP\r\n\t\t\t\t\t\t\t\tBY c.cat_id\r\n\t\t\t\t\t\t\t");
             if ($catsRes) {
                 foreach ($catsRes as $cat) {
                     if ($cat && $cat->ID && $cat->ID > 0 && !in_array($cat->ID, $exclCats)) {
                         if ($debug) {
                             if ($debug) {
                                 $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Cat-ID:" . $cat->ID));
                             }
                         }
                         if (!$qt["enabled"]) {
                             $this->AddUrl(get_category_link($cat->ID), $this->GetTimestampFromMySql($cat->last_mod), $this->GetOption("cf_cats"), $this->GetOption("pr_cats"));
                         }
                         qt_permalink($qt, get_category_link($cat->ID), null, $cat->last_mod, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this);
                     }
                 }
             }
         } else {
             $cats = get_terms("category", array("hide_empty" => true, "hierarchical" => false));
             if ($cats && is_array($cats) && count($cats) > 0) {
                 foreach ($cats as $cat) {
                     if (!in_array($cat->term_id, $exclCats)) {
                         if (!$qt["enabled"]) {
                             $this->AddUrl(get_category_link($cat->term_id), 0, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"));
                         }
                         qt_permalink($qt, get_category_link($cat->term_id), null, 0, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this);
                     }
                 }
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Cats"));
         }
     }
     //Add the archives
     if ($this->GetOption("in_arch")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Archive"));
         }
         $now = current_time('mysql');
         //nxt2.1 introduced post_status='future', for earlier nxt versions we need to check the post_date_gmt
         $arcresults = $nxtdb->get_results("\r\n\t\t\t\t\t\tSELECT DISTINCT\r\n\t\t\t\t\t\t\tYEAR(post_date_gmt) AS `year`,\r\n\t\t\t\t\t\t\tMONTH(post_date_gmt) AS `month`,\r\n\t\t\t\t\t\t\tMAX(post_date_gmt) as last_mod,\r\n\t\t\t\t\t\t\tcount(ID) as posts\r\n\t\t\t\t\t\tFROM\r\n\t\t\t\t\t\t\t{$nxtdb->posts}\r\n\t\t\t\t\t\tWHERE\r\n\t\t\t\t\t\t\tpost_date < '{$now}'\r\n\t\t\t\t\t\t\tAND post_status = 'publish'\r\n\t\t\t\t\t\t\tAND post_type = 'post'\r\n\t\t\t\t\t\t\t" . (floatval($nxt_version) < 2.1 ? "AND {$nxtdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'" : "") . "\r\n\t\t\t\t\t\tGROUP BY\r\n\t\t\t\t\t\t\tYEAR(post_date_gmt),\r\n\t\t\t\t\t\t\tMONTH(post_date_gmt)\r\n\t\t\t\t\t\tORDER BY\r\n\t\t\t\t\t\t\tpost_date_gmt DESC");
         if ($arcresults) {
             foreach ($arcresults as $arcresult) {
                 $url = get_month_link($arcresult->year, $arcresult->month);
                 $changeFreq = "";
                 //Archive is the current one
                 if ($arcresult->month == date("n") && $arcresult->year == date("Y")) {
                     $changeFreq = $this->GetOption("cf_arch_curr");
                 } else {
                     // Archive is older
                     $changeFreq = $this->GetOption("cf_arch_old");
                 }
                 if (!$qt["enabled"]) {
                     $this->AddUrl($url, $this->GetTimestampFromMySql($arcresult->last_mod), $changeFreq, $this->GetOption("pr_arch"));
                 }
                 qt_permalink($qt, $url, null, $arcresult->last_mod, $changeFreq, $this->GetOption("pr_arch"), $this);
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Archive"));
         }
     }
     //Add the author pages
     if ($this->GetOption("in_auth")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Author pages"));
         }
         $linkFunc = null;
         //get_author_link is deprecated in nxt 2.1, try to use get_author_posts_url first.
         if (function_exists('get_author_posts_url')) {
             $linkFunc = 'get_author_posts_url';
         } else {
             if (function_exists('get_author_link')) {
                 $linkFunc = 'get_author_link';
             }
         }
         //Who knows what happens in later nxt versions, so check again if it worked
         if ($linkFunc !== null) {
             //Unfortunately there is no API function to get all authors, so we have to do it the dirty way...
             //We retrieve only users with published and not password protected posts (and not pages)
             //nxt2.1 introduced post_status='future', for earlier nxt versions we need to check the post_date_gmt
             $sql = "SELECT DISTINCT\r\n\t\t\t\t\t\t\tu.ID,\r\n\t\t\t\t\t\t\tu.user_nicename,\r\n\t\t\t\t\t\t\tMAX(p.post_modified_gmt) AS last_post\r\n\t\t\t\t\t\tFROM\r\n\t\t\t\t\t\t\t{$nxtdb->users} u,\r\n\t\t\t\t\t\t\t{$nxtdb->posts} p\r\n\t\t\t\t\t\tWHERE\r\n\t\t\t\t\t\t\tp.post_author = u.ID\r\n\t\t\t\t\t\t\tAND p.post_status = 'publish'\r\n\t\t\t\t\t\t\tAND p.post_type = 'post'\r\n\t\t\t\t\t\t\tAND p.post_password = ''\r\n\t\t\t\t\t\t\t" . (floatval($nxt_version) < 2.1 ? "AND p.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'" : "") . "\r\n\t\t\t\t\t\tGROUP BY\r\n\t\t\t\t\t\t\tu.ID,\r\n\t\t\t\t\t\t\tu.user_nicename";
             $authors = $nxtdb->get_results($sql);
             if ($authors && is_array($authors)) {
                 foreach ($authors as $author) {
                     if ($debug) {
                         if ($debug) {
                             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Author-ID:" . $author->ID));
                         }
                     }
                     $url = $linkFunc == 'get_author_posts_url' ? get_author_posts_url($author->ID, $author->user_nicename) : get_author_link(false, $author->ID, $author->user_nicename);
                     if (!$qt["enabled"]) {
                         $this->AddUrl($url, $this->GetTimestampFromMySql($author->last_post), $this->GetOption("cf_auth"), $this->GetOption("pr_auth"));
                     }
                     qt_permalink($qt, $url, null, $author->last_post, $this->GetOption("cf_auth"), $this->GetOption("pr_auth"), $this);
                 }
             }
         } else {
             //Too bad, no author pages for you :(
             if ($debug) {
                 $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: No valid author link function found"));
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Author pages"));
         }
     }
     //Add tag pages
     if ($this->GetOption("in_tags") && $this->IsTaxonomySupported()) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Tags"));
         }
         $tags = get_terms("post_tag", array("hide_empty" => true, "hierarchical" => false));
         if ($tags && is_array($tags) && count($tags) > 0) {
             foreach ($tags as $tag) {
                 if (!$qt["enabled"]) {
                     $this->AddUrl(get_tag_link($tag->term_id), 0, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"));
                 }
                 qt_permalink($qt, get_tag_link($tag->term_id), null, 0, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"), $this);
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Tags"));
         }
     }
     //Add custom taxonomy pages
     if ($this->GetOption("in_tax") && $this->IsTaxonomySupported()) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start custom taxonomies"));
         }
         $enabledTaxonomies = $this->GetOption("in_tax");
         $taxList = array();
         foreach ($enabledTaxonomies as $taxName) {
             $taxonomy = get_taxonomy($taxName);
             if ($taxonomy) {
                 $taxList[] = $nxtdb->escape($taxonomy->name);
             }
         }
         if (count($taxList) > 0) {
             //We're selecting all term information (t.*) plus some additional fields
             //like the last mod date and the taxonomy name, so nxt doesnt need to make
             //additional queries to build the permalink structure.
             //This does NOT work for categories and tags yet, because nxt uses get_category_link
             //and get_tag_link internally and that would cause one additional query per term!
             $sql = "\r\n\t\t\t\t\tSELECT\r\n\t\t\t\t\t\tt.*,\r\n\t\t\t\t\t\ttt.taxonomy AS _taxonomy,\r\n\t\t\t\t\t\tUNIX_TIMESTAMP(MAX(post_date_gmt)) as _mod_date\r\n\t\t\t\t\tFROM\r\n\t\t\t\t\t\t{$nxtdb->posts} p ,\r\n\t\t\t\t\t\t{$nxtdb->term_relationships} r,\r\n\t\t\t\t\t\t{$nxtdb->terms} t,\r\n\t\t\t\t\t\t{$nxtdb->term_taxonomy} tt\r\n\t\t\t\t\tWHERE\r\n\t\t\t\t\t\tp.ID = r.object_id\r\n\t\t\t\t\t\tAND p.post_status = 'publish'\r\n\t\t\t\t\t\tAND p.post_type = 'post'\r\n\t\t\t\t\t\tAND p.post_password = ''\r\n\t\t\t\t\t\tAND r.term_taxonomy_id = t.term_id\r\n\t\t\t\t\t\tAND t.term_id = tt.term_id\r\n\t\t\t\t\t\tAND tt.count > 0\r\n\t\t\t\t\t\tAND tt.taxonomy IN ('" . implode("','", $taxList) . "')\r\n\t\t\t\t\tGROUP BY\r\n\t\t\t\t\t\tt.term_id";
             $termInfo = $nxtdb->get_results($sql);
             foreach ($termInfo as $term) {
                 $this->AddUrl(get_term_link($term, $term->_taxonomy), $term->_mod_date, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"));
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End custom taxonomies"));
         }
     }
     //Add the custom pages
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Custom Pages"));
     }
     if ($this->_pages && is_array($this->_pages) && count($this->_pages) > 0) {
         //#type $page GoogleSitemapGeneratorPage
         foreach ($this->_pages as $page) {
             $this->AddUrl($page->GetUrl(), $page->getLastMod(), $page->getChangeFreq(), $page->getPriority());
         }
     }
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Custom Pages"));
     }
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start additional URLs"));
     }
     do_action('sm_buildmap');
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End additional URLs"));
     }
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry("</urlset>"));
     $pingUrl = '';
     if ($this->GetOption("b_xml")) {
         if ($this->_fileHandle && fclose($this->_fileHandle)) {
             $this->_fileHandle = null;
             $status->EndXml(true);
             $pingUrl = $this->GetXmlUrl();
         } else {
             $status->EndXml(false, "Could not close the sitemap file.");
         }
     }
     if ($this->IsGzipEnabled()) {
         if ($this->_fileZipHandle && fclose($this->_fileZipHandle)) {
             $this->_fileZipHandle = null;
             $status->EndZip(true);
             $pingUrl = $this->GetZipUrl();
         } else {
             $status->EndZip(false, "Could not close the zipped sitemap file");
         }
     }
     //Ping Google
     if ($this->GetOption("b_ping") && !empty($pingUrl)) {
         $sPingUrl = "http://www.google.com/webmasters/sitemaps/ping?sitemap=" . urlencode($pingUrl);
         $status->StartGooglePing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false) {
             $status->EndGooglePing(false, $this->_lastError);
             trigger_error("Failed to ping Google: " . htmlspecialchars(strip_tags($pingres)), E_USER_NOTICE);
         } else {
             $status->EndGooglePing(true);
         }
     }
     //Ping Ask.com
     if ($this->GetOption("b_pingask") && !empty($pingUrl)) {
         $sPingUrl = "http://submissions.ask.com/ping?sitemap=" . urlencode($pingUrl);
         $status->StartAskPing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false || strpos($pingres, "successfully received and added") === false) {
             //Ask.com returns 200 OK even if there was an error, so we need to check the content.
             $status->EndAskPing(false, $this->_lastError);
             trigger_error("Failed to ping Ask.com: " . htmlspecialchars(strip_tags($pingres)), E_USER_NOTICE);
         } else {
             $status->EndAskPing(true);
         }
     }
     //Ping Bing
     if ($this->GetOption("b_pingmsn") && !empty($pingUrl)) {
         $sPingUrl = "http://www.bing.com/webmaster/ping.aspx?siteMap=" . urlencode($pingUrl);
         $status->StartMsnPing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         //Bing returns ip/country-based success messages, so there is no way to check the content. Rely on HTTP 500 only then...
         if ($pingres == NULL || $pingres === false || strpos($pingres, " ") === false) {
             trigger_error("Failed to ping Bing: " . htmlspecialchars(strip_tags($pingres)), E_USER_NOTICE);
             $status->EndMsnPing(false, $this->_lastError);
         } else {
             $status->EndMsnPing(true);
         }
     }
     $status->End();
     $this->_isActive = false;
     //done...
     return $status;
 }
Exemple #2
0
 /**
  * Builds the sitemap and writes it into a xml file.
  * 
  * @since 3.0
  * @access public
  * @author Arne Brachhold <himself [at] arnebrachhold [dot] de>
  * @return array An array with messages such as failed writes etc.
  */
 function BuildSitemap()
 {
     global $wpdb, $posts, $wp_version;
     $this->Initate();
     if ($this->GetOption("b_memory") != '') {
         @ini_set("memory_limit", $this->GetOption("b_memory"));
     }
     if ($this->GetOption("sm_b_time") != -1) {
         @set_time_limit($this->GetOption("sm_b_time"));
     }
     //This object saves the status information of the script directly to the database
     $status = new GoogleSitemapGeneratorStatus();
     //Other plugins can detect if the building process is active
     $this->_isActive = true;
     //$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
     //Debug mode?
     $debug = $this->GetOption("b_debug");
     if ($this->GetOption("b_xml")) {
         $fileName = $this->GetXmlPath();
         $status->StartXml($this->GetXmlPath(), $this->GetXmlUrl());
         if ($this->IsFileWritable($fileName)) {
             $this->_fileHandle = fopen($fileName, "w");
             if (!$this->_fileHandle) {
                 $status->EndXml(false, "Not openable");
             }
         } else {
             $status->EndXml(false, "not writable");
         }
     }
     //Write gzipped sitemap file
     if ($this->IsGzipEnabled()) {
         $fileName = $this->GetZipPath();
         $status->StartZip($this->GetZipPath(), $this->GetZipUrl());
         if ($this->IsFileWritable($fileName)) {
             $this->_fileZipHandle = gzopen($fileName, "w1");
             if (!$this->_fileZipHandle) {
                 $status->EndZip(false, "Not openable");
             }
         } else {
             $status->EndZip(false, "not writable");
         }
     }
     if (!$this->_fileHandle && !$this->_fileZipHandle) {
         $status->End();
         return;
     }
     //Content of the XML file
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));
     if ($this->GetOption("b_style") != '') {
         $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $this->GetOption("b_style") . '"?' . '>'));
     }
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
     $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
     //All comments as an asso. Array (postID=>commentCount)
     $comments = $this->GetOption("b_prio_provider") != "" ? $this->GetComments() : array();
     //Full number of comments
     $commentCount = count($comments) > 0 ? $this->GetCommentCount($comments) : 0;
     if ($debug && $this->GetOption("b_prio_provider") != "") {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));
     }
     //Go XML!
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<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">'));
     $home = get_bloginfo('url');
     //Add the home page (WITH a slash!)
     if ($this->GetOption("in_home")) {
         $this->AddUrl(trailingslashit($home), $this->GetTimestampFromMySql(get_lastpostmodified('GMT')), $this->GetOption("cf_home"), $this->GetOption("pr_home"));
     }
     //Add the posts
     if ($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
         }
         //Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
         $wpCompat = floatval($wp_version) < 2.1;
         $sql = "SELECT `ID`, `post_author`, `post_date`, `post_date_gmt`, `post_status`, `post_name`, `post_modified`, `post_modified_gmt`, `post_parent`, `post_type` FROM `" . $wpdb->posts . "` WHERE ";
         $where = '(';
         if ($this->GetOption('in_posts')) {
             //WP < 2.1: posts are post_status = publish
             //WP >= 2.1: post_type must be 'post', no date check required because future posts are post_status='future'
             if ($wpCompat) {
                 $where .= "(post_status = 'publish' AND post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "')";
             } else {
                 $where .= " (post_status = 'publish' AND (post_type = 'post' OR post_type = '')) ";
             }
         }
         if ($this->GetOption('in_pages')) {
             if ($this->GetOption('in_posts')) {
                 $where .= " OR ";
             }
             if ($wpCompat) {
                 //WP < 2.1: posts have post_status = published, pages have post_status = static
                 $where .= " post_status='static' ";
             } else {
                 //WP >= 2.1: posts have post_type = 'post' and pages have post_type = 'page'. Both must be published.
                 $where .= " (post_status = 'publish' AND post_type = 'page') ";
             }
         }
         $where .= ") ";
         $excludes = $this->GetOption('b_exclude');
         if (is_array($excludes) && count($excludes) > 0) {
             $where .= " AND ID NOT IN ('" . implode("','", $excludes) . "')";
         }
         $where .= " AND post_password='' ORDER BY post_modified DESC";
         $sql .= $where;
         if ($this->GetOption("sm_b_max_posts") > 0) {
             $sql .= " LIMIT 0," . $this->GetOption("sm_b_max_posts");
         }
         $postCount = intval($wpdb->get_var("SELECT COUNT(*) AS cnt FROM `" . $wpdb->posts . "` WHERE " . $where, 0, 0));
         //Create a new connection because we are using mysql_unbuffered_query and don't want to disturb the WP connection
         //Safe Mode for other plugins which use mysql_query() without a connection handler and will destroy our resultset :(
         $con = $postRes = null;
         if ($this->GetOption("b_safemode") === true) {
             $postRes = mysql_query($sql, $wpdb->dbh);
             if (!$postRes) {
                 trigger_error("MySQL query failed: " . mysql_error(), E_USER_NOTICE);
                 //E_NOTE will be displayed on our debug mode
                 return;
             }
         } else {
             $con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD, true);
             if (!$con) {
                 trigger_error("MySQL Connection failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
             if (!mysql_select_db(DB_NAME, $con)) {
                 trigger_error("MySQL DB Select failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
             $postRes = mysql_unbuffered_query($sql, $con);
             if (!$postRes) {
                 trigger_error("MySQL unbuffered query failed: " . mysql_error(), E_USER_NOTICE);
                 return;
             }
         }
         if ($postRes) {
             //#type $prioProvider GoogleSitemapGeneratorPrioProviderBase
             $prioProvider = NULL;
             if ($this->GetOption("b_prio_provider") != '') {
                 $providerClass = $this->GetOption('b_prio_provider');
                 $prioProvider = new $providerClass($commentCount, $postCount);
             }
             //$posts is used by Alex King's Popularity Contest plugin
             //if($posts == null || !is_array($posts)) {
             //	$posts = &$postRes;
             //}
             $z = 1;
             $zz = 1;
             //Default priorities
             $default_prio_posts = $this->GetOption('pr_posts');
             $default_prio_pages = $this->GetOption('pr_pages');
             //Change frequencies
             $cf_pages = $this->GetOption('sm_cf_pages');
             $cf_posts = $this->GetOption('sm_cf_posts');
             $minPrio = $this->GetOption('pr_posts_min');
             //Cycle through all posts and add them
             while ($post = mysql_fetch_object($postRes)) {
                 //Fill the cache with our DB result. Since it's incomplete (no text-content for example), we will clean it later.
                 $cache = array(&$post);
                 update_post_cache($cache);
                 $permalink = get_permalink($post->ID);
                 if ($permalink != $home) {
                     $isPage = false;
                     if ($wpCompat) {
                         $isPage = $post->post_status == 'static';
                     } else {
                         $isPage = $post->post_type == 'page';
                     }
                     //Set the current working post
                     $GLOBALS['post'] =& $post;
                     //Default Priority if auto calc is disabled
                     $prio = 0;
                     if ($isPage) {
                         //Priority for static pages
                         $prio = $default_prio_pages;
                     } else {
                         //Priority for normal posts
                         $prio = $default_prio_posts;
                     }
                     //If priority calc. is enabled, calculate (but only for posts, not pages)!
                     if ($prioProvider !== null && !$isPage) {
                         //Comment count for this post
                         $cmtcnt = isset($comments[$post->ID]) ? $comments[$post->ID] : 0;
                         $prio = $prioProvider->GetPostPriority($post->ID, $cmtcnt);
                         if ($debug) {
                             $this->AddElement(new GoogleSitemapGeneratorDebugEntry('Debug: Priority report of postID ' . $post->ID . ': Comments: ' . $cmtcnt . ' of ' . $commentCount . ' = ' . $prio . ' points'));
                         }
                     }
                     if (!$isPage && $minPrio > 0 && $prio < $minPrio) {
                         $prio = $minPrio;
                     }
                     //Add it
                     $this->AddUrl($permalink, $this->GetTimestampFromMySql($post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ? $post->post_modified_gmt : $post->post_date_gmt), $isPage ? $cf_pages : $cf_posts, $prio);
                 }
                 //Update the status every 100 posts and at the end.
                 //If the script breaks because of memory or time limit,
                 //we have a "last reponded" value which can be compared to the server settings
                 if ($zz == 100 || $z == $postCount) {
                     $status->SaveStep($z);
                     $zz = 0;
                 } else {
                     $zz++;
                 }
                 $z++;
                 //Clean cache because it's incomplete
                 clean_post_cache($post->ID);
             }
             unset($postRes);
             unset($prioProvider);
             if ($this->GetOption("b_safemode") !== true && $con) {
                 mysql_close($con);
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Postings"));
         }
     }
     //Add the cats
     if ($this->GetOption("in_cats")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Cats"));
         }
         if (!$this->IsTaxonomySupported()) {
             $catsRes = $wpdb->get_results("\r\n\t\t\t\t\t\t\tSELECT \r\n\t\t\t\t\t\t\t\tc.cat_ID AS ID, \r\n\t\t\t\t\t\t\t\tMAX(p.post_modified_gmt) AS last_mod \r\n\t\t\t\t\t\t\tFROM \r\n\t\t\t\t\t\t\t\t`" . $wpdb->categories . "` c,\r\n\t\t\t\t\t\t\t\t`" . $wpdb->post2cat . "` pc,\r\n\t\t\t\t\t\t\t\t`" . $wpdb->posts . "` p\r\n\t\t\t\t\t\t\tWHERE\r\n\t\t\t\t\t\t\t\tpc.category_id = c.cat_ID\r\n\t\t\t\t\t\t\t\tAND p.ID = pc.post_id\r\n\t\t\t\t\t\t\t\tAND p.post_status = 'publish'\r\n\t\t\t\t\t\t\t\tAND p.post_type='post'\r\n\t\t\t\t\t\t\tGROUP\r\n\t\t\t\t\t\t\t\tBY c.cat_id\r\n\t\t\t\t\t\t\t");
             if ($catsRes) {
                 foreach ($catsRes as $cat) {
                     if ($cat && $cat->ID && $cat->ID > 0) {
                         if ($debug) {
                             if ($debug) {
                                 $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Cat-ID:" . $cat->ID));
                             }
                         }
                         $this->AddUrl(get_category_link($cat->ID), $this->GetTimestampFromMySql($cat->last_mod), $this->GetOption("cf_cats"), $this->GetOption("pr_cats"));
                     }
                 }
             }
         } else {
             $cats = get_terms("category", array("hide_empty" => true, "hierarchical" => false));
             if ($cats && is_array($cats) && count($cats) > 0) {
                 foreach ($cats as $cat) {
                     $this->AddUrl(get_category_link($cat->term_id), 0, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"));
                 }
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Cats"));
         }
     }
     //Add the archives
     if ($this->GetOption("in_arch")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Archive"));
         }
         $now = current_time('mysql');
         //WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
         $arcresults = $wpdb->get_results("\r\n\t\t\t\t\t\tSELECT DISTINCT \r\n\t\t\t\t\t\t\tYEAR(post_date_gmt) AS `year`, \r\n\t\t\t\t\t\t\tMONTH(post_date_gmt) AS `month`, \r\n\t\t\t\t\t\t\tMAX(post_date_gmt) as last_mod, \r\n\t\t\t\t\t\t\tcount(ID) as posts \r\n\t\t\t\t\t\tFROM \r\n\t\t\t\t\t\t\t{$wpdb->posts} \r\n\t\t\t\t\t\tWHERE \r\n\t\t\t\t\t\t\tpost_date < '{$now}' \r\n\t\t\t\t\t\t\tAND post_status = 'publish' \r\n\t\t\t\t\t\t\tAND post_type = 'post'\r\n\t\t\t\t\t\t\t" . (floatval($wp_version) < 2.1 ? "AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'" : "") . "\r\n\t\t\t\t\t\tGROUP BY \r\n\t\t\t\t\t\t\tYEAR(post_date_gmt), \r\n\t\t\t\t\t\t\tMONTH(post_date_gmt) \r\n\t\t\t\t\t\tORDER BY \r\n\t\t\t\t\t\t\tpost_date_gmt DESC");
         if ($arcresults) {
             foreach ($arcresults as $arcresult) {
                 $url = get_month_link($arcresult->year, $arcresult->month);
                 $changeFreq = "";
                 //Archive is the current one
                 if ($arcresult->month == date("n") && $arcresult->year == date("Y")) {
                     $changeFreq = $this->GetOption("cf_arch_curr");
                 } else {
                     // Archive is older
                     $changeFreq = $this->GetOption("cf_arch_old");
                 }
                 $this->AddUrl($url, $this->GetTimestampFromMySql($arcresult->last_mod), $changeFreq, $this->GetOption("pr_arch"));
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Archive"));
         }
     }
     //Add the author pages
     if ($this->GetOption("in_auth")) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Author pages"));
         }
         $linkFunc = null;
         //get_author_link is deprecated in WP 2.1, try to use get_author_posts_url first.
         if (function_exists('get_author_posts_url')) {
             $linkFunc = 'get_author_posts_url';
         } else {
             if (function_exists('get_author_link')) {
                 $linkFunc = 'get_author_link';
             }
         }
         //Who knows what happens in later WP versions, so check again if it worked
         if ($linkFunc !== null) {
             //Unfortunately there is no API function to get all authors, so we have to do it the dirty way...
             //We retrieve only users with published and not password protected posts (and not pages)
             //WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
             $sql = "SELECT DISTINCT \r\n\t\t\t\t\t\t\t{$wpdb->users}.ID, \r\n\t\t\t\t\t\t\t{$wpdb->users}.user_nicename, \r\n\t\t\t\t\t\t\tMAX({$wpdb->posts}.post_modified_gmt) AS last_post \r\n\t\t\t\t\t\tFROM \r\n\t\t\t\t\t\t\t{$wpdb->users}, \r\n\t\t\t\t\t\t\t{$wpdb->posts} \r\n\t\t\t\t\t\tWHERE \r\n\t\t\t\t\t\t\t{$wpdb->posts}.post_author = {$wpdb->posts}.ID \r\n\t\t\t\t\t\t\tAND {$wpdb->posts}.post_status = 'publish'\r\n\t\t\t\t\t\t\tAND {$wpdb->posts}.post_type = 'post' \r\n\t\t\t\t\t\t\tAND {$wpdb->posts}.post_password = '' \r\n\t\t\t\t\t\t\t" . (floatval($wp_version) < 2.1 ? "AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'" : "") . "\r\n\t\t\t\t\t\tGROUP BY \r\n\t\t\t\t\t\t\t{$wpdb->posts}.ID, \r\n\t\t\t\t\t\t\t{$wpdb->users}.user_nicename";
             $authors = $wpdb->get_results($sql);
             if ($authors && is_array($authors)) {
                 foreach ($authors as $author) {
                     if ($debug) {
                         if ($debug) {
                             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Author-ID:" . $author->ID));
                         }
                     }
                     $url = $linkFunc == 'get_author_posts_url' ? get_author_posts_url($author->ID, $author->user_nicename) : get_author_link(false, $author->ID, $author->user_nicename);
                     $this->AddUrl($url, $this->GetTimestampFromMySql($author->last_post), $this->GetOption("cf_auth"), $this->GetOption("pr_auth"));
                 }
             }
         } else {
             //Too bad, no author pages for you :(
             if ($debug) {
                 $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: No valid author link function found"));
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Author pages"));
         }
     }
     //Add tag pages
     if ($this->GetOption("in_tags") && $this->IsTaxonomySupported()) {
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Tags"));
         }
         $tags = get_terms("post_tag", array("hide_empty" => true, "hierarchical" => false));
         if ($tags && is_array($tags) && count($tags) > 0) {
             foreach ($tags as $tag) {
                 $this->AddUrl(get_tag_link($tag->term_id), 0, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"));
             }
         }
         if ($debug) {
             $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Tags"));
         }
     }
     //Add the custom pages
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Custom Pages"));
     }
     if ($this->_pages && is_array($this->_pages) && count($this->_pages) > 0) {
         //#type $page GoogleSitemapGeneratorPage
         foreach ($this->_pages as $page) {
             $this->AddUrl($page->GetUrl(), $page->getLastMod(), $page->getChangeFreq(), $page->getPriority());
         }
     }
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Custom Pages"));
     }
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start additional URLs"));
     }
     do_action("sm_buildmap");
     if ($debug) {
         $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End additional URLs"));
     }
     $this->AddElement(new GoogleSitemapGeneratorXmlEntry("</urlset>"));
     $pingUrl = '';
     if ($this->GetOption("b_xml")) {
         if ($this->_fileHandle && fclose($this->_fileHandle)) {
             $this->_fileHandle = null;
             $status->EndXml(true);
             $pingUrl = $this->GetXmlUrl();
         } else {
             $status->EndXml(false, "Could not close the sitemap file.");
         }
     }
     if ($this->IsGzipEnabled()) {
         if ($this->_fileZipHandle && fclose($this->_fileZipHandle)) {
             $this->_fileZipHandle = null;
             $status->EndZip(true);
             $pingUrl = $this->GetZipUrl();
         } else {
             $status->EndZip(false, "Could not close the zipped sitemap file");
         }
     }
     //Ping Google
     if ($this->GetOption("b_ping") && !empty($pingUrl)) {
         $sPingUrl = "http://www.google.com/webmasters/sitemaps/ping?sitemap=" . urlencode($pingUrl);
         $status->StartGooglePing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false) {
             $status->EndGooglePing(false, $this->_lastError);
         } else {
             $status->EndGooglePing(true);
         }
     }
     //Ping Ask.com
     if ($this->GetOption("b_pingask") && !empty($pingUrl)) {
         $sPingUrl = "http://submissions.ask.com/ping?sitemap=" . urlencode($pingUrl);
         $status->StartAskPing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false || strpos($pingres, "successfully received and added") === false) {
             //Ask.com returns 200 OK even if there was an error, so we need to check the content.
             $status->EndAskPing(false, $this->_lastError);
         } else {
             $status->EndAskPing(true);
         }
     }
     //Ping YAHOO
     if ($this->GetOption("sm_b_pingyahoo") === true && $this->GetOption("sm_b_yahookey") != "" && !empty($pingUrl)) {
         $sPingUrl = "http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=" . $this->GetOption("sm_b_yahookey") . "&url=" . urlencode($pingUrl);
         $status->StartYahooPing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false || strpos(strtolower($pingres), "success") === false) {
             $status->EndYahooPing(false, $this->_lastError);
         } else {
             $status->EndYahooPing(true);
         }
     }
     //Ping MSN
     if ($this->GetOption("b_pingmsn") && !empty($pingUrl)) {
         $sPingUrl = "http://webmaster.live.com/ping.aspx?siteMap=" . urlencode($pingUrl);
         $status->StartMsnPing($sPingUrl);
         $pingres = $this->RemoteOpen($sPingUrl);
         if ($pingres == NULL || $pingres === false || strpos($pingres, "Thanks for submitting your sitemap") === false) {
             $status->EndMsnPing(false, $this->_lastError);
         } else {
             $status->EndMsnPing(true);
         }
     }
     $status->End();
     $this->_isActive = false;
     //done...
     return $status;
 }