diff --git a/src/wp-includes/Oxymel.php b/src/wp-includes/Oxymel.php
new file mode 100644
index 0000000..857329e
--- /dev/null
+++ b/src/wp-includes/Oxymel.php
@@ -0,0 +1,211 @@
+<?php
+class Oxymel {
+	private $xml;
+	private $dom;
+	private $current_element;
+	private $last_inserted;
+	private $go_deep_on_next_element = 0;
+	private $go_up_on_next_element = 0;
+	private $nesting_level = 0;
+	private $contains_nesting_level = 0;
+	private $indentation= '  ';
+
+	public function __construct() {
+		$this->xml = '';
+		$this->init_new_dom();
+	}
+
+	public function to_string() {
+		return $this->xml .= $this->indent( $this->xml_from_dom(), $this->nesting_level );
+	}
+
+	public function __call( $name, $args ) {
+		array_unshift( $args, $name );
+		return call_user_func_array( array( $this, 'tag' ), $args );
+	}
+
+	public function __get( $name ) {
+		return $this->$name();
+	}
+
+	public function contains() {
+		$this->contains_nesting_level++;
+		$this->nesting_level++;
+		if ( $this->go_deep_on_next_element ) {
+			throw new OxymelException( 'contains cannot be used consecutively more than once' );
+		}
+		$this->go_deep_on_next_element++;
+		return $this;
+	}
+
+	public function end() {
+		$this->contains_nesting_level--;
+		$this->nesting_level--;
+		if ( $this->contains_nesting_level < 0 ) {
+			throw new OxymelException( 'end is used without a matching contains' );
+		}
+		$this->go_up_on_next_element++;
+		return $this;
+	}
+
+	public function tag( $name, $content_or_attributes = null, $attributes = array() ) {
+		list( $content, $attributes ) = $this->get_content_and_attributes_from_tag_args( $content_or_attributes, $attributes );
+		$is_opening =  0 === strpos( $name, 'open_' );
+		$is_closing =  0 === strpos( $name, 'close_' );
+		$name = preg_replace("/^(open|close)_/", '', $name );
+
+		$element = $this->create_element( $name, $content, $attributes );
+
+		if ( !$is_opening && !$is_closing )
+			$this->add_element_to_dom( $element );
+		elseif ( $is_opening )
+			$this->add_opening_tag_from_element( $element );
+		elseif ( $is_closing )
+			$this->add_closing_tag_from_tag_name( $name );
+
+		return $this;
+	}
+
+	public function cdata( $text ) {
+		$this->add_element_to_dom( $this->dom->createCDATASection( $text ) );
+		return $this;
+	}
+
+	public function text( $text ) {
+		$this->add_element_to_dom( $this->dom->createTextNode( $text ) );
+		return $this;
+	}
+
+	public function comment( $text ) {
+		$this->add_element_to_dom( $this->dom->createComment( $text ) );
+		return $this;
+	}
+
+	public function xml() {
+		$this->add_element_to_dom( $this->dom->createProcessingInstruction( 'xml', 'version="1.0" encoding="UTF-8"' ) );
+		return $this;
+	}
+
+	public function oxymel( Oxymel $other ) {
+		foreach( $other->dom->childNodes as $child ) {
+			$child = $this->dom->importNode( $child, true );
+			$this->add_element_to_dom( $child );
+		}
+		return $this;
+	}
+
+	public function raw(  $raw_xml ) {
+		if ( !$raw_xml ) {
+			return $this;
+		}
+		$fragment = $this->dom->createDocumentFragment();
+		$fragment->appendXML($raw_xml);
+		$this->add_element_to_dom( $fragment );
+		return $this;
+	}
+
+	private function add_element_to_dom( $element ) {
+		$this->move_current_element_deep();
+		$this->move_current_element_up();
+		$this->last_inserted = $this->current_element->appendChild($element);
+	}
+
+	private function move_current_element_deep() {
+		if ( $this->go_deep_on_next_element ) {
+			if ( !$this->last_inserted ) {
+				throw new OxymelException( 'contains has been used before adding any tags' );
+			}
+			$this->current_element = $this->last_inserted;
+			$this->go_deep_on_next_element--;
+		}
+	}
+
+	private function move_current_element_up() {
+		if ( $this->go_up_on_next_element ) {
+			while ( $this->go_up_on_next_element ) {
+				$this->current_element = $this->current_element->parentNode;
+				$this->go_up_on_next_element--;
+			}
+		}
+	}
+
+	private function get_content_and_attributes_from_tag_args( $content_or_attributes, array $attributes ) {
+		$content = null;
+		if ( !$attributes ) {
+			if ( is_array( $content_or_attributes ) )
+				$attributes = $content_or_attributes;
+			else
+				$content = $content_or_attributes;
+		} else {
+			$content = $content_or_attributes;
+		}
+		return array( $content, $attributes );
+	}
+
+	private function init_new_dom() {
+		unset( $this->dom, $this->current_element );
+		$this->dom = new DOMDocument();
+		$this->dom->formatOutput = true;
+		$this->current_element = $this->dom;
+		$this->last_inserted = null;
+	}
+
+	private function xml_from_dom() {
+		if ( 0 !== $this->contains_nesting_level ) {
+			throw new OxymelException( 'contains and end calls do not match' );
+		}
+		$xml = '';
+		foreach( $this->dom->childNodes as $child ) {
+			$xml .= $this->dom->saveXML( $child ) . "\n";
+		}
+		return $xml;
+	}
+
+	private function create_element( $name, $content, $attributes ) {
+		if ( !is_null( $content ) )
+			$element = $this->dom->createElement( $name, $content );
+		else
+			$element = $this->dom->createElement( $name );
+
+		foreach( $attributes as $attribute_name => $attribute_value ) {
+			$element->setAttribute( $attribute_name, $attribute_value );
+		}
+
+		return $element;
+	}
+
+	private function add_opening_tag_from_element( $element ) {
+		$this->xml .= $this->indent( $this->xml_from_dom(), $this->nesting_level );
+		$tag = $this->dom->saveXML($element);
+		$this->xml .= $this->indent( str_replace( '/>', '>', $tag ) . "\n", $this->nesting_level );
+		$this->nesting_level++;
+		$this->init_new_dom();
+	}
+
+	private function add_closing_tag_from_tag_name( $name ) {
+		$this->xml .= $this->xml_from_dom();
+		$this->nesting_level--;
+		if ( $this->nesting_level < 0 ) {
+			$this->xml = $this->indent( $this->xml, -$this->nesting_level );
+			$this->nesting_level = 0;
+		}
+		$this->xml .= $this->indent( "</$name>\n", $this->nesting_level );
+		$this->init_new_dom();
+	}
+
+	private function indent( $string, $level ) {
+		if ( !$level ) {
+			return $string;
+		}
+		$lines = explode( "\n", $string );
+		foreach( $lines as &$line ) {
+			if ( !trim( $line ) )
+				continue;
+			$line = str_repeat( $this->indentation, $level ) . $line;
+		}
+		return implode( "\n", $lines );
+	}
+}
+
+class OxymelException extends Exception {
+}
diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php
index 734509a..dc5c117 100644
--- a/src/wp-includes/default-constants.php
+++ b/src/wp-includes/default-constants.php
@@ -87,6 +87,17 @@ function wp_initial_constants() {
 	define( 'DAY_IN_SECONDS',    24 * HOUR_IN_SECONDS   );
 	define( 'WEEK_IN_SECONDS',    7 * DAY_IN_SECONDS    );
 	define( 'YEAR_IN_SECONDS',  365 * DAY_IN_SECONDS    );
+
+	// Constants for expressing human-readable data sizes
+	// in their respective number of bytes.
+	define( 'KB_IN_BYTES', 1024 );
+	define( 'MB_IN_BYTES', 1024 * KB_IN_BYTES );
+	define( 'GB_IN_BYTES', 1024 * MB_IN_BYTES );
+	define( 'TB_IN_BYTES', 1024 * GB_IN_BYTES );
+	define( 'PB_IN_BYTES', 1024 * TB_IN_BYTES );
+	define( 'EB_IN_BYTES', 1024 * PB_IN_BYTES );
+	define( 'ZB_IN_BYTES', 1024 * EB_IN_BYTES );
+	define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES );
 }
 
 /**
diff --git a/src/wp-includes/export/class-wp-export-query.php b/src/wp-includes/export/class-wp-export-query.php
new file mode 100644
index 0000000..30de3fe
--- /dev/null
+++ b/src/wp-includes/export/class-wp-export-query.php
@@ -0,0 +1,331 @@
+<?php
+/**
+ * Represents a set of posts and other site data to be exported.
+ *
+ * An immutable object, which gathers all data needed for the export.
+ */
+class WP_Export_Query {
+	const QUERY_CHUNK = 100;
+
+	private static $defaults = array(
+		'post_ids' => null,
+		'post_type' => null,
+		'status' => null,
+		'author' => null,
+		'start_date' => null,
+		'end_date' => null,
+		'category' => null,
+	);
+
+	private $post_ids;
+	private $filters;
+	private $xml_gen;
+
+	private $wheres = array();
+	private $joins = array();
+
+	private $author;
+	private $category;
+
+	public $missing_parents = false;
+
+	public function __construct( $filters = array() ) {
+		$this->filters = wp_parse_args( $filters, self::$defaults );
+		$this->post_ids = $this->calculate_post_ids();
+	}
+
+	public function post_ids() {
+		return $this->post_ids;
+	}
+
+	public function charset() {
+		return get_bloginfo( 'charset' );
+	}
+
+	public function site_metadata() {
+		$metadata = array(
+			'name' => $this->bloginfo_rss( 'name' ),
+			'url' => $this->bloginfo_rss( 'url' ),
+			'language' => $this->bloginfo_rss( 'language' ),
+			'description' => $this->bloginfo_rss( 'description' ),
+			'pubDate' => date( 'D, d M Y H:i:s +0000' ),
+			'site_url' => is_multisite()? network_home_url() : $this->bloginfo_rss( 'url' ),
+			'blog_url' => $this->bloginfo_rss( 'url' ),
+		);
+		return $metadata;
+	}
+
+	public function wp_generator_tag() {
+		return apply_filters( 'the_generator', get_the_generator( 'export' ), 'export' );
+	}
+
+	public function authors() {
+		global $wpdb;
+		$authors = array();
+		$author_ids = $wpdb->get_col( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" );
+		foreach ( (array) $author_ids as $author_id ) {
+			$authors[] = get_userdata( $author_id );
+		}
+		$authors = array_filter( $authors );
+		return $authors;
+	}
+
+	public function categories() {
+		if ( $this->category ) {
+			return array( $this->category );
+		}
+		if ( $this->filters['post_type'] ) {
+			return array();
+		}
+		$categories = (array) get_categories( array( 'get' => 'all' ) );
+
+		$this->check_for_orphaned_terms( $categories );
+
+		$categories = self::topologically_sort_terms( $categories );
+
+		return $categories;
+	}
+
+	public function tags() {
+		if ( $this->filters['post_type'] ) {
+			return array();
+		}
+		$tags = (array) get_tags( array( 'get' => 'all' ) );
+
+		$this->check_for_orphaned_terms( $tags );
+
+		return $tags;
+	}
+
+	public function custom_taxonomies_terms() {
+		if ( $this->filters['post_type'] ) {
+			return array();
+		}
+		$custom_taxonomies = get_taxonomies( array( '_builtin' => false ) );
+		$custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) );
+		$this->check_for_orphaned_terms( $custom_terms );
+		$custom_terms = self::topologically_sort_terms( $custom_terms );
+		return $custom_terms;
+	}
+
+	public function nav_menu_terms() {
+		$nav_menus = wp_get_nav_menus();
+		foreach( $nav_menus as &$term ) {
+			$term->description = '';
+		}
+		return $nav_menus;
+	}
+
+	public function exportify_post( $post ) {
+		$GLOBALS['wp_query']->in_the_loop = true;
+		$previous_global_post = isset( $GLOBALS['post'] )? $GLOBALS['post'] : null;
+		$GLOBALS['post'] = $post;
+		setup_postdata( $post );
+		$post->post_content = apply_filters( 'the_content_export', $post->post_content );
+		$post->post_excerpt = apply_filters( 'the_excerpt_export', $post->post_excerpt );
+		$post->is_sticky = is_sticky( $post->ID ) ? 1 : 0;
+		$post->terms = self::get_terms_for_post( $post );
+		$post->meta = self::get_meta_for_post( $post );
+		$post->comments = self::get_comments_for_post( $post );
+		$GLOBALS['post'] = $previous_global_post;
+		return $post;
+	}
+
+	public function posts() {
+		$posts_iterator = new WP_Post_IDs_Iterator( $this->post_ids, self::QUERY_CHUNK );
+		return new WP_Map_Iterator( $posts_iterator, array( $this, 'exportify_post' ) );
+	}
+
+	private function calculate_post_ids() {
+		global $wpdb;
+		if ( is_array( $this->filters['post_ids'] ) ) {
+			return $this->filters['post_ids'];
+		}
+		$this->post_type_where();
+		$this->status_where();
+		$this->author_where();
+		$this->start_date_where();
+		$this->end_date_where();
+		$this->category_where();
+
+		$where = implode( ' AND ', array_filter( $this->wheres ) );
+		if ( $where ) $where = "WHERE $where";
+		$join = implode( ' ', array_filter( $this->joins ) );
+
+		$post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where" );
+		$post_ids = array_merge( $post_ids, $this->attachments_for_specific_post_types( $post_ids ) );
+		return $post_ids;
+	}
+
+	private function post_type_where() {
+		global $wpdb;
+		$post_types_filters = array( 'can_export' => true );
+		if ( $this->filters['post_type'] ) {
+			$post_types_filters = array_merge( $post_types_filters, array( 'name' => $this->filters['post_type'] ) );
+		}
+		$post_types = get_post_types( $post_types_filters );
+		if ( !$post_types ) {
+			$this->wheres[] = 'p.post_type IS NULL';
+			return;
+		}
+		$this->wheres[] = $wpdb->build_IN_condition( 'p.post_type', $post_types );
+	}
+
+	private function status_where() {
+		global $wpdb;
+		if ( !$this->filters['status'] ) {
+			$this->wheres[] = "p.post_status != 'auto-draft'";
+			return;
+		}
+		$this->wheres[] = $wpdb->prepare( 'p.post_status = %s', $this->filters['status'] );
+	}
+
+	private function author_where() {
+		global $wpdb;
+		$user = $this->find_user_from_any_object( $this->filters['author'] );
+		if ( !$user || is_wp_error( $user ) ) {
+			return;
+		}
+		$this->author = $user;
+		$this->wheres[] = $wpdb->prepare( 'p.post_author = %d', $user->ID );
+	}
+
+	private function start_date_where() {
+		global $wpdb;
+		$timestamp = strtotime( $this->filters['start_date'] );
+		if ( !$timestamp ) {
+			return;
+		}
+		$this->wheres[] = $wpdb->prepare( 'p.post_date >= %s', date( 'Y-m-d 00:00:00', $timestamp ) );
+	}
+
+	private function end_date_where() {
+		global $wpdb;
+		$timestamp = strtotime( $this->filters['end_date'] );
+		if ( !$timestamp ) {
+			return;
+		}
+		$this->wheres[] = $wpdb->prepare( 'p.post_date <= %s', date( 'Y-m-d 23:59:59', $timestamp ) );
+	}
+
+	private function category_where() {
+		global $wpdb;
+		if ( 'post' != $this->filters['post_type'] ) {
+			return;
+		}
+		$category = $this->find_category_from_any_object( $this->filters['category'] );
+		if ( !$category ) {
+			return;
+		}
+		$this->category = $category;
+		$this->joins[] = "INNER JOIN {$wpdb->term_relationships} AS tr ON (p.ID = tr.object_id)";
+		$this->wheres[] = $wpdb->prepare( 'tr.term_taxonomy_id = %d', $category->term_taxonomy_id );
+	}
+
+	private function attachments_for_specific_post_types( $post_ids ) {
+		global $wpdb;
+		if ( !$this->filters['post_type'] ) {
+			return array();
+		}
+		$attachment_ids = array();
+		while ( $batch_of_post_ids = array_splice( $post_ids, 0, self::QUERY_CHUNK ) ) {
+			$post_parent_condition = $wpdb->build_IN_condition( 'post_parent', $batch_of_post_ids );
+			$attachment_ids = array_merge( $attachment_ids, (array)$wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND $post_parent_condition" ) );
+		}
+		return array_map( 'intval', $attachment_ids );
+	}
+
+	private function bloginfo_rss( $section ) {
+		return apply_filters( 'bloginfo_rss', get_bloginfo_rss( $section ), $section );
+	}
+
+	private function find_user_from_any_object( $user ) {
+		if ( is_numeric( $user ) ) {
+			return get_user_by( 'id', $user );
+		} elseif ( is_string( $user ) ) {
+			return get_user_by( 'login', $user );
+		} elseif ( isset( $user->ID ) ) {
+			return get_user_by( 'id', $user->ID );
+		}
+		return false;
+	}
+
+	private function find_category_from_any_object( $category ) {
+		if ( is_numeric( $category ) ) {
+			return get_term( $category, 'category' );
+		} elseif ( is_string( $category ) ) {
+			$term = term_exists( $category, 'category' );
+			return isset( $term['term_id'] )? get_term( $term['term_id'], 'category' ) : false;
+		} elseif ( isset( $category->term_id ) ) {
+			return get_term( $category->term_id, 'category' );
+		}
+		return false;
+	}
+
+	private static function topologically_sort_terms( $terms ) {
+		$sorted = array();
+		while ( $term = array_shift( $terms ) ) {
+			if ( $term->parent == 0 || isset( $sorted[$term->parent] ) )
+				$sorted[$term->term_id] = $term;
+			else
+				$terms[] = $term;
+		}
+		return $sorted;
+	}
+
+	private function check_for_orphaned_terms( $terms ) {
+		$term_ids = array();
+		$have_parent = array();
+
+		foreach ( $terms as $term ) {
+			$term_ids[ $term->term_id ] = true;
+			if ( $term->parent != 0 )
+				$have_parent[] = $term;
+		}
+
+		foreach ( $have_parent as $has_parent ) {
+			if ( ! isset( $term_ids[ $has_parent->parent ] ) ) {
+				$this->missing_parents = $has_parent;
+				throw new WP_Export_Term_Exception( __( 'Term is missing a parent.' ) );
+			}
+		}
+	}
+
+	private static function get_terms_for_post( $post ) {
+		$taxonomies = get_object_taxonomies( $post->post_type );
+		if ( empty( $taxonomies ) )
+			return array();
+		$terms = wp_get_object_terms( $post->ID, $taxonomies );
+		$terms = $terms? $terms : array();
+		return $terms;
+	}
+
+	private static function get_meta_for_post( $post ) {
+		global $wpdb;
+		$meta_for_export = array();
+		$meta_from_db = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
+		foreach ( $meta_from_db as $meta ) {
+			if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) )
+				continue;
+			$meta_for_export[] = $meta;
+		}
+		return $meta_for_export;
+	}
+
+	private static function get_comments_for_post( $post ) {
+		global $wpdb;
+		$comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );
+		foreach( $comments as $comment ) {
+			$meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
+			$meta = $meta? $meta : array();
+			$comment->meta = $meta;
+		}
+		return $comments;
+	}
+}
+
+class WP_Export_Exception extends RuntimeException {
+}
+
+class WP_Export_Term_Exception extends RuntimeException {
+}
diff --git a/src/wp-includes/export/class-wp-export-wxr-formatter.php b/src/wp-includes/export/class-wp-export-wxr-formatter.php
new file mode 100644
index 0000000..073c271
--- /dev/null
+++ b/src/wp-includes/export/class-wp-export-wxr-formatter.php
@@ -0,0 +1,279 @@
+<?php
+/**
+ * Version number for the export format.
+ *
+ * Bump this when something changes that might affect compatibility.
+ *
+ * @since 2.5.0
+ */
+define( 'WXR_VERSION', '1.2' );
+
+require_once ABSPATH . WPINC . '/Oxymel.php';
+
+class WP_Export_Oxymel extends Oxymel {
+	public function optional( $tag_name, $contents ) {
+		if ( $contents ) {
+			$this->$tag_name( $contents );
+		}
+		return $this;
+	}
+
+	public function optional_cdata( $tag_name, $contents ) {
+		if ( $contents ) {
+			$this->$tag_name->contains->cdata( $contents )->end;
+		}
+		return $this;
+	}
+}
+
+/**
+ * Responsible for formatting the data in WP_Export_Query to WXR
+ */
+class WP_Export_WXR_Formatter {
+	function __construct( $export ) {
+		$this->export = $export;
+		$this->wxr_version = WXR_VERSION;
+	}
+
+	function before_posts() {
+		$before_posts_xml = '';
+		$before_posts_xml .= $this->header();
+		$before_posts_xml .= $this->site_metadata();
+		$before_posts_xml .= $this->authors();
+		$before_posts_xml .= $this->categories();
+		$before_posts_xml .= $this->tags();
+		$before_posts_xml .= $this->nav_menu_terms();
+		$before_posts_xml .= $this->custom_taxonomies_terms();
+		$before_posts_xml .= $this->rss2_head_action();
+		return $before_posts_xml;
+	}
+
+	function posts() {
+		return new WP_Map_Iterator( $this->export->posts(), array( $this, 'post' ) );
+	}
+
+	function after_posts() {
+		return $this->footer();
+	}
+
+	function header() {
+		$oxymel = new Oxymel;
+		$charset = $this->export->charset();
+		$wp_generator_tag = $this->export->wp_generator_tag();
+		$comment = <<<COMMENT
+
+ This is a WordPress eXtended RSS file generated by WordPress as an export of your site.
+ It contains information about your site's posts, pages, comments, categories, and other content.
+ You may use this file to transfer that content from one site to another.
+ This file is not intended to serve as a complete backup of your site.
+
+ To import this information into a WordPress site follow these steps:
+ 1. Log in to that site as an administrator.
+ 2. Go to Tools: Import in the WordPress admin panel.
+ 3. Install the "WordPress" importer from the list.
+ 4. Activate & Run Importer.
+ 5. Upload this file using the form provided on that page.
+ 6. You will first be asked to map the authors in this export file to users
+    on the site. For each author, you may choose to map to an
+    existing user on the site or to create a new user.
+ 7. WordPress will then import each of the posts, pages, comments, categories, etc.
+    contained in this file into your site.
+
+COMMENT;
+		return $oxymel
+			->xml
+			->comment( $comment )
+			->raw( $wp_generator_tag )
+			->open_rss( array(
+				'version' => '2.0',
+				'xmlns:excerpt' => "http://wordpress.org/export/{$this->wxr_version}/excerpt/",
+				'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:wp' => "http://wordpress.org/export/{$this->wxr_version}/",
+			) )
+				->open_channel
+				->to_string();
+
+	}
+
+	function site_metadata() {
+		$oxymel = new Oxymel;
+		$metadata = $this->export->site_metadata();
+		return $oxymel
+			->title( $metadata['name'] )
+			->link( $metadata['url'] )
+			->description( $metadata['description'] )
+			->pubDate( $metadata['pubDate'] )
+			->language( $metadata['language'] )
+			->tag( 'wp:wxr_version', $this->wxr_version )
+			->tag( 'wp:base_site_url', $metadata['site_url'] )
+			->tag( 'wp:base_blog_url', $metadata['blog_url'] )
+			->to_string();
+	}
+
+	function authors() {
+		$oxymel = new Oxymel;
+		$authors = $this->export->authors();
+		foreach ( $authors as $author ) {
+			$oxymel
+				->tag( 'wp:author' )->contains
+					->tag( 'wp:author_login', $author->user_login )
+					->tag( 'wp:author_email', $author->user_email )
+					->tag( 'wp:author_display_name' )->contains->cdata( $author->display_name )->end
+					->tag( 'wp:author_first_name' )->contains->cdata( $author->user_first_name )->end
+					->tag( 'wp:author_last_name' )->contains->cdata( $author->user_last_name )->end
+					->end;
+		}
+		return $oxymel->to_string();
+	}
+
+	function categories() {
+		$oxymel = new WP_Export_Oxymel;
+		$categories = $this->export->categories();
+		foreach( $categories as $term_id => $category ) {
+			$category->parent_slug = $category->parent? $categories[$category->parent]->slug : '';
+			$oxymel->tag( 'wp:category' )->contains
+				->tag( 'wp:term_id', $category->term_id )
+				->tag( 'wp:category_nicename', $category->slug )
+				->tag( 'wp:category_parent', $category->parent_slug )
+				->optional_cdata( 'wp:cat_name', $category->name )
+				->optional_cdata( 'wp:category_description', $category->description )
+				->end;
+		}
+		return $oxymel->to_string();
+	}
+
+	function tags() {
+		$oxymel = new WP_Export_Oxymel;
+		$tags = $this->export->tags();
+		foreach( $tags as $tag ) {
+			$oxymel->tag( 'wp:tag' )->contains
+				->tag( 'wp:term_id', $tag->term_id )
+				->tag( 'wp:tag_slug', $tag->slug )
+				->optional_cdata( 'wp:tag_name', $tag->name )
+				->optional_cdata( 'wp:tag_description', $tag->description )
+				->end;
+		}
+		return $oxymel->to_string();
+	}
+
+	function nav_menu_terms() {
+		return $this->terms( $this->export->nav_menu_terms() );
+	}
+
+	function custom_taxonomies_terms() {
+		return $this->terms( $this->export->custom_taxonomies_terms() );
+	}
+
+	function rss2_head_action() {
+		ob_start();
+		do_action( 'rss2_head' );
+		$action_output = ob_get_clean();
+		return $action_output;
+	}
+
+	private function terms( $terms ) {
+		$oxymel = new WP_Export_Oxymel;
+		foreach( $terms as $term ) {
+			$term->parent_slug = $term->parent? $terms[$term->parent]->slug : '';
+			$oxymel->tag( 'wp:term' )->contains
+				->tag( 'wp:term_id', $term->term_id )
+				->tag( 'wp:term_taxonomy', $term->taxonomy )
+				->tag( 'wp:term_slug', $term->slug );
+			if ( 'nav_menu' != $term->taxonomy ) {
+				$oxymel
+				->tag( 'wp:term_parent', $term->parent_slug );
+			}
+				$oxymel
+				->optional_cdata( 'wp:term_name', $term->name )
+				->optional_cdata( 'wp:term_description', $term->description )
+				->end;
+		}
+		return $oxymel->to_string();
+	}
+
+	function post( $post ) {
+		$oxymel = new WP_Export_Oxymel;
+		$GLOBALS['wp_query']->in_the_loop = true;
+		$GLOBALS['post'] = $post;
+		setup_postdata( $post );
+
+		$oxymel->item->contains
+			->title( apply_filters( 'the_title_rss', $post->post_title ) )
+			->link( apply_filters('the_permalink_rss', get_permalink() ) )
+			->pubDate( mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ) )
+			->tag( 'dc:creator', get_the_author_meta( 'login' ) )
+			->guid( get_the_guid(), array( 'isPermaLink' => 'false' ) )
+			->description( '' )
+			->tag( 'content:encoded' )->contains->cdata( $post->post_content )->end
+			->tag( 'excerpt:encoded' )->contains->cdata( $post->post_excerpt )->end
+			->tag( 'wp:post_id', $post->ID )
+			->tag( 'wp:post_date', $post->post_date )
+			->tag( 'wp:post_date_gmt', $post->post_date_gmt )
+			->tag( 'wp:comment_status', $post->comment_status )
+			->tag( 'wp:ping_status', $post->ping_status )
+			->tag( 'wp:post_name', $post->post_name )
+			->tag( 'wp:status', $post->post_status )
+			->tag( 'wp:post_parent', $post->post_parent )
+			->tag( 'wp:menu_order', $post->menu_order )
+			->tag( 'wp:post_type', $post->post_type )
+			->tag( 'wp:post_password', $post->post_password )
+			->tag( 'wp:is_sticky', $post->is_sticky )
+			->optional( 'wp:attachment_url', wp_get_attachment_url( $post->ID ) );
+		foreach( $post->terms as $term ) {
+			$oxymel
+			->category( array( 'domain' => $term->taxonomy, 'nicename' => $term->slug  ) )->contains->cdata( $term->name )->end;
+		}
+		foreach( $post->meta as $meta ) {
+			$oxymel
+			->tag( 'wp:postmeta' )->contains
+				->tag( 'wp:meta_key', $meta->meta_key )
+				->tag( 'wp:meta_value' )->contains->cdata( $meta->meta_value )->end
+				->end;
+		}
+		foreach( $post->comments as $comment ) {
+			$oxymel
+			->tag( 'wp:comment' )->contains
+				->tag( 'wp:comment_id', $comment->comment_ID )
+				->tag( 'wp:comment_author' )->contains->cdata( $comment->comment_author )->end
+				->tag( 'wp:comment_author_email', $comment->comment_author_email )
+				->tag( 'wp:comment_author_url', $comment->comment_author_url )
+				->tag( 'wp:comment_author_IP', $comment->comment_author_IP )
+				->tag( 'wp:comment_date', $comment->comment_date )
+				->tag( 'wp:comment_date_gmt', $comment->comment_date_gmt )
+				->tag( 'wp:comment_content' )->contains->cdata( $comment->comment_content )->end
+				->tag( 'wp:comment_approved', $comment->comment_approved )
+				->tag( 'wp:comment_type', $comment->comment_type )
+				->tag( 'wp:comment_parent', $comment->comment_parent )
+				->tag( 'wp:comment_user_id', $comment->user_id )
+				->oxymel( $this->comment_meta( $comment ) )
+				->end;
+		}
+		$oxymel
+			->end;
+		return $oxymel->to_string();
+	}
+
+	private function comment_meta( $comment ) {
+		global $wpdb;
+		$metas = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
+		if ( !$metas ) {
+			return new Oxymel;
+		}
+		$oxymel = new WP_Export_Oxymel;
+		foreach( $metas as $meta ) {
+			$oxymel->tag( 'wp:commentmeta' )->contains
+				->tag( 'wp:meta_key', $meta->meta_key )
+				->tag( 'wp:meta_value', $meta->meta_value )
+			->end;
+		}
+		return $oxymel;
+	}
+
+
+	function footer() {
+		$oxymel = new Oxymel;
+		return $oxymel->close_channel->close_rss->to_string();
+	}
+}
diff --git a/src/wp-includes/export/functions.export.php b/src/wp-includes/export/functions.export.php
new file mode 100644
index 0000000..dd3b177
--- /dev/null
+++ b/src/wp-includes/export/functions.export.php
@@ -0,0 +1,19 @@
+<?php
+
+function wp_export( $args = array() ) {
+	$defaults = array(
+		'filters' => array(),
+		'format' => 'WP_Export_WXR_Formatter',
+		'writer' => 'WP_Export_Returner',
+		'writer_args' => null,
+	);
+	$args = wp_parse_args( $args, $defaults );
+	$export_query = new WP_Export_Query( $args['filters'] );
+	$formatter = new $args['format']( $export_query );
+	$writer = new $args['writer']( $formatter, $args['writer_args'] );
+	try {
+		return $writer->export();
+	} catch ( WP_Export_Exception $e ) {
+		return new WP_Error( 'wp-export-error', $e->getMessage() );
+	}
+}
diff --git a/src/wp-includes/export/writers.php b/src/wp-includes/export/writers.php
new file mode 100644
index 0000000..e0d1594
--- /dev/null
+++ b/src/wp-includes/export/writers.php
@@ -0,0 +1,183 @@
+<?php
+abstract class WP_Export_Base_Writer {
+	protected $formatter;
+
+	function __construct( $formatter ) {
+		$this->formatter = $formatter;
+	}
+
+	public function export() {
+		$this->write( $this->formatter->before_posts() );
+		foreach( $this->formatter->posts() as $post_in_wxr ) {
+			$this->write( $post_in_wxr );
+		}
+		$this->write( $this->formatter->after_posts() );
+	}
+
+	abstract protected function write( $xml );
+}
+
+class WP_Export_XML_Over_HTTP extends WP_Export_Base_Writer {
+	private $file_name;
+
+	function __construct( $formatter, $file_name ) {
+		parent::__construct( $formatter );
+		$this->file_name = $file_name;
+	}
+
+	public function export() {
+		try {
+			$export = $this->get_export();
+			$this->send_headers();
+			echo $export;
+		} catch ( WP_Export_Exception $e ) {
+			$message = apply_filters( 'export_error_message', $e->getMessage() );
+			wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) );
+		} catch ( WP_Export_Term_Exception $e ) {
+			do_action( 'export_term_orphaned', $this->formatter->export->missing_parents );
+			$message = apply_filters( 'export_term_error_message', $e->getMessage() );
+			wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) );
+		}
+	}
+
+	protected function write( $xml ) {
+		$this->result .= $xml;
+	}
+
+	protected function get_export() {
+		$this->result = '';
+		parent::export();
+		return $this->result;
+	}
+
+	protected function send_headers() {
+		header( 'Content-Description: File Transfer' );
+		header( 'Content-Disposition: attachment; filename=' . $this->file_name );
+		header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
+	}
+}
+
+class WP_Export_Returner extends WP_Export_Base_Writer {
+	private $result = '';
+
+	public function export() {
+		$this->private = '';
+		try { 
+			parent::export();
+		} catch ( WP_Export_Exception $e ) {
+			$message = apply_filters( 'export_error_message', $e->getMessage() );
+			return new WP_Error( 'wp-export-error', $message );
+			
+		} catch ( WP_Export_Term_Exception $e ) {
+			do_action( 'export_term_orphaned', $this->formatter->export->missing_parents );
+			$message = apply_filters( 'export_term_error_message', $e->getMessage() );
+			return new WP_Error( 'wp-export-error', $message );
+		}
+		return $this->result;
+	}
+	protected function write( $xml ) {
+		$this->result .= $xml;
+	}
+}
+
+class WP_Export_File_Writer extends WP_Export_Base_Writer {
+	private $f;
+	private $file_name;
+
+	public function __construct( $formatter, $file_name ) {
+		parent::__construct( $formatter );
+		$this->file_name = $file_name;
+	}
+
+	public function export() {
+		$this->f = fopen( $this->file_name, 'w' );
+		if ( !$this->f ) {
+			throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) );
+		}
+
+		try { 
+			parent::export();
+		} catch ( WP_Export_Exception $e ) {
+			throw $e;
+		} catch ( WP_Export_Term_Exception $e ) {
+			throw $e;
+		}
+
+		fclose( $this->f );
+	}
+
+	protected function write( $xml ) {
+		$res = fwrite( $this->f, $xml);
+		if ( false === $res ) {
+			throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) );
+		}
+	}
+}
+
+class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer {
+	private $result = '';
+	private $f;
+	private $next_file_number = 0;
+	private $current_file_size = 0;
+
+	function __construct( $formatter, $writer_args = array() ) {
+		parent::__construct( $formatter );
+		//TODO: check if args are not missing
+		$this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $max_file_size;
+		$this->destination_directory = $writer_args['destination_directory'];
+		$this->filename_template = $writer_args['filename_template'];
+		$this->before_posts_xml = $this->formatter->before_posts();
+		$this->after_posts_xml = $this->formatter->after_posts();
+	}
+
+	public function export() {
+		$this->start_new_file();
+		foreach( $this->formatter->posts() as $post_xml ) {
+			if ( $this->current_file_size + strlen( $post_xml ) > $this->max_file_size ) {
+				$this->start_new_file();
+			}
+			$this->write( $post_xml );
+		}
+		$this->close_current_file();
+	}
+
+	protected function write( $xml ) {
+		$res = fwrite( $this->f, $xml);
+		if ( false === $res ) {
+			throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) );
+		}
+		$this->current_file_size += strlen( $xml );
+	}
+
+	private function start_new_file() {
+		if ( $this->f ) {
+			$this->close_current_file();
+		}
+		$file_path = $this->next_file_path();
+		$this->f = fopen( $file_path, 'w' );
+		if ( !$this->f ) {
+			throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) );
+		}
+		$this->current_file_size = 0;
+		$this->write( $this->before_posts_xml );
+	}
+
+	private function close_current_file() {
+		if ( !$this->f ) {
+			return;
+		}
+		$this->write( $this->after_posts_xml );
+		fclose( $this->f );
+	}
+
+	private function next_file_name() {
+		$next_file_name = sprintf( $this->filename_template, $this->next_file_number );
+		$this->next_file_number++;
+		return $next_file_name;
+	}
+
+	private function next_file_path() {
+		return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name();
+	}
+
+}
diff --git a/src/wp-includes/iterators.php b/src/wp-includes/iterators.php
new file mode 100644
index 0000000..6a4613c
--- /dev/null
+++ b/src/wp-includes/iterators.php
@@ -0,0 +1,80 @@
+<?php
+class WP_Map_Iterator extends IteratorIterator {
+	function __construct( $iterator, $callback ) {
+		$this->callback = $callback;
+		parent::__construct( $iterator );
+	}
+
+	function current() {
+		$original_current = parent::current();
+		return call_user_func( $this->callback, $original_current );
+	}
+}
+
+class WP_Post_IDs_Iterator implements Iterator {
+	private $limit = 100;
+	private $post_ids;
+	private $ids_left;
+	private $results = array();
+
+	public function __construct( $post_ids, $limit = null ) {
+		$this->db = $GLOBALS['wpdb'];
+		$this->post_ids = $post_ids;
+		$this->ids_left = $post_ids;
+		if ( !is_null( $limit ) ) {
+			$this->limit = $limit;
+		}
+	}
+
+	public function current() {
+		return $this->results[$this->index_in_results];
+	}
+
+	public function key() {
+		return $this->global_index;
+	}
+
+	public function next() {
+		$this->index_in_results++;
+		$this->global_index++;
+	}
+
+	public function rewind() {
+		$this->results = array();
+		$this->global_index = 0;
+		$this->index_in_results = 0;
+		$this->ids_left = $this->post_ids;
+	}
+
+	public function valid() {
+		if ( isset( $this->results[$this->index_in_results] ) ) {
+			return true;
+		}
+		if ( empty( $this->ids_left ) ) {
+			return false;
+		}
+		$has_posts = $this->load_next_posts_from_db();
+		if ( !$has_posts ) {
+			return false;
+		}
+		$this->index_in_results = 0;
+		return true;
+	}
+
+	private function load_next_posts_from_db() {
+		$next_batch_post_ids = array_splice( $this->ids_left, 0, $this->limit );
+		$in_post_ids_sql = $this->db->build_IN_condition( 'ID', $next_batch_post_ids );
+		$this->results = $this->db->get_results( "SELECT * FROM {$this->db->posts} WHERE $in_post_ids_sql" );
+		if ( !$this->results ) {
+			if ( $this->db->last_error ) {
+				throw new WP_Iterator_Exception( 'Database error: ' . $this->db->last_error );
+			} else {
+				return false;
+			}
+		}
+		return true;
+	}
+}
+
+class WP_Iterator_Exception extends Exception {
+}
diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php
index 5393240..492a222 100644
--- a/src/wp-includes/wp-db.php
+++ b/src/wp-includes/wp-db.php
@@ -2843,4 +2843,22 @@ class wpdb {
 		}
 		return preg_replace( '/[^0-9.].*/', '', $server_info );
 	}
+
+	/**
+	 * Builds a SQL condition in the form "post_id IN (1, 2, 3, 4)"
+	 *
+	 * @since 3.6.0
+	 *
+	 * @param string $column_name The name of the table column from the IN condition
+	 * @param array $values Array of values in which the column value should be
+	 * @param string $format Optional printf format specifier for the elements of the array. Defaults to %s.
+	 * @return string The IN condition, with escaped values. If there are no values, the return value is an empty string.
+	 */
+	function build_IN_condition( $column_name, $values, $format = '%s' ) {
+		if ( !is_array( $values ) || empty( $values ) ) {
+			return '';
+		}
+		$formats = implode( ', ', array_fill( 0, count( $values ), $format ) );
+		return $this->prepare( "$column_name IN ($formats)", $values );
+	}
 }
diff --git a/src/wp-settings.php b/src/wp-settings.php
index 715a2c2..97c5a94 100644
--- a/src/wp-settings.php
+++ b/src/wp-settings.php
@@ -134,6 +134,11 @@ require( ABSPATH . WPINC . '/category-template.php' );
 require( ABSPATH . WPINC . '/comment.php' );
 require( ABSPATH . WPINC . '/comment-template.php' );
 require( ABSPATH . WPINC . '/rewrite.php' );
+require( ABSPATH . WPINC . '/iterators.php' );
+require( ABSPATH . WPINC . '/export/class-wp-export-query.php' );
+require( ABSPATH . WPINC . '/export/class-wp-export-wxr-formatter.php' );
+require( ABSPATH . WPINC . '/export/writers.php' );
+require( ABSPATH . WPINC . '/export/functions.export.php' );
 require( ABSPATH . WPINC . '/feed.php' );
 require( ABSPATH . WPINC . '/bookmark.php' );
 require( ABSPATH . WPINC . '/bookmark-template.php' );
diff --git a/tests/phpunit/tests/export/class-wp-export-query.php b/tests/phpunit/tests/export/class-wp-export-query.php
new file mode 100644
index 0000000..5be2567
--- /dev/null
+++ b/tests/phpunit/tests/export/class-wp-export-query.php
@@ -0,0 +1,258 @@
+<?php
+
+/**
+ * Test WP_Export_Query class
+ *
+ * @group export
+ * @ticket 22435
+ */
+class Test_WP_Export_Query extends WP_UnitTestCase {
+	function setUp() {
+		if ( ! class_exists( 'WP_Export_Query' ) ) {
+			$this->markTestSkipped( "WP_Export_Query class doesn't exist" );
+		}
+
+		parent::setUp();
+	}
+
+	function test_WP_Export_Query_should_be_initialized_with_an_array() {
+		$export = new WP_Export_Query( array( 'author' => 'all' ) );
+		$this->assertTrue( (bool) $export );
+	}
+
+	function test_WP_Export_Query_should_use_post_ids_if_passed() {
+		$export = new WP_Export_Query( array( 'post_ids' => array( 1, 2, 3 ) ) );
+		$this->assertEquals( array( 1, 2, 3 ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_all_posts_if_all_arg_is_true() {
+		$post_id = $this->factory->post->create();
+		$export = new WP_Export_Query();
+		$this->assertEquals( array( $post_id ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_all_posts_if_no_args_passed() {
+		$post_id = $this->factory->post->create();
+		$export = new WP_Export_Query();
+		$this->assertEquals( array( $post_id ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_not_export_anything_if_post_type_arg_is_set_to_non_existing_post_type() {
+		$post_id = $this->factory->post->create();
+		$export = new WP_Export_Query( array( 'post_type' => 'baba' ) );
+		$this->assertEquals( array(), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_a_certain_post_type_if_the_post_type_arg_is_set() {
+		register_post_type( 'baba' );
+		$post_id = $this->factory->post->create( array( 'post_type' => 'baba' ) );
+		$_       = $this->factory->post->create( array( 'post_type' => 'dyado' ) );
+		$export = new WP_Export_Query( array( 'post_type' => 'baba' ) );
+		$this->assertEquals( array( $post_id ), $export->post_ids() );
+		_unregister_post_type( 'baba' );
+	}
+
+	function test_WP_Export_Query_should_not_export_post_types_with_can_export_set_to_false() {
+		register_post_type( 'non-exportable', array( 'can_export' => false ) );
+		register_post_type( 'exportable', array( 'can_export' => true ) );
+		$non_exportable_post_id = $this->factory->post->create( array( 'post_type' => 'non-exportable' ) );
+		$exportable_post_id = $this->factory->post->create( array( 'post_type' => 'exportable' ) );
+		$export = new WP_Export_Query();
+		$this->assertEquals( array( $exportable_post_id ), $export->post_ids() );
+		_unregister_post_type( 'non-exportable' );
+		_unregister_post_type( 'exportable' );
+	}
+
+	function test_WP_Export_Query_should_not_export_auto_drafts_by_default() {
+		$post_id = $this->factory->post->create( array( 'post_status' => 'auto-draft' ) );
+		$export = new WP_Export_Query();
+		$this->assertEquals( array(), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_status_if_status_arg_is_set() {
+		$post_id_baba = $this->factory->post->create( array( 'post_status' => 'baba' ) );
+		$post_id_dudu = $this->factory->post->create( array( 'post_status' => 'dudu' ) );
+		$export = new WP_Export_Query( array( 'status' => 'baba' ) );
+		$this->assertEquals( array( $post_id_baba ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_author_id_if_status_arg_is_a_number() {
+		$user_id = $this->factory->user->create();
+		$post_by_user = $this->factory->post->create( array( 'post_author' => $user_id ) );
+		$other_post = $this->factory->post->create( array( 'post_author' => $user_id + 1 ) );
+		$export = new WP_Export_Query( array( 'author' => $user_id ) );
+		$this->assertEquals( array( $post_by_user ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_author_name_if_status_arg_is_a_username() {
+		$user = $this->factory->user->create_and_get( array( 'user_login' => 'baba' ) );
+		$post_by_user = $this->factory->post->create( array( 'post_author' => $user->ID ) );
+		$other_post = $this->factory->post->create( array( 'post_author' => $user->ID + 1 ) );
+		$export = new WP_Export_Query( array( 'author' => 'baba' ) );
+		$this->assertEquals( array( $post_by_user ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_author_object_if_author_is_an_object_with_ID_member_variable() {
+		$user = $this->factory->user->create_and_get();
+		$post_by_user = $this->factory->post->create( array( 'post_author' => $user->ID ) );
+		$other_post = $this->factory->post->create( array( 'post_author' => $user->ID + 1 ) );
+		$export = new WP_Export_Query( array( 'author' => $user ) );
+		$this->assertEquals( array( $post_by_user ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_after_certain_start_date_if_start_date_arg_is_passed() {
+		$post_before = $this->factory->post->create( array( 'post_date' => '2012-11-10 23:59:59' ) );
+		$post_after = $this->factory->post->create( array( 'post_date' => '2012-11-11 00:00:00' ) );
+		$export = new WP_Export_Query( array( 'start_date' => '2012-11-11' ) );
+		$this->assertEquals( array( $post_after ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_after_certain_end_date_if_end_date_arg_is_passed() {
+		$post_before = $this->factory->post->create( array( 'post_date' => '2012-11-10 23:59:59' ) );
+		$post_after = $this->factory->post->create( array( 'post_date' => '2012-11-11 00:00:00' ) );
+		$export = new WP_Export_Query( array( 'end_date' => '2012-11-10' ) );
+		$this->assertEquals( array( $post_before ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_category_if_category_arg_is_passed() {
+		$category_id = $this->factory->category->create( array( 'name' => 'baba' ) );
+		$post_with_category = $this->factory->post->create( array( 'post_category' => array( $category_id ) ) );
+		$post_without = $this->factory->post->create();
+		$export = new WP_Export_Query( array( 'post_type' => 'post', 'category' => 'baba' ) );
+		$this->assertEquals( array( $post_with_category ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_only_posts_with_certain_category_id_if_category_arg_is_passed() {
+		$category_id = $this->factory->category->create( array( 'name' => 'baba' ) );
+		$post_with_category = $this->factory->post->create( array( 'post_category' => array( $category_id ) ) );
+		$post_without = $this->factory->post->create();
+		$export = new WP_Export_Query( array( 'post_type' => 'post', 'category' => $category_id ) );
+		$this->assertEquals( array( $post_with_category ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_filter_posts_by_category_only_for_post_post_type() {
+		$category_id = $this->factory->category->create( array( 'name' => 'baba' ) );
+		$post_with_category = $this->factory->post->create( array( 'post_category' => array( $category_id ) ) );
+		$post_without = $this->factory->post->create();
+		$different_post_type = $this->factory->post->create( array( 'post_type' => 'page' ) );
+		$export = new WP_Export_Query( array( 'category' => $category_id ) );
+		$this->assertEqualSets( array( $post_with_category, $post_without, $different_post_type ), $export->post_ids() );
+	}
+
+	function test_WP_Export_Query_should_include_attachments_of_posts_if_we_are_filtering_only_some_post_types() {
+		register_post_type( 'baba' );
+		$post_id = $this->factory->post->create( array( 'post_type' => 'baba' ) );
+		$attachment_post_id = $this->factory->post->create( array( 'post_type' => 'attachment', 'post_parent' => $post_id ) );
+		$export = new WP_Export_Query( array( 'post_type' => 'baba' ) );
+		$this->assertEquals( array( $post_id, $attachment_post_id ), $export->post_ids() );
+		_unregister_post_type( 'baba' );
+	}
+
+	function test_authors_should_return_list_of_users_for_each_post_author() {
+		$user_id = $this->factory->user->create();
+		$this->factory->post->create( array( 'post_author' => $user_id ) );
+		$export = new WP_Export_Query();
+		$authors = $export->authors();
+		$this->assertEquals( 1, count( $authors ) );
+		$this->assertEquals( $user_id, $authors[0]->ID );
+	}
+
+	function test_authors_should_skip_non_existing_authors() {
+		$this->factory->post->create( array( 'post_author' => 11 ) );
+		$export = new WP_Export_Query();
+		$this->assertEquals( array(), $export->authors() );
+	}
+
+	function test_authors_should_skip_auto_draft_authors() {
+		$user_id = $this->factory->user->create();
+		$this->factory->post->create( array( 'post_author' => $user_id, 'post_status' => 'auto-draft' ) );
+		$export = new WP_Export_Query();
+		$this->assertEquals( array(), $export->authors() );
+	}
+
+	function test_categories_should_return_only_the_category_we_are_filtering_on() {
+		$category_id = $this->factory->category->create( array( 'name' => 'baba' ) );
+		$other_category_id = $this->factory->category->create( array( 'name' => 'dyado' ) );
+		$export = new WP_Export_Query( array( 'post_type' => 'post', 'category' => $category_id ) );
+		$categories = $export->categories();
+		$this->assertTrue( is_array( $categories ) );
+		$this->assertEquals( 1, count( $categories ) );
+	}
+
+	function test_categories_should_return_no_categories_if_we_are_requesting_only_one_post_type() {
+		$category_id = $this->factory->category->create();
+		$export = new WP_Export_Query( array( 'post_type' => 'post' ) );
+		$this->assertEquals( array(), $export->categories() );
+	}
+
+	function test_categories_should_return_all_categories_if_we_are_requesting_all_post_types() {
+		$category_id = $this->factory->category->create();
+		$another_category_id = $this->factory->category->create();
+		$export = new WP_Export_Query();
+		$this->assertEqualSets( array( 1, $category_id, $another_category_id ), self::get_term_ids( $export->categories() ) );
+	}
+
+	function test_categories_should_not_return_a_child_before_its_parent_category() {
+		$child_category_id = $this->factory->category->create();
+		$top_category_id = $this->factory->category->create();
+		wp_update_term( $child_category_id, 'category', array( 'parent' => $top_category_id ) );
+		$export = new WP_Export_Query();
+		$this->assertNoChildBeforeParent( $export->categories() );
+	}
+
+	function test_tags_should_return_all_tags() {
+		$tag_id = $this->factory->tag->create();
+		$export = new WP_Export_Query();
+		$this->assertEquals( array( $tag_id ), self::get_term_ids( $export->tags() ) );
+	}
+
+	function test_tags_should_return_no_tags_if_we_are_requesting_only_one_post_type() {
+		$category_id = $this->factory->tag->create();
+		$export = new WP_Export_Query( array( 'post_type' => 'post' ) );
+		$this->assertEquals( array(), $export->tags() );
+	}
+
+	function test_custom_taxonomies_terms_should_return_all_terms() {
+		register_taxonomy( 'taxonomy_all', 'post' );
+		$term_id = $this->factory->term->create( array( 'taxonomy' => 'taxonomy_all' ) );
+		$export = new WP_Export_Query();
+		$this->assertEquals( array( $term_id ), self::get_term_ids( $export->custom_taxonomies_terms() ) );
+		_unregister_taxonomy( 'taxonomy_all' );
+	}
+
+	function test_custom_taxonomes_terms_should_return_no_terms_if_we_are_requesting_only_one_post_type() {
+		register_taxonomy( 'taxonomy_one_post_type', 'post' );
+		$term_id = $this->factory->term->create( array( 'taxonomy' => 'taxonomy_one_post_type' ) );
+		$export = new WP_Export_Query( array( 'post_type' => 'post' ) );
+		$this->assertEquals( array(), $export->custom_taxonomies_terms() );
+		_unregister_taxonomy( 'taxonomy_one_post_type' );
+	}
+
+	function test_custom_taxonomies_terms_should_not_return_a_child_before_its_parent_term() {
+		register_taxonomy( 'heir', 'post', array( 'hierarchical' => true ) );
+		$child_term_id = $this->factory->term->create( array( 'taxonomy' => 'heir' ) );
+		$top_term_id = $this->factory->term->create( array( 'taxonomy' => 'heir' ) );
+		wp_update_term( $child_term_id, 'heir', array( 'parent' => $top_term_id ) );
+		$export = new WP_Export_Query();
+		$this->assertNoChildBeforeParent( $export->custom_taxonomies_terms() );
+		_unregister_taxonomy( 'heir' );
+	}
+
+	private function assertNoChildBeforeParent( $terms ) {
+		$visited = array();
+		foreach( $terms as $term ) {
+			$this->assertTrue( isset( $visited[$term->parent] ) || !$term->parent );
+			$visited[$term->term_id] = true;
+		}
+	}
+
+	private static function get_term_ids( $terms ) {
+		return array_values( array_map( array( __CLASS__, '_get_term_ids_cb' ), $terms ) );
+	}
+
+	private static function _get_term_ids_cb( $c ) {
+		return intval( $c->term_id );
+	}
+
+}
+
diff --git a/tests/phpunit/tests/export/functions.export.php b/tests/phpunit/tests/export/functions.export.php
new file mode 100644
index 0000000..e3b77e7
--- /dev/null
+++ b/tests/phpunit/tests/export/functions.export.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Test export functions
+ *
+ * @group export
+ * @ticket 22435
+ */
+class Test_WP_Export_Functions extends WP_UnitTestCase {
+	function setUp() {
+		if ( ! function_exists( 'wp_export' ) ) {
+			$this->markTestSkipped( "wp_export function doesn't exist" );
+		}
+
+		parent::setUp();
+	}
+	
+	function test_wp_export_returns_wp_error_if_the_writer_throws_Export_exception() {
+		$this->assertTrue( is_wp_error( wp_export( array( 'writer' => 'Test_WP_Export_Stub_Writer_Throws_Export_Exception' ) ) ) );
+	}
+
+	function test_wp_export_passes_the_exception_if_the_writer_throws_other_exception() {
+		$this->setExpectedException( 'Exception' );
+		wp_export( array( 'writer' => 'Test_WP_Export_Stub_Writer_Throws_Other_Exception' ) );
+	}
+
+}
+
+class Test_WP_Export_Stub_Writer_Throws_Export_Exception {
+	function __construct( $formatter ) {
+	}
+	function export() {
+		throw new WP_Export_Exception( 'baba' );
+	}
+}
+
+class Test_WP_Export_Stub_Writer_Throws_Other_Exception {
+	function __construct( $formatter ) {
+	}
+	function export() {
+		throw new Exception( 'baba' );
+	}
+}
diff --git a/tests/phpunit/tests/export/writers.php b/tests/phpunit/tests/export/writers.php
new file mode 100644
index 0000000..6715d17
--- /dev/null
+++ b/tests/phpunit/tests/export/writers.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Test WP_Export_*_Writer classes
+ *
+ * @group export
+ * @ticket 22435
+ */
+class Test_WP_Export_Writers extends WP_UnitTestCase {
+	function test_export_returner_returns_all_the_return_values() {
+		if ( ! class_exists( 'WP_Export_Returner' ) ) {
+			$this->markTestSkipped( "WP_Export_Returner class doesn't exist" );
+		}
+		$returner = new WP_Export_Returner( $this->get_x_formatter() );
+		$this->assertEquals( 'xxx' , $returner->export() );
+	}
+
+	private function get_x_formatter() {
+		$methods = array( 'before_posts', 'posts', 'after_posts' );
+		$formatter = $this->getMock( 'WP_Export_WXR_Formatter', $methods, array( null ) );
+		foreach( $methods as $method ) {
+			$return = 'posts' == $method? array( 'x' ) : 'x';
+			$formatter->expects( $this->once() )->method( $method )->with()->will( $this->returnValue( $return ) );
+		}
+		return $formatter;
+	}
+}
+
diff --git a/tests/phpunit/tests/iterators.php b/tests/phpunit/tests/iterators.php
new file mode 100644
index 0000000..bd5f0d7
--- /dev/null
+++ b/tests/phpunit/tests/iterators.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @ticket 22435
+ */
+class Test_WP_Post_IDs_Iterator extends WP_UnitTestCase {
+	function setUp() {
+		if ( ! class_exists( 'WP_Post_IDs_Iterator' ) ) {
+			$this->markTestSkipped( "WP_Post_IDs_Iterator class doesn't exist" );
+		}
+
+		parent::setUp();
+	}
+
+	function test_create() {
+		new WP_Post_IDs_Iterator( array( 1, 2, 3 ) );
+	}
+
+	function test_no_posts() {
+		$this->assertIteratorReturnsSamePostIDs( array() );
+	}
+
+	function test_less_ids_than_limit() {
+		$post_id_0 = $this->factory->post->create();
+		$post_id_1 = $this->factory->post->create();
+		$this->assertIteratorReturnsSamePostIDs( array( $post_id_0, $post_id_1 ), 10 );
+	}
+
+	function test_ids_exactly_as_limit() {
+		$post_id_0 = $this->factory->post->create();
+		$post_id_1 = $this->factory->post->create();
+		$this->assertIteratorReturnsSamePostIDs( array( $post_id_0, $post_id_1 ), 2 );
+	}
+
+	function test_more_ids_than_limit() {
+		$post_id_0 = $this->factory->post->create();
+		$post_id_1 = $this->factory->post->create();
+		$post_id_2 = $this->factory->post->create();
+		$this->assertIteratorReturnsSamePostIDs( array( $post_id_0, $post_id_1, $post_id_2 ), 2 );
+	}
+
+	function test_ids_exactly_twice_more_than_limit() {
+		$post_id_0 = $this->factory->post->create();
+		$post_id_1 = $this->factory->post->create();
+		$post_id_2 = $this->factory->post->create();
+		$post_id_3 = $this->factory->post->create();
+		$this->assertIteratorReturnsSamePostIDs( array( $post_id_0, $post_id_1, $post_id_2, $post_id_3 ), 2 );
+	}
+
+	private function assertIteratorReturnsSamePostIDs( $post_ids, $limit = 2 ) {
+		$this->assertEquals( $post_ids, wp_list_pluck( iterator_to_array( new WP_Post_IDs_Iterator( $post_ids, $limit ) ), 'ID' ) );
+	}
+}
