WordPress Importer - Version 0.6.3

Version Description

  • Add support for import term metadata.
  • Fix bug that caused slashes to be stripped from imported content.
  • Fix bug that caused characters to be stripped inside of CDATA in some cases.
  • Fix PHP notices.
Download this release

Release Info

Developer boonebgorges
Plugin Icon 128x128 WordPress Importer
Version 0.6.3
Comparing to
See all releases

Code changes from version 0.6.2 to 0.6.3

Files changed (4) hide show
  1. languages/wordpress-importer.pot +56 -48
  2. parsers.php +36 -9
  3. readme.txt +8 -2
  4. wordpress-importer.php +1218 -1146
languages/wordpress-importer.pot CHANGED
@@ -1,18 +1,19 @@
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.5\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/wordpress-importer\n"
7
- "POT-Creation-Date: 2011-07-16 15:45: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
 
@@ -22,49 +23,56 @@ msgid ""
22
  "parser..."
23
  msgstr ""
24
 
25
- #: parsers.php:67 parsers.php:72 parsers.php:262 parsers.php:451
26
  msgid ""
27
  "This does not appear to be a WXR file, missing/invalid WXR version number"
28
  msgstr ""
29
 
30
- #: wordpress-importer.php:134 wordpress-importer.php:143
31
- #: wordpress-importer.php:194 wordpress-importer.php:202
 
32
  msgid "Sorry, there has been an error."
33
  msgstr ""
34
 
35
- #: wordpress-importer.php:135
36
  msgid "The file does not exist, please try again."
37
  msgstr ""
38
 
39
- #: wordpress-importer.php:178
40
  msgid "All done."
41
  msgstr ""
42
 
43
- #: wordpress-importer.php:178
44
  msgid "Have fun!"
45
  msgstr ""
46
 
47
- #: wordpress-importer.php:179
48
  msgid "Remember to update the passwords and roles of imported users."
49
  msgstr ""
50
 
51
- #: wordpress-importer.php:210
 
 
 
 
 
 
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:235
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:261
64
  msgid "Assign Authors"
65
  msgstr ""
66
 
67
- #: wordpress-importer.php:262
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 "
@@ -72,137 +80,137 @@ msgid ""
72
  "code>s entries."
73
  msgstr ""
74
 
75
- #: wordpress-importer.php:264
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:274
83
  msgid "Import Attachments"
84
  msgstr ""
85
 
86
- #: wordpress-importer.php:277
87
  msgid "Download and import file attachments"
88
  msgstr ""
89
 
90
- #: wordpress-importer.php:281
91
  msgid "Submit"
92
  msgstr ""
93
 
94
- #: wordpress-importer.php:294
95
  msgid "Import author:"
96
  msgstr ""
97
 
98
- #: wordpress-importer.php:305
99
  msgid "or create new user with login name:"
100
  msgstr ""
101
 
102
- #: wordpress-importer.php:308
103
  msgid "as a new user:"
104
  msgstr ""
105
 
106
- #: wordpress-importer.php:316
107
  msgid "assign posts to an existing user:"
108
  msgstr ""
109
 
110
- #: wordpress-importer.php:318
111
  msgid "or assign posts to an existing user:"
112
  msgstr ""
113
 
114
- #: wordpress-importer.php:319
115
  msgid "- Select -"
116
  msgstr ""
117
 
118
- #: wordpress-importer.php:369
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:418
125
  msgid "Failed to import category %s"
126
  msgstr ""
127
 
128
- #: wordpress-importer.php:456
129
  msgid "Failed to import post tag %s"
130
  msgstr ""
131
 
132
- #: wordpress-importer.php:500 wordpress-importer.php:626
133
  msgid "Failed to import %s %s"
134
  msgstr ""
135
 
136
- #: wordpress-importer.php:522
137
  msgid "Failed to import &#8220;%s&#8221;: Invalid post type %s"
138
  msgstr ""
139
 
140
- #: wordpress-importer.php:543
141
  msgid "%s &#8220;%s&#8221; already exists."
142
  msgstr ""
143
 
144
- #: wordpress-importer.php:598
145
  msgid "Failed to import %s &#8220;%s&#8221;"
146
  msgstr ""
147
 
148
- #: wordpress-importer.php:744
149
  msgid "Menu item skipped due to missing menu slug"
150
  msgstr ""
151
 
152
- #: wordpress-importer.php:751
153
  msgid "Menu item skipped due to invalid menu slug: %s"
154
  msgstr ""
155
 
156
- #: wordpress-importer.php:814
157
  msgid "Fetching attachments is not enabled"
158
  msgstr ""
159
 
160
- #: wordpress-importer.php:827
161
  msgid "Invalid file type"
162
  msgstr ""
163
 
164
- #: wordpress-importer.php:871
165
  msgid "Remote server did not respond"
166
  msgstr ""
167
 
168
- #: wordpress-importer.php:877
169
  msgid "Remote server returned error response %1$d %2$s"
170
  msgstr ""
171
 
172
- #: wordpress-importer.php:884
173
  msgid "Remote file is incorrect size"
174
  msgstr ""
175
 
176
- #: wordpress-importer.php:889
177
  msgid "Zero size file downloaded"
178
  msgstr ""
179
 
180
- #: wordpress-importer.php:895
181
  msgid "Remote file is too large, limit is %s"
182
  msgstr ""
183
 
184
- #: wordpress-importer.php:994
185
  msgid "Import WordPress"
186
  msgstr ""
187
 
188
- #: wordpress-importer.php:1001
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:1016
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:1017
202
  msgid "Choose a WXR (.xml) file to upload, then click Upload file and import."
203
  msgstr ""
204
 
205
- #: wordpress-importer.php:1091
206
  msgid ""
207
  "Import <strong>posts, pages, comments, custom fields, categories, and tags</"
208
  "strong> from a WordPress export file."
1
+ # Copyright (C) 2016 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.6.3\n"
6
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wordpress-"
7
+ "importer\n"
8
+ "POT-Creation-Date: 2016-08-19 13:28:24+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
 
16
+ #: parsers.php:42 parsers.php:72 parsers.php:80
17
  msgid "There was an error when reading this WXR file"
18
  msgstr ""
19
 
23
  "parser..."
24
  msgstr ""
25
 
26
+ #: parsers.php:84 parsers.php:89 parsers.php:306 parsers.php:495
27
  msgid ""
28
  "This does not appear to be a WXR file, missing/invalid WXR version number"
29
  msgstr ""
30
 
31
+ #: wordpress-importer.php:132 wordpress-importer.php:141
32
+ #: wordpress-importer.php:192 wordpress-importer.php:196
33
+ #: wordpress-importer.php:205
34
  msgid "Sorry, there has been an error."
35
  msgstr ""
36
 
37
+ #: wordpress-importer.php:133
38
  msgid "The file does not exist, please try again."
39
  msgstr ""
40
 
41
+ #: wordpress-importer.php:176
42
  msgid "All done."
43
  msgstr ""
44
 
45
+ #: wordpress-importer.php:176
46
  msgid "Have fun!"
47
  msgstr ""
48
 
49
+ #: wordpress-importer.php:177
50
  msgid "Remember to update the passwords and roles of imported users."
51
  msgstr ""
52
 
53
+ #: wordpress-importer.php:197
54
+ msgid ""
55
+ "The export file could not be found at <code>%s</code>. It is likely that "
56
+ "this was caused by a permissions problem."
57
+ msgstr ""
58
+
59
+ #: wordpress-importer.php:213
60
  msgid ""
61
  "This WXR file (version %s) may not be supported by this version of the "
62
  "importer. Please consider updating."
63
  msgstr ""
64
 
65
+ #: wordpress-importer.php:238
66
  msgid ""
67
  "Failed to import author %s. Their posts will be attributed to the current "
68
  "user."
69
  msgstr ""
70
 
71
+ #: wordpress-importer.php:264
72
  msgid "Assign Authors"
73
  msgstr ""
74
 
75
+ #: wordpress-importer.php:265
76
  msgid ""
77
  "To make it easier for you to edit and save the imported content, you may "
78
  "want to reassign the author of the imported item to an existing user of this "
80
  "code>s entries."
81
  msgstr ""
82
 
83
+ #: wordpress-importer.php:267
84
  msgid ""
85
  "If a new user is created by WordPress, a new password will be randomly "
86
  "generated and the new user&#8217;s role will be set as %s. Manually changing "
87
  "the new user&#8217;s details will be necessary."
88
  msgstr ""
89
 
90
+ #: wordpress-importer.php:277
91
  msgid "Import Attachments"
92
  msgstr ""
93
 
94
+ #: wordpress-importer.php:280
95
  msgid "Download and import file attachments"
96
  msgstr ""
97
 
98
+ #: wordpress-importer.php:284
99
  msgid "Submit"
100
  msgstr ""
101
 
102
+ #: wordpress-importer.php:297
103
  msgid "Import author:"
104
  msgstr ""
105
 
106
+ #: wordpress-importer.php:308
107
  msgid "or create new user with login name:"
108
  msgstr ""
109
 
110
+ #: wordpress-importer.php:311
111
  msgid "as a new user:"
112
  msgstr ""
113
 
114
+ #: wordpress-importer.php:319
115
  msgid "assign posts to an existing user:"
116
  msgstr ""
117
 
118
+ #: wordpress-importer.php:321
119
  msgid "or assign posts to an existing user:"
120
  msgstr ""
121
 
122
+ #: wordpress-importer.php:322
123
  msgid "- Select -"
124
  msgstr ""
125
 
126
+ #: wordpress-importer.php:372
127
  msgid ""
128
  "Failed to create new user for %s. Their posts will be attributed to the "
129
  "current user."
130
  msgstr ""
131
 
132
+ #: wordpress-importer.php:424
133
  msgid "Failed to import category %s"
134
  msgstr ""
135
 
136
+ #: wordpress-importer.php:467
137
  msgid "Failed to import post tag %s"
138
  msgstr ""
139
 
140
+ #: wordpress-importer.php:516 wordpress-importer.php:738
141
  msgid "Failed to import %s %s"
142
  msgstr ""
143
 
144
+ #: wordpress-importer.php:605
145
  msgid "Failed to import &#8220;%s&#8221;: Invalid post type %s"
146
  msgstr ""
147
 
148
+ #: wordpress-importer.php:642
149
  msgid "%s &#8220;%s&#8221; already exists."
150
  msgstr ""
151
 
152
+ #: wordpress-importer.php:704
153
  msgid "Failed to import %s &#8220;%s&#8221;"
154
  msgstr ""
155
 
156
+ #: wordpress-importer.php:869
157
  msgid "Menu item skipped due to missing menu slug"
158
  msgstr ""
159
 
160
+ #: wordpress-importer.php:876
161
  msgid "Menu item skipped due to invalid menu slug: %s"
162
  msgstr ""
163
 
164
+ #: wordpress-importer.php:939
165
  msgid "Fetching attachments is not enabled"
166
  msgstr ""
167
 
168
+ #: wordpress-importer.php:952
169
  msgid "Invalid file type"
170
  msgstr ""
171
 
172
+ #: wordpress-importer.php:996
173
  msgid "Remote server did not respond"
174
  msgstr ""
175
 
176
+ #: wordpress-importer.php:1002
177
  msgid "Remote server returned error response %1$d %2$s"
178
  msgstr ""
179
 
180
+ #: wordpress-importer.php:1009
181
  msgid "Remote file is incorrect size"
182
  msgstr ""
183
 
184
+ #: wordpress-importer.php:1014
185
  msgid "Zero size file downloaded"
186
  msgstr ""
187
 
188
+ #: wordpress-importer.php:1020
189
  msgid "Remote file is too large, limit is %s"
190
  msgstr ""
191
 
192
+ #: wordpress-importer.php:1119
193
  msgid "Import WordPress"
194
  msgstr ""
195
 
196
+ #: wordpress-importer.php:1126
197
  msgid ""
198
  "A new version of this importer is available. Please update to version %s to "
199
  "ensure compatibility with newer export files."
200
  msgstr ""
201
 
202
+ #: wordpress-importer.php:1141
203
  msgid ""
204
  "Howdy! Upload your WordPress eXtended RSS (WXR) file and we&#8217;ll import "
205
  "the posts, pages, comments, custom fields, categories, and tags into this "
206
  "site."
207
  msgstr ""
208
 
209
+ #: wordpress-importer.php:1142
210
  msgid "Choose a WXR (.xml) file to upload, then click Upload file and import."
211
  msgstr ""
212
 
213
+ #: wordpress-importer.php:1216
214
  msgid ""
215
  "Import <strong>posts, pages, comments, custom fields, categories, and tags</"
216
  "strong> from a WordPress export file."
parsers.php CHANGED
@@ -114,28 +114,46 @@ class WXR_Parser_SimpleXML {
114
  // grab cats, tags and terms
115
  foreach ( $xml->xpath('/rss/channel/wp:category') as $term_arr ) {
116
  $t = $term_arr->children( $namespaces['wp'] );
117
- $categories[] = array(
118
  'term_id' => (int) $t->term_id,
119
  'category_nicename' => (string) $t->category_nicename,
120
  'category_parent' => (string) $t->category_parent,
121
  'cat_name' => (string) $t->cat_name,
122
  'category_description' => (string) $t->category_description
123
  );
 
 
 
 
 
 
 
 
 
124
  }
125
 
126
  foreach ( $xml->xpath('/rss/channel/wp:tag') as $term_arr ) {
127
  $t = $term_arr->children( $namespaces['wp'] );
128
- $tags[] = array(
129
  'term_id' => (int) $t->term_id,
130
  'tag_slug' => (string) $t->tag_slug,
131
  'tag_name' => (string) $t->tag_name,
132
  'tag_description' => (string) $t->tag_description
133
  );
 
 
 
 
 
 
 
 
 
134
  }
135
 
136
  foreach ( $xml->xpath('/rss/channel/wp:term') as $term_arr ) {
137
  $t = $term_arr->children( $namespaces['wp'] );
138
- $terms[] = array(
139
  'term_id' => (int) $t->term_id,
140
  'term_taxonomy' => (string) $t->term_taxonomy,
141
  'slug' => (string) $t->term_slug,
@@ -143,6 +161,15 @@ class WXR_Parser_SimpleXML {
143
  'term_name' => (string) $t->term_name,
144
  'term_description' => (string) $t->term_description
145
  );
 
 
 
 
 
 
 
 
 
146
  }
147
 
148
  // grab posts
@@ -204,7 +231,7 @@ class WXR_Parser_SimpleXML {
204
  );
205
  }
206
  }
207
-
208
  $post['comments'][] = array(
209
  'comment_id' => (int) $comment->comment_id,
210
  'comment_author' => (string) $comment->comment_author,
@@ -324,7 +351,11 @@ class WXR_Parser_XML {
324
  if ( ! trim( $cdata ) )
325
  return;
326
 
327
- $this->cdata .= trim( $cdata );
 
 
 
 
328
  }
329
 
330
  function tag_close( $parser, $tag ) {
@@ -405,10 +436,6 @@ class WXR_Parser_Regex {
405
  $this->has_gzip = is_callable( 'gzopen' );
406
  }
407
 
408
- function WXR_Parser_Regex() {
409
- $this->__construct();
410
- }
411
-
412
  function parse( $file ) {
413
  $wxr_version = $in_post = false;
414
 
114
  // grab cats, tags and terms
115
  foreach ( $xml->xpath('/rss/channel/wp:category') as $term_arr ) {
116
  $t = $term_arr->children( $namespaces['wp'] );
117
+ $category = array(
118
  'term_id' => (int) $t->term_id,
119
  'category_nicename' => (string) $t->category_nicename,
120
  'category_parent' => (string) $t->category_parent,
121
  'cat_name' => (string) $t->cat_name,
122
  'category_description' => (string) $t->category_description
123
  );
124
+
125
+ foreach ( $t->termmeta as $meta ) {
126
+ $category['termmeta'][] = array(
127
+ 'key' => (string) $meta->meta_key,
128
+ 'value' => (string) $meta->meta_value
129
+ );
130
+ }
131
+
132
+ $categories[] = $category;
133
  }
134
 
135
  foreach ( $xml->xpath('/rss/channel/wp:tag') as $term_arr ) {
136
  $t = $term_arr->children( $namespaces['wp'] );
137
+ $tag = array(
138
  'term_id' => (int) $t->term_id,
139
  'tag_slug' => (string) $t->tag_slug,
140
  'tag_name' => (string) $t->tag_name,
141
  'tag_description' => (string) $t->tag_description
142
  );
143
+
144
+ foreach ( $t->termmeta as $meta ) {
145
+ $tag['termmeta'][] = array(
146
+ 'key' => (string) $meta->meta_key,
147
+ 'value' => (string) $meta->meta_value
148
+ );
149
+ }
150
+
151
+ $tags[] = $tag;
152
  }
153
 
154
  foreach ( $xml->xpath('/rss/channel/wp:term') as $term_arr ) {
155
  $t = $term_arr->children( $namespaces['wp'] );
156
+ $term = array(
157
  'term_id' => (int) $t->term_id,
158
  'term_taxonomy' => (string) $t->term_taxonomy,
159
  'slug' => (string) $t->term_slug,
161
  'term_name' => (string) $t->term_name,
162
  'term_description' => (string) $t->term_description
163
  );
164
+
165
+ foreach ( $t->termmeta as $meta ) {
166
+ $term['termmeta'][] = array(
167
+ 'key' => (string) $meta->meta_key,
168
+ 'value' => (string) $meta->meta_value
169
+ );
170
+ }
171
+
172
+ $terms[] = $term;
173
  }
174
 
175
  // grab posts
231
  );
232
  }
233
  }
234
+
235
  $post['comments'][] = array(
236
  'comment_id' => (int) $comment->comment_id,
237
  'comment_author' => (string) $comment->comment_author,
351
  if ( ! trim( $cdata ) )
352
  return;
353
 
354
+ if ( false !== $this->in_tag || false !== $this->in_sub_tag ) {
355
+ $this->cdata .= $cdata;
356
+ } else {
357
+ $this->cdata .= trim( $cdata );
358
+ }
359
  }
360
 
361
  function tag_close( $parser, $tag ) {
436
  $this->has_gzip = is_callable( 'gzopen' );
437
  }
438
 
 
 
 
 
439
  function parse( $file ) {
440
  $wxr_version = $in_post = false;
441
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: wordpressdotorg
3
  Tags: importer, wordpress
4
  Requires at least: 3.0
5
- Tested up to: 4.5
6
- Stable tag: 0.6.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -38,6 +38,12 @@ If you would prefer to do things manually then follow these instructions:
38
 
39
  == Changelog ==
40
 
 
 
 
 
 
 
41
  = 0.6.2 =
42
  * Add wp_import_existing_post filter. See: https://core.trac.wordpress.org/ticket/33721
43
 
2
  Contributors: wordpressdotorg
3
  Tags: importer, wordpress
4
  Requires at least: 3.0
5
+ Tested up to: 4.6
6
+ Stable tag: 0.6.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
38
 
39
  == Changelog ==
40
 
41
+ = 0.6.3 =
42
+ * Add support for import term metadata.
43
+ * Fix bug that caused slashes to be stripped from imported content.
44
+ * Fix bug that caused characters to be stripped inside of CDATA in some cases.
45
+ * Fix PHP notices.
46
+
47
  = 0.6.2 =
48
  * Add wp_import_existing_post filter. See: https://core.trac.wordpress.org/ticket/33721
49
 
wordpress-importer.php CHANGED
@@ -1,1146 +1,1218 @@
1
- <?php
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.6.2
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.2; // 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
- /**
67
- * Registered callback function for the WordPress Importer
68
- *
69
- * Manages the three separate stages of the WXR import process
70
- */
71
- function dispatch() {
72
- $this->header();
73
-
74
- $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
75
- switch ( $step ) {
76
- case 0:
77
- $this->greet();
78
- break;
79
- case 1:
80
- check_admin_referer( 'import-upload' );
81
- if ( $this->handle_upload() )
82
- $this->import_options();
83
- break;
84
- case 2:
85
- check_admin_referer( 'import-wordpress' );
86
- $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() );
87
- $this->id = (int) $_POST['import_id'];
88
- $file = get_attached_file( $this->id );
89
- set_time_limit(0);
90
- $this->import( $file );
91
- break;
92
- }
93
-
94
- $this->footer();
95
- }
96
-
97
- /**
98
- * The main controller for the actual import stage.
99
- *
100
- * @param string $file Path to the WXR file for importing
101
- */
102
- function import( $file ) {
103
- add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
104
- add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
105
-
106
- $this->import_start( $file );
107
-
108
- $this->get_author_mapping();
109
-
110
- wp_suspend_cache_invalidation( true );
111
- $this->process_categories();
112
- $this->process_tags();
113
- $this->process_terms();
114
- $this->process_posts();
115
- wp_suspend_cache_invalidation( false );
116
-
117
- // update incorrect/missing information in the DB
118
- $this->backfill_parents();
119
- $this->backfill_attachment_urls();
120
- $this->remap_featured_images();
121
-
122
- $this->import_end();
123
- }
124
-
125
- /**
126
- * Parses the WXR file and prepares us for the task of processing parsed data
127
- *
128
- * @param string $file Path to the WXR file for importing
129
- */
130
- function import_start( $file ) {
131
- if ( ! is_file($file) ) {
132
- echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
133
- echo __( 'The file does not exist, please try again.', 'wordpress-importer' ) . '</p>';
134
- $this->footer();
135
- die();
136
- }
137
-
138
- $import_data = $this->parse( $file );
139
-
140
- if ( is_wp_error( $import_data ) ) {
141
- echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
142
- echo esc_html( $import_data->get_error_message() ) . '</p>';
143
- $this->footer();
144
- die();
145
- }
146
-
147
- $this->version = $import_data['version'];
148
- $this->get_authors_from_import( $import_data );
149
- $this->posts = $import_data['posts'];
150
- $this->terms = $import_data['terms'];
151
- $this->categories = $import_data['categories'];
152
- $this->tags = $import_data['tags'];
153
- $this->base_url = esc_url( $import_data['base_url'] );
154
-
155
- wp_defer_term_counting( true );
156
- wp_defer_comment_counting( true );
157
-
158
- do_action( 'import_start' );
159
- }
160
-
161
- /**
162
- * Performs post-import cleanup of files and the cache
163
- */
164
- function import_end() {
165
- wp_import_cleanup( $this->id );
166
-
167
- wp_cache_flush();
168
- foreach ( get_taxonomies() as $tax ) {
169
- delete_option( "{$tax}_children" );
170
- _get_term_hierarchy( $tax );
171
- }
172
-
173
- wp_defer_term_counting( false );
174
- wp_defer_comment_counting( false );
175
-
176
- echo '<p>' . __( 'All done.', 'wordpress-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wordpress-importer' ) . '</a>' . '</p>';
177
- echo '<p>' . __( 'Remember to update the passwords and roles of imported users.', 'wordpress-importer' ) . '</p>';
178
-
179
- do_action( 'import_end' );
180
- }
181
-
182
- /**
183
- * Handles the WXR upload and initial parsing of the file to prepare for
184
- * displaying author import options
185
- *
186
- * @return bool False if error uploading or invalid file, true otherwise
187
- */
188
- function handle_upload() {
189
- $file = wp_import_handle_upload();
190
-
191
- if ( isset( $file['error'] ) ) {
192
- echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
193
- echo esc_html( $file['error'] ) . '</p>';
194
- return false;
195
- } else if ( ! file_exists( $file['file'] ) ) {
196
- echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
197
- printf( __( 'The export file could not be found at <code>%s</code>. It is likely that this was caused by a permissions problem.', 'wordpress-importer' ), esc_html( $file['file'] ) );
198
- echo '</p>';
199
- return false;
200
- }
201
-
202
- $this->id = (int) $file['id'];
203
- $import_data = $this->parse( $file['file'] );
204
- if ( is_wp_error( $import_data ) ) {
205
- echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
206
- echo esc_html( $import_data->get_error_message() ) . '</p>';
207
- return false;
208
- }
209
-
210
- $this->version = $import_data['version'];
211
- if ( $this->version > $this->max_wxr_version ) {
212
- echo '<div class="error"><p><strong>';
213
- 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']) );
214
- echo '</strong></p></div>';
215
- }
216
-
217
- $this->get_authors_from_import( $import_data );
218
-
219
- return true;
220
- }
221
-
222
- /**
223
- * Retrieve authors from parsed WXR data
224
- *
225
- * Uses the provided author information from WXR 1.1 files
226
- * or extracts info from each post for WXR 1.0 files
227
- *
228
- * @param array $import_data Data returned by a WXR parser
229
- */
230
- function get_authors_from_import( $import_data ) {
231
- if ( ! empty( $import_data['authors'] ) ) {
232
- $this->authors = $import_data['authors'];
233
- // no author information, grab it from the posts
234
- } else {
235
- foreach ( $import_data['posts'] as $post ) {
236
- $login = sanitize_user( $post['post_author'], true );
237
- if ( empty( $login ) ) {
238
- printf( __( 'Failed to import author %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html( $post['post_author'] ) );
239
- echo '<br />';
240
- continue;
241
- }
242
-
243
- if ( ! isset($this->authors[$login]) )
244
- $this->authors[$login] = array(
245
- 'author_login' => $login,
246
- 'author_display_name' => $post['post_author']
247
- );
248
- }
249
- }
250
- }
251
-
252
- /**
253
- * Display pre-import options, author importing/mapping and option to
254
- * fetch attachments
255
- */
256
- function import_options() {
257
- $j = 0;
258
- ?>
259
- <form action="<?php echo admin_url( 'admin.php?import=wordpress&amp;step=2' ); ?>" method="post">
260
- <?php wp_nonce_field( 'import-wordpress' ); ?>
261
- <input type="hidden" name="import_id" value="<?php echo $this->id; ?>" />
262
-
263
- <?php if ( ! empty( $this->authors ) ) : ?>
264
- <h3><?php _e( 'Assign Authors', 'wordpress-importer' ); ?></h3>
265
- <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>
266
- <?php if ( $this->allow_create_users() ) : ?>
267
- <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>
268
- <?php endif; ?>
269
- <ol id="authors">
270
- <?php foreach ( $this->authors as $author ) : ?>
271
- <li><?php $this->author_select( $j++, $author ); ?></li>
272
- <?php endforeach; ?>
273
- </ol>
274
- <?php endif; ?>
275
-
276
- <?php if ( $this->allow_fetch_attachments() ) : ?>
277
- <h3><?php _e( 'Import Attachments', 'wordpress-importer' ); ?></h3>
278
- <p>
279
- <input type="checkbox" value="1" name="fetch_attachments" id="import-attachments" />
280
- <label for="import-attachments"><?php _e( 'Download and import file attachments', 'wordpress-importer' ); ?></label>
281
- </p>
282
- <?php endif; ?>
283
-
284
- <p class="submit"><input type="submit" class="button" value="<?php esc_attr_e( 'Submit', 'wordpress-importer' ); ?>" /></p>
285
- </form>
286
- <?php
287
- }
288
-
289
- /**
290
- * Display import options for an individual author. That is, either create
291
- * a new user based on import info or map to an existing user
292
- *
293
- * @param int $n Index for each author in the form
294
- * @param array $author Author information, e.g. login, display name, email
295
- */
296
- function author_select( $n, $author ) {
297
- _e( 'Import author:', 'wordpress-importer' );
298
- echo ' <strong>' . esc_html( $author['author_display_name'] );
299
- if ( $this->version != '1.0' ) echo ' (' . esc_html( $author['author_login'] ) . ')';
300
- echo '</strong><br />';
301
-
302
- if ( $this->version != '1.0' )
303
- echo '<div style="margin-left:18px">';
304
-
305
- $create_users = $this->allow_create_users();
306
- if ( $create_users ) {
307
- if ( $this->version != '1.0' ) {
308
- _e( 'or create new user with login name:', 'wordpress-importer' );
309
- $value = '';
310
- } else {
311
- _e( 'as a new user:', 'wordpress-importer' );
312
- $value = esc_attr( sanitize_user( $author['author_login'], true ) );
313
- }
314
-
315
- echo ' <input type="text" name="user_new['.$n.']" value="'. $value .'" /><br />';
316
- }
317
-
318
- if ( ! $create_users && $this->version == '1.0' )
319
- _e( 'assign posts to an existing user:', 'wordpress-importer' );
320
- else
321
- _e( 'or assign posts to an existing user:', 'wordpress-importer' );
322
- wp_dropdown_users( array( 'name' => "user_map[$n]", 'multi' => true, 'show_option_all' => __( '- Select -', 'wordpress-importer' ) ) );
323
- echo '<input type="hidden" name="imported_authors['.$n.']" value="' . esc_attr( $author['author_login'] ) . '" />';
324
-
325
- if ( $this->version != '1.0' )
326
- echo '</div>';
327
- }
328
-
329
- /**
330
- * Map old author logins to local user IDs based on decisions made
331
- * in import options form. Can map to an existing user, create a new user
332
- * or falls back to the current user in case of error with either of the previous
333
- */
334
- function get_author_mapping() {
335
- if ( ! isset( $_POST['imported_authors'] ) )
336
- return;
337
-
338
- $create_users = $this->allow_create_users();
339
-
340
- foreach ( (array) $_POST['imported_authors'] as $i => $old_login ) {
341
- // Multisite adds strtolower to sanitize_user. Need to sanitize here to stop breakage in process_posts.
342
- $santized_old_login = sanitize_user( $old_login, true );
343
- $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false;
344
-
345
- if ( ! empty( $_POST['user_map'][$i] ) ) {
346
- $user = get_userdata( intval($_POST['user_map'][$i]) );
347
- if ( isset( $user->ID ) ) {
348
- if ( $old_id )
349
- $this->processed_authors[$old_id] = $user->ID;
350
- $this->author_mapping[$santized_old_login] = $user->ID;
351
- }
352
- } else if ( $create_users ) {
353
- if ( ! empty($_POST['user_new'][$i]) ) {
354
- $user_id = wp_create_user( $_POST['user_new'][$i], wp_generate_password() );
355
- } else if ( $this->version != '1.0' ) {
356
- $user_data = array(
357
- 'user_login' => $old_login,
358
- 'user_pass' => wp_generate_password(),
359
- 'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '',
360
- 'display_name' => $this->authors[$old_login]['author_display_name'],
361
- 'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '',
362
- 'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '',
363
- );
364
- $user_id = wp_insert_user( $user_data );
365
- }
366
-
367
- if ( ! is_wp_error( $user_id ) ) {
368
- if ( $old_id )
369
- $this->processed_authors[$old_id] = $user_id;
370
- $this->author_mapping[$santized_old_login] = $user_id;
371
- } else {
372
- 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']) );
373
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
374
- echo ' ' . $user_id->get_error_message();
375
- echo '<br />';
376
- }
377
- }
378
-
379
- // failsafe: if the user_id was invalid, default to the current user
380
- if ( ! isset( $this->author_mapping[$santized_old_login] ) ) {
381
- if ( $old_id )
382
- $this->processed_authors[$old_id] = (int) get_current_user_id();
383
- $this->author_mapping[$santized_old_login] = (int) get_current_user_id();
384
- }
385
- }
386
- }
387
-
388
- /**
389
- * Create new categories based on import information
390
- *
391
- * Doesn't create a new category if its slug already exists
392
- */
393
- function process_categories() {
394
- $this->categories = apply_filters( 'wp_import_categories', $this->categories );
395
-
396
- if ( empty( $this->categories ) )
397
- return;
398
-
399
- foreach ( $this->categories as $cat ) {
400
- // if the category already exists leave it alone
401
- $term_id = term_exists( $cat['category_nicename'], 'category' );
402
- if ( $term_id ) {
403
- if ( is_array($term_id) ) $term_id = $term_id['term_id'];
404
- if ( isset($cat['term_id']) )
405
- $this->processed_terms[intval($cat['term_id'])] = (int) $term_id;
406
- continue;
407
- }
408
-
409
- $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] );
410
- $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : '';
411
- $catarr = array(
412
- 'category_nicename' => $cat['category_nicename'],
413
- 'category_parent' => $category_parent,
414
- 'cat_name' => $cat['cat_name'],
415
- 'category_description' => $category_description
416
- );
417
-
418
- $id = wp_insert_category( $catarr );
419
- if ( ! is_wp_error( $id ) ) {
420
- if ( isset($cat['term_id']) )
421
- $this->processed_terms[intval($cat['term_id'])] = $id;
422
- } else {
423
- printf( __( 'Failed to import category %s', 'wordpress-importer' ), esc_html($cat['category_nicename']) );
424
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
425
- echo ': ' . $id->get_error_message();
426
- echo '<br />';
427
- continue;
428
- }
429
- }
430
-
431
- unset( $this->categories );
432
- }
433
-
434
- /**
435
- * Create new post tags based on import information
436
- *
437
- * Doesn't create a tag if its slug already exists
438
- */
439
- function process_tags() {
440
- $this->tags = apply_filters( 'wp_import_tags', $this->tags );
441
-
442
- if ( empty( $this->tags ) )
443
- return;
444
-
445
- foreach ( $this->tags as $tag ) {
446
- // if the tag already exists leave it alone
447
- $term_id = term_exists( $tag['tag_slug'], 'post_tag' );
448
- if ( $term_id ) {
449
- if ( is_array($term_id) ) $term_id = $term_id['term_id'];
450
- if ( isset($tag['term_id']) )
451
- $this->processed_terms[intval($tag['term_id'])] = (int) $term_id;
452
- continue;
453
- }
454
-
455
- $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : '';
456
- $tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc );
457
-
458
- $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr );
459
- if ( ! is_wp_error( $id ) ) {
460
- if ( isset($tag['term_id']) )
461
- $this->processed_terms[intval($tag['term_id'])] = $id['term_id'];
462
- } else {
463
- printf( __( 'Failed to import post tag %s', 'wordpress-importer' ), esc_html($tag['tag_name']) );
464
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
465
- echo ': ' . $id->get_error_message();
466
- echo '<br />';
467
- continue;
468
- }
469
- }
470
-
471
- unset( $this->tags );
472
- }
473
-
474
- /**
475
- * Create new terms based on import information
476
- *
477
- * Doesn't create a term its slug already exists
478
- */
479
- function process_terms() {
480
- $this->terms = apply_filters( 'wp_import_terms', $this->terms );
481
-
482
- if ( empty( $this->terms ) )
483
- return;
484
-
485
- foreach ( $this->terms as $term ) {
486
- // if the term already exists in the correct taxonomy leave it alone
487
- $term_id = term_exists( $term['slug'], $term['term_taxonomy'] );
488
- if ( $term_id ) {
489
- if ( is_array($term_id) ) $term_id = $term_id['term_id'];
490
- if ( isset($term['term_id']) )
491
- $this->processed_terms[intval($term['term_id'])] = (int) $term_id;
492
- continue;
493
- }
494
-
495
- if ( empty( $term['term_parent'] ) ) {
496
- $parent = 0;
497
- } else {
498
- $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] );
499
- if ( is_array( $parent ) ) $parent = $parent['term_id'];
500
- }
501
- $description = isset( $term['term_description'] ) ? $term['term_description'] : '';
502
- $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) );
503
-
504
- $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr );
505
- if ( ! is_wp_error( $id ) ) {
506
- if ( isset($term['term_id']) )
507
- $this->processed_terms[intval($term['term_id'])] = $id['term_id'];
508
- } else {
509
- printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) );
510
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
511
- echo ': ' . $id->get_error_message();
512
- echo '<br />';
513
- continue;
514
- }
515
- }
516
-
517
- unset( $this->terms );
518
- }
519
-
520
- /**
521
- * Create new posts based on import information
522
- *
523
- * Posts marked as having a parent which doesn't exist will become top level items.
524
- * Doesn't create a new post if: the post type doesn't exist, the given post ID
525
- * is already noted as imported or a post with the same title and date already exists.
526
- * Note that new/updated terms, comments and meta are imported for the last of the above.
527
- */
528
- function process_posts() {
529
- $this->posts = apply_filters( 'wp_import_posts', $this->posts );
530
-
531
- foreach ( $this->posts as $post ) {
532
- $post = apply_filters( 'wp_import_post_data_raw', $post );
533
-
534
- if ( ! post_type_exists( $post['post_type'] ) ) {
535
- printf( __( 'Failed to import &#8220;%s&#8221;: Invalid post type %s', 'wordpress-importer' ),
536
- esc_html($post['post_title']), esc_html($post['post_type']) );
537
- echo '<br />';
538
- do_action( 'wp_import_post_exists', $post );
539
- continue;
540
- }
541
-
542
- if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) )
543
- continue;
544
-
545
- if ( $post['status'] == 'auto-draft' )
546
- continue;
547
-
548
- if ( 'nav_menu_item' == $post['post_type'] ) {
549
- $this->process_menu_item( $post );
550
- continue;
551
- }
552
-
553
- $post_type_object = get_post_type_object( $post['post_type'] );
554
-
555
- $post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
556
-
557
- /**
558
- * Filter ID of the existing post corresponding to post currently importing.
559
- *
560
- * Return 0 to force the post to be imported. Filter the ID to be something else
561
- * to override which existing post is mapped to the imported post.
562
- *
563
- * @see post_exists()
564
- * @since 0.6.2
565
- *
566
- * @param int $post_exists Post ID, or 0 if post did not exist.
567
- * @param array $post The post array to be inserted.
568
- */
569
- $post_exists = apply_filters( 'wp_import_existing_post', $post_exists, $post );
570
-
571
- if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
572
- printf( __('%s &#8220;%s&#8221; already exists.', 'wordpress-importer'), $post_type_object->labels->singular_name, esc_html($post['post_title']) );
573
- echo '<br />';
574
- $comment_post_ID = $post_id = $post_exists;
575
- $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists );
576
- } else {
577
- $post_parent = (int) $post['post_parent'];
578
- if ( $post_parent ) {
579
- // if we already know the parent, map it to the new local ID
580
- if ( isset( $this->processed_posts[$post_parent] ) ) {
581
- $post_parent = $this->processed_posts[$post_parent];
582
- // otherwise record the parent for later
583
- } else {
584
- $this->post_orphans[intval($post['post_id'])] = $post_parent;
585
- $post_parent = 0;
586
- }
587
- }
588
-
589
- // map the post author
590
- $author = sanitize_user( $post['post_author'], true );
591
- if ( isset( $this->author_mapping[$author] ) )
592
- $author = $this->author_mapping[$author];
593
- else
594
- $author = (int) get_current_user_id();
595
-
596
- $postdata = array(
597
- 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'],
598
- 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'],
599
- 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'],
600
- 'post_status' => $post['status'], 'post_name' => $post['post_name'],
601
- 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'],
602
- 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'],
603
- 'post_type' => $post['post_type'], 'post_password' => $post['post_password']
604
- );
605
-
606
- $original_post_ID = $post['post_id'];
607
- $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $post );
608
-
609
- if ( 'attachment' == $postdata['post_type'] ) {
610
- $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid'];
611
-
612
- // try to use _wp_attached file for upload folder placement to ensure the same location as the export site
613
- // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
614
- $postdata['upload_date'] = $post['post_date'];
615
- if ( isset( $post['postmeta'] ) ) {
616
- foreach( $post['postmeta'] as $meta ) {
617
- if ( $meta['key'] == '_wp_attached_file' ) {
618
- if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) )
619
- $postdata['upload_date'] = $matches[0];
620
- break;
621
- }
622
- }
623
- }
624
-
625
- $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url );
626
- } else {
627
- $comment_post_ID = $post_id = wp_insert_post( $postdata, true );
628
- do_action( 'wp_import_insert_post', $post_id, $original_post_ID, $postdata, $post );
629
- }
630
-
631
- if ( is_wp_error( $post_id ) ) {
632
- printf( __( 'Failed to import %s &#8220;%s&#8221;', 'wordpress-importer' ),
633
- $post_type_object->labels->singular_name, esc_html($post['post_title']) );
634
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
635
- echo ': ' . $post_id->get_error_message();
636
- echo '<br />';
637
- continue;
638
- }
639
-
640
- if ( $post['is_sticky'] == 1 )
641
- stick_post( $post_id );
642
- }
643
-
644
- // map pre-import ID to local ID
645
- $this->processed_posts[intval($post['post_id'])] = (int) $post_id;
646
-
647
- if ( ! isset( $post['terms'] ) )
648
- $post['terms'] = array();
649
-
650
- $post['terms'] = apply_filters( 'wp_import_post_terms', $post['terms'], $post_id, $post );
651
-
652
- // add categories, tags and other terms
653
- if ( ! empty( $post['terms'] ) ) {
654
- $terms_to_set = array();
655
- foreach ( $post['terms'] as $term ) {
656
- // back compat with WXR 1.0 map 'tag' to 'post_tag'
657
- $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain'];
658
- $term_exists = term_exists( $term['slug'], $taxonomy );
659
- $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
660
- if ( ! $term_id ) {
661
- $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
662
- if ( ! is_wp_error( $t ) ) {
663
- $term_id = $t['term_id'];
664
- do_action( 'wp_import_insert_term', $t, $term, $post_id, $post );
665
- } else {
666
- printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($taxonomy), esc_html($term['name']) );
667
- if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
668
- echo ': ' . $t->get_error_message();
669
- echo '<br />';
670
- do_action( 'wp_import_insert_term_failed', $t, $term, $post_id, $post );
671
- continue;
672
- }
673
- }
674
- $terms_to_set[$taxonomy][] = intval( $term_id );
675
- }
676
-
677
- foreach ( $terms_to_set as $tax => $ids ) {
678
- $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
679
- do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $post );
680
- }
681
- unset( $post['terms'], $terms_to_set );
682
- }
683
-
684
- if ( ! isset( $post['comments'] ) )
685
- $post['comments'] = array();
686
-
687
- $post['comments'] = apply_filters( 'wp_import_post_comments', $post['comments'], $post_id, $post );
688
-
689
- // add/update comments
690
- if ( ! empty( $post['comments'] ) ) {
691
- $num_comments = 0;
692
- $inserted_comments = array();
693
- foreach ( $post['comments'] as $comment ) {
694
- $comment_id = $comment['comment_id'];
695
- $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID;
696
- $newcomments[$comment_id]['comment_author'] = $comment['comment_author'];
697
- $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email'];
698
- $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP'];
699
- $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url'];
700
- $newcomments[$comment_id]['comment_date'] = $comment['comment_date'];
701
- $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt'];
702
- $newcomments[$comment_id]['comment_content'] = $comment['comment_content'];
703
- $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved'];
704
- $newcomments[$comment_id]['comment_type'] = $comment['comment_type'];
705
- $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent'];
706
- $newcomments[$comment_id]['commentmeta'] = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
707
- if ( isset( $this->processed_authors[$comment['comment_user_id']] ) )
708
- $newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']];
709
- }
710
- ksort( $newcomments );
711
-
712
- foreach ( $newcomments as $key => $comment ) {
713
- // if this is a new post we can skip the comment_exists() check
714
- if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) {
715
- if ( isset( $inserted_comments[$comment['comment_parent']] ) )
716
- $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
717
- $comment = wp_filter_comment( $comment );
718
- $inserted_comments[$key] = wp_insert_comment( $comment );
719
- do_action( 'wp_import_insert_comment', $inserted_comments[$key], $comment, $comment_post_ID, $post );
720
-
721
- foreach( $comment['commentmeta'] as $meta ) {
722
- $value = maybe_unserialize( $meta['value'] );
723
- add_comment_meta( $inserted_comments[$key], $meta['key'], $value );
724
- }
725
-
726
- $num_comments++;
727
- }
728
- }
729
- unset( $newcomments, $inserted_comments, $post['comments'] );
730
- }
731
-
732
- if ( ! isset( $post['postmeta'] ) )
733
- $post['postmeta'] = array();
734
-
735
- $post['postmeta'] = apply_filters( 'wp_import_post_meta', $post['postmeta'], $post_id, $post );
736
-
737
- // add/update post meta
738
- if ( ! empty( $post['postmeta'] ) ) {
739
- foreach ( $post['postmeta'] as $meta ) {
740
- $key = apply_filters( 'import_post_meta_key', $meta['key'], $post_id, $post );
741
- $value = false;
742
-
743
- if ( '_edit_last' == $key ) {
744
- if ( isset( $this->processed_authors[intval($meta['value'])] ) )
745
- $value = $this->processed_authors[intval($meta['value'])];
746
- else
747
- $key = false;
748
- }
749
-
750
- if ( $key ) {
751
- // export gets meta straight from the DB so could have a serialized string
752
- if ( ! $value )
753
- $value = maybe_unserialize( $meta['value'] );
754
-
755
- add_post_meta( $post_id, $key, $value );
756
- do_action( 'import_post_meta', $post_id, $key, $value );
757
-
758
- // if the post has a featured image, take note of this in case of remap
759
- if ( '_thumbnail_id' == $key )
760
- $this->featured_images[$post_id] = (int) $value;
761
- }
762
- }
763
- }
764
- }
765
-
766
- unset( $this->posts );
767
- }
768
-
769
- /**
770
- * Attempt to create a new menu item from import data
771
- *
772
- * Fails for draft, orphaned menu items and those without an associated nav_menu
773
- * or an invalid nav_menu term. If the post type or term object which the menu item
774
- * represents doesn't exist then the menu item will not be imported (waits until the
775
- * end of the import to retry again before discarding).
776
- *
777
- * @param array $item Menu item details from WXR file
778
- */
779
- function process_menu_item( $item ) {
780
- // skip draft, orphaned menu items
781
- if ( 'draft' == $item['status'] )
782
- return;
783
-
784
- $menu_slug = false;
785
- if ( isset($item['terms']) ) {
786
- // loop through terms, assume first nav_menu term is correct menu
787
- foreach ( $item['terms'] as $term ) {
788
- if ( 'nav_menu' == $term['domain'] ) {
789
- $menu_slug = $term['slug'];
790
- break;
791
- }
792
- }
793
- }
794
-
795
- // no nav_menu term associated with this menu item
796
- if ( ! $menu_slug ) {
797
- _e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' );
798
- echo '<br />';
799
- return;
800
- }
801
-
802
- $menu_id = term_exists( $menu_slug, 'nav_menu' );
803
- if ( ! $menu_id ) {
804
- printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) );
805
- echo '<br />';
806
- return;
807
- } else {
808
- $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
809
- }
810
-
811
- foreach ( $item['postmeta'] as $meta )
812
- $$meta['key'] = $meta['value'];
813
-
814
- if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) {
815
- $_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)];
816
- } else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) {
817
- $_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)];
818
- } else if ( 'custom' != $_menu_item_type ) {
819
- // associated object is missing or not imported yet, we'll retry later
820
- $this->missing_menu_items[] = $item;
821
- return;
822
- }
823
-
824
- if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) {
825
- $_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)];
826
- } else if ( $_menu_item_menu_item_parent ) {
827
- $this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent;
828
- $_menu_item_menu_item_parent = 0;
829
- }
830
-
831
- // wp_update_nav_menu_item expects CSS classes as a space separated string
832
- $_menu_item_classes = maybe_unserialize( $_menu_item_classes );
833
- if ( is_array( $_menu_item_classes ) )
834
- $_menu_item_classes = implode( ' ', $_menu_item_classes );
835
-
836
- $args = array(
837
- 'menu-item-object-id' => $_menu_item_object_id,
838
- 'menu-item-object' => $_menu_item_object,
839
- 'menu-item-parent-id' => $_menu_item_menu_item_parent,
840
- 'menu-item-position' => intval( $item['menu_order'] ),
841
- 'menu-item-type' => $_menu_item_type,
842
- 'menu-item-title' => $item['post_title'],
843
- 'menu-item-url' => $_menu_item_url,
844
- 'menu-item-description' => $item['post_content'],
845
- 'menu-item-attr-title' => $item['post_excerpt'],
846
- 'menu-item-target' => $_menu_item_target,
847
- 'menu-item-classes' => $_menu_item_classes,
848
- 'menu-item-xfn' => $_menu_item_xfn,
849
- 'menu-item-status' => $item['status']
850
- );
851
-
852
- $id = wp_update_nav_menu_item( $menu_id, 0, $args );
853
- if ( $id && ! is_wp_error( $id ) )
854
- $this->processed_menu_items[intval($item['post_id'])] = (int) $id;
855
- }
856
-
857
- /**
858
- * If fetching attachments is enabled then attempt to create a new attachment
859
- *
860
- * @param array $post Attachment post details from WXR
861
- * @param string $url URL to fetch attachment from
862
- * @return int|WP_Error Post ID on success, WP_Error otherwise
863
- */
864
- function process_attachment( $post, $url ) {
865
- if ( ! $this->fetch_attachments )
866
- return new WP_Error( 'attachment_processing_error',
867
- __( 'Fetching attachments is not enabled', 'wordpress-importer' ) );
868
-
869
- // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
870
- if ( preg_match( '|^/[\w\W]+$|', $url ) )
871
- $url = rtrim( $this->base_url, '/' ) . $url;
872
-
873
- $upload = $this->fetch_remote_file( $url, $post );
874
- if ( is_wp_error( $upload ) )
875
- return $upload;
876
-
877
- if ( $info = wp_check_filetype( $upload['file'] ) )
878
- $post['post_mime_type'] = $info['type'];
879
- else
880
- return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') );
881
-
882
- $post['guid'] = $upload['url'];
883
-
884
- // as per wp-admin/includes/upload.php
885
- $post_id = wp_insert_attachment( $post, $upload['file'] );
886
- wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
887
-
888
- // remap resized image URLs, works by stripping the extension and remapping the URL stub.
889
- if ( preg_match( '!^image/!', $info['type'] ) ) {
890
- $parts = pathinfo( $url );
891
- $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
892
-
893
- $parts_new = pathinfo( $upload['url'] );
894
- $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
895
-
896
- $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
897
- }
898
-
899
- return $post_id;
900
- }
901
-
902
- /**
903
- * Attempt to download a remote file attachment
904
- *
905
- * @param string $url URL of item to fetch
906
- * @param array $post Attachment details
907
- * @return array|WP_Error Local file location details on success, WP_Error otherwise
908
- */
909
- function fetch_remote_file( $url, $post ) {
910
- // extract the file name and extension from the url
911
- $file_name = basename( $url );
912
-
913
- // get placeholder file in the upload dir with a unique, sanitized filename
914
- $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
915
- if ( $upload['error'] )
916
- return new WP_Error( 'upload_dir_error', $upload['error'] );
917
-
918
- // fetch the remote url and write it to the placeholder file
919
- $headers = wp_get_http( $url, $upload['file'] );
920
-
921
- // request failed
922
- if ( ! $headers ) {
923
- @unlink( $upload['file'] );
924
- return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') );
925
- }
926
-
927
- // make sure the fetch was successful
928
- if ( $headers['response'] != '200' ) {
929
- @unlink( $upload['file'] );
930
- 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']) ) );
931
- }
932
-
933
- $filesize = filesize( $upload['file'] );
934
-
935
- if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) {
936
- @unlink( $upload['file'] );
937
- return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') );
938
- }
939
-
940
- if ( 0 == $filesize ) {
941
- @unlink( $upload['file'] );
942
- return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') );
943
- }
944
-
945
- $max_size = (int) $this->max_attachment_size();
946
- if ( ! empty( $max_size ) && $filesize > $max_size ) {
947
- @unlink( $upload['file'] );
948
- return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) );
949
- }
950
-
951
- // keep track of the old and new urls so we can substitute them later
952
- $this->url_remap[$url] = $upload['url'];
953
- $this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed?
954
- // keep track of the destination if the remote url is redirected somewhere else
955
- if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url )
956
- $this->url_remap[$headers['x-final-location']] = $upload['url'];
957
-
958
- return $upload;
959
- }
960
-
961
- /**
962
- * Attempt to associate posts and menu items with previously missing parents
963
- *
964
- * An imported post's parent may not have been imported when it was first created
965
- * so try again. Similarly for child menu items and menu items which were missing
966
- * the object (e.g. post) they represent in the menu
967
- */
968
- function backfill_parents() {
969
- global $wpdb;
970
-
971
- // find parents for post orphans
972
- foreach ( $this->post_orphans as $child_id => $parent_id ) {
973
- $local_child_id = $local_parent_id = false;
974
- if ( isset( $this->processed_posts[$child_id] ) )
975
- $local_child_id = $this->processed_posts[$child_id];
976
- if ( isset( $this->processed_posts[$parent_id] ) )
977
- $local_parent_id = $this->processed_posts[$parent_id];
978
-
979
- if ( $local_child_id && $local_parent_id )
980
- $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' );
981
- }
982
-
983
- // all other posts/terms are imported, retry menu items with missing associated object
984
- $missing_menu_items = $this->missing_menu_items;
985
- foreach ( $missing_menu_items as $item )
986
- $this->process_menu_item( $item );
987
-
988
- // find parents for menu item orphans
989
- foreach ( $this->menu_item_orphans as $child_id => $parent_id ) {
990
- $local_child_id = $local_parent_id = 0;
991
- if ( isset( $this->processed_menu_items[$child_id] ) )
992
- $local_child_id = $this->processed_menu_items[$child_id];
993
- if ( isset( $this->processed_menu_items[$parent_id] ) )
994
- $local_parent_id = $this->processed_menu_items[$parent_id];
995
-
996
- if ( $local_child_id && $local_parent_id )
997
- update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id );
998
- }
999
- }
1000
-
1001
- /**
1002
- * Use stored mapping information to update old attachment URLs
1003
- */
1004
- function backfill_attachment_urls() {
1005
- global $wpdb;
1006
- // make sure we do the longest urls first, in case one is a substring of another
1007
- uksort( $this->url_remap, array(&$this, 'cmpr_strlen') );
1008
-
1009
- foreach ( $this->url_remap as $from_url => $to_url ) {
1010
- // remap urls in post_content
1011
- $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) );
1012
- // remap enclosure urls
1013
- $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) );
1014
- }
1015
- }
1016
-
1017
- /**
1018
- * Update _thumbnail_id meta to new, imported attachment IDs
1019
- */
1020
- function remap_featured_images() {
1021
- // cycle through posts that have a featured image
1022
- foreach ( $this->featured_images as $post_id => $value ) {
1023
- if ( isset( $this->processed_posts[$value] ) ) {
1024
- $new_id = $this->processed_posts[$value];
1025
- // only update if there's a difference
1026
- if ( $new_id != $value )
1027
- update_post_meta( $post_id, '_thumbnail_id', $new_id );
1028
- }
1029
- }
1030
- }
1031
-
1032
- /**
1033
- * Parse a WXR file
1034
- *
1035
- * @param string $file Path to WXR file for parsing
1036
- * @return array Information gathered from the WXR file
1037
- */
1038
- function parse( $file ) {
1039
- $parser = new WXR_Parser();
1040
- return $parser->parse( $file );
1041
- }
1042
-
1043
- // Display import page title
1044
- function header() {
1045
- echo '<div class="wrap">';
1046
- screen_icon();
1047
- echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>';
1048
-
1049
- $updates = get_plugin_updates();
1050
- $basename = plugin_basename(__FILE__);
1051
- if ( isset( $updates[$basename] ) ) {
1052
- $update = $updates[$basename];
1053
- echo '<div class="error"><p><strong>';
1054
- 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 );
1055
- echo '</strong></p></div>';
1056
- }
1057
- }
1058
-
1059
- // Close div.wrap
1060
- function footer() {
1061
- echo '</div>';
1062
- }
1063
-
1064
- /**
1065
- * Display introductory text and file upload form
1066
- */
1067
- function greet() {
1068
- echo '<div class="narrow">';
1069
- 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>';
1070
- echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>';
1071
- wp_import_upload_form( 'admin.php?import=wordpress&amp;step=1' );
1072
- echo '</div>';
1073
- }
1074
-
1075
- /**
1076
- * Decide if the given meta key maps to information we will want to import
1077
- *
1078
- * @param string $key The meta key to check
1079
- * @return string|bool The key if we do want to import, false if not
1080
- */
1081
- function is_valid_meta_key( $key ) {
1082
- // skip attachment metadata since we'll regenerate it from scratch
1083
- // skip _edit_lock as not relevant for import
1084
- if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
1085
- return false;
1086
- return $key;
1087
- }
1088
-
1089
- /**
1090
- * Decide whether or not the importer is allowed to create users.
1091
- * Default is true, can be filtered via import_allow_create_users
1092
- *
1093
- * @return bool True if creating users is allowed
1094
- */
1095
- function allow_create_users() {
1096
- return apply_filters( 'import_allow_create_users', true );
1097
- }
1098
-
1099
- /**
1100
- * Decide whether or not the importer should attempt to download attachment files.
1101
- * Default is true, can be filtered via import_allow_fetch_attachments. The choice
1102
- * made at the import options screen must also be true, false here hides that checkbox.
1103
- *
1104
- * @return bool True if downloading attachments is allowed
1105
- */
1106
- function allow_fetch_attachments() {
1107
- return apply_filters( 'import_allow_fetch_attachments', true );
1108
- }
1109
-
1110
- /**
1111
- * Decide what the maximum file size for downloaded attachments is.
1112
- * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
1113
- *
1114
- * @return int Maximum attachment file size to import
1115
- */
1116
- function max_attachment_size() {
1117
- return apply_filters( 'import_attachment_size_limit', 0 );
1118
- }
1119
-
1120
- /**
1121
- * Added to http_request_timeout filter to force timeout at 60 seconds during import
1122
- * @return int 60
1123
- */
1124
- function bump_request_timeout( $val ) {
1125
- return 60;
1126
- }
1127
-
1128
- // return the difference in length between two strings
1129
- function cmpr_strlen( $a, $b ) {
1130
- return strlen($b) - strlen($a);
1131
- }
1132
- }
1133
-
1134
- } // class_exists( 'WP_Importer' )
1135
-
1136
- function wordpress_importer_init() {
1137
- load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
1138
-
1139
- /**
1140
- * WordPress Importer object for registering the import callback
1141
- * @global WP_Import $wp_import
1142
- */
1143
- $GLOBALS['wp_import'] = new WP_Import();
1144
- 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' ) );
1145
- }
1146
- add_action( 'admin_init', 'wordpress_importer_init' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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.6.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.2; // 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
+ /**
67
+ * Registered callback function for the WordPress Importer
68
+ *
69
+ * Manages the three separate stages of the WXR import process
70
+ */
71
+ function dispatch() {
72
+ $this->header();
73
+
74
+ $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
75
+ switch ( $step ) {
76
+ case 0:
77
+ $this->greet();
78
+ break;
79
+ case 1:
80
+ check_admin_referer( 'import-upload' );
81
+ if ( $this->handle_upload() )
82
+ $this->import_options();
83
+ break;
84
+ case 2:
85
+ check_admin_referer( 'import-wordpress' );
86
+ $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() );
87
+ $this->id = (int) $_POST['import_id'];
88
+ $file = get_attached_file( $this->id );
89
+ set_time_limit(0);
90
+ $this->import( $file );
91
+ break;
92
+ }
93
+
94
+ $this->footer();
95
+ }
96
+
97
+ /**
98
+ * The main controller for the actual import stage.
99
+ *
100
+ * @param string $file Path to the WXR file for importing
101
+ */
102
+ function import( $file ) {
103
+ add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
104
+ add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
105
+
106
+ $this->import_start( $file );
107
+
108
+ $this->get_author_mapping();
109
+
110
+ wp_suspend_cache_invalidation( true );
111
+ $this->process_categories();
112
+ $this->process_tags();
113
+ $this->process_terms();
114
+ $this->process_posts();
115
+ wp_suspend_cache_invalidation( false );
116
+
117
+ // update incorrect/missing information in the DB
118
+ $this->backfill_parents();
119
+ $this->backfill_attachment_urls();
120
+ $this->remap_featured_images();
121
+
122
+ $this->import_end();
123
+ }
124
+
125
+ /**
126
+ * Parses the WXR file and prepares us for the task of processing parsed data
127
+ *
128
+ * @param string $file Path to the WXR file for importing
129
+ */
130
+ function import_start( $file ) {
131
+ if ( ! is_file($file) ) {
132
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
133
+ echo __( 'The file does not exist, please try again.', 'wordpress-importer' ) . '</p>';
134
+ $this->footer();
135
+ die();
136
+ }
137
+
138
+ $import_data = $this->parse( $file );
139
+
140
+ if ( is_wp_error( $import_data ) ) {
141
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
142
+ echo esc_html( $import_data->get_error_message() ) . '</p>';
143
+ $this->footer();
144
+ die();
145
+ }
146
+
147
+ $this->version = $import_data['version'];
148
+ $this->get_authors_from_import( $import_data );
149
+ $this->posts = $import_data['posts'];
150
+ $this->terms = $import_data['terms'];
151
+ $this->categories = $import_data['categories'];
152
+ $this->tags = $import_data['tags'];
153
+ $this->base_url = esc_url( $import_data['base_url'] );
154
+
155
+ wp_defer_term_counting( true );
156
+ wp_defer_comment_counting( true );
157
+
158
+ do_action( 'import_start' );
159
+ }
160
+
161
+ /**
162
+ * Performs post-import cleanup of files and the cache
163
+ */
164
+ function import_end() {
165
+ wp_import_cleanup( $this->id );
166
+
167
+ wp_cache_flush();
168
+ foreach ( get_taxonomies() as $tax ) {
169
+ delete_option( "{$tax}_children" );
170
+ _get_term_hierarchy( $tax );
171
+ }
172
+
173
+ wp_defer_term_counting( false );
174
+ wp_defer_comment_counting( false );
175
+
176
+ echo '<p>' . __( 'All done.', 'wordpress-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wordpress-importer' ) . '</a>' . '</p>';
177
+ echo '<p>' . __( 'Remember to update the passwords and roles of imported users.', 'wordpress-importer' ) . '</p>';
178
+
179
+ do_action( 'import_end' );
180
+ }
181
+
182
+ /**
183
+ * Handles the WXR upload and initial parsing of the file to prepare for
184
+ * displaying author import options
185
+ *
186
+ * @return bool False if error uploading or invalid file, true otherwise
187
+ */
188
+ function handle_upload() {
189
+ $file = wp_import_handle_upload();
190
+
191
+ if ( isset( $file['error'] ) ) {
192
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
193
+ echo esc_html( $file['error'] ) . '</p>';
194
+ return false;
195
+ } else if ( ! file_exists( $file['file'] ) ) {
196
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
197
+ printf( __( 'The export file could not be found at <code>%s</code>. It is likely that this was caused by a permissions problem.', 'wordpress-importer' ), esc_html( $file['file'] ) );
198
+ echo '</p>';
199
+ return false;
200
+ }
201
+
202
+ $this->id = (int) $file['id'];
203
+ $import_data = $this->parse( $file['file'] );
204
+ if ( is_wp_error( $import_data ) ) {
205
+ echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />';
206
+ echo esc_html( $import_data->get_error_message() ) . '</p>';
207
+ return false;
208
+ }
209
+
210
+ $this->version = $import_data['version'];
211
+ if ( $this->version > $this->max_wxr_version ) {
212
+ echo '<div class="error"><p><strong>';
213
+ 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']) );
214
+ echo '</strong></p></div>';
215
+ }
216
+
217
+ $this->get_authors_from_import( $import_data );
218
+
219
+ return true;
220
+ }
221
+
222
+ /**
223
+ * Retrieve authors from parsed WXR data
224
+ *
225
+ * Uses the provided author information from WXR 1.1 files
226
+ * or extracts info from each post for WXR 1.0 files
227
+ *
228
+ * @param array $import_data Data returned by a WXR parser
229
+ */
230
+ function get_authors_from_import( $import_data ) {
231
+ if ( ! empty( $import_data['authors'] ) ) {
232
+ $this->authors = $import_data['authors'];
233
+ // no author information, grab it from the posts
234
+ } else {
235
+ foreach ( $import_data['posts'] as $post ) {
236
+ $login = sanitize_user( $post['post_author'], true );
237
+ if ( empty( $login ) ) {
238
+ printf( __( 'Failed to import author %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html( $post['post_author'] ) );
239
+ echo '<br />';
240
+ continue;
241
+ }
242
+
243
+ if ( ! isset($this->authors[$login]) )
244
+ $this->authors[$login] = array(
245
+ 'author_login' => $login,
246
+ 'author_display_name' => $post['post_author']
247
+ );
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Display pre-import options, author importing/mapping and option to
254
+ * fetch attachments
255
+ */
256
+ function import_options() {
257
+ $j = 0;
258
+ ?>
259
+ <form action="<?php echo admin_url( 'admin.php?import=wordpress&amp;step=2' ); ?>" method="post">
260
+ <?php wp_nonce_field( 'import-wordpress' ); ?>
261
+ <input type="hidden" name="import_id" value="<?php echo $this->id; ?>" />
262
+
263
+ <?php if ( ! empty( $this->authors ) ) : ?>
264
+ <h3><?php _e( 'Assign Authors', 'wordpress-importer' ); ?></h3>
265
+ <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>
266
+ <?php if ( $this->allow_create_users() ) : ?>
267
+ <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>
268
+ <?php endif; ?>
269
+ <ol id="authors">
270
+ <?php foreach ( $this->authors as $author ) : ?>
271
+ <li><?php $this->author_select( $j++, $author ); ?></li>
272
+ <?php endforeach; ?>
273
+ </ol>
274
+ <?php endif; ?>
275
+
276
+ <?php if ( $this->allow_fetch_attachments() ) : ?>
277
+ <h3><?php _e( 'Import Attachments', 'wordpress-importer' ); ?></h3>
278
+ <p>
279
+ <input type="checkbox" value="1" name="fetch_attachments" id="import-attachments" />
280
+ <label for="import-attachments"><?php _e( 'Download and import file attachments', 'wordpress-importer' ); ?></label>
281
+ </p>
282
+ <?php endif; ?>
283
+
284
+ <p class="submit"><input type="submit" class="button" value="<?php esc_attr_e( 'Submit', 'wordpress-importer' ); ?>" /></p>
285
+ </form>
286
+ <?php
287
+ }
288
+
289
+ /**
290
+ * Display import options for an individual author. That is, either create
291
+ * a new user based on import info or map to an existing user
292
+ *
293
+ * @param int $n Index for each author in the form
294
+ * @param array $author Author information, e.g. login, display name, email
295
+ */
296
+ function author_select( $n, $author ) {
297
+ _e( 'Import author:', 'wordpress-importer' );
298
+ echo ' <strong>' . esc_html( $author['author_display_name'] );
299
+ if ( $this->version != '1.0' ) echo ' (' . esc_html( $author['author_login'] ) . ')';
300
+ echo '</strong><br />';
301
+
302
+ if ( $this->version != '1.0' )
303
+ echo '<div style="margin-left:18px">';
304
+
305
+ $create_users = $this->allow_create_users();
306
+ if ( $create_users ) {
307
+ if ( $this->version != '1.0' ) {
308
+ _e( 'or create new user with login name:', 'wordpress-importer' );
309
+ $value = '';
310
+ } else {
311
+ _e( 'as a new user:', 'wordpress-importer' );
312
+ $value = esc_attr( sanitize_user( $author['author_login'], true ) );
313
+ }
314
+
315
+ echo ' <input type="text" name="user_new['.$n.']" value="'. $value .'" /><br />';
316
+ }
317
+
318
+ if ( ! $create_users && $this->version == '1.0' )
319
+ _e( 'assign posts to an existing user:', 'wordpress-importer' );
320
+ else
321
+ _e( 'or assign posts to an existing user:', 'wordpress-importer' );
322
+ wp_dropdown_users( array( 'name' => "user_map[$n]", 'multi' => true, 'show_option_all' => __( '- Select -', 'wordpress-importer' ) ) );
323
+ echo '<input type="hidden" name="imported_authors['.$n.']" value="' . esc_attr( $author['author_login'] ) . '" />';
324
+
325
+ if ( $this->version != '1.0' )
326
+ echo '</div>';
327
+ }
328
+
329
+ /**
330
+ * Map old author logins to local user IDs based on decisions made
331
+ * in import options form. Can map to an existing user, create a new user
332
+ * or falls back to the current user in case of error with either of the previous
333
+ */
334
+ function get_author_mapping() {
335
+ if ( ! isset( $_POST['imported_authors'] ) )
336
+ return;
337
+
338
+ $create_users = $this->allow_create_users();
339
+
340
+ foreach ( (array) $_POST['imported_authors'] as $i => $old_login ) {
341
+ // Multisite adds strtolower to sanitize_user. Need to sanitize here to stop breakage in process_posts.
342
+ $santized_old_login = sanitize_user( $old_login, true );
343
+ $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false;
344
+
345
+ if ( ! empty( $_POST['user_map'][$i] ) ) {
346
+ $user = get_userdata( intval($_POST['user_map'][$i]) );
347
+ if ( isset( $user->ID ) ) {
348
+ if ( $old_id )
349
+ $this->processed_authors[$old_id] = $user->ID;
350
+ $this->author_mapping[$santized_old_login] = $user->ID;
351
+ }
352
+ } else if ( $create_users ) {
353
+ if ( ! empty($_POST['user_new'][$i]) ) {
354
+ $user_id = wp_create_user( $_POST['user_new'][$i], wp_generate_password() );
355
+ } else if ( $this->version != '1.0' ) {
356
+ $user_data = array(
357
+ 'user_login' => $old_login,
358
+ 'user_pass' => wp_generate_password(),
359
+ 'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '',
360
+ 'display_name' => $this->authors[$old_login]['author_display_name'],
361
+ 'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '',
362
+ 'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '',
363
+ );
364
+ $user_id = wp_insert_user( $user_data );
365
+ }
366
+
367
+ if ( ! is_wp_error( $user_id ) ) {
368
+ if ( $old_id )
369
+ $this->processed_authors[$old_id] = $user_id;
370
+ $this->author_mapping[$santized_old_login] = $user_id;
371
+ } else {
372
+ 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']) );
373
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
374
+ echo ' ' . $user_id->get_error_message();
375
+ echo '<br />';
376
+ }
377
+ }
378
+
379
+ // failsafe: if the user_id was invalid, default to the current user
380
+ if ( ! isset( $this->author_mapping[$santized_old_login] ) ) {
381
+ if ( $old_id )
382
+ $this->processed_authors[$old_id] = (int) get_current_user_id();
383
+ $this->author_mapping[$santized_old_login] = (int) get_current_user_id();
384
+ }
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Create new categories based on import information
390
+ *
391
+ * Doesn't create a new category if its slug already exists
392
+ */
393
+ function process_categories() {
394
+ $this->categories = apply_filters( 'wp_import_categories', $this->categories );
395
+
396
+ if ( empty( $this->categories ) )
397
+ return;
398
+
399
+ foreach ( $this->categories as $cat ) {
400
+ // if the category already exists leave it alone
401
+ $term_id = term_exists( $cat['category_nicename'], 'category' );
402
+ if ( $term_id ) {
403
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
404
+ if ( isset($cat['term_id']) )
405
+ $this->processed_terms[intval($cat['term_id'])] = (int) $term_id;
406
+ continue;
407
+ }
408
+
409
+ $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] );
410
+ $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : '';
411
+ $catarr = array(
412
+ 'category_nicename' => $cat['category_nicename'],
413
+ 'category_parent' => $category_parent,
414
+ 'cat_name' => $cat['cat_name'],
415
+ 'category_description' => $category_description
416
+ );
417
+ $catarr = wp_slash( $catarr );
418
+
419
+ $id = wp_insert_category( $catarr );
420
+ if ( ! is_wp_error( $id ) ) {
421
+ if ( isset($cat['term_id']) )
422
+ $this->processed_terms[intval($cat['term_id'])] = $id;
423
+ } else {
424
+ printf( __( 'Failed to import category %s', 'wordpress-importer' ), esc_html($cat['category_nicename']) );
425
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
426
+ echo ': ' . $id->get_error_message();
427
+ echo '<br />';
428
+ continue;
429
+ }
430
+
431
+ $this->process_termmeta( $cat, $id['term_id'] );
432
+ }
433
+
434
+ unset( $this->categories );
435
+ }
436
+
437
+ /**
438
+ * Create new post tags based on import information
439
+ *
440
+ * Doesn't create a tag if its slug already exists
441
+ */
442
+ function process_tags() {
443
+ $this->tags = apply_filters( 'wp_import_tags', $this->tags );
444
+
445
+ if ( empty( $this->tags ) )
446
+ return;
447
+
448
+ foreach ( $this->tags as $tag ) {
449
+ // if the tag already exists leave it alone
450
+ $term_id = term_exists( $tag['tag_slug'], 'post_tag' );
451
+ if ( $term_id ) {
452
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
453
+ if ( isset($tag['term_id']) )
454
+ $this->processed_terms[intval($tag['term_id'])] = (int) $term_id;
455
+ continue;
456
+ }
457
+
458
+ $tag = wp_slash( $tag );
459
+ $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : '';
460
+ $tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc );
461
+
462
+ $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr );
463
+ if ( ! is_wp_error( $id ) ) {
464
+ if ( isset($tag['term_id']) )
465
+ $this->processed_terms[intval($tag['term_id'])] = $id['term_id'];
466
+ } else {
467
+ printf( __( 'Failed to import post tag %s', 'wordpress-importer' ), esc_html($tag['tag_name']) );
468
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
469
+ echo ': ' . $id->get_error_message();
470
+ echo '<br />';
471
+ continue;
472
+ }
473
+
474
+ $this->process_termmeta( $tag, $id['term_id'] );
475
+ }
476
+
477
+ unset( $this->tags );
478
+ }
479
+
480
+ /**
481
+ * Create new terms based on import information
482
+ *
483
+ * Doesn't create a term its slug already exists
484
+ */
485
+ function process_terms() {
486
+ $this->terms = apply_filters( 'wp_import_terms', $this->terms );
487
+
488
+ if ( empty( $this->terms ) )
489
+ return;
490
+
491
+ foreach ( $this->terms as $term ) {
492
+ // if the term already exists in the correct taxonomy leave it alone
493
+ $term_id = term_exists( $term['slug'], $term['term_taxonomy'] );
494
+ if ( $term_id ) {
495
+ if ( is_array($term_id) ) $term_id = $term_id['term_id'];
496
+ if ( isset($term['term_id']) )
497
+ $this->processed_terms[intval($term['term_id'])] = (int) $term_id;
498
+ continue;
499
+ }
500
+
501
+ if ( empty( $term['term_parent'] ) ) {
502
+ $parent = 0;
503
+ } else {
504
+ $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] );
505
+ if ( is_array( $parent ) ) $parent = $parent['term_id'];
506
+ }
507
+ $term = wp_slash( $term );
508
+ $description = isset( $term['term_description'] ) ? $term['term_description'] : '';
509
+ $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) );
510
+
511
+ $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr );
512
+ if ( ! is_wp_error( $id ) ) {
513
+ if ( isset($term['term_id']) )
514
+ $this->processed_terms[intval($term['term_id'])] = $id['term_id'];
515
+ } else {
516
+ printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) );
517
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
518
+ echo ': ' . $id->get_error_message();
519
+ echo '<br />';
520
+ continue;
521
+ }
522
+
523
+ $this->process_termmeta( $term, $id['term_id'] );
524
+ }
525
+
526
+ unset( $this->terms );
527
+ }
528
+
529
+ /**
530
+ * Add metadata to imported term.
531
+ *
532
+ * @since 0.6.2
533
+ *
534
+ * @param array $term Term data from WXR import.
535
+ * @param int $term_id ID of the newly created term.
536
+ */
537
+ protected function process_termmeta( $term, $term_id ) {
538
+ if ( ! isset( $term['termmeta'] ) ) {
539
+ $term['termmeta'] = array();
540
+ }
541
+
542
+ /**
543
+ * Filters the metadata attached to an imported term.
544
+ *
545
+ * @since 0.6.2
546
+ *
547
+ * @param array $termmeta Array of term meta.
548
+ * @param int $term_id ID of the newly created term.
549
+ * @param array $term Term data from the WXR import.
550
+ */
551
+ $term['termmeta'] = apply_filters( 'wp_import_term_meta', $term['termmeta'], $term_id, $term );
552
+
553
+ if ( empty( $term['termmeta'] ) ) {
554
+ return;
555
+ }
556
+
557
+ foreach ( $term['termmeta'] as $meta ) {
558
+ /**
559
+ * Filters the meta key for an imported piece of term meta.
560
+ *
561
+ * @since 0.6.2
562
+ *
563
+ * @param string $meta_key Meta key.
564
+ * @param int $term_id ID of the newly created term.
565
+ * @param array $term Term data from the WXR import.
566
+ */
567
+ $key = apply_filters( 'import_term_meta_key', $meta['key'], $term_id, $term );
568
+ if ( ! $key ) {
569
+ continue;
570
+ }
571
+
572
+ // Export gets meta straight from the DB so could have a serialized string
573
+ $value = maybe_unserialize( $meta['value'] );
574
+
575
+ add_term_meta( $term_id, $key, $value );
576
+
577
+ /**
578
+ * Fires after term meta is imported.
579
+ *
580
+ * @since 0.6.2
581
+ *
582
+ * @param int $term_id ID of the newly created term.
583
+ * @param string $key Meta key.
584
+ * @param mixed $value Meta value.
585
+ */
586
+ do_action( 'import_term_meta', $term_id, $key, $value );
587
+ }
588
+ }
589
+
590
+ /**
591
+ * Create new posts based on import information
592
+ *
593
+ * Posts marked as having a parent which doesn't exist will become top level items.
594
+ * Doesn't create a new post if: the post type doesn't exist, the given post ID
595
+ * is already noted as imported or a post with the same title and date already exists.
596
+ * Note that new/updated terms, comments and meta are imported for the last of the above.
597
+ */
598
+ function process_posts() {
599
+ $this->posts = apply_filters( 'wp_import_posts', $this->posts );
600
+
601
+ foreach ( $this->posts as $post ) {
602
+ $post = apply_filters( 'wp_import_post_data_raw', $post );
603
+
604
+ if ( ! post_type_exists( $post['post_type'] ) ) {
605
+ printf( __( 'Failed to import &#8220;%s&#8221;: Invalid post type %s', 'wordpress-importer' ),
606
+ esc_html($post['post_title']), esc_html($post['post_type']) );
607
+ echo '<br />';
608
+ do_action( 'wp_import_post_exists', $post );
609
+ continue;
610
+ }
611
+
612
+ if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) )
613
+ continue;
614
+
615
+ if ( $post['status'] == 'auto-draft' )
616
+ continue;
617
+
618
+ if ( 'nav_menu_item' == $post['post_type'] ) {
619
+ $this->process_menu_item( $post );
620
+ continue;
621
+ }
622
+
623
+ $post_type_object = get_post_type_object( $post['post_type'] );
624
+
625
+ $post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
626
+
627
+ /**
628
+ * Filter ID of the existing post corresponding to post currently importing.
629
+ *
630
+ * Return 0 to force the post to be imported. Filter the ID to be something else
631
+ * to override which existing post is mapped to the imported post.
632
+ *
633
+ * @see post_exists()
634
+ * @since 0.6.2
635
+ *
636
+ * @param int $post_exists Post ID, or 0 if post did not exist.
637
+ * @param array $post The post array to be inserted.
638
+ */
639
+ $post_exists = apply_filters( 'wp_import_existing_post', $post_exists, $post );
640
+
641
+ if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
642
+ printf( __('%s &#8220;%s&#8221; already exists.', 'wordpress-importer'), $post_type_object->labels->singular_name, esc_html($post['post_title']) );
643
+ echo '<br />';
644
+ $comment_post_ID = $post_id = $post_exists;
645
+ $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists );
646
+ } else {
647
+ $post_parent = (int) $post['post_parent'];
648
+ if ( $post_parent ) {
649
+ // if we already know the parent, map it to the new local ID
650
+ if ( isset( $this->processed_posts[$post_parent] ) ) {
651
+ $post_parent = $this->processed_posts[$post_parent];
652
+ // otherwise record the parent for later
653
+ } else {
654
+ $this->post_orphans[intval($post['post_id'])] = $post_parent;
655
+ $post_parent = 0;
656
+ }
657
+ }
658
+
659
+ // map the post author
660
+ $author = sanitize_user( $post['post_author'], true );
661
+ if ( isset( $this->author_mapping[$author] ) )
662
+ $author = $this->author_mapping[$author];
663
+ else
664
+ $author = (int) get_current_user_id();
665
+
666
+ $postdata = array(
667
+ 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'],
668
+ 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'],
669
+ 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'],
670
+ 'post_status' => $post['status'], 'post_name' => $post['post_name'],
671
+ 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'],
672
+ 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'],
673
+ 'post_type' => $post['post_type'], 'post_password' => $post['post_password']
674
+ );
675
+
676
+ $original_post_ID = $post['post_id'];
677
+ $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $post );
678
+
679
+ $postdata = wp_slash( $postdata );
680
+
681
+ if ( 'attachment' == $postdata['post_type'] ) {
682
+ $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid'];
683
+
684
+ // try to use _wp_attached file for upload folder placement to ensure the same location as the export site
685
+ // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
686
+ $postdata['upload_date'] = $post['post_date'];
687
+ if ( isset( $post['postmeta'] ) ) {
688
+ foreach( $post['postmeta'] as $meta ) {
689
+ if ( $meta['key'] == '_wp_attached_file' ) {
690
+ if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) )
691
+ $postdata['upload_date'] = $matches[0];
692
+ break;
693
+ }
694
+ }
695
+ }
696
+
697
+ $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url );
698
+ } else {
699
+ $comment_post_ID = $post_id = wp_insert_post( $postdata, true );
700
+ do_action( 'wp_import_insert_post', $post_id, $original_post_ID, $postdata, $post );
701
+ }
702
+
703
+ if ( is_wp_error( $post_id ) ) {
704
+ printf( __( 'Failed to import %s &#8220;%s&#8221;', 'wordpress-importer' ),
705
+ $post_type_object->labels->singular_name, esc_html($post['post_title']) );
706
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
707
+ echo ': ' . $post_id->get_error_message();
708
+ echo '<br />';
709
+ continue;
710
+ }
711
+
712
+ if ( $post['is_sticky'] == 1 )
713
+ stick_post( $post_id );
714
+ }
715
+
716
+ // map pre-import ID to local ID
717
+ $this->processed_posts[intval($post['post_id'])] = (int) $post_id;
718
+
719
+ if ( ! isset( $post['terms'] ) )
720
+ $post['terms'] = array();
721
+
722
+ $post['terms'] = apply_filters( 'wp_import_post_terms', $post['terms'], $post_id, $post );
723
+
724
+ // add categories, tags and other terms
725
+ if ( ! empty( $post['terms'] ) ) {
726
+ $terms_to_set = array();
727
+ foreach ( $post['terms'] as $term ) {
728
+ // back compat with WXR 1.0 map 'tag' to 'post_tag'
729
+ $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain'];
730
+ $term_exists = term_exists( $term['slug'], $taxonomy );
731
+ $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
732
+ if ( ! $term_id ) {
733
+ $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
734
+ if ( ! is_wp_error( $t ) ) {
735
+ $term_id = $t['term_id'];
736
+ do_action( 'wp_import_insert_term', $t, $term, $post_id, $post );
737
+ } else {
738
+ printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($taxonomy), esc_html($term['name']) );
739
+ if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
740
+ echo ': ' . $t->get_error_message();
741
+ echo '<br />';
742
+ do_action( 'wp_import_insert_term_failed', $t, $term, $post_id, $post );
743
+ continue;
744
+ }
745
+ }
746
+ $terms_to_set[$taxonomy][] = intval( $term_id );
747
+ }
748
+
749
+ foreach ( $terms_to_set as $tax => $ids ) {
750
+ $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
751
+ do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $post );
752
+ }
753
+ unset( $post['terms'], $terms_to_set );
754
+ }
755
+
756
+ if ( ! isset( $post['comments'] ) )
757
+ $post['comments'] = array();
758
+
759
+ $post['comments'] = apply_filters( 'wp_import_post_comments', $post['comments'], $post_id, $post );
760
+
761
+ // add/update comments
762
+ if ( ! empty( $post['comments'] ) ) {
763
+ $num_comments = 0;
764
+ $inserted_comments = array();
765
+ foreach ( $post['comments'] as $comment ) {
766
+ $comment_id = $comment['comment_id'];
767
+ $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID;
768
+ $newcomments[$comment_id]['comment_author'] = $comment['comment_author'];
769
+ $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email'];
770
+ $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP'];
771
+ $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url'];
772
+ $newcomments[$comment_id]['comment_date'] = $comment['comment_date'];
773
+ $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt'];
774
+ $newcomments[$comment_id]['comment_content'] = $comment['comment_content'];
775
+ $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved'];
776
+ $newcomments[$comment_id]['comment_type'] = $comment['comment_type'];
777
+ $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent'];
778
+ $newcomments[$comment_id]['commentmeta'] = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
779
+ if ( isset( $this->processed_authors[$comment['comment_user_id']] ) )
780
+ $newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']];
781
+ }
782
+ ksort( $newcomments );
783
+
784
+ foreach ( $newcomments as $key => $comment ) {
785
+ // if this is a new post we can skip the comment_exists() check
786
+ if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) {
787
+ if ( isset( $inserted_comments[$comment['comment_parent']] ) )
788
+ $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
789
+ $comment = wp_filter_comment( $comment );
790
+ $inserted_comments[$key] = wp_insert_comment( $comment );
791
+ do_action( 'wp_import_insert_comment', $inserted_comments[$key], $comment, $comment_post_ID, $post );
792
+
793
+ foreach( $comment['commentmeta'] as $meta ) {
794
+ $value = maybe_unserialize( $meta['value'] );
795
+ add_comment_meta( $inserted_comments[$key], $meta['key'], $value );
796
+ }
797
+
798
+ $num_comments++;
799
+ }
800
+ }
801
+ unset( $newcomments, $inserted_comments, $post['comments'] );
802
+ }
803
+
804
+ if ( ! isset( $post['postmeta'] ) )
805
+ $post['postmeta'] = array();
806
+
807
+ $post['postmeta'] = apply_filters( 'wp_import_post_meta', $post['postmeta'], $post_id, $post );
808
+
809
+ // add/update post meta
810
+ if ( ! empty( $post['postmeta'] ) ) {
811
+ foreach ( $post['postmeta'] as $meta ) {
812
+ $key = apply_filters( 'import_post_meta_key', $meta['key'], $post_id, $post );
813
+ $value = false;
814
+
815
+ if ( '_edit_last' == $key ) {
816
+ if ( isset( $this->processed_authors[intval($meta['value'])] ) )
817
+ $value = $this->processed_authors[intval($meta['value'])];
818
+ else
819
+ $key = false;
820
+ }
821
+
822
+ if ( $key ) {
823
+ // export gets meta straight from the DB so could have a serialized string
824
+ if ( ! $value )
825
+ $value = maybe_unserialize( $meta['value'] );
826
+
827
+ add_post_meta( $post_id, $key, $value );
828
+ do_action( 'import_post_meta', $post_id, $key, $value );
829
+
830
+ // if the post has a featured image, take note of this in case of remap
831
+ if ( '_thumbnail_id' == $key )
832
+ $this->featured_images[$post_id] = (int) $value;
833
+ }
834
+ }
835
+ }
836
+ }
837
+
838
+ unset( $this->posts );
839
+ }
840
+
841
+ /**
842
+ * Attempt to create a new menu item from import data
843
+ *
844
+ * Fails for draft, orphaned menu items and those without an associated nav_menu
845
+ * or an invalid nav_menu term. If the post type or term object which the menu item
846
+ * represents doesn't exist then the menu item will not be imported (waits until the
847
+ * end of the import to retry again before discarding).
848
+ *
849
+ * @param array $item Menu item details from WXR file
850
+ */
851
+ function process_menu_item( $item ) {
852
+ // skip draft, orphaned menu items
853
+ if ( 'draft' == $item['status'] )
854
+ return;
855
+
856
+ $menu_slug = false;
857
+ if ( isset($item['terms']) ) {
858
+ // loop through terms, assume first nav_menu term is correct menu
859
+ foreach ( $item['terms'] as $term ) {
860
+ if ( 'nav_menu' == $term['domain'] ) {
861
+ $menu_slug = $term['slug'];
862
+ break;
863
+ }
864
+ }
865
+ }
866
+
867
+ // no nav_menu term associated with this menu item
868
+ if ( ! $menu_slug ) {
869
+ _e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' );
870
+ echo '<br />';
871
+ return;
872
+ }
873
+
874
+ $menu_id = term_exists( $menu_slug, 'nav_menu' );
875
+ if ( ! $menu_id ) {
876
+ printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) );
877
+ echo '<br />';
878
+ return;
879
+ } else {
880
+ $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
881
+ }
882
+
883
+ foreach ( $item['postmeta'] as $meta )
884
+ $$meta['key'] = $meta['value'];
885
+
886
+ if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) {
887
+ $_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)];
888
+ } else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) {
889
+ $_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)];
890
+ } else if ( 'custom' != $_menu_item_type ) {
891
+ // associated object is missing or not imported yet, we'll retry later
892
+ $this->missing_menu_items[] = $item;
893
+ return;
894
+ }
895
+
896
+ if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) {
897
+ $_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)];
898
+ } else if ( $_menu_item_menu_item_parent ) {
899
+ $this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent;
900
+ $_menu_item_menu_item_parent = 0;
901
+ }
902
+
903
+ // wp_update_nav_menu_item expects CSS classes as a space separated string
904
+ $_menu_item_classes = maybe_unserialize( $_menu_item_classes );
905
+ if ( is_array( $_menu_item_classes ) )
906
+ $_menu_item_classes = implode( ' ', $_menu_item_classes );
907
+
908
+ $args = array(
909
+ 'menu-item-object-id' => $_menu_item_object_id,
910
+ 'menu-item-object' => $_menu_item_object,
911
+ 'menu-item-parent-id' => $_menu_item_menu_item_parent,
912
+ 'menu-item-position' => intval( $item['menu_order'] ),
913
+ 'menu-item-type' => $_menu_item_type,
914
+ 'menu-item-title' => $item['post_title'],
915
+ 'menu-item-url' => $_menu_item_url,
916
+ 'menu-item-description' => $item['post_content'],
917
+ 'menu-item-attr-title' => $item['post_excerpt'],
918
+ 'menu-item-target' => $_menu_item_target,
919
+ 'menu-item-classes' => $_menu_item_classes,
920
+ 'menu-item-xfn' => $_menu_item_xfn,
921
+ 'menu-item-status' => $item['status']
922
+ );
923
+
924
+ $id = wp_update_nav_menu_item( $menu_id, 0, $args );
925
+ if ( $id && ! is_wp_error( $id ) )
926
+ $this->processed_menu_items[intval($item['post_id'])] = (int) $id;
927
+ }
928
+
929
+ /**
930
+ * If fetching attachments is enabled then attempt to create a new attachment
931
+ *
932
+ * @param array $post Attachment post details from WXR
933
+ * @param string $url URL to fetch attachment from
934
+ * @return int|WP_Error Post ID on success, WP_Error otherwise
935
+ */
936
+ function process_attachment( $post, $url ) {
937
+ if ( ! $this->fetch_attachments )
938
+ return new WP_Error( 'attachment_processing_error',
939
+ __( 'Fetching attachments is not enabled', 'wordpress-importer' ) );
940
+
941
+ // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
942
+ if ( preg_match( '|^/[\w\W]+$|', $url ) )
943
+ $url = rtrim( $this->base_url, '/' ) . $url;
944
+
945
+ $upload = $this->fetch_remote_file( $url, $post );
946
+ if ( is_wp_error( $upload ) )
947
+ return $upload;
948
+
949
+ if ( $info = wp_check_filetype( $upload['file'] ) )
950
+ $post['post_mime_type'] = $info['type'];
951
+ else
952
+ return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') );
953
+
954
+ $post['guid'] = $upload['url'];
955
+
956
+ // as per wp-admin/includes/upload.php
957
+ $post_id = wp_insert_attachment( $post, $upload['file'] );
958
+ wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
959
+
960
+ // remap resized image URLs, works by stripping the extension and remapping the URL stub.
961
+ if ( preg_match( '!^image/!', $info['type'] ) ) {
962
+ $parts = pathinfo( $url );
963
+ $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
964
+
965
+ $parts_new = pathinfo( $upload['url'] );
966
+ $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
967
+
968
+ $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
969
+ }
970
+
971
+ return $post_id;
972
+ }
973
+
974
+ /**
975
+ * Attempt to download a remote file attachment
976
+ *
977
+ * @param string $url URL of item to fetch
978
+ * @param array $post Attachment details
979
+ * @return array|WP_Error Local file location details on success, WP_Error otherwise
980
+ */
981
+ function fetch_remote_file( $url, $post ) {
982
+ // extract the file name and extension from the url
983
+ $file_name = basename( $url );
984
+
985
+ // get placeholder file in the upload dir with a unique, sanitized filename
986
+ $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
987
+ if ( $upload['error'] )
988
+ return new WP_Error( 'upload_dir_error', $upload['error'] );
989
+
990
+ // fetch the remote url and write it to the placeholder file
991
+ $headers = wp_get_http( $url, $upload['file'] );
992
+
993
+ // request failed
994
+ if ( ! $headers ) {
995
+ @unlink( $upload['file'] );
996
+ return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') );
997
+ }
998
+
999
+ // make sure the fetch was successful
1000
+ if ( $headers['response'] != '200' ) {
1001
+ @unlink( $upload['file'] );
1002
+ 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']) ) );
1003
+ }
1004
+
1005
+ $filesize = filesize( $upload['file'] );
1006
+
1007
+ if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) {
1008
+ @unlink( $upload['file'] );
1009
+ return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') );
1010
+ }
1011
+
1012
+ if ( 0 == $filesize ) {
1013
+ @unlink( $upload['file'] );
1014
+ return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') );
1015
+ }
1016
+
1017
+ $max_size = (int) $this->max_attachment_size();
1018
+ if ( ! empty( $max_size ) && $filesize > $max_size ) {
1019
+ @unlink( $upload['file'] );
1020
+ return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) );
1021
+ }
1022
+
1023
+ // keep track of the old and new urls so we can substitute them later
1024
+ $this->url_remap[$url] = $upload['url'];
1025
+ $this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed?
1026
+ // keep track of the destination if the remote url is redirected somewhere else
1027
+ if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url )
1028
+ $this->url_remap[$headers['x-final-location']] = $upload['url'];
1029
+
1030
+ return $upload;
1031
+ }
1032
+
1033
+ /**
1034
+ * Attempt to associate posts and menu items with previously missing parents
1035
+ *
1036
+ * An imported post's parent may not have been imported when it was first created
1037
+ * so try again. Similarly for child menu items and menu items which were missing
1038
+ * the object (e.g. post) they represent in the menu
1039
+ */
1040
+ function backfill_parents() {
1041
+ global $wpdb;
1042
+
1043
+ // find parents for post orphans
1044
+ foreach ( $this->post_orphans as $child_id => $parent_id ) {
1045
+ $local_child_id = $local_parent_id = false;
1046
+ if ( isset( $this->processed_posts[$child_id] ) )
1047
+ $local_child_id = $this->processed_posts[$child_id];
1048
+ if ( isset( $this->processed_posts[$parent_id] ) )
1049
+ $local_parent_id = $this->processed_posts[$parent_id];
1050
+
1051
+ if ( $local_child_id && $local_parent_id )
1052
+ $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' );
1053
+ }
1054
+
1055
+ // all other posts/terms are imported, retry menu items with missing associated object
1056
+ $missing_menu_items = $this->missing_menu_items;
1057
+ foreach ( $missing_menu_items as $item )
1058
+ $this->process_menu_item( $item );
1059
+
1060
+ // find parents for menu item orphans
1061
+ foreach ( $this->menu_item_orphans as $child_id => $parent_id ) {
1062
+ $local_child_id = $local_parent_id = 0;
1063
+ if ( isset( $this->processed_menu_items[$child_id] ) )
1064
+ $local_child_id = $this->processed_menu_items[$child_id];
1065
+ if ( isset( $this->processed_menu_items[$parent_id] ) )
1066
+ $local_parent_id = $this->processed_menu_items[$parent_id];
1067
+
1068
+ if ( $local_child_id && $local_parent_id )
1069
+ update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id );
1070
+ }
1071
+ }
1072
+
1073
+ /**
1074
+ * Use stored mapping information to update old attachment URLs
1075
+ */
1076
+ function backfill_attachment_urls() {
1077
+ global $wpdb;
1078
+ // make sure we do the longest urls first, in case one is a substring of another
1079
+ uksort( $this->url_remap, array(&$this, 'cmpr_strlen') );
1080
+
1081
+ foreach ( $this->url_remap as $from_url => $to_url ) {
1082
+ // remap urls in post_content
1083
+ $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) );
1084
+ // remap enclosure urls
1085
+ $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) );
1086
+ }
1087
+ }
1088
+
1089
+ /**
1090
+ * Update _thumbnail_id meta to new, imported attachment IDs
1091
+ */
1092
+ function remap_featured_images() {
1093
+ // cycle through posts that have a featured image
1094
+ foreach ( $this->featured_images as $post_id => $value ) {
1095
+ if ( isset( $this->processed_posts[$value] ) ) {
1096
+ $new_id = $this->processed_posts[$value];
1097
+ // only update if there's a difference
1098
+ if ( $new_id != $value )
1099
+ update_post_meta( $post_id, '_thumbnail_id', $new_id );
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ /**
1105
+ * Parse a WXR file
1106
+ *
1107
+ * @param string $file Path to WXR file for parsing
1108
+ * @return array Information gathered from the WXR file
1109
+ */
1110
+ function parse( $file ) {
1111
+ $parser = new WXR_Parser();
1112
+ return $parser->parse( $file );
1113
+ }
1114
+
1115
+ // Display import page title
1116
+ function header() {
1117
+ echo '<div class="wrap">';
1118
+ screen_icon();
1119
+ echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>';
1120
+
1121
+ $updates = get_plugin_updates();
1122
+ $basename = plugin_basename(__FILE__);
1123
+ if ( isset( $updates[$basename] ) ) {
1124
+ $update = $updates[$basename];
1125
+ echo '<div class="error"><p><strong>';
1126
+ 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 );
1127
+ echo '</strong></p></div>';
1128
+ }
1129
+ }
1130
+
1131
+ // Close div.wrap
1132
+ function footer() {
1133
+ echo '</div>';
1134
+ }
1135
+
1136
+ /**
1137
+ * Display introductory text and file upload form
1138
+ */
1139
+ function greet() {
1140
+ echo '<div class="narrow">';
1141
+ 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>';
1142
+ echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>';
1143
+ wp_import_upload_form( 'admin.php?import=wordpress&amp;step=1' );
1144
+ echo '</div>';
1145
+ }
1146
+
1147
+ /**
1148
+ * Decide if the given meta key maps to information we will want to import
1149
+ *
1150
+ * @param string $key The meta key to check
1151
+ * @return string|bool The key if we do want to import, false if not
1152
+ */
1153
+ function is_valid_meta_key( $key ) {
1154
+ // skip attachment metadata since we'll regenerate it from scratch
1155
+ // skip _edit_lock as not relevant for import
1156
+ if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
1157
+ return false;
1158
+ return $key;
1159
+ }
1160
+
1161
+ /**
1162
+ * Decide whether or not the importer is allowed to create users.
1163
+ * Default is true, can be filtered via import_allow_create_users
1164
+ *
1165
+ * @return bool True if creating users is allowed
1166
+ */
1167
+ function allow_create_users() {
1168
+ return apply_filters( 'import_allow_create_users', true );
1169
+ }
1170
+
1171
+ /**
1172
+ * Decide whether or not the importer should attempt to download attachment files.
1173
+ * Default is true, can be filtered via import_allow_fetch_attachments. The choice
1174
+ * made at the import options screen must also be true, false here hides that checkbox.
1175
+ *
1176
+ * @return bool True if downloading attachments is allowed
1177
+ */
1178
+ function allow_fetch_attachments() {
1179
+ return apply_filters( 'import_allow_fetch_attachments', true );
1180
+ }
1181
+
1182
+ /**
1183
+ * Decide what the maximum file size for downloaded attachments is.
1184
+ * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
1185
+ *
1186
+ * @return int Maximum attachment file size to import
1187
+ */
1188
+ function max_attachment_size() {
1189
+ return apply_filters( 'import_attachment_size_limit', 0 );
1190
+ }
1191
+
1192
+ /**
1193
+ * Added to http_request_timeout filter to force timeout at 60 seconds during import
1194
+ * @return int 60
1195
+ */
1196
+ function bump_request_timeout( $val ) {
1197
+ return 60;
1198
+ }
1199
+
1200
+ // return the difference in length between two strings
1201
+ function cmpr_strlen( $a, $b ) {
1202
+ return strlen($b) - strlen($a);
1203
+ }
1204
+ }
1205
+
1206
+ } // class_exists( 'WP_Importer' )
1207
+
1208
+ function wordpress_importer_init() {
1209
+ load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
1210
+
1211
+ /**
1212
+ * WordPress Importer object for registering the import callback
1213
+ * @global WP_Import $wp_import
1214
+ */
1215
+ $GLOBALS['wp_import'] = new WP_Import();
1216
+ 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' ) );
1217
+ }
1218
+ add_action( 'admin_init', 'wordpress_importer_init' );