Make WordPress Core

Ticket #22435: export-api.diff

File export-api.diff, 36.2 KB (added by nbachiyski, 12 years ago)
  • wp-includes/Oxymel.php

     
     1<?php
     2class Oxymel {
     3        private $xml;
     4        private $dom;
     5        private $current_element;
     6        private $last_inserted;
     7        private $go_deep_on_next_element = 0;
     8        private $go_up_on_next_element = 0;
     9        private $nesting_level = 0;
     10        private $contains_nesting_level = 0;
     11        private $indentation= '  ';
     12
     13        public function __construct() {
     14                $this->xml = '';
     15                $this->init_new_dom();
     16        }
     17
     18        public function to_string() {
     19                return $this->xml .= $this->indent( $this->xml_from_dom(), $this->nesting_level );
     20        }
     21
     22        public function __call( $name, $args ) {
     23                array_unshift( $args, $name );
     24                return call_user_func_array( array( $this, 'tag' ), $args );
     25        }
     26
     27        public function __get( $name ) {
     28                return $this->$name();
     29        }
     30
     31        public function contains() {
     32                $this->contains_nesting_level++;
     33                $this->nesting_level++;
     34                if ( $this->go_deep_on_next_element ) {
     35                        throw new OxymelException( 'contains cannot be used consecutively more than once' );
     36                }
     37                $this->go_deep_on_next_element++;
     38                return $this;
     39        }
     40
     41        public function end() {
     42                $this->contains_nesting_level--;
     43                $this->nesting_level--;
     44                if ( $this->contains_nesting_level < 0 ) {
     45                        throw new OxymelException( 'end is used without a matching contains' );
     46                }
     47                $this->go_up_on_next_element++;
     48                return $this;
     49        }
     50
     51        public function tag( $name, $content_or_attributes = null, $attributes = array() ) {
     52                list( $content, $attributes ) = $this->get_content_and_attributes_from_tag_args( $content_or_attributes, $attributes );
     53                $is_opening =  0 === strpos( $name, 'open_' );
     54                $is_closing =  0 === strpos( $name, 'close_' );
     55                $name = preg_replace("/^(open|close)_/", '', $name );
     56
     57                $element = $this->create_element( $name, $content, $attributes );
     58
     59                if ( !$is_opening && !$is_closing )
     60                        $this->add_element_to_dom( $element );
     61                elseif ( $is_opening )
     62                        $this->add_opening_tag_from_element( $element );
     63                elseif ( $is_closing )
     64                        $this->add_closing_tag_from_tag_name( $name );
     65
     66                return $this;
     67        }
     68
     69        public function cdata( $text ) {
     70                $this->add_element_to_dom( $this->dom->createCDATASection( $text ) );
     71                return $this;
     72        }
     73
     74        public function text( $text ) {
     75                $this->add_element_to_dom( $this->dom->createTextNode( $text ) );
     76                return $this;
     77        }
     78
     79        public function comment( $text ) {
     80                $this->add_element_to_dom( $this->dom->createComment( $text ) );
     81                return $this;
     82        }
     83
     84        public function xml() {
     85                $this->add_element_to_dom( $this->dom->createProcessingInstruction( 'xml', 'version="1.0" encoding="UTF-8"' ) );
     86                return $this;
     87        }
     88
     89        public function oxymel( Oxymel $other ) {
     90                foreach( $other->dom->childNodes as $child ) {
     91                        $child = $this->dom->importNode( $child, true );
     92                        $this->add_element_to_dom( $child );
     93                }
     94                return $this;
     95        }
     96
     97        public function raw(  $raw_xml ) {
     98                if ( !$raw_xml ) {
     99                        return $this;
     100                }
     101                $fragment = $this->dom->createDocumentFragment();
     102                $fragment->appendXML($raw_xml);
     103                $this->add_element_to_dom( $fragment );
     104                return $this;
     105        }
     106
     107        private function add_element_to_dom( $element ) {
     108                $this->move_current_element_deep();
     109                $this->move_current_element_up();
     110                $this->last_inserted = $this->current_element->appendChild($element);
     111        }
     112
     113        private function move_current_element_deep() {
     114                if ( $this->go_deep_on_next_element ) {
     115                        if ( !$this->last_inserted ) {
     116                                throw new OxymelException( 'contains has been used before adding any tags' );
     117                        }
     118                        $this->current_element = $this->last_inserted;
     119                        $this->go_deep_on_next_element--;
     120                }
     121        }
     122
     123        private function move_current_element_up() {
     124                if ( $this->go_up_on_next_element ) {
     125                        while ( $this->go_up_on_next_element ) {
     126                                $this->current_element = $this->current_element->parentNode;
     127                                $this->go_up_on_next_element--;
     128                        }
     129                }
     130        }
     131
     132        private function get_content_and_attributes_from_tag_args( $content_or_attributes, array $attributes ) {
     133                $content = null;
     134                if ( !$attributes ) {
     135                        if ( is_array( $content_or_attributes ) )
     136                                $attributes = $content_or_attributes;
     137                        else
     138                                $content = $content_or_attributes;
     139                } else {
     140                        $content = $content_or_attributes;
     141                }
     142                return array( $content, $attributes );
     143        }
     144
     145        private function init_new_dom() {
     146                unset( $this->dom, $this->current_element );
     147                $this->dom = new DOMDocument();
     148                $this->dom->formatOutput = true;
     149                $this->current_element = $this->dom;
     150                $this->last_inserted = null;
     151        }
     152
     153        private function xml_from_dom() {
     154                if ( 0 !== $this->contains_nesting_level ) {
     155                        throw new OxymelException( 'contains and end calls do not match' );
     156                }
     157                $xml = '';
     158                foreach( $this->dom->childNodes as $child ) {
     159                        $xml .= $this->dom->saveXML( $child ) . "\n";
     160                }
     161                return $xml;
     162        }
     163
     164        private function create_element( $name, $content, $attributes ) {
     165                if ( !is_null( $content ) )
     166                        $element = $this->dom->createElement( $name, $content );
     167                else
     168                        $element = $this->dom->createElement( $name );
     169
     170                foreach( $attributes as $attribute_name => $attribute_value ) {
     171                        $element->setAttribute( $attribute_name, $attribute_value );
     172                }
     173
     174                return $element;
     175        }
     176
     177        private function add_opening_tag_from_element( $element ) {
     178                $this->xml .= $this->indent( $this->xml_from_dom(), $this->nesting_level );
     179                $tag = $this->dom->saveXML($element);
     180                $this->xml .= $this->indent( str_replace( '/>', '>', $tag ) . "\n", $this->nesting_level );
     181                $this->nesting_level++;
     182                $this->init_new_dom();
     183        }
     184
     185        private function add_closing_tag_from_tag_name( $name ) {
     186                $this->xml .= $this->xml_from_dom();
     187                $this->nesting_level--;
     188                if ( $this->nesting_level < 0 ) {
     189                        $this->xml = $this->indent( $this->xml, -$this->nesting_level );
     190                        $this->nesting_level = 0;
     191                }
     192                $this->xml .= $this->indent( "</$name>\n", $this->nesting_level );
     193                $this->init_new_dom();
     194        }
     195
     196        private function indent( $string, $level ) {
     197                if ( !$level ) {
     198                        return $string;
     199                }
     200                $lines = explode( "\n", $string );
     201                foreach( $lines as &$line ) {
     202                        if ( !trim( $line ) )
     203                                continue;
     204                        $line = str_repeat( $this->indentation, $level ) . $line;
     205                }
     206                return implode( "\n", $lines );
     207        }
     208}
     209
     210class OxymelException extends Exception {
     211}
  • wp-includes/default-constants.php

    Property changes on: wp-includes/Oxymel.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    8080        define( 'DAY_IN_SECONDS',    24 * HOUR_IN_SECONDS   );
    8181        define( 'WEEK_IN_SECONDS',    7 * DAY_IN_SECONDS    );
    8282        define( 'YEAR_IN_SECONDS',  365 * DAY_IN_SECONDS    );
     83
     84        // Constants for expressing human-readable data sizes
     85        // in their respective number of bytes.
     86        define( 'KB_IN_BYTES', 1024 );
     87        define( 'MB_IN_BYTES', 1024 * KB_IN_BYTES );
     88        define( 'GB_IN_BYTES', 1024 * MB_IN_BYTES );
     89        define( 'TB_IN_BYTES', 1024 * GB_IN_BYTES );
     90        define( 'PB_IN_BYTES', 1024 * TB_IN_BYTES );
     91        define( 'EB_IN_BYTES', 1024 * PB_IN_BYTES );
     92        define( 'ZB_IN_BYTES', 1024 * EB_IN_BYTES );
     93        define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES );
    8394}
    8495
    8596/**
  • wp-includes/export/class-wp-export-query.php

     
     1<?php
     2/**
     3 * Represents a set of posts and other site data to be exported.
     4 *
     5 * An immutable object, which gathers all data needed for the export.
     6 */
     7class WP_Export_Query {
     8        const QUERY_CHUNK = 100;
     9
     10        private static $defaults = array(
     11                'post_ids' => null,
     12                'post_type' => null,
     13                'status' => null,
     14                'author' => null,
     15                'start_date' => null,
     16                'end_date' => null,
     17                'category' => null,
     18        );
     19
     20        private $post_ids;
     21        private $filters;
     22        private $xml_gen;
     23
     24        private $wheres = array();
     25        private $joins = array();
     26
     27        private $author;
     28        private $category;
     29
     30        public function __construct( $filters = array() ) {
     31                $this->filters = wp_parse_args( $filters, self::$defaults );
     32                $this->post_ids = $this->calculate_post_ids();
     33        }
     34
     35        public function post_ids() {
     36                return $this->post_ids;
     37        }
     38
     39        public function charset() {
     40                return get_bloginfo( 'charset' );
     41        }
     42
     43        public function site_metadata() {
     44                $metadata = array(
     45                        'name' => $this->bloginfo_rss( 'name' ),
     46                        'url' => $this->bloginfo_rss( 'url' ),
     47                        'language' => $this->bloginfo_rss( 'language' ),
     48                        'description' => $this->bloginfo_rss( 'description' ),
     49                        'pubDate' => date( 'D, d M Y H:i:s +0000' ),
     50                        'site_url' => is_multisite()? network_home_url() : $this->bloginfo_rss( 'url' ),
     51                        'blog_url' => $this->bloginfo_rss( 'url' ),
     52                );
     53                return $metadata;
     54        }
     55
     56        public function wp_generator_tag() {
     57                return apply_filters( 'the_generator', get_the_generator( 'export' ), 'export' );
     58        }
     59
     60        public function authors() {
     61                global $wpdb;
     62                $authors = array();
     63                $author_ids = $wpdb->get_col( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" );
     64                foreach ( (array) $author_ids as $author_id ) {
     65                        $authors[] = get_userdata( $author_id );
     66                }
     67                $authors = array_filter( $authors );
     68                return $authors;
     69        }
     70
     71        public function categories() {
     72                if ( $this->category ) {
     73                        return $this->category;
     74                }
     75                if ( $this->filters['post_type'] ) {
     76                        return array();
     77                }
     78                $categories = (array) get_categories( array( 'get' => 'all' ) );
     79                $categories = self::topologically_sort_terms( $categories );
     80                return $categories;
     81        }
     82
     83        public function tags() {
     84                if ( $this->filters['post_type'] ) {
     85                        return array();
     86                }
     87                $tags = (array) get_tags( array( 'get' => 'all' ) );
     88                return $tags;
     89        }
     90
     91        public function custom_taxonomies_terms() {
     92                if ( $this->filters['post_type'] ) {
     93                        return array();
     94                }
     95                $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) );
     96                $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) );
     97                $custom_terms = self::topologically_sort_terms( $custom_terms );
     98                return $custom_terms;
     99        }
     100
     101        public function nav_menu_terms() {
     102                $nav_menus = wp_get_nav_menus();
     103                foreach( $nav_menus as &$term ) {
     104                        $term->description = '';
     105                }
     106                return $nav_menus;
     107        }
     108
     109        public function exportify_post( $post ) {
     110                $GLOBALS['wp_query']->in_the_loop = true;
     111                $previous_global_post = isset( $GLOBALS['post'] )? $GLOBALS['post'] : null;
     112                $GLOBALS['post'] = $post;
     113                setup_postdata( $post );
     114                $post->post_content = apply_filters( 'the_content_export', $post->post_content );
     115                $post->post_excerpt = apply_filters( 'the_excerpt_export', $post->post_excerpt );
     116                $post->is_sticky = is_sticky( $post->ID ) ? 1 : 0;
     117                $post->terms = self::get_terms_for_post( $post );
     118                $post->meta = self::get_meta_for_post( $post );
     119                $post->comments = self::get_comments_for_post( $post );
     120                $GLOBALS['post'] = $previous_global_post;
     121                return $post;
     122        }
     123
     124        public function posts() {
     125                $posts_iterator = new WP_Post_IDs_Iterator( $this->post_ids, self::QUERY_CHUNK );
     126                return new WP_Map_Iterator( $posts_iterator, array( $this, 'exportify_post' ) );
     127        }
     128
     129        private function calculate_post_ids() {
     130                global $wpdb;
     131                if ( is_array( $this->filters['post_ids'] ) ) {
     132                        return $this->filters['post_ids'];
     133                }
     134                $this->post_type_where();
     135                $this->status_where();
     136                $this->author_where();
     137                $this->start_date_where();
     138                $this->end_date_where();
     139                $this->category_where();
     140
     141                $where = implode( ' AND ', array_filter( $this->wheres ) );
     142                if ( $where ) $where = "WHERE $where";
     143                $join = implode( ' ', array_filter( $this->joins ) );
     144
     145                $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where" );
     146                $post_ids = array_merge( $post_ids, $this->attachments_for_specific_post_types( $post_ids ) );
     147                return $post_ids;
     148        }
     149
     150        private function post_type_where() {
     151                global $wpdb;
     152                $post_types_filters = array( 'can_export' => true );
     153                if ( $this->filters['post_type'] ) {
     154                        $post_types_filters = array_merge( $post_types_filters, array( 'name' => $this->filters['post_type'] ) );
     155                }
     156                $post_types = get_post_types( $post_types_filters );
     157                if ( !$post_types ) {
     158                        $this->wheres[] = 'p.post_type IS NULL';
     159                        return;
     160                }
     161                $this->wheres[] = $wpdb->build_IN_condition( 'p.post_type', $post_types );
     162        }
     163
     164        private function status_where() {
     165                global $wpdb;
     166                if ( !$this->filters['status'] ) {
     167                        $this->wheres[] = "p.post_status != 'auto-draft'";
     168                        return;
     169                }
     170                $this->wheres[] = $wpdb->prepare( 'p.post_status = %s', $this->filters['status'] );
     171        }
     172
     173        private function author_where() {
     174                global $wpdb;
     175                $user = $this->find_user_from_any_object( $this->filters['author'] );
     176                if ( !$user || is_wp_error( $user ) ) {
     177                        return;
     178                }
     179                $this->author = $user;
     180                $this->wheres[] = $wpdb->prepare( 'p.post_author = %d', $user->ID );
     181        }
     182
     183        private function start_date_where() {
     184                global $wpdb;
     185                $timestamp = strtotime( $this->filters['start_date'] );
     186                if ( !$timestamp ) {
     187                        return;
     188                }
     189                $this->wheres[] = $wpdb->prepare( 'p.post_date >= %s', date( 'Y-m-d 00:00:00', $timestamp ) );
     190        }
     191
     192        private function end_date_where() {
     193                global $wpdb;
     194                $timestamp = strtotime( $this->filters['end_date'] );
     195                if ( !$timestamp ) {
     196                        return;
     197                }
     198                $this->wheres[] = $wpdb->prepare( 'p.post_date <= %s', date( 'Y-m-d 23:59:59', $timestamp ) );
     199        }
     200
     201        private function category_where() {
     202                global $wpdb;
     203                if ( 'post' != $this->filters['post_type'] ) {
     204                        return;
     205                }
     206                $category = $this->find_category_from_any_object( $this->filters['category'] );
     207                if ( !$category ) {
     208                        return;
     209                }
     210                $this->category = $category;
     211                $this->joins[] = "INNER JOIN {$wpdb->term_relationships} AS tr ON (p.ID = tr.object_id)";
     212                $this->wheres[] = $wpdb->prepare( 'tr.term_taxonomy_id = %d', $category->term_taxonomy_id );
     213        }
     214
     215        private function attachments_for_specific_post_types( $post_ids ) {
     216                global $wpdb;
     217                if ( !$this->filters['post_type'] ) {
     218                        return array();
     219                }
     220                $attachment_ids = array();
     221                while ( $batch_of_post_ids = array_splice( $post_ids, 0, self::QUERY_CHUNK ) ) {
     222                        $post_parent_condition = $wpdb->build_IN_condition( 'post_parent', $batch_of_post_ids );
     223                        $attachment_ids = array_merge( $attachment_ids, (array)$wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND $post_parent_condition" ) );
     224                }
     225                return array_map( 'intval', $attachment_ids );
     226        }
     227
     228        private function bloginfo_rss( $section ) {
     229                return apply_filters( 'bloginfo_rss', get_bloginfo_rss( $section ), $section );
     230        }
     231
     232        private function find_user_from_any_object( $user ) {
     233                if ( is_numeric( $user ) ) {
     234                        return get_user_by( 'id', $user );
     235                } elseif ( is_string( $user ) ) {
     236                        return get_user_by( 'login', $user );
     237                } elseif ( isset( $user->ID ) ) {
     238                        return get_user_by( 'id', $user->ID );
     239                }
     240                return false;
     241        }
     242
     243        private function find_category_from_any_object( $category ) {
     244                if ( is_numeric( $category ) ) {
     245                        return get_term( $category, 'category' );
     246                } elseif ( is_string( $category ) ) {
     247                        $term = term_exists( $category, 'category' );
     248                        return isset( $term['term_id'] )? get_term( $term['term_id'], 'category' ) : false;
     249                } elseif ( isset( $category->term_id ) ) {
     250                        return get_term( $category->term_id, 'category' );
     251                }
     252                return false;
     253        }
     254
     255        private static function topologically_sort_terms( $terms ) {
     256                $sorted = array();
     257                while ( $term = array_shift( $terms ) ) {
     258                        if ( $term->parent == 0 || isset( $sorted[$term->parent] ) )
     259                                $sorted[$term->term_id] = $term;
     260                        else
     261                                $terms[] = $term;
     262                }
     263                return $sorted;
     264        }
     265
     266        private static function get_terms_for_post( $post ) {
     267                $taxonomies = get_object_taxonomies( $post->post_type );
     268                if ( empty( $taxonomies ) )
     269                        return array();
     270                $terms = wp_get_object_terms( $post->ID, $taxonomies );
     271                $terms = $terms? $terms : array();
     272                return $terms;
     273        }
     274
     275        private static function get_meta_for_post( $post ) {
     276                global $wpdb;
     277                $meta_for_export = array();
     278                $meta_from_db = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
     279                foreach ( $meta_from_db as $meta ) {
     280                        if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) )
     281                                continue;
     282                        $meta_for_export[] = $meta;
     283                }
     284                return $meta_for_export;
     285        }
     286
     287        private static function get_comments_for_post( $post ) {
     288                global $wpdb;
     289                $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );
     290                foreach( $comments as $comment ) {
     291                        $meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
     292                        $meta = $meta? $meta : array();
     293                        $comment->meta = $meta;
     294                }
     295                return $comments;
     296        }
     297}
     298
     299class WP_Export_Exception extends RuntimeException {
     300}
  • wp-includes/export/class-wp-export-wxr-formatter.php

    Property changes on: wp-includes/export/class-wp-export-query.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Version number for the export format.
     4 *
     5 * Bump this when something changes that might affect compatibility.
     6 *
     7 * @since 2.5.0
     8 */
     9define( 'WXR_VERSION', '1.2' );
     10
     11require_once ABSPATH . WPINC . '/Oxymel.php';
     12
     13class WP_Export_Oxymel extends Oxymel {
     14        public function optional( $tag_name, $contents ) {
     15                if ( $contents ) {
     16                        $this->$tag_name( $contents );
     17                }
     18                return $this;
     19        }
     20
     21        public function optional_cdata( $tag_name, $contents ) {
     22                if ( $contents ) {
     23                        $this->$tag_name->contains->cdata( $contents )->end;
     24                }
     25                return $this;
     26        }
     27}
     28
     29/**
     30 * Responsible for formatting the data in WP_Export_Query to WXR
     31 */
     32class WP_Export_WXR_Formatter {
     33        function __construct( $export ) {
     34                $this->export = $export;
     35                $this->wxr_version = WXR_VERSION;
     36        }
     37
     38        function before_posts() {
     39                $before_posts_xml = '';
     40                $before_posts_xml .= $this->header();
     41                $before_posts_xml .= $this->site_metadata();
     42                $before_posts_xml .= $this->authors();
     43                $before_posts_xml .= $this->categories();
     44                $before_posts_xml .= $this->tags();
     45                $before_posts_xml .= $this->nav_menu_terms();
     46                $before_posts_xml .= $this->custom_taxonomies_terms();
     47                $before_posts_xml .= $this->rss2_head_action();
     48                return $before_posts_xml;
     49        }
     50
     51        function posts() {
     52                return new WP_Map_Iterator( $this->export->posts(), array( $this, 'post' ) );
     53        }
     54
     55        function after_posts() {
     56                return $this->footer();
     57        }
     58
     59        function header() {
     60                $oxymel = new Oxymel;
     61                $charset = $this->export->charset();
     62                $wp_generator_tag = $this->export->wp_generator_tag();
     63                $comment = <<<COMMENT
     64
     65 This is a WordPress eXtended RSS file generated by WordPress as an export of your site.
     66 It contains information about your site's posts, pages, comments, categories, and other content.
     67 You may use this file to transfer that content from one site to another.
     68 This file is not intended to serve as a complete backup of your site.
     69
     70 To import this information into a WordPress site follow these steps:
     71 1. Log in to that site as an administrator.
     72 2. Go to Tools: Import in the WordPress admin panel.
     73 3. Install the "WordPress" importer from the list.
     74 4. Activate & Run Importer.
     75 5. Upload this file using the form provided on that page.
     76 6. You will first be asked to map the authors in this export file to users
     77    on the site. For each author, you may choose to map to an
     78    existing user on the site or to create a new user.
     79 7. WordPress will then import each of the posts, pages, comments, categories, etc.
     80    contained in this file into your site.
     81
     82COMMENT;
     83                return $oxymel
     84                        ->xml
     85                        ->comment( $comment )
     86                        ->raw( $wp_generator_tag )
     87                        ->open_rss( array(
     88                                'version' => '2.0',
     89                                'xmlns:excerpt' => "http://wordpress.org/export/{$this->wxr_version}/excerpt/",
     90                                'xmlns:content' => "http://purl.org/rss/1.0/modules/content/",
     91                                'xmlns:wfw' => "http://wellformedweb.org/CommentAPI/",
     92                                'xmlns:dc' => "http://purl.org/dc/elements/1.1/",
     93                                'xmlns:wp' => "http://wordpress.org/export/{$this->wxr_version}/",
     94                        ) )
     95                                ->open_channel
     96                                ->to_string();
     97
     98        }
     99
     100        function site_metadata() {
     101                $oxymel = new Oxymel;
     102                $metadata = $this->export->site_metadata();
     103                return $oxymel
     104                        ->title( $metadata['name'] )
     105                        ->link( $metadata['url'] )
     106                        ->description( $metadata['description'] )
     107                        ->pubDate( $metadata['pubDate'] )
     108                        ->language( $metadata['language'] )
     109                        ->tag( 'wp:wxr_version', $this->wxr_version )
     110                        ->tag( 'wp:base_site_url', $metadata['site_url'] )
     111                        ->tag( 'wp:base_blog_url', $metadata['blog_url'] )
     112                        ->to_string();
     113        }
     114
     115        function authors() {
     116                $oxymel = new Oxymel;
     117                $authors = $this->export->authors();
     118                foreach ( $authors as $author ) {
     119                        $oxymel
     120                                ->tag( 'wp:wp_author' )->contains
     121                                        ->tag( 'wp:author_login', $author->user_login )
     122                                        ->tag( 'wp:author_email', $author->user_email )
     123                                        ->tag( 'wp:author_display_name' )->contains->cdata( $author->display_name )->end
     124                                        ->tag( 'wp:author_first_name' )->contains->cdata( $author->user_first_name )->end
     125                                        ->tag( 'wp:author_last_name' )->contains->cdata( $author->user_last_name )->end
     126                                        ->end;
     127                }
     128                return $oxymel->to_string();
     129        }
     130
     131        function categories() {
     132                $oxymel = new WP_Export_Oxymel;
     133                $categories = $this->export->categories();
     134                foreach( $categories as $term_id => $category ) {
     135                        $category->parent_slug = $category->parent? $categories[$category->parent]->slug : '';
     136                        $oxymel->tag( 'wp:category' )->contains
     137                                ->tag( 'wp:term_id', $category->term_id )
     138                                ->tag( 'wp:category_nicename', $category->slug )
     139                                ->tag( 'wp:category_parent', $category->parent_slug )
     140                                ->optional_cdata( 'wp:cat_name', $category->name )
     141                                ->optional_cdata( 'wp:category_description', $category->description )
     142                                ->end;
     143                }
     144                return $oxymel->to_string();
     145        }
     146
     147        function tags() {
     148                $oxymel = new WP_Export_Oxymel;
     149                $tags = $this->export->tags();
     150                foreach( $tags as $tag ) {
     151                        $oxymel->tag( 'wp:tag' )->contains
     152                                ->tag( 'wp:term_id', $tag->term_id )
     153                                ->tag( 'wp:tag_slug', $tag->slug )
     154                                ->optional_cdata( 'wp:tag_name', $tag->name )
     155                                ->optional_cdata( 'wp:tag_description', $tag->description )
     156                                ->end;
     157                }
     158                return $oxymel->to_string();
     159        }
     160
     161        function nav_menu_terms() {
     162                return $this->terms( $this->export->nav_menu_terms() );
     163        }
     164
     165        function custom_taxonomies_terms() {
     166                return $this->terms( $this->export->custom_taxonomies_terms() );
     167        }
     168
     169        function rss2_head_action() {
     170                ob_start();
     171                do_action( 'rss2_head' );
     172                $action_output = ob_get_clean();
     173                return $action_output;
     174        }
     175
     176        private function terms( $terms ) {
     177                $oxymel = new WP_Export_Oxymel;
     178                foreach( $terms as $term ) {
     179                        $term->parent_slug = $term->parent? $terms[$term->parent]->slug : '';
     180                        $oxymel->tag( 'wp:term' )->contains
     181                                ->tag( 'wp:term_id', $term->term_id )
     182                                ->tag( 'wp:term_taxonomy', $term->taxonomy )
     183                                ->tag( 'wp:term_slug', $term->slug );
     184                        if ( 'nav_menu' != $term->taxonomy ) {
     185                                $oxymel
     186                                ->tag( 'wp:term_parent', $term->parent_slug );
     187                        }
     188                                $oxymel
     189                                ->optional_cdata( 'wp:term_name', $term->name )
     190                                ->optional_cdata( 'wp:term_description', $term->description )
     191                                ->end;
     192                }
     193                return $oxymel->to_string();
     194        }
     195
     196        function post( $post ) {
     197                $oxymel = new WP_Export_Oxymel;
     198                $GLOBALS['wp_query']->in_the_loop = true;
     199                $GLOBALS['post'] = $post;
     200                setup_postdata( $post );
     201
     202                $oxymel->item->contains
     203                        ->title( apply_filters( 'the_title_rss', $post->post_title ) )
     204                        ->link( apply_filters('the_permalink_rss', get_permalink() ) )
     205                        ->pubDate( mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ) )
     206                        ->tag( 'dc:creator', get_the_author_meta( 'login' ) )
     207                        ->guid( get_the_guid(), array( 'isPermaLink' => 'false' ) )
     208                        ->description( '' )
     209                        ->tag( 'content:encoded' )->contains->cdata( $post->post_content )->end
     210                        ->tag( 'excerpt:encoded' )->contains->cdata( $post->post_excerpt )->end
     211                        ->tag( 'wp:post_id', $post->ID )
     212                        ->tag( 'wp:post_date', $post->post_date )
     213                        ->tag( 'wp:post_date_gmt', $post->post_date_gmt )
     214                        ->tag( 'wp:comment_status', $post->comment_status )
     215                        ->tag( 'wp:ping_status', $post->ping_status )
     216                        ->tag( 'wp:post_name', $post->post_name )
     217                        ->tag( 'wp:status', $post->post_status )
     218                        ->tag( 'wp:post_parent', $post->post_parent )
     219                        ->tag( 'wp:menu_order', $post->menu_order )
     220                        ->tag( 'wp:post_type', $post->post_type )
     221                        ->tag( 'wp:post_password', $post->post_password )
     222                        ->tag( 'wp:is_sticky', $post->is_sticky )
     223                        ->optional( 'wp:attachment_url', wp_get_attachment_url( $post->ID ) );
     224                foreach( $post->terms as $term ) {
     225                        $oxymel
     226                        ->category( array( 'domain' => $term->taxonomy, 'nicename' => $term->slug  ) )->contains->cdata( $term->name )->end;
     227                }
     228                foreach( $post->meta as $meta ) {
     229                        $oxymel
     230                        ->tag( 'wp:postmeta' )->contains
     231                                ->tag( 'wp:meta_key', $meta->meta_key )
     232                                ->tag( 'wp:meta_value' )->contains->cdata( $meta->meta_value )->end
     233                                ->end;
     234                }
     235                foreach( $post->comments as $comment ) {
     236                        $oxymel
     237                        ->tag( 'wp:comment' )->contains
     238                                ->tag( 'wp:comment_id', $comment->comment_ID )
     239                                ->tag( 'wp:comment_author' )->contains->cdata( $comment->comment_author )->end
     240                                ->tag( 'wp:comment_author_email', $comment->comment_author_email )
     241                                ->tag( 'wp:comment_author_url', $comment->comment_author_url )
     242                                ->tag( 'wp:comment_author_IP', $comment->comment_author_IP )
     243                                ->tag( 'wp:comment_date', $comment->comment_date )
     244                                ->tag( 'wp:comment_date_gmt', $comment->comment_date_gmt )
     245                                ->tag( 'wp:comment_content' )->contains->cdata( $comment->comment_content )->end
     246                                ->tag( 'wp:comment_approved', $comment->comment_approved )
     247                                ->tag( 'wp:comment_type', $comment->comment_type )
     248                                ->tag( 'wp:comment_parent', $comment->comment_parent )
     249                                ->tag( 'wp:comment_user_id', $comment->user_id )
     250                                ->oxymel( $this->comment_meta( $comment ) )
     251                                ->end;
     252                }
     253                $oxymel
     254                        ->end;
     255                return $oxymel->to_string();
     256        }
     257
     258        private function comment_meta( $comment ) {
     259                global $wpdb;
     260                $metas = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
     261                if ( !$metas ) {
     262                        return new Oxymel;
     263                }
     264                $oxymel = new WP_Export_Oxymel;
     265                foreach( $metas as $meta ) {
     266                        $oxymel->tag( 'wp:commentmeta' )->contains
     267                                ->tag( 'wp:meta_key', $meta->meta_key )
     268                                ->tag( 'wp:meta_value', $meta->meta_value )
     269                        ->end;
     270                }
     271                return $oxymel;
     272        }
     273
     274
     275        function footer() {
     276                $oxymel = new Oxymel;
     277                return $oxymel->close_channel->close_rss->to_string();
     278        }
     279}
  • wp-includes/export/functions.export.php

    Property changes on: wp-includes/export/class-wp-export-wxr-formatter.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1<?php
     2
     3function wp_export( $args = array() ) {
     4        $defaults = array(
     5                'filters' => array(),
     6                'format' => 'WP_Export_WXR_Formatter',
     7                'writer' => 'WP_Export_Returner',
     8                'writer_args' => null,
     9        );
     10        $args = wp_parse_args( $args, $defaults );
     11        $export_query = new WP_Export_Query( $args['filters'] );
     12        $formatter = new $args['format']( $export_query );
     13        $writer = new $args['writer']( $formatter, $args['writer_args'] );
     14        try {
     15                return $writer->export();
     16        } catch ( WP_Export_Exception $e ) {
     17                return new WP_Error( 'wp-export-error', $e->getMessage() );
     18        }
     19}
  • wp-includes/export/writers.php

    Property changes on: wp-includes/export/functions.export.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1<?php
     2abstract class WP_Export_Base_Writer {
     3        protected $formatter;
     4
     5        function __construct( $formatter ) {
     6                $this->formatter = $formatter;
     7        }
     8
     9        public function export() {
     10                $this->write( $this->formatter->before_posts() );
     11                foreach( $this->formatter->posts() as $post_in_wxr ) {
     12                        $this->write( $post_in_wxr );
     13                }
     14                $this->write( $this->formatter->after_posts() );
     15        }
     16
     17        abstract protected function write( $xml );
     18}
     19
     20class WP_Export_XML_Over_HTTP extends WP_Export_Base_Writer {
     21        private $file_name;
     22
     23        function __construct( $formatter, $file_name ) {
     24                parent::__construct( $formatter );
     25                $this->file_name = $file_name;
     26        }
     27
     28        public function export() {
     29                header( 'Content-Description: File Transfer' );
     30                header( 'Content-Disposition: attachment; filename=' . $this->file_name );
     31                header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
     32                parent::export();
     33        }
     34
     35        protected function write( $xml ) {
     36                echo $xml;
     37        }
     38}
     39
     40class WP_Export_Returner extends WP_Export_Base_Writer {
     41        private $result = '';
     42
     43        public function export() {
     44                $this->private = '';
     45                parent::export();
     46                return $this->result;
     47        }
     48        protected function write( $xml ) {
     49                $this->result .= $xml;
     50        }
     51}
     52
     53class WP_Export_File_Writer extends WP_Export_Base_Writer {
     54        private $f;
     55        private $file_name;
     56
     57        public function __construct( $formatter, $file_name ) {
     58                parent::__construct( $formatter );
     59                $this->file_name = $file_name;
     60        }
     61
     62        public function export() {
     63                $this->f = fopen( $this->file_name, 'w' );
     64                if ( !$this->f ) {
     65                        throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) );
     66                }
     67                parent::export();
     68                fclose( $this->f );
     69        }
     70
     71        protected function write( $xml ) {
     72                $res = fwrite( $this->f, $xml);
     73                if ( false === $res ) {
     74                        throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) );
     75                }
     76        }
     77}
     78
     79class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer {
     80        private $result = '';
     81        private $f;
     82        private $next_file_number = 0;
     83        private $current_file_size = 0;
     84
     85        function __construct( $formatter, $writer_args = array() ) {
     86                parent::__construct( $formatter );
     87                //TODO: check if args are not missing
     88                $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $max_file_size;
     89                $this->destination_directory = $writer_args['destination_directory'];
     90                $this->filename_template = $writer_args['filename_template'];
     91                $this->before_posts_xml = $this->formatter->before_posts();
     92                $this->after_posts_xml = $this->formatter->after_posts();
     93        }
     94
     95        public function export() {
     96                $this->start_new_file();
     97                foreach( $this->formatter->posts() as $post_xml ) {
     98                        if ( $this->current_file_size + strlen( $post_xml ) > $this->max_file_size ) {
     99                                $this->start_new_file();
     100                        }
     101                        $this->write( $post_xml );
     102                }
     103                $this->close_current_file();
     104        }
     105
     106        protected function write( $xml ) {
     107                $res = fwrite( $this->f, $xml);
     108                if ( false === $res ) {
     109                        throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) );
     110                }
     111                $this->current_file_size += strlen( $xml );
     112        }
     113
     114        private function start_new_file() {
     115                if ( $this->f ) {
     116                        $this->close_current_file();
     117                }
     118                $file_path = $this->next_file_path();
     119                $this->f = fopen( $file_path, 'w' );
     120                if ( !$this->f ) {
     121                        throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) );
     122                }
     123                $this->current_file_size = 0;
     124                $this->write( $this->before_posts_xml );
     125        }
     126
     127        private function close_current_file() {
     128                if ( !$this->f ) {
     129                        return;
     130                }
     131                $this->write( $this->after_posts_xml );
     132                fclose( $this->f );
     133        }
     134
     135        private function next_file_name() {
     136                $next_file_name = sprintf( $this->filename_template, $this->next_file_number );
     137                $this->next_file_number++;
     138                return $next_file_name;
     139        }
     140
     141        private function next_file_path() {
     142                return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name();
     143        }
     144
     145}
  • wp-includes/iterators.php

     
     1<?php
     2class WP_Map_Iterator extends IteratorIterator {
     3        function __construct( $iterator, $callback ) {
     4                $this->callback = $callback;
     5                parent::__construct( $iterator );
     6        }
     7
     8        function current() {
     9                $original_current = parent::current();
     10                return call_user_func( $this->callback, $original_current );
     11        }
     12}
     13
     14class WP_Post_IDs_Iterator implements Iterator {
     15        private $limit = 100;
     16        private $post_ids;
     17        private $ids_left;
     18        private $results = array();
     19
     20        public function __construct( $post_ids, $limit = null ) {
     21                $this->db = $GLOBALS['wpdb'];
     22                $this->post_ids = $post_ids;
     23                $this->ids_left = $post_ids;
     24                if ( !is_null( $limit ) ) {
     25                        $this->limit = $limit;
     26                }
     27        }
     28
     29        public function current() {
     30                return $this->results[$this->index_in_results];
     31        }
     32
     33        public function key() {
     34                return $this->global_index;
     35        }
     36
     37        public function next() {
     38                $this->index_in_results++;
     39                $this->global_index++;
     40        }
     41
     42        public function rewind() {
     43                $this->results = array();
     44                $this->global_index = 0;
     45                $this->index_in_results = 0;
     46                $this->ids_left = $this->post_ids;
     47        }
     48
     49        public function valid() {
     50                if ( isset( $this->results[$this->index_in_results] ) ) {
     51                        return true;
     52                }
     53                if ( empty( $this->ids_left ) ) {
     54                        return false;
     55                }
     56                $has_posts = $this->load_next_posts_from_db();
     57                if ( !$has_posts ) {
     58                        return false;
     59                }
     60                $this->index_in_results = 0;
     61                return true;
     62        }
     63
     64        private function load_next_posts_from_db() {
     65                $next_batch_post_ids = array_splice( $this->ids_left, 0, $this->limit );
     66                $in_post_ids_sql = $this->db->build_IN_condition( 'ID', $next_batch_post_ids );
     67                $this->results = $this->db->get_results( "SELECT * FROM {$this->db->posts} WHERE $in_post_ids_sql" );
     68                if ( !$this->results ) {
     69                        if ( $this->db->last_error ) {
     70                                throw new WP_Iterator_Exception( 'Database error: ' . $this->db->last_error );
     71                        } else {
     72                                return false;
     73                        }
     74                }
     75                return true;
     76        }
     77}
     78
     79class WP_Iterator_Exception extends Exception {
     80}
  • wp-includes/wp-db.php

     
    17341734        function db_version() {
    17351735                return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ) );
    17361736        }
     1737
     1738        /**
     1739         * Builds a SQL condition in the form "post_id IN (1, 2, 3, 4)"
     1740         *
     1741         * @since 3.6.0
     1742         *
     1743         * @param string $column_name The name of the table column from the IN condition
     1744         * @param array $values Array of values in which the column value should be
     1745         * @param string $format Optional printf format specifier for the elements of the array. Defaults to %s.
     1746         * @return string The IN condition, with escaped values. If there are no values, the return value is an empty string.
     1747         */
     1748        function build_IN_condition( $column_name, $values, $format = '%s' ) {
     1749                if ( !is_array( $values ) || empty( $values ) ) {
     1750                        return '';
     1751                }
     1752                $formats = implode( ', ', array_fill( 0, count( $values ), $format ) );
     1753                return $this->prepare( "$column_name IN ($formats)", $values );
     1754        }
    17371755}
  • wp-settings.php

     
    123123require( ABSPATH . WPINC . '/comment.php' );
    124124require( ABSPATH . WPINC . '/comment-template.php' );
    125125require( ABSPATH . WPINC . '/rewrite.php' );
     126require( ABSPATH . WPINC . '/iterators.php' );
     127require( ABSPATH . WPINC . '/export/class-wp-export-query.php' );
     128require( ABSPATH . WPINC . '/export/class-wp-export-wxr-formatter.php' );
     129require( ABSPATH . WPINC . '/export/writers.php' );
     130require( ABSPATH . WPINC . '/export/functions.export.php' );
    126131require( ABSPATH . WPINC . '/feed.php' );
    127132require( ABSPATH . WPINC . '/bookmark.php' );
    128133require( ABSPATH . WPINC . '/bookmark-template.php' );