├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── README.md
├── assets
├── import.css
├── import.js
├── intro.css
└── intro.js
├── bin
└── install-wp-tests.sh
├── class-command.php
├── class-logger-cli.php
├── class-logger-html.php
├── class-logger-serversentevents.php
├── class-logger.php
├── class-wxr-import-info.php
├── class-wxr-import-ui.php
├── class-wxr-importer.php
├── composer.json
├── package.json
├── phpcs.ruleset.xml
├── phpunit.xml.dist
├── plugin.php
├── templates
├── footer.php
├── header.php
├── import.php
├── intro.php
├── select-options.php
└── upload.php
└── tests
├── bootstrap.php
└── test-importer-plugin.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Package Managers
2 | ## Composer
3 | /vendor
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: false
3 |
4 | language: php
5 |
6 | matrix:
7 | fast_finish: true
8 | include:
9 | - php: 5.2
10 | - php: 5.3
11 | - php: 5.4
12 | - php: 5.5
13 | - php: 5.6
14 | - php: 7.0
15 | - php: hhvm
16 |
17 | - php: 5.6
18 | env: WP_TRAVISCI="travis:phpvalidate"
19 |
20 | branches:
21 | only:
22 | - master
23 |
24 | env:
25 | global:
26 | - WP_TRAVISCI="travis:phpunit"
27 |
28 | # Clones WordPress and configures our testing environment.
29 | before_script:
30 | # Setup Coveralls
31 | - phpenv local 5.5
32 | - composer install --no-interaction
33 | - phpenv local --unset
34 |
35 | - bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
36 |
37 | - cd $TRAVIS_BUILD_DIR
38 | - nvm install 6
39 | - nvm use 6
40 | - node -v
41 | - npm -v
42 | - npm install -g grunt-cli
43 | - npm install
44 |
45 | script:
46 | - grunt $WP_TRAVISCI
47 |
48 | after_script:
49 | # Push coverage off to Codecov
50 | - bash <(curl -s https://codecov.io/bash)
51 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | So you want to contribute to the Importer? Fantastic! There are a few rules you'll need to follow for all contributions.
4 |
5 | (There are always exceptions to these rules. :) )
6 |
7 | ## Process
8 |
9 | 1. Ideally, start with an issue to check the need for a PR. It's possible that a feature may be rejected at an early stage, and it's better to find out before you write the code.
10 | 2. Write the code. Small, atomic commits are preferred. Explain the motivation behind the change when needed.
11 | 3. File a PR. If it isn't ready for merge yet, note that in the description. If your PR closes an existing issue, add "fixes #xxx" to the message, so that the issue will be closed when the PR is merged.
12 | 4. If needed, iterate on the code until it is ready. This includes adding unit tests. When you're ready, comment that the PR is complete.
13 | 5. A committer will review your code and offer you feedback.
14 | 6. Update with the feedback as necessary.
15 | 7. PR will be merged.
16 |
17 | Notes:
18 |
19 | * All code needs to go through peer review. Committers may not merge their own PR.
20 | * PRs should **never be squashed or rebased**. This includes when merging. Keeping the history is important for tracking motivation behind changes later.
21 |
22 | ## Best Practices
23 |
24 | All code in the Importer must be compatible with PHP 5.2. Treat this code as if it were part of WordPress core, and apply the [same best practices](https://make.wordpress.org/core/handbook/best-practices/).
25 |
26 | ### Commit Messages
27 |
28 | Commit messages should follow the [general git best practices](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html):
29 |
30 | ```
31 | Capitalized, short (50 chars or less) summary
32 |
33 | More detailed explanatory text, if necessary. Wrap it to about 72
34 | characters or so. In some contexts, the first line is treated as the
35 | subject of an email and the rest of the text as the body. The blank
36 | line separating the summary from the body is critical (unless you omit
37 | the body entirely); tools like rebase can get confused if you run the
38 | two together.
39 |
40 | Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
41 | or "Fixes bug." This convention matches up with commit messages generated
42 | by commands like git merge and git revert.
43 |
44 | Further paragraphs come after blank lines.
45 |
46 | - Bullet points are okay, too
47 |
48 | - Typically a hyphen or asterisk is used for the bullet, followed by a
49 | single space, with blank lines in between, but conventions vary here
50 |
51 | - Use a hanging indent
52 | ```
53 |
54 | There is no need to reference issues inside commits, as all interaction with issues is handled via pull requests.
55 |
56 |
57 | ## Coding Style
58 |
59 | The coding style should match [the WordPress coding standards](https://make.wordpress.org/core/handbook/coding-standards/php/).
60 |
61 |
62 | ## Unit Tests
63 |
64 | PRs should include unit tests for any changes. These are written in PHPUnit, and should be added to the file corresponding to the class they test (that is, tests for `class-wxr-importer.php` would be in `tests/test-wxr-importer.php`).
65 |
66 | Where possible, features should be unit tested. The eventual aim is to have >90% coverage.
67 |
68 |
73 |
74 |
75 | ## Licensing
76 |
77 | By contributing code to this repository, you agree to license your code for use under the [GPL License](https://github.com/humanmade/WordPress-Importer/blob/master/LICENSE).
78 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function( grunt ) {
2 | 'use strict';
3 |
4 | require('phplint').gruntPlugin(grunt);
5 | grunt.initConfig( {
6 |
7 | pkg: grunt.file.readJSON( 'package.json' ),
8 |
9 | phpcs: {
10 | plugin: {
11 | src: './'
12 | },
13 | options: {
14 | bin: "vendor/bin/phpcs --extensions=php --ignore=\"*/vendor/*,*/node_modules/*\"",
15 | standard: "phpcs.ruleset.xml"
16 | }
17 | },
18 |
19 | phplint: {
20 | options: {
21 | limit: 10,
22 | stdout: true,
23 | stderr: true
24 | },
25 | files: ['tests/*.php', '*.php']
26 | },
27 |
28 | phpunit: {
29 | 'default': {
30 | cmd: 'phpunit',
31 | args: [ '-c', 'phpunit.xml.dist' ],
32 | }
33 | }
34 |
35 | } );
36 | grunt.loadNpmTasks( 'grunt-phpcs' );
37 |
38 | // Testing tasks.
39 | grunt.registerMultiTask('phpunit', 'Runs PHPUnit tests, including the ajax, external-http, and multisite tests.', function() {
40 | grunt.util.spawn({
41 | cmd: this.data.cmd,
42 | args: this.data.args,
43 | opts: {stdio: 'inherit'}
44 | }, this.async());
45 | });
46 |
47 | grunt.registerTask( 'test', [ 'phpcs', 'phplint', 'phpunit' ] );
48 | grunt.util.linefeed = '\n';
49 |
50 | // Travis CI tasks.
51 | grunt.registerTask('travis:phpvalidate', 'Runs PHPUnit Travis CI PHP code tasks.', [
52 | 'phpcs',
53 | 'phplint'
54 | ] );
55 | grunt.registerTask('travis:phpunit', 'Runs PHPUnit Travis CI tasks.', [
56 | 'phpunit',
57 | ] );
58 | };
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | WordPress Importer - Import content into WordPress
2 |
3 | Copyright 2016-2017 by the contributors
4 |
5 | This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, write to the Free Software
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 |
19 | This program incorporates work covered by the following copyright and
20 | permission notices:
21 |
22 | WordPress Importer - Import content into WordPress
23 |
24 | Copyright 2016-2017 by the contributors
25 |
26 | The WordPress Importer is released under the GPL
27 |
28 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
29 |
30 | GNU GENERAL PUBLIC LICENSE
31 | Version 2, June 1991
32 |
33 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
34 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 | Everyone is permitted to copy and distribute verbatim copies
36 | of this license document, but changing it is not allowed.
37 |
38 | Preamble
39 |
40 | The licenses for most software are designed to take away your
41 | freedom to share and change it. By contrast, the GNU General Public
42 | License is intended to guarantee your freedom to share and change free
43 | software--to make sure the software is free for all its users. This
44 | General Public License applies to most of the Free Software
45 | Foundation's software and to any other program whose authors commit to
46 | using it. (Some other Free Software Foundation software is covered by
47 | the GNU Lesser General Public License instead.) You can apply it to
48 | your programs, too.
49 |
50 | When we speak of free software, we are referring to freedom, not
51 | price. Our General Public Licenses are designed to make sure that you
52 | have the freedom to distribute copies of free software (and charge for
53 | this service if you wish), that you receive source code or can get it
54 | if you want it, that you can change the software or use pieces of it
55 | in new free programs; and that you know you can do these things.
56 |
57 | To protect your rights, we need to make restrictions that forbid
58 | anyone to deny you these rights or to ask you to surrender the rights.
59 | These restrictions translate to certain responsibilities for you if you
60 | distribute copies of the software, or if you modify it.
61 |
62 | For example, if you distribute copies of such a program, whether
63 | gratis or for a fee, you must give the recipients all the rights that
64 | you have. You must make sure that they, too, receive or can get the
65 | source code. And you must show them these terms so they know their
66 | rights.
67 |
68 | We protect your rights with two steps: (1) copyright the software, and
69 | (2) offer you this license which gives you legal permission to copy,
70 | distribute and/or modify the software.
71 |
72 | Also, for each author's protection and ours, we want to make certain
73 | that everyone understands that there is no warranty for this free
74 | software. If the software is modified by someone else and passed on, we
75 | want its recipients to know that what they have is not the original, so
76 | that any problems introduced by others will not reflect on the original
77 | authors' reputations.
78 |
79 | Finally, any free program is threatened constantly by software
80 | patents. We wish to avoid the danger that redistributors of a free
81 | program will individually obtain patent licenses, in effect making the
82 | program proprietary. To prevent this, we have made it clear that any
83 | patent must be licensed for everyone's free use or not licensed at all.
84 |
85 | The precise terms and conditions for copying, distribution and
86 | modification follow.
87 |
88 | GNU GENERAL PUBLIC LICENSE
89 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
90 |
91 | 0. This License applies to any program or other work which contains
92 | a notice placed by the copyright holder saying it may be distributed
93 | under the terms of this General Public License. The "Program", below,
94 | refers to any such program or work, and a "work based on the Program"
95 | means either the Program or any derivative work under copyright law:
96 | that is to say, a work containing the Program or a portion of it,
97 | either verbatim or with modifications and/or translated into another
98 | language. (Hereinafter, translation is included without limitation in
99 | the term "modification".) Each licensee is addressed as "you".
100 |
101 | Activities other than copying, distribution and modification are not
102 | covered by this License; they are outside its scope. The act of
103 | running the Program is not restricted, and the output from the Program
104 | is covered only if its contents constitute a work based on the
105 | Program (independent of having been made by running the Program).
106 | Whether that is true depends on what the Program does.
107 |
108 | 1. You may copy and distribute verbatim copies of the Program's
109 | source code as you receive it, in any medium, provided that you
110 | conspicuously and appropriately publish on each copy an appropriate
111 | copyright notice and disclaimer of warranty; keep intact all the
112 | notices that refer to this License and to the absence of any warranty;
113 | and give any other recipients of the Program a copy of this License
114 | along with the Program.
115 |
116 | You may charge a fee for the physical act of transferring a copy, and
117 | you may at your option offer warranty protection in exchange for a fee.
118 |
119 | 2. You may modify your copy or copies of the Program or any portion
120 | of it, thus forming a work based on the Program, and copy and
121 | distribute such modifications or work under the terms of Section 1
122 | above, provided that you also meet all of these conditions:
123 |
124 | a) You must cause the modified files to carry prominent notices
125 | stating that you changed the files and the date of any change.
126 |
127 | b) You must cause any work that you distribute or publish, that in
128 | whole or in part contains or is derived from the Program or any
129 | part thereof, to be licensed as a whole at no charge to all third
130 | parties under the terms of this License.
131 |
132 | c) If the modified program normally reads commands interactively
133 | when run, you must cause it, when started running for such
134 | interactive use in the most ordinary way, to print or display an
135 | announcement including an appropriate copyright notice and a
136 | notice that there is no warranty (or else, saying that you provide
137 | a warranty) and that users may redistribute the program under
138 | these conditions, and telling the user how to view a copy of this
139 | License. (Exception: if the Program itself is interactive but
140 | does not normally print such an announcement, your work based on
141 | the Program is not required to print an announcement.)
142 |
143 | These requirements apply to the modified work as a whole. If
144 | identifiable sections of that work are not derived from the Program,
145 | and can be reasonably considered independent and separate works in
146 | themselves, then this License, and its terms, do not apply to those
147 | sections when you distribute them as separate works. But when you
148 | distribute the same sections as part of a whole which is a work based
149 | on the Program, the distribution of the whole must be on the terms of
150 | this License, whose permissions for other licensees extend to the
151 | entire whole, and thus to each and every part regardless of who wrote it.
152 |
153 | Thus, it is not the intent of this section to claim rights or contest
154 | your rights to work written entirely by you; rather, the intent is to
155 | exercise the right to control the distribution of derivative or
156 | collective works based on the Program.
157 |
158 | In addition, mere aggregation of another work not based on the Program
159 | with the Program (or with a work based on the Program) on a volume of
160 | a storage or distribution medium does not bring the other work under
161 | the scope of this License.
162 |
163 | 3. You may copy and distribute the Program (or a work based on it,
164 | under Section 2) in object code or executable form under the terms of
165 | Sections 1 and 2 above provided that you also do one of the following:
166 |
167 | a) Accompany it with the complete corresponding machine-readable
168 | source code, which must be distributed under the terms of Sections
169 | 1 and 2 above on a medium customarily used for software interchange; or,
170 |
171 | b) Accompany it with a written offer, valid for at least three
172 | years, to give any third party, for a charge no more than your
173 | cost of physically performing source distribution, a complete
174 | machine-readable copy of the corresponding source code, to be
175 | distributed under the terms of Sections 1 and 2 above on a medium
176 | customarily used for software interchange; or,
177 |
178 | c) Accompany it with the information you received as to the offer
179 | to distribute corresponding source code. (This alternative is
180 | allowed only for noncommercial distribution and only if you
181 | received the program in object code or executable form with such
182 | an offer, in accord with Subsection b above.)
183 |
184 | The source code for a work means the preferred form of the work for
185 | making modifications to it. For an executable work, complete source
186 | code means all the source code for all modules it contains, plus any
187 | associated interface definition files, plus the scripts used to
188 | control compilation and installation of the executable. However, as a
189 | special exception, the source code distributed need not include
190 | anything that is normally distributed (in either source or binary
191 | form) with the major components (compiler, kernel, and so on) of the
192 | operating system on which the executable runs, unless that component
193 | itself accompanies the executable.
194 |
195 | If distribution of executable or object code is made by offering
196 | access to copy from a designated place, then offering equivalent
197 | access to copy the source code from the same place counts as
198 | distribution of the source code, even though third parties are not
199 | compelled to copy the source along with the object code.
200 |
201 | 4. You may not copy, modify, sublicense, or distribute the Program
202 | except as expressly provided under this License. Any attempt
203 | otherwise to copy, modify, sublicense or distribute the Program is
204 | void, and will automatically terminate your rights under this License.
205 | However, parties who have received copies, or rights, from you under
206 | this License will not have their licenses terminated so long as such
207 | parties remain in full compliance.
208 |
209 | 5. You are not required to accept this License, since you have not
210 | signed it. However, nothing else grants you permission to modify or
211 | distribute the Program or its derivative works. These actions are
212 | prohibited by law if you do not accept this License. Therefore, by
213 | modifying or distributing the Program (or any work based on the
214 | Program), you indicate your acceptance of this License to do so, and
215 | all its terms and conditions for copying, distributing or modifying
216 | the Program or works based on it.
217 |
218 | 6. Each time you redistribute the Program (or any work based on the
219 | Program), the recipient automatically receives a license from the
220 | original licensor to copy, distribute or modify the Program subject to
221 | these terms and conditions. You may not impose any further
222 | restrictions on the recipients' exercise of the rights granted herein.
223 | You are not responsible for enforcing compliance by third parties to
224 | this License.
225 |
226 | 7. If, as a consequence of a court judgment or allegation of patent
227 | infringement or for any other reason (not limited to patent issues),
228 | conditions are imposed on you (whether by court order, agreement or
229 | otherwise) that contradict the conditions of this License, they do not
230 | excuse you from the conditions of this License. If you cannot
231 | distribute so as to satisfy simultaneously your obligations under this
232 | License and any other pertinent obligations, then as a consequence you
233 | may not distribute the Program at all. For example, if a patent
234 | license would not permit royalty-free redistribution of the Program by
235 | all those who receive copies directly or indirectly through you, then
236 | the only way you could satisfy both it and this License would be to
237 | refrain entirely from distribution of the Program.
238 |
239 | If any portion of this section is held invalid or unenforceable under
240 | any particular circumstance, the balance of the section is intended to
241 | apply and the section as a whole is intended to apply in other
242 | circumstances.
243 |
244 | It is not the purpose of this section to induce you to infringe any
245 | patents or other property right claims or to contest validity of any
246 | such claims; this section has the sole purpose of protecting the
247 | integrity of the free software distribution system, which is
248 | implemented by public license practices. Many people have made
249 | generous contributions to the wide range of software distributed
250 | through that system in reliance on consistent application of that
251 | system; it is up to the author/donor to decide if he or she is willing
252 | to distribute software through any other system and a licensee cannot
253 | impose that choice.
254 |
255 | This section is intended to make thoroughly clear what is believed to
256 | be a consequence of the rest of this License.
257 |
258 | 8. If the distribution and/or use of the Program is restricted in
259 | certain countries either by patents or by copyrighted interfaces, the
260 | original copyright holder who places the Program under this License
261 | may add an explicit geographical distribution limitation excluding
262 | those countries, so that distribution is permitted only in or among
263 | countries not thus excluded. In such case, this License incorporates
264 | the limitation as if written in the body of this License.
265 |
266 | 9. The Free Software Foundation may publish revised and/or new versions
267 | of the General Public License from time to time. Such new versions will
268 | be similar in spirit to the present version, but may differ in detail to
269 | address new problems or concerns.
270 |
271 | Each version is given a distinguishing version number. If the Program
272 | specifies a version number of this License which applies to it and "any
273 | later version", you have the option of following the terms and conditions
274 | either of that version or of any later version published by the Free
275 | Software Foundation. If the Program does not specify a version number of
276 | this License, you may choose any version ever published by the Free Software
277 | Foundation.
278 |
279 | 10. If you wish to incorporate parts of the Program into other free
280 | programs whose distribution conditions are different, write to the author
281 | to ask for permission. For software which is copyrighted by the Free
282 | Software Foundation, write to the Free Software Foundation; we sometimes
283 | make exceptions for this. Our decision will be guided by the two goals
284 | of preserving the free status of all derivatives of our free software and
285 | of promoting the sharing and reuse of software generally.
286 |
287 | NO WARRANTY
288 |
289 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
290 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
291 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
292 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
293 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
294 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
295 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
296 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
297 | REPAIR OR CORRECTION.
298 |
299 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
300 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
301 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
302 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
303 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
304 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
305 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
306 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
307 | POSSIBILITY OF SUCH DAMAGES.
308 |
309 | END OF TERMS AND CONDITIONS
310 |
311 | How to Apply These Terms to Your New Programs
312 |
313 | If you develop a new program, and you want it to be of the greatest
314 | possible use to the public, the best way to achieve this is to make it
315 | free software which everyone can redistribute and change under these terms.
316 |
317 | To do so, attach the following notices to the program. It is safest
318 | to attach them to the start of each source file to most effectively
319 | convey the exclusion of warranty; and each file should have at least
320 | the "copyright" line and a pointer to where the full notice is found.
321 |
322 |
323 | Copyright (C)
324 |
325 | This program is free software; you can redistribute it and/or modify
326 | it under the terms of the GNU General Public License as published by
327 | the Free Software Foundation; either version 2 of the License, or
328 | (at your option) any later version.
329 |
330 | This program is distributed in the hope that it will be useful,
331 | but WITHOUT ANY WARRANTY; without even the implied warranty of
332 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
333 | GNU General Public License for more details.
334 |
335 | You should have received a copy of the GNU General Public License along
336 | with this program; if not, write to the Free Software Foundation, Inc.,
337 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
338 |
339 | Also add information on how to contact you by electronic and paper mail.
340 |
341 | If the program is interactive, make it output a short notice like this
342 | when it starts in an interactive mode:
343 |
344 | Gnomovision version 69, Copyright (C) year name of author
345 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
346 | This is free software, and you are welcome to redistribute it
347 | under certain conditions; type `show c' for details.
348 |
349 | The hypothetical commands `show w' and `show c' should show the appropriate
350 | parts of the General Public License. Of course, the commands you use may
351 | be called something other than `show w' and `show c'; they could even be
352 | mouse-clicks or menu items--whatever suits your program.
353 |
354 | You should also get your employer (if you work as a programmer) or your
355 | school, if any, to sign a "copyright disclaimer" for the program, if
356 | necessary. Here is a sample; alter the names:
357 |
358 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
359 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
360 |
361 | , 1 April 1989
362 | Ty Coon, President of Vice
363 |
364 | This General Public License does not permit incorporating your program into
365 | proprietary programs. If your program is a subroutine library, you may
366 | consider it more useful to permit linking proprietary applications with the
367 | library. If this is what you want to do, use the GNU Lesser General
368 | Public License instead of this License.
369 |
370 | WRITTEN OFFER
371 |
372 | The source code for any program binaries or compressed scripts that are
373 | included with the WordPress Importer can be freely obtained at the
374 | following URL:
375 |
376 | https://github.com/humanmade/WordPress-Importer
377 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WordPress Importer Redux
2 | This repository contains the new version of the [WordPress Importer][] currently in development. [Learn more about the rewrite](https://make.wordpress.org/core/?p=15550).
3 |
4 | Fast, lightweight, consistent. Pick three. :palm_tree: :sunglasses:
5 |
6 | [WordPress Importer]: https://wordpress.org/plugins/wordpress-importer/
7 |
8 | ## How do I use it?
9 |
10 | ### Via the Dashboard
11 |
12 | 1. Install the plugin directly from GitHub. ([Download as a ZIP.](https://github.com/humanmade/WordPress-Importer/archive/master.zip))
13 | 2. Activate the plugin (make sure you also deactivate the original Wordpress Importer if you have it installed).
14 | 3. Head to Tools → Import
15 | 4. Select "WordPress (v2)"
16 | 5. Follow the on-screen instructions.
17 |
18 | ### Via the CLI
19 |
20 | The plugin also includes CLI commands out of the box.
21 |
22 | Simply activate the plugin, then run:
23 |
24 | ```sh
25 | wp wxr-importer import import-file.xml
26 | ```
27 |
28 | Run `wp help wxr-importer import` to discover what you can do via the CLI.
29 |
30 | ## Current Status
31 |
32 | The current major items are currently missing or suboptimal in the Importer:
33 |
34 | * [x] **Web UI** ([#1](https://github.com/humanmade/WordPress-Importer/issues/1)): ~~Right now, there's essentially *no* web interface for the importer. This sucks.~~ Done!
35 |
36 | * **Automatic Testing**: There's no unit tests. Boooooo.
37 |
38 | ## How can I help?
39 |
40 | The best way to help with the importer right now is to **try importing and see what breaks**. Compare the old importer to the new one, and find any inconsistent behaviour.
41 |
42 | We have a [general feedback thread](https://github.com/humanmade/WordPress-Importer/issues/7) so you can let us know how it goes. If the importer works perfectly, let us know. If something doesn't import the way you think it should, you can file a new issue, or leave a comment to check whether it's intentional first. :)
43 |
44 | ## License
45 |
46 | The WordPress Importer is licensed under the GPLv2 or later.
47 |
48 | ## Credits
49 |
50 | Original plugin created by Ryan Boren, [Jon Cave][duck_] (@joncave), [Andrew Nacin][nacin] (@nacin), and [Peter Westwood][westi] (@westi). Redux project by [Ryan McCue](https://github.com/rmccue) and [contributors](https://github.com/humanmade/WordPress-Importer/graphs/contributors).
51 |
52 | [duck_]: https://profiles.wordpress.org/duck_
53 | [nacin]: https://profiles.wordpress.org/nacin
54 | [westi]: https://profiles.wordpress.org/westi
55 |
--------------------------------------------------------------------------------
/assets/import.css:
--------------------------------------------------------------------------------
1 | .import-status {
2 | width: 100%;
3 |
4 | font-size: 14px;
5 | line-height: 16px;
6 | margin-bottom: 1em;
7 | }
8 | .import-status thead th {
9 | width: 32%;
10 | text-align: left;
11 | font-size: 16px;
12 | padding-bottom: 1em;
13 | }
14 | .import-status thead th:first-child {
15 | width: 36%;
16 | }
17 |
18 | .import-status th,
19 | .import-status td {
20 | padding: 0 0 8px;
21 | margin-bottom: 6px;
22 | }
23 |
24 | #import-log tbody {
25 | max-height: 40em;
26 | }
27 | .import-status-indicator {
28 | margin-bottom: 1em;
29 | }
30 | .import-status-indicator progress {
31 | width: 100%;
32 | }
33 | .import-status-indicator .status {
34 | text-align: center;
35 | }
36 | .import-status-indicator .status .dashicons {
37 | color: #46B450;
38 | font-size: 3rem;
39 | height: auto;
40 | width: auto;
41 | }
42 | #completed-total {
43 | display: none;
44 | }
45 | #import-status-message {
46 | border-top: 1px solid #f2f2f2;
47 | height: 40px;
48 | line-height: 40px;
49 | margin: 20px 0;
50 | }
51 |
--------------------------------------------------------------------------------
/assets/import.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | var wxrImport = {
3 | complete: {
4 | posts: 0,
5 | media: 0,
6 | users: 0,
7 | comments: 0,
8 | terms: 0,
9 | },
10 |
11 | updateDelta: function (type, delta) {
12 | this.complete[ type ] += delta;
13 |
14 | var self = this;
15 | requestAnimationFrame(function () {
16 | self.render();
17 | });
18 | },
19 | updateProgress: function ( type, complete, total ) {
20 | var text = complete + '/' + total;
21 | document.getElementById( 'completed-' + type ).innerHTML = text;
22 | total = parseInt( total, 10 );
23 | if ( 0 === total || isNaN( total ) ) {
24 | total = 1;
25 | }
26 | var percent = parseInt( complete, 10 ) / total;
27 | document.getElementById( 'progress-' + type ).innerHTML = Math.round( percent * 100 ) + '%';
28 | document.getElementById( 'progressbar-' + type ).value = percent * 100;
29 | },
30 | render: function () {
31 | var types = Object.keys( this.complete );
32 | var complete = 0;
33 | var total = 0;
34 |
35 | for (var i = types.length - 1; i >= 0; i--) {
36 | var type = types[i];
37 | this.updateProgress( type, this.complete[ type ], this.data.count[ type ] );
38 |
39 | complete += this.complete[ type ];
40 | total += this.data.count[ type ];
41 | }
42 |
43 | this.updateProgress( 'total', complete, total );
44 | }
45 | };
46 | wxrImport.data = wxrImportData;
47 | wxrImport.render();
48 |
49 | var evtSource = new EventSource( wxrImport.data.url );
50 | evtSource.onmessage = function ( message ) {
51 | var data = JSON.parse( message.data );
52 | switch ( data.action ) {
53 | case 'updateDelta':
54 | wxrImport.updateDelta( data.type, data.delta );
55 | break;
56 |
57 | case 'complete':
58 | evtSource.close();
59 | var import_status_msg = jQuery('#import-status-message');
60 | import_status_msg.text( wxrImport.data.strings.complete );
61 | import_status_msg.removeClass('notice-info');
62 | import_status_msg.addClass('notice-success');
63 | break;
64 | }
65 | };
66 | evtSource.addEventListener( 'log', function ( message ) {
67 | var data = JSON.parse( message.data );
68 | var row = document.createElement('tr');
69 | var level = document.createElement( 'td' );
70 | level.appendChild( document.createTextNode( data.level ) );
71 | row.appendChild( level );
72 |
73 | var message = document.createElement( 'td' );
74 | message.appendChild( document.createTextNode( data.message ) );
75 | row.appendChild( message );
76 |
77 | jQuery('#import-log').append( row );
78 | });
79 | })(jQuery);
80 |
--------------------------------------------------------------------------------
/assets/intro.css:
--------------------------------------------------------------------------------
1 | #plupload-upload-ui .drag-drop-status {
2 | display: none;
3 |
4 | margin: 70px auto 0;
5 | width: 400px;
6 | }
7 | #plupload-upload-ui .drag-drop-status .media-item {
8 | width: 200px;
9 | margin: 0 auto;
10 | }
11 |
--------------------------------------------------------------------------------
/assets/intro.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | var options = importUploadSettings;
3 | var uploader, statusTemplate, errorTemplate;
4 |
5 | // progress and success handlers for media multi uploads
6 | var renderStatus = function ( attachment ) {
7 | var attr = attachment.attributes;
8 | var $status = jQuery.parseHTML( statusTemplate( attr ).trim() );
9 |
10 | $('.bar', $status).width( (200 * attr.loaded) / attr.size );
11 | $('.percent', $status).html( attr.percent + '%' );
12 |
13 | $('.drag-drop-status').empty().append( $status );
14 | };
15 | var renderError = function ( message ) {
16 | var data = {
17 | message: message,
18 | };
19 |
20 | var status = errorTemplate( data );
21 | var $status = $('.drag-drop-status');
22 | $status.html( status );
23 | $status.one( 'click', 'button', function () {
24 | $status.empty().hide();
25 | $('.drag-drop-selector').show();
26 | });
27 | };
28 | var actions = {
29 | init: function () {
30 | var uploaddiv = $('#plupload-upload-ui');
31 |
32 | if ( uploader.supports.dragdrop ) {
33 | uploaddiv.addClass('drag-drop');
34 | } else {
35 | uploaddiv.removeClass('drag-drop');
36 | }
37 | },
38 |
39 | added: function ( attachment ) {
40 | $('.drag-drop-selector').hide();
41 | $('.drag-drop-status').show();
42 |
43 | renderStatus( attachment );
44 | },
45 |
46 | progress: function ( attachment ) {
47 | renderStatus( attachment );
48 | },
49 |
50 | success: function ( attachment ) {
51 | $('#import-selected-id').val( attachment.id );
52 |
53 | renderStatus( attachment );
54 | },
55 |
56 | error: function ( message, data, file ) {
57 | renderError( message );
58 | },
59 | };
60 |
61 | // init and set the uploader
62 | var init = function() {
63 | var isIE = navigator.userAgent.indexOf('Trident/') != -1 || navigator.userAgent.indexOf('MSIE ') != -1;
64 |
65 | // Make sure flash sends cookies (seems in IE it does whitout switching to urlstream mode)
66 | if ( ! isIE && 'flash' === plupload.predictRuntime( options ) &&
67 | ( ! options.required_features || ! options.required_features.hasOwnProperty( 'send_binary_string' ) ) ) {
68 |
69 | options.required_features = options.required_features || {};
70 | options.required_features.send_binary_string = true;
71 | }
72 |
73 | var instanceOptions = _.extend({}, options, actions);
74 | instanceOptions.browser = $('#plupload-browse-button');
75 | instanceOptions.dropzone = $('#plupload-upload-ui');
76 |
77 | uploader = new wp.Uploader(instanceOptions);
78 | };
79 |
80 | $(document).ready(function() {
81 | statusTemplate = wp.template( 'import-upload-status' );
82 | errorTemplate = wp.template( 'import-upload-error' );
83 |
84 | init();
85 |
86 | // Create the media frame.
87 | var frame = wp.media({
88 | id: 'import-select',
89 | // Set the title of the modal.
90 | title: options.l10n.frameTitle,
91 | multiple: true,
92 |
93 | // Tell the modal to show only xml files.
94 | library: {
95 | type: '',
96 | status: 'private',
97 | },
98 |
99 | // Customize the submit button.
100 | button: {
101 | // Set the text of the button.
102 | text: options.l10n.buttonText,
103 | // Tell the button not to close the modal, since we're
104 | // going to refresh the page when the image is selected.
105 | close: false,
106 | },
107 | });
108 | $('.upload-select').on( 'click', function ( event ) {
109 | event.preventDefault();
110 |
111 | frame.open();
112 | });
113 | frame.on( 'select', function () {
114 | console.log( this, arguments );
115 | var attachment = frame.state().get('selection').first().toJSON();
116 | console.log( attachment );
117 |
118 | var $input = $('#import-selected-id');
119 | $input.val( attachment.id );
120 | $input.parents('form')[0].submit();
121 | });
122 | });
123 |
124 |
125 | })( jQuery );
126 |
--------------------------------------------------------------------------------
/bin/install-wp-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ $# -lt 3 ]; then
4 | echo "usage: $0 [db-host] [wp-version]"
5 | exit 1
6 | fi
7 |
8 | DB_NAME=$1
9 | DB_USER=$2
10 | DB_PASS=$3
11 | DB_HOST=${4-localhost}
12 | WP_VERSION=${5-latest}
13 |
14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
16 |
17 | download() {
18 | if [ `which curl` ]; then
19 | curl -s "$1" > "$2";
20 | elif [ `which wget` ]; then
21 | wget -nv -O "$2" "$1"
22 | fi
23 | }
24 |
25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
26 | WP_TESTS_TAG="tags/$WP_VERSION"
27 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
28 | WP_TESTS_TAG="trunk"
29 | else
30 | # http serves a single offer, whereas https serves multiple. we only want one
31 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
32 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
33 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
34 | if [[ -z "$LATEST_VERSION" ]]; then
35 | echo "Latest WordPress version could not be found"
36 | exit 1
37 | fi
38 | WP_TESTS_TAG="tags/$LATEST_VERSION"
39 | fi
40 |
41 | set -ex
42 |
43 | install_wp() {
44 |
45 | if [ -d $WP_CORE_DIR ]; then
46 | return;
47 | fi
48 |
49 | mkdir -p $WP_CORE_DIR
50 |
51 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
52 | mkdir -p /tmp/wordpress-nightly
53 | download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip
54 | unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
55 | mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
56 | else
57 | if [ $WP_VERSION == 'latest' ]; then
58 | local ARCHIVE_NAME='latest'
59 | else
60 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
61 | fi
62 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
63 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
64 | fi
65 |
66 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
67 | }
68 |
69 | install_test_suite() {
70 | # portable in-place argument for both GNU sed and Mac OSX sed
71 | if [[ $(uname -s) == 'Darwin' ]]; then
72 | local ioption='-i .bak'
73 | else
74 | local ioption='-i'
75 | fi
76 |
77 | # set up testing suite if it doesn't yet exist
78 | if [ ! -d $WP_TESTS_DIR ]; then
79 | # set up testing suite
80 | mkdir -p $WP_TESTS_DIR
81 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
82 | fi
83 |
84 | cd $WP_TESTS_DIR
85 |
86 | if [ ! -f wp-tests-config.php ]; then
87 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
88 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php
89 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
90 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
91 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
92 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
93 | fi
94 |
95 | }
96 |
97 | install_db() {
98 | # parse DB_HOST for port or socket references
99 | local PARTS=(${DB_HOST//\:/ })
100 | local DB_HOSTNAME=${PARTS[0]};
101 | local DB_SOCK_OR_PORT=${PARTS[1]};
102 | local EXTRA=""
103 |
104 | if ! [ -z $DB_HOSTNAME ] ; then
105 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
106 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
107 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then
108 | EXTRA=" --socket=$DB_SOCK_OR_PORT"
109 | elif ! [ -z $DB_HOSTNAME ] ; then
110 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
111 | fi
112 | fi
113 |
114 | # create database
115 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
116 | }
117 |
118 | install_wp
119 | install_test_suite
120 | install_db
121 |
--------------------------------------------------------------------------------
/class-command.php:
--------------------------------------------------------------------------------
1 | ...
10 | * : Path to one or more valid WXR files for importing. Directories are also accepted.
11 | *
12 | * [--verbose[=]]
13 | * : Should we print verbose statements?
14 | * (No value for 'info'; or one of 'emergency', 'alert', 'critical',
15 | * 'error', 'warning', 'notice', 'info', 'debug')
16 | *
17 | * [--default-author=]
18 | * : Default author ID to use if invalid user is found in the import data.
19 | */
20 | public function import( $args, $assoc_args ) {
21 | $logger = new WP_Importer_Logger_CLI();
22 | if ( ! empty( $assoc_args['verbose'] ) ) {
23 | if ( $assoc_args['verbose'] === true ) {
24 | $logger->min_level = 'info';
25 | } else {
26 | $valid = $logger->level_to_numeric( $assoc_args['verbose'] );
27 | if ( ! $valid ) {
28 | WP_CLI::error( 'Invalid verbosity level' );
29 | return;
30 | }
31 |
32 | $logger->min_level = $assoc_args['verbose'];
33 | }
34 | }
35 |
36 | $path = realpath( $args[0] );
37 | if ( ! $path ) {
38 | WP_CLI::error( sprintf( 'Specified file %s does not exist', $args[0] ) );
39 | }
40 |
41 | $options = array(
42 | 'fetch_attachments' => true,
43 | );
44 | if ( isset( $assoc_args['default-author'] ) ) {
45 | $options['default_author'] = absint( $assoc_args['default-author'] );
46 |
47 | if ( ! get_user_by( 'ID', $options['default_author'] ) ) {
48 | WP_CLI::error( 'Invalid default author ID specified.' );
49 | }
50 | }
51 | $importer = new WXR_Importer( $options );
52 | $importer->set_logger( $logger );
53 | $result = $importer->import( $path );
54 | if ( is_wp_error( $result ) ) {
55 | WP_CLI::error( $result->get_error_message() );
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/class-logger-cli.php:
--------------------------------------------------------------------------------
1 | level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
16 | return;
17 | }
18 |
19 | printf(
20 | '[%s] %s' . PHP_EOL,
21 | strtoupper( $level ),
22 | $message
23 | );
24 | }
25 |
26 | public static function level_to_numeric( $level ) {
27 | $levels = array(
28 | 'emergency' => 8,
29 | 'alert' => 7,
30 | 'critical' => 6,
31 | 'error' => 5,
32 | 'warning' => 4,
33 | 'notice' => 3,
34 | 'info' => 2,
35 | 'debug' => 1,
36 | );
37 | if ( ! isset( $levels[ $level ] ) ) {
38 | return 0;
39 | }
40 |
41 | return $levels[ $level ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/class-logger-html.php:
--------------------------------------------------------------------------------
1 | ' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . ' ';
18 | echo esc_html( $message );
19 | echo '
';
20 | break;
21 |
22 | case 'error':
23 | case 'warning':
24 | case 'notice':
25 | case 'info':
26 | echo '
';
150 | $error .= esc_html__(
151 | 'Before you can upload your import file, you will need to fix the following error:',
152 | 'wordpress-importer'
153 | );
154 | $error .= sprintf( '