WordPress Importer - Version 0.3

Version Description

  • Use an XML Parser if possible
  • Proper import support for nav menus
  • ... and more, see Trac ticket #15197
Download this release

Release Info

Developer duck_
Plugin Icon 128x128 WordPress Importer
Version 0.3
Comparing to
See all releases

Code changes from version 0.2 to 0.3

Files changed (4) hide show
  1. languages/wordpress-importer.pot +125 -95
  2. parsers.php +601 -0
  3. readme.txt +21 -8
  4. wordpress-importer.php +843 -704
languages/wordpress-importer.pot CHANGED
@@ -1,178 +1,208 @@
1
- # Translation of the WordPress plugin WordPress Importer 0.2 by wordpressdotorg.
2
- # Copyright (C) 2010 wordpressdotorg
3
  # This file is distributed under the same license as the WordPress Importer package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
- #
6
- #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: WordPress Importer 0.2\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wordpress-importer\n"
11
- "POT-Creation-Date: 2010-06-01 13:26+0300\n"
 
 
 
12
  "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "MIME-Version: 1.0\n"
16
- "Content-Type: text/plain; charset=utf-8\n"
17
- "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
 
20
- #: wordpress-importer.php:55
21
- msgid "Import WordPress"
22
  msgstr ""
23
 
24
- #: wordpress-importer.php:64
25
  msgid ""
26
- "Howdy! Upload your WordPress eXtended RSS (WXR) file and we&#8217;ll import "
27
- "the posts, pages, comments, custom fields, categories, and tags into this "
28
- "site."
29
  msgstr ""
30
 
31
- #: wordpress-importer.php:65
32
  msgid ""
33
- "Choose a WordPress WXR file to upload, then click Upload file and import."
34
  msgstr ""
35
 
36
- #: wordpress-importer.php:228
37
- msgid "Assign Authors"
 
38
  msgstr ""
39
 
40
- #: wordpress-importer.php:229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  msgid ""
42
- "To make it easier for you to edit and save the imported posts and drafts, "
43
- "you may want to change the name of the author of the posts. For example, you "
44
- "may want to import all the entries as <code>admin</code>s entries."
45
  msgstr ""
46
 
47
- #: wordpress-importer.php:232
48
  msgid ""
49
- "If a new user is created by WordPress, a password will be randomly "
50
- "generated. Manually change the user&#8217;s details if necessary."
51
  msgstr ""
52
 
53
- #: wordpress-importer.php:245
54
- msgid "Import author:"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  msgstr ""
56
 
57
- #: wordpress-importer.php:253
58
  msgid "Import Attachments"
59
  msgstr ""
60
 
61
- #: wordpress-importer.php:256
62
  msgid "Download and import file attachments"
63
  msgstr ""
64
 
65
- #: wordpress-importer.php:263
66
  msgid "Submit"
67
  msgstr ""
68
 
69
- #: wordpress-importer.php:272
70
- #, php-format
71
- msgid "Create user %1$s or map to existing"
72
  msgstr ""
73
 
74
- #: wordpress-importer.php:275
75
- msgid "Map to existing"
76
  msgstr ""
77
 
78
- #: wordpress-importer.php:283
79
- msgid "- Select -"
80
  msgstr ""
81
 
82
- #: wordpress-importer.php:299
83
- msgid "Invalid file"
84
  msgstr ""
85
 
86
- #: wordpress-importer.php:300
87
- msgid "Please upload a valid WXR (WordPress eXtended RSS) export file."
88
  msgstr ""
89
 
90
- #: wordpress-importer.php:343
91
- #, php-format
92
- msgid "Importing category <em>%s</em>&#8230;"
93
  msgstr ""
94
 
95
- #: wordpress-importer.php:365
96
- #, php-format
97
- msgid "Importing tag <em>%s</em>&#8230;"
 
98
  msgstr ""
99
 
100
- #: wordpress-importer.php:403
101
- #, php-format
102
- msgid "Importing <em>%s</em>&#8230;"
103
  msgstr ""
104
 
105
- #: wordpress-importer.php:424
106
- msgid "All done."
107
  msgstr ""
108
 
109
- #: wordpress-importer.php:424
110
- msgid "Have fun!"
111
  msgstr ""
112
 
113
- #: wordpress-importer.php:488
114
- #, php-format
115
- msgid "Post <em>%s</em> already exists."
116
  msgstr ""
117
 
118
- #: wordpress-importer.php:521
119
- #, php-format
120
- msgid "Importing post <em>%s</em>..."
121
  msgstr ""
122
 
123
- #: wordpress-importer.php:617
124
- #, php-format
125
- msgid "(%s comment)"
126
- msgid_plural "(%s comments)"
127
- msgstr[0] ""
128
- msgstr[1] ""
129
-
130
- #: wordpress-importer.php:645
131
- #, php-format
132
- msgid "Importing attachment <em>%s</em>... "
133
  msgstr ""
134
 
135
- #: wordpress-importer.php:653
136
- #, php-format
137
- msgid "Remote file error: %s"
138
  msgstr ""
139
 
140
- #: wordpress-importer.php:661
141
- msgid "Zero length file, deleting"
142
  msgstr ""
143
 
144
- #: wordpress-importer.php:670
145
- msgid "Invalid file type"
146
  msgstr ""
147
 
148
- #: wordpress-importer.php:691
149
- #, php-format
150
- msgid "Skipping attachment <em>%s</em>"
151
  msgstr ""
152
 
153
- #: wordpress-importer.php:716
154
  msgid "Remote server did not respond"
155
  msgstr ""
156
 
157
- #: wordpress-importer.php:722
158
- #, php-format
159
- msgid "Remote file returned error response %1$d %2$s"
160
  msgstr ""
161
 
162
- #: wordpress-importer.php:726
163
  msgid "Remote file is incorrect size"
164
  msgstr ""
165
 
166
- #: wordpress-importer.php:732
167
- #, php-format
 
 
 
168
  msgid "Remote file is too large, limit is %s"
169
  msgstr ""
170
 
171
- #: wordpress-importer.php:864
172
- msgid "Sorry, there has been an error."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  msgstr ""
174
 
175
- #: wordpress-importer.php:914
176
  msgid ""
177
  "Import <strong>posts, pages, comments, custom fields, categories, and tags</"
178
  "strong> from a WordPress export file."
@@ -188,8 +218,8 @@ msgstr ""
188
 
189
  #. Description of the plugin/theme
190
  msgid ""
191
- "Import posts, pages, comments, custom fields, categories, and tags from a "
192
- "WordPress export file."
193
  msgstr ""
194
 
195
  #. Author of the plugin/theme
1
+ # Copyright (C) 2011 WordPress Importer
 
2
  # This file is distributed under the same license as the WordPress Importer package.
 
 
 
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WordPress Importer 0.3\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wordpress-importer\n"
7
+ "POT-Creation-Date: 2011-02-21 21:07:12+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
  "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
 
 
 
 
14
 
15
+ #: parsers.php:42 parsers.php:63
16
+ msgid "There was an error when reading this WXR file"
17
  msgstr ""
18
 
19
+ #: parsers.php:43
20
  msgid ""
21
+ "Details are shown above. The importer will now try again with a different "
22
+ "parser..."
 
23
  msgstr ""
24
 
25
+ #: parsers.php:67 parsers.php:72 parsers.php:248 parsers.php:430
26
  msgid ""
27
+ "This does not appear to be a WXR file, missing/invalid WXR version number"
28
  msgstr ""
29
 
30
+ #: wordpress-importer.php:133 wordpress-importer.php:142
31
+ #: wordpress-importer.php:193 wordpress-importer.php:201
32
+ msgid "Sorry, there has been an error."
33
  msgstr ""
34
 
35
+ #: wordpress-importer.php:134
36
+ msgid "The file does not exist, please try again."
37
+ msgstr ""
38
+
39
+ #: wordpress-importer.php:177
40
+ msgid "All done."
41
+ msgstr ""
42
+
43
+ #: wordpress-importer.php:177
44
+ msgid "Have fun!"
45
+ msgstr ""
46
+
47
+ #: wordpress-importer.php:178
48
+ msgid "Remember to update the passwords and roles of imported users."
49
+ msgstr ""
50
+
51
+ #: wordpress-importer.php:209
52
  msgid ""
53
+ "This WXR file (version %s) may not be supported by this version of the "
54
+ "importer. Please consider updating."
 
55
  msgstr ""
56
 
57
+ #: wordpress-importer.php:234
58
  msgid ""
59
+ "Failed to import author %s. Their posts will be attributed to the current "
60
+ "user."
61
  msgstr ""
62
 
63
+ #: wordpress-importer.php:260
64
+ msgid "Assign Authors"
65
+ msgstr ""
66
+
67
+ #: wordpress-importer.php:261
68
+ msgid ""
69
+ "To make it easier for you to edit and save the imported content, you may "
70
+ "want to reassign the author of the imported item to an existing user of this "
71
+ "site. For example, you may want to import all the entries as <code>admin</"
72
+ "code>s entries."
73
+ msgstr ""
74
+
75
+ #: wordpress-importer.php:263
76
+ msgid ""
77
+ "If a new user is created by WordPress, a new password will be randomly "
78
+ "generated and the new user&#8217;s role will be set as %s. Manually changing "
79
+ "the new user&#8217;s details will be necessary."
80
  msgstr ""
81
 
82
+ #: wordpress-importer.php:273
83
  msgid "Import Attachments"
84
  msgstr ""
85
 
86
+ #: wordpress-importer.php:276
87
  msgid "Download and import file attachments"
88
  msgstr ""
89
 
90
+ #: wordpress-importer.php:280
91
  msgid "Submit"
92
  msgstr ""
93
 
94
+ #: wordpress-importer.php:293
95
+ msgid "Import author:"
 
96
  msgstr ""
97
 
98
+ #: wordpress-importer.php:304
99
+ msgid "or create new user with login name:"
100
  msgstr ""
101
 
102
+ #: wordpress-importer.php:307
103
+ msgid "as a new user:"
104
  msgstr ""
105
 
106
+ #: wordpress-importer.php:315
107
+ msgid "assign posts to an existing user:"
108
  msgstr ""
109
 
110
+ #: wordpress-importer.php:317
111
+ msgid "or assign posts to an existing user:"
112
  msgstr ""
113
 
114
+ #: wordpress-importer.php:318
115
+ msgid "- Select -"
 
116
  msgstr ""
117
 
118
+ #: wordpress-importer.php:366
119
+ msgid ""
120
+ "Failed to create new user for %s. Their posts will be attributed to the "
121
+ "current user."
122
  msgstr ""
123
 
124
+ #: wordpress-importer.php:413
125
+ msgid "Failed to import category %s"
 
126
  msgstr ""
127
 
128
+ #: wordpress-importer.php:449
129
+ msgid "Failed to import post tag %s"
130
  msgstr ""
131
 
132
+ #: wordpress-importer.php:491 wordpress-importer.php:603
133
+ msgid "Failed to import %s %s"
134
  msgstr ""
135
 
136
+ #: wordpress-importer.php:513
137
+ msgid "Failed to import &#8220;%s&#8221;: Invalid post type %s"
 
138
  msgstr ""
139
 
140
+ #: wordpress-importer.php:534
141
+ msgid "%s &#8220;%s&#8221; already exists."
 
142
  msgstr ""
143
 
144
+ #: wordpress-importer.php:575
145
+ msgid "Failed to import %s &#8220;%s&#8221;"
 
 
 
 
 
 
 
 
146
  msgstr ""
147
 
148
+ #: wordpress-importer.php:712
149
+ msgid "Menu item skipped due to missing menu slug"
 
150
  msgstr ""
151
 
152
+ #: wordpress-importer.php:719
153
+ msgid "Menu item skipped due to invalid menu slug: %s"
154
  msgstr ""
155
 
156
+ #: wordpress-importer.php:782
157
+ msgid "Fetching attachments is not enabled"
158
  msgstr ""
159
 
160
+ #: wordpress-importer.php:795
161
+ msgid "Invalid file type"
 
162
  msgstr ""
163
 
164
+ #: wordpress-importer.php:838
165
  msgid "Remote server did not respond"
166
  msgstr ""
167
 
168
+ #: wordpress-importer.php:844
169
+ msgid "Remote server returned error response %1$d %2$s"
 
170
  msgstr ""
171
 
172
+ #: wordpress-importer.php:851
173
  msgid "Remote file is incorrect size"
174
  msgstr ""
175
 
176
+ #: wordpress-importer.php:856
177
+ msgid "Zero size file downloaded"
178
+ msgstr ""
179
+
180
+ #: wordpress-importer.php:862
181
  msgid "Remote file is too large, limit is %s"
182
  msgstr ""
183
 
184
+ #: wordpress-importer.php:961
185
+ msgid "Import WordPress"
186
+ msgstr ""
187
+
188
+ #: wordpress-importer.php:968
189
+ msgid ""
190
+ "A new version of this importer is available. Please update to version %s to "
191
+ "ensure compatibility with newer export files."
192
+ msgstr ""
193
+
194
+ #: wordpress-importer.php:983
195
+ msgid ""
196
+ "Howdy! Upload your WordPress eXtended RSS (WXR) file and we&#8217;ll import "
197
+ "the posts, pages, comments, custom fields, categories, and tags into this "
198
+ "site."
199
+ msgstr ""
200
+
201
+ #: wordpress-importer.php:984
202
+ msgid "Choose a WXR file to upload, then click Upload file and import."
203
  msgstr ""
204
 
205
+ #: wordpress-importer.php:1058
206
  msgid ""
207
  "Import <strong>posts, pages, comments, custom fields, categories, and tags</"
208
  "strong> from a WordPress export file."
218
 
219
  #. Description of the plugin/theme
220
  msgid ""
221
+ "Import posts, pages, comments, custom fields, categories, tags and more from "
222
+ "a WordPress export file."
223
  msgstr ""
224
 
225
  #. Author of the plugin/theme
