Index: feed-atom.php
===================================================================
--- feed-atom.php	(revision 11981)
+++ feed-atom.php	(working copy)
@@ -4,52 +4,19 @@
  *
  * @package WordPress
  */
-
-header('Content-Type: ' . feed_content_type('atom') . '; charset=' . get_option('blog_charset'), true);
+ 
+$feed_type='atom';
+header('Content-Type: ' . feed_content_type($feed_type) . '; charset=' . get_option('blog_charset'), true);
 $more = 1;
 
 echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
-<feed
-  xmlns="http://www.w3.org/2005/Atom"
-  xmlns:thr="http://purl.org/syndication/thread/1.0"
-  xml:lang="<?php echo get_option('rss_language'); ?>"
-  xml:base="<?php bloginfo_rss('home') ?>/wp-atom.php"
-  <?php do_action('atom_ns'); ?>
- >
-	<title type="text"><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
-	<subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
 
-	<updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></updated>
-	<?php the_generator( 'atom' ); ?>
-
-	<link rel="alternate" type="text/html" href="<?php bloginfo_rss('home') ?>" />
-	<id><?php bloginfo('atom_url'); ?></id>
-	<link rel="self" type="application/atom+xml" href="<?php self_link(); ?>" />
-
-	<?php do_action('atom_head'); ?>
-	<?php while (have_posts()) : the_post(); ?>
-	<entry>
-		<author>
-			<name><?php the_author() ?></name>
-			<?php $author_url = get_the_author_meta('url'); if ( !empty($author_url) ) : ?>
-			<uri><?php the_author_meta('url')?></uri>
-			<?php endif; ?>
-		</author>
-		<title type="<?php html_type_rss(); ?>"><![CDATA[<?php the_title_rss() ?>]]></title>
-		<link rel="alternate" type="text/html" href="<?php the_permalink_rss() ?>" />
-		<id><?php the_guid(); ?></id>
-		<updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
-		<published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
-		<?php the_category_rss('atom') ?>
-		<summary type="<?php html_type_rss(); ?>"><![CDATA[<?php the_excerpt_rss(); ?>]]></summary>
-<?php if ( !get_option('rss_use_excerpt') ) : ?>
-		<content type="<?php html_type_rss(); ?>" xml:base="<?php the_permalink_rss() ?>"><![CDATA[<?php the_content_feed('atom') ?>]]></content>
-<?php endif; ?>
-<?php atom_enclosure(); ?>
-<?php do_action('atom_entry'); ?>
-		<link rel="replies" type="text/html" href="<?php the_permalink_rss() ?>#comments" thr:count="<?php echo get_comments_number()?>"/>
-		<link rel="replies" type="application/atom+xml" href="<?php echo get_post_comments_feed_link(0,'atom') ?>" thr:count="<?php echo get_comments_number()?>"/>
-		<thr:total><?php echo get_comments_number()?></thr:total>
-	</entry>
-	<?php endwhile ; ?>
-</feed>
+<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xml:lang="<?php echo get_option('rss_language'); ?>" xml:base="<?php bloginfo_rss('url') ?>/wp-atom.php" <?php do_action('atom_ns'); ?>>
+<?php
+	feed_headers($feed_type);
+	while (have_posts()) {
+		the_post();
+		feed_entry($feed_type, 'entry', apply_filters('feed_entry_element_preceding', "\t"), apply_filters('feed_entry_element_trailing', "\n"));
+	}
+?>
+</feed>
\ No newline at end of file
Index: feed-rss2.php
===================================================================
--- feed-rss2.php	(revision 11981)
+++ feed-rss2.php	(working copy)
@@ -5,57 +5,21 @@
  * @package WordPress
  */
 
+$feed_type='rss2';
 header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
 $more = 1;
 
 echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
 
-<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/"
-	<?php do_action('rss2_ns'); ?>
->
-
+<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/" <?php do_action('rss2_ns'); ?>>
 <channel>
-	<title><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
-	<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
-	<link><?php bloginfo_rss('url') ?></link>
-	<description><?php bloginfo_rss("description") ?></description>
-	<lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
-	<?php the_generator( 'rss2' ); ?>
 	<language><?php echo get_option('rss_language'); ?></language>
-	<sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>
-	<sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>
-	<?php do_action('rss2_head'); ?>
-	<?php while( have_posts()) : the_post(); ?>
-	<item>
-		<title><?php the_title_rss() ?></title>
-		<link><?php the_permalink_rss() ?></link>
-		<comments><?php comments_link(); ?></comments>
-		<pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?></pubDate>
-		<dc:creator><?php the_author() ?></dc:creator>
-		<?php the_category_rss() ?>
-
-		<guid isPermaLink="false"><?php the_guid(); ?></guid>
-<?php if (get_option('rss_use_excerpt')) : ?>
-		<description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
-<?php else : ?>
-		<description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
-	<?php if ( strlen( $post->post_content ) > 0 ) : ?>
-		<content:encoded><![CDATA[<?php the_content_feed('rss2') ?>]]></content:encoded>
-	<?php else : ?>
-		<content:encoded><![CDATA[<?php the_excerpt_rss() ?>]]></content:encoded>
-	<?php endif; ?>
-<?php endif; ?>
-		<wfw:commentRss><?php echo get_post_comments_feed_link(null, 'rss2'); ?></wfw:commentRss>
-		<slash:comments><?php echo get_comments_number(); ?></slash:comments>
-<?php rss_enclosure(); ?>
-	<?php do_action('rss2_item'); ?>
-	</item>
-	<?php endwhile; ?>
+<?php
+	feed_headers($feed_type);
+	while (have_posts()) {
+		the_post();
+		feed_entry($feed_type, 'item', apply_filters('feed_entry_element_preceding', "\t"), apply_filters('feed_entry_element_trailing', "\n"));
+	}
+?>
 </channel>
-</rss>
+</rss>
\ No newline at end of file
Index: feed.php
===================================================================
--- feed.php	(revision 11981)
+++ feed.php	(working copy)
@@ -183,13 +183,23 @@
  * @package WordPress
  * @subpackage Feed
  * @since 2.3.0
- * @uses apply_filters() Call 'the_permalink_rss' on the post permalink
+ * @return get_the_permalink_rss()
  */
 function the_permalink_rss() {
-	echo apply_filters('the_permalink_rss', get_permalink());
+	echo get_the_permalink_rss();
 }
 
 /**
+ * Retrieve the permalink to the post for use in feeds.
+ *
+ * @since 2.9
+ * @uses apply_filters() Call 'the_permalink_rss' on the post permalink
+ */
+function get_the_permalink_rss() {
+	return apply_filters('the_permalink_rss', get_permalink());
+}
+
+/**
  * Display the feed GUID for the current comment.
  *
  * @package WordPress
@@ -276,45 +286,34 @@
  *
  * All of the categories for the current post in the feed loop, will be
  * retrieved and have feed markup added, so that they can easily be added to the
- * RSS2, Atom, or RSS1 and RSS0.91 RDF feeds.
+ * feeds.
  *
  * @package WordPress
  * @subpackage Feed
  * @since 2.1.0
  * @uses apply_filters()
+ * @uses feed_entry_category()
  *
  * @param string $type Optional, default is 'rss'. Either 'rss', 'atom', or 'rdf'.
  * @return string All of the post categories for displaying in the feed.
  */
 function get_the_category_rss($type = 'rss') {
-	$categories = get_the_category();
-	$tags = get_the_tags();
+	$categories = (array)get_the_category();
+	$tags = (array)get_the_tags();
+	$base_scheme = untrailingslashit(get_bloginfo_rss('url'));
+	$category_scheme = "$base_scheme/category/";
+	$tag_scheme = "$base_scheme/tag/";
 	$the_list = '';
-	$cat_names = array();
-
-	$filter = 'rss';
-	if ( 'atom' == $type )
-		$filter = 'raw';
-
-	if ( !empty($categories) ) foreach ( (array) $categories as $category ) {
-		$cat_names[] = sanitize_term_field('name', $category->name, $category->term_id, 'category', $filter);
+	foreach ($categories as $category) {
+		if (!empty($category->slug)) {
+			$the_list .= feed_entry_category($type, $category->name, $category->slug, $category_scheme);
+		}
 	}
-
-	if ( !empty($tags) ) foreach ( (array) $tags as $tag ) {
-		$cat_names[] = sanitize_term_field('name', $tag->name, $tag->term_id, 'post_tag', $filter);
+	foreach ($tags as $tag) {
+		if (!empty($tag->slug)) {
+			$the_list .= feed_entry_category($type, $tag->name, $tag->slug, $tag_scheme);
+		}
 	}
-
-	$cat_names = array_unique($cat_names);
-
-	foreach ( $cat_names as $cat_name ) {
-		if ( 'rdf' == $type )
-			$the_list .= "\t\t<dc:subject><![CDATA[$cat_name]]></dc:subject>\n";
-		elseif ( 'atom' == $type )
-			$the_list .= sprintf( '<category scheme="%1$s" term="%2$s" />', esc_attr( apply_filters( 'get_bloginfo_rss', get_bloginfo( 'url' ) ) ), esc_attr( $cat_name ) );
-		else
-			$the_list .= "\t\t<category><![CDATA[" . @html_entity_decode( $cat_name, ENT_COMPAT, get_option('blog_charset') ) . "]]></category>\n";
-	}
-
 	return apply_filters('the_category_rss', $the_list, $type);
 }
 
@@ -531,3 +530,631 @@
 
 	return $feed;
 }
+
+/**
+ * Feed ID Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $id : Feed ID
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_id'
+ * @return XML string
+ */
+function feed_id($feed_type, $id, $preceding = "\t", $trailing = "\n") {
+	$prefix = ($feed_type == 'atom' ? '' : 'atom:');
+	return apply_filters('feed_id', "$preceding<{$prefix}id>$id</{$prefix}id>$trailing", $feed_type, $id, $preceding, $trailing);
+}
+
+/**
+ * Feed Title Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $text : Text of the feed title
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_title'
+ * @return XML string
+ */
+function feed_title($feed_type, $text, $preceding = "\t", $trailing = "\n") {
+	return apply_filters('feed_title', "$preceding<title>$text</title>$trailing", $feed_type, $text, $preceding, $trailing);
+}
+
+/**
+ * Feed Subtitle Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $text : Text of the feed subtitle/description
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_subtitle'
+ * @return XML string
+ */
+function feed_subtitle($feed_type, $text, $preceding = "\t", $trailing = "\n") {
+	if ($feed_type == 'atom' && !empty($text)) {
+		$subtitle = "$preceding<subtitle>$text</subtitle>$trailing";
+	}
+	elseif ($feed_type == 'rss2') {
+		if (empty($text)) {
+			$subtitle = "$preceding<description />$trailing";
+		}
+		else {
+			$subtitle = "$preceding<description>$text</description>$trailing";
+		}
+	}
+	else {
+		$subtitle = '';
+	}
+	return apply_filters('feed_subtitle', $subtitle, $feed_type, $text, $preceding, $trailing);
+}
+
+/**
+ * Feed Self Link Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $href : The self link of the feed
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_self_link'
+ * @return XML string
+ */
+function feed_self_link($feed_type, $href, $preceding = "\t", $trailing = "\n") {
+	$prefix = ($feed_type == 'atom' ? '' : 'atom:');
+	$self_link = "$preceding<{$prefix}link rel=\"self\" type=\"" . feed_content_type($feed_type) . "\" href=\"$href\" />$trailing";
+	return apply_filters('feed_self_link', $self_link, $feed_type, $href, $preceding, $trailing);
+}
+
+/**
+ * Feed Link Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param bool $is_entry : if the link is entry link
+ * @param string $href : The link of the feed
+ * @param string $href_type : The content type of the link
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_link' or 'feed_entry_link' depending on $is_entry
+ * @return XML string
+ */
+function feed_link($feed_type, $is_entry, $href, $href_type = null, $preceding = "\t", $trailing = "\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$link = '<link rel="alternate"';
+			if (!empty($href_type)) {
+				$link .= " type=\"$href_type\"";
+			}
+			$link .= " href=\"$href\" />";
+			break;
+		case 'rss2':
+			$link = "<link>$href</link>";
+			break;
+	}
+	$link = $preceding . $link . $trailing;
+	return apply_filters(($is_entry == true ? 'feed_entry_link' : 'feed_link'), $link, $feed_type, $href, $href_type, $preceding, $trailing);
+}
+
+/**
+ * Feed Replies Link Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $href : The location of the replies to the feed
+ * @param string $href_type : The content type of the link
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_replies_link'
+ * @return XML string
+ */
+function feed_replies_link($feed_type, $href, $href_type = null, $preceding = "\t", $trailing = "\n") {
+	$prefix = ($feed_type == 'atom' ? '' : 'atom:');
+	$replies_link = "$preceding<{$prefix}link rel=\"replies\"";
+	if (!empty($href_type)) {
+		$replies_link .= " type=\"$href_type\"";
+	}
+	$replies_link .= " href=\"$href\" />$trailing";
+	return apply_filters('feed_replies_link', $replies_link, $feed_type, $href, $href_type, $preceding, $trailing);
+}
+
+/**
+ * Feed Last-Updated Timestamp Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param int $updated_time: The last-updated timestamp of the feed
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_updated'
+ * @return XML string
+ */
+function feed_updated($feed_type, $updated_time, $preceding="\t", $trailing="\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$updated = '<updated>' . gmdate('Y-m-d\TH:i:s\Z', $updated_time).'</updated>';
+			break;
+		case 'rss2':
+			$updated = '<lastBuildDate>' . gmdate('D, d M Y H:i:s +0000', $updated_time). '</lastBuildDate>';
+			break;
+	}
+	$updated = $preceding . $updated . $trailing;
+	return apply_filters('feed_updated', $updated, $feed_type, $updated_time, $preceding, $trailing);
+}
+
+/**
+ * Feed Update Limit Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $period: Feed update period: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly'
+ * @param int $frequency: Feed update frequency, relative to $period
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_update_limit'
+ * @return XML string
+ */
+function feed_update_limit($feed_type, $period, $frequency, $preceding = "\t", $trailing = "\n") {
+	$update_limit = $preceding . "<sy:updatePeriod>$period</sy:updatePeriod>" . $trailing .
+					$preceding . "<sy:updateFrequency>$frequency</sy:updateFrequency>" . $trailing;
+	return apply_filters('feed_update_limit', $update_limit, $feed_type, $period, $frequency, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry ID Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $id: The entry id
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_id'
+ * @return XML string
+ */
+function feed_entry_id($feed_type, $id, $preceding = "\t\t", $trailing = "\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$entry_id = "<id>$id</id>";
+			break;
+		case 'rss2':
+			$entry_id = "<guid isPermaLink=\"false\">$id</guid>";
+			break;
+	}
+	$entry_id = $preceding . $entry_id . $trailing;
+	return apply_filters('feed_entry_id', $entry_id, $feed_type, $id, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Title Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $text: The text of the entry title
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_title'
+ * @return XML string
+ */
+function feed_entry_title($feed_type, $text, $preceding = "\t\t", $trailing = "\n") {
+	return apply_filters('feed_entry_title', "$preceding<title>$text</title>$trailing", $feed_type, $text, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Category Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $category_label: The display name of the category
+ * @param string $category_term Optional : The slug of the category
+ * @param string $category_scheme Optional : The scheme of the category
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_category'
+ * @return XML string
+ */
+function feed_entry_category($feed_type, $category_label, $category_term = null, $category_scheme = null, $preceding = "\t\t", $trailing = "\n") {
+	if (empty($category_term)) {
+		$category_term = $category_label;
+	}
+	switch ($feed_type) {
+		case 'atom':
+			$entry_category = '<category';
+			if (!empty($category_scheme)) {
+				$entry_category .= " scheme=\"$category_scheme\"";
+			}
+			$entry_category .= " term=\"$category_term\" label=\"$category_label\" />";
+			break;
+		case 'rss2':
+			$entry_category = '<category';
+			if (!empty($category_scheme)) {
+				$entry_category .= " domain=\"$category_scheme\"";
+			}
+			$entry_category .= ">$category_label</category>";
+			break;
+	}
+	$entry_category = $preceding . $entry_category . $trailing;
+	return apply_filters('feed_entry_category', $entry_category, $feed_type, $category_label, $category_term, $category_scheme, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Author Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $author_name: The author's display name
+ * @param string $author_email Optional : The author's email address
+ * @param string $author_uri Optional : The author's URI
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_author'
+ * @return XML string
+ */
+function feed_entry_author($feed_type, $author_name, $author_email = null, $author_uri = null, $preceding = "\t\t", $trailing = "\n") {
+	$feed_display_author_email = apply_filters('feed_display_author_email', false);
+	switch ($feed_type) {
+		case 'atom':
+			$entry_author = "<author><name>$author_name</name>";
+			if ($feed_display_author_email == true && !empty($author_email)) {
+				$entry_author .= "<email>$author_email</email>";
+			}
+			if (!empty($author_uri)) {
+				$entry_author .= "<uri>$author_uri</uri>";
+			}
+			$entry_author .= "</author>";
+			break;
+		case 'rss2':
+			if ($feed_display_author_email == true && !empty($author_email)) {
+				$entry_author = "<author>$author_email ($author_name)</author>";
+			}
+			else {
+				$entry_author = "<dc:creator>$author_name</dc:creator>";
+			}
+			break;
+	}
+	$entry_author = $preceding . $entry_author . $trailing;
+	return apply_filters('feed_entry_author', $entry_author, $feed_type, $author_name, $author_email, $author_uri, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Summary Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $summary: The feed entry's summary
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_summary'
+ * @return XML string
+ */
+function feed_entry_summary($feed_type, $summary, $preceding = "\t\t", $trailing = "\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$entry_summary = "<summary type=\"text\">$summary</summary>";
+			break;
+		case 'rss2':
+			$entry_summary = "<description><![CDATA[$summary]]></description>";
+			break;
+	}
+	$entry_summary = $preceding . $entry_summary . $trailing;
+	return apply_filters('feed_entry_summary', $entry_summary, $feed_type, $summary, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Content Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $content: The feed entry's content
+ * @param string $content_type Optional: content type: null | 'text' | 'html' | 'xhtml'
+ * @param string $content_base_url Optional: The base url of the content
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_content'
+ * @return XML string
+ */
+function feed_entry_content($feed_type, $content, $content_type = null, $content_base_url = null, $preceding = "\t\t", $trailing = "\n") {
+	if (empty($content_type)) {
+		$content_type = (strpos(get_bloginfo('html_type'), 'xhtml') !== false ? 'xhtml' : 'html');
+	}
+	if (!empty($content)) {
+		switch ($feed_type) {
+			case 'atom':
+				$entry_content = "<content type=\"$content_type\"";
+				if (!empty($content_base_url)) {
+					$entry_content .= " xml:base=\"$content_base_url\"";
+				}
+				$entry_content .= '>';
+				switch ($content_type) {
+					case 'xhtml':
+						$entry_content .= "<div xmlns=\"http://www.w3.org/1999/xhtml\">$content</div>";
+						break;
+					case 'html':
+						$entry_content .= "<![CDATA[$content]]>";
+						break;
+					default:
+						$entry_content .= $content;
+						break;
+				}
+				$entry_content .= '</content>';
+				break;
+			case 'rss2':
+				$entry_content = "<content:encoded><![CDATA[$content]]></content:encoded>";
+				break;
+		}
+		$entry_content = $preceding . $entry_content . $trailing;
+	}
+	else {
+		$entry_content = '';
+	}
+	return apply_filters('feed_entry_content', $entry_content, $feed_type, $content, $content_type, $content_base_url, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Comment Information Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $blog_comment_link: The link to the feed entry's comment part
+ * @param string $feed_comment_link: The link to the feed entry's comment feed
+ * @param int $comment_number: Number of comments
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_comment_info'
+ * @return XML string
+ */
+function feed_entry_comment_info($feed_type, $blog_comment_link, $feed_comment_link, $comment_number, $preceding = "\t\t", $trailing = "\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$entry_comment_info=
+				$preceding . '<link rel="replies" type="' . get_bloginfo('html_type') . "\" href=\"$blog_comment_link\" thr:count=\"$comment_number\" />" . $trailing .
+				$preceding . '<link rel="replies" type="' . feed_content_type($feed_type) . "\" href=\"$feed_comment_link\" thr:count=\"$comment_number\" />" . $trailing .
+				$preceding . "<thr:total>$comment_number</thr:total>" . $trailing;
+			break;
+		case 'rss2':
+			$entry_comment_info=
+				$preceding . "<comments>$blog_comment_link</comments>" . $trailing .
+				$preceding . "<wfw:commentRss>$feed_comment_link</wfw:commentRss>" . $trailing .
+				$preceding . "<slash:comments>$comment_number</slash:comments>" . $trailing;
+			break;
+	}
+	return apply_filters('feed_entry_comment_info', $entry_comment_info, $feed_type, $blog_comment_link, $feed_comment_link, $comment_number, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Published TimeStamp Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param int $published_time: The published time of the feed entry
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_published'
+ * @return XML string
+ */
+function feed_entry_published($feed_type, $published_time, $preceding = "\t\t", $trailing = "\n") {
+	switch ($feed_type) {
+		case 'atom':
+			$entry_published = '<published>' . gmdate('Y-m-d\TH:i:s\Z',$published_time) . '</published>';
+			break;
+		case 'rss2':
+			$entry_published = '<pubDate>' . gmdate('D, d M Y H:i:s +0000',$published_time) . '</pubDate>';
+			break;
+	}
+	$entry_published = $preceding . $entry_published . $trailing;
+	return apply_filters('feed_entry_published', $entry_published, $feed_type, $published_time, $preceding, $trailing);
+}
+
+/**
+ * Feed Entry Updated TimeStamp Template
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param int $updated_time: The updated time of the feed entry
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ * @uses apply_filters() Calls 'feed_entry_updated'
+ * @return XML string
+ */
+function feed_entry_updated($feed_type, $updated_time, $preceding = "\t\t", $trailing = "\n") {
+	if ($feed_type == 'atom') {
+		$entry_updated = $preceding . '<updated>' . gmdate('Y-m-d\TH:i:s\Z', $updated_time) . '</updated>' . $trailing;
+	}
+	else {
+		$entry_updated = '';
+	}
+	return apply_filters('feed_entry_updated', $entry_updated, $feed_type, $updated_time, $preceding, $trailing);
+}
+
+/**
+ * Feed Headers Generator
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ */
+function feed_headers($feed_type) {
+	global $wp_query;
+	if (is_category()) {
+		$cat_id = $wp_query->get_queried_object_id();
+		$id = get_category_feed_link($cat_id, $feed_type, true);
+		$subtitle = trim(strip_tags(category_description($cat_id)));
+		$self_link = get_category_feed_link($cat_id, $feed_type);
+		$feed_link = get_category_link($cat_id);
+		$replies_link = get_category_comments_feed_link($cat_id, $feed_type);
+	}
+	elseif (is_tag()) {
+		$tag_atom_id = $wp_query->get_queried_object_id();
+		$id = get_tag_feed_link($tag_id, $feed_type, true);
+		$subtitle = trim(strip_tags(tag_description($cat_id)));
+		$self_link = get_tag_feed_link($tag_id, $feed_type);
+		$feed_link = get_tag_link($tag_id);
+		$replies_link = get_tag_comments_feed_link($tag_id, $feed_type);
+	}
+	elseif (is_author()) {
+		$author_id = $wp_query->get_queried_object_id();
+		$id = get_author_feed_link($author_id, $feed_type, true);
+		$subtitle = null;
+		$self_link = get_author_feed_link($author_id, $feed_type);
+		$feed_link = get_author_posts_url($author_id);
+		$replies_link = get_author_comments_feed_link($author_id, $feed_type);
+	}
+	elseif (is_date()) {
+		$year = $month = $day = $hour = $minute = $second = $canonical_feed_link = $alternate_link = $comments_feed_link = null;
+		$year_string = get_query_var('year');
+		$month_string = get_query_var('monthnum');
+		$day_string = get_query_var('day');
+		$hour_string = get_query_var('hour');
+		$minute_string = get_query_var('minute');
+		$second_string = get_query_var('second');
+		$m = get_query_var('m');
+		$week = get_query_var('w');
+		if (!empty($week)) {
+			if (!empty($year_string)) {
+				$year = $year_string;
+			}
+			elseif (!empty($m) && strlen($m) >= 4) {
+				$year = substr($m, 0, 4);
+			}
+			$canonical_feed_link = get_week_feed_link($year, $week, $feed_type);
+			$alternate_link = get_week_link($year, $week);
+			$comments_feed_link = get_week_comments_feed_link($year, $week, $feed_type);
+		}
+		elseif (empty($m)) {
+			if (!empty($year_string)) {
+				$year = $year_string;
+			}
+			if (!empty($month_string)) {
+				$month = $month_string;
+			}
+			if (!empty($day_string)) {
+				$day = $day_string;
+			}
+			if (!empty($hour_string)) {
+				$hour = $hour_string;
+			}
+			if (!empty($minute_string)) {
+				$minute = $minute_string;
+			}
+			if (!empty($second_string)) {
+				$second = $second_string;
+			}
+		}
+		else {
+			$m_length = strlen($m);
+			switch ($m_length) {
+				case 14:
+					$second = substr($m, 12, 2);
+				case 12:
+					$minute = substr($m, 10, 2);
+				case 10:
+					$hour = substr($m, 8, 2);
+				case 8:
+					$day = substr($m, 6, 2);
+				case 6:
+					$month = substr($m, 4, 2);
+				case 4:
+					$year = substr($m, 0, 4);
+					break;
+				default:
+					return false;
+			}
+		}
+		if ($canonical_feed_link === null) {
+			$canonical_feed_link = get_archive_feed_link($year, $month, $day, $hour, $minute, $second, $feed_type);
+		}
+		if ($alternate_link === null) {
+			$alternate_link = get_archive_link($year, $month, $day, $hour, $minute, $second);
+		}
+		if ($comments_feed_link === null) {
+			$comments_feed_link = get_archive_comments_feed_link($year, $month, $day, $hour, $minute, $second, $feed_type);
+		}
+		$subtitle = null;
+		$id=$self_link = $canonical_feed_link;
+		$feed_link = $alternate_link;
+		$replies_link = $comments_feed_link;
+	}
+	elseif (is_search()) {
+		$search_query = get_search_query();
+		$subtitle = null;
+		$id = $self_link = get_search_feed_link($search_query, $feed_type);
+		$feed_link = get_search_link($search_query);
+		$replies_link = get_search_comments_feed_link($search_query, $feed_type);
+	}
+	else {
+		$id = get_feed_link($feed_type, true);
+		$subtitle = get_bloginfo_rss('description');
+		$self_link = get_bloginfo("{$feed_type}_url");
+		$feed_link = trailingslashit(get_bloginfo_rss('url'));
+		$replies_link = get_bloginfo_rss("comments_{$feed_type}_url");
+	}
+	echo feed_id($feed_type, $id);
+	echo feed_title($feed_type, get_bloginfo_rss('name') . get_wp_title_rss());
+	echo feed_subtitle($feed_type, $subtitle);
+	echo feed_self_link($feed_type, $self_link);
+	echo feed_link($feed_type, false, $feed_link, get_bloginfo('html_type'));
+	echo feed_replies_link($feed_type, $replies_link, feed_content_type($feed_type));
+	echo "\t";
+	the_generator($feed_type);
+	if (apply_filters('feed_set_update_limit', true) == true) {
+		echo feed_update_limit($feed_type, apply_filters('rss_update_period', 'hourly'), apply_filters('rss_update_frequency', 1));
+	}
+	do_action("{$feed_type}_head");
+	echo feed_updated($feed_type, strtotime(get_lastpostmodified('GMT')));
+}
+
+/**
+ * Feed Entry Generator
+ *
+ * @since 2.9
+ *
+ * @param string $feed_type : Feed Type
+ * @param string $entry_element_name : Name of the entry element
+ * @param string $preceding Optional : Whitespaces before the element
+ * @param string $trailing Optional : Whitespaces after the element
+ */
+function feed_entry($feed_type, $entry_element_name, $preceding = "\t", $trailing = "\n") {
+	echo $preceding . "<$entry_element_name>" . $trailing;
+	echo feed_entry_id($feed_type, get_the_guid());
+	echo feed_entry_title($feed_type, get_the_title_rss());
+	echo get_the_category_rss($feed_type);
+	echo feed_entry_author($feed_type, get_the_author(), get_the_author_meta('user_email'), get_the_author_meta('user_url'));
+	echo feed_entry_summary($feed_type, trim(get_the_excerpt()));
+	$feed_entry_link = get_the_permalink_rss();
+	if (get_option('rss_use_excerpt') == false) {
+		echo feed_entry_content($feed_type, trim(get_the_content_feed($feed_type)), null, $feed_entry_link);
+	}
+	echo feed_link($feed_type, true, $feed_entry_link, get_bloginfo('html_type'), "\t\t");
+	echo feed_entry_comment_info($feed_type, $feed_entry_link . '#comments', get_post_comments_feed_link(null, $feed_type), get_comments_number());
+	switch ($feed_type) {
+		case 'atom':
+			atom_enclosure();
+			do_action('atom_entry');
+			break;
+		case 'rss2':
+			rss_enclosure();
+			do_action('rss2_item');
+			break;
+	}
+	echo feed_entry_published($feed_type, get_post_time('U', true));
+	echo feed_entry_updated($feed_type, get_post_modified_time('U', true));
+	echo $preceding . "</$entry_element_name>" . $trailing;
+}
\ No newline at end of file
Index: link-template.php
===================================================================
--- link-template.php	(revision 11981)
+++ link-template.php	(working copy)
@@ -357,13 +357,23 @@
  * @since 1.5.0
  *
  * @param string $feed Optional, defaults to default feed. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string
  */
-function get_feed_link($feed = '') {
+function get_feed_link($feed = '', $return_canonical_form = false) {
 	global $wp_rewrite;
 
 	$permalink = $wp_rewrite->get_feed_permastruct();
-	if ( '' != $permalink ) {
+	if ($return_canonical_form==true||empty($permalink)) {
+		if ( empty($feed) )
+			$feed = get_default_feed();
+
+		if ( false !== strpos($feed, 'comments_') )
+			$feed = str_replace('comments_', 'comments-', $feed);
+
+		$output = trailingslashit(get_option('home')) . "?feed={$feed}";
+	}
+	else {
 		if ( false !== strpos($feed, 'comments_') ) {
 			$feed = str_replace('comments_', '', $feed);
 			$permalink = $wp_rewrite->get_comment_feed_permastruct();
@@ -375,16 +385,8 @@
 		$permalink = str_replace('%feed%', $feed, $permalink);
 		$permalink = preg_replace('#/+#', '/', "/$permalink");
 		$output =  get_option('home') . user_trailingslashit($permalink, 'feed');
-	} else {
-		if ( empty($feed) )
-			$feed = get_default_feed();
-
-		if ( false !== strpos($feed, 'comments_') )
-			$feed = str_replace('comments_', 'comments-', $feed);
-
-		$output = trailingslashit(get_option('home')) . "?feed={$feed}";
 	}
-
+	
 	return apply_filters('feed_link', $output, $feed);
 }
 
@@ -395,9 +397,10 @@
  *
  * @param int $post_id Optional. Post ID.
  * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string
  */
-function get_post_comments_feed_link($post_id = '', $feed = '') {
+function get_post_comments_feed_link($post_id = '', $feed = '', $return_canonical_form = false) {
 	global $id;
 
 	if ( empty($post_id) )
@@ -406,19 +409,20 @@
 	if ( empty($feed) )
 		$feed = get_default_feed();
 
-	if ( '' != get_option('permalink_structure') ) {
-		$url = trailingslashit( get_permalink($post_id) ) . 'feed';
-		if ( $feed != get_default_feed() )
-			$url .= "/$feed";
-		$url = user_trailingslashit($url, 'single_feed');
-	} else {
+	if ($return_canonical_form==true||empty($permalink)) {
 		$type = get_post_field('post_type', $post_id);
 		if ( 'page' == $type )
 			$url = trailingslashit(get_option('home')) . "?feed=$feed&amp;page_id=$post_id";
 		else
 			$url = trailingslashit(get_option('home')) . "?feed=$feed&amp;p=$post_id";
 	}
-
+	else {
+		$url = trailingslashit( get_permalink($post_id) ) . 'feed';
+		if ( $feed != get_default_feed() )
+			$url .= "/$feed";
+		$url = user_trailingslashit($url, 'single_feed');
+	}
+	
 	return apply_filters('post_comments_feed_link', $url);
 }
 
@@ -436,10 +440,11 @@
  * @param string $link_text Descriptive text.
  * @param int $post_id Optional post ID.  Default to current post.
  * @param string $feed Optional. Feed format.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string Link to the comment feed for the current post.
 */
-function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
-	$url = get_post_comments_feed_link($post_id, $feed);
+function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '', $return_canonical_form = false) {
+	$url = get_post_comments_feed_link($post_id, $feed, $return_canonical_form);
 	if ( empty($link_text) )
 		$link_text = __('Comments Feed');
 
@@ -458,18 +463,20 @@
  *
  * @param int $author_id ID of an author.
  * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string Link to the feed for the author specified by $author_id.
 */
-function get_author_feed_link( $author_id, $feed = '' ) {
+function get_author_feed_link( $author_id, $feed = '', $return_canonical_form = false) {
 	$author_id = (int) $author_id;
 	$permalink_structure = get_option('permalink_structure');
 
 	if ( empty($feed) )
 		$feed = get_default_feed();
 
-	if ( '' == $permalink_structure ) {
+	if ($return_canonical_form==true||empty($permalink_structure)) {
 		$link = trailingslashit(get_option('home')) . "?feed=$feed&amp;author=" . $author_id;
-	} else {
+	}
+	else {
 		$link = get_author_posts_url($author_id);
 		if ( $feed == get_default_feed() )
 			$feed_link = 'feed';
@@ -485,6 +492,41 @@
 }
 
 /**
+ * Retrieve the comments feed link for a given author.
+ *
+ * @since 2.9
+ *
+ * @param int $author_id ID of an author.
+ * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes
+ * @return string Link to the comments feed for the author specified by $author_id.
+*/
+function get_author_comments_feed_link($author_id, $feed = '', $return_canonical_form = false) {
+	$author_id = (int) $author_id;
+	$permalink_structure = get_option('permalink_structure');
+
+	if ( empty($feed) )
+		$feed = get_default_feed();
+
+	if ($return_canonical_form==true||empty($permalink_structure)) {
+		$link = trailingslashit(get_option('home')) . "?feed=comments-$feed&amp;author=" . $author_id;
+	}
+	else {
+		$link = get_author_posts_url($author_id);
+		if ( $feed == get_default_feed() )
+			$feed_link = 'comments/feed';
+		else
+			$feed_link = "comments/feed/$feed";
+
+		$link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+	}
+
+	$link = apply_filters('author_comments_feed_link', $link, $feed);
+
+	return $link;
+}
+
+/**
  * Retrieve the feed link for a category.
  *
  * Returns a link to the feed for all post in a given category. A specific feed
@@ -496,9 +538,10 @@
  *
  * @param int $cat_id ID of a category.
  * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string Link to the feed for the category specified by $cat_id.
 */
-function get_category_feed_link($cat_id, $feed = '') {
+function get_category_feed_link($cat_id, $feed = '', $return_canonical_form = false) {
 	$cat_id = (int) $cat_id;
 
 	$category = get_category($cat_id);
@@ -511,9 +554,10 @@
 
 	$permalink_structure = get_option('permalink_structure');
 
-	if ( '' == $permalink_structure ) {
+	if ($return_canonical_form==true||empty($permalink_structure)) {
 		$link = trailingslashit(get_option('home')) . "?feed=$feed&amp;cat=" . $cat_id;
-	} else {
+	}
+	else {
 		$link = get_category_link($cat_id);
 		if( $feed == get_default_feed() )
 			$feed_link = 'feed';
@@ -529,15 +573,57 @@
 }
 
 /**
+ * Retrieve the comments feed link for a category.
+ *
+ * @since 2.9
+ *
+ * @param int $cat_id ID of a category.
+ * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes
+ * @return string Link to the comments feed for the category specified by $cat_id.
+*/
+function get_category_comments_feed_link($cat_id, $feed = '', $return_canonical_form = false) {
+	$cat_id = (int) $cat_id;
+
+	$category = get_category($cat_id);
+
+	if ( empty($category) || is_wp_error($category) )
+		return false;
+
+	if ( empty($feed) )
+		$feed = get_default_feed();
+
+	$permalink_structure = get_option('permalink_structure');
+
+	if ($return_canonical_form==true||empty($permalink_structure)) {
+		$link = trailingslashit(get_option('home')) . "?feed=comments-$feed&amp;cat=" . $cat_id;
+	}
+	else {
+		$link = get_category_link($cat_id);
+		if( $feed == get_default_feed() )
+			$feed_link = 'comments/feed';
+		else
+			$feed_link = "comments/feed/$feed";
+
+		$link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+	}
+
+	$link = apply_filters('category_comments_feed_link', $link, $feed);
+
+	return $link;
+}
+
+/**
  * Retrieve permalink for feed of tag.
  *
  * @since 2.3.0
  *
  * @param int $tag_id Tag ID.
  * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes (since 2.9)
  * @return string
  */
-function get_tag_feed_link($tag_id, $feed = '') {
+function get_tag_feed_link($tag_id, $feed = '', $return_canonical_form = false) {
 	$tag_id = (int) $tag_id;
 
 	$tag = get_tag($tag_id);
@@ -550,9 +636,10 @@
 	if ( empty($feed) )
 		$feed = get_default_feed();
 
-	if ( '' == $permalink_structure ) {
+	if ($return_canonical_form==true||empty($permalink_structure)) {
 		$link = trailingslashit(get_option('home')) . "?feed=$feed&amp;tag=" . $tag->slug;
-	} else {
+	}
+	else {
 		$link = get_tag_link($tag->term_id);
 		if ( $feed == get_default_feed() )
 			$feed_link = 'feed';
@@ -567,6 +654,46 @@
 }
 
 /**
+ * Retrieve permalink for the comments feed of tag.
+ *
+ * @since 2.9
+ *
+ * @param int $tag_id Tag ID.
+ * @param string $feed Optional. Feed type.
+ * @param bool $return_canonical_form Optional. Whether the function should generate a link that will not change even when the permalink format changes
+ * @return string
+ */
+function get_tag_comments_feed_link($tag_id, $feed = '', $return_canonical_form = false) {
+	$tag_id = (int) $tag_id;
+
+	$tag = get_tag($tag_id);
+
+	if ( empty($tag) || is_wp_error($tag) )
+		return false;
+
+	$permalink_structure = get_option('permalink_structure');
+
+	if ( empty($feed) )
+		$feed = get_default_feed();
+
+	if ($return_canonical_form==true||empty($permalink_structure)) {
+		$link = trailingslashit(get_option('home')) . "?feed=comments-$feed&amp;tag=" . $tag->slug;
+	}
+	else {
+		$link = get_tag_link($tag->term_id);
+		if ( $feed == get_default_feed() )
+			$feed_link = 'comments/feed';
+		else
+			$feed_link = "comments/feed/$feed";
+		$link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+	}
+
+	$link = apply_filters('tag_comments_feed_link', $link, $feed);
+
+	return $link;
+}
+
+/**
  * Retrieve edit tag link.
  *
  * @since 2.7.0
@@ -609,6 +736,26 @@
 }
 
 /**
+ * Retrieve the permalink for the search results.
+ *
+ * @since 2.9
+ *
+ * @param string $search_query Optional. Search query.
+ * @return string
+ */
+function get_search_link($search_query = '') {
+	if(empty($search_query)) {
+		$search=esc_attr(get_search_query());
+	}
+	else {
+		$search=esc_attr(stripslashes($search_query));
+	}
+	$link=trailingslashit(get_option('home'))."?s=$search";
+	$link=apply_filters('search_link',$link);
+	return $link;
+}
+
+/**
  * Retrieve the permalink for the feed of the search results.
  *
  * @since 2.5.0
@@ -659,6 +806,215 @@
 }
 
 /**
+ * Convert link array to link string. For internal use only.
+ *
+ * @since 2.9
+ *
+ * @param array $array The link array
+ * @return string
+ */
+function _archive_array_to_link($array) {
+	$link = $array[0];
+	$array_length = count($array);
+	if ($array_length > 1) {
+		$link .= "?$array[1]";
+		if ($array_length > 2) {
+			for ($i = 2; $i < $array_length ; $i++) {
+				$link .= "&amp;$array[$i]";
+			}
+		}
+	}
+	return $link;
+}
+
+/**
+ * Retrieve the archive link of a specific time
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $month Optional
+ * @param int $day Optional
+ * @param int $hour Optional
+ * @param int $minute Optional
+ * @param int $second Optional
+ * @param bool $return_array Optional
+ * @return array or string depending on $return_array
+ */
+function get_archive_link($year, $month = null, $day = null, $hour = null, $minute = null, $second = null, $return_array = false) {
+	$array = array(trailingslashit(get_option('home')));
+	if ($year !== null) {
+		$year = (int)$year;
+		if ($year <= 0) {
+			return false;
+		}
+		$array[] = "year=$year";
+	}
+	if ($month!==null) {
+		$month = (int)$month;
+		if ($month < 1 || $month > 12) {
+			return false;
+		}
+		$array[] = "monthnum=$month";
+	}
+	if ($day !== null) {
+		$day = (int)$day;
+		if ($day < 1 || $day > 31) {
+			return false;
+		}
+		$array[] = "day=$day";
+	}
+	if ($hour !== null) {
+		$hour = (int)$hour;
+		if ($hour < 0 || $hour > 23) {
+			return false;
+		}
+		$array[] = "hour=$hour";
+	}
+	if ($minute !== null) {
+		$minute = (int)$minute;
+		if($minute < 0 || $minute > 60) {
+			return false;
+		}
+		$array[] = "minute=$minute";
+	}
+	if ($second !== null) {
+		$second = (int)$second;
+		if($second < 0 || $second > 60) {
+			return false;
+		}
+		$array[] = "second=$second";
+	}
+	if ($return_array == true) {
+		return $array;
+	}
+	else {
+		return apply_filters('archive_link', _archive_array_to_link($array), $year, $month, $day, $hour, $minute, $second);
+	}
+}
+
+/**
+ * Retrieve the feed link of a specific time
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $month Optional
+ * @param int $day Optional
+ * @param int $hour Optional
+ * @param int $minute Optional
+ * @param int $second Optional
+ * @param string $feed Optional. Feed Type
+ * @return string
+ */
+function get_archive_feed_link($year, $month = null, $day = null, $hour = null, $minute = null, $second = null, $feed = '') {
+	$array = get_archive_link($year, $month, $day, $hour, $minute, $second, true);
+	if ($array === false) {
+		return false;
+	}
+	if (empty($feed)) {
+		$feed = get_default_feed();
+	}
+	$array[] = "feed=$feed";
+	return apply_filters('archive_feed_link', _archive_array_to_link($array), $year, $month, $day, $hour, $minute, $second, $feed);
+}
+
+/**
+ * Retrieve the comments feed link of a specific time
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $month Optional
+ * @param int $day Optional
+ * @param int $hour Optional
+ * @param int $minute Optional
+ * @param int $second Optional
+ * @param string $feed Optional. Feed Type
+ * @return string
+ */
+function get_archive_comments_feed_link($year, $month = null, $day = null, $hour = null, $minute = null, $second = null, $feed = '') {
+	$array = get_archive_link($year, $month, $day, $hour, $minute, $second, true);
+	if ($array === false) {
+		return false;
+	}
+	if (empty($feed)) {
+		$feed = get_default_feed();
+	}
+	$array[] = "feed=comments-$feed";
+	return apply_filters('archive_comments_feed_link', _archive_array_to_link($array), $year, $month, $day, $hour, $minute, $second, $feed);
+}
+
+/**
+ * Retrieve the archive link of a specific week
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $week
+ * @param bool $return_array Optional
+ * @return array or string depending on $return_array
+ */
+function get_week_link($year, $week, $return_array = false) {
+	$array = get_archive_link($year, null, null, null, null, null, true);
+	$week = (int)$week;
+	if ($array === false || $week < 0 || $week > 53) {
+		return false;
+	}
+	$array[] = "w=$week";
+	if ($return_array == true) {
+		return $array;
+	}
+	else {
+		return apply_filters('week_link', _archive_array_to_link($array));
+	}
+}
+
+/**
+ * Retrieve the feed link of a specific week
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $week
+ * @param string $feed Optional. Feed Type
+ * @return string
+ */
+function get_week_feed_link($year, $week, $feed = '') {
+	$array = get_week_link($year, $week, true);
+	if ($array === false) {
+		return false;
+	}
+	if (empty($feed)) {
+		$feed = get_default_feed();
+	}
+	$array[] = "feed=$feed";
+	return apply_filters('week_feed_link', _archive_array_to_link($array), $feed);
+}
+
+/**
+ * Retrieve the comments feed link of a specific week
+ *
+ * @since 2.9
+ *
+ * @param int $year
+ * @param int $week
+ * @param string $feed Optional. Feed Type
+ * @return string
+ */
+function get_week_comments_feed_link($year, $week, $feed = '') {
+	$array = get_week_link($year, $week, true);
+	if ($array === false) {
+		return false;
+	}
+	if (empty($feed)) {
+		$feed = get_default_feed();
+	}
+	$array[] = "feed=comments-$feed";
+	return apply_filters('week_comments_feed_link', _archive_array_to_link($array), $feed);
+}
+
+/**
  * Retrieve edit posts link for post.
  *
  * Can be used within the WordPress loop or outside of it. Can be used with