parsers.php ADDED
@@ -0,0 +1,601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress eXtended RSS file parser implementations
4
+ *
5
+ * @package WordPress
6
+ * @subpackage Importer
7
+ */
8
+
9
+ /**
10
+ * WordPress Importer class for managing parsing of WXR files.
11
+ */
12
+ class WXR_Parser {
13
+ function parse( $file ) {
14
+ // Attempt to use proper XML parsers first
15
+ if ( extension_loaded( 'simplexml' ) ) {
16
+ $parser = new WXR_Parser_SimpleXML;
17
+ $result = $parser->parse( $file );
18
+
19
+ // If SimpleXML succeeds or this is an invalid WXR file then return the results
20
+ if ( ! is_wp_error( $result ) || 'SimpleXML_parse_error' != $result->get_error_code() )
21
+ return $result;
22
+ } else if ( extension_loaded( 'xml' ) ) {
23
+ $parser = new WXR_Parser_XML;
24
+ $result = $parser->parse( $file );
25
+
26
+ // If XMLParser succeeds or this is an invalid WXR file then return the results
27
+ if ( ! is_wp_error( $result ) || 'XML_parse_error' != $result->get_error_code() )
28
+ return $result;
29
+ }
30
+
31
+ // We have a malformed XML file, so display the error and fallthrough to regex
32
+ if ( isset($result) && defined('IMPORT_DEBUG') && IMPORT_DEBUG ) {
33
+ echo '<pre>';
34
+ if ( 'SimpleXML_parse_error' == $result->get_error_code() ) {
35
+ foreach ( $result->get_error_data() as $error )
36
+ echo $error->line . ':' . $error->column . ' ' . esc_html( $error->message ) . "\n";
37
+ } else if ( 'XML_parse_error' == $result->get_error_code() ) {
38
+ $error = $result->get_error_data();
39
+ echo $error[0] . ':' . $error[1] . ' ' . esc_html( $error[2] );
40
+ }
41
+ echo '</pre>';
42
+ echo '<p><strong>' . __( 'There was an error when reading this WXR file', 'wordpress-importer' ) . '</strong><br />';
43
+ echo __( 'Details are shown above. The importer will now try again with a different parser...', 'wordpress-importer' ) . '</p>';
44
+ }
45
+
46
+ // use regular expressions if nothing else available or this is bad XML
47
+ $parser = new WXR_Parser_Regex;
48
+ return $parser->parse( $file );
49
+ }
50
+ }
51
+
52
+ /**
53
+ * WXR Parser that makes use of the SimpleXML PHP extension.
54
+ */
55
+ class WXR_Parser_SimpleXML {
56
+ function parse( $file ) {
57
+ $authors = $posts = $categories = $tags = $terms = array();
58
+
59
+ $internal_errors = libxml_use_internal_errors(true);
60
+ $xml = simplexml_load_file( $file );
61
+ // halt if loading produces an error
62
+ if ( ! $xml )
63
+ return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this WXR file', 'wordpress-importer' ), libxml_get_errors() );
64
+
65
+ $wxr_version = $xml->xpath('/rss/channel/wp:wxr_version');
66
+ if ( ! $wxr_version )
67
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
68
+
69
+ $wxr_version = (string) trim( $wxr_version[0] );
70
+ // confirm that we are dealing with the correct file format
71
+ if ( ! preg_match( '/^\d+\.\d+$/', $wxr_version ) )
72
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
73
+
74
+ $base_url = $xml->xpath('/rss/channel/wp:base_site_url');
75
+ $base_url = (string) trim( $base_url[0] );
76
+
77
+ $namespaces = $xml->getDocNamespaces();
78
+ if ( ! isset( $namespaces['wp'] ) )
79
+ $namespaces['wp'] = 'http://wordpress.org/export/1.1/';
80
+ if ( ! isset( $namespaces['excerpt'] ) )
81
+ $namespaces['excerpt'] = 'http://wordpress.org/export/1.1/excerpt/';
82
+
83
+ // grab authors
84
+ foreach ( $xml->xpath('/rss/channel/wp:author') as $author_arr ) {
85
+ $a = $author_arr->children( $namespaces['wp'] );
86
+ $login = (string) $a->author_login;
87
+ $authors[$login] = array(
88
+ 'author_id' => (int) $a->author_id,
89
+ 'author_login' => $login,
90
+ 'author_email' => (string) $a->author_email,
91
+ 'author_display_name' => (string) $a->author_display_name,
92
+ 'author_first_name' => (string) $a->author_first_name,
93
+ 'author_last_name' => (string) $a->author_last_name
94
+ );
95
+ }
96
+
97
+ // grab cats, tags and terms
98
+ foreach ( $xml->xpath('/rss/channel/wp:category') as $term_arr ) {
99
+ $t = $term_arr->children( $namespaces['wp'] );
100
+ $categories[] = array(
101
+ 'term_id' => (int) $t->term_id,
102
+ 'category_nicename' => (string) $t->category_nicename,
103
+ 'category_parent' => (string) $t->category_parent,
104
+ 'cat_name' => (string) $t->cat_name,
105
+ 'category_description' => (string) $t->category_description
106
+ );
107
+ }
108
+
109
+ foreach ( $xml->xpath('/rss/channel/wp:tag') as $term_arr ) {
110
+ $t = $term_arr->children( $namespaces['wp'] );
111
+ $tags[] = array(
112
+ 'term_id' => (int) $t->term_id,
113
+ 'tag_slug' => (string) $t->tag_slug,
114
+ 'tag_name' => (string) $t->tag_name,
115
+ 'tag_description' => (string) $t->tag_description
116
+ );
117
+ }
118
+
119
+ foreach ( $xml->xpath('/rss/channel/wp:term') as $term_arr ) {
120
+ $t = $term_arr->children( $namespaces['wp'] );
121
+ $terms[] = array(
122
+ 'term_id' => (int) $t->term_id,
123
+ 'term_taxonomy' => (string) $t->term_taxonomy,
124
+ 'slug' => (string) $t->term_slug,
125
+ 'term_parent' => (string) $t->term_parent,
126
+ 'term_name' => (string) $t->term_name,
127
+ 'term_description' => (string) $t->term_description
128
+ );
129
+ }
130
+
131
+ // grab posts
132
+ foreach ( $xml->channel->item as $item ) {
133
+ $post = array(
134
+ 'post_title' => (string) $item->title,
135
+ 'guid' => (string) $item->guid,
136
+ );
137
+
138
+ $dc = $item->children( 'http://purl.org/dc/elements/1.1/' );
139
+ $post['post_author'] = (string) $dc->creator;
140
+
141
+ $content = $item->children( 'http://purl.org/rss/1.0/modules/content/' );
142
+ $excerpt = $item->children( $namespaces['excerpt'] );
143
+ $post['post_content'] = (string) $content->encoded;
144
+ $post['post_excerpt'] = (string) $excerpt->encoded;
145
+
146
+ $wp = $item->children( $namespaces['wp'] );
147
+ $post['post_id'] = (int) $wp->post_id;
148
+ $post['post_date'] = (string) $wp->post_date;
149
+ $post['post_date_gmt'] = (string) $wp->post_date_gmt;
150
+ $post['comment_status'] = (string) $wp->comment_status;
151
+ $post['ping_status'] = (string) $wp->ping_status;
152
+ $post['post_name'] = (string) $wp->post_name;
153
+ $post['status'] = (string) $wp->status;
154
+ $post['post_parent'] = (int) $wp->post_parent;
155
+ $post['menu_order'] = (int) $wp->menu_order;
156
+ $post['post_type'] = (string) $wp->post_type;
157
+ $post['post_password'] = (string) $wp->post_password;
158
+ $post['is_sticky'] = (int) $wp->is_sticky;
159
+
160
+ foreach ( $item->category as $c ) {
161
+ $att = $c->attributes();
162
+ if ( isset( $att['nicename'] ) )
163
+ $post['terms'][] = array(
164
+ 'name' => (string) $c,
165
+ 'slug' => (string) $att['nicename'],
166
+ 'domain' => (string) $att['domain']
167
+ );
168
+ }
169
+
170
+ foreach ( $wp->postmeta as $meta ) {
171
+ $post['postmeta'][] = array(
172
+ 'key' => (string) $meta->meta_key,
173
+ 'value' => (string) $meta->meta_value,
174
+ );
175
+ }
176
+
177
+ foreach ( $wp->comment as $comment ) {
178
+ $post['comments'][] = array(
179
+ 'comment_id' => (int) $comment->comment_id,
180
+ 'comment_author' => (string) $comment->comment_author,
181
+ 'comment_author_email' => (string) $comment->comment_author_email,
182
+ 'comment_author_IP' => (string) $comment->comment_author_IP,
183
+ 'comment_author_url' => (string) $comment->comment_author_url,
184
+ 'comment_date' => (string) $comment->comment_date,
185
+ 'comment_date_gmt' => (string) $comment->comment_date_gmt,
186
+ 'comment_content' => (string) $comment->comment_content,
187
+ 'comment_approved' => (string) $comment->comment_approved,
188
+ 'comment_type' => (string) $comment->comment_type,
189
+ 'comment_parent' => (string) $comment->comment_parent,
190
+ 'comment_user_id' => (int) $comment->comment_user_id,
191
+ );
192
+ }
193
+
194
+ $posts[] = $post;
195
+ }
196
+
197
+ return array(
198
+ 'authors' => $authors,
199
+ 'posts' => $posts,
200
+ 'categories' => $categories,
201
+ 'tags' => $tags,
202
+ 'terms' => $terms,
203
+ 'base_url' => $base_url,
204
+ 'version' => $wxr_version
205
+ );
206
+ }
207
+ }
208
+
209
+ /**
210
+ * WXR Parser that makes use of the XML Parser PHP extension.
211
+ */
212
+ class WXR_Parser_XML {
213
+ var $wp_tags = array(
214
+ 'wp:post_id', 'wp:post_date', 'wp:post_date_gmt', 'wp:comment_status', 'wp:ping_status',
215
+ 'wp:status', 'wp:post_name', 'wp:post_parent', 'wp:menu_order', 'wp:post_type', 'wp:post_password',
216
+ 'wp:is_sticky', 'wp:term_id', 'wp:category_nicename', 'wp:category_parent', 'wp:cat_name', 'wp:category_description',
217
+ 'wp:tag_slug', 'wp:tag_name', 'wp:tag_description', 'wp:term_taxonomy', 'wp:term_parent',
218
+ 'wp:term_name', 'wp:term_description', 'wp:author_id', 'wp:author_login', 'wp:author_email', 'wp:author_display_name',
219
+ 'wp:author_first_name', 'wp:author_last_name',
220
+ );
221
+ var $wp_sub_tags = array(
222
+ 'wp:comment_id', 'wp:comment_author', 'wp:comment_author_email', 'wp:comment_author_url',
223
+ 'wp:comment_author_IP', 'wp:comment_date', 'wp:comment_date_gmt', 'wp:comment_content',
224
+ 'wp:comment_approved', 'wp:comment_type', 'wp:comment_parent', 'wp:comment_user_id',
225
+ );
226
+
227
+ function parse( $file ) {
228
+ $this->wxr_version = $this->in_post = $this->cdata = $this->data = $this->sub_data = $this->in_tag = $this->in_sub_tag = false;
229
+ $this->authors = $this->posts = $this->term = $this->category = $this->tag = array();
230
+
231
+ $xml = xml_parser_create( 'UTF-8' );
232
+ xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 );
233
+ xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 );
234
+ xml_set_object( $xml, $this );
235
+ xml_set_character_data_handler( $xml, 'cdata' );
236
+ xml_set_element_handler( $xml, 'tag_open', 'tag_close' );
237
+
238
+ if ( ! xml_parse( $xml, file_get_contents( $file ), true ) ) {
239
+ $current_line = xml_get_current_line_number( $xml );
240
+ $current_column = xml_get_current_column_number( $xml );
241
+ $error_code = xml_get_error_code( $xml );
242
+ $error_string = xml_error_string( $error_code );
243
+ return new WP_Error( 'XML_parse_error', 'There was an error when reading this WXR file', array( $current_line, $current_column, $error_string ) );
244
+ }
245
+ xml_parser_free( $xml );
246
+
247
+ if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) )
248
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
249
+
250
+ return array(
251
+ 'authors' => $this->authors,
252
+ 'posts' => $this->posts,
253
+ 'categories' => $this->category,
254
+ 'tags' => $this->tag,
255
+ 'terms' => $this->term,
256
+ 'base_url' => $this->base_url,
257
+ 'version' => $this->wxr_version
258
+ );
259
+ }
260
+
261
+ function tag_open( $parse, $tag, $attr ) {
262
+ if ( in_array( $tag, $this->wp_tags ) ) {
263
+ $this->in_tag = substr( $tag, 3 );
264
+ return;
265
+ }
266
+
267
+ if ( in_array( $tag, $this->wp_sub_tags ) ) {
268
+ $this->in_sub_tag = substr( $tag, 3 );
269
+ return;
270
+ }
271
+
272
+ switch ( $tag ) {
273
+ case 'category':
274
+ if ( isset($attr['domain'], $attr['nicename']) ) {
275
+ $this->sub_data['domain'] = $attr['domain'];
276
+ $this->sub_data['slug'] = $attr['nicename'];
277
+ }
278
+ break;
279
+ case 'item': $this->in_post = true;
280
+ case 'title': if ( $this->in_post ) $this->in_tag = 'post_title'; break;
281
+ case 'guid': $this->in_tag = 'guid'; break;
282
+ case 'dc:creator': $this->in_tag = 'post_author'; break;
283
+ case 'content:encoded': $this->in_tag = 'post_content'; break;
284
+ case 'excerpt:encoded': $this->in_tag = 'post_excerpt'; break;
285
+
286
+ case 'wp:term_slug': $this->in_tag = 'slug'; break;
287
+ case 'wp:meta_key': $this->in_sub_tag = 'key'; break;
288
+ case 'wp:meta_value': $this->in_sub_tag = 'value'; break;
289
+ }
290
+ }
291
+
292
+ function cdata( $parser, $cdata ) {
293
+ if ( ! trim( $cdata ) )
294
+ return;
295
+
296
+ $this->cdata .= trim( $cdata );
297
+ }
298
+
299
+ function tag_close( $parser, $tag ) {
300
+ switch ( $tag ) {
301
+ case 'wp:comment':
302
+ if ( ! empty( $this->sub_data ) )
303
+ $this->data['comments'][] = $this->sub_data;
304
+ $this->sub_data = false;
305
+ break;
306
+ case 'category':
307
+ if ( ! empty( $this->sub_data ) ) {
308
+ $this->sub_data['name'] = $this->cdata;
309
+ $this->data['terms'][] = $this->sub_data;
310
+ }
311
+ $this->sub_data = false;
312
+ break;
313
+ case 'wp:postmeta':
314
+ if ( ! empty( $this->sub_data ) )
315
+ $this->data['postmeta'][] = $this->sub_data;
316
+ $this->sub_data = false;
317
+ break;
318
+ case 'item':
319
+ $this->posts[] = $this->data;
320
+ $this->data = false;
321
+ break;
322
+ case 'wp:category':
323
+ case 'wp:tag':
324
+ case 'wp:term':
325
+ $n = substr( $tag, 3 );
326
+ array_push( $this->$n, $this->data );
327
+ $this->data = false;
328
+ break;
329
+ case 'wp:author':
330
+ if ( ! empty($this->data['author_login']) )
331
+ $this->authors[$this->data['author_login']] = $this->data;
332
+ $this->data = false;
333
+ break;
334
+ case 'wp:base_site_url':
335
+ $this->base_url = $this->cdata;
336
+ break;
337
+ case 'wp:wxr_version':
338
+ $this->wxr_version = $this->cdata;
339
+ break;
340
+
341
+ default:
342
+ if ( $this->in_sub_tag ) {
343
+ $this->sub_data[$this->in_sub_tag] = ! empty( $this->cdata ) ? $this->cdata : '';
344
+ $this->in_sub_tag = false;
345
+ } else if ( $this->in_tag ) {
346
+ $this->data[$this->in_tag] = ! empty( $this->cdata ) ? $this->cdata : '';
347
+ $this->in_tag = false;
348
+ }
349
+ }
350
+
351
+ $this->cdata = false;
352
+ }
353
+ }
354
+
355
+ /**
356
+ * WXR Parser that uses regular expressions. Fallback for installs without an XML parser.
357
+ */
358
+ class WXR_Parser_Regex {
359
+ var $authors = array();
360
+ var $posts = array();
361
+ var $categories = array();
362
+ var $tags = array();
363
+ var $terms = array();
364
+ var $base_url = '';
365
+
366
+ function WXR_Parser_Regex() {
367
+ $this->__construct();
368
+ }
369
+
370
+ function __construct() {
371
+ $this->has_gzip = is_callable( 'gzopen' );
372
+ }
373
+
374
+ function parse( $file ) {
375
+ $wxr_version = $in_post = false;
376
+
377
+ $fp = $this->fopen( $file, 'r' );
378
+ if ( $fp ) {
379
+ while ( ! $this->feof( $fp ) ) {
380
+ $importline = rtrim( $this->fgets( $fp ) );
381
+
382
+ if ( ! $wxr_version && preg_match( '|<wp:wxr_version>(\d+\.\d+)</wp:wxr_version>|', $importline, $version ) )
383
+ $wxr_version = $version[1];
384
+
385
+ if ( false !== strpos( $importline, '<wp:base_site_url>' ) ) {
386
+ preg_match( '|<wp:base_site_url>(.*?)</wp:base_site_url>|is', $importline, $url );
387
+ $this->base_url = $url[1];
388
+ continue;
389
+ }
390
+ if ( false !== strpos( $importline, '<wp:category>' ) ) {
391
+ preg_match( '|<wp:category>(.*?)</wp:category>|is', $importline, $category );
392
+ $this->categories[] = $this->process_category( $category[1] );
393
+ continue;
394
+ }
395
+ if ( false !== strpos( $importline, '<wp:tag>' ) ) {
396
+ preg_match( '|<wp:tag>(.*?)</wp:tag>|is', $importline, $tag );
397
+ $this->tags[] = $this->process_tag( $tag[1] );
398
+ continue;
399
+ }
400
+ if ( false !== strpos( $importline, '<wp:term>' ) ) {
401
+ preg_match( '|<wp:term>(.*?)</wp:term>|is', $importline, $term );
402
+ $this->terms[] = $this->process_term( $term[1] );
403
+ continue;
404
+ }
405
+ if ( false !== strpos( $importline, '<wp:author>' ) ) {
406
+ preg_match( '|<wp:author>(.*?)</wp:author>|is', $importline, $author );
407
+ $a = $this->process_author( $author[1] );
408
+ $this->authors[$a['author_login']] = $a;
409
+ continue;
410
+ }
411
+ if ( false !== strpos( $importline, '<item>' ) ) {
412
+ $post = '';
413
+ $in_post = true;
414
+ continue;
415
+ }
416
+ if ( false !== strpos( $importline, '</item>' ) ) {
417
+ $in_post = false;
418
+ $this->posts[] = $this->process_post( $post );
419
+ continue;
420
+ }
421
+ if ( $in_post ) {
422
+ $post .= $importline . "\n";
423
+ }
424
+ }
425
+
426
+ $this->fclose($fp);
427
+ }
428
+
429
+ if ( ! $wxr_version )
430
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
431
+
432
+ return array(
433
+ 'authors' => $this->authors,
434
+ 'posts' => $this->posts,
435
+ 'categories' => $this->categories,
436
+ 'tags' => $this->tags,
437
+ 'terms' => $this->terms,
438
+ 'base_url' => $this->base_url,
439
+ 'version' => $wxr_version
440
+ );
441
+ }
442
+
443
+ function get_tag( $string, $tag ) {
444
+ global $wpdb;
445
+ preg_match( "|<$tag.*?>(.*?)</$tag>|is", $string, $return );
446
+ if ( isset( $return[1] ) ) {
447
+ $return = preg_replace( '|^<!\[CDATA\[(.*)\]\]>$|s', '$1', $return[1] );
448
+ $return = $wpdb->escape( trim( $return ) );
449
+ } else {
450
+ $return = '';
451
+ }
452
+ return $return;
453
+ }
454
+
455
+ function process_category( $c ) {
456
+ return array(
457
+ 'term_id' => $this->get_tag( $c, 'wp:term_id' ),
458
+ 'cat_name' => $this->get_tag( $c, 'wp:cat_name' ),
459
+ 'category_nicename' => $this->get_tag( $c, 'wp:category_nicename' ),
460
+ 'category_parent' => $this->get_tag( $c, 'wp:category_parent' ),
461
+ 'category_description' => $this->get_tag( $c, 'wp:category_description' ),
462
+ );
463
+ }
464
+
465
+ function process_tag( $t ) {
466
+ return array(
467
+ 'term_id' => $this->get_tag( $t, 'wp:term_id' ),
468
+ 'tag_name' => $this->get_tag( $t, 'wp:tag_name' ),
469
+ 'tag_slug' => $this->get_tag( $t, 'wp:tag_slug' ),
470
+ 'tag_description' => $this->get_tag( $t, 'wp:tag_description' ),
471
+ );
472
+ }
473
+
474
+ function process_term( $t ) {
475
+ return array(
476
+ 'term_id' => $this->get_tag( $t, 'wp:term_id' ),
477
+ 'term_taxonomy' => $this->get_tag( $t, 'wp:term_taxonomy' ),
478
+ 'slug' => $this->get_tag( $t, 'wp:term_slug' ),
479
+ 'term_parent' => $this->get_tag( $t, 'wp:term_parent' ),
480
+ 'term_name' => $this->get_tag( $t, 'wp:term_name' ),
481
+ 'term_description' => $this->get_tag( $t, 'wp:term_description' ),
482
+ );
483
+ }
484
+
485
+ function process_author( $a ) {
486
+ return array(
487
+ 'author_id' => $this->get_tag( $a, 'wp:author_id' ),
488
+ 'author_login' => $this->get_tag( $a, 'wp:author_login' ),
489
+ 'author_email' => $this->get_tag( $a, 'wp:author_email' ),
490
+ 'author_display_name' => $this->get_tag( $a, 'wp:author_display_name' ),
491
+ 'author_first_name' => $this->get_tag( $a, 'wp:author_first_name' ),
492
+ 'author_last_name' => $this->get_tag( $a, 'wp:author_last_name' ),
493
+ );
494
+ }
495
+
496
+ function process_post( $post ) {
497
+ $post_id = $this->get_tag( $post, 'wp:post_id' );
498
+ $post_title = $this->get_tag( $post, 'title' );
499
+ $post_date = $this->get_tag( $post, 'wp:post_date' );
500
+ $post_date_gmt = $this->get_tag( $post, 'wp:post_date_gmt' );
501
+ $comment_status = $this->get_tag( $post, 'wp:comment_status' );
502
+ $ping_status = $this->get_tag( $post, 'wp:ping_status' );
503
+ $status = $this->get_tag( $post, 'wp:status' );
504
+ $post_name = $this->get_tag( $post, 'wp:post_name' );
505
+ $post_parent = $this->get_tag( $post, 'wp:post_parent' );
506
+ $menu_order = $this->get_tag( $post, 'wp:menu_order' );
507
+ $post_type = $this->get_tag( $post, 'wp:post_type' );
508
+ $post_password = $this->get_tag( $post, 'wp:post_password' );
509
+ $is_sticky = $this->get_tag( $post, 'wp:is_sticky' );
510
+ $guid = $this->get_tag( $post, 'guid' );
511
+ $post_author = $this->get_tag( $post, 'dc:creator' );
512
+
513
+ $post_excerpt = $this->get_tag( $post, 'excerpt:encoded' );
514
+ $post_excerpt = preg_replace_callback( '|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_excerpt );
515
+ $post_excerpt = str_replace( '<br>', '<br />', $post_excerpt );
516
+ $post_excerpt = str_replace( '<hr>', '<hr />', $post_excerpt );
517
+
518
+ $post_content = $this->get_tag( $post, 'content:encoded' );
519
+ $post_content = preg_replace_callback( '|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_content );
520
+ $post_content = str_replace( '<br>', '<br />', $post_content );
521
+ $post_content = str_replace( '<hr>', '<hr />', $post_content );
522
+
523
+ $postdata = compact( 'post_id', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_excerpt',
524
+ 'post_title', 'status', 'post_name', 'comment_status', 'ping_status', 'guid', 'post_parent',
525
+ 'menu_order', 'post_type', 'post_password', 'is_sticky'
526
+ );
527
+
528
+ preg_match_all( '|<category domain="([^"]+?)" nicename="([^"]+?)">(.+?)</category>|is', $post, $terms, PREG_SET_ORDER );
529
+ foreach ( $terms as $t ) {
530
+ $post_terms[] = array(
531
+ 'slug' => $t[2],
532
+ 'domain' => $t[1],
533
+ 'name' => str_replace( array( '<![CDATA[', ']]>' ), '', $t[3] ),
534
+ );
535
+ }
536
+ if ( ! empty( $post_terms ) ) $postdata['terms'] = $post_terms;
537
+
538
+ preg_match_all( '|<wp:comment>(.+?)</wp:comment>|is', $post, $comments );
539
+ $comments = $comments[1];
540
+ if ( $comments ) {
541
+ foreach ( $comments as $comment ) {
542
+ $post_comments[] = array(
543
+ 'comment_id' => $this->get_tag( $comment, 'wp:comment_id' ),
544
+ 'comment_author' => $this->get_tag( $comment, 'wp:comment_author' ),
545
+ 'comment_author_email' => $this->get_tag( $comment, 'wp:comment_author_email' ),
546
+ 'comment_author_IP' => $this->get_tag( $comment, 'wp:comment_author_IP' ),
547
+ 'comment_author_url' => $this->get_tag( $comment, 'wp:comment_author_url' ),
548
+ 'comment_date' => $this->get_tag( $comment, 'wp:comment_date' ),
549
+ 'comment_date_gmt' => $this->get_tag( $comment, 'wp:comment_date_gmt' ),
550
+ 'comment_content' => $this->get_tag( $comment, 'wp:comment_content' ),
551
+ 'comment_approved' => $this->get_tag( $comment, 'wp:comment_approved' ),
552
+ 'comment_type' => $this->get_tag( $comment, 'wp:comment_type' ),
553
+ 'comment_parent' => $this->get_tag( $comment, 'wp:comment_parent' ),
554
+ );
555
+ }
556
+ }
557
+ if ( ! empty( $post_comments ) ) $postdata['comments'] = $post_comments;
558
+
559
+ preg_match_all( '|<wp:postmeta>(.+?)</wp:postmeta>|is', $post, $postmeta );
560
+ $postmeta = $postmeta[1];
561
+ if ( $postmeta ) {
562
+ foreach ( $postmeta as $p ) {
563
+ $post_postmeta[] = array(
564
+ 'key' => $this->get_tag( $p, 'wp:meta_key' ),
565
+ 'value' => $this->get_tag( $p, 'wp:meta_value' ),
566
+ );
567
+ }
568
+ }
569
+ if ( ! empty( $post_postmeta ) ) $postdata['postmeta'] = $post_postmeta;
570
+
571
+ return $postdata;
572
+ }
573
+
574
+ function _normalize_tag( $matches ) {
575
+ return '<' . strtolower( $matches[1] );
576
+ }
577
+
578
+ function fopen( $filename, $mode = 'r' ) {
579
+ if ( $this->has_gzip )
580
+ return gzopen( $filename, $mode );
581
+ return fopen( $filename, $mode );
582
+ }
583
+
584
+ function feof( $fp ) {
585
+ if ( $this->has_gzip )
586
+ return gzeof( $fp );
587
+ return feof( $fp );
588
+ }
589
+
590
+ function fgets( $fp, $len = 8192 ) {
591
+ if ( $this->has_gzip )
592
+ return gzgets( $fp, $len );
593
+ return fgets( $fp, $len );
594
+ }
595
+
596
+ function fclose( $fp ) {
597
+ if ( $this->has_gzip )
598
+ return gzclose( $fp );
599
+ return fclose( $fp );
600
+ }
601
+ }
readme.txt CHANGED
@@ -3,26 +3,39 @@ Contributors: wordpressdotorg
3
  Donate link:
4
  Tags: importer, wordpress
5
  Requires at least: 3.0
6
- Tested up to: 3.0
7
  Stable tag: 0.2
8
 
9
- Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.
10
 
11
  == Description ==
12
 
13
- Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.
14
 
15
  == Installation ==
16
 
17
  1. Upload the `wordpress-importer` folder to the `/wp-content/plugins/` directory
18
  1. Activate the plugin through the 'Plugins' menu in WordPress
19
- 1. Go to the Tools -> Import screen, Click on WordPress
20
-
21
- == Frequently Asked Questions ==
22
-
23
- == Screenshots ==
24
 
25
  == Changelog ==
26
 
 
 
 
 
 
27
  = 0.1 =
28
  * Initial release
 
 
 
 
 
 
 
 
 
 
 
 
3
  Donate link:
4
  Tags: importer, wordpress
5
  Requires at least: 3.0
6
+ Tested up to: 3.1
7
  Stable tag: 0.2
8
 
9
+ Import posts, pages, comments, custom fields, categories, tags and more from a WordPress export file.
10
 
11
  == Description ==
12
 
13
+ Import posts, pages, comments, custom fields, categories, tags and more from a WordPress export file.
14
 
15
  == Installation ==
16
 
17
  1. Upload the `wordpress-importer` folder to the `/wp-content/plugins/` directory
18
  1. Activate the plugin through the 'Plugins' menu in WordPress
19
+ 1. Go to the Tools -> Import screen, click on WordPress
 
 
 
 
20
 
21
  == Changelog ==
22
 
23
+ = 0.3 =
24
+ * Use an XML Parser if possible
25
+ * Proper import support for nav menus
26
+ * ... and more, see [Trac ticket #15197](http://core.trac.wordpress.org/ticket/15197)
27
+
28
  = 0.1 =
29
  * Initial release
30
+
31
+ == Upgrade Notice ==
32
+
33
+ = 0.3 =
34
+ Upgrade for a more robust and reliable experience when importing WordPress export files, and for compatibility with WordPress 3.1.
35
+
36
+ == Filters ==
37
+
38
+ The importer has a couple of filters to allow you to completely enable/block certain features:
39
+ * `import_allow_create_users`: return false if you only want to allow mapping to existing users
40
+ * `import_allow_fetch_attachments`: return false if you do not wish to allow importing and downloading of attachments
41
+ * `import_attachment_size_limit`: return an integer value for the maximum file size in bytes to save (default is 0, which is unlimited)
wordpress-importer.php CHANGED
@@ -2,920 +2,1059 @@
2
  /*
3
  Plugin Name: WordPress Importer
4
  Plugin URI: http://wordpress.org/extend/plugins/wordpress-importer/
5
- Description: Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.
6
  Author: wordpressdotorg
7
  Author URI: http://wordpress.org/
8
- Version: 0.2
9
- Stable tag: 0.2
10
- License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11
  */
12
 
13
- if ( !defined('WP_LOAD_IMPORTERS') )
14
  return;
15
 
 
 
 
16
  // Load Importer API
17
  require_once ABSPATH . 'wp-admin/includes/import.php';
18
 
19
- if ( !class_exists( 'WP_Importer' ) ) {
20
  $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
21
  if ( file_exists( $class_wp_importer ) )
22
- require_once $class_wp_importer;
23
  }
24
 
 
 
 
25
  /**
26
- * WordPress Importer
27
  *
28
  * @package WordPress
29
  * @subpackage Importer
30
  */
31
  if ( class_exists( 'WP_Importer' ) ) {
32
  class WP_Import extends WP_Importer {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- var $post_ids_processed = array ();
35
- var $orphans = array ();
36
- var $file;
37
- var $id;
38
- var $mtnames = array ();
39
- var $newauthornames = array ();
40
- var $allauthornames = array ();
41
-
42
- var $author_ids = array ();
43
- var $tags = array ();
44
- var $categories = array ();
45
- var $terms = array ();
46
- var $authors = array ();
47
-
48
- var $j = -1;
49
  var $fetch_attachments = false;
50
- var $url_remap = array ();
51
-
52
- function header() {
53
- echo '<div class="wrap">';
54
- screen_icon();
55
- echo '<h2>'.__('Import WordPress', 'wordpress-importer').'</h2>';
56
- }
57
 
58
- function footer() {
59
- echo '</div>';
60
- }
61
 
62
- function greet() {
63
- echo '<div class="narrow">';
64
- echo '<p>'.__('Howdy! Upload your WordPress eXtended RSS (WXR) file and we&#8217;ll import the posts, pages, comments, custom fields, categories, and tags into this site.', 'wordpress-importer').'</p>';
65
- echo '<p>'.__('Choose a WordPress WXR file to upload, then click Upload file and import.', 'wordpress-importer').'</p>';
66
- wp_import_upload_form("admin.php?import=wordpress&amp;step=1");
67
- echo '</div>';
68
- }
69
 
70
- function get_tag( $string, $tag ) {
71
- global $wpdb;
72
- preg_match("|<$tag.*?>(.*?)</$tag>|is", $string, $return);
73
- if ( isset($return[1]) ) {
74
- $return = preg_replace('|^<!\[CDATA\[(.*)\]\]>$|s', '$1', $return[1]);
75
- $return = $wpdb->escape( trim( $return ) );
76
- } else {
77
- $return = '';
 
 
 
 
 
 
 
 
 
 
78
  }
79
- return $return;
80
- }
81
 
82
- function has_gzip() {
83
- return is_callable('gzopen');
84
- }
85
-
86
- function fopen($filename, $mode='r') {
87
- if ( $this->has_gzip() )
88
- return gzopen($filename, $mode);
89
- return fopen($filename, $mode);
90
  }
91
 
92
- function feof($fp) {
93
- if ( $this->has_gzip() )
94
- return gzeof($fp);
95
- return feof($fp);
96
- }
 
 
97
 
98
- function fgets($fp, $len=8192) {
99
- if ( $this->has_gzip() )
100
- return gzgets($fp, $len);
101
- return fgets($fp, $len);
102
- }
103
 
104
- function fclose($fp) {
105
- if ( $this->has_gzip() )
106
- return gzclose($fp);
107
- return fclose($fp);
108
- }
109
 
110
- function get_entries($process_post_func=NULL) {
111
- set_magic_quotes_runtime(0);
 
 
 
 
112
 
113
- $doing_entry = false;
114
- $is_wxr_file = false;
 
 
115
 
116
- $fp = $this->fopen($this->file, 'r');
117
- if ($fp) {
118
- while ( !$this->feof($fp) ) {
119
- $importline = rtrim($this->fgets($fp));
120
 
121
- // this doesn't check that the file is perfectly valid but will at least confirm that it's not the wrong format altogether
122
- if ( !$is_wxr_file && preg_match('|xmlns:wp="http://wordpress[.]org/export/\d+[.]\d+/"|', $importline) )
123
- $is_wxr_file = true;
 
 
 
 
 
 
 
 
 
124
 
125
- if ( false !== strpos($importline, '<wp:base_site_url>') ) {
126
- preg_match('|<wp:base_site_url>(.*?)</wp:base_site_url>|is', $importline, $url);
127
- $this->base_url = $url[1];
128
- continue;
129
- }
130
- if ( false !== strpos($importline, '<wp:category>') ) {
131
- preg_match('|<wp:category>(.*?)</wp:category>|is', $importline, $category);
132
- $this->categories[] = $category[1];
133
- continue;
134
- }
135
- if ( false !== strpos($importline, '<wp:tag>') ) {
136
- preg_match('|<wp:tag>(.*?)</wp:tag>|is', $importline, $tag);
137
- $this->tags[] = $tag[1];
138
- continue;
139
- }
140
- if ( false !== strpos($importline, '<wp:term>') ) {
141
- preg_match('|<wp:term>(.*?)</wp:term>|is', $importline, $term);
142
- $this->terms[] = $term[1];
143
- continue;
144
- }
145
- if ( false !== strpos($importline, '<wp:author>') ) {
146
- preg_match('|<wp:author>(.*?)</wp:author>|is', $importline, $author);
147
- $this->authors[] = $author[1];
148
- continue;
149
- }
150
- if ( false !== strpos($importline, '<item>') ) {
151
- $this->post = '';
152
- $doing_entry = true;
153
- continue;
154
- }
155
- if ( false !== strpos($importline, '</item>') ) {
156
- $doing_entry = false;
157
- if ($process_post_func)
158
- call_user_func($process_post_func, $this->post);
159
- continue;
160
- }
161
- if ( $doing_entry ) {
162
- $this->post .= $importline . "\n";
163
- }
164
- }
165
 
166
- $this->fclose($fp);
 
 
 
 
167
  }
168
 
169
- return $is_wxr_file;
 
 
 
 
 
 
 
 
 
170
 
 
171
  }
172
 
173
- function get_wp_authors() {
174
- // We need to find unique values of author names, while preserving the order, so this function emulates the unique_value(); php function, without the sorting.
175
- $temp = $this->allauthornames;
176
- $authors[0] = array_shift($temp);
177
- $y = count($temp) + 1;
178
- for ($x = 1; $x < $y; $x ++) {
179
- $next = array_shift($temp);
180
- if (!(in_array($next, $authors)))
181
- array_push($authors, $next);
 
182
  }
183
 
184
- return $authors;
 
 
 
 
 
 
185
  }
186
 
187
- function get_authors_from_post() {
188
- global $current_user;
 
 
 
 
 
 
189
 
190
- // this will populate $this->author_ids with a list of author_names => user_ids
 
 
 
 
191
 
192
- foreach ( (array) $_POST['author_in'] as $i => $in_author_name ) {
 
 
 
 
 
 
193
 
194
- if ( !empty($_POST['user_select'][$i]) ) {
195
- // an existing user was selected in the dropdown list
196
- $user = get_userdata( intval($_POST['user_select'][$i]) );
197
- if ( isset($user->ID) )
198
- $this->author_ids[$in_author_name] = $user->ID;
199
- }
200
- elseif ( $this->allow_create_users() ) {
201
- // nothing was selected in the dropdown list, so we'll use the name in the text field
202
 
203
- $new_author_name = trim($_POST['user_create'][$i]);
204
- // if the user didn't enter a name, assume they want to use the same name as in the import file
205
- if ( empty($new_author_name) )
206
- $new_author_name = $in_author_name;
207
 
208
- $user_id = username_exists($new_author_name);
209
- if ( !$user_id ) {
210
- $user_id = wp_create_user($new_author_name, wp_generate_password());
211
- }
212
 
213
- if ( !is_wp_error( $user_id ) ) {
214
- $this->author_ids[$in_author_name] = $user_id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  }
216
- }
217
 
218
- // failsafe: if the user_id was invalid, default to the current user
219
- if ( empty($this->author_ids[$in_author_name]) ) {
220
- $this->author_ids[$in_author_name] = intval($current_user->ID);
 
 
221
  }
222
  }
223
-
224
  }
225
 
226
- function wp_authors_form() {
 
 
 
 
 
227
  ?>
228
- <h2><?php _e('Assign Authors', 'wordpress-importer'); ?></h2>
229
- <p><?php _e('To make it easier for you to edit and save the imported posts and drafts, you may want to change the name of the author of the posts. For example, you may want to import all the entries as <code>admin</code>s entries.', 'wordpress-importer'); ?></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  <?php
231
- if ( $this->allow_create_users() ) {
232
- echo '<p>'.__('If a new user is created by WordPress, a password will be randomly generated. Manually change the user&#8217;s details if necessary.', 'wordpress-importer')."</p>\n";
233
  }
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
- $authors = $this->get_wp_authors();
237
- echo '<form action="?import=wordpress&amp;step=2&amp;id=' . $this->id . '" method="post">';
238
- wp_nonce_field('import-wordpress');
239
- ?>
240
- <ol id="authors">
241
- <?php
242
- $j = -1;
243
- foreach ($authors as $author) {
244
- ++ $j;
245
- echo '<li>'.__('Import author:', 'wordpress-importer').' <strong>'.$author.'</strong><br />';
246
- $this->users_form($j, $author);
247
- echo '</li>';
248
- }
249
-
250
- if ( $this->allow_fetch_attachments() ) {
251
- ?>
252
- </ol>
253
- <h2><?php _e('Import Attachments', 'wordpress-importer'); ?></h2>
254
- <p>
255
- <input type="checkbox" value="1" name="attachments" id="import-attachments" />
256
- <label for="import-attachments"><?php _e('Download and import file attachments', 'wordpress-importer') ?></label>
257
- </p>
258
-
259
- <?php
260
  }
261
 
262
- echo '<p class="submit">';
263
- echo '<input type="submit" class="button" value="'. esc_attr__('Submit', 'wordpress-importer') .'" />'.'<br />';
264
- echo '</p>';
265
- echo '</form>';
 
 
266
 
 
 
267
  }
268
 
269
- function users_form($n, $author) {
270
-
271
- if ( $this->allow_create_users() ) {
272
- printf('<label>'.__('Create user %1$s or map to existing', 'wordpress-importer'), ' <input type="text" value="'. esc_attr($author) .'" name="'.'user_create['.intval($n).']'.'" maxlength="30" /></label> <br />');
273
- }
274
- else {
275
- echo __('Map to existing', 'wordpress-importer').'<br />';
276
- }
277
 
278
- // keep track of $n => $author name
279
- echo '<input type="hidden" name="author_in['.intval($n).']" value="' . esc_attr($author).'" />';
280
 
281
- $users = get_users_of_blog();
282
- ?><select name="user_select[<?php echo $n; ?>]">
283
- <option value="0"><?php _e('- Select -', 'wordpress-importer'); ?></option>
284
- <?php
285
- foreach ($users as $user) {
286
- echo '<option value="'.$user->user_id.'">'.$user->user_login.'</option>';
287
- }
288
- ?>
289
- </select>
290
- <?php
291
- }
292
 
293
- function select_authors() {
294
- $is_wxr_file = $this->get_entries(array(&$this, 'process_author'));
295
- if ( $is_wxr_file ) {
296
- $this->wp_authors_form();
297
- }
298
- else {
299
- echo '<h2>'.__('Invalid file', 'wordpress-importer').'</h2>';
300
- echo '<p>'.__('Please upload a valid WXR (WordPress eXtended RSS) export file.', 'wordpress-importer').'</p>';
301
- }
302
- }
303
-
304
- // fetch the user ID for a given author name, respecting the mapping preferences
305
- function checkauthor($author) {
306
- global $current_user;
 
 
 
 
 
 
 
307
 
308
- if ( !empty($this->author_ids[$author]) )
309
- return $this->author_ids[$author];
 
 
 
 
 
 
 
 
 
310
 
311
- // failsafe: map to the current user
312
- return $current_user->ID;
 
 
 
 
 
313
  }
314
 
315
-
316
-
 
 
 
317
  function process_categories() {
318
- global $wpdb;
319
-
320
- $cat_names = (array) get_terms('category', array('fields' => 'names'));
321
-
322
- while ( $c = array_shift($this->categories) ) {
323
- $cat_name = trim($this->get_tag( $c, 'wp:cat_name' ));
324
-
325
- // If the category exists we leave it alone
326
- if ( in_array($cat_name, $cat_names) )
327
  continue;
 
328
 
329
- $category_nicename = $this->get_tag( $c, 'wp:category_nicename' );
330
- $category_description = $this->get_tag( $c, 'wp:category_description' );
331
- $posts_private = (int) $this->get_tag( $c, 'wp:posts_private' );
332
- $links_private = (int) $this->get_tag( $c, 'wp:links_private' );
333
-
334
- $parent = $this->get_tag( $c, 'wp:category_parent' );
335
-
336
- if ( empty($parent) )
337
- $category_parent = '0';
338
- else
339
- $category_parent = category_exists($parent);
340
-
341
- $catarr = compact('category_nicename', 'category_parent', 'posts_private', 'links_private', 'posts_private', 'cat_name', 'category_description');
342
-
343
- print '<em>' . sprintf( __( 'Importing category <em>%s</em>&#8230;' , 'wordpress-importer'), esc_html($cat_name) ) . '</em><br />' . "\n";
344
- $cat_ID = wp_insert_category($catarr);
 
 
 
345
  }
 
 
346
  }
347
 
 
 
 
 
 
348
  function process_tags() {
349
- global $wpdb;
350
-
351
- $tag_names = (array) get_terms('post_tag', array('fields' => 'names'));
352
-
353
- while ( $c = array_shift($this->tags) ) {
354
- $tag_name = trim($this->get_tag( $c, 'wp:tag_name' ));
355
-
356
- // If the category exists we leave it alone
357
- if ( in_array($tag_name, $tag_names) )
358
  continue;
 
359
 
360
- $slug = $this->get_tag( $c, 'wp:tag_slug' );
361
- $description = $this->get_tag( $c, 'wp:tag_description' );
362
-
363
- $tagarr = compact('slug', 'description');
364
 
365
- print '<em>' . sprintf( __( 'Importing tag <em>%s</em>&#8230;' , 'wordpress-importer'), esc_html($tag_name) ) . '</em><br />' . "\n";
366
- $tag_ID = wp_insert_term($tag_name, 'post_tag', $tagarr);
367
- }
368
- }
369
-
370
- function process_terms() {
371
- global $wpdb, $wp_taxonomies;
372
-
373
- $custom_taxonomies = $wp_taxonomies;
374
- // get rid of the standard taxonomies
375
- unset( $custom_taxonomies['category'] );
376
- unset( $custom_taxonomies['post_tag'] );
377
- unset( $custom_taxonomies['link_category'] );
378
-
379
- $custom_taxonomies = array_keys( $custom_taxonomies );
380
- $current_terms = (array) get_terms( $custom_taxonomies, array('get' => 'all') );
381
- $taxonomies = array();
382
- foreach ( $current_terms as $term ) {
383
- if ( isset( $_terms[$term->taxonomy] ) ) {
384
- $taxonomies[$term->taxonomy] = array_merge( $taxonomies[$term->taxonomy], array($term->name) );
385
  } else {
386
- $taxonomies[$term->taxonomy] = array($term->name);
 
 
 
 
387
  }
388
  }
389
 
390
- while ( $c = array_shift($this->terms) ) {
391
- $term_name = trim($this->get_tag( $c, 'wp:term_name' ));
392
- $term_taxonomy = trim($this->get_tag( $c, 'wp:term_taxonomy' ));
393
 
394
- // If the term exists in the taxonomy we leave it alone
395
- if ( isset($taxonomies[$term_taxonomy] ) && in_array( $term_name, $taxonomies[$term_taxonomy] ) )
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  continue;
 
397
 
398
- $slug = $this->get_tag( $c, 'wp:term_slug' );
399
- $description = $this->get_tag( $c, 'wp:term_description' );
400
-
401
- $termarr = compact('slug', 'description');
 
 
 
 
402
 
403
- print '<em>' . sprintf( __( 'Importing <em>%s</em>&#8230;' , 'wordpress-importer'), esc_html($term_name) ) . '</em><br />' . "\n";
404
- $term_ID = wp_insert_term($term_name, $this->get_tag( $c, 'wp:term_taxonomy' ), $termarr);
 
 
 
 
 
 
 
 
405
  }
406
- }
407
 
408
- function process_author($post) {
409
- $author = $this->get_tag( $post, 'dc:creator' );
410
- if ($author)
411
- $this->allauthornames[] = $author;
412
  }
413
 
 
 
 
 
 
 
 
 
414
  function process_posts() {
415
- echo '<ol>';
416
-
417
- $this->get_entries(array(&$this, 'process_post'));
418
-
419
- echo '</ol>';
420
-
421
- wp_import_cleanup($this->id);
422
- do_action('import_done', 'wordpress');
423
-
424
- echo '<h3>'.sprintf(__('All done.', 'wordpress-importer').' <a href="%s">'.__('Have fun!', 'wordpress-importer').'</a>', get_option('home')).'</h3>';
425
- }
426
-
427
- function _normalize_tag( $matches ) {
428
- return '<' . strtolower( $matches[1] );
429
- }
430
-
431
- function process_post($post) {
432
- global $wpdb;
433
-
434
- $post_ID = (int) $this->get_tag( $post, 'wp:post_id' );
435
- if ( $post_ID && !empty($this->post_ids_processed[$post_ID]) ) // Processed already
436
- return 0;
437
-
438
- set_time_limit( 60 );
439
-
440
- // There are only ever one of these
441
- $post_title = $this->get_tag( $post, 'title' );
442
- $post_date = $this->get_tag( $post, 'wp:post_date' );
443
- $post_date_gmt = $this->get_tag( $post, 'wp:post_date_gmt' );
444
- $comment_status = $this->get_tag( $post, 'wp:comment_status' );
445
- $ping_status = $this->get_tag( $post, 'wp:ping_status' );
446
- $post_status = $this->get_tag( $post, 'wp:status' );
447
- $post_name = $this->get_tag( $post, 'wp:post_name' );
448
- $post_parent = $this->get_tag( $post, 'wp:post_parent' );
449
- $menu_order = $this->get_tag( $post, 'wp:menu_order' );
450
- $post_type = $this->get_tag( $post, 'wp:post_type' );
451
- $post_password = $this->get_tag( $post, 'wp:post_password' );
452
- $is_sticky = $this->get_tag( $post, 'wp:is_sticky' );
453
- $guid = $this->get_tag( $post, 'guid' );
454
- $post_author = $this->get_tag( $post, 'dc:creator' );
455
-
456
- $post_excerpt = $this->get_tag( $post, 'excerpt:encoded' );
457
- $post_excerpt = preg_replace_callback('|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_excerpt);
458
- $post_excerpt = str_replace('<br>', '<br />', $post_excerpt);
459
- $post_excerpt = str_replace('<hr>', '<hr />', $post_excerpt);
460
-
461
- $post_content = $this->get_tag( $post, 'content:encoded' );
462
- $post_content = preg_replace_callback('|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_content);
463
- $post_content = str_replace('<br>', '<br />', $post_content);
464
- $post_content = str_replace('<hr>', '<hr />', $post_content);
465
-
466
- preg_match_all('|<category domain="tag">(.*?)</category>|is', $post, $tags);
467
- $tags = $tags[1];
468
-
469
- $tag_index = 0;
470
- foreach ($tags as $tag) {
471
- $tags[$tag_index] = $wpdb->escape( html_entity_decode( str_replace(array( '<![CDATA[', ']]>' ), '', $tag ) ) );
472
- $tag_index++;
473
- }
474
 
475
- preg_match_all('|<category>(.*?)</category>|is', $post, $categories);
476
- $categories = $categories[1];
477
 
478
- $cat_index = 0;
479
- foreach ($categories as $category) {
480
- $categories[$cat_index] = $wpdb->escape( html_entity_decode( str_replace( array( '<![CDATA[', ']]>' ), '', $category ) ) );
481
- $cat_index++;
482
- }
483
 
484
- $post_exists = post_exists($post_title, '', $post_date);
 
 
 
485
 
486
- if ( $post_exists ) {
487
- echo '<li>';
488
- printf(__('Post <em>%s</em> already exists.', 'wordpress-importer'), stripslashes($post_title));
489
- $comment_post_ID = $post_id = $post_exists;
490
- } else {
491
 
492
- // If it has parent, process parent first.
493
- $post_parent = (int) $post_parent;
494
- if ($post_parent) {
495
- // if we already know the parent, map it to the local ID
496
- if ( isset( $this->post_ids_processed[$post_parent] ) ) {
497
- $post_parent = $this->post_ids_processed[$post_parent]; // new ID of the parent
498
- }
499
- else {
500
- // record the parent for later
501
- $this->orphans[intval($post_ID)] = $post_parent;
 
 
 
 
 
 
502
  }
503
- }
504
-
505
- echo '<li>';
506
 
507
- $post_author = $this->checkauthor($post_author); //just so that if a post already exists, new users are not created by checkauthor
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
 
509
- $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_excerpt', 'post_title', 'post_status', 'post_name', 'comment_status', 'ping_status', 'guid', 'post_parent', 'menu_order', 'post_type', 'post_password');
510
- $postdata['import_id'] = $post_ID;
511
- if ($post_type == 'attachment') {
512
- $remote_url = $this->get_tag( $post, 'wp:attachment_url' );
513
- if ( !$remote_url )
514
- $remote_url = $guid;
 
 
515
 
516
- $comment_post_ID = $post_id = $this->process_attachment($postdata, $remote_url);
517
- if ( !$post_id or is_wp_error($post_id) )
518
- return $post_id;
519
- }
520
- else {
521
- printf(__('Importing post <em>%s</em>...', 'wordpress-importer') . "\n", stripslashes($post_title));
522
- $comment_post_ID = $post_id = wp_insert_post($postdata);
523
- if ( $post_id && $is_sticky == 1 )
524
  stick_post( $post_id );
525
-
526
  }
527
 
528
- if ( is_wp_error( $post_id ) )
529
- return $post_id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
530
 
531
- // Memorize old and new ID.
532
- if ( $post_id && $post_ID ) {
533
- $this->post_ids_processed[intval($post_ID)] = intval($post_id);
 
534
  }
535
 
536
- // Add categories.
537
- if (count($categories) > 0) {
538
- $post_cats = array();
539
- foreach ($categories as $category) {
540
- if ( '' == $category )
541
- continue;
542
- $slug = sanitize_term_field('slug', $category, 0, 'category', 'db');
543
- $cat = get_term_by('slug', $slug, 'category');
544
- $cat_ID = 0;
545
- if ( ! empty($cat) )
546
- $cat_ID = $cat->term_id;
547
- if ($cat_ID == 0) {
548
- $category = $wpdb->escape($category);
549
- $cat_ID = wp_insert_category(array('cat_name' => $category));
550
- if ( is_wp_error($cat_ID) )
551
- continue;
 
 
 
 
 
 
 
 
 
 
 
 
552
  }
553
- $post_cats[] = $cat_ID;
554
  }
555
- wp_set_post_categories($post_id, $post_cats);
556
  }
557
 
558
- // Add tags.
559
- if (count($tags) > 0) {
560
- $post_tags = array();
561
- foreach ($tags as $tag) {
562
- if ( '' == $tag )
563
- continue;
564
- $slug = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
565
- $tag_obj = get_term_by('slug', $slug, 'post_tag');
566
- $tag_id = 0;
567
- if ( ! empty($tag_obj) )
568
- $tag_id = $tag_obj->term_id;
569
- if ( $tag_id == 0 ) {
570
- $tag = $wpdb->escape($tag);
571
- $tag_id = wp_insert_term($tag, 'post_tag');
572
- if ( is_wp_error($tag_id) )
573
- continue;
574
- $tag_id = $tag_id['term_id'];
 
 
 
 
 
 
 
575
  }
576
- $post_tags[] = intval($tag_id);
577
  }
578
- wp_set_post_tags($post_id, $post_tags);
579
  }
580
  }
581
 
582
- // Now for comments
583
- preg_match_all('|<wp:comment>(.*?)</wp:comment>|is', $post, $comments);
584
- $comments = $comments[1];
585
- $num_comments = 0;
586
- $inserted_comments = array();
587
- if ( $comments) {
588
- foreach ($comments as $comment) {
589
- $comment_id = $this->get_tag( $comment, 'wp:comment_id');
590
- $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID;
591
- $newcomments[$comment_id]['comment_author'] = $this->get_tag( $comment, 'wp:comment_author');
592
- $newcomments[$comment_id]['comment_author_email'] = $this->get_tag( $comment, 'wp:comment_author_email');
593
- $newcomments[$comment_id]['comment_author_IP'] = $this->get_tag( $comment, 'wp:comment_author_IP');
594
- $newcomments[$comment_id]['comment_author_url'] = $this->get_tag( $comment, 'wp:comment_author_url');
595
- $newcomments[$comment_id]['comment_date'] = $this->get_tag( $comment, 'wp:comment_date');
596
- $newcomments[$comment_id]['comment_date_gmt'] = $this->get_tag( $comment, 'wp:comment_date_gmt');
597
- $newcomments[$comment_id]['comment_content'] = $this->get_tag( $comment, 'wp:comment_content');
598
- $newcomments[$comment_id]['comment_approved'] = $this->get_tag( $comment, 'wp:comment_approved');
599
- $newcomments[$comment_id]['comment_type'] = $this->get_tag( $comment, 'wp:comment_type');
600
- $newcomments[$comment_id]['comment_parent'] = $this->get_tag( $comment, 'wp:comment_parent');
601
- }
602
- // Sort by comment ID, to make sure comment parents exist (if there at all)
603
- ksort($newcomments);
604
- foreach ($newcomments as $key => $comment) {
605
- // if this is a new post we can skip the comment_exists() check
606
- if ( !$post_exists || !comment_exists($comment['comment_author'], $comment['comment_date']) ) {
607
- if (isset($inserted_comments[$comment['comment_parent']]))
608
- $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
609
- $comment = wp_filter_comment($comment);
610
- $inserted_comments[$key] = wp_insert_comment($comment);
611
- $num_comments++;
612
  }
613
  }
614
  }
615
 
616
- if ( $num_comments )
617
- printf(' '._n('(%s comment)', '(%s comments)', $num_comments, 'wordpress-importer'), $num_comments);
618
-
619
- // Now for post meta
620
- preg_match_all('|<wp:postmeta>(.*?)</wp:postmeta>|is', $post, $postmeta);
621
- $postmeta = $postmeta[1];
622
- if ( $postmeta) { foreach ($postmeta as $p) {
623
- $key = $this->get_tag( $p, 'wp:meta_key' );
624
- $value = $this->get_tag( $p, 'wp:meta_value' );
625
-
626
- $this->process_post_meta($post_id, $key, $value);
627
-
628
- } }
629
 
630
- do_action('import_post_added', $post_id);
631
- print "</li>\n";
632
- }
 
 
 
 
 
633
 
634
- function process_post_meta($post_id, $key, $value) {
635
- // the filter can return false to skip a particular metadata key
636
- $_key = apply_filters('import_post_meta_key', $key);
637
- if ( $_key ) {
638
- add_post_meta( $post_id, $_key, $value );
639
- do_action('import_post_meta', $post_id, $_key, $value);
 
 
 
 
 
640
  }
641
- }
642
 
643
- function process_attachment($postdata, $remote_url) {
644
- if ($this->fetch_attachments and $remote_url) {
645
- printf( __('Importing attachment <em>%s</em>... ', 'wordpress-importer'), htmlspecialchars($remote_url) );
 
 
 
646
 
647
- // If the URL is absolute, but does not contain http, upload it assuming the base_site_url variable
648
- if ( preg_match('/^\/[\w\W]+$/', $remote_url) )
649
- $remote_url = rtrim($this->base_url,'/').$remote_url;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
 
651
- $upload = $this->fetch_remote_file($postdata, $remote_url);
652
- if ( is_wp_error($upload) ) {
653
- printf( __('Remote file error: %s', 'wordpress-importer'), htmlspecialchars($upload->get_error_message()) );
654
- return $upload;
655
- }
656
- else {
657
- print '('.size_format(filesize($upload['file'])).')';
658
- }
 
 
 
659
 
660
- if ( 0 == filesize( $upload['file'] ) ) {
661
- print __( "Zero length file, deleting" , 'wordpress-importer') . "\n";
662
- unlink( $upload['file'] );
663
- return;
664
- }
665
 
666
- if ( $info = wp_check_filetype($upload['file']) ) {
667
- $postdata['post_mime_type'] = $info['type'];
668
- }
669
- else {
670
- print __('Invalid file type', 'wordpress-importer');
671
- return;
672
- }
673
 
674
- $postdata['guid'] = $upload['url'];
 
 
 
675
 
676
- // as per wp-admin/includes/upload.php
677
- $post_id = wp_insert_attachment($postdata, $upload['file']);
678
- wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
679
 
680
- // remap the thumbnail url. this isn't perfect because we're just guessing the original url.
681
- if ( preg_match('@^image/@', $info['type']) && $thumb_url = wp_get_attachment_thumb_url($post_id) ) {
682
- $parts = pathinfo($remote_url);
683
- $ext = $parts['extension'];
684
- $name = basename($parts['basename'], ".{$ext}");
685
- $this->url_remap[$parts['dirname'] . '/' . $name . '.thumbnail.' . $ext] = $thumb_url;
686
- }
687
 
688
- return $post_id;
689
- }
690
- else {
691
- printf( __('Skipping attachment <em>%s</em>', 'wordpress-importer'), htmlspecialchars($remote_url) );
 
 
692
  }
 
 
693
  }
694
 
695
- function fetch_remote_file( $post, $url ) {
 
 
 
 
 
 
 
696
  add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
697
 
698
- $upload = wp_upload_dir($post['post_date']);
699
-
700
  // extract the file name and extension from the url
701
- $file_name = basename($url);
702
 
703
- // get placeholder file in the upload dir with a unique sanitized filename
704
- $upload = wp_upload_bits( $file_name, 0, '', $post['post_date']);
705
- if ( $upload['error'] ) {
706
- echo $upload['error'];
707
  return new WP_Error( 'upload_dir_error', $upload['error'] );
708
- }
709
 
710
  // fetch the remote url and write it to the placeholder file
711
- $headers = wp_get_http($url, $upload['file']);
712
 
713
- //Request failed
714
  if ( ! $headers ) {
715
- @unlink($upload['file']);
716
  return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') );
717
  }
718
 
719
  // make sure the fetch was successful
720
  if ( $headers['response'] != '200' ) {
721
- @unlink($upload['file']);
722
- return new WP_Error( 'import_file_error', sprintf(__('Remote file returned error response %1$d %2$s', 'wordpress-importer'), $headers['response'], get_status_header_desc($headers['response']) ) );
723
  }
724
- elseif ( isset($headers['content-length']) && filesize($upload['file']) != $headers['content-length'] ) {
725
- @unlink($upload['file']);
 
 
 
726
  return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') );
727
  }
728
 
729
- $max_size = $this->max_attachment_size();
730
- if ( !empty($max_size) and filesize($upload['file']) > $max_size ) {
731
- @unlink($upload['file']);
732
- return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', size_format($max_size), 'wordpress-importer')) );
 
 
 
 
 
733
  }
734
 
735
  // keep track of the old and new urls so we can substitute them later
736
  $this->url_remap[$url] = $upload['url'];
737
  $this->url_remap[$post['guid']] = $upload['url'];
738
  // if the remote url is redirected somewhere else, keep track of the destination too
739
- if ( $headers['x-final-location'] != $url )
740
  $this->url_remap[$headers['x-final-location']] = $upload['url'];
741
 
742
  return $upload;
743
-
744
  }
745
 
746
  /**
747
- * Bump up the request timeout for http requests
748
  *
749
- * @param int $val
750
- * @return int
 
751
  */
752
- function bump_request_timeout( $val ) {
753
- return 60;
754
- }
755
 
756
- // sort by strlen, longest string first
757
- function cmpr_strlen($a, $b) {
758
- return strlen($b) - strlen($a);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
759
  }
760
 
761
- // update url references in post bodies to point to the new local files
 
 
762
  function backfill_attachment_urls() {
763
-
764
  // make sure we do the longest urls first, in case one is a substring of another
765
- uksort($this->url_remap, array(&$this, 'cmpr_strlen'));
766
 
767
- global $wpdb;
768
- foreach ($this->url_remap as $from_url => $to_url) {
769
  // remap urls in post_content
770
- $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, '%s', '%s')", $from_url, $to_url) );
771
  // remap enclosure urls
772
- $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, '%s', '%s') WHERE meta_key='enclosure'", $from_url, $to_url) );
773
  }
774
  }
775
 
776
- // update the post_parent of orphans now that we know the local id's of all parents
777
- function backfill_parents() {
778
- global $wpdb;
779
-
780
- foreach ($this->orphans as $child_id => $parent_id) {
781
- $local_child_id = $local_parent_id = false;
782
- if ( isset( $this->post_ids_processed[$child_id] ) )
783
- $local_child_id = $this->post_ids_processed[$child_id];
784
- if ( isset( $this->post_ids_processed[$parent_id] ) )
785
- $local_parent_id = $this->post_ids_processed[$parent_id];
786
-
787
- if ($local_child_id and $local_parent_id) {
788
- $wpdb->update($wpdb->posts, array('post_parent' => $local_parent_id), array('ID' => $local_child_id) );
789
  }
790
  }
791
  }
792
 
793
- function is_valid_meta_key($key) {
794
- // skip attachment metadata since we'll regenerate it from scratch
795
- if ( $key == '_wp_attached_file' || $key == '_wp_attachment_metadata' )
796
- return false;
797
- return $key;
798
- }
799
-
800
- // give the user the option of creating new users to represent authors in the import file?
801
- function allow_create_users() {
802
- return apply_filters('import_allow_create_users', true);
803
  }
804
 
805
- // give the user the option of downloading and importing attached files
806
- function allow_fetch_attachments() {
807
- return apply_filters('import_allow_fetch_attachments', true);
 
 
 
 
 
 
 
 
 
 
 
808
  }
809
 
810
- function max_attachment_size() {
811
- // can be overridden with a filter - 0 means no limit
812
- return apply_filters('import_attachment_size_limit', 0);
813
  }
814
 
815
- function import_start() {
816
- wp_defer_term_counting(true);
817
- wp_defer_comment_counting(true);
818
- do_action('import_start');
 
 
 
 
 
819
  }
820
 
821
- function import_end() {
822
- do_action('import_end');
823
-
824
- // clear the caches after backfilling
825
- foreach ($this->post_ids_processed as $post_id)
826
- clean_post_cache($post_id);
827
-
828
- wp_defer_term_counting(false);
829
- wp_defer_comment_counting(false);
 
 
 
830
  }
831
 
832
- function import($id, $fetch_attachments = false) {
833
- $this->id = (int) $id;
834
- $this->fetch_attachments = ($this->allow_fetch_attachments() && (bool) $fetch_attachments);
835
-
836
- add_filter('import_post_meta_key', array($this, 'is_valid_meta_key'));
837
- $file = get_attached_file($this->id);
838
- $this->import_file($file);
 
839
  }
840
 
841
- function import_file($file) {
842
- $this->file = $file;
843
-
844
- $this->import_start();
845
- $this->get_authors_from_post();
846
- wp_suspend_cache_invalidation(true);
847
- $this->get_entries();
848
- $this->process_categories();
849
- $this->process_tags();
850
- $this->process_terms();
851
- $result = $this->process_posts();
852
- wp_suspend_cache_invalidation(false);
853
- $this->backfill_parents();
854
- $this->backfill_attachment_urls();
855
- $this->import_end();
856
-
857
- if ( is_wp_error( $result ) )
858
- return $result;
859
  }
860
 
861
- function handle_upload() {
862
- $file = wp_import_handle_upload();
863
- if ( isset($file['error']) ) {
864
- echo '<p>'.__('Sorry, there has been an error.', 'wordpress-importer').'</p>';
865
- echo '<p><strong>' . $file['error'] . '</strong></p>';
866
- return false;
867
- }
868
- $this->file = $file['file'];
869
- $this->id = (int) $file['id'];
870
- return true;
871
  }
872
 
873
- function dispatch() {
874
- if (empty ($_GET['step']))
875
- $step = 0;
876
- else
877
- $step = (int) $_GET['step'];
878
-
879
- $this->header();
880
- switch ($step) {
881
- case 0 :
882
- $this->greet();
883
- break;
884
- case 1 :
885
- check_admin_referer('import-upload');
886
- if ( $this->handle_upload() )
887
- $this->select_authors();
888
- break;
889
- case 2:
890
- check_admin_referer('import-wordpress');
891
- $fetch_attachments = ! empty( $_POST['attachments'] );
892
- $result = $this->import( $_GET['id'], $fetch_attachments);
893
- if ( is_wp_error( $result ) )
894
- echo $result->get_error_message();
895
- break;
896
- }
897
- $this->footer();
898
  }
899
 
900
- function WP_Import() {
901
- // Nothing.
 
902
  }
903
  }
904
 
905
- /**
906
- * Register WordPress Importer
907
- *
908
- * @since unknown
909
- * @var WP_Import
910
- * @name $wp_import
911
- */
912
- $wp_import = new WP_Import();
913
-
914
- register_importer('wordpress', 'WordPress', __('Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer'), array ($wp_import, 'dispatch'));
915
-
916
  } // class_exists( 'WP_Importer' )
917
 
918
  function wordpress_importer_init() {
919
- load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
 
 
 
 
 
 
 
920
  }
921
- add_action( 'init', 'wordpress_importer_init' );
2
  /*
3
  Plugin Name: WordPress Importer
4
  Plugin URI: http://wordpress.org/extend/plugins/wordpress-importer/
5
+ Description: Import posts, pages, comments, custom fields, categories, tags and more from a WordPress export file.
6
  Author: wordpressdotorg
7
  Author URI: http://wordpress.org/
8
+ Version: 0.3
9
+ Text Domain: wordpress-importer
10
+ License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11
  */
12
 
13
+ if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
14
  return;
15
 
16
+ /** Display verbose errors */
17
+ define( 'IMPORT_DEBUG', false );
18
+
19
  // Load Importer API
20
  require_once ABSPATH . 'wp-admin/includes/import.php';
21
 
22
+ if ( ! class_exists( 'WP_Importer' ) ) {
23
  $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
24
  if ( file_exists( $class_wp_importer ) )
25
+ require $class_wp_importer;
26
  }
27
 
28
+ // include WXR file parsers
29
+ require dirname( __FILE__ ) . '/parsers.php';
30
+
31
  /**
32
+ * WordPress Importer class for managing the import process of a WXR file
33
  *
34
  * @package WordPress
35
  * @subpackage Importer
36
  */
37
  if ( class_exists( 'WP_Importer' ) ) {
38
  class WP_Import extends WP_Importer {
39
+ var $max_wxr_version = 1.1; // max. supported WXR version
40
+
41
+ var $id; // WXR attachment ID
42
+
43
+ // information to import from WXR file
44
+ var $version;
45
+ var $authors = array();
46
+ var $posts = array();
47
+ var $terms = array();
48
+ var $categories = array();
49
+ var $tags = array();
50
+ var $base_url = '';
51
+
52
+ // mappings from old information to new
53
+ var $processed_authors = array();
54
+ var $author_mapping = array();
55
+ var $processed_terms = array();
56
+ var $processed_posts = array();
57
+ var $post_orphans = array();
58
+ var $processed_menu_items = array();
59
+ var $menu_item_orphans = array();
60
+ var $missing_menu_items = array();
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  var $fetch_attachments = false;
63
+ var $url_remap = array();
64
+ var $featured_images = array();
 
 
 
 
 
65
 
66
+ function WP_Import() { /* nothing */ }
 
 
67
 
68
+ /**
69
+ * Registered callback function for the WordPress Importer
70
+ *
71
+ * Manages the three separate stages of the WXR import process
72
+ */
73
+ function dispatch() {
74
+ $this->header();
75
 
76
+ $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
77
+ switch ( $step ) {
78
+ case 0:
79
+ $this->greet();
80
+ break;
81
+ case 1:
82
+ check_admin_referer( 'import-upload' );
83
+ if ( $this->handle_upload() )
84
+ $this->import_options();
85
+ break;
86
+ case 2:
87
+ check_admin_referer( 'import-wordpress' );
88
+ $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() );
89
+ $this->id = (int) $_POST['import_id'];
90
+ $file = get_attached_file( $this->id );
91
+ set_time_limit(0);
92
+ $this->import( $file );
93
+ break;
94
  }
 
 
95
 
96
+ $this->footer();
 
 
 
 
 
 
 
97
  }
98
 
99
+ /**
100
+ * The main controller for the actual import stage.
101
+ *
102
+ * @param string $file Path to the WXR file for importing
103
+ */
104
+ function import( $file ) {
105
+ add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
106
 
107
+ $this->import_start( $file );
 
 
 
 
108
 
109
+ $this->get_author_mapping();
 
 
 
 
110
 
111
+ wp_suspend_cache_invalidation( true );
112
+ $this->process_categories();
113
+ $this->process_tags();
114
+ $this->process_terms();
115
+ $this->process_posts();
116
+ wp_suspend_cache_invalidation( false );
117
 
118
+ // update incorrect/missing information in the DB
119
+ $this->backfill_parents();
120
+ $this->backfill_attachment_urls();
121
+ $this->remap_featured_images();
122
 
123
+ $this->import_end();
124
+ }
 
 
125
 
126
+ /**
127
+ * Parses the WXR file and prepares us for the task of processing parsed data
128
+ *
129
+ * @param string $file Path to the WXR file for importing
130
+ */
131
+ function import_start( $file ) {
132
+ if ( ! is_file($file) ) {
133
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
134
+ echo __( 'The file does not exist, please try again.', 'wordpress-importer' ) . '</p>';
135
+ $this->footer();
136
+ die();
137
+ }
138
 
139
+ $import_data = $this->parse( $file );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
+ if ( is_wp_error( $import_data ) ) {
142
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
143
+ echo esc_html( $import_data->get_error_message() ) . '</p>';
144
+ $this->footer();
145
+ die();
146
  }
147
 
148
+ $this->version = $import_data['version'];
149
+ $this->get_authors_from_import( $import_data );
150
+ $this->posts = $import_data['posts'];
151
+ $this->terms = $import_data['terms'];
152
+ $this->categories = $import_data['categories'];
153
+ $this->tags = $import_data['tags'];
154
+ $this->base_url = esc_url( $import_data['base_url'] );
155
+
156
+ wp_defer_term_counting( true );
157
+ wp_defer_comment_counting( true );
158
 
159
+ do_action( 'import_start' );
160
  }
161
 
162
+ /**
163
+ * Performs post-import cleanup of files and the cache
164
+ */
165
+ function import_end() {
166
+ wp_import_cleanup( $this->id );
167
+
168
+ wp_cache_flush();
169
+ foreach ( get_taxonomies() as $tax ) {
170
+ delete_option( "{$tax}_children" );
171
+ _get_term_hierarchy( $tax );
172
  }
173
 
174
+ wp_defer_term_counting( false );
175
+ wp_defer_comment_counting( false );
176
+
177
+ echo '<p>' . __( 'All done.', 'wordpress-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wordpress-importer' ) . '</a>' . '</p>';
178
+ echo '<p>' . __( 'Remember to update the passwords and roles of imported users.', 'wordpress-importer' ) . '</p>';
179
+
180
+ do_action( 'import_end' );
181
  }
182
 
183
+ /**
184
+ * Handles the WXR upload and initial parsing of the file to prepare for
185
+ * displaying author import options
186
+ *
187
+ * @return bool False if error uploading or invalid file, true otherwise
188
+ */
189
+ function handle_upload() {
190
+ $file = wp_import_handle_upload();
191
 
192
+ if ( isset( $file['error'] ) ) {
193
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
194
+ echo esc_html( $file['error'] ) . '</p>';
195
+ return false;
196
+ }
197
 
198
+ $this->id = (int) $file['id'];
199
+ $import_data = $this->parse( $file['file'] );
200
+ if ( is_wp_error( $import_data ) ) {
201
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
202
+ echo esc_html( $import_data->get_error_message() ) . '</p>';
203
+ return false;
204
+ }
205
 
206
+ $this->version = $import_data['version'];
207
+ if ( $this->version > $this->max_wxr_version ) {
208
+ echo '<div class="error"><p><strong>';
209
+ printf( __( 'This WXR file (version %s) may not be supported by this version of the importer. Please consider updating.', 'wordpress-importer' ), esc_html($import_data['version']) );
210
+ echo '</strong></p></div>';
211
+ }
 
 
212
 
213
+ $this->get_authors_from_import( $import_data );
 
 
 
214
 
215
+ return true;
216
+ }
 
 
217
 
218
+ /**
219
+ * Retrieve authors from parsed WXR data
220
+ *
221
+ * Uses the provided author information from WXR 1.1 files
222
+ * or extracts info from each post for WXR 1.0 files
223
+ *
224
+ * @param array $import_data Data returned by a WXR parser
225
+ */
226
+ function get_authors_from_import( $import_data ) {
227
+ if ( ! empty( $import_data['authors'] ) ) {
228
+ $this->authors = $import_data['authors'];
229
+ // no author information, grab it from the posts
230
+ } else {
231
+ foreach ( $import_data['posts'] as $post ) {
232
+ $login = sanitize_user( $post['post_author'], true );
233
+ if ( empty( $login ) ) {
234
+ printf( __( 'Failed to import author %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html( $post['post_author'] ) );
235
+ echo '<br />';
236
+ continue;
237
  }
 
238
 
239
+ if ( ! isset($this->authors[$login]) )
240
+ $this->authors[$login] = array(
241
+ 'author_login' => $login,
242
+ 'author_display_name' => $post['post_author']
243
+ );
244
  }
245
  }
 
246
  }
247
 
248
+ /**
249
+ * Display pre-import options, author importing/mapping and option to
250
+ * fetch attachments
251
+ */
252
+ function import_options() {
253
+ $j = 0;
254
  ?>
255
+ <form action="<?php echo admin_url( 'admin.php?import=wordpress&amp;step=2' ); ?>" method="post">
256
+ <?php wp_nonce_field( 'import-wordpress' ); ?>
257
+ <input type="hidden" name="import_id" value="<?php echo $this->id; ?>" />
258
+
259
+ <?php if ( ! empty( $this->authors ) ) : ?>
260
+ <h3><?php _e( 'Assign Authors', 'wordpress-importer' ); ?></h3>
261
+ <p><?php _e( 'To make it easier for you to edit and save the imported content, you may want to reassign the author of the imported item to an existing user of this site. For example, you may want to import all the entries as <code>admin</code>s entries.', 'wordpress-importer' ); ?></p>
262
+ <?php if ( $this->allow_create_users() ) : ?>
263
+ <p><?php printf( __( 'If a new user is created by WordPress, a new password will be randomly generated and the new user&#8217;s role will be set as %s. Manually changing the new user&#8217;s details will be necessary.', 'wordpress-importer' ), esc_html( get_option('default_role') ) ); ?></p>
264
+ <?php endif; ?>
265
+ <ol id="authors">
266
+ <?php foreach ( $this->authors as $author ) : ?>
267
+ <li><?php $this->author_select( $j++, $author ); ?></li>
268
+ <?php endforeach; ?>
269
+ </ol>
270
+ <?php endif; ?>
271
+
272
+ <?php if ( $this->allow_fetch_attachments() ) : ?>
273
+ <h3><?php _e( 'Import Attachments', 'wordpress-importer' ); ?></h3>
274
+ <p>
275
+ <input type="checkbox" value="1" name="fetch_attachments" id="import-attachments" />
276
+ <label for="import-attachments"><?php _e( 'Download and import file attachments', 'wordpress-importer' ); ?></label>
277
+ </p>
278
+ <?php endif; ?>
279
+
280
+ <p class="submit"><input type="submit" class="button" value="<?php esc_attr_e( 'Submit', 'wordpress-importer' ); ?>" /></p>
281
+ </form>
282
  <?php
 
 
283
  }
284
 
285
+ /**
286
+ * Display import options for an individual author. That is, either create
287
+ * a new user based on import info or map to an existing user
288
+ *
289
+ * @param int $n Index for each author in the form
290
+ * @param array $author Author information, e.g. login, display name, email
291
+ */
292
+ function author_select( $n, $author ) {
293
+ _e( 'Import author:', 'wordpress-importer' );
294
+ echo ' <strong>' . esc_html( $author['author_display_name'] );
295
+ if ( $this->version != '1.0' ) echo ' (' . esc_html( $author['author_login'] ) . ')';
296
+ echo '</strong><br />';
297
+
298
+ if ( $this->version != '1.0' )
299
+ echo '<div style="margin-left:18px">';
300
+
301
+ $create_users = $this->allow_create_users();
302
+ if ( $create_users ) {
303
+ if ( $this->version != '1.0' ) {
304
+ _e( 'or create new user with login name:', 'wordpress-importer' );
305
+ $value = '';
306
+ } else {
307
+ _e( 'as a new user:', 'wordpress-importer' );
308
+ $value = esc_attr( sanitize_user( $author['author_login'], true ) );
309
+ }
310
 
311
+ echo ' <input type="text" name="user_new['.$n.']" value="'. $value .'" /><br />';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  }
313
 
314
+ if ( ! $create_users && $this->version == '1.0' )
315
+ _e( 'assign posts to an existing user:', 'wordpress-importer' );
316
+ else
317
+ _e( 'or assign posts to an existing user:', 'wordpress-importer' );
318
+ wp_dropdown_users( array( 'name' => "user_map[$n]", 'multi' => true, 'show_option_all' => __( '- Select -', 'wordpress-importer' ) ) );
319
+ echo '<input type="hidden" name="imported_authors['.$n.']" value="' . esc_attr( $author['author_login'] ) . '" />';
320
 
321
+ if ( $this->version != '1.0' )
322
+ echo '</div>';
323
  }
324
 
325
+ /**
326
+ * Map old author logins to local user IDs based on decisions made
327
+ * in import options form. Can map to an existing user, create a new user
328
+ * or falls back to the current user in case of error with either of the previous
329
+ */
330
+ function get_author_mapping() {
331
+ if ( ! isset( $_POST['imported_authors'] ) )
332
+ return;
333
 
334
+ $create_users = $this->allow_create_users();
 
335
 
336
+ foreach ( (array) $_POST['imported_authors'] as $i => $old_login ) {
337
+ $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false;
 
 
 
 
 
 
 
 
 
338
 
339
+ if ( ! empty( $_POST['user_map'][$i] ) ) {
340
+ $user = get_userdata( intval($_POST['user_map'][$i]) );
341
+ if ( isset( $user->ID ) ) {
342
+ if ( $old_id )
343
+ $this->processed_authors[$old_id] = $user->ID;
344
+ $this->author_mapping[$old_login] = $user->ID;
345
+ }
346
+ } else if ( $create_users ) {
347
+ if ( ! empty($_POST['user_new'][$i]) ) {
348
+ $user_id = wp_create_user( $_POST['user_new'][$i], wp_generate_password() );
349
+ } else if ( $this->version != '1.0' ) {
350
+ $user_data = array(
351
+ 'user_login' => $old_login,
352
+ 'user_pass' => wp_generate_password(),
353
+ 'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '',
354
+ 'display_name' => $this->authors[$old_login]['author_display_name'],
355
+ 'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '',
356
+ 'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '',
357
+ );
358
+ $user_id = wp_insert_user( $user_data );
359
+ }
360
 
361
+ if ( ! is_wp_error( $user_id ) ) {
362
+ if ( $old_id )
363
+ $this->processed_authors[$old_id] = $user_id;
364
+ $this->author_mapping[$old_login] = $user_id;
365
+ } else {
366
+ printf( __( 'Failed to create new user for %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html($this->authors[$old_login]['author_display_name']) );
367
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
368
+ echo ' ' . $user_id->get_error_message();
369
+ echo '<br />';
370
+ }
371
+ }
372
 
373
+ // failsafe: if the user_id was invalid, default to the current user
374
+ if ( ! isset( $this->author_mapping[$old_login] ) ) {
375
+ if ( $old_id )
376
+ $this->processed_authors[$old_id] = (int) get_current_user_id();
377
+ $this->author_mapping[$old_login] = (int) get_current_user_id();
378
+ }
379
+ }
380
  }
381
 
382
+ /**
383
+ * Create new categories based on import information
384
+ *
385
+ * Doesn't create a new category if its slug already exists
386
+ */
387
  function process_categories() {
388
+ if ( empty( $this->categories ) )
389
+ return;
390
+
391
+ foreach ( $this->categories as $cat ) {
392
+ // if the category already exists leave it alone
393
+ $term_id = term_exists( $cat['category_nicename'], 'category' );
394
+ if ( $term_id ) {
395
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
396
+ $this->processed_terms[intval($cat['term_id'])] = (int) $term_id;
397
  continue;
398
+ }
399
 
400
+ $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] );
401
+ $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : '';
402
+ $catarr = array(
403
+ 'category_nicename' => $cat['category_nicename'],
404
+ 'category_parent' => $category_parent,
405
+ 'cat_name' => $cat['cat_name'],
406
+ 'category_description' => $category_description
407
+ );
408
+
409
+ $id = wp_insert_category( $catarr );
410
+ if ( ! is_wp_error( $id ) ) {
411
+ $this->processed_terms[intval($cat['term_id'])] = $id;
412
+ } else {
413
+ printf( __( 'Failed to import category %s', 'wordpress-importer' ), esc_html($cat['category_nicename']) );
414
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
415
+ echo ': ' . $id->get_error_message();
416
+ echo '<br />';
417
+ continue;
418
+ }
419
  }
420
+
421
+ unset( $this->categories );
422
  }
423
 
424
+ /**
425
+ * Create new post tags based on import information
426
+ *
427
+ * Doesn't create a tag if its slug already exists
428
+ */
429
  function process_tags() {
430
+ if ( empty( $this->tags ) )
431
+ return;
432
+
433
+ foreach ( $this->tags as $tag ) {
434
+ // if the tag already exists leave it alone
435
+ $term_id = term_exists( $tag['tag_slug'], 'post_tag' );
436
+ if ( $term_id ) {
437
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
438
+ $this->processed_terms[intval($tag['term_id'])] = (int) $term_id;
439
  continue;
440
+ }
441
 
442
+ $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : '';
443
+ $tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc );
 
 
444
 
445
+ $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr );
446
+ if ( ! is_wp_error( $id ) ) {
447
+ $this->processed_terms[intval($tag['term_id'])] = $id['term_id'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  } else {
449
+ printf( __( 'Failed to import post tag %s', 'wordpress-importer' ), esc_html($tag['tag_name']) );
450
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
451
+ echo ': ' . $id->get_error_message();
452
+ echo '<br />';
453
+ continue;
454
  }
455
  }
456
 
457
+ unset( $this->tags );
458
+ }
 
459
 
460
+ /**
461
+ * Create new terms based on import information
462
+ *
463
+ * Doesn't create a term its slug already exists
464
+ */
465
+ function process_terms() {
466
+ if ( empty( $this->terms ) )
467
+ return;
468
+
469
+ foreach ( $this->terms as $term ) {
470
+ // if the term already exists in the correct taxonomy leave it alone
471
+ $term_id = term_exists( $term['slug'], $term['term_taxonomy'] );
472
+ if ( $term_id ) {
473
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
474
+ $this->processed_terms[intval($term['term_id'])] = (int) $term_id;
475
  continue;
476
+ }
477
 
478
+ if ( empty( $term['term_parent'] ) ) {
479
+ $parent = 0;
480
+ } else {
481
+ $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] );
482
+ if ( is_array( $parent ) ) $parent = $parent['term_id'];
483
+ }
484
+ $description = isset( $term['term_description'] ) ? $term['term_description'] : '';
485
+ $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) );
486
 
487
+ $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr );
488
+ if ( ! is_wp_error( $id ) ) {
489
+ $this->processed_terms[intval($term['term_id'])] = $id['term_id'];
490
+ } else {
491
+ printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) );
492
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
493
+ echo ': ' . $id->get_error_message();
494
+ echo '<br />';
495
+ continue;
496
+ }
497
  }
 
498
 
499
+ unset( $this->terms );
 
 
 
500
  }
501
 
502
+ /**
503
+ * Create new posts based on import information
504
+ *
505
+ * Posts marked as having a parent which doesn't exist will become top level items.
506
+ * Doesn't create a new post if: the post type doesn't exist, the given post ID
507
+ * is already noted as imported or a post with the same title and date already exists.
508
+ * Note that new/updated terms, comments and meta are imported for the last of the above.
509
+ */
510
  function process_posts() {
511
+ foreach ( $this->posts as $post ) {
512
+ if ( ! post_type_exists( $post['post_type'] ) ) {
513
+ printf( __( 'Failed to import &#8220;%s&#8221;: Invalid post type %s', 'wordpress-importer' ),
514
+ esc_html($post['post_title']), esc_html($post['post_type']) );
515
+ echo '<br />';
516
+ continue;
517
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
 
519
+ if ( isset( $this->processed_posts[$post['post_id']] ) )
520
+ continue;
521
 
522
+ if ( $post['status'] == 'auto-draft' )
523
+ continue;
 
 
 
524
 
525
+ if ( 'nav_menu_item' == $post['post_type'] ) {
526
+ $this->process_menu_item( $post );
527
+ continue;
528
+ }
529
 
530
+ $post_type_object = get_post_type_object( $post['post_type'] );
 
 
 
 
531
 
532
+ $post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
533
+ if ( $post_exists ) {
534
+ printf( __('%s &#8220;%s&#8221; already exists.', 'wordpress-importer'), $post_type_object->labels->singular_name, esc_html($post['post_title']) );
535
+ echo '<br />';
536
+ $comment_post_ID = $post_id = $post_exists;
537
+ } else {
538
+ $post_parent = (int) $post['post_parent'];
539
+ if ( $post_parent ) {
540
+ // if we already know the parent, map it to the new local ID
541
+ if ( isset( $this->processed_posts[$post_parent] ) ) {
542
+ $post_parent = $this->processed_posts[$post_parent];
543
+ // otherwise record the parent for later
544
+ } else {
545
+ $this->post_orphans[intval($post['post_id'])] = $post_parent;
546
+ $post_parent = 0;
547
+ }
548
  }
 
 
 
549
 
550
+ // map the post author
551
+ $author = sanitize_user( $post['post_author'], true );
552
+ if ( isset( $this->author_mapping[$author] ) )
553
+ $author = $this->author_mapping[$author];
554
+ else
555
+ $author = (int) get_current_user_id();
556
+
557
+ $postdata = array(
558
+ 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'],
559
+ 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'],
560
+ 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'],
561
+ 'post_status' => $post['status'], 'post_name' => $post['post_name'],
562
+ 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'],
563
+ 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'],
564
+ 'post_type' => $post['post_type'], 'post_password' => $post['post_password']
565
+ );
566
+
567
+ if ( 'attachment' == $postdata['post_type'] ) {
568
+ $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid'];
569
+ $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url );
570
+ } else {
571
+ $comment_post_ID = $post_id = wp_insert_post( $postdata, true );
572
+ }
573
 
574
+ if ( is_wp_error( $post_id ) ) {
575
+ printf( __( 'Failed to import %s &#8220;%s&#8221;', 'wordpress-importer' ),
576
+ $post_type_object->labels->singular_name, esc_html($post['post_title']) );
577
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
578
+ echo ': ' . $post_id->get_error_message();
579
+ echo '<br />';
580
+ continue;
581
+ }
582
 
583
+ if ( $post['is_sticky'] == 1 )
 
 
 
 
 
 
 
584
  stick_post( $post_id );
 
585
  }
586
 
587
+ // map pre-import ID to local ID
588
+ $this->processed_posts[intval($post['post_id'])] = (int) $post_id;
589
+
590
+ // add categories, tags and other terms
591
+ if ( ! empty( $post['terms'] ) ) {
592
+ $terms_to_set = array();
593
+ foreach ( $post['terms'] as $term ) {
594
+ // back compat with WXR 1.0 map 'tag' to 'post_tag'
595
+ $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain'];
596
+ $term_exists = term_exists( $term['slug'], $taxonomy );
597
+ $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
598
+ if ( ! $term_id ) {
599
+ $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
600
+ if ( ! is_wp_error( $t ) ) {
601
+ $term_id = $t['term_id'];
602
+ } else {
603
+ printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($taxonomy), esc_html($term['name']) );
604
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
605
+ echo ': ' . $t->get_error_message();
606
+ echo '<br />';
607
+ continue;
608
+ }
609
+ }
610
+ $terms_to_set[$taxonomy][] = intval( $term_id );
611
+ }
612
 
613
+ foreach ( $terms_to_set as $tax => $ids ) {
614
+ $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
615
+ }
616
+ unset( $post['terms'], $terms_to_set );
617
  }
618
 
619
+ // add/update comments
620
+ if ( ! empty( $post['comments'] ) ) {
621
+ $num_comments = 0;
622
+ $inserted_comments = array();
623
+ foreach ( $post['comments'] as $comment ) {
624
+ $comment_id = $comment['comment_id'];
625
+ $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID;
626
+ $newcomments[$comment_id]['comment_author'] = $comment['comment_author'];
627
+ $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email'];
628
+ $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP'];
629
+ $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url'];
630
+ $newcomments[$comment_id]['comment_date'] = $comment['comment_date'];
631
+ $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt'];
632
+ $newcomments[$comment_id]['comment_content'] = $comment['comment_content'];
633
+ $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved'];
634
+ $newcomments[$comment_id]['comment_type'] = $comment['comment_type'];
635
+ $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent'];
636
+ }
637
+ ksort( $newcomments );
638
+
639
+ foreach ( $newcomments as $key => $comment ) {
640
+ // if this is a new post we can skip the comment_exists() check
641
+ if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) {
642
+ if ( isset( $inserted_comments[$comment['comment_parent']] ) )
643
+ $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
644
+ $comment = wp_filter_comment( $comment );
645
+ $inserted_comments[$key] = wp_insert_comment( $comment );
646
+ $num_comments++;
647
  }
 
648
  }
649
+ unset( $newcomments, $inserted_comments, $post['comments'] );
650
  }
651
 
652
+ // add/update post meta
653
+ if ( isset( $post['postmeta'] ) ) {
654
+ foreach ( $post['postmeta'] as $meta ) {
655
+ $key = apply_filters( 'import_post_meta_key', $meta['key'] );
656
+ $value = false;
657
+
658
+ if ( '_edit_last' == $key ) {
659
+ if ( isset( $this->processed_authors[intval($meta['value'])] ) )
660
+ $value = $this->processed_authors[intval($meta['value'])];
661
+ else
662
+ $key = false;
663
+ }
664
+
665
+ if ( $key ) {
666
+ // export gets meta straight from the DB so could have a serialized string
667
+ if ( ! $value )
668
+ $value = maybe_unserialize( $meta['value'] );
669
+
670
+ update_post_meta( $post_id, $key, $value );
671
+ do_action( 'import_post_meta', $post_id, $key, $value );
672
+
673
+ // if the post has a featured image, take note of this in case of remap
674
+ if ( '_thumbnail_id' == $key )
675
+ $this->featured_images[$post_id] = (int) $value;
676
  }
 
677
  }
 
678
  }
679
  }
680
 
681
+ unset( $this->posts );
682
+ }
683
+
684
+ /**
685
+ * Attempt to create a new menu item from import data
686
+ *
687
+ * Fails for draft, orphaned menu items and those without an associated nav_menu
688
+ * or an invalid nav_menu term. If the post type or term object which the menu item
689
+ * represents doesn't exist then the menu item will not be imported (waits until the
690
+ * end of the import to retry again before discarding).
691
+ *
692
+ * @param array $item Menu item details from WXR file
693
+ */
694
+ function process_menu_item( $item ) {
695
+ // skip draft, orphaned menu items
696
+ if ( 'draft' == $item['status'] )
697
+ return;
698
+
699
+ $menu_slug = false;
700
+ if ( isset($item['terms']) ) {
701
+ // loop through terms, assume first nav_menu term is correct menu
702
+ foreach ( $item['terms'] as $term ) {
703
+ if ( 'nav_menu' == $term['domain'] ) {
704
+ $menu_slug = $term['slug'];
705
+ break;
 
 
 
 
 
706
  }
707
  }
708
  }
709
 
710
+ // no nav_menu term associated with this menu item
711
+ if ( ! $menu_slug ) {
712
+ _e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' );
713
+ echo '<br />';
714
+ return;
715
+ }
 
 
 
 
 
 
 
716
 
717
+ $menu_id = term_exists( $menu_slug, 'nav_menu' );
718
+ if ( ! $menu_id ) {
719
+ printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) );
720
+ echo '<br />';
721
+ return;
722
+ } else {
723
+ $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
724
+ }
725
 
726
+ foreach ( $item['postmeta'] as $meta )
727
+ $$meta['key'] = $meta['value'];
728
+
729
+ if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) {
730
+ $_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)];
731
+ } else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) {
732
+ $_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)];
733
+ } else if ( 'custom' != $_menu_item_type ) {
734
+ // associated object is missing or not imported yet, we'll retry later
735
+ $this->missing_menu_items[] = $item;
736
+ return;
737
  }
 
738
 
739
+ if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) {
740
+ $_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)];
741
+ } else if ( $_menu_item_menu_item_parent ) {
742
+ $this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent;
743
+ $_menu_item_menu_item_parent = 0;
744
+ }
745
 
746
+ // wp_update_nav_menu_item expects CSS classes as a space separated string
747
+ $_menu_item_classes = maybe_unserialize( $_menu_item_classes );
748
+ if ( is_array( $_menu_item_classes ) )
749
+ $_menu_item_classes = implode( ' ', $_menu_item_classes );
750
+
751
+ $args = array(
752
+ 'menu-item-object-id' => $_menu_item_object_id,
753
+ 'menu-item-object' => $_menu_item_object,
754
+ 'menu-item-parent-id' => $_menu_item_menu_item_parent,
755
+ 'menu-item-position' => intval( $item['menu_order'] ),
756
+ 'menu-item-type' => $_menu_item_type,
757
+ 'menu-item-title' => $item['post_title'],
758
+ 'menu-item-url' => $_menu_item_url,
759
+ 'menu-item-description' => $item['post_content'],
760
+ 'menu-item-attr-title' => $item['post_excerpt'],
761
+ 'menu-item-target' => $_menu_item_target,
762
+ 'menu-item-classes' => $_menu_item_classes,
763
+ 'menu-item-xfn' => $_menu_item_xfn,
764
+ 'menu-item-status' => $item['status']
765
+ );
766
+
767
+ $id = wp_update_nav_menu_item( $menu_id, 0, $args );
768
+ if ( $id && ! is_wp_error( $id ) )
769
+ $this->processed_menu_items[intval($item['post_id'])] = (int) $id;
770
+ }
771
 
772
+ /**
773
+ * If fetching attachments is enabled then attempt to create a new attachment
774
+ *
775
+ * @param array $post Attachment post details from WXR
776
+ * @param string $url URL to fetch attachment from
777
+ * @return int|WP_Error Post ID on success, WP_Error otherwise
778
+ */
779
+ function process_attachment( $post, $url ) {
780
+ if ( ! $this->fetch_attachments )
781
+ return new WP_Error( 'attachment_processing_error',
782
+ __( 'Fetching attachments is not enabled', 'wordpress-importer' ) );
783
 
784
+ // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
785
+ if ( preg_match( '|^/[\w\W]+$|', $url ) )
786
+ $url = rtrim( $this->base_url, '/' ) . $url;
 
 
787
 
788
+ $upload = $this->fetch_remote_file( $url, $post );
789
+ if ( is_wp_error( $upload ) )
790
+ return $upload;
 
 
 
 
791
 
792
+ if ( $info = wp_check_filetype( $upload['file'] ) )
793
+ $post['post_mime_type'] = $info['type'];
794
+ else
795
+ return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') );
796
 
797
+ $post['guid'] = $upload['url'];
 
 
798
 
799
+ // as per wp-admin/includes/upload.php
800
+ $post_id = wp_insert_attachment( $post, $upload['file'] );
801
+ wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
 
 
 
 
802
 
803
+ // remap the thumbnail url. this isn't perfect because we're just guessing the original url.
804
+ if ( preg_match( '@^image/@', $info['type'] ) && $thumb_url = wp_get_attachment_thumb_url( $post_id ) ) {
805
+ $parts = pathinfo( $url );
806
+ $ext = $parts['extension'];
807
+ $name = basename($parts['basename'], ".{$ext}");
808
+ $this->url_remap[$parts['dirname'] . '/' . $name . '.thumbnail.' . $ext] = $thumb_url;
809
  }
810
+
811
+ return $post_id;
812
  }
813
 
814
+ /**
815
+ * Attempt to download a remote file attachment
816
+ *
817
+ * @param string $url URL of item to fetch
818
+ * @param array $post Attachment details
819
+ * @return array|WP_Error Local file location details on success, WP_Error otherwise
820
+ */
821
+ function fetch_remote_file( $url, $post ) {
822
  add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
823
 
 
 
824
  // extract the file name and extension from the url
825
+ $file_name = basename( $url );
826
 
827
+ // get placeholder file in the upload dir with a unique, sanitized filename
828
+ $upload = wp_upload_bits( $file_name, 0, '', $post['post_date'] );
829
+ if ( $upload['error'] )
 
830
  return new WP_Error( 'upload_dir_error', $upload['error'] );
 
831
 
832
  // fetch the remote url and write it to the placeholder file
833
+ $headers = wp_get_http( $url, $upload['file'] );
834
 
835
+ // request failed
836
  if ( ! $headers ) {
837
+ @unlink( $upload['file'] );
838
  return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') );
839
  }
840
 
841
  // make sure the fetch was successful
842
  if ( $headers['response'] != '200' ) {
843
+ @unlink( $upload['file'] );
844
+ return new WP_Error( 'import_file_error', sprintf( __('Remote server returned error response %1$d %2$s', 'wordpress-importer'), esc_html($headers['response']), get_status_header_desc($headers['response']) ) );
845
  }
846
+
847
+ $filesize = filesize( $upload['file'] );
848
+
849
+ if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) {
850
+ @unlink( $upload['file'] );
851
  return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') );
852
  }
853
 
854
+ if ( 0 == $filesize ) {
855
+ @unlink( $upload['file'] );
856
+ return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') );
857
+ }
858
+
859
+ $max_size = (int) $this->max_attachment_size();
860
+ if ( ! empty( $max_size ) && $filesize > $max_size ) {
861
+ @unlink( $upload['file'] );
862
+ return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) );
863
  }
864
 
865
  // keep track of the old and new urls so we can substitute them later
866
  $this->url_remap[$url] = $upload['url'];
867
  $this->url_remap[$post['guid']] = $upload['url'];
868
  // if the remote url is redirected somewhere else, keep track of the destination too
869
+ if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url )
870
  $this->url_remap[$headers['x-final-location']] = $upload['url'];
871
 
872
  return $upload;
 
873
  }
874
 
875
  /**
876
+ * Attempt to associate posts and menu items with previously missing parents
877
  *
878
+ * An imported post's parent may not have been imported when it was first created
879
+ * so try again. Similarly for child menu items and menu items which were missing
880
+ * the object (e.g. post) they represent in the menu
881
  */
882
+ function backfill_parents() {
883
+ global $wpdb;
 
884
 
885
+ // find parents for post orphans
886
+ foreach ( $this->post_orphans as $child_id => $parent_id ) {
887
+ $local_child_id = $local_parent_id = false;
888
+ if ( isset( $this->processed_posts[$child_id] ) )
889
+ $local_child_id = $this->processed_posts[$child_id];
890
+ if ( isset( $this->processed_posts[$parent_id] ) )
891
+ $local_parent_id = $this->processed_posts[$parent_id];
892
+
893
+ if ( $local_child_id && $local_parent_id )
894
+ $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' );
895
+ }
896
+
897
+ // all other posts/terms are imported, retry menu items with missing associated object
898
+ $missing_menu_items = $this->missing_menu_items;
899
+ foreach ( $missing_menu_items as $item )
900
+ $this->process_menu_item( $item );
901
+
902
+ // find parents for menu item orphans
903
+ foreach ( $this->menu_item_orphans as $child_id => $parent_id ) {
904
+ $local_child_id = $local_parent_id = 0;
905
+ if ( isset( $this->processed_menu_items[$child_id] ) )
906
+ $local_child_id = $this->processed_menu_items[$child_id];
907
+ if ( isset( $this->processed_menu_items[$parent_id] ) )
908
+ $local_parent_id = $this->processed_menu_items[$parent_id];
909
+
910
+ if ( $local_child_id && $local_parent_id )
911
+ update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id );
912
+ }
913
  }
914
 
915
+ /**
916
+ * Use stored mapping information to update old attachment URLs
917
+ */
918
  function backfill_attachment_urls() {
919
+ global $wpdb;
920
  // make sure we do the longest urls first, in case one is a substring of another
921
+ uksort( $this->url_remap, array(&$this, 'cmpr_strlen') );
922
 
923
+ foreach ( $this->url_remap as $from_url => $to_url ) {
 
924
  // remap urls in post_content
925
+ $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) );
926
  // remap enclosure urls
927
+ $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) );
928
  }
929
  }
930
 
931
+ /**
932
+ * Update _thumbnail_id meta to new, imported attachment IDs
933
+ */
934
+ function remap_featured_images() {
935
+ // cycle through posts that have a featured image
936
+ foreach ( $this->featured_images as $post_id => $value ) {
937
+ if ( isset( $this->processed_posts[$value] ) ) {
938
+ $new_id = $this->processed_posts[$value];
939
+ // only update if there's a difference
940
+ if ( $new_id != $value )
941
+ update_post_meta( $post_id, '_thumbnail_id', $new_id );
 
 
942
  }
943
  }
944
  }
945
 
946
+ /**
947
+ * Parse a WXR file
948
+ *
949
+ * @param string $file Path to WXR file for parsing
950
+ * @return array Information gathered from the WXR file
951
+ */
952
+ function parse( $file ) {
953
+ $parser = new WXR_Parser();
954
+ return $parser->parse( $file );
 
955
  }
956
 
957
+ // Display import page title
958
+ function header() {
959
+ echo '<div class="wrap">';
960
+ screen_icon();
961
+ echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>';
962
+
963
+ $updates = get_plugin_updates();
964
+ $basename = plugin_basename(__FILE__);
965
+ if ( isset( $updates[$basename] ) ) {
966
+ $update = $updates[$basename];
967
+ echo '<div class="error"><p><strong>';
968
+ printf( __( 'A new version of this importer is available. Please update to version %s to ensure compatibility with newer export files.', 'wordpress-importer' ), $update->update->new_version );
969
+ echo '</strong></p></div>';
970
+ }
971
  }
972
 
973
+ // Close div.wrap
974
+ function footer() {
975
+ echo '</div>';
976
  }
977
 
978
+ /**
979
+ * Display introductory text and file upload form
980
+ */
981
+ function greet() {
982
+ echo '<div class="narrow">';
983
+ echo '<p>'.__( 'Howdy! Upload your WordPress eXtended RSS (WXR) file and we&#8217;ll import the posts, pages, comments, custom fields, categories, and tags into this site.', 'wordpress-importer' ).'</p>';
984
+ echo '<p>'.__( 'Choose a WXR file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>';
985
+ wp_import_upload_form( 'admin.php?import=wordpress&amp;step=1' );
986
+ echo '</div>';
987
  }
988
 
989
+ /**
990
+ * Decide if the given meta key maps to information we will want to import
991
+ *
992
+ * @param string $key The meta key to check
993
+ * @return string|bool The key if we do want to import, false if not
994
+ */
995
+ function is_valid_meta_key( $key ) {
996
+ // skip attachment metadata since we'll regenerate it from scratch
997
+ // skip _edit_lock as not relevant for import
998
+ if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
999
+ return false;
1000
+ return $key;
1001
  }
1002
 
1003
+ /**
1004
+ * Decide whether or not the importer is allowed to create users.
1005
+ * Default is true, can be filtered via import_allow_create_users
1006
+ *
1007
+ * @return bool True if creating users is allowed
1008
+ */
1009
+ function allow_create_users() {
1010
+ return apply_filters( 'import_allow_create_users', true );
1011
  }
1012
 
1013
+ /**
1014
+ * Decide whether or not the importer should attempt to download attachment files.
1015
+ * Default is true, can be filtered via import_allow_fetch_attachments. The choice
1016
+ * made at the import options screen must also be true, false here hides that checkbox.
1017
+ *
1018
+ * @return bool True if downloading attachments is allowed
1019
+ */
1020
+ function allow_fetch_attachments() {
1021
+ return apply_filters( 'import_allow_fetch_attachments', true );
 
 
 
 
 
 
 
 
 
1022
  }
1023
 
1024
+ /**
1025
+ * Decide what the maximum file size for downloaded attachments is.
1026
+ * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
1027
+ *
1028
+ * @return int Maximum attachment file size to import
1029
+ */
1030
+ function max_attachment_size() {
1031
+ return apply_filters( 'import_attachment_size_limit', 0 );
 
 
1032
  }
1033
 
1034
+ /**
1035
+ * Added to http_request_timeout filter to force timeout at 60 seconds during import
1036
+ * @return int 60
1037
+ */
1038
+ function bump_request_timeout() {
1039
+ return 60;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  }
1041
 
1042
+ // return the difference in length between two strings
1043
+ function cmpr_strlen( $a, $b ) {
1044
+ return strlen($b) - strlen($a);
1045
  }
1046
  }
1047
 
 
 
 
 
 
 
 
 
 
 
 
1048
  } // class_exists( 'WP_Importer' )
1049
 
1050
  function wordpress_importer_init() {
1051
+ load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
1052
+
1053
+ /**
1054
+ * WordPress Importer object for registering the import callback
1055
+ * @global WP_Import $wp_import
1056
+ */
1057
+ $GLOBALS['wp_import'] = new WP_Import();
1058
+ register_importer( 'wordpress', 'WordPress', __('Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer'), array( $GLOBALS['wp_import'], 'dispatch' ) );
1059
  }
1060
+ add_action( 'admin_init', 'wordpress_importer_init' );