Version Description
- Fixes: Deprecated an incorrect name filter.
- Fixes: Minor Bug Fixes.
Download this release
Release Info
Developer | raratheme |
Plugin | Rara One Click Demo Import |
Version | 1.3.1 |
Comparing to | |
See all releases |
Code changes from version 1.3.0 to 1.3.1
- LICENSE.txt +338 -338
- assets/css/style.css +171 -171
- assets/js/script.js +120 -120
- includes/class-rrdi-customizer-option.php +24 -24
- includes/class-rrdi-helpers.php +610 -610
- includes/class-rrdi-importer.php +78 -78
- includes/class-rrdi-include-files.php +22 -22
- includes/class-rrdi-init.php +44 -44
- includes/class-rrdi-logger.php +64 -64
- includes/class-rrdi-main.php +815 -815
- includes/class-rrdi-wxr-importer.php +51 -51
- includes/extras/class-logger-cli.php +45 -45
- includes/extras/class-logger.php +136 -136
- includes/extras/class-wxr-importer.php +2250 -2250
- includes/settings/installed-demos.php +237 -237
- includes/settings/intro.php +24 -24
- includes/settings/welcome.php +52 -52
- includes/vendor/class-demo-installer-skin.php +61 -64
- includes/vendor/class-demo-upgrader.php +353 -353
- includes/vendor/class-rrdi-customizer-importer.php +193 -193
- includes/vendor/class-rrdi-widget-importer.php +304 -304
- languages/rara-one-click-demo-import.pot +5 -5
- rara-one-click-demo-import.php +26 -26
- readme.txt +179 -175
LICENSE.txt
CHANGED
@@ -1,339 +1,339 @@
|
|
1 |
-
GNU GENERAL PUBLIC LICENSE
|
2 |
-
Version 2, June 1991
|
3 |
-
|
4 |
-
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
5 |
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
-
Everyone is permitted to copy and distribute verbatim copies
|
7 |
-
of this license document, but changing it is not allowed.
|
8 |
-
|
9 |
-
Preamble
|
10 |
-
|
11 |
-
The licenses for most software are designed to take away your
|
12 |
-
freedom to share and change it. By contrast, the GNU General Public
|
13 |
-
License is intended to guarantee your freedom to share and change free
|
14 |
-
software--to make sure the software is free for all its users. This
|
15 |
-
General Public License applies to most of the Free Software
|
16 |
-
Foundation's software and to any other program whose authors commit to
|
17 |
-
using it. (Some other Free Software Foundation software is covered by
|
18 |
-
the GNU Lesser General Public License instead.) You can apply it to
|
19 |
-
your programs, too.
|
20 |
-
|
21 |
-
When we speak of free software, we are referring to freedom, not
|
22 |
-
price. Our General Public Licenses are designed to make sure that you
|
23 |
-
have the freedom to distribute copies of free software (and charge for
|
24 |
-
this service if you wish), that you receive source code or can get it
|
25 |
-
if you want it, that you can change the software or use pieces of it
|
26 |
-
in new free programs; and that you know you can do these things.
|
27 |
-
|
28 |
-
To protect your rights, we need to make restrictions that forbid
|
29 |
-
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
-
These restrictions translate to certain responsibilities for you if you
|
31 |
-
distribute copies of the software, or if you modify it.
|
32 |
-
|
33 |
-
For example, if you distribute copies of such a program, whether
|
34 |
-
gratis or for a fee, you must give the recipients all the rights that
|
35 |
-
you have. You must make sure that they, too, receive or can get the
|
36 |
-
source code. And you must show them these terms so they know their
|
37 |
-
rights.
|
38 |
-
|
39 |
-
We protect your rights with two steps: (1) copyright the software, and
|
40 |
-
(2) offer you this license which gives you legal permission to copy,
|
41 |
-
distribute and/or modify the software.
|
42 |
-
|
43 |
-
Also, for each author's protection and ours, we want to make certain
|
44 |
-
that everyone understands that there is no warranty for this free
|
45 |
-
software. If the software is modified by someone else and passed on, we
|
46 |
-
want its recipients to know that what they have is not the original, so
|
47 |
-
that any problems introduced by others will not reflect on the original
|
48 |
-
authors' reputations.
|
49 |
-
|
50 |
-
Finally, any free program is threatened constantly by software
|
51 |
-
patents. We wish to avoid the danger that redistributors of a free
|
52 |
-
program will individually obtain patent licenses, in effect making the
|
53 |
-
program proprietary. To prevent this, we have made it clear that any
|
54 |
-
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
-
|
56 |
-
The precise terms and conditions for copying, distribution and
|
57 |
-
modification follow.
|
58 |
-
|
59 |
-
GNU GENERAL PUBLIC LICENSE
|
60 |
-
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
-
|
62 |
-
0. This License applies to any program or other work which contains
|
63 |
-
a notice placed by the copyright holder saying it may be distributed
|
64 |
-
under the terms of this General Public License. The "Program", below,
|
65 |
-
refers to any such program or work, and a "work based on the Program"
|
66 |
-
means either the Program or any derivative work under copyright law:
|
67 |
-
that is to say, a work containing the Program or a portion of it,
|
68 |
-
either verbatim or with modifications and/or translated into another
|
69 |
-
language. (Hereinafter, translation is included without limitation in
|
70 |
-
the term "modification".) Each licensee is addressed as "you".
|
71 |
-
|
72 |
-
Activities other than copying, distribution and modification are not
|
73 |
-
covered by this License; they are outside its scope. The act of
|
74 |
-
running the Program is not restricted, and the output from the Program
|
75 |
-
is covered only if its contents constitute a work based on the
|
76 |
-
Program (independent of having been made by running the Program).
|
77 |
-
Whether that is true depends on what the Program does.
|
78 |
-
|
79 |
-
1. You may copy and distribute verbatim copies of the Program's
|
80 |
-
source code as you receive it, in any medium, provided that you
|
81 |
-
conspicuously and appropriately publish on each copy an appropriate
|
82 |
-
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
-
notices that refer to this License and to the absence of any warranty;
|
84 |
-
and give any other recipients of the Program a copy of this License
|
85 |
-
along with the Program.
|
86 |
-
|
87 |
-
You may charge a fee for the physical act of transferring a copy, and
|
88 |
-
you may at your option offer warranty protection in exchange for a fee.
|
89 |
-
|
90 |
-
2. You may modify your copy or copies of the Program or any portion
|
91 |
-
of it, thus forming a work based on the Program, and copy and
|
92 |
-
distribute such modifications or work under the terms of Section 1
|
93 |
-
above, provided that you also meet all of these conditions:
|
94 |
-
|
95 |
-
a) You must cause the modified files to carry prominent notices
|
96 |
-
stating that you changed the files and the date of any change.
|
97 |
-
|
98 |
-
b) You must cause any work that you distribute or publish, that in
|
99 |
-
whole or in part contains or is derived from the Program or any
|
100 |
-
part thereof, to be licensed as a whole at no charge to all third
|
101 |
-
parties under the terms of this License.
|
102 |
-
|
103 |
-
c) If the modified program normally reads commands interactively
|
104 |
-
when run, you must cause it, when started running for such
|
105 |
-
interactive use in the most ordinary way, to print or display an
|
106 |
-
announcement including an appropriate copyright notice and a
|
107 |
-
notice that there is no warranty (or else, saying that you provide
|
108 |
-
a warranty) and that users may redistribute the program under
|
109 |
-
these conditions, and telling the user how to view a copy of this
|
110 |
-
License. (Exception: if the Program itself is interactive but
|
111 |
-
does not normally print such an announcement, your work based on
|
112 |
-
the Program is not required to print an announcement.)
|
113 |
-
|
114 |
-
These requirements apply to the modified work as a whole. If
|
115 |
-
identifiable sections of that work are not derived from the Program,
|
116 |
-
and can be reasonably considered independent and separate works in
|
117 |
-
themselves, then this License, and its terms, do not apply to those
|
118 |
-
sections when you distribute them as separate works. But when you
|
119 |
-
distribute the same sections as part of a whole which is a work based
|
120 |
-
on the Program, the distribution of the whole must be on the terms of
|
121 |
-
this License, whose permissions for other licensees extend to the
|
122 |
-
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
-
|
124 |
-
Thus, it is not the intent of this section to claim rights or contest
|
125 |
-
your rights to work written entirely by you; rather, the intent is to
|
126 |
-
exercise the right to control the distribution of derivative or
|
127 |
-
collective works based on the Program.
|
128 |
-
|
129 |
-
In addition, mere aggregation of another work not based on the Program
|
130 |
-
with the Program (or with a work based on the Program) on a volume of
|
131 |
-
a storage or distribution medium does not bring the other work under
|
132 |
-
the scope of this License.
|
133 |
-
|
134 |
-
3. You may copy and distribute the Program (or a work based on it,
|
135 |
-
under Section 2) in object code or executable form under the terms of
|
136 |
-
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
-
|
138 |
-
a) Accompany it with the complete corresponding machine-readable
|
139 |
-
source code, which must be distributed under the terms of Sections
|
140 |
-
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
-
|
142 |
-
b) Accompany it with a written offer, valid for at least three
|
143 |
-
years, to give any third party, for a charge no more than your
|
144 |
-
cost of physically performing source distribution, a complete
|
145 |
-
machine-readable copy of the corresponding source code, to be
|
146 |
-
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
-
customarily used for software interchange; or,
|
148 |
-
|
149 |
-
c) Accompany it with the information you received as to the offer
|
150 |
-
to distribute corresponding source code. (This alternative is
|
151 |
-
allowed only for noncommercial distribution and only if you
|
152 |
-
received the program in object code or executable form with such
|
153 |
-
an offer, in accord with Subsection b above.)
|
154 |
-
|
155 |
-
The source code for a work means the preferred form of the work for
|
156 |
-
making modifications to it. For an executable work, complete source
|
157 |
-
code means all the source code for all modules it contains, plus any
|
158 |
-
associated interface definition files, plus the scripts used to
|
159 |
-
control compilation and installation of the executable. However, as a
|
160 |
-
special exception, the source code distributed need not include
|
161 |
-
anything that is normally distributed (in either source or binary
|
162 |
-
form) with the major components (compiler, kernel, and so on) of the
|
163 |
-
operating system on which the executable runs, unless that component
|
164 |
-
itself accompanies the executable.
|
165 |
-
|
166 |
-
If distribution of executable or object code is made by offering
|
167 |
-
access to copy from a designated place, then offering equivalent
|
168 |
-
access to copy the source code from the same place counts as
|
169 |
-
distribution of the source code, even though third parties are not
|
170 |
-
compelled to copy the source along with the object code.
|
171 |
-
|
172 |
-
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
-
except as expressly provided under this License. Any attempt
|
174 |
-
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
-
void, and will automatically terminate your rights under this License.
|
176 |
-
However, parties who have received copies, or rights, from you under
|
177 |
-
this License will not have their licenses terminated so long as such
|
178 |
-
parties remain in full compliance.
|
179 |
-
|
180 |
-
5. You are not required to accept this License, since you have not
|
181 |
-
signed it. However, nothing else grants you permission to modify or
|
182 |
-
distribute the Program or its derivative works. These actions are
|
183 |
-
prohibited by law if you do not accept this License. Therefore, by
|
184 |
-
modifying or distributing the Program (or any work based on the
|
185 |
-
Program), you indicate your acceptance of this License to do so, and
|
186 |
-
all its terms and conditions for copying, distributing or modifying
|
187 |
-
the Program or works based on it.
|
188 |
-
|
189 |
-
6. Each time you redistribute the Program (or any work based on the
|
190 |
-
Program), the recipient automatically receives a license from the
|
191 |
-
original licensor to copy, distribute or modify the Program subject to
|
192 |
-
these terms and conditions. You may not impose any further
|
193 |
-
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
-
You are not responsible for enforcing compliance by third parties to
|
195 |
-
this License.
|
196 |
-
|
197 |
-
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
-
infringement or for any other reason (not limited to patent issues),
|
199 |
-
conditions are imposed on you (whether by court order, agreement or
|
200 |
-
otherwise) that contradict the conditions of this License, they do not
|
201 |
-
excuse you from the conditions of this License. If you cannot
|
202 |
-
distribute so as to satisfy simultaneously your obligations under this
|
203 |
-
License and any other pertinent obligations, then as a consequence you
|
204 |
-
may not distribute the Program at all. For example, if a patent
|
205 |
-
license would not permit royalty-free redistribution of the Program by
|
206 |
-
all those who receive copies directly or indirectly through you, then
|
207 |
-
the only way you could satisfy both it and this License would be to
|
208 |
-
refrain entirely from distribution of the Program.
|
209 |
-
|
210 |
-
If any portion of this section is held invalid or unenforceable under
|
211 |
-
any particular circumstance, the balance of the section is intended to
|
212 |
-
apply and the section as a whole is intended to apply in other
|
213 |
-
circumstances.
|
214 |
-
|
215 |
-
It is not the purpose of this section to induce you to infringe any
|
216 |
-
patents or other property right claims or to contest validity of any
|
217 |
-
such claims; this section has the sole purpose of protecting the
|
218 |
-
integrity of the free software distribution system, which is
|
219 |
-
implemented by public license practices. Many people have made
|
220 |
-
generous contributions to the wide range of software distributed
|
221 |
-
through that system in reliance on consistent application of that
|
222 |
-
system; it is up to the author/donor to decide if he or she is willing
|
223 |
-
to distribute software through any other system and a licensee cannot
|
224 |
-
impose that choice.
|
225 |
-
|
226 |
-
This section is intended to make thoroughly clear what is believed to
|
227 |
-
be a consequence of the rest of this License.
|
228 |
-
|
229 |
-
8. If the distribution and/or use of the Program is restricted in
|
230 |
-
certain countries either by patents or by copyrighted interfaces, the
|
231 |
-
original copyright holder who places the Program under this License
|
232 |
-
may add an explicit geographical distribution limitation excluding
|
233 |
-
those countries, so that distribution is permitted only in or among
|
234 |
-
countries not thus excluded. In such case, this License incorporates
|
235 |
-
the limitation as if written in the body of this License.
|
236 |
-
|
237 |
-
9. The Free Software Foundation may publish revised and/or new versions
|
238 |
-
of the General Public License from time to time. Such new versions will
|
239 |
-
be similar in spirit to the present version, but may differ in detail to
|
240 |
-
address new problems or concerns.
|
241 |
-
|
242 |
-
Each version is given a distinguishing version number. If the Program
|
243 |
-
specifies a version number of this License which applies to it and "any
|
244 |
-
later version", you have the option of following the terms and conditions
|
245 |
-
either of that version or of any later version published by the Free
|
246 |
-
Software Foundation. If the Program does not specify a version number of
|
247 |
-
this License, you may choose any version ever published by the Free Software
|
248 |
-
Foundation.
|
249 |
-
|
250 |
-
10. If you wish to incorporate parts of the Program into other free
|
251 |
-
programs whose distribution conditions are different, write to the author
|
252 |
-
to ask for permission. For software which is copyrighted by the Free
|
253 |
-
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
-
make exceptions for this. Our decision will be guided by the two goals
|
255 |
-
of preserving the free status of all derivatives of our free software and
|
256 |
-
of promoting the sharing and reuse of software generally.
|
257 |
-
|
258 |
-
NO WARRANTY
|
259 |
-
|
260 |
-
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
-
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
-
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
-
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
-
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
-
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
-
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
-
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
-
REPAIR OR CORRECTION.
|
269 |
-
|
270 |
-
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
-
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
-
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
-
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
-
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
-
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
-
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
-
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
-
POSSIBILITY OF SUCH DAMAGES.
|
279 |
-
|
280 |
-
END OF TERMS AND CONDITIONS
|
281 |
-
|
282 |
-
How to Apply These Terms to Your New Programs
|
283 |
-
|
284 |
-
If you develop a new program, and you want it to be of the greatest
|
285 |
-
possible use to the public, the best way to achieve this is to make it
|
286 |
-
free software which everyone can redistribute and change under these terms.
|
287 |
-
|
288 |
-
To do so, attach the following notices to the program. It is safest
|
289 |
-
to attach them to the start of each source file to most effectively
|
290 |
-
convey the exclusion of warranty; and each file should have at least
|
291 |
-
the "copyright" line and a pointer to where the full notice is found.
|
292 |
-
|
293 |
-
<one line to give the program's name and a brief idea of what it does.>
|
294 |
-
Copyright (C) <year> <name of author>
|
295 |
-
|
296 |
-
This program is free software; you can redistribute it and/or modify
|
297 |
-
it under the terms of the GNU General Public License as published by
|
298 |
-
the Free Software Foundation; either version 2 of the License, or
|
299 |
-
(at your option) any later version.
|
300 |
-
|
301 |
-
This program is distributed in the hope that it will be useful,
|
302 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
303 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
304 |
-
GNU General Public License for more details.
|
305 |
-
|
306 |
-
You should have received a copy of the GNU General Public License along
|
307 |
-
with this program; if not, write to the Free Software Foundation, Inc.,
|
308 |
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
309 |
-
|
310 |
-
Also add information on how to contact you by electronic and paper mail.
|
311 |
-
|
312 |
-
If the program is interactive, make it output a short notice like this
|
313 |
-
when it starts in an interactive mode:
|
314 |
-
|
315 |
-
Gnomovision version 69, Copyright (C) year name of author
|
316 |
-
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
317 |
-
This is free software, and you are welcome to redistribute it
|
318 |
-
under certain conditions; type `show c' for details.
|
319 |
-
|
320 |
-
The hypothetical commands `show w' and `show c' should show the appropriate
|
321 |
-
parts of the General Public License. Of course, the commands you use may
|
322 |
-
be called something other than `show w' and `show c'; they could even be
|
323 |
-
mouse-clicks or menu items--whatever suits your program.
|
324 |
-
|
325 |
-
You should also get your employer (if you work as a programmer) or your
|
326 |
-
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
-
necessary. Here is a sample; alter the names:
|
328 |
-
|
329 |
-
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
-
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
-
|
332 |
-
<signature of Ty Coon>, 1 April 1989
|
333 |
-
Ty Coon, President of Vice
|
334 |
-
|
335 |
-
This General Public License does not permit incorporating your program into
|
336 |
-
proprietary programs. If your program is a subroutine library, you may
|
337 |
-
consider it more useful to permit linking proprietary applications with the
|
338 |
-
library. If this is what you want to do, use the GNU Lesser General
|
339 |
Public License instead of this License.
|
1 |
+
GNU GENERAL PUBLIC LICENSE
|
2 |
+
Version 2, June 1991
|
3 |
+
|
4 |
+
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
7 |
+
of this license document, but changing it is not allowed.
|
8 |
+
|
9 |
+
Preamble
|
10 |
+
|
11 |
+
The licenses for most software are designed to take away your
|
12 |
+
freedom to share and change it. By contrast, the GNU General Public
|
13 |
+
License is intended to guarantee your freedom to share and change free
|
14 |
+
software--to make sure the software is free for all its users. This
|
15 |
+
General Public License applies to most of the Free Software
|
16 |
+
Foundation's software and to any other program whose authors commit to
|
17 |
+
using it. (Some other Free Software Foundation software is covered by
|
18 |
+
the GNU Lesser General Public License instead.) You can apply it to
|
19 |
+
your programs, too.
|
20 |
+
|
21 |
+
When we speak of free software, we are referring to freedom, not
|
22 |
+
price. Our General Public Licenses are designed to make sure that you
|
23 |
+
have the freedom to distribute copies of free software (and charge for
|
24 |
+
this service if you wish), that you receive source code or can get it
|
25 |
+
if you want it, that you can change the software or use pieces of it
|
26 |
+
in new free programs; and that you know you can do these things.
|
27 |
+
|
28 |
+
To protect your rights, we need to make restrictions that forbid
|
29 |
+
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
+
These restrictions translate to certain responsibilities for you if you
|
31 |
+
distribute copies of the software, or if you modify it.
|
32 |
+
|
33 |
+
For example, if you distribute copies of such a program, whether
|
34 |
+
gratis or for a fee, you must give the recipients all the rights that
|
35 |
+
you have. You must make sure that they, too, receive or can get the
|
36 |
+
source code. And you must show them these terms so they know their
|
37 |
+
rights.
|
38 |
+
|
39 |
+
We protect your rights with two steps: (1) copyright the software, and
|
40 |
+
(2) offer you this license which gives you legal permission to copy,
|
41 |
+
distribute and/or modify the software.
|
42 |
+
|
43 |
+
Also, for each author's protection and ours, we want to make certain
|
44 |
+
that everyone understands that there is no warranty for this free
|
45 |
+
software. If the software is modified by someone else and passed on, we
|
46 |
+
want its recipients to know that what they have is not the original, so
|
47 |
+
that any problems introduced by others will not reflect on the original
|
48 |
+
authors' reputations.
|
49 |
+
|
50 |
+
Finally, any free program is threatened constantly by software
|
51 |
+
patents. We wish to avoid the danger that redistributors of a free
|
52 |
+
program will individually obtain patent licenses, in effect making the
|
53 |
+
program proprietary. To prevent this, we have made it clear that any
|
54 |
+
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
+
|
56 |
+
The precise terms and conditions for copying, distribution and
|
57 |
+
modification follow.
|
58 |
+
|
59 |
+
GNU GENERAL PUBLIC LICENSE
|
60 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
+
|
62 |
+
0. This License applies to any program or other work which contains
|
63 |
+
a notice placed by the copyright holder saying it may be distributed
|
64 |
+
under the terms of this General Public License. The "Program", below,
|
65 |
+
refers to any such program or work, and a "work based on the Program"
|
66 |
+
means either the Program or any derivative work under copyright law:
|
67 |
+
that is to say, a work containing the Program or a portion of it,
|
68 |
+
either verbatim or with modifications and/or translated into another
|
69 |
+
language. (Hereinafter, translation is included without limitation in
|
70 |
+
the term "modification".) Each licensee is addressed as "you".
|
71 |
+
|
72 |
+
Activities other than copying, distribution and modification are not
|
73 |
+
covered by this License; they are outside its scope. The act of
|
74 |
+
running the Program is not restricted, and the output from the Program
|
75 |
+
is covered only if its contents constitute a work based on the
|
76 |
+
Program (independent of having been made by running the Program).
|
77 |
+
Whether that is true depends on what the Program does.
|
78 |
+
|
79 |
+
1. You may copy and distribute verbatim copies of the Program's
|
80 |
+
source code as you receive it, in any medium, provided that you
|
81 |
+
conspicuously and appropriately publish on each copy an appropriate
|
82 |
+
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
+
notices that refer to this License and to the absence of any warranty;
|
84 |
+
and give any other recipients of the Program a copy of this License
|
85 |
+
along with the Program.
|
86 |
+
|
87 |
+
You may charge a fee for the physical act of transferring a copy, and
|
88 |
+
you may at your option offer warranty protection in exchange for a fee.
|
89 |
+
|
90 |
+
2. You may modify your copy or copies of the Program or any portion
|
91 |
+
of it, thus forming a work based on the Program, and copy and
|
92 |
+
distribute such modifications or work under the terms of Section 1
|
93 |
+
above, provided that you also meet all of these conditions:
|
94 |
+
|
95 |
+
a) You must cause the modified files to carry prominent notices
|
96 |
+
stating that you changed the files and the date of any change.
|
97 |
+
|
98 |
+
b) You must cause any work that you distribute or publish, that in
|
99 |
+
whole or in part contains or is derived from the Program or any
|
100 |
+
part thereof, to be licensed as a whole at no charge to all third
|
101 |
+
parties under the terms of this License.
|
102 |
+
|
103 |
+
c) If the modified program normally reads commands interactively
|
104 |
+
when run, you must cause it, when started running for such
|
105 |
+
interactive use in the most ordinary way, to print or display an
|
106 |
+
announcement including an appropriate copyright notice and a
|
107 |
+
notice that there is no warranty (or else, saying that you provide
|
108 |
+
a warranty) and that users may redistribute the program under
|
109 |
+
these conditions, and telling the user how to view a copy of this
|
110 |
+
License. (Exception: if the Program itself is interactive but
|
111 |
+
does not normally print such an announcement, your work based on
|
112 |
+
the Program is not required to print an announcement.)
|
113 |
+
|
114 |
+
These requirements apply to the modified work as a whole. If
|
115 |
+
identifiable sections of that work are not derived from the Program,
|
116 |
+
and can be reasonably considered independent and separate works in
|
117 |
+
themselves, then this License, and its terms, do not apply to those
|
118 |
+
sections when you distribute them as separate works. But when you
|
119 |
+
distribute the same sections as part of a whole which is a work based
|
120 |
+
on the Program, the distribution of the whole must be on the terms of
|
121 |
+
this License, whose permissions for other licensees extend to the
|
122 |
+
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
+
|
124 |
+
Thus, it is not the intent of this section to claim rights or contest
|
125 |
+
your rights to work written entirely by you; rather, the intent is to
|
126 |
+
exercise the right to control the distribution of derivative or
|
127 |
+
collective works based on the Program.
|
128 |
+
|
129 |
+
In addition, mere aggregation of another work not based on the Program
|
130 |
+
with the Program (or with a work based on the Program) on a volume of
|
131 |
+
a storage or distribution medium does not bring the other work under
|
132 |
+
the scope of this License.
|
133 |
+
|
134 |
+
3. You may copy and distribute the Program (or a work based on it,
|
135 |
+
under Section 2) in object code or executable form under the terms of
|
136 |
+
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
+
|
138 |
+
a) Accompany it with the complete corresponding machine-readable
|
139 |
+
source code, which must be distributed under the terms of Sections
|
140 |
+
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
+
|
142 |
+
b) Accompany it with a written offer, valid for at least three
|
143 |
+
years, to give any third party, for a charge no more than your
|
144 |
+
cost of physically performing source distribution, a complete
|
145 |
+
machine-readable copy of the corresponding source code, to be
|
146 |
+
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
+
customarily used for software interchange; or,
|
148 |
+
|
149 |
+
c) Accompany it with the information you received as to the offer
|
150 |
+
to distribute corresponding source code. (This alternative is
|
151 |
+
allowed only for noncommercial distribution and only if you
|
152 |
+
received the program in object code or executable form with such
|
153 |
+
an offer, in accord with Subsection b above.)
|
154 |
+
|
155 |
+
The source code for a work means the preferred form of the work for
|
156 |
+
making modifications to it. For an executable work, complete source
|
157 |
+
code means all the source code for all modules it contains, plus any
|
158 |
+
associated interface definition files, plus the scripts used to
|
159 |
+
control compilation and installation of the executable. However, as a
|
160 |
+
special exception, the source code distributed need not include
|
161 |
+
anything that is normally distributed (in either source or binary
|
162 |
+
form) with the major components (compiler, kernel, and so on) of the
|
163 |
+
operating system on which the executable runs, unless that component
|
164 |
+
itself accompanies the executable.
|
165 |
+
|
166 |
+
If distribution of executable or object code is made by offering
|
167 |
+
access to copy from a designated place, then offering equivalent
|
168 |
+
access to copy the source code from the same place counts as
|
169 |
+
distribution of the source code, even though third parties are not
|
170 |
+
compelled to copy the source along with the object code.
|
171 |
+
|
172 |
+
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
+
except as expressly provided under this License. Any attempt
|
174 |
+
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
+
void, and will automatically terminate your rights under this License.
|
176 |
+
However, parties who have received copies, or rights, from you under
|
177 |
+
this License will not have their licenses terminated so long as such
|
178 |
+
parties remain in full compliance.
|
179 |
+
|
180 |
+
5. You are not required to accept this License, since you have not
|
181 |
+
signed it. However, nothing else grants you permission to modify or
|
182 |
+
distribute the Program or its derivative works. These actions are
|
183 |
+
prohibited by law if you do not accept this License. Therefore, by
|
184 |
+
modifying or distributing the Program (or any work based on the
|
185 |
+
Program), you indicate your acceptance of this License to do so, and
|
186 |
+
all its terms and conditions for copying, distributing or modifying
|
187 |
+
the Program or works based on it.
|
188 |
+
|
189 |
+
6. Each time you redistribute the Program (or any work based on the
|
190 |
+
Program), the recipient automatically receives a license from the
|
191 |
+
original licensor to copy, distribute or modify the Program subject to
|
192 |
+
these terms and conditions. You may not impose any further
|
193 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
+
You are not responsible for enforcing compliance by third parties to
|
195 |
+
this License.
|
196 |
+
|
197 |
+
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
+
infringement or for any other reason (not limited to patent issues),
|
199 |
+
conditions are imposed on you (whether by court order, agreement or
|
200 |
+
otherwise) that contradict the conditions of this License, they do not
|
201 |
+
excuse you from the conditions of this License. If you cannot
|
202 |
+
distribute so as to satisfy simultaneously your obligations under this
|
203 |
+
License and any other pertinent obligations, then as a consequence you
|
204 |
+
may not distribute the Program at all. For example, if a patent
|
205 |
+
license would not permit royalty-free redistribution of the Program by
|
206 |
+
all those who receive copies directly or indirectly through you, then
|
207 |
+
the only way you could satisfy both it and this License would be to
|
208 |
+
refrain entirely from distribution of the Program.
|
209 |
+
|
210 |
+
If any portion of this section is held invalid or unenforceable under
|
211 |
+
any particular circumstance, the balance of the section is intended to
|
212 |
+
apply and the section as a whole is intended to apply in other
|
213 |
+
circumstances.
|
214 |
+
|
215 |
+
It is not the purpose of this section to induce you to infringe any
|
216 |
+
patents or other property right claims or to contest validity of any
|
217 |
+
such claims; this section has the sole purpose of protecting the
|
218 |
+
integrity of the free software distribution system, which is
|
219 |
+
implemented by public license practices. Many people have made
|
220 |
+
generous contributions to the wide range of software distributed
|
221 |
+
through that system in reliance on consistent application of that
|
222 |
+
system; it is up to the author/donor to decide if he or she is willing
|
223 |
+
to distribute software through any other system and a licensee cannot
|
224 |
+
impose that choice.
|
225 |
+
|
226 |
+
This section is intended to make thoroughly clear what is believed to
|
227 |
+
be a consequence of the rest of this License.
|
228 |
+
|
229 |
+
8. If the distribution and/or use of the Program is restricted in
|
230 |
+
certain countries either by patents or by copyrighted interfaces, the
|
231 |
+
original copyright holder who places the Program under this License
|
232 |
+
may add an explicit geographical distribution limitation excluding
|
233 |
+
those countries, so that distribution is permitted only in or among
|
234 |
+
countries not thus excluded. In such case, this License incorporates
|
235 |
+
the limitation as if written in the body of this License.
|
236 |
+
|
237 |
+
9. The Free Software Foundation may publish revised and/or new versions
|
238 |
+
of the General Public License from time to time. Such new versions will
|
239 |
+
be similar in spirit to the present version, but may differ in detail to
|
240 |
+
address new problems or concerns.
|
241 |
+
|
242 |
+
Each version is given a distinguishing version number. If the Program
|
243 |
+
specifies a version number of this License which applies to it and "any
|
244 |
+
later version", you have the option of following the terms and conditions
|
245 |
+
either of that version or of any later version published by the Free
|
246 |
+
Software Foundation. If the Program does not specify a version number of
|
247 |
+
this License, you may choose any version ever published by the Free Software
|
248 |
+
Foundation.
|
249 |
+
|
250 |
+
10. If you wish to incorporate parts of the Program into other free
|
251 |
+
programs whose distribution conditions are different, write to the author
|
252 |
+
to ask for permission. For software which is copyrighted by the Free
|
253 |
+
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
+
make exceptions for this. Our decision will be guided by the two goals
|
255 |
+
of preserving the free status of all derivatives of our free software and
|
256 |
+
of promoting the sharing and reuse of software generally.
|
257 |
+
|
258 |
+
NO WARRANTY
|
259 |
+
|
260 |
+
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
+
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
+
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
+
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
+
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
+
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
+
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
+
REPAIR OR CORRECTION.
|
269 |
+
|
270 |
+
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
+
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
+
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
+
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
+
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
+
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
+
POSSIBILITY OF SUCH DAMAGES.
|
279 |
+
|
280 |
+
END OF TERMS AND CONDITIONS
|
281 |
+
|
282 |
+
How to Apply These Terms to Your New Programs
|
283 |
+
|
284 |
+
If you develop a new program, and you want it to be of the greatest
|
285 |
+
possible use to the public, the best way to achieve this is to make it
|
286 |
+
free software which everyone can redistribute and change under these terms.
|
287 |
+
|
288 |
+
To do so, attach the following notices to the program. It is safest
|
289 |
+
to attach them to the start of each source file to most effectively
|
290 |
+
convey the exclusion of warranty; and each file should have at least
|
291 |
+
the "copyright" line and a pointer to where the full notice is found.
|
292 |
+
|
293 |
+
<one line to give the program's name and a brief idea of what it does.>
|
294 |
+
Copyright (C) <year> <name of author>
|
295 |
+
|
296 |
+
This program is free software; you can redistribute it and/or modify
|
297 |
+
it under the terms of the GNU General Public License as published by
|
298 |
+
the Free Software Foundation; either version 2 of the License, or
|
299 |
+
(at your option) any later version.
|
300 |
+
|
301 |
+
This program is distributed in the hope that it will be useful,
|
302 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
303 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
304 |
+
GNU General Public License for more details.
|
305 |
+
|
306 |
+
You should have received a copy of the GNU General Public License along
|
307 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
308 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
309 |
+
|
310 |
+
Also add information on how to contact you by electronic and paper mail.
|
311 |
+
|
312 |
+
If the program is interactive, make it output a short notice like this
|
313 |
+
when it starts in an interactive mode:
|
314 |
+
|
315 |
+
Gnomovision version 69, Copyright (C) year name of author
|
316 |
+
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
317 |
+
This is free software, and you are welcome to redistribute it
|
318 |
+
under certain conditions; type `show c' for details.
|
319 |
+
|
320 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
321 |
+
parts of the General Public License. Of course, the commands you use may
|
322 |
+
be called something other than `show w' and `show c'; they could even be
|
323 |
+
mouse-clicks or menu items--whatever suits your program.
|
324 |
+
|
325 |
+
You should also get your employer (if you work as a programmer) or your
|
326 |
+
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
+
necessary. Here is a sample; alter the names:
|
328 |
+
|
329 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
+
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
+
|
332 |
+
<signature of Ty Coon>, 1 April 1989
|
333 |
+
Ty Coon, President of Vice
|
334 |
+
|
335 |
+
This General Public License does not permit incorporating your program into
|
336 |
+
proprietary programs. If your program is a subroutine library, you may
|
337 |
+
consider it more useful to permit linking proprietary applications with the
|
338 |
+
library. If this is what you want to do, use the GNU Lesser General
|
339 |
Public License instead of this License.
|
assets/css/style.css
CHANGED
@@ -1,172 +1,172 @@
|
|
1 |
-
/* Overriding WordPress native styles */
|
2 |
-
|
3 |
-
.rrdi h2 {
|
4 |
-
text-align: inherit;
|
5 |
-
}
|
6 |
-
|
7 |
-
.rrdi h2:first-child,
|
8 |
-
.rrdi h3:first-child {
|
9 |
-
margin-top: 0;
|
10 |
-
}
|
11 |
-
|
12 |
-
.rrdi hr {
|
13 |
-
margin: 2.62em 0;
|
14 |
-
}
|
15 |
-
|
16 |
-
.feature-section + hr {
|
17 |
-
margin-top: 0;
|
18 |
-
}
|
19 |
-
|
20 |
-
#wpbody select {
|
21 |
-
height: auto;
|
22 |
-
padding: .62em;
|
23 |
-
line-height: inherit;
|
24 |
-
}
|
25 |
-
|
26 |
-
.rrdi .notice {
|
27 |
-
display: block !important;
|
28 |
-
margin-top: 1.4em;
|
29 |
-
margin-bottom: 0;
|
30 |
-
}
|
31 |
-
|
32 |
-
/* Plugin elements */
|
33 |
-
|
34 |
-
.RRDI__demo-import-files {
|
35 |
-
width: 100%;
|
36 |
-
}
|
37 |
-
|
38 |
-
.RRDI__demo-import-preview-image-message {
|
39 |
-
font-style: italic;
|
40 |
-
}
|
41 |
-
|
42 |
-
/* Plugin title */
|
43 |
-
|
44 |
-
.RRDI__title:before {
|
45 |
-
width: auto;
|
46 |
-
height: auto;
|
47 |
-
font-size: inherit;
|
48 |
-
}
|
49 |
-
|
50 |
-
/* Plugin intro text */
|
51 |
-
|
52 |
-
.RRDI__intro-text ul {
|
53 |
-
padding: 0 4%;
|
54 |
-
list-style-type: square;
|
55 |
-
}
|
56 |
-
|
57 |
-
/* Plugin multi select import and Plugin file upload containers */
|
58 |
-
|
59 |
-
.RRDI__file-upload,
|
60 |
-
.RRDI__multi-select-import,
|
61 |
-
.RRDI__demo-import-notice:not(:empty) {
|
62 |
-
padding: 4%;
|
63 |
-
margin: 1.62em 0;
|
64 |
-
background-color: #ffffff;
|
65 |
-
border: 1px solid #e5e5e5;
|
66 |
-
}
|
67 |
-
|
68 |
-
.RRDI__file-upload {
|
69 |
-
margin: 0;
|
70 |
-
margin-bottom: -1px;
|
71 |
-
}
|
72 |
-
|
73 |
-
.RRDI__file-upload span {
|
74 |
-
font-size: .81em;
|
75 |
-
font-weight: normal;
|
76 |
-
opacity: .66;
|
77 |
-
}
|
78 |
-
|
79 |
-
.RRDI__demo-import-notice:not(:empty) {
|
80 |
-
border: 0;
|
81 |
-
border-left: 4px solid #00a0d2;
|
82 |
-
-webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
|
83 |
-
box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
|
84 |
-
}
|
85 |
-
|
86 |
-
[dir="rtl"] .RRDI__demo-import-notice:not(:empty) {
|
87 |
-
border: 0;
|
88 |
-
border-right: 4px solid #00a0d2;
|
89 |
-
}
|
90 |
-
|
91 |
-
/* Plugin button */
|
92 |
-
|
93 |
-
.RRDI__button-container {
|
94 |
-
margin-top: 1.62em;
|
95 |
-
}
|
96 |
-
|
97 |
-
/* AJAX loader */
|
98 |
-
|
99 |
-
.RRDI__ajax-loader {
|
100 |
-
font-size: 1.5em;
|
101 |
-
display: none;
|
102 |
-
}
|
103 |
-
|
104 |
-
.RRDI__ajax-loader .spinner {
|
105 |
-
display: inline-block;
|
106 |
-
float: none;
|
107 |
-
visibility: visible;
|
108 |
-
margin-bottom: 6px;
|
109 |
-
}
|
110 |
-
|
111 |
-
#tabs-container .tabs-menu{
|
112 |
-
margin: 0;
|
113 |
-
padding: 0;
|
114 |
-
list-style: none;
|
115 |
-
overflow: hidden;
|
116 |
-
text-transform: capitalize;
|
117 |
-
}
|
118 |
-
|
119 |
-
#tabs-container .tabs-menu li{
|
120 |
-
float: left;
|
121 |
-
border: 1px solid transparent;
|
122 |
-
margin: 0;
|
123 |
-
}
|
124 |
-
|
125 |
-
#tabs-container .tabs-menu li.current{
|
126 |
-
border: 1px solid #ddd;
|
127 |
-
background: #fff;
|
128 |
-
border-bottom: 1px solid transparent;
|
129 |
-
}
|
130 |
-
|
131 |
-
#tabs-container .tabs-menu li a{
|
132 |
-
text-decoration: none;
|
133 |
-
color: #444;
|
134 |
-
display: block;
|
135 |
-
padding: 10px 10px 10px;
|
136 |
-
font-size: 18px;
|
137 |
-
}
|
138 |
-
|
139 |
-
#tabs-container .tabs-menu li a:focus{
|
140 |
-
box-shadow: none;
|
141 |
-
}
|
142 |
-
|
143 |
-
#tabs-container .tab-content{
|
144 |
-
background: #fff;
|
145 |
-
padding: 10px .9em;
|
146 |
-
display: none;
|
147 |
-
border: 1px solid #ddd;
|
148 |
-
margin-top: -1px;
|
149 |
-
}
|
150 |
-
#Demo_Import li {
|
151 |
-
line-height: 35px;
|
152 |
-
}
|
153 |
-
div#Demo_Import {
|
154 |
-
font-size: 15px;
|
155 |
-
}
|
156 |
-
.home-page-url{
|
157 |
-
display: none;
|
158 |
-
}
|
159 |
-
|
160 |
-
.rddi-import-intro p,
|
161 |
-
.rddi-import-intro{
|
162 |
-
font-size: 19px;
|
163 |
-
line-height: 25px;
|
164 |
-
}
|
165 |
-
|
166 |
-
.rddi-import-intro ul{
|
167 |
-
list-style: square;
|
168 |
-
padding-left: 26px;
|
169 |
-
}
|
170 |
-
.rddi-import-intro ul li span{
|
171 |
-
font-weight: 800;
|
172 |
}
|
1 |
+
/* Overriding WordPress native styles */
|
2 |
+
|
3 |
+
.rrdi h2 {
|
4 |
+
text-align: inherit;
|
5 |
+
}
|
6 |
+
|
7 |
+
.rrdi h2:first-child,
|
8 |
+
.rrdi h3:first-child {
|
9 |
+
margin-top: 0;
|
10 |
+
}
|
11 |
+
|
12 |
+
.rrdi hr {
|
13 |
+
margin: 2.62em 0;
|
14 |
+
}
|
15 |
+
|
16 |
+
.feature-section + hr {
|
17 |
+
margin-top: 0;
|
18 |
+
}
|
19 |
+
|
20 |
+
#wpbody select {
|
21 |
+
height: auto;
|
22 |
+
padding: .62em;
|
23 |
+
line-height: inherit;
|
24 |
+
}
|
25 |
+
|
26 |
+
.rrdi .notice {
|
27 |
+
display: block !important;
|
28 |
+
margin-top: 1.4em;
|
29 |
+
margin-bottom: 0;
|
30 |
+
}
|
31 |
+
|
32 |
+
/* Plugin elements */
|
33 |
+
|
34 |
+
.RRDI__demo-import-files {
|
35 |
+
width: 100%;
|
36 |
+
}
|
37 |
+
|
38 |
+
.RRDI__demo-import-preview-image-message {
|
39 |
+
font-style: italic;
|
40 |
+
}
|
41 |
+
|
42 |
+
/* Plugin title */
|
43 |
+
|
44 |
+
.RRDI__title:before {
|
45 |
+
width: auto;
|
46 |
+
height: auto;
|
47 |
+
font-size: inherit;
|
48 |
+
}
|
49 |
+
|
50 |
+
/* Plugin intro text */
|
51 |
+
|
52 |
+
.RRDI__intro-text ul {
|
53 |
+
padding: 0 4%;
|
54 |
+
list-style-type: square;
|
55 |
+
}
|
56 |
+
|
57 |
+
/* Plugin multi select import and Plugin file upload containers */
|
58 |
+
|
59 |
+
.RRDI__file-upload,
|
60 |
+
.RRDI__multi-select-import,
|
61 |
+
.RRDI__demo-import-notice:not(:empty) {
|
62 |
+
padding: 4%;
|
63 |
+
margin: 1.62em 0;
|
64 |
+
background-color: #ffffff;
|
65 |
+
border: 1px solid #e5e5e5;
|
66 |
+
}
|
67 |
+
|
68 |
+
.RRDI__file-upload {
|
69 |
+
margin: 0;
|
70 |
+
margin-bottom: -1px;
|
71 |
+
}
|
72 |
+
|
73 |
+
.RRDI__file-upload span {
|
74 |
+
font-size: .81em;
|
75 |
+
font-weight: normal;
|
76 |
+
opacity: .66;
|
77 |
+
}
|
78 |
+
|
79 |
+
.RRDI__demo-import-notice:not(:empty) {
|
80 |
+
border: 0;
|
81 |
+
border-left: 4px solid #00a0d2;
|
82 |
+
-webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
|
83 |
+
box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
|
84 |
+
}
|
85 |
+
|
86 |
+
[dir="rtl"] .RRDI__demo-import-notice:not(:empty) {
|
87 |
+
border: 0;
|
88 |
+
border-right: 4px solid #00a0d2;
|
89 |
+
}
|
90 |
+
|
91 |
+
/* Plugin button */
|
92 |
+
|
93 |
+
.RRDI__button-container {
|
94 |
+
margin-top: 1.62em;
|
95 |
+
}
|
96 |
+
|
97 |
+
/* AJAX loader */
|
98 |
+
|
99 |
+
.RRDI__ajax-loader {
|
100 |
+
font-size: 1.5em;
|
101 |
+
display: none;
|
102 |
+
}
|
103 |
+
|
104 |
+
.RRDI__ajax-loader .spinner {
|
105 |
+
display: inline-block;
|
106 |
+
float: none;
|
107 |
+
visibility: visible;
|
108 |
+
margin-bottom: 6px;
|
109 |
+
}
|
110 |
+
|
111 |
+
#tabs-container .tabs-menu{
|
112 |
+
margin: 0;
|
113 |
+
padding: 0;
|
114 |
+
list-style: none;
|
115 |
+
overflow: hidden;
|
116 |
+
text-transform: capitalize;
|
117 |
+
}
|
118 |
+
|
119 |
+
#tabs-container .tabs-menu li{
|
120 |
+
float: left;
|
121 |
+
border: 1px solid transparent;
|
122 |
+
margin: 0;
|
123 |
+
}
|
124 |
+
|
125 |
+
#tabs-container .tabs-menu li.current{
|
126 |
+
border: 1px solid #ddd;
|
127 |
+
background: #fff;
|
128 |
+
border-bottom: 1px solid transparent;
|
129 |
+
}
|
130 |
+
|
131 |
+
#tabs-container .tabs-menu li a{
|
132 |
+
text-decoration: none;
|
133 |
+
color: #444;
|
134 |
+
display: block;
|
135 |
+
padding: 10px 10px 10px;
|
136 |
+
font-size: 18px;
|
137 |
+
}
|
138 |
+
|
139 |
+
#tabs-container .tabs-menu li a:focus{
|
140 |
+
box-shadow: none;
|
141 |
+
}
|
142 |
+
|
143 |
+
#tabs-container .tab-content{
|
144 |
+
background: #fff;
|
145 |
+
padding: 10px .9em;
|
146 |
+
display: none;
|
147 |
+
border: 1px solid #ddd;
|
148 |
+
margin-top: -1px;
|
149 |
+
}
|
150 |
+
#Demo_Import li {
|
151 |
+
line-height: 35px;
|
152 |
+
}
|
153 |
+
div#Demo_Import {
|
154 |
+
font-size: 15px;
|
155 |
+
}
|
156 |
+
.home-page-url{
|
157 |
+
display: none;
|
158 |
+
}
|
159 |
+
|
160 |
+
.rddi-import-intro p,
|
161 |
+
.rddi-import-intro{
|
162 |
+
font-size: 19px;
|
163 |
+
line-height: 25px;
|
164 |
+
}
|
165 |
+
|
166 |
+
.rddi-import-intro ul{
|
167 |
+
list-style: square;
|
168 |
+
padding-left: 26px;
|
169 |
+
}
|
170 |
+
.rddi-import-intro ul li span{
|
171 |
+
font-weight: 800;
|
172 |
}
|
assets/js/script.js
CHANGED
@@ -1,120 +1,120 @@
|
|
1 |
-
jQuery( function ( $ ) {
|
2 |
-
|
3 |
-
$( '.js-rrdi-import-data' ).on( 'click', function () {
|
4 |
-
// Reset response div content.
|
5 |
-
$( '.js-rrdi-ajax-response' ).empty();
|
6 |
-
|
7 |
-
// Prepare data for the AJAX call
|
8 |
-
var data = new FormData();
|
9 |
-
data.append( 'action', 'rrdi_import_demo_data' );
|
10 |
-
data.append( 'security', rrdi.ajax_nonce );
|
11 |
-
data.append( 'selected', $( '#RRDI__demo-import-files' ).val() );
|
12 |
-
if ( $('#RRDI__content-file-upload').length ) {
|
13 |
-
data.append( 'content_file', $('#RRDI__content-file-upload')[0].files[0] );
|
14 |
-
}
|
15 |
-
if ( $('#RRDI__widget-file-upload').length ) {
|
16 |
-
data.append( 'widget_file', $('#RRDI__widget-file-upload')[0].files[0] );
|
17 |
-
}
|
18 |
-
if ( $('#RRDI__customizer-file-upload').length ) {
|
19 |
-
data.append( 'customizer_file', $('#RRDI__customizer-file-upload')[0].files[0] );
|
20 |
-
}
|
21 |
-
|
22 |
-
// AJAX call to import everything (content, widgets, before/after setup)
|
23 |
-
ajaxCall( data );
|
24 |
-
|
25 |
-
});
|
26 |
-
|
27 |
-
function ajaxCall( data ) {
|
28 |
-
$.ajax({
|
29 |
-
method: 'POST',
|
30 |
-
url: rrdi.ajax_url,
|
31 |
-
data: data,
|
32 |
-
contentType: false,
|
33 |
-
processData: false,
|
34 |
-
beforeSend: function() {
|
35 |
-
$( '.js-rrdi-ajax-loader' ).show();
|
36 |
-
}
|
37 |
-
})
|
38 |
-
.done( function( response ) {
|
39 |
-
|
40 |
-
if ( 'undefined' !== typeof response.status && 'newAJAX' === response.status ) {
|
41 |
-
ajaxCall( data );
|
42 |
-
}
|
43 |
-
else if ( 'undefined' !== typeof response.message ) {
|
44 |
-
$( '.js-rrdi-ajax-response' ).append( '<p>' + response.message + '</p>' );
|
45 |
-
$( '.js-rrdi-ajax-loader' ).hide();
|
46 |
-
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
47 |
-
$( 'a.demo-importer' ).hide();
|
48 |
-
$( 'a.home-page-url' ).show();
|
49 |
-
|
50 |
-
}
|
51 |
-
else {
|
52 |
-
$( '.js-rrdi-ajax-response' ).append( '<div class="notice notice-error is-dismissible"><p>' + response + '</p></div>' );
|
53 |
-
$( '.js-rrdi-ajax-loader' ).hide();
|
54 |
-
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
55 |
-
$( 'a.demo-importer' ).hide();
|
56 |
-
$( 'a.home-page-url' ).show();
|
57 |
-
}
|
58 |
-
})
|
59 |
-
.fail( function( error ) {
|
60 |
-
$( '.js-rrdi-ajax-response' ).append( '<div class="notice notice-error is-dismissible"><p>Error: ' + error.statusText + ' (' + error.status + ')' + '</p></div>' );
|
61 |
-
$( '.js-rrdi-ajax-loader' ).hide();
|
62 |
-
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
63 |
-
});
|
64 |
-
}
|
65 |
-
|
66 |
-
// Switch preview images on select change event, but only if the img element .js-rrdi-preview-image exists.
|
67 |
-
// Also switch the import notice (if it exists).
|
68 |
-
$( '#RRDI__demo-import-files' ).on( 'change', function(){
|
69 |
-
if ( $( '.js-rrdi-preview-image' ).length ) {
|
70 |
-
|
71 |
-
// Attempt to change the image, else display message for missing image.
|
72 |
-
var currentFilePreviewImage = rrdi.import_files[ this.value ]['import_preview_image_url'] || '';
|
73 |
-
$( '.js-rrdi-preview-image' ).prop( 'src', currentFilePreviewImage );
|
74 |
-
$( '.js-rrdi-preview-image-message' ).html( '' );
|
75 |
-
|
76 |
-
if ( '' === currentFilePreviewImage ) {
|
77 |
-
$( '.js-rrdi-preview-image-message' ).html( rrdi.texts.missing_preview_image );
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
// Update import notice.
|
82 |
-
var currentImportNotice = rrdi.import_files[ this.value ]['import_notice'] || '';
|
83 |
-
$( '.js-rrdi-demo-import-notice' ).html( currentImportNotice );
|
84 |
-
});
|
85 |
-
|
86 |
-
$('.tabs-menu a').click(function(event) {
|
87 |
-
event.preventDefault();
|
88 |
-
$(this).parent().addClass('current');
|
89 |
-
$(this).parent().siblings().removeClass('current');
|
90 |
-
var tab = $(this).attr('href');
|
91 |
-
$('.tab-content').not(tab).css('display', 'none');
|
92 |
-
$('#'+tab).show();
|
93 |
-
});
|
94 |
-
|
95 |
-
var uploadViewToggle = $( '.upload-view-toggle' ),
|
96 |
-
$body = $( document.body );
|
97 |
-
uploadViewToggle.on( 'click', function() {
|
98 |
-
// Toggle the upload view.
|
99 |
-
$body.toggleClass( 'show-upload-view' );
|
100 |
-
// Toggle the `aria-expanded` button attribute.
|
101 |
-
uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
|
102 |
-
});
|
103 |
-
if( $('.tabs-menu a').attr('href') != 'Demo_Import')
|
104 |
-
{
|
105 |
-
$('.upload-view-toggle').hide();
|
106 |
-
}
|
107 |
-
else{
|
108 |
-
$('.upload-view-toggle').show();
|
109 |
-
}
|
110 |
-
$('.tabs-menu a').click(function(event) {
|
111 |
-
if( $(this).attr('href') != 'Demo_Import')
|
112 |
-
{
|
113 |
-
$('.upload-view-toggle').hide();
|
114 |
-
}
|
115 |
-
else{
|
116 |
-
$('.upload-view-toggle').show();
|
117 |
-
}
|
118 |
-
});
|
119 |
-
|
120 |
-
});
|
1 |
+
jQuery( function ( $ ) {
|
2 |
+
|
3 |
+
$( '.js-rrdi-import-data' ).on( 'click', function () {
|
4 |
+
// Reset response div content.
|
5 |
+
$( '.js-rrdi-ajax-response' ).empty();
|
6 |
+
|
7 |
+
// Prepare data for the AJAX call
|
8 |
+
var data = new FormData();
|
9 |
+
data.append( 'action', 'rrdi_import_demo_data' );
|
10 |
+
data.append( 'security', rrdi.ajax_nonce );
|
11 |
+
data.append( 'selected', $( '#RRDI__demo-import-files' ).val() );
|
12 |
+
if ( $('#RRDI__content-file-upload').length ) {
|
13 |
+
data.append( 'content_file', $('#RRDI__content-file-upload')[0].files[0] );
|
14 |
+
}
|
15 |
+
if ( $('#RRDI__widget-file-upload').length ) {
|
16 |
+
data.append( 'widget_file', $('#RRDI__widget-file-upload')[0].files[0] );
|
17 |
+
}
|
18 |
+
if ( $('#RRDI__customizer-file-upload').length ) {
|
19 |
+
data.append( 'customizer_file', $('#RRDI__customizer-file-upload')[0].files[0] );
|
20 |
+
}
|
21 |
+
|
22 |
+
// AJAX call to import everything (content, widgets, before/after setup)
|
23 |
+
ajaxCall( data );
|
24 |
+
|
25 |
+
});
|
26 |
+
|
27 |
+
function ajaxCall( data ) {
|
28 |
+
$.ajax({
|
29 |
+
method: 'POST',
|
30 |
+
url: rrdi.ajax_url,
|
31 |
+
data: data,
|
32 |
+
contentType: false,
|
33 |
+
processData: false,
|
34 |
+
beforeSend: function() {
|
35 |
+
$( '.js-rrdi-ajax-loader' ).show();
|
36 |
+
}
|
37 |
+
})
|
38 |
+
.done( function( response ) {
|
39 |
+
|
40 |
+
if ( 'undefined' !== typeof response.status && 'newAJAX' === response.status ) {
|
41 |
+
ajaxCall( data );
|
42 |
+
}
|
43 |
+
else if ( 'undefined' !== typeof response.message ) {
|
44 |
+
$( '.js-rrdi-ajax-response' ).append( '<p>' + response.message + '</p>' );
|
45 |
+
$( '.js-rrdi-ajax-loader' ).hide();
|
46 |
+
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
47 |
+
$( 'a.demo-importer' ).hide();
|
48 |
+
$( 'a.home-page-url' ).show();
|
49 |
+
|
50 |
+
}
|
51 |
+
else {
|
52 |
+
$( '.js-rrdi-ajax-response' ).append( '<div class="notice notice-error is-dismissible"><p>' + response + '</p></div>' );
|
53 |
+
$( '.js-rrdi-ajax-loader' ).hide();
|
54 |
+
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
55 |
+
$( 'a.demo-importer' ).hide();
|
56 |
+
$( 'a.home-page-url' ).show();
|
57 |
+
}
|
58 |
+
})
|
59 |
+
.fail( function( error ) {
|
60 |
+
$( '.js-rrdi-ajax-response' ).append( '<div class="notice notice-error is-dismissible"><p>Error: ' + error.statusText + ' (' + error.status + ')' + '</p></div>' );
|
61 |
+
$( '.js-rrdi-ajax-loader' ).hide();
|
62 |
+
$( '.js-rrdi-import-data' ).prop('disabled', true);
|
63 |
+
});
|
64 |
+
}
|
65 |
+
|
66 |
+
// Switch preview images on select change event, but only if the img element .js-rrdi-preview-image exists.
|
67 |
+
// Also switch the import notice (if it exists).
|
68 |
+
$( '#RRDI__demo-import-files' ).on( 'change', function(){
|
69 |
+
if ( $( '.js-rrdi-preview-image' ).length ) {
|
70 |
+
|
71 |
+
// Attempt to change the image, else display message for missing image.
|
72 |
+
var currentFilePreviewImage = rrdi.import_files[ this.value ]['import_preview_image_url'] || '';
|
73 |
+
$( '.js-rrdi-preview-image' ).prop( 'src', currentFilePreviewImage );
|
74 |
+
$( '.js-rrdi-preview-image-message' ).html( '' );
|
75 |
+
|
76 |
+
if ( '' === currentFilePreviewImage ) {
|
77 |
+
$( '.js-rrdi-preview-image-message' ).html( rrdi.texts.missing_preview_image );
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
// Update import notice.
|
82 |
+
var currentImportNotice = rrdi.import_files[ this.value ]['import_notice'] || '';
|
83 |
+
$( '.js-rrdi-demo-import-notice' ).html( currentImportNotice );
|
84 |
+
});
|
85 |
+
|
86 |
+
$('.tabs-menu a').click(function(event) {
|
87 |
+
event.preventDefault();
|
88 |
+
$(this).parent().addClass('current');
|
89 |
+
$(this).parent().siblings().removeClass('current');
|
90 |
+
var tab = $(this).attr('href');
|
91 |
+
$('.tab-content').not(tab).css('display', 'none');
|
92 |
+
$('#'+tab).show();
|
93 |
+
});
|
94 |
+
|
95 |
+
var uploadViewToggle = $( '.upload-view-toggle' ),
|
96 |
+
$body = $( document.body );
|
97 |
+
uploadViewToggle.on( 'click', function() {
|
98 |
+
// Toggle the upload view.
|
99 |
+
$body.toggleClass( 'show-upload-view' );
|
100 |
+
// Toggle the `aria-expanded` button attribute.
|
101 |
+
uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
|
102 |
+
});
|
103 |
+
if( $('.tabs-menu a').attr('href') != 'Demo_Import')
|
104 |
+
{
|
105 |
+
$('.upload-view-toggle').hide();
|
106 |
+
}
|
107 |
+
else{
|
108 |
+
$('.upload-view-toggle').show();
|
109 |
+
}
|
110 |
+
$('.tabs-menu a').click(function(event) {
|
111 |
+
if( $(this).attr('href') != 'Demo_Import')
|
112 |
+
{
|
113 |
+
$('.upload-view-toggle').hide();
|
114 |
+
}
|
115 |
+
else{
|
116 |
+
$('.upload-view-toggle').show();
|
117 |
+
}
|
118 |
+
});
|
119 |
+
|
120 |
+
});
|
includes/class-rrdi-customizer-option.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* A class that extends WP_Customize_Setting so we can access
|
4 |
-
* the protected updated method when importing options.
|
5 |
-
*
|
6 |
-
* Used in the Customizer importer.
|
7 |
-
*
|
8 |
-
* @since 1.0.1
|
9 |
-
* @package rara-one-click-demo-import
|
10 |
-
*/
|
11 |
-
|
12 |
-
final class RRDI_Customizer_Option extends WP_Customize_Setting {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Import an option value for this setting.
|
16 |
-
*
|
17 |
-
* @since 1.0.1
|
18 |
-
* @param mixed $value The option value.
|
19 |
-
* @return void
|
20 |
-
*/
|
21 |
-
public function import( $value ) {
|
22 |
-
$this->update( $value );
|
23 |
-
}
|
24 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* A class that extends WP_Customize_Setting so we can access
|
4 |
+
* the protected updated method when importing options.
|
5 |
+
*
|
6 |
+
* Used in the Customizer importer.
|
7 |
+
*
|
8 |
+
* @since 1.0.1
|
9 |
+
* @package rara-one-click-demo-import
|
10 |
+
*/
|
11 |
+
|
12 |
+
final class RRDI_Customizer_Option extends WP_Customize_Setting {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Import an option value for this setting.
|
16 |
+
*
|
17 |
+
* @since 1.0.1
|
18 |
+
* @param mixed $value The option value.
|
19 |
+
* @return void
|
20 |
+
*/
|
21 |
+
public function import( $value ) {
|
22 |
+
$this->update( $value );
|
23 |
+
}
|
24 |
+
}
|
includes/class-rrdi-helpers.php
CHANGED
@@ -1,610 +1,610 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Static functions used in the rrdi plugin.
|
4 |
-
*
|
5 |
-
* @package rara-one-click-demo-import
|
6 |
-
*/
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Class with static helper functions.
|
10 |
-
*/
|
11 |
-
class RRDI_Helpers {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Filter through the array of import files and get rid of those who do not comply.
|
15 |
-
*
|
16 |
-
* @param array $import_files list of arrays with import file details.
|
17 |
-
* @return array list of filtered arrays.
|
18 |
-
*/
|
19 |
-
public static function validate_import_file_info( $import_files ) {
|
20 |
-
$filtered_import_file_info = array();
|
21 |
-
|
22 |
-
foreach ( $import_files as $import_file ) {
|
23 |
-
if ( self::is_import_file_info_format_correct( $import_file ) ) {
|
24 |
-
$filtered_import_file_info[] = $import_file;
|
25 |
-
}
|
26 |
-
}
|
27 |
-
|
28 |
-
return $filtered_import_file_info;
|
29 |
-
}
|
30 |
-
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Helper function: a simple check for valid import file format.
|
34 |
-
*
|
35 |
-
* @param array $import_file_info array with import file details.
|
36 |
-
* @return boolean
|
37 |
-
*/
|
38 |
-
private static function is_import_file_info_format_correct( $import_file_info ) {
|
39 |
-
if ( ( empty( $import_file_info['import_file_url'] ) && empty( $import_file_info['local_import_file'] ) ) || empty( $import_file_info['import_file_name'] ) ) {
|
40 |
-
return false;
|
41 |
-
}
|
42 |
-
|
43 |
-
return true;
|
44 |
-
}
|
45 |
-
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Download import files. Content .xml and widgets .wie|.json files.
|
49 |
-
*
|
50 |
-
* @param array $import_file_info array with import file details.
|
51 |
-
* @param string $start_date string of date and time.
|
52 |
-
* @return array|WP_Error array of paths to the downloaded files or WP_Error object with error message.
|
53 |
-
*/
|
54 |
-
public static function download_import_files( $import_file_info, $start_date = '' ) {
|
55 |
-
|
56 |
-
$downloaded_files = array();
|
57 |
-
$upload_dir = wp_upload_dir();
|
58 |
-
$upload_path = apply_filters( 'rrdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );
|
59 |
-
|
60 |
-
// ----- Set content file path -----
|
61 |
-
// Check if 'import_file_url' is not defined. That would mean a local file.
|
62 |
-
if ( empty( $import_file_info['import_file_url'] ) ) {
|
63 |
-
if ( file_exists( $import_file_info['local_import_file'] ) ) {
|
64 |
-
$downloaded_files['content'] = $import_file_info['local_import_file'];
|
65 |
-
}
|
66 |
-
else {
|
67 |
-
return new WP_Error(
|
68 |
-
'url_or_local_file_not_defined',
|
69 |
-
sprintf(
|
70 |
-
__( '"import_file_url" or "local_import_file" for %s%s%s are not defined!', 'rara-one-click-demo-import' ),
|
71 |
-
'<strong>',
|
72 |
-
$$import_file_info['import_file_name'],
|
73 |
-
'</strong>'
|
74 |
-
)
|
75 |
-
);
|
76 |
-
}
|
77 |
-
}
|
78 |
-
else {
|
79 |
-
|
80 |
-
// Retrieve demo data content from the URL.
|
81 |
-
$demo_import_content = self::get_content_from_url( $import_file_info['import_file_url'], $import_file_info['import_file_name'] );
|
82 |
-
|
83 |
-
// Return from this function if there was an error.
|
84 |
-
if ( is_wp_error( $demo_import_content ) ) {
|
85 |
-
return $demo_import_content;
|
86 |
-
}
|
87 |
-
|
88 |
-
// Setup filename path to save the data content.
|
89 |
-
$demo_import_file_path = $upload_path . apply_filters( 'rrdi/downloaded_content_file_prefix', 'demo-content-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_content_file_suffix_and_file_extension', '.xml' );
|
90 |
-
|
91 |
-
// Write data content to the file and return the file path on successful write.
|
92 |
-
$downloaded_files['content'] = self::write_to_file( $demo_import_content, $demo_import_file_path );
|
93 |
-
|
94 |
-
// Return from this function if there was an error.
|
95 |
-
if ( is_wp_error( $downloaded_files['content'] ) ) {
|
96 |
-
return $downloaded_files['content'];
|
97 |
-
}
|
98 |
-
}
|
99 |
-
|
100 |
-
// ----- Set widget file path -----
|
101 |
-
// Get widgets file as well. If defined!
|
102 |
-
if ( ! empty( $import_file_info['import_widget_file_url'] ) ) {
|
103 |
-
|
104 |
-
// Retrieve widget content from the URL.
|
105 |
-
$demo_import_widgets_content = self::get_content_from_url( $import_file_info['import_widget_file_url'], $import_file_info['import_file_name'] );
|
106 |
-
|
107 |
-
// Return from this function if there was an error.
|
108 |
-
if ( is_wp_error( $demo_import_widgets_content ) ) {
|
109 |
-
return $demo_import_widgets_content;
|
110 |
-
}
|
111 |
-
|
112 |
-
// Setup filename path to save the widget content.
|
113 |
-
$import_widgets_file_path = $upload_path . apply_filters( 'rrdi/downloaded_widgets_file_prefix', 'demo-widgets-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_widgets_file_suffix_and_file_extension', '.json' );
|
114 |
-
|
115 |
-
// Write widget content to the file and return the file path on successful write.
|
116 |
-
$downloaded_files['widgets'] = self::write_to_file( $demo_import_widgets_content, $import_widgets_file_path );
|
117 |
-
|
118 |
-
// Return from this function if there was an error.
|
119 |
-
if ( is_wp_error( $downloaded_files['widgets'] ) ) {
|
120 |
-
return $downloaded_files['widgets'];
|
121 |
-
}
|
122 |
-
}
|
123 |
-
else if ( ! empty( $import_file_info['local_import_widget_file'] ) ) {
|
124 |
-
if ( file_exists( $import_file_info['local_import_widget_file'] ) ) {
|
125 |
-
$downloaded_files['widgets'] = $import_file_info['local_import_widget_file'];
|
126 |
-
}
|
127 |
-
}
|
128 |
-
|
129 |
-
// ----- Set customizer file path -----
|
130 |
-
// Get customizer import file as well. If defined!
|
131 |
-
if ( ! empty( $import_file_info['import_customizer_file_url'] ) ) {
|
132 |
-
|
133 |
-
// Retrieve customizer content from the URL.
|
134 |
-
$demo_import_customizer_content = self::get_content_from_url( $import_file_info['import_customizer_file_url'], $import_file_info['import_file_name'] );
|
135 |
-
|
136 |
-
// Return from this function if there was an error.
|
137 |
-
if ( is_wp_error( $demo_import_customizer_content ) ) {
|
138 |
-
return $demo_import_customizer_content;
|
139 |
-
}
|
140 |
-
|
141 |
-
// Setup filename path to save the customizer content.
|
142 |
-
$import_customizer_file_path = $upload_path . apply_filters( 'rrdi/downloaded_customizer_file_prefix', 'demo-customizer-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_customizer_file_suffix_and_file_extension', '.dat' );
|
143 |
-
|
144 |
-
// Write customizer content to the file and return the file path on successful write.
|
145 |
-
$downloaded_files['customizer'] = self::write_to_file( $demo_import_customizer_content, $import_customizer_file_path );
|
146 |
-
|
147 |
-
// Return from this function if there was an error.
|
148 |
-
if ( is_wp_error( $downloaded_files['customizer'] ) ) {
|
149 |
-
return $downloaded_files['customizer'];
|
150 |
-
}
|
151 |
-
}
|
152 |
-
else if ( ! empty( $import_file_info['local_import_customizer_file'] ) ) {
|
153 |
-
if ( file_exists( $import_file_info['local_import_customizer_file'] ) ) {
|
154 |
-
$downloaded_files['customizer'] = $import_file_info['local_import_customizer_file'];
|
155 |
-
}
|
156 |
-
}
|
157 |
-
|
158 |
-
return $downloaded_files;
|
159 |
-
}
|
160 |
-
|
161 |
-
|
162 |
-
/**
|
163 |
-
* Helper function: get content from an url.
|
164 |
-
*
|
165 |
-
* @param string $url URL to the content file.
|
166 |
-
* @param string $file_name optional, name of the file (used in the error reports).
|
167 |
-
* @return string|WP_Error, content from the URL or WP_Error object with error message
|
168 |
-
*/
|
169 |
-
private static function get_content_from_url( $url, $file_name = 'Import file' ) {
|
170 |
-
|
171 |
-
// Test if the URL to the file is defined.
|
172 |
-
if ( empty( $url ) ) {
|
173 |
-
return new WP_Error(
|
174 |
-
'url_not_defined',
|
175 |
-
sprintf(
|
176 |
-
__( 'URL for %s%s%s file is not defined!', 'rara-one-click-demo-import' ),
|
177 |
-
'<strong>',
|
178 |
-
$file_name,
|
179 |
-
'</strong>'
|
180 |
-
)
|
181 |
-
);
|
182 |
-
}
|
183 |
-
|
184 |
-
// Get file content from the server.
|
185 |
-
$response = wp_remote_get(
|
186 |
-
$url,
|
187 |
-
array( 'timeout' => apply_filters( 'rrdi/timeout_for_downloading_import_file', 20 ) )
|
188 |
-
);
|
189 |
-
|
190 |
-
if ( is_wp_error( $response ) || 200 !== $response['response']['code'] ) {
|
191 |
-
|
192 |
-
// Collect the right format of error data (array or WP_Error).
|
193 |
-
$response_error = self::get_error_from_response( $response );
|
194 |
-
|
195 |
-
return new WP_Error(
|
196 |
-
'file_fetching_error',
|
197 |
-
sprintf(
|
198 |
-
__( 'An error occurred while fetching %s%s%s file from the server!%sReason: %s - %s.', 'rara-one-click-demo-import' ),
|
199 |
-
'<strong>',
|
200 |
-
$file_name,
|
201 |
-
'</strong>',
|
202 |
-
'<br>',
|
203 |
-
$response_error['error_code'],
|
204 |
-
$response_error['error_message']
|
205 |
-
) . '<br>' .
|
206 |
-
apply_filters( 'rrdi/message_after_file_fetching_error', '' )
|
207 |
-
);
|
208 |
-
}
|
209 |
-
|
210 |
-
// Return content retrieved from the URL.
|
211 |
-
return wp_remote_retrieve_body( $response );
|
212 |
-
}
|
213 |
-
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Write content to a file.
|
217 |
-
*
|
218 |
-
* @param string $content content to be saved to the file.
|
219 |
-
* @param string $file_path file path where the content should be saved.
|
220 |
-
* @return string|WP_Error path to the saved file or WP_Error object with error message.
|
221 |
-
*/
|
222 |
-
public static function write_to_file( $content, $file_path ) {
|
223 |
-
|
224 |
-
// Verify WP file-system credentials.
|
225 |
-
$verified_credentials = self::check_wp_filesystem_credentials();
|
226 |
-
|
227 |
-
if ( is_wp_error( $verified_credentials ) ) {
|
228 |
-
return $verified_credentials;
|
229 |
-
}
|
230 |
-
|
231 |
-
// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
|
232 |
-
global $wp_filesystem;
|
233 |
-
|
234 |
-
if ( ! $wp_filesystem->put_contents( $file_path, $content ) ) {
|
235 |
-
return new WP_Error(
|
236 |
-
'failed_writing_file_to_server',
|
237 |
-
sprintf(
|
238 |
-
__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'rara-one-click-demo-import' ),
|
239 |
-
'<br>',
|
240 |
-
$file_path
|
241 |
-
)
|
242 |
-
);
|
243 |
-
}
|
244 |
-
|
245 |
-
// Return the file path on successful file write.
|
246 |
-
return $file_path;
|
247 |
-
}
|
248 |
-
|
249 |
-
|
250 |
-
/**
|
251 |
-
* Append content to the file.
|
252 |
-
*
|
253 |
-
* @param string $content content to be saved to the file.
|
254 |
-
* @param string $file_path file path where the content should be saved.
|
255 |
-
* @param string $separator_text separates the existing content of the file with the new content.
|
256 |
-
* @return boolean|WP_Error, path to the saved file or WP_Error object with error message.
|
257 |
-
*/
|
258 |
-
public static function append_to_file( $content, $file_path, $separator_text = '' ) {
|
259 |
-
|
260 |
-
// Verify WP file-system credentials.
|
261 |
-
$verified_credentials = self::check_wp_filesystem_credentials();
|
262 |
-
|
263 |
-
if ( is_wp_error( $verified_credentials ) ) {
|
264 |
-
return $verified_credentials;
|
265 |
-
}
|
266 |
-
|
267 |
-
// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
|
268 |
-
global $wp_filesystem;
|
269 |
-
|
270 |
-
$existing_data = '';
|
271 |
-
if ( file_exists( $file_path ) ) {
|
272 |
-
$existing_data = $wp_filesystem->get_contents( $file_path );
|
273 |
-
}
|
274 |
-
|
275 |
-
// Style separator.
|
276 |
-
$separator = PHP_EOL . '---' . $separator_text . '---' . PHP_EOL;
|
277 |
-
|
278 |
-
if ( ! $wp_filesystem->put_contents( $file_path, $existing_data . $separator . $content . PHP_EOL ) ) {
|
279 |
-
return new WP_Error(
|
280 |
-
'failed_writing_file_to_server',
|
281 |
-
sprintf(
|
282 |
-
__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'rara-one-click-demo-import' ),
|
283 |
-
'<br>',
|
284 |
-
$file_path
|
285 |
-
)
|
286 |
-
);
|
287 |
-
}
|
288 |
-
|
289 |
-
return true;
|
290 |
-
}
|
291 |
-
|
292 |
-
|
293 |
-
/**
|
294 |
-
* Get data from a file
|
295 |
-
*
|
296 |
-
* @param string $file_path file path where the content should be saved.
|
297 |
-
* @return string $data, content of the file or WP_Error object with error message.
|
298 |
-
*/
|
299 |
-
public static function data_from_file( $file_path ) {
|
300 |
-
|
301 |
-
// Verify WP file-system credentials.
|
302 |
-
$verified_credentials = self::check_wp_filesystem_credentials();
|
303 |
-
|
304 |
-
if ( is_wp_error( $verified_credentials ) ) {
|
305 |
-
return $verified_credentials;
|
306 |
-
}
|
307 |
-
|
308 |
-
// By this point, the $wp_filesystem global should be working, so let's use it to read a file.
|
309 |
-
global $wp_filesystem;
|
310 |
-
|
311 |
-
$data = $wp_filesystem->get_contents( $file_path );
|
312 |
-
|
313 |
-
if ( ! $data ) {
|
314 |
-
return new WP_Error(
|
315 |
-
'failed_reading_file_from_server',
|
316 |
-
sprintf(
|
317 |
-
__( 'An error occurred while reading a file from your server! Tried reading file from path: %s%s.', 'rara-one-click-demo-import' ),
|
318 |
-
'<br>',
|
319 |
-
$file_path
|
320 |
-
)
|
321 |
-
);
|
322 |
-
}
|
323 |
-
|
324 |
-
// Return the file data.
|
325 |
-
return $data;
|
326 |
-
}
|
327 |
-
|
328 |
-
|
329 |
-
/**
|
330 |
-
* Helper function: check for WP file-system credentials needed for reading and writing to a file.
|
331 |
-
*
|
332 |
-
* @return boolean|WP_Error
|
333 |
-
*/
|
334 |
-
private static function check_wp_filesystem_credentials() {
|
335 |
-
|
336 |
-
// Check if the file-system method is 'direct', if not display an error.
|
337 |
-
if ( ! ( 'direct' === get_filesystem_method() ) ) {
|
338 |
-
return new WP_Error(
|
339 |
-
'no_direct_file_access',
|
340 |
-
sprintf(
|
341 |
-
__( 'This WordPress page does not have %sdirect%s write file access. This plugin needs it in order to save the demo import xml file to the upload directory of your site. You can change this setting with these instructions: %s.', 'rara-one-click-demo-import' ),
|
342 |
-
'<strong>',
|
343 |
-
'</strong>',
|
344 |
-
'<a href="http://gregorcapuder.com/wordpress-how-to-set-direct-filesystem-method/" target="_blank">How to set <strong>direct</strong> filesystem method</a>'
|
345 |
-
)
|
346 |
-
);
|
347 |
-
}
|
348 |
-
|
349 |
-
// Get plugin page settings.
|
350 |
-
$plugin_page_setup = apply_filters( 'rrdi/plugin_page_setup', array(
|
351 |
-
'parent_slug' => 'themes.php',
|
352 |
-
'page_title' => esc_html__( 'Rara One Click Demo Import' , 'rara-one-click-demo-import' ),
|
353 |
-
'menu_title' => esc_html__( 'Rara Demo Import' , 'rara-one-click-demo-import' ),
|
354 |
-
'capability' => 'import',
|
355 |
-
'menu_slug' => 'rara-demo-import',
|
356 |
-
)
|
357 |
-
);
|
358 |
-
|
359 |
-
// Get user credentials for WP file-system API.
|
360 |
-
$demo_import_page_url = wp_nonce_url( $plugin_page_setup['parent_slug'] . '?page=' . $plugin_page_setup['menu_slug'], $plugin_page_setup['menu_slug'] );
|
361 |
-
|
362 |
-
if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) {
|
363 |
-
return new WP_error(
|
364 |
-
'filesystem_credentials_could_not_be_retrieved',
|
365 |
-
__( 'An error occurred while retrieving reading/writing permissions to your server (could not retrieve WP filesystem credentials)!', 'rara-one-click-demo-import' )
|
366 |
-
);
|
367 |
-
}
|
368 |
-
|
369 |
-
// Now we have credentials, try to get the wp_filesystem running.
|
370 |
-
if ( ! WP_Filesystem( $creds ) ) {
|
371 |
-
return new WP_Error(
|
372 |
-
'wrong_login_credentials',
|
373 |
-
__( 'Your WordPress login credentials don\'t allow to use WP_Filesystem!', 'rara-one-click-demo-import' )
|
374 |
-
);
|
375 |
-
}
|
376 |
-
|
377 |
-
return true;
|
378 |
-
}
|
379 |
-
|
380 |
-
|
381 |
-
/**
|
382 |
-
* Helper function: get the right format of response errors
|
383 |
-
*
|
384 |
-
* @param array|WP_Error $response array or WP_Error.
|
385 |
-
* @return array, with error code and error message.
|
386 |
-
*/
|
387 |
-
private static function get_error_from_response( $response ) {
|
388 |
-
$response_error = array();
|
389 |
-
|
390 |
-
if ( is_array( $response ) ) {
|
391 |
-
$response_error['error_code'] = $response['response']['code'];
|
392 |
-
$response_error['error_message'] = $response['response']['message'];
|
393 |
-
}
|
394 |
-
else {
|
395 |
-
$response_error['error_code'] = $response->get_error_code();
|
396 |
-
$response_error['error_message'] = $response->get_error_message();
|
397 |
-
}
|
398 |
-
|
399 |
-
return $response_error;
|
400 |
-
}
|
401 |
-
|
402 |
-
|
403 |
-
/**
|
404 |
-
* Get log file path
|
405 |
-
*
|
406 |
-
* @param string $start_date date|time|timestamp to use in the log filename.
|
407 |
-
* @return string, path to the log file
|
408 |
-
*/
|
409 |
-
public static function get_log_path( $start_date = '' ) {
|
410 |
-
|
411 |
-
$upload_dir = wp_upload_dir();
|
412 |
-
$upload_path = apply_filters( 'rrdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );
|
413 |
-
|
414 |
-
$log_path = $upload_path . apply_filters( 'rrdi/log_file_prefix', 'log_file_' ) . $start_date . apply_filters( 'rrdi/log_file_suffix_and_file_extension', '.txt' );
|
415 |
-
|
416 |
-
self::register_file_as_media_attachment( $log_path );
|
417 |
-
|
418 |
-
return $log_path;
|
419 |
-
}
|
420 |
-
|
421 |
-
|
422 |
-
/**
|
423 |
-
* Register file as attachment to the Media page.
|
424 |
-
*
|
425 |
-
* @param string $log_path log file path.
|
426 |
-
* @return void
|
427 |
-
*/
|
428 |
-
public static function register_file_as_media_attachment( $log_path ) {
|
429 |
-
|
430 |
-
// Check the type of file.
|
431 |
-
$log_mimes = array( 'txt' => 'text/plain' );
|
432 |
-
$filetype = wp_check_filetype( basename( $log_path ), apply_filters( 'rrdi/file_mimes', $log_mimes ) );
|
433 |
-
|
434 |
-
// Prepare an array of post data for the attachment.
|
435 |
-
$attachment = array(
|
436 |
-
'guid' => self::get_log_url( $log_path ),
|
437 |
-
'post_mime_type' => $filetype['type'],
|
438 |
-
'post_title' => apply_filters( 'rrdi/attachment_prefix', esc_html__( 'Rara One Click Demo Import - ', 'rara-one-click-demo-import' ) ) . preg_replace( '/\.[^.]+$/', '', basename( $log_path ) ),
|
439 |
-
'post_content' => '',
|
440 |
-
'post_status' => 'inherit',
|
441 |
-
);
|
442 |
-
|
443 |
-
// Insert the file as attachment in Media page.
|
444 |
-
$attach_id = wp_insert_attachment( $attachment, $log_path );
|
445 |
-
}
|
446 |
-
|
447 |
-
|
448 |
-
/**
|
449 |
-
* Get log file url
|
450 |
-
*
|
451 |
-
* @param string $log_path log path to use for the log filename.
|
452 |
-
* @return string, url to the log file.
|
453 |
-
*/
|
454 |
-
public static function get_log_url( $log_path ) {
|
455 |
-
|
456 |
-
$upload_dir = wp_upload_dir();
|
457 |
-
$upload_url = apply_filters( 'rrdi/upload_file_url', trailingslashit( $upload_dir['url'] ) );
|
458 |
-
|
459 |
-
return $upload_url . basename( $log_path );
|
460 |
-
}
|
461 |
-
|
462 |
-
|
463 |
-
/**
|
464 |
-
* Check if the AJAX call is valid.
|
465 |
-
*/
|
466 |
-
public static function verify_ajax_call() {
|
467 |
-
|
468 |
-
check_ajax_referer( 'rrdi-ajax-verification', 'security' );
|
469 |
-
|
470 |
-
// Check if user has the WP capability to import data.
|
471 |
-
if ( ! current_user_can( 'import' ) ) {
|
472 |
-
wp_die(
|
473 |
-
sprintf(
|
474 |
-
__( '%sYour user role isn\'t high enough. You don\'t have permission to import demo data.%s', 'rara-one-click-demo-import' ),
|
475 |
-
'<div class="notice notice-error"><p>',
|
476 |
-
'</p></div>'
|
477 |
-
)
|
478 |
-
);
|
479 |
-
}
|
480 |
-
}
|
481 |
-
|
482 |
-
|
483 |
-
/**
|
484 |
-
* Process uploaded files and return the paths to these files.
|
485 |
-
*
|
486 |
-
* @param array $uploaded_files $_FILES array form an AJAX request.
|
487 |
-
* @param string $log_file_path path to the log file.
|
488 |
-
* @return array of paths to the content import and widget import files.
|
489 |
-
*/
|
490 |
-
public static function process_uploaded_files( $uploaded_files, $log_file_path ) {
|
491 |
-
|
492 |
-
// Variable holding the paths to the uploaded files.
|
493 |
-
$selected_import_files = array();
|
494 |
-
|
495 |
-
// Upload settings to disable form and type testing for AJAX uploads.
|
496 |
-
$upload_overrides = array(
|
497 |
-
'test_form' => false,
|
498 |
-
'test_type' => false,
|
499 |
-
);
|
500 |
-
|
501 |
-
// Handle demo content and widgets file upload.
|
502 |
-
$content_file_info = wp_handle_upload( $_FILES['content_file'], $upload_overrides );
|
503 |
-
$widget_file_info = wp_handle_upload( $_FILES['widget_file'], $upload_overrides );
|
504 |
-
$customizer_file_info = wp_handle_upload( $_FILES['customizer_file'], $upload_overrides );
|
505 |
-
|
506 |
-
if ( empty( $content_file_info['file'] ) || isset( $content_file_info['error'] ) ) {
|
507 |
-
|
508 |
-
// Write error to log file and send an AJAX response with the error.
|
509 |
-
self::log_error_and_send_ajax_response(
|
510 |
-
__( 'Please upload XML file for content import. If you want to import widgets or customizer settings only, please use Widget Importer & Exporter or the Customizer Export/Import plugin.', 'rara-one-click-demo-import' ),
|
511 |
-
$log_file_path,
|
512 |
-
esc_html__( 'Upload files', 'rara-one-click-demo-import' )
|
513 |
-
);
|
514 |
-
}
|
515 |
-
|
516 |
-
// Set uploaded content file.
|
517 |
-
$selected_import_files['content'] = $content_file_info['file'];
|
518 |
-
|
519 |
-
// Process widget import file.
|
520 |
-
if ( $widget_file_info && ! isset( $widget_file_info['error'] ) ) {
|
521 |
-
|
522 |
-
// Set uploaded widget file.
|
523 |
-
$selected_import_files['widgets'] = $widget_file_info['file'];
|
524 |
-
}
|
525 |
-
else {
|
526 |
-
|
527 |
-
// Add this error to log file.
|
528 |
-
$log_added = self::append_to_file(
|
529 |
-
sprintf(
|
530 |
-
__( 'Widget file was not uploaded. Error: %s', 'rara-one-click-demo-import' ),
|
531 |
-
$widget_file_info['error']
|
532 |
-
),
|
533 |
-
$log_file_path,
|
534 |
-
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
535 |
-
);
|
536 |
-
}
|
537 |
-
|
538 |
-
// Process Customizer import file.
|
539 |
-
if ( $customizer_file_info && ! isset( $customizer_file_info['error'] ) ) {
|
540 |
-
|
541 |
-
// Set uploaded widget file.
|
542 |
-
$selected_import_files['customizer'] = $customizer_file_info['file'];
|
543 |
-
}
|
544 |
-
else {
|
545 |
-
|
546 |
-
// Add this error to log file.
|
547 |
-
$log_added = self::append_to_file(
|
548 |
-
sprintf(
|
549 |
-
__( 'Customizer file was not uploaded. Error: %s', 'rara-one-click-demo-import' ),
|
550 |
-
$customizer_file_info['error']
|
551 |
-
),
|
552 |
-
$log_file_path,
|
553 |
-
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
554 |
-
);
|
555 |
-
}
|
556 |
-
|
557 |
-
// Add this message to log file.
|
558 |
-
$log_added = self::append_to_file(
|
559 |
-
__( 'The import files were successfully uploaded!', 'rara-one-click-demo-import' ) . self::import_file_info( $selected_import_files ),
|
560 |
-
$log_file_path,
|
561 |
-
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
562 |
-
);
|
563 |
-
|
564 |
-
// Return array with paths of uploaded files.
|
565 |
-
return $selected_import_files;
|
566 |
-
}
|
567 |
-
|
568 |
-
|
569 |
-
/**
|
570 |
-
* Get import file information and max execution time.
|
571 |
-
*
|
572 |
-
* @param array $selected_import_files array of selected import files.
|
573 |
-
*/
|
574 |
-
public static function import_file_info( $selected_import_files ) {
|
575 |
-
return PHP_EOL .
|
576 |
-
sprintf(
|
577 |
-
__( 'Initial max execution time = %s', 'rara-one-click-demo-import' ),
|
578 |
-
ini_get( 'max_execution_time' )
|
579 |
-
) . PHP_EOL .
|
580 |
-
sprintf(
|
581 |
-
__( 'Files info:%1$sSite URL = %2$s%1$sData file = %3$s%1$sWidget file = %4$s%1$sCustomizer file = %5$s', 'rara-one-click-demo-import' ),
|
582 |
-
PHP_EOL,
|
583 |
-
get_site_url(),
|
584 |
-
$selected_import_files['content'],
|
585 |
-
empty( $selected_import_files['widgets'] ) ? esc_html__( 'not defined!', 'rara-one-click-demo-import' ) : $selected_import_files['widgets'],
|
586 |
-
empty( $selected_import_files['customizer'] ) ? esc_html__( 'not defined!', 'rara-one-click-demo-import' ) : $selected_import_files['customizer']
|
587 |
-
);
|
588 |
-
}
|
589 |
-
|
590 |
-
|
591 |
-
/**
|
592 |
-
* Write the error to the log file and send the AJAX response.
|
593 |
-
*
|
594 |
-
* @param string $error_text text to display in the log file and in the AJAX response.
|
595 |
-
* @param string $log_file_path path to the log file.
|
596 |
-
* @param string $separator title separating the old and new content.
|
597 |
-
*/
|
598 |
-
public static function log_error_and_send_ajax_response( $error_text, $log_file_path, $separator = '' ) {
|
599 |
-
|
600 |
-
// Add this error to log file.
|
601 |
-
$log_added = self::append_to_file(
|
602 |
-
$error_text,
|
603 |
-
$log_file_path,
|
604 |
-
$separator
|
605 |
-
);
|
606 |
-
|
607 |
-
// Send JSON Error response to the AJAX call.
|
608 |
-
wp_send_json( $error_text );
|
609 |
-
}
|
610 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Static functions used in the rrdi plugin.
|
4 |
+
*
|
5 |
+
* @package rara-one-click-demo-import
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class with static helper functions.
|
10 |
+
*/
|
11 |
+
class RRDI_Helpers {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Filter through the array of import files and get rid of those who do not comply.
|
15 |
+
*
|
16 |
+
* @param array $import_files list of arrays with import file details.
|
17 |
+
* @return array list of filtered arrays.
|
18 |
+
*/
|
19 |
+
public static function validate_import_file_info( $import_files ) {
|
20 |
+
$filtered_import_file_info = array();
|
21 |
+
|
22 |
+
foreach ( $import_files as $import_file ) {
|
23 |
+
if ( self::is_import_file_info_format_correct( $import_file ) ) {
|
24 |
+
$filtered_import_file_info[] = $import_file;
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
return $filtered_import_file_info;
|
29 |
+
}
|
30 |
+
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Helper function: a simple check for valid import file format.
|
34 |
+
*
|
35 |
+
* @param array $import_file_info array with import file details.
|
36 |
+
* @return boolean
|
37 |
+
*/
|
38 |
+
private static function is_import_file_info_format_correct( $import_file_info ) {
|
39 |
+
if ( ( empty( $import_file_info['import_file_url'] ) && empty( $import_file_info['local_import_file'] ) ) || empty( $import_file_info['import_file_name'] ) ) {
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
return true;
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Download import files. Content .xml and widgets .wie|.json files.
|
49 |
+
*
|
50 |
+
* @param array $import_file_info array with import file details.
|
51 |
+
* @param string $start_date string of date and time.
|
52 |
+
* @return array|WP_Error array of paths to the downloaded files or WP_Error object with error message.
|
53 |
+
*/
|
54 |
+
public static function download_import_files( $import_file_info, $start_date = '' ) {
|
55 |
+
|
56 |
+
$downloaded_files = array();
|
57 |
+
$upload_dir = wp_upload_dir();
|
58 |
+
$upload_path = apply_filters( 'rrdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );
|
59 |
+
|
60 |
+
// ----- Set content file path -----
|
61 |
+
// Check if 'import_file_url' is not defined. That would mean a local file.
|
62 |
+
if ( empty( $import_file_info['import_file_url'] ) ) {
|
63 |
+
if ( file_exists( $import_file_info['local_import_file'] ) ) {
|
64 |
+
$downloaded_files['content'] = $import_file_info['local_import_file'];
|
65 |
+
}
|
66 |
+
else {
|
67 |
+
return new WP_Error(
|
68 |
+
'url_or_local_file_not_defined',
|
69 |
+
sprintf(
|
70 |
+
__( '"import_file_url" or "local_import_file" for %s%s%s are not defined!', 'rara-one-click-demo-import' ),
|
71 |
+
'<strong>',
|
72 |
+
$$import_file_info['import_file_name'],
|
73 |
+
'</strong>'
|
74 |
+
)
|
75 |
+
);
|
76 |
+
}
|
77 |
+
}
|
78 |
+
else {
|
79 |
+
|
80 |
+
// Retrieve demo data content from the URL.
|
81 |
+
$demo_import_content = self::get_content_from_url( $import_file_info['import_file_url'], $import_file_info['import_file_name'] );
|
82 |
+
|
83 |
+
// Return from this function if there was an error.
|
84 |
+
if ( is_wp_error( $demo_import_content ) ) {
|
85 |
+
return $demo_import_content;
|
86 |
+
}
|
87 |
+
|
88 |
+
// Setup filename path to save the data content.
|
89 |
+
$demo_import_file_path = $upload_path . apply_filters( 'rrdi/downloaded_content_file_prefix', 'demo-content-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_content_file_suffix_and_file_extension', '.xml' );
|
90 |
+
|
91 |
+
// Write data content to the file and return the file path on successful write.
|
92 |
+
$downloaded_files['content'] = self::write_to_file( $demo_import_content, $demo_import_file_path );
|
93 |
+
|
94 |
+
// Return from this function if there was an error.
|
95 |
+
if ( is_wp_error( $downloaded_files['content'] ) ) {
|
96 |
+
return $downloaded_files['content'];
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
// ----- Set widget file path -----
|
101 |
+
// Get widgets file as well. If defined!
|
102 |
+
if ( ! empty( $import_file_info['import_widget_file_url'] ) ) {
|
103 |
+
|
104 |
+
// Retrieve widget content from the URL.
|
105 |
+
$demo_import_widgets_content = self::get_content_from_url( $import_file_info['import_widget_file_url'], $import_file_info['import_file_name'] );
|
106 |
+
|
107 |
+
// Return from this function if there was an error.
|
108 |
+
if ( is_wp_error( $demo_import_widgets_content ) ) {
|
109 |
+
return $demo_import_widgets_content;
|
110 |
+
}
|
111 |
+
|
112 |
+
// Setup filename path to save the widget content.
|
113 |
+
$import_widgets_file_path = $upload_path . apply_filters( 'rrdi/downloaded_widgets_file_prefix', 'demo-widgets-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_widgets_file_suffix_and_file_extension', '.json' );
|
114 |
+
|
115 |
+
// Write widget content to the file and return the file path on successful write.
|
116 |
+
$downloaded_files['widgets'] = self::write_to_file( $demo_import_widgets_content, $import_widgets_file_path );
|
117 |
+
|
118 |
+
// Return from this function if there was an error.
|
119 |
+
if ( is_wp_error( $downloaded_files['widgets'] ) ) {
|
120 |
+
return $downloaded_files['widgets'];
|
121 |
+
}
|
122 |
+
}
|
123 |
+
else if ( ! empty( $import_file_info['local_import_widget_file'] ) ) {
|
124 |
+
if ( file_exists( $import_file_info['local_import_widget_file'] ) ) {
|
125 |
+
$downloaded_files['widgets'] = $import_file_info['local_import_widget_file'];
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
// ----- Set customizer file path -----
|
130 |
+
// Get customizer import file as well. If defined!
|
131 |
+
if ( ! empty( $import_file_info['import_customizer_file_url'] ) ) {
|
132 |
+
|
133 |
+
// Retrieve customizer content from the URL.
|
134 |
+
$demo_import_customizer_content = self::get_content_from_url( $import_file_info['import_customizer_file_url'], $import_file_info['import_file_name'] );
|
135 |
+
|
136 |
+
// Return from this function if there was an error.
|
137 |
+
if ( is_wp_error( $demo_import_customizer_content ) ) {
|
138 |
+
return $demo_import_customizer_content;
|
139 |
+
}
|
140 |
+
|
141 |
+
// Setup filename path to save the customizer content.
|
142 |
+
$import_customizer_file_path = $upload_path . apply_filters( 'rrdi/downloaded_customizer_file_prefix', 'demo-customizer-import-file_' ) . $start_date . apply_filters( 'rrdi/downloaded_customizer_file_suffix_and_file_extension', '.dat' );
|
143 |
+
|
144 |
+
// Write customizer content to the file and return the file path on successful write.
|
145 |
+
$downloaded_files['customizer'] = self::write_to_file( $demo_import_customizer_content, $import_customizer_file_path );
|
146 |
+
|
147 |
+
// Return from this function if there was an error.
|
148 |
+
if ( is_wp_error( $downloaded_files['customizer'] ) ) {
|
149 |
+
return $downloaded_files['customizer'];
|
150 |
+
}
|
151 |
+
}
|
152 |
+
else if ( ! empty( $import_file_info['local_import_customizer_file'] ) ) {
|
153 |
+
if ( file_exists( $import_file_info['local_import_customizer_file'] ) ) {
|
154 |
+
$downloaded_files['customizer'] = $import_file_info['local_import_customizer_file'];
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
return $downloaded_files;
|
159 |
+
}
|
160 |
+
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Helper function: get content from an url.
|
164 |
+
*
|
165 |
+
* @param string $url URL to the content file.
|
166 |
+
* @param string $file_name optional, name of the file (used in the error reports).
|
167 |
+
* @return string|WP_Error, content from the URL or WP_Error object with error message
|
168 |
+
*/
|
169 |
+
private static function get_content_from_url( $url, $file_name = 'Import file' ) {
|
170 |
+
|
171 |
+
// Test if the URL to the file is defined.
|
172 |
+
if ( empty( $url ) ) {
|
173 |
+
return new WP_Error(
|
174 |
+
'url_not_defined',
|
175 |
+
sprintf(
|
176 |
+
__( 'URL for %s%s%s file is not defined!', 'rara-one-click-demo-import' ),
|
177 |
+
'<strong>',
|
178 |
+
$file_name,
|
179 |
+
'</strong>'
|
180 |
+
)
|
181 |
+
);
|
182 |
+
}
|
183 |
+
|
184 |
+
// Get file content from the server.
|
185 |
+
$response = wp_remote_get(
|
186 |
+
$url,
|
187 |
+
array( 'timeout' => apply_filters( 'rrdi/timeout_for_downloading_import_file', 20 ) )
|
188 |
+
);
|
189 |
+
|
190 |
+
if ( is_wp_error( $response ) || 200 !== $response['response']['code'] ) {
|
191 |
+
|
192 |
+
// Collect the right format of error data (array or WP_Error).
|
193 |
+
$response_error = self::get_error_from_response( $response );
|
194 |
+
|
195 |
+
return new WP_Error(
|
196 |
+
'file_fetching_error',
|
197 |
+
sprintf(
|
198 |
+
__( 'An error occurred while fetching %s%s%s file from the server!%sReason: %s - %s.', 'rara-one-click-demo-import' ),
|
199 |
+
'<strong>',
|
200 |
+
$file_name,
|
201 |
+
'</strong>',
|
202 |
+
'<br>',
|
203 |
+
$response_error['error_code'],
|
204 |
+
$response_error['error_message']
|
205 |
+
) . '<br>' .
|
206 |
+
apply_filters( 'rrdi/message_after_file_fetching_error', '' )
|
207 |
+
);
|
208 |
+
}
|
209 |
+
|
210 |
+
// Return content retrieved from the URL.
|
211 |
+
return wp_remote_retrieve_body( $response );
|
212 |
+
}
|
213 |
+
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Write content to a file.
|
217 |
+
*
|
218 |
+
* @param string $content content to be saved to the file.
|
219 |
+
* @param string $file_path file path where the content should be saved.
|
220 |
+
* @return string|WP_Error path to the saved file or WP_Error object with error message.
|
221 |
+
*/
|
222 |
+
public static function write_to_file( $content, $file_path ) {
|
223 |
+
|
224 |
+
// Verify WP file-system credentials.
|
225 |
+
$verified_credentials = self::check_wp_filesystem_credentials();
|
226 |
+
|
227 |
+
if ( is_wp_error( $verified_credentials ) ) {
|
228 |
+
return $verified_credentials;
|
229 |
+
}
|
230 |
+
|
231 |
+
// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
|
232 |
+
global $wp_filesystem;
|
233 |
+
|
234 |
+
if ( ! $wp_filesystem->put_contents( $file_path, $content ) ) {
|
235 |
+
return new WP_Error(
|
236 |
+
'failed_writing_file_to_server',
|
237 |
+
sprintf(
|
238 |
+
__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'rara-one-click-demo-import' ),
|
239 |
+
'<br>',
|
240 |
+
$file_path
|
241 |
+
)
|
242 |
+
);
|
243 |
+
}
|
244 |
+
|
245 |
+
// Return the file path on successful file write.
|
246 |
+
return $file_path;
|
247 |
+
}
|
248 |
+
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Append content to the file.
|
252 |
+
*
|
253 |
+
* @param string $content content to be saved to the file.
|
254 |
+
* @param string $file_path file path where the content should be saved.
|
255 |
+
* @param string $separator_text separates the existing content of the file with the new content.
|
256 |
+
* @return boolean|WP_Error, path to the saved file or WP_Error object with error message.
|
257 |
+
*/
|
258 |
+
public static function append_to_file( $content, $file_path, $separator_text = '' ) {
|
259 |
+
|
260 |
+
// Verify WP file-system credentials.
|
261 |
+
$verified_credentials = self::check_wp_filesystem_credentials();
|
262 |
+
|
263 |
+
if ( is_wp_error( $verified_credentials ) ) {
|
264 |
+
return $verified_credentials;
|
265 |
+
}
|
266 |
+
|
267 |
+
// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
|
268 |
+
global $wp_filesystem;
|
269 |
+
|
270 |
+
$existing_data = '';
|
271 |
+
if ( file_exists( $file_path ) ) {
|
272 |
+
$existing_data = $wp_filesystem->get_contents( $file_path );
|
273 |
+
}
|
274 |
+
|
275 |
+
// Style separator.
|
276 |
+
$separator = PHP_EOL . '---' . $separator_text . '---' . PHP_EOL;
|
277 |
+
|
278 |
+
if ( ! $wp_filesystem->put_contents( $file_path, $existing_data . $separator . $content . PHP_EOL ) ) {
|
279 |
+
return new WP_Error(
|
280 |
+
'failed_writing_file_to_server',
|
281 |
+
sprintf(
|
282 |
+
__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'rara-one-click-demo-import' ),
|
283 |
+
'<br>',
|
284 |
+
$file_path
|
285 |
+
)
|
286 |
+
);
|
287 |
+
}
|
288 |
+
|
289 |
+
return true;
|
290 |
+
}
|
291 |
+
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Get data from a file
|
295 |
+
*
|
296 |
+
* @param string $file_path file path where the content should be saved.
|
297 |
+
* @return string $data, content of the file or WP_Error object with error message.
|
298 |
+
*/
|
299 |
+
public static function data_from_file( $file_path ) {
|
300 |
+
|
301 |
+
// Verify WP file-system credentials.
|
302 |
+
$verified_credentials = self::check_wp_filesystem_credentials();
|
303 |
+
|
304 |
+
if ( is_wp_error( $verified_credentials ) ) {
|
305 |
+
return $verified_credentials;
|
306 |
+
}
|
307 |
+
|
308 |
+
// By this point, the $wp_filesystem global should be working, so let's use it to read a file.
|
309 |
+
global $wp_filesystem;
|
310 |
+
|
311 |
+
$data = $wp_filesystem->get_contents( $file_path );
|
312 |
+
|
313 |
+
if ( ! $data ) {
|
314 |
+
return new WP_Error(
|
315 |
+
'failed_reading_file_from_server',
|
316 |
+
sprintf(
|
317 |
+
__( 'An error occurred while reading a file from your server! Tried reading file from path: %s%s.', 'rara-one-click-demo-import' ),
|
318 |
+
'<br>',
|
319 |
+
$file_path
|
320 |
+
)
|
321 |
+
);
|
322 |
+
}
|
323 |
+
|
324 |
+
// Return the file data.
|
325 |
+
return $data;
|
326 |
+
}
|
327 |
+
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Helper function: check for WP file-system credentials needed for reading and writing to a file.
|
331 |
+
*
|
332 |
+
* @return boolean|WP_Error
|
333 |
+
*/
|
334 |
+
private static function check_wp_filesystem_credentials() {
|
335 |
+
|
336 |
+
// Check if the file-system method is 'direct', if not display an error.
|
337 |
+
if ( ! ( 'direct' === get_filesystem_method() ) ) {
|
338 |
+
return new WP_Error(
|
339 |
+
'no_direct_file_access',
|
340 |
+
sprintf(
|
341 |
+
__( 'This WordPress page does not have %sdirect%s write file access. This plugin needs it in order to save the demo import xml file to the upload directory of your site. You can change this setting with these instructions: %s.', 'rara-one-click-demo-import' ),
|
342 |
+
'<strong>',
|
343 |
+
'</strong>',
|
344 |
+
'<a href="http://gregorcapuder.com/wordpress-how-to-set-direct-filesystem-method/" target="_blank">How to set <strong>direct</strong> filesystem method</a>'
|
345 |
+
)
|
346 |
+
);
|
347 |
+
}
|
348 |
+
|
349 |
+
// Get plugin page settings.
|
350 |
+
$plugin_page_setup = apply_filters( 'rrdi/plugin_page_setup', array(
|
351 |
+
'parent_slug' => 'themes.php',
|
352 |
+
'page_title' => esc_html__( 'Rara One Click Demo Import' , 'rara-one-click-demo-import' ),
|
353 |
+
'menu_title' => esc_html__( 'Rara Demo Import' , 'rara-one-click-demo-import' ),
|
354 |
+
'capability' => 'import',
|
355 |
+
'menu_slug' => 'rara-demo-import',
|
356 |
+
)
|
357 |
+
);
|
358 |
+
|
359 |
+
// Get user credentials for WP file-system API.
|
360 |
+
$demo_import_page_url = wp_nonce_url( $plugin_page_setup['parent_slug'] . '?page=' . $plugin_page_setup['menu_slug'], $plugin_page_setup['menu_slug'] );
|
361 |
+
|
362 |
+
if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) {
|
363 |
+
return new WP_error(
|
364 |
+
'filesystem_credentials_could_not_be_retrieved',
|
365 |
+
__( 'An error occurred while retrieving reading/writing permissions to your server (could not retrieve WP filesystem credentials)!', 'rara-one-click-demo-import' )
|
366 |
+
);
|
367 |
+
}
|
368 |
+
|
369 |
+
// Now we have credentials, try to get the wp_filesystem running.
|
370 |
+
if ( ! WP_Filesystem( $creds ) ) {
|
371 |
+
return new WP_Error(
|
372 |
+
'wrong_login_credentials',
|
373 |
+
__( 'Your WordPress login credentials don\'t allow to use WP_Filesystem!', 'rara-one-click-demo-import' )
|
374 |
+
);
|
375 |
+
}
|
376 |
+
|
377 |
+
return true;
|
378 |
+
}
|
379 |
+
|
380 |
+
|
381 |
+
/**
|
382 |
+
* Helper function: get the right format of response errors
|
383 |
+
*
|
384 |
+
* @param array|WP_Error $response array or WP_Error.
|
385 |
+
* @return array, with error code and error message.
|
386 |
+
*/
|
387 |
+
private static function get_error_from_response( $response ) {
|
388 |
+
$response_error = array();
|
389 |
+
|
390 |
+
if ( is_array( $response ) ) {
|
391 |
+
$response_error['error_code'] = $response['response']['code'];
|
392 |
+
$response_error['error_message'] = $response['response']['message'];
|
393 |
+
}
|
394 |
+
else {
|
395 |
+
$response_error['error_code'] = $response->get_error_code();
|
396 |
+
$response_error['error_message'] = $response->get_error_message();
|
397 |
+
}
|
398 |
+
|
399 |
+
return $response_error;
|
400 |
+
}
|
401 |
+
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Get log file path
|
405 |
+
*
|
406 |
+
* @param string $start_date date|time|timestamp to use in the log filename.
|
407 |
+
* @return string, path to the log file
|
408 |
+
*/
|
409 |
+
public static function get_log_path( $start_date = '' ) {
|
410 |
+
|
411 |
+
$upload_dir = wp_upload_dir();
|
412 |
+
$upload_path = apply_filters( 'rrdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );
|
413 |
+
|
414 |
+
$log_path = $upload_path . apply_filters( 'rrdi/log_file_prefix', 'log_file_' ) . $start_date . apply_filters( 'rrdi/log_file_suffix_and_file_extension', '.txt' );
|
415 |
+
|
416 |
+
self::register_file_as_media_attachment( $log_path );
|
417 |
+
|
418 |
+
return $log_path;
|
419 |
+
}
|
420 |
+
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Register file as attachment to the Media page.
|
424 |
+
*
|
425 |
+
* @param string $log_path log file path.
|
426 |
+
* @return void
|
427 |
+
*/
|
428 |
+
public static function register_file_as_media_attachment( $log_path ) {
|
429 |
+
|
430 |
+
// Check the type of file.
|
431 |
+
$log_mimes = array( 'txt' => 'text/plain' );
|
432 |
+
$filetype = wp_check_filetype( basename( $log_path ), apply_filters( 'rrdi/file_mimes', $log_mimes ) );
|
433 |
+
|
434 |
+
// Prepare an array of post data for the attachment.
|
435 |
+
$attachment = array(
|
436 |
+
'guid' => self::get_log_url( $log_path ),
|
437 |
+
'post_mime_type' => $filetype['type'],
|
438 |
+
'post_title' => apply_filters( 'rrdi/attachment_prefix', esc_html__( 'Rara One Click Demo Import - ', 'rara-one-click-demo-import' ) ) . preg_replace( '/\.[^.]+$/', '', basename( $log_path ) ),
|
439 |
+
'post_content' => '',
|
440 |
+
'post_status' => 'inherit',
|
441 |
+
);
|
442 |
+
|
443 |
+
// Insert the file as attachment in Media page.
|
444 |
+
$attach_id = wp_insert_attachment( $attachment, $log_path );
|
445 |
+
}
|
446 |
+
|
447 |
+
|
448 |
+
/**
|
449 |
+
* Get log file url
|
450 |
+
*
|
451 |
+
* @param string $log_path log path to use for the log filename.
|
452 |
+
* @return string, url to the log file.
|
453 |
+
*/
|
454 |
+
public static function get_log_url( $log_path ) {
|
455 |
+
|
456 |
+
$upload_dir = wp_upload_dir();
|
457 |
+
$upload_url = apply_filters( 'rrdi/upload_file_url', trailingslashit( $upload_dir['url'] ) );
|
458 |
+
|
459 |
+
return $upload_url . basename( $log_path );
|
460 |
+
}
|
461 |
+
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Check if the AJAX call is valid.
|
465 |
+
*/
|
466 |
+
public static function verify_ajax_call() {
|
467 |
+
|
468 |
+
check_ajax_referer( 'rrdi-ajax-verification', 'security' );
|
469 |
+
|
470 |
+
// Check if user has the WP capability to import data.
|
471 |
+
if ( ! current_user_can( 'import' ) ) {
|
472 |
+
wp_die(
|
473 |
+
sprintf(
|
474 |
+
__( '%sYour user role isn\'t high enough. You don\'t have permission to import demo data.%s', 'rara-one-click-demo-import' ),
|
475 |
+
'<div class="notice notice-error"><p>',
|
476 |
+
'</p></div>'
|
477 |
+
)
|
478 |
+
);
|
479 |
+
}
|
480 |
+
}
|
481 |
+
|
482 |
+
|
483 |
+
/**
|
484 |
+
* Process uploaded files and return the paths to these files.
|
485 |
+
*
|
486 |
+
* @param array $uploaded_files $_FILES array form an AJAX request.
|
487 |
+
* @param string $log_file_path path to the log file.
|
488 |
+
* @return array of paths to the content import and widget import files.
|
489 |
+
*/
|
490 |
+
public static function process_uploaded_files( $uploaded_files, $log_file_path ) {
|
491 |
+
|
492 |
+
// Variable holding the paths to the uploaded files.
|
493 |
+
$selected_import_files = array();
|
494 |
+
|
495 |
+
// Upload settings to disable form and type testing for AJAX uploads.
|
496 |
+
$upload_overrides = array(
|
497 |
+
'test_form' => false,
|
498 |
+
'test_type' => false,
|
499 |
+
);
|
500 |
+
|
501 |
+
// Handle demo content and widgets file upload.
|
502 |
+
$content_file_info = wp_handle_upload( $_FILES['content_file'], $upload_overrides );
|
503 |
+
$widget_file_info = wp_handle_upload( $_FILES['widget_file'], $upload_overrides );
|
504 |
+
$customizer_file_info = wp_handle_upload( $_FILES['customizer_file'], $upload_overrides );
|
505 |
+
|
506 |
+
if ( empty( $content_file_info['file'] ) || isset( $content_file_info['error'] ) ) {
|
507 |
+
|
508 |
+
// Write error to log file and send an AJAX response with the error.
|
509 |
+
self::log_error_and_send_ajax_response(
|
510 |
+
__( 'Please upload XML file for content import. If you want to import widgets or customizer settings only, please use Widget Importer & Exporter or the Customizer Export/Import plugin.', 'rara-one-click-demo-import' ),
|
511 |
+
$log_file_path,
|
512 |
+
esc_html__( 'Upload files', 'rara-one-click-demo-import' )
|
513 |
+
);
|
514 |
+
}
|
515 |
+
|
516 |
+
// Set uploaded content file.
|
517 |
+
$selected_import_files['content'] = $content_file_info['file'];
|
518 |
+
|
519 |
+
// Process widget import file.
|
520 |
+
if ( $widget_file_info && ! isset( $widget_file_info['error'] ) ) {
|
521 |
+
|
522 |
+
// Set uploaded widget file.
|
523 |
+
$selected_import_files['widgets'] = $widget_file_info['file'];
|
524 |
+
}
|
525 |
+
else {
|
526 |
+
|
527 |
+
// Add this error to log file.
|
528 |
+
$log_added = self::append_to_file(
|
529 |
+
sprintf(
|
530 |
+
__( 'Widget file was not uploaded. Error: %s', 'rara-one-click-demo-import' ),
|
531 |
+
$widget_file_info['error']
|
532 |
+
),
|
533 |
+
$log_file_path,
|
534 |
+
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
535 |
+
);
|
536 |
+
}
|
537 |
+
|
538 |
+
// Process Customizer import file.
|
539 |
+
if ( $customizer_file_info && ! isset( $customizer_file_info['error'] ) ) {
|
540 |
+
|
541 |
+
// Set uploaded widget file.
|
542 |
+
$selected_import_files['customizer'] = $customizer_file_info['file'];
|
543 |
+
}
|
544 |
+
else {
|
545 |
+
|
546 |
+
// Add this error to log file.
|
547 |
+
$log_added = self::append_to_file(
|
548 |
+
sprintf(
|
549 |
+
__( 'Customizer file was not uploaded. Error: %s', 'rara-one-click-demo-import' ),
|
550 |
+
$customizer_file_info['error']
|
551 |
+
),
|
552 |
+
$log_file_path,
|
553 |
+
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
554 |
+
);
|
555 |
+
}
|
556 |
+
|
557 |
+
// Add this message to log file.
|
558 |
+
$log_added = self::append_to_file(
|
559 |
+
__( 'The import files were successfully uploaded!', 'rara-one-click-demo-import' ) . self::import_file_info( $selected_import_files ),
|
560 |
+
$log_file_path,
|
561 |
+
esc_html__( 'Upload files' , 'rara-one-click-demo-import' )
|
562 |
+
);
|
563 |
+
|
564 |
+
// Return array with paths of uploaded files.
|
565 |
+
return $selected_import_files;
|
566 |
+
}
|
567 |
+
|
568 |
+
|
569 |
+
/**
|
570 |
+
* Get import file information and max execution time.
|
571 |
+
*
|
572 |
+
* @param array $selected_import_files array of selected import files.
|
573 |
+
*/
|
574 |
+
public static function import_file_info( $selected_import_files ) {
|
575 |
+
return PHP_EOL .
|
576 |
+
sprintf(
|
577 |
+
__( 'Initial max execution time = %s', 'rara-one-click-demo-import' ),
|
578 |
+
ini_get( 'max_execution_time' )
|
579 |
+
) . PHP_EOL .
|
580 |
+
sprintf(
|
581 |
+
__( 'Files info:%1$sSite URL = %2$s%1$sData file = %3$s%1$sWidget file = %4$s%1$sCustomizer file = %5$s', 'rara-one-click-demo-import' ),
|
582 |
+
PHP_EOL,
|
583 |
+
get_site_url(),
|
584 |
+
$selected_import_files['content'],
|
585 |
+
empty( $selected_import_files['widgets'] ) ? esc_html__( 'not defined!', 'rara-one-click-demo-import' ) : $selected_import_files['widgets'],
|
586 |
+
empty( $selected_import_files['customizer'] ) ? esc_html__( 'not defined!', 'rara-one-click-demo-import' ) : $selected_import_files['customizer']
|
587 |
+
);
|
588 |
+
}
|
589 |
+
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Write the error to the log file and send the AJAX response.
|
593 |
+
*
|
594 |
+
* @param string $error_text text to display in the log file and in the AJAX response.
|
595 |
+
* @param string $log_file_path path to the log file.
|
596 |
+
* @param string $separator title separating the old and new content.
|
597 |
+
*/
|
598 |
+
public static function log_error_and_send_ajax_response( $error_text, $log_file_path, $separator = '' ) {
|
599 |
+
|
600 |
+
// Add this error to log file.
|
601 |
+
$log_added = self::append_to_file(
|
602 |
+
$error_text,
|
603 |
+
$log_file_path,
|
604 |
+
$separator
|
605 |
+
);
|
606 |
+
|
607 |
+
// Send JSON Error response to the AJAX call.
|
608 |
+
wp_send_json( $error_text );
|
609 |
+
}
|
610 |
+
}
|
includes/class-rrdi-importer.php
CHANGED
@@ -1,78 +1,78 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class for declaring the importer used in the Rara One Click Demo Import plugin
|
4 |
-
*
|
5 |
-
* @package rara-one-click-demo-import
|
6 |
-
*/
|
7 |
-
|
8 |
-
class RRDI_Importer {
|
9 |
-
|
10 |
-
private $importer;
|
11 |
-
|
12 |
-
public function __construct( $importer_options = array(), $logger = null ) {
|
13 |
-
|
14 |
-
// Include files that are needed for WordPress Importer v2.
|
15 |
-
$this->include_required_files();
|
16 |
-
|
17 |
-
// Set the WordPress Importer v2 as the importer used in this plugin.
|
18 |
-
// More: https://github.com/humanmade/WordPress-Importer.
|
19 |
-
$this->importer = new RRDI_WXR_Importer( $importer_options );
|
20 |
-
|
21 |
-
// Set logger to the importer.
|
22 |
-
if ( ! empty( $logger ) ) {
|
23 |
-
$this->set_logger( $logger );
|
24 |
-
}
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Include required files.
|
29 |
-
*/
|
30 |
-
private function include_required_files() {
|
31 |
-
defined( 'WP_LOAD_IMPORTERS' ) || define( 'WP_LOAD_IMPORTERS', true );
|
32 |
-
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
33 |
-
if( is_plugin_active( 'theme-demo-import/theme-demo-import.php' ) )
|
34 |
-
{
|
35 |
-
}
|
36 |
-
else if ( is_plugin_active( 'one-click-demo-import/one-click-demo-import.php' ) ){
|
37 |
-
# code...
|
38 |
-
}
|
39 |
-
else{
|
40 |
-
require ABSPATH . '/wp-admin/includes/class-wp-importer.php';
|
41 |
-
}
|
42 |
-
require RRDI_PATH . 'includes/class-rrdi-wxr-importer.php';
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Imports content from a WordPress export file.
|
47 |
-
*
|
48 |
-
* @param string $data_file path to xml file, file with WordPress export data.
|
49 |
-
*/
|
50 |
-
public function import( $data_file ) {
|
51 |
-
$this->importer->import( $data_file );
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Set the logger used in the import
|
56 |
-
*
|
57 |
-
* @param object $logger logger instance.
|
58 |
-
*/
|
59 |
-
public function set_logger( $logger ) {
|
60 |
-
$this->importer->set_logger( $logger );
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Get all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
65 |
-
*/
|
66 |
-
public function get_importer_data() {
|
67 |
-
return $this->importer->get_importer_data();
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Sets all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
72 |
-
*
|
73 |
-
* @param array $data with set variables.
|
74 |
-
*/
|
75 |
-
public function set_importer_data( $data ) {
|
76 |
-
$this->importer->set_importer_data( $data );
|
77 |
-
}
|
78 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class for declaring the importer used in the Rara One Click Demo Import plugin
|
4 |
+
*
|
5 |
+
* @package rara-one-click-demo-import
|
6 |
+
*/
|
7 |
+
|
8 |
+
class RRDI_Importer {
|
9 |
+
|
10 |
+
private $importer;
|
11 |
+
|
12 |
+
public function __construct( $importer_options = array(), $logger = null ) {
|
13 |
+
|
14 |
+
// Include files that are needed for WordPress Importer v2.
|
15 |
+
$this->include_required_files();
|
16 |
+
|
17 |
+
// Set the WordPress Importer v2 as the importer used in this plugin.
|
18 |
+
// More: https://github.com/humanmade/WordPress-Importer.
|
19 |
+
$this->importer = new RRDI_WXR_Importer( $importer_options );
|
20 |
+
|
21 |
+
// Set logger to the importer.
|
22 |
+
if ( ! empty( $logger ) ) {
|
23 |
+
$this->set_logger( $logger );
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Include required files.
|
29 |
+
*/
|
30 |
+
private function include_required_files() {
|
31 |
+
defined( 'WP_LOAD_IMPORTERS' ) || define( 'WP_LOAD_IMPORTERS', true );
|
32 |
+
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
33 |
+
if( is_plugin_active( 'theme-demo-import/theme-demo-import.php' ) )
|
34 |
+
{
|
35 |
+
}
|
36 |
+
else if ( is_plugin_active( 'one-click-demo-import/one-click-demo-import.php' ) ){
|
37 |
+
# code...
|
38 |
+
}
|
39 |
+
else{
|
40 |
+
require ABSPATH . '/wp-admin/includes/class-wp-importer.php';
|
41 |
+
}
|
42 |
+
require RRDI_PATH . 'includes/class-rrdi-wxr-importer.php';
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Imports content from a WordPress export file.
|
47 |
+
*
|
48 |
+
* @param string $data_file path to xml file, file with WordPress export data.
|
49 |
+
*/
|
50 |
+
public function import( $data_file ) {
|
51 |
+
$this->importer->import( $data_file );
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Set the logger used in the import
|
56 |
+
*
|
57 |
+
* @param object $logger logger instance.
|
58 |
+
*/
|
59 |
+
public function set_logger( $logger ) {
|
60 |
+
$this->importer->set_logger( $logger );
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Get all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
65 |
+
*/
|
66 |
+
public function get_importer_data() {
|
67 |
+
return $this->importer->get_importer_data();
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Sets all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
72 |
+
*
|
73 |
+
* @param array $data with set variables.
|
74 |
+
*/
|
75 |
+
public function set_importer_data( $data ) {
|
76 |
+
$this->importer->set_importer_data( $data );
|
77 |
+
}
|
78 |
+
}
|
includes/class-rrdi-include-files.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Include files.
|
4 |
-
*
|
5 |
-
* @package rara-one-click-demo-import
|
6 |
-
*/
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Rara One Click Demo Import class, so we don't have to worry about namespaces.
|
10 |
-
*/
|
11 |
-
class RRDI_Theme_Demo_Include_Files {
|
12 |
-
|
13 |
-
function __construct()
|
14 |
-
{
|
15 |
-
// Include files.
|
16 |
-
require RRDI_PATH . 'includes/class-rrdi-helpers.php';
|
17 |
-
require RRDI_PATH . 'includes/class-rrdi-importer.php';
|
18 |
-
require RRDI_PATH . 'includes/vendor/class-rrdi-widget-importer.php';
|
19 |
-
require RRDI_PATH . 'includes/vendor/class-rrdi-customizer-importer.php';
|
20 |
-
require RRDI_PATH . 'includes/class-rrdi-logger.php';
|
21 |
-
}
|
22 |
-
}
|
23 |
new RRDI_Theme_Demo_Include_Files;
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Include files.
|
4 |
+
*
|
5 |
+
* @package rara-one-click-demo-import
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Rara One Click Demo Import class, so we don't have to worry about namespaces.
|
10 |
+
*/
|
11 |
+
class RRDI_Theme_Demo_Include_Files {
|
12 |
+
|
13 |
+
function __construct()
|
14 |
+
{
|
15 |
+
// Include files.
|
16 |
+
require RRDI_PATH . 'includes/class-rrdi-helpers.php';
|
17 |
+
require RRDI_PATH . 'includes/class-rrdi-importer.php';
|
18 |
+
require RRDI_PATH . 'includes/vendor/class-rrdi-widget-importer.php';
|
19 |
+
require RRDI_PATH . 'includes/vendor/class-rrdi-customizer-importer.php';
|
20 |
+
require RRDI_PATH . 'includes/class-rrdi-logger.php';
|
21 |
+
}
|
22 |
+
}
|
23 |
new RRDI_Theme_Demo_Include_Files;
|
includes/class-rrdi-init.php
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Display admin error message if PHP version is older than 5.3.2.
|
4 |
-
* Otherwise execute the main plugin class.
|
5 |
-
*/
|
6 |
-
class RDDI_init
|
7 |
-
{
|
8 |
-
function __construct()
|
9 |
-
{
|
10 |
-
$this->rddi_init_version_check();
|
11 |
-
}
|
12 |
-
|
13 |
-
function rddi_init_version_check()
|
14 |
-
{
|
15 |
-
|
16 |
-
if ( version_compare( phpversion(), '5.3.2', '<' ) ) {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Display an admin error notice when PHP is older the version 5.3.2.
|
20 |
-
* Hook it to the 'admin_notices' action.
|
21 |
-
*/
|
22 |
-
function rrdi_old_php_admin_error_notice() {
|
23 |
-
$message = sprintf( esc_html__( 'The %2$sRara One Click Demo Import%3$s plugin requires %2$sPHP 5.3.2+%3$s to run properly. Please contact your hosting company and ask them to update the PHP version of your site to at least PHP 5.3.2.%4$s Your current version of PHP: %2$s%1$s%3$s', 'rara-one-click-demo-import' ), phpversion(), '<strong>', '</strong>', '<br>' );
|
24 |
-
|
25 |
-
printf( '<div class="notice notice-error"><p>%1$s</p></div>', wp_kses_post( $message ) );
|
26 |
-
}
|
27 |
-
add_action( 'admin_notices', 'rrdi_old_php_admin_error_notice' );
|
28 |
-
}
|
29 |
-
else {
|
30 |
-
$upload = wp_upload_dir();
|
31 |
-
$upload_dir = $upload['basedir'];
|
32 |
-
$upload_dir = $upload_dir . '/rara-demo-pack';
|
33 |
-
if (! is_dir($upload_dir)) {
|
34 |
-
mkdir( $upload_dir, 0755 );
|
35 |
-
}
|
36 |
-
|
37 |
-
// Require main plugin file.
|
38 |
-
require RRDI_PATH . 'includes/class-rrdi-main.php';
|
39 |
-
|
40 |
-
// Instantiate the main plugin class *Singleton*.
|
41 |
-
$Theme_Demo_Import = RRDI_Theme_Demo_Import::Instance();
|
42 |
-
}
|
43 |
-
}
|
44 |
-
}
|
45 |
new RDDI_init;
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Display admin error message if PHP version is older than 5.3.2.
|
4 |
+
* Otherwise execute the main plugin class.
|
5 |
+
*/
|
6 |
+
class RDDI_init
|
7 |
+
{
|
8 |
+
function __construct()
|
9 |
+
{
|
10 |
+
$this->rddi_init_version_check();
|
11 |
+
}
|
12 |
+
|
13 |
+
function rddi_init_version_check()
|
14 |
+
{
|
15 |
+
|
16 |
+
if ( version_compare( phpversion(), '5.3.2', '<' ) ) {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Display an admin error notice when PHP is older the version 5.3.2.
|
20 |
+
* Hook it to the 'admin_notices' action.
|
21 |
+
*/
|
22 |
+
function rrdi_old_php_admin_error_notice() {
|
23 |
+
$message = sprintf( esc_html__( 'The %2$sRara One Click Demo Import%3$s plugin requires %2$sPHP 5.3.2+%3$s to run properly. Please contact your hosting company and ask them to update the PHP version of your site to at least PHP 5.3.2.%4$s Your current version of PHP: %2$s%1$s%3$s', 'rara-one-click-demo-import' ), phpversion(), '<strong>', '</strong>', '<br>' );
|
24 |
+
|
25 |
+
printf( '<div class="notice notice-error"><p>%1$s</p></div>', wp_kses_post( $message ) );
|
26 |
+
}
|
27 |
+
add_action( 'admin_notices', 'rrdi_old_php_admin_error_notice' );
|
28 |
+
}
|
29 |
+
else {
|
30 |
+
$upload = wp_upload_dir();
|
31 |
+
$upload_dir = $upload['basedir'];
|
32 |
+
$upload_dir = $upload_dir . '/rara-demo-pack';
|
33 |
+
if (! is_dir($upload_dir)) {
|
34 |
+
mkdir( $upload_dir, 0755 );
|
35 |
+
}
|
36 |
+
|
37 |
+
// Require main plugin file.
|
38 |
+
require RRDI_PATH . 'includes/class-rrdi-main.php';
|
39 |
+
|
40 |
+
// Instantiate the main plugin class *Singleton*.
|
41 |
+
$Theme_Demo_Import = RRDI_Theme_Demo_Import::Instance();
|
42 |
+
}
|
43 |
+
}
|
44 |
+
}
|
45 |
new RDDI_init;
|
includes/class-rrdi-logger.php
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Logger class used in the Rara One Click Demo Import plugin
|
4 |
-
*
|
5 |
-
* @package rara-one-click-demo-import
|
6 |
-
*/
|
7 |
-
|
8 |
-
// Include files.
|
9 |
-
require RRDI_PATH . 'includes/extras/class-logger.php';
|
10 |
-
require RRDI_PATH . 'includes/extras/class-logger-cli.php';
|
11 |
-
|
12 |
-
class RRDI_Logger extends RDDI_WP_Importer_Logger_CLI {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Variable for front-end error display.
|
16 |
-
*/
|
17 |
-
public $error_output = '';
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Overwritten log function from RDDI_WP_Importer_Logger_CLI.
|
21 |
-
*
|
22 |
-
* Logs with an arbitrary level.
|
23 |
-
*
|
24 |
-
* @param mixed $level level of reporting.
|
25 |
-
* @param string $message log message.
|
26 |
-
* @param array $context context to the log message.
|
27 |
-
*/
|
28 |
-
public function log( $level, $message, array $context = array() ) {
|
29 |
-
|
30 |
-
// Save error messages for front-end display.
|
31 |
-
$this->error_output( $level, $message, $context = array() );
|
32 |
-
|
33 |
-
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
|
34 |
-
return;
|
35 |
-
}
|
36 |
-
|
37 |
-
printf(
|
38 |
-
'[%s] %s' . PHP_EOL,
|
39 |
-
esc_html( strtoupper( $level ) ),
|
40 |
-
wp_kses_post( $message )
|
41 |
-
);
|
42 |
-
}
|
43 |
-
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Save messages for error output.
|
47 |
-
* Only the messages greater then Error.
|
48 |
-
*
|
49 |
-
* @param mixed $level level of reporting.
|
50 |
-
* @param string $message log message.
|
51 |
-
* @param array $context context to the log message.
|
52 |
-
*/
|
53 |
-
public function error_output( $level, $message, array $context = array() ) {
|
54 |
-
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( 'error' ) ) {
|
55 |
-
return;
|
56 |
-
}
|
57 |
-
|
58 |
-
$this->error_output .= sprintf(
|
59 |
-
'[%s] %s<br>',
|
60 |
-
strtoupper( $level ),
|
61 |
-
$message
|
62 |
-
);
|
63 |
-
}
|
64 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Logger class used in the Rara One Click Demo Import plugin
|
4 |
+
*
|
5 |
+
* @package rara-one-click-demo-import
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Include files.
|
9 |
+
require RRDI_PATH . 'includes/extras/class-logger.php';
|
10 |
+
require RRDI_PATH . 'includes/extras/class-logger-cli.php';
|
11 |
+
|
12 |
+
class RRDI_Logger extends RDDI_WP_Importer_Logger_CLI {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Variable for front-end error display.
|
16 |
+
*/
|
17 |
+
public $error_output = '';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Overwritten log function from RDDI_WP_Importer_Logger_CLI.
|
21 |
+
*
|
22 |
+
* Logs with an arbitrary level.
|
23 |
+
*
|
24 |
+
* @param mixed $level level of reporting.
|
25 |
+
* @param string $message log message.
|
26 |
+
* @param array $context context to the log message.
|
27 |
+
*/
|
28 |
+
public function log( $level, $message, array $context = array() ) {
|
29 |
+
|
30 |
+
// Save error messages for front-end display.
|
31 |
+
$this->error_output( $level, $message, $context = array() );
|
32 |
+
|
33 |
+
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
|
34 |
+
return;
|
35 |
+
}
|
36 |
+
|
37 |
+
printf(
|
38 |
+
'[%s] %s' . PHP_EOL,
|
39 |
+
esc_html( strtoupper( $level ) ),
|
40 |
+
wp_kses_post( $message )
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Save messages for error output.
|
47 |
+
* Only the messages greater then Error.
|
48 |
+
*
|
49 |
+
* @param mixed $level level of reporting.
|
50 |
+
* @param string $message log message.
|
51 |
+
* @param array $context context to the log message.
|
52 |
+
*/
|
53 |
+
public function error_output( $level, $message, array $context = array() ) {
|
54 |
+
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( 'error' ) ) {
|
55 |
+
return;
|
56 |
+
}
|
57 |
+
|
58 |
+
$this->error_output .= sprintf(
|
59 |
+
'[%s] %s<br>',
|
60 |
+
strtoupper( $level ),
|
61 |
+
$message
|
62 |
+
);
|
63 |
+
}
|
64 |
+
}
|
includes/class-rrdi-main.php
CHANGED
@@ -1,815 +1,815 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Main Rara One Click Demo Import plugin class/file.
|
4 |
-
*
|
5 |
-
* @package rara-one-click-demo-import
|
6 |
-
*/
|
7 |
-
/**
|
8 |
-
* Rara One Click Demo Import class, so we don't have to worry about namespaces.
|
9 |
-
*/
|
10 |
-
class RRDI_Theme_Demo_Import {
|
11 |
-
|
12 |
-
public $demo_config;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Demo packages.
|
16 |
-
*
|
17 |
-
* @var array
|
18 |
-
*/
|
19 |
-
public $demo_packages;
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Demo installer.
|
23 |
-
*
|
24 |
-
* @var bool
|
25 |
-
*/
|
26 |
-
public $demo_installer = true;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Define allowed authors for theme demo import.
|
30 |
-
*
|
31 |
-
* @var array
|
32 |
-
*/
|
33 |
-
public $rrdi_allowed_authors_uris = array( 'https://raratheme.com/', 'https://rarathemes.com/', 'https://wptravelengine.com' );
|
34 |
-
|
35 |
-
/**
|
36 |
-
* @var $instance the reference to *Singleton* instance of this class
|
37 |
-
*/
|
38 |
-
private static $instance;
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Private variables used throughout the plugin.
|
42 |
-
*/
|
43 |
-
private $importer, $plugin_page, $import_files, $logger, $log_file_path, $selected_index, $selected_import_files, $microtime, $frontend_error_messages, $ajax_call_number;
|
44 |
-
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Returns the *Singleton* instance of this class.
|
48 |
-
*
|
49 |
-
* @return Theme_Demo_Import the *Singleton* instance.
|
50 |
-
*/
|
51 |
-
public static function Instance() {
|
52 |
-
if ( null === static::$instance ) {
|
53 |
-
static::$instance = new static();
|
54 |
-
}
|
55 |
-
|
56 |
-
return static::$instance;
|
57 |
-
}
|
58 |
-
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Class construct function, to initiate the plugin.
|
62 |
-
* Protected constructor to prevent creating a new instance of the
|
63 |
-
* *Singleton* via the `new` operator from outside of this class.
|
64 |
-
*/
|
65 |
-
protected function __construct() {
|
66 |
-
require RRDI_PATH . 'includes/class-rrdi-include-files.php';
|
67 |
-
// Actions.
|
68 |
-
|
69 |
-
$this->includes();
|
70 |
-
|
71 |
-
add_action( 'init', array( $this, 'setup' ), 5 );
|
72 |
-
$get_theme = wp_get_theme();
|
73 |
-
|
74 |
-
if ( $this->is_valid_theme_author() ) {
|
75 |
-
|
76 |
-
add_action( 'admin_menu', array( $this, 'create_plugin_page' ) );
|
77 |
-
|
78 |
-
}
|
79 |
-
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
80 |
-
add_action( 'wp_ajax_rrdi_import_demo_data', array( $this, 'rrdi_import_demo_data_ajax_callback' ) );
|
81 |
-
add_action( 'init', array( $this, 'setup_plugin_with_filter_data' ) );
|
82 |
-
add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
|
83 |
-
// AJAX Events to import demo and dismiss notice.
|
84 |
-
add_action( 'wp_ajax_dismiss-notice', array( $this, 'ajax_dismiss_notice' ) );
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Check if theme author is valid to use demo importer.
|
89 |
-
*
|
90 |
-
* @return boolean
|
91 |
-
*/
|
92 |
-
public function is_valid_theme_author() {
|
93 |
-
|
94 |
-
$allowed_authors = apply_filters( 'rrdi_valid_theme_author_uris', $this->rrdi_allowed_authors_uris );
|
95 |
-
$theme_data = wp_get_theme();
|
96 |
-
|
97 |
-
$allowed_urls = array_map( 'parse_url', $allowed_authors );
|
98 |
-
$allowed_hosts = array_column( $allowed_urls, 'host' );
|
99 |
-
$theme_author_url = parse_url( $theme_data->get( 'AuthorURI' ) );
|
100 |
-
|
101 |
-
return in_array( $theme_author_url['host'], $allowed_hosts );
|
102 |
-
|
103 |
-
}
|
104 |
-
|
105 |
-
/**
|
106 |
-
* Demo importer setup.
|
107 |
-
*/
|
108 |
-
public function setup() {
|
109 |
-
$this->demo_config = apply_filters( 'rara_demo_importer_config', array() );
|
110 |
-
$this->demo_packages = apply_filters( 'rara_demo_importer_packages', array() );
|
111 |
-
$this->demo_installer = apply_filters( 'rara_demo_importer_installer', true );
|
112 |
-
}
|
113 |
-
|
114 |
-
|
115 |
-
function getNewestDir( $path ) {
|
116 |
-
$working_dir = getcwd();
|
117 |
-
chdir( $path ); // chdir to requested dir
|
118 |
-
$ret_val = false;
|
119 |
-
if ( $p = opendir( $path ) ) {
|
120 |
-
while ( false !== ( $file = readdir( $p ) ) ) {
|
121 |
-
if ( $file[0] != '.' && is_dir( $file ) ) {
|
122 |
-
$list[] = date( 'YmdHis', filemtime( $path . '/' . $file ) ) . $path . '/' . $file;
|
123 |
-
}
|
124 |
-
}
|
125 |
-
if ( isset( $list ) ) {
|
126 |
-
rsort( $list );
|
127 |
-
$ret_val = $list[0];
|
128 |
-
}
|
129 |
-
}
|
130 |
-
chdir( $working_dir ); // chdir back to script's dir
|
131 |
-
return $ret_val;
|
132 |
-
}
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Includes.
|
136 |
-
*/
|
137 |
-
private function includes() {
|
138 |
-
|
139 |
-
$get_theme = wp_get_theme();
|
140 |
-
|
141 |
-
if ( $this->is_valid_theme_author() ) {
|
142 |
-
|
143 |
-
$td = $get_theme->get( 'TextDomain' ) . '-demo-content';
|
144 |
-
if ( strpos( $td, 'pro' ) === false ) {
|
145 |
-
$upload_dir = wp_upload_dir();
|
146 |
-
// Check the folder contains at least 1 valid demo config.
|
147 |
-
$path = $upload_dir['basedir'] . '/rara-demo-pack/';
|
148 |
-
$files = $path . $td . '/import-hooks.php';
|
149 |
-
if ( file_exists( $files ) && is_readable( $files ) ) {
|
150 |
-
include $files;
|
151 |
-
}
|
152 |
-
}
|
153 |
-
}
|
154 |
-
}
|
155 |
-
|
156 |
-
/**
|
157 |
-
* Private clone method to prevent cloning of the instance of the *Singleton* instance.
|
158 |
-
*
|
159 |
-
* @return void
|
160 |
-
*/
|
161 |
-
private function __clone() {}
|
162 |
-
|
163 |
-
|
164 |
-
/**
|
165 |
-
* Private unserialize method to prevent unserializing of the *Singleton* instance.
|
166 |
-
*
|
167 |
-
* @return void
|
168 |
-
*/
|
169 |
-
public function __wakeup() {}
|
170 |
-
|
171 |
-
|
172 |
-
/**
|
173 |
-
* Creates the plugin page and a submenu item in WP Appearance menu.
|
174 |
-
*/
|
175 |
-
public function create_plugin_page() {
|
176 |
-
$plugin_page_setup = apply_filters(
|
177 |
-
'rrdi/plugin_page_setup',
|
178 |
-
array(
|
179 |
-
'parent_slug' => 'themes.php',
|
180 |
-
'page_title' => esc_html__( 'Rara One Click Demo Import', 'rara-one-click-demo-import' ),
|
181 |
-
'menu_title' => esc_html__( 'Rara Demo Import', 'rara-one-click-demo-import' ),
|
182 |
-
'capability' => 'import',
|
183 |
-
'menu_slug' => 'rara-demo-import',
|
184 |
-
)
|
185 |
-
);
|
186 |
-
|
187 |
-
$this->plugin_page = add_submenu_page( $plugin_page_setup['parent_slug'], $plugin_page_setup['page_title'], $plugin_page_setup['menu_title'], $plugin_page_setup['capability'], $plugin_page_setup['menu_slug'], array( $this, 'display_plugin_page' ) );
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Settings Tabs.
|
192 |
-
*
|
193 |
-
* @since 1.0.4
|
194 |
-
*/
|
195 |
-
function rrdi_settings_option_tabs() {
|
196 |
-
|
197 |
-
$options = array(
|
198 |
-
'Before_You_Begin' => 'intro.php',
|
199 |
-
'Demo_Import' => 'welcome.php',
|
200 |
-
'Pro_Theme_Demo_Import' => 'installed-demos.php',
|
201 |
-
);
|
202 |
-
$options = apply_filters( 'rrdi_settings_option_tabs', $options );
|
203 |
-
return $options;
|
204 |
-
}
|
205 |
-
|
206 |
-
private function rddi_upload_demo_pack() {
|
207 |
-
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
208 |
-
|
209 |
-
if ( ! current_user_can( 'upload_files' ) ) {
|
210 |
-
wp_die( __( 'Sorry, you are not allowed to install demo on this site.', 'rara-one-click-demo-import' ) );
|
211 |
-
}
|
212 |
-
|
213 |
-
check_admin_referer( 'demo-upload' );
|
214 |
-
|
215 |
-
$file_upload = new File_Upload_Upgrader( 'demozip', 'package' );
|
216 |
-
|
217 |
-
$title = sprintf( __( 'Installing Demo from uploaded file: %s', 'rara-one-click-demo-import' ), esc_html( basename( $file_upload->filename ) ) );
|
218 |
-
$nonce = 'demo-upload';
|
219 |
-
$url = add_query_arg( array( 'package' => $file_upload->id ), 'themes.php?page=demo-importer&action=upload-demo' );
|
220 |
-
$type = 'upload'; // Install demo type, From Web or an Upload.
|
221 |
-
|
222 |
-
// Demo Upgrader Class.
|
223 |
-
include_once dirname( __FILE__ ) . '/vendor/class-demo-upgrader.php';
|
224 |
-
include_once dirname( __FILE__ ) . '/vendor/class-demo-installer-skin.php';
|
225 |
-
|
226 |
-
$upgrader = new RDDI_Demo_Upgrader( new RDDI_Demo_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) );
|
227 |
-
$result = $upgrader->install( $file_upload->package );
|
228 |
-
|
229 |
-
if ( $result || is_wp_error( $result ) ) {
|
230 |
-
$file_upload->cleanup();
|
231 |
-
}
|
232 |
-
}
|
233 |
-
|
234 |
-
/**
|
235 |
-
* Plugin page display.
|
236 |
-
*/
|
237 |
-
public function display_plugin_page() {
|
238 |
-
if ( isset( $_GET['action'] ) && 'upload-demo' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
239 |
-
$this->rddi_upload_demo_pack();
|
240 |
-
} else { ?>
|
241 |
-
<div class="wrap">
|
242 |
-
<h1>
|
243 |
-
<?php
|
244 |
-
esc_html_e( 'RARA Demo Import', 'rara-one-click-demo-import' );
|
245 |
-
if ( current_user_can( 'upload_files' ) ) {
|
246 |
-
echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js tg-demo-upload" aria-expanded="false">' . __( 'Upload Demo File', 'rara-one-click-demo-import' ) . '</button>';
|
247 |
-
}
|
248 |
-
?>
|
249 |
-
</h1>
|
250 |
-
<div id="tabs-container">
|
251 |
-
<div class="tab">
|
252 |
-
<ul class="tabs-menu">
|
253 |
-
<?php
|
254 |
-
$settings_tab = $this->rrdi_settings_option_tabs();
|
255 |
-
$count = 0;
|
256 |
-
foreach ( $settings_tab as $key => $value ) {
|
257 |
-
$tab_label = preg_replace( '/_/', ' ', $key );
|
258 |
-
?>
|
259 |
-
<li
|
260 |
-
<?php
|
261 |
-
if ( $count == 0 ) {
|
262 |
-
?>
|
263 |
-
class="current"<?php } ?>><a href="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $tab_label ); ?></a></li>
|
264 |
-
<?php
|
265 |
-
$count++;
|
266 |
-
}
|
267 |
-
?>
|
268 |
-
</ul>
|
269 |
-
<?php
|
270 |
-
$counter = 0;
|
271 |
-
foreach ( $settings_tab as $key => $value ) {
|
272 |
-
?>
|
273 |
-
<div id="<?php echo esc_attr( $key ); ?>" class="tab-content"
|
274 |
-
<?php
|
275 |
-
if ( $counter == 0 ) {
|
276 |
-
?>
|
277 |
-
style="display: block;" <?php } ?>>
|
278 |
-
<?php
|
279 |
-
include_once RRDI_PATH . '/includes/settings/' . strtolower( $value );
|
280 |
-
?>
|
281 |
-
</div>
|
282 |
-
<?php $counter++; } ?>
|
283 |
-
</div>
|
284 |
-
</div>
|
285 |
-
</div>
|
286 |
-
<?php
|
287 |
-
}
|
288 |
-
}
|
289 |
-
|
290 |
-
private function prepare_demos_for_js( $demos = null ) {
|
291 |
-
$prepared_demos = array();
|
292 |
-
$current_template = get_option( 'template' );
|
293 |
-
$demo_imported_id = get_option( 'rara_demo_imported_id' );
|
294 |
-
|
295 |
-
/**
|
296 |
-
* Filters demo data before it is prepared for JavaScript.
|
297 |
-
*
|
298 |
-
* @param array $prepared_demos An associative array of demo data. Default empty array.
|
299 |
-
* @param null|array $demos An array of demo config to prepare, if any.
|
300 |
-
* @param string $demo_imported_id The current demo imported id.
|
301 |
-
*/
|
302 |
-
$prepared_demos = (array) apply_filters( 'rara_demo_importer_pre_prepare_demos_for_js', array(), $demos, $demo_imported_id );
|
303 |
-
|
304 |
-
if ( ! empty( $prepared_demos ) ) {
|
305 |
-
return $prepared_demos;
|
306 |
-
}
|
307 |
-
|
308 |
-
// Make sure the imported demo is listed first.
|
309 |
-
if ( isset( $demos[ $demo_imported_id ] ) ) {
|
310 |
-
$prepared_demos[ $demo_imported_id ] = array();
|
311 |
-
}
|
312 |
-
|
313 |
-
if ( ! empty( $demos ) ) {
|
314 |
-
foreach ( $demos as $demo_id => $demo_data ) {
|
315 |
-
$demo_notices = array();
|
316 |
-
$encoded_slug = urlencode( $demo_id );
|
317 |
-
$demo_package = isset( $demo_data['demo_pack'] ) ? $demo_data['demo_pack'] : false;
|
318 |
-
$plugins_list = isset( $demo_data['plugins_list'] ) ? $demo_data['plugins_list'] : array();
|
319 |
-
|
320 |
-
// Plugins status.
|
321 |
-
foreach ( $plugins_list as $plugin => $plugin_data ) {
|
322 |
-
$plugins_list[ $plugin ]['is_active'] = is_plugin_active( $plugin_data['slug'] );
|
323 |
-
}
|
324 |
-
|
325 |
-
// Add demo notices.
|
326 |
-
if ( isset( $demo_data['template'] ) && $current_template !== $demo_data['template'] ) {
|
327 |
-
$demo_notices['required_theme'] = true;
|
328 |
-
} elseif ( wp_list_filter(
|
329 |
-
$plugins_list,
|
330 |
-
array(
|
331 |
-
'required' => true,
|
332 |
-
'is_active' => false,
|
333 |
-
)
|
334 |
-
) ) {
|
335 |
-
$demo_notices['required_plugins'] = true;
|
336 |
-
}
|
337 |
-
|
338 |
-
// Prepare all demos.
|
339 |
-
$prepared_demos[ $demo_id ] = array(
|
340 |
-
'id' => $demo_id,
|
341 |
-
'name' => $demo_data['name'],
|
342 |
-
'theme' => $demo_data['theme'],
|
343 |
-
'package' => $demo_package,
|
344 |
-
'screenshot' => $this->import_file_url( $demo_id, 'screenshot.jpg' ),
|
345 |
-
'description' => isset( $demo_data['description'] ) ? $demo_data['description'] : '',
|
346 |
-
'author' => isset( $demo_data['author'] ) ? $demo_data['author'] : __( 'rara', 'rara-one-click-demo-import' ),
|
347 |
-
'authorAndUri' => '<a href="http://rara.com" target="_blank">rara</a>',
|
348 |
-
'version' => isset( $demo_data['version'] ) ? $demo_data['version'] : '1.1.0',
|
349 |
-
'active' => $demo_id === $demo_imported_id,
|
350 |
-
'hasNotice' => $demo_notices,
|
351 |
-
'plugins' => $plugins_list,
|
352 |
-
'actions' => array(
|
353 |
-
'preview' => home_url( '/' ),
|
354 |
-
'demo_url' => $demo_data['demo_url'],
|
355 |
-
'delete' => current_user_can( 'upload_files' ) ? wp_nonce_url( admin_url( 'themes.php?page=demo-importer&browse=uploads&action=delete&demo_pack=' . urlencode( $demo_id ) ), 'delete-demo_' . $demo_id ) : null,
|
356 |
-
),
|
357 |
-
);
|
358 |
-
}
|
359 |
-
}
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Filters the demos prepared for JavaScript.
|
363 |
-
*
|
364 |
-
* Could be useful for changing the order, which is by name by default.
|
365 |
-
*
|
366 |
-
* @param array $prepared_demos Array of demos.
|
367 |
-
*/
|
368 |
-
$prepared_demos = apply_filters( 'rara_demo_importer_prepare_demos_for_js', $prepared_demos );
|
369 |
-
$prepared_demos = array_values( $prepared_demos );
|
370 |
-
return array_filter( $prepared_demos );
|
371 |
-
}
|
372 |
-
/**
|
373 |
-
* Enqueue admin scripts (JS and CSS)
|
374 |
-
*
|
375 |
-
* @param string $hook holds info on which admin page you are currently loading.
|
376 |
-
*/
|
377 |
-
public function admin_enqueue_scripts( $hook ) {
|
378 |
-
|
379 |
-
// Enqueue the scripts only on the plugin page.
|
380 |
-
if ( $this->plugin_page === $hook ) {
|
381 |
-
wp_enqueue_script( 'rrdi-main-js', RRDI_URL . 'assets/js/script.js', array( 'jquery', 'jquery-form' ), RRDI_VERSION );
|
382 |
-
|
383 |
-
wp_localize_script(
|
384 |
-
'rrdi-main-js',
|
385 |
-
'rrdi',
|
386 |
-
array(
|
387 |
-
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
388 |
-
'ajax_nonce' => wp_create_nonce( 'rrdi-ajax-verification' ),
|
389 |
-
'import_files' => $this->import_files,
|
390 |
-
'texts' => array(
|
391 |
-
'missing_preview_image' => esc_html__( 'No preview image defined for this import.', 'rara-one-click-demo-import' ),
|
392 |
-
),
|
393 |
-
)
|
394 |
-
);
|
395 |
-
wp_enqueue_style( 'rrdi-main-css', RRDI_URL . 'assets/css/style.css', array(), RRDI_VERSION );
|
396 |
-
}
|
397 |
-
}
|
398 |
-
|
399 |
-
|
400 |
-
/**
|
401 |
-
* Main AJAX callback function for:
|
402 |
-
* 1. prepare import files (uploaded or predefined via filters)
|
403 |
-
* 2. import content
|
404 |
-
* 3. before widgets import setup (optional)
|
405 |
-
* 4. import widgets (optional)
|
406 |
-
* 5. import customizer options (optional)
|
407 |
-
* 6. after import setup (optional)
|
408 |
-
*/
|
409 |
-
public function rrdi_import_demo_data_ajax_callback() {
|
410 |
-
|
411 |
-
// Try to update PHP memory limit (so that it does not run out of it).
|
412 |
-
ini_set( 'memory_limit', apply_filters( 'rrdi/import_memory_limit', '350M' ) );
|
413 |
-
|
414 |
-
// Verify if the AJAX call is valid (checks nonce and current_user_can).
|
415 |
-
RRDI_Helpers::verify_ajax_call();
|
416 |
-
|
417 |
-
// Is this a new AJAX call to continue the previous import?
|
418 |
-
$use_existing_importer_data = $this->get_importer_data();
|
419 |
-
|
420 |
-
if ( ! $use_existing_importer_data ) {
|
421 |
-
|
422 |
-
// Set the AJAX call number.
|
423 |
-
$this->ajax_call_number = empty( $this->ajax_call_number ) ? 0 : $this->ajax_call_number;
|
424 |
-
|
425 |
-
// Error messages displayed on front page.
|
426 |
-
$this->frontend_error_messages = '';
|
427 |
-
|
428 |
-
// Create a date and time string to use for demo and log file names.
|
429 |
-
$demo_import_start_time = date( apply_filters( 'rrdi/date_format_for_file_names', 'Y-m-d__H-i-s' ) );
|
430 |
-
|
431 |
-
// Define log file path.
|
432 |
-
$this->log_file_path = RRDI_Helpers::get_log_path( $demo_import_start_time );
|
433 |
-
|
434 |
-
// Get selected file index or set it to 0.
|
435 |
-
$this->selected_index = empty( $_POST['selected'] ) ? 0 : absint( $_POST['selected'] );
|
436 |
-
|
437 |
-
/**
|
438 |
-
* 1. Prepare import files.
|
439 |
-
* Manually uploaded import files or predefined import files via filter: rrdi/import_files
|
440 |
-
*/
|
441 |
-
if ( ! empty( $_FILES ) ) { // Using manual file uploads?
|
442 |
-
|
443 |
-
// Get paths for the uploaded files.
|
444 |
-
$this->selected_import_files = RRDI_Helpers::process_uploaded_files( $_FILES, $this->log_file_path );
|
445 |
-
|
446 |
-
// Set the name of the import files, because we used the uploaded files.
|
447 |
-
$this->import_files[ $this->selected_index ]['import_file_name'] = esc_html__( 'Manually uploaded files', 'rara-one-click-demo-import' );
|
448 |
-
} elseif ( ! empty( $this->import_files[ $this->selected_index ] ) ) { // Use predefined import files from wp filter: rrdi/import_files.
|
449 |
-
|
450 |
-
// Download the import files (content and widgets files) and save it to variable for later use.
|
451 |
-
$this->selected_import_files = RRDI_Helpers::download_import_files(
|
452 |
-
$this->import_files[ $this->selected_index ],
|
453 |
-
$demo_import_start_time
|
454 |
-
);
|
455 |
-
|
456 |
-
// Check Errors.
|
457 |
-
if ( is_wp_error( $this->selected_import_files ) ) {
|
458 |
-
|
459 |
-
// Write error to log file and send an AJAX response with the error.
|
460 |
-
RRDI_Helpers::log_error_and_send_ajax_response(
|
461 |
-
$this->selected_import_files->get_error_message(),
|
462 |
-
$this->log_file_path,
|
463 |
-
esc_html__( 'Downloaded files', 'rara-one-click-demo-import' )
|
464 |
-
);
|
465 |
-
}
|
466 |
-
|
467 |
-
// Add this message to log file.
|
468 |
-
$log_added = RRDI_Helpers::append_to_file(
|
469 |
-
sprintf(
|
470 |
-
__( 'The import files for: %s were successfully downloaded!', 'rara-one-click-demo-import' ),
|
471 |
-
$this->import_files[ $this->selected_index ]['import_file_name']
|
472 |
-
) . RRDI_Helpers::import_file_info( $this->selected_import_files ),
|
473 |
-
$this->log_file_path,
|
474 |
-
esc_html__( 'Downloaded files', 'rara-one-click-demo-import' )
|
475 |
-
);
|
476 |
-
} else {
|
477 |
-
|
478 |
-
// Send JSON Error response to the AJAX call.
|
479 |
-
wp_send_json( esc_html__( 'No import files specified!', 'rara-one-click-demo-import' ) );
|
480 |
-
}
|
481 |
-
}
|
482 |
-
|
483 |
-
/**
|
484 |
-
* 2. Import content.
|
485 |
-
* Returns any errors greater then the "error" logger level, that will be displayed on front page.
|
486 |
-
*/
|
487 |
-
$this->frontend_error_messages .= $this->import_content( $this->selected_import_files['content'] );
|
488 |
-
|
489 |
-
/**
|
490 |
-
* 3. Before widgets import setup.
|
491 |
-
*/
|
492 |
-
$action = 'rrdi/before_widgets_import';
|
493 |
-
if ( ( false !== has_action( $action ) ) && empty( $this->frontend_error_messages ) ) {
|
494 |
-
|
495 |
-
// Run the before_widgets_import action to setup other settings.
|
496 |
-
$this->do_import_action( $action, $this->import_files[ $this->selected_index ] );
|
497 |
-
}
|
498 |
-
|
499 |
-
/**
|
500 |
-
* 4. Import widgets.
|
501 |
-
*/
|
502 |
-
if ( ! empty( $this->selected_import_files['widgets'] ) && empty( $this->frontend_error_messages ) ) {
|
503 |
-
$this->import_widgets( $this->selected_import_files['widgets'] );
|
504 |
-
}
|
505 |
-
|
506 |
-
/**
|
507 |
-
* 5. Import customize options.
|
508 |
-
*/
|
509 |
-
if ( ! empty( $this->selected_import_files['customizer'] ) && empty( $this->frontend_error_messages ) ) {
|
510 |
-
$this->import_customizer( $this->selected_import_files['customizer'] );
|
511 |
-
}
|
512 |
-
|
513 |
-
/**
|
514 |
-
* 6. After import setup.
|
515 |
-
*/
|
516 |
-
$action = 'rrdi/after_import';
|
517 |
-
if ( ( false !== has_action( $action ) ) && empty( $this->frontend_error_messages ) ) {
|
518 |
-
|
519 |
-
// Run the after_import action to setup other settings.
|
520 |
-
$this->do_import_action( $action, $this->import_files[ $this->selected_index ] );
|
521 |
-
}
|
522 |
-
|
523 |
-
// Display final messages (success or error messages).
|
524 |
-
if ( empty( $this->frontend_error_messages ) ) {
|
525 |
-
$response['message'] = sprintf(
|
526 |
-
__( '%1$s%3$sCompleted Successfully!%4$s%2$sThe process has finished. Please check your page and make sure that everything has been imported correctly. If you want, you can now deactivate the %3$sRara One Click Demo Import%4$s plugin.%5$s', 'rara-one-click-demo-import' ),
|
527 |
-
'<div class="notice notice-success"><p>',
|
528 |
-
'<br>',
|
529 |
-
'<strong>',
|
530 |
-
'</strong>',
|
531 |
-
'</p></div>'
|
532 |
-
);
|
533 |
-
} else {
|
534 |
-
$response['message'] = $this->frontend_error_messages . '<br>';
|
535 |
-
$response['message'] .= sprintf(
|
536 |
-
__( '%1$sUnfortunately, demo import has finished with some errors.%2$sMore details about the errors can be found in this %3$s%5$slog file%6$s%4$s%7$s', 'rara-one-click-demo-import' ),
|
537 |
-
'<div class="notice notice-error"><p>',
|
538 |
-
'<br>',
|
539 |
-
'<strong>',
|
540 |
-
'</strong>',
|
541 |
-
'<a href="' . RRDI_Helpers::get_log_url( $this->log_file_path ) . '" target="_blank">',
|
542 |
-
'</a>',
|
543 |
-
'</p></div>'
|
544 |
-
);
|
545 |
-
}
|
546 |
-
|
547 |
-
wp_send_json( $response );
|
548 |
-
}
|
549 |
-
|
550 |
-
|
551 |
-
/**
|
552 |
-
* Import content from an WP XML file.
|
553 |
-
*
|
554 |
-
* @param string $import_file_path path to the import file.
|
555 |
-
*/
|
556 |
-
private function import_content( $import_file_path ) {
|
557 |
-
|
558 |
-
$this->microtime = microtime( true );
|
559 |
-
|
560 |
-
// This should be replaced with multiple AJAX calls (import in smaller chunks)
|
561 |
-
// so that it would not come to the Internal Error, because of the PHP script timeout.
|
562 |
-
// Also this function has no effect when PHP is running in safe mode
|
563 |
-
// http://php.net/manual/en/function.set-time-limit.php.
|
564 |
-
// Increase PHP max execution time. Just in case, even though the AJAX calls are only 25 sec long.
|
565 |
-
if ( strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) === false ) {
|
566 |
-
set_time_limit( apply_filters( 'rrdi/set_time_limit_for_demo_data_import', 300 ) );
|
567 |
-
}
|
568 |
-
|
569 |
-
// Disable import of authors.
|
570 |
-
add_filter( 'wxr_importer.pre_process.user', '__return_false' );
|
571 |
-
|
572 |
-
// Check, if we need to send another AJAX request and set the importing author to the current user.
|
573 |
-
add_filter( 'wxr_importer.pre_process.post', array( $this, 'new_ajax_request_maybe' ) );
|
574 |
-
|
575 |
-
// Disables generation of multiple image sizes (thumbnails) in the content import step.
|
576 |
-
if ( ! apply_filters( 'rrdi/regenerate_thumbnails_in_content_import', true ) ) {
|
577 |
-
add_filter(
|
578 |
-
'intermediate_image_sizes_advanced',
|
579 |
-
function() {
|
580 |
-
return null;
|
581 |
-
}
|
582 |
-
);
|
583 |
-
}
|
584 |
-
|
585 |
-
// Import content.
|
586 |
-
if ( ! empty( $import_file_path ) ) {
|
587 |
-
ob_start();
|
588 |
-
$this->importer->import( $import_file_path );
|
589 |
-
$message = ob_get_clean();
|
590 |
-
|
591 |
-
// Add this message to log file.
|
592 |
-
$log_added = RRDI_Helpers::append_to_file(
|
593 |
-
$message . PHP_EOL . esc_html__( 'Max execution time after content import = ', 'rara-one-click-demo-import' ) . ini_get( 'max_execution_time' ),
|
594 |
-
$this->log_file_path,
|
595 |
-
esc_html__( 'Importing content', 'rara-one-click-demo-import' )
|
596 |
-
);
|
597 |
-
}
|
598 |
-
|
599 |
-
// Delete content importer data for current import from DB.
|
600 |
-
delete_transient( 'RRDI_importer_data' );
|
601 |
-
|
602 |
-
// Return any error messages for the front page output (errors, critical, alert and emergency level messages only).
|
603 |
-
return $this->logger->error_output;
|
604 |
-
}
|
605 |
-
|
606 |
-
|
607 |
-
/**
|
608 |
-
* Import widgets from WIE or JSON file.
|
609 |
-
*
|
610 |
-
* @param string $widget_import_file_path path to the widget import file.
|
611 |
-
*/
|
612 |
-
private function import_widgets( $widget_import_file_path ) {
|
613 |
-
|
614 |
-
// Widget import results.
|
615 |
-
$results = array();
|
616 |
-
|
617 |
-
// Create an instance of the Widget Importer.
|
618 |
-
$widget_importer = new RRDI_Widget_Importer();
|
619 |
-
|
620 |
-
// Import widgets.
|
621 |
-
if ( ! empty( $widget_import_file_path ) ) {
|
622 |
-
|
623 |
-
// Import widgets and return result.
|
624 |
-
$results = $widget_importer->import_widgets( $widget_import_file_path );
|
625 |
-
}
|
626 |
-
|
627 |
-
// Check for errors.
|
628 |
-
if ( is_wp_error( $results ) ) {
|
629 |
-
|
630 |
-
// Write error to log file and send an AJAX response with the error.
|
631 |
-
RRDI_Helpers::log_error_and_send_ajax_response(
|
632 |
-
$results->get_error_message(),
|
633 |
-
$this->log_file_path,
|
634 |
-
esc_html__( 'Importing widgets', 'rara-one-click-demo-import' )
|
635 |
-
);
|
636 |
-
}
|
637 |
-
|
638 |
-
ob_start();
|
639 |
-
$widget_importer->format_results_for_log( $results );
|
640 |
-
$message = ob_get_clean();
|
641 |
-
|
642 |
-
// Add this message to log file.
|
643 |
-
$log_added = RRDI_Helpers::append_to_file(
|
644 |
-
$message,
|
645 |
-
$this->log_file_path,
|
646 |
-
esc_html__( 'Importing widgets', 'rara-one-click-demo-import' )
|
647 |
-
);
|
648 |
-
}
|
649 |
-
|
650 |
-
|
651 |
-
/**
|
652 |
-
* Import customizer from a DAT file, generated by the Customizer Export/Import plugin.
|
653 |
-
*
|
654 |
-
* @param string $customizer_import_file_path path to the customizer import file.
|
655 |
-
*/
|
656 |
-
private function import_customizer( $customizer_import_file_path ) {
|
657 |
-
|
658 |
-
// Try to import the customizer settings.
|
659 |
-
$results = RRDI_Customizer_Importer::import_customizer_options( $customizer_import_file_path );
|
660 |
-
|
661 |
-
// Check for errors.
|
662 |
-
if ( is_wp_error( $results ) ) {
|
663 |
-
|
664 |
-
// Write error to log file and send an AJAX response with the error.
|
665 |
-
RRDI_Helpers::log_error_and_send_ajax_response(
|
666 |
-
$results->get_error_message(),
|
667 |
-
$this->log_file_path,
|
668 |
-
esc_html__( 'Importing customizer settings', 'rara-one-click-demo-import' )
|
669 |
-
);
|
670 |
-
}
|
671 |
-
|
672 |
-
// Add this message to log file.
|
673 |
-
$log_added = RRDI_Helpers::append_to_file(
|
674 |
-
esc_html__( 'Customizer settings import finished!', 'rara-one-click-demo-import' ),
|
675 |
-
$this->log_file_path,
|
676 |
-
esc_html__( 'Importing customizer settings', 'rara-one-click-demo-import' )
|
677 |
-
);
|
678 |
-
}
|
679 |
-
|
680 |
-
|
681 |
-
/**
|
682 |
-
* Setup other things in the passed wp action.
|
683 |
-
*
|
684 |
-
* @param string $action the action name to be executed.
|
685 |
-
* @param array $selected_import with information about the selected import.
|
686 |
-
*/
|
687 |
-
private function do_import_action( $action, $selected_import ) {
|
688 |
-
|
689 |
-
ob_start();
|
690 |
-
do_action( $action, $selected_import );
|
691 |
-
$message = ob_get_clean();
|
692 |
-
|
693 |
-
// Add this message to log file.
|
694 |
-
$log_added = RRDI_Helpers::append_to_file(
|
695 |
-
$message,
|
696 |
-
$this->log_file_path,
|
697 |
-
$action
|
698 |
-
);
|
699 |
-
}
|
700 |
-
|
701 |
-
|
702 |
-
/**
|
703 |
-
* Check if we need to create a new AJAX request, so that server does not timeout.
|
704 |
-
*
|
705 |
-
* @param array $data current post data.
|
706 |
-
* @return array
|
707 |
-
*/
|
708 |
-
public function new_ajax_request_maybe( $data ) {
|
709 |
-
$time = microtime( true ) - $this->microtime;
|
710 |
-
|
711 |
-
// We should make a new ajax call, if the time is right.
|
712 |
-
if ( $time > apply_filters( 'rrdi/time_for_one_ajax_call', 25 ) ) {
|
713 |
-
$this->ajax_call_number++;
|
714 |
-
$this->set_importer_data();
|
715 |
-
|
716 |
-
$response = array(
|
717 |
-
'status' => 'newAJAX',
|
718 |
-
'message' => 'New AJAX request!: ' . $time,
|
719 |
-
);
|
720 |
-
|
721 |
-
// Add any output to the log file and clear the buffers.
|
722 |
-
$message = ob_get_clean();
|
723 |
-
|
724 |
-
// Add message to log file.
|
725 |
-
$log_added = RRDI_Helpers::append_to_file(
|
726 |
-
__( 'Completed AJAX call number: ', 'rara-one-click-demo-import' ) . $this->ajax_call_number . PHP_EOL . $message,
|
727 |
-
$this->log_file_path,
|
728 |
-
''
|
729 |
-
);
|
730 |
-
|
731 |
-
wp_send_json( $response );
|
732 |
-
}
|
733 |
-
|
734 |
-
// Set importing author to the current user.
|
735 |
-
// Fixes the [WARNING] Could not find the author for ... log warning messages.
|
736 |
-
$current_user_obj = wp_get_current_user();
|
737 |
-
$data['post_author'] = $current_user_obj->user_login;
|
738 |
-
|
739 |
-
return $data;
|
740 |
-
}
|
741 |
-
|
742 |
-
/**
|
743 |
-
* Set current state of the content importer, so we can continue the import with new AJAX request.
|
744 |
-
*/
|
745 |
-
private function set_importer_data() {
|
746 |
-
$data = array(
|
747 |
-
'frontend_error_messages' => $this->frontend_error_messages,
|
748 |
-
'ajax_call_number' => $this->ajax_call_number,
|
749 |
-
'log_file_path' => $this->log_file_path,
|
750 |
-
'selected_index' => $this->selected_index,
|
751 |
-
'selected_import_files' => $this->selected_import_files,
|
752 |
-
);
|
753 |
-
|
754 |
-
$data = array_merge( $data, $this->importer->get_importer_data() );
|
755 |
-
|
756 |
-
set_transient( 'RRDI_importer_data', $data, 0.5 * HOUR_IN_SECONDS );
|
757 |
-
}
|
758 |
-
|
759 |
-
/**
|
760 |
-
* Get content importer data, so we can continue the import with this new AJAX request.
|
761 |
-
*/
|
762 |
-
private function get_importer_data() {
|
763 |
-
if ( $data = get_transient( 'RRDI_importer_data' ) ) {
|
764 |
-
$this->frontend_error_messages = empty( $data['frontend_error_messages'] ) ? '' : $data['frontend_error_messages'];
|
765 |
-
$this->ajax_call_number = empty( $data['ajax_call_number'] ) ? 1 : $data['ajax_call_number'];
|
766 |
-
$this->log_file_path = empty( $data['log_file_path'] ) ? '' : $data['log_file_path'];
|
767 |
-
$this->selected_index = empty( $data['selected_index'] ) ? 0 : $data['selected_index'];
|
768 |
-
$this->selected_import_files = empty( $data['selected_import_files'] ) ? array() : $data['selected_import_files'];
|
769 |
-
$this->importer->set_importer_data( $data );
|
770 |
-
|
771 |
-
return true;
|
772 |
-
}
|
773 |
-
return false;
|
774 |
-
}
|
775 |
-
|
776 |
-
/**
|
777 |
-
* Load the plugin textdomain, so that translations can be made.
|
778 |
-
*/
|
779 |
-
public function load_textdomain() {
|
780 |
-
load_plugin_textdomain( 'rara-one-click-demo-import', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
|
781 |
-
}
|
782 |
-
|
783 |
-
|
784 |
-
/**
|
785 |
-
* Get data from filters, after the theme has loaded and instantiate the importer.
|
786 |
-
*/
|
787 |
-
public function setup_plugin_with_filter_data() {
|
788 |
-
|
789 |
-
// Get info of import data files and filter it.
|
790 |
-
$this->import_files = RRDI_Helpers::validate_import_file_info( apply_filters( 'rrdi/import_files', array() ) );
|
791 |
-
|
792 |
-
// Importer options array.
|
793 |
-
$importer_options = apply_filters(
|
794 |
-
'rrdi/importer_options',
|
795 |
-
array(
|
796 |
-
'fetch_attachments' => true,
|
797 |
-
)
|
798 |
-
);
|
799 |
-
|
800 |
-
// Logger options for the logger used in the importer.
|
801 |
-
$logger_options = apply_filters(
|
802 |
-
'rrdi/logger_options',
|
803 |
-
array(
|
804 |
-
'logger_min_level' => 'warning',
|
805 |
-
)
|
806 |
-
);
|
807 |
-
|
808 |
-
// Configure logger instance and set it to the importer.
|
809 |
-
$this->logger = new RRDI_Logger();
|
810 |
-
$this->logger->min_level = $logger_options['logger_min_level'];
|
811 |
-
|
812 |
-
// Create importer instance with proper parameters.
|
813 |
-
$this->importer = new RRDI_Importer( $importer_options, $this->logger );
|
814 |
-
}
|
815 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Main Rara One Click Demo Import plugin class/file.
|
4 |
+
*
|
5 |
+
* @package rara-one-click-demo-import
|
6 |
+
*/
|
7 |
+
/**
|
8 |
+
* Rara One Click Demo Import class, so we don't have to worry about namespaces.
|
9 |
+
*/
|
10 |
+
class RRDI_Theme_Demo_Import {
|
11 |
+
|
12 |
+
public $demo_config;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Demo packages.
|
16 |
+
*
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
public $demo_packages;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Demo installer.
|
23 |
+
*
|
24 |
+
* @var bool
|
25 |
+
*/
|
26 |
+
public $demo_installer = true;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Define allowed authors for theme demo import.
|
30 |
+
*
|
31 |
+
* @var array
|
32 |
+
*/
|
33 |
+
public $rrdi_allowed_authors_uris = array( 'https://raratheme.com/', 'https://rarathemes.com/', 'https://wptravelengine.com' );
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var $instance the reference to *Singleton* instance of this class
|
37 |
+
*/
|
38 |
+
private static $instance;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Private variables used throughout the plugin.
|
42 |
+
*/
|
43 |
+
private $importer, $plugin_page, $import_files, $logger, $log_file_path, $selected_index, $selected_import_files, $microtime, $frontend_error_messages, $ajax_call_number;
|
44 |
+
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Returns the *Singleton* instance of this class.
|
48 |
+
*
|
49 |
+
* @return Theme_Demo_Import the *Singleton* instance.
|
50 |
+
*/
|
51 |
+
public static function Instance() {
|
52 |
+
if ( null === static::$instance ) {
|
53 |
+
static::$instance = new static();
|
54 |
+
}
|
55 |
+
|
56 |
+
return static::$instance;
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Class construct function, to initiate the plugin.
|
62 |
+
* Protected constructor to prevent creating a new instance of the
|
63 |
+
* *Singleton* via the `new` operator from outside of this class.
|
64 |
+
*/
|
65 |
+
protected function __construct() {
|
66 |
+
require RRDI_PATH . 'includes/class-rrdi-include-files.php';
|
67 |
+
// Actions.
|
68 |
+
|
69 |
+
$this->includes();
|
70 |
+
|
71 |
+
add_action( 'init', array( $this, 'setup' ), 5 );
|
72 |
+
$get_theme = wp_get_theme();
|
73 |
+
|
74 |
+
if ( $this->is_valid_theme_author() ) {
|
75 |
+
|
76 |
+
add_action( 'admin_menu', array( $this, 'create_plugin_page' ) );
|
77 |
+
|
78 |
+
}
|
79 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
80 |
+
add_action( 'wp_ajax_rrdi_import_demo_data', array( $this, 'rrdi_import_demo_data_ajax_callback' ) );
|
81 |
+
add_action( 'init', array( $this, 'setup_plugin_with_filter_data' ) );
|
82 |
+
add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
|
83 |
+
// AJAX Events to import demo and dismiss notice.
|
84 |
+
add_action( 'wp_ajax_dismiss-notice', array( $this, 'ajax_dismiss_notice' ) );
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Check if theme author is valid to use demo importer.
|
89 |
+
*
|
90 |
+
* @return boolean
|
91 |
+
*/
|
92 |
+
public function is_valid_theme_author() {
|
93 |
+
|
94 |
+
$allowed_authors = apply_filters( 'rrdi_valid_theme_author_uris', $this->rrdi_allowed_authors_uris );
|
95 |
+
$theme_data = wp_get_theme();
|
96 |
+
|
97 |
+
$allowed_urls = array_map( 'parse_url', $allowed_authors );
|
98 |
+
$allowed_hosts = array_column( $allowed_urls, 'host' );
|
99 |
+
$theme_author_url = parse_url( $theme_data->get( 'AuthorURI' ) );
|
100 |
+
|
101 |
+
return in_array( $theme_author_url['host'], $allowed_hosts );
|
102 |
+
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Demo importer setup.
|
107 |
+
*/
|
108 |
+
public function setup() {
|
109 |
+
$this->demo_config = apply_filters( 'rara_demo_importer_config', array() );
|
110 |
+
$this->demo_packages = apply_filters( 'rara_demo_importer_packages', array() );
|
111 |
+
$this->demo_installer = apply_filters( 'rara_demo_importer_installer', true );
|
112 |
+
}
|
113 |
+
|
114 |
+
|
115 |
+
function getNewestDir( $path ) {
|
116 |
+
$working_dir = getcwd();
|
117 |
+
chdir( $path ); // chdir to requested dir
|
118 |
+
$ret_val = false;
|
119 |
+
if ( $p = opendir( $path ) ) {
|
120 |
+
while ( false !== ( $file = readdir( $p ) ) ) {
|
121 |
+
if ( $file[0] != '.' && is_dir( $file ) ) {
|
122 |
+
$list[] = date( 'YmdHis', filemtime( $path . '/' . $file ) ) . $path . '/' . $file;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
if ( isset( $list ) ) {
|
126 |
+
rsort( $list );
|
127 |
+
$ret_val = $list[0];
|
128 |
+
}
|
129 |
+
}
|
130 |
+
chdir( $working_dir ); // chdir back to script's dir
|
131 |
+
return $ret_val;
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Includes.
|
136 |
+
*/
|
137 |
+
private function includes() {
|
138 |
+
|
139 |
+
$get_theme = wp_get_theme();
|
140 |
+
|
141 |
+
if ( $this->is_valid_theme_author() ) {
|
142 |
+
|
143 |
+
$td = $get_theme->get( 'TextDomain' ) . '-demo-content';
|
144 |
+
if ( strpos( $td, 'pro' ) === false ) {
|
145 |
+
$upload_dir = wp_upload_dir();
|
146 |
+
// Check the folder contains at least 1 valid demo config.
|
147 |
+
$path = $upload_dir['basedir'] . '/rara-demo-pack/';
|
148 |
+
$files = $path . $td . '/import-hooks.php';
|
149 |
+
if ( file_exists( $files ) && is_readable( $files ) ) {
|
150 |
+
include $files;
|
151 |
+
}
|
152 |
+
}
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Private clone method to prevent cloning of the instance of the *Singleton* instance.
|
158 |
+
*
|
159 |
+
* @return void
|
160 |
+
*/
|
161 |
+
private function __clone() {}
|
162 |
+
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Private unserialize method to prevent unserializing of the *Singleton* instance.
|
166 |
+
*
|
167 |
+
* @return void
|
168 |
+
*/
|
169 |
+
public function __wakeup() {}
|
170 |
+
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Creates the plugin page and a submenu item in WP Appearance menu.
|
174 |
+
*/
|
175 |
+
public function create_plugin_page() {
|
176 |
+
$plugin_page_setup = apply_filters(
|
177 |
+
'rrdi/plugin_page_setup',
|
178 |
+
array(
|
179 |
+
'parent_slug' => 'themes.php',
|
180 |
+
'page_title' => esc_html__( 'Rara One Click Demo Import', 'rara-one-click-demo-import' ),
|
181 |
+
'menu_title' => esc_html__( 'Rara Demo Import', 'rara-one-click-demo-import' ),
|
182 |
+
'capability' => 'import',
|
183 |
+
'menu_slug' => 'rara-demo-import',
|
184 |
+
)
|
185 |
+
);
|
186 |
+
|
187 |
+
$this->plugin_page = add_submenu_page( $plugin_page_setup['parent_slug'], $plugin_page_setup['page_title'], $plugin_page_setup['menu_title'], $plugin_page_setup['capability'], $plugin_page_setup['menu_slug'], array( $this, 'display_plugin_page' ) );
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Settings Tabs.
|
192 |
+
*
|
193 |
+
* @since 1.0.4
|
194 |
+
*/
|
195 |
+
function rrdi_settings_option_tabs() {
|
196 |
+
|
197 |
+
$options = array(
|
198 |
+
'Before_You_Begin' => 'intro.php',
|
199 |
+
'Demo_Import' => 'welcome.php',
|
200 |
+
'Pro_Theme_Demo_Import' => 'installed-demos.php',
|
201 |
+
);
|
202 |
+
$options = apply_filters( 'rrdi_settings_option_tabs', $options );
|
203 |
+
return $options;
|
204 |
+
}
|
205 |
+
|
206 |
+
private function rddi_upload_demo_pack() {
|
207 |
+
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
208 |
+
|
209 |
+
if ( ! current_user_can( 'upload_files' ) ) {
|
210 |
+
wp_die( __( 'Sorry, you are not allowed to install demo on this site.', 'rara-one-click-demo-import' ) );
|
211 |
+
}
|
212 |
+
|
213 |
+
check_admin_referer( 'demo-upload' );
|
214 |
+
|
215 |
+
$file_upload = new File_Upload_Upgrader( 'demozip', 'package' );
|
216 |
+
|
217 |
+
$title = sprintf( __( 'Installing Demo from uploaded file: %s', 'rara-one-click-demo-import' ), esc_html( basename( $file_upload->filename ) ) );
|
218 |
+
$nonce = 'demo-upload';
|
219 |
+
$url = add_query_arg( array( 'package' => $file_upload->id ), 'themes.php?page=demo-importer&action=upload-demo' );
|
220 |
+
$type = 'upload'; // Install demo type, From Web or an Upload.
|
221 |
+
|
222 |
+
// Demo Upgrader Class.
|
223 |
+
include_once dirname( __FILE__ ) . '/vendor/class-demo-upgrader.php';
|
224 |
+
include_once dirname( __FILE__ ) . '/vendor/class-demo-installer-skin.php';
|
225 |
+
|
226 |
+
$upgrader = new RDDI_Demo_Upgrader( new RDDI_Demo_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) );
|
227 |
+
$result = $upgrader->install( $file_upload->package );
|
228 |
+
|
229 |
+
if ( $result || is_wp_error( $result ) ) {
|
230 |
+
$file_upload->cleanup();
|
231 |
+
}
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Plugin page display.
|
236 |
+
*/
|
237 |
+
public function display_plugin_page() {
|
238 |
+
if ( isset( $_GET['action'] ) && 'upload-demo' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
239 |
+
$this->rddi_upload_demo_pack();
|
240 |
+
} else { ?>
|
241 |
+
<div class="wrap">
|
242 |
+
<h1>
|
243 |
+
<?php
|
244 |
+
esc_html_e( 'RARA Demo Import', 'rara-one-click-demo-import' );
|
245 |
+
if ( current_user_can( 'upload_files' ) ) {
|
246 |
+
echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js tg-demo-upload" aria-expanded="false">' . __( 'Upload Demo File', 'rara-one-click-demo-import' ) . '</button>';
|
247 |
+
}
|
248 |
+
?>
|
249 |
+
</h1>
|
250 |
+
<div id="tabs-container">
|
251 |
+
<div class="tab">
|
252 |
+
<ul class="tabs-menu">
|
253 |
+
<?php
|
254 |
+
$settings_tab = $this->rrdi_settings_option_tabs();
|
255 |
+
$count = 0;
|
256 |
+
foreach ( $settings_tab as $key => $value ) {
|
257 |
+
$tab_label = preg_replace( '/_/', ' ', $key );
|
258 |
+
?>
|
259 |
+
<li
|
260 |
+
<?php
|
261 |
+
if ( $count == 0 ) {
|
262 |
+
?>
|
263 |
+
class="current"<?php } ?>><a href="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $tab_label ); ?></a></li>
|
264 |
+
<?php
|
265 |
+
$count++;
|
266 |
+
}
|
267 |
+
?>
|
268 |
+
</ul>
|
269 |
+
<?php
|
270 |
+
$counter = 0;
|
271 |
+
foreach ( $settings_tab as $key => $value ) {
|
272 |
+
?>
|
273 |
+
<div id="<?php echo esc_attr( $key ); ?>" class="tab-content"
|
274 |
+
<?php
|
275 |
+
if ( $counter == 0 ) {
|
276 |
+
?>
|
277 |
+
style="display: block;" <?php } ?>>
|
278 |
+
<?php
|
279 |
+
include_once RRDI_PATH . '/includes/settings/' . strtolower( $value );
|
280 |
+
?>
|
281 |
+
</div>
|
282 |
+
<?php $counter++; } ?>
|
283 |
+
</div>
|
284 |
+
</div>
|
285 |
+
</div>
|
286 |
+
<?php
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
private function prepare_demos_for_js( $demos = null ) {
|
291 |
+
$prepared_demos = array();
|
292 |
+
$current_template = get_option( 'template' );
|
293 |
+
$demo_imported_id = get_option( 'rara_demo_imported_id' );
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Filters demo data before it is prepared for JavaScript.
|
297 |
+
*
|
298 |
+
* @param array $prepared_demos An associative array of demo data. Default empty array.
|
299 |
+
* @param null|array $demos An array of demo config to prepare, if any.
|
300 |
+
* @param string $demo_imported_id The current demo imported id.
|
301 |
+
*/
|
302 |
+
$prepared_demos = (array) apply_filters( 'rara_demo_importer_pre_prepare_demos_for_js', array(), $demos, $demo_imported_id );
|
303 |
+
|
304 |
+
if ( ! empty( $prepared_demos ) ) {
|
305 |
+
return $prepared_demos;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Make sure the imported demo is listed first.
|
309 |
+
if ( isset( $demos[ $demo_imported_id ] ) ) {
|
310 |
+
$prepared_demos[ $demo_imported_id ] = array();
|
311 |
+
}
|
312 |
+
|
313 |
+
if ( ! empty( $demos ) ) {
|
314 |
+
foreach ( $demos as $demo_id => $demo_data ) {
|
315 |
+
$demo_notices = array();
|
316 |
+
$encoded_slug = urlencode( $demo_id );
|
317 |
+
$demo_package = isset( $demo_data['demo_pack'] ) ? $demo_data['demo_pack'] : false;
|
318 |
+
$plugins_list = isset( $demo_data['plugins_list'] ) ? $demo_data['plugins_list'] : array();
|
319 |
+
|
320 |
+
// Plugins status.
|
321 |
+
foreach ( $plugins_list as $plugin => $plugin_data ) {
|
322 |
+
$plugins_list[ $plugin ]['is_active'] = is_plugin_active( $plugin_data['slug'] );
|
323 |
+
}
|
324 |
+
|
325 |
+
// Add demo notices.
|
326 |
+
if ( isset( $demo_data['template'] ) && $current_template !== $demo_data['template'] ) {
|
327 |
+
$demo_notices['required_theme'] = true;
|
328 |
+
} elseif ( wp_list_filter(
|
329 |
+
$plugins_list,
|
330 |
+
array(
|
331 |
+
'required' => true,
|
332 |
+
'is_active' => false,
|
333 |
+
)
|
334 |
+
) ) {
|
335 |
+
$demo_notices['required_plugins'] = true;
|
336 |
+
}
|
337 |
+
|
338 |
+
// Prepare all demos.
|
339 |
+
$prepared_demos[ $demo_id ] = array(
|
340 |
+
'id' => $demo_id,
|
341 |
+
'name' => $demo_data['name'],
|
342 |
+
'theme' => $demo_data['theme'],
|
343 |
+
'package' => $demo_package,
|
344 |
+
'screenshot' => $this->import_file_url( $demo_id, 'screenshot.jpg' ),
|
345 |
+
'description' => isset( $demo_data['description'] ) ? $demo_data['description'] : '',
|
346 |
+
'author' => isset( $demo_data['author'] ) ? $demo_data['author'] : __( 'rara', 'rara-one-click-demo-import' ),
|
347 |
+
'authorAndUri' => '<a href="http://rara.com" target="_blank">rara</a>',
|
348 |
+
'version' => isset( $demo_data['version'] ) ? $demo_data['version'] : '1.1.0',
|
349 |
+
'active' => $demo_id === $demo_imported_id,
|
350 |
+
'hasNotice' => $demo_notices,
|
351 |
+
'plugins' => $plugins_list,
|
352 |
+
'actions' => array(
|
353 |
+
'preview' => home_url( '/' ),
|
354 |
+
'demo_url' => $demo_data['demo_url'],
|
355 |
+
'delete' => current_user_can( 'upload_files' ) ? wp_nonce_url( admin_url( 'themes.php?page=demo-importer&browse=uploads&action=delete&demo_pack=' . urlencode( $demo_id ) ), 'delete-demo_' . $demo_id ) : null,
|
356 |
+
),
|
357 |
+
);
|
358 |
+
}
|
359 |
+
}
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Filters the demos prepared for JavaScript.
|
363 |
+
*
|
364 |
+
* Could be useful for changing the order, which is by name by default.
|
365 |
+
*
|
366 |
+
* @param array $prepared_demos Array of demos.
|
367 |
+
*/
|
368 |
+
$prepared_demos = apply_filters( 'rara_demo_importer_prepare_demos_for_js', $prepared_demos );
|
369 |
+
$prepared_demos = array_values( $prepared_demos );
|
370 |
+
return array_filter( $prepared_demos );
|
371 |
+
}
|
372 |
+
/**
|
373 |
+
* Enqueue admin scripts (JS and CSS)
|
374 |
+
*
|
375 |
+
* @param string $hook holds info on which admin page you are currently loading.
|
376 |
+
*/
|
377 |
+
public function admin_enqueue_scripts( $hook ) {
|
378 |
+
|
379 |
+
// Enqueue the scripts only on the plugin page.
|
380 |
+
if ( $this->plugin_page === $hook ) {
|
381 |
+
wp_enqueue_script( 'rrdi-main-js', RRDI_URL . 'assets/js/script.js', array( 'jquery', 'jquery-form' ), RRDI_VERSION );
|
382 |
+
|
383 |
+
wp_localize_script(
|
384 |
+
'rrdi-main-js',
|
385 |
+
'rrdi',
|
386 |
+
array(
|
387 |
+
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
388 |
+
'ajax_nonce' => wp_create_nonce( 'rrdi-ajax-verification' ),
|
389 |
+
'import_files' => $this->import_files,
|
390 |
+
'texts' => array(
|
391 |
+
'missing_preview_image' => esc_html__( 'No preview image defined for this import.', 'rara-one-click-demo-import' ),
|
392 |
+
),
|
393 |
+
)
|
394 |
+
);
|
395 |
+
wp_enqueue_style( 'rrdi-main-css', RRDI_URL . 'assets/css/style.css', array(), RRDI_VERSION );
|
396 |
+
}
|
397 |
+
}
|
398 |
+
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Main AJAX callback function for:
|
402 |
+
* 1. prepare import files (uploaded or predefined via filters)
|
403 |
+
* 2. import content
|
404 |
+
* 3. before widgets import setup (optional)
|
405 |
+
* 4. import widgets (optional)
|
406 |
+
* 5. import customizer options (optional)
|
407 |
+
* 6. after import setup (optional)
|
408 |
+
*/
|
409 |
+
public function rrdi_import_demo_data_ajax_callback() {
|
410 |
+
|
411 |
+
// Try to update PHP memory limit (so that it does not run out of it).
|
412 |
+
ini_set( 'memory_limit', apply_filters( 'rrdi/import_memory_limit', '350M' ) );
|
413 |
+
|
414 |
+
// Verify if the AJAX call is valid (checks nonce and current_user_can).
|
415 |
+
RRDI_Helpers::verify_ajax_call();
|
416 |
+
|
417 |
+
// Is this a new AJAX call to continue the previous import?
|
418 |
+
$use_existing_importer_data = $this->get_importer_data();
|
419 |
+
|
420 |
+
if ( ! $use_existing_importer_data ) {
|
421 |
+
|
422 |
+
// Set the AJAX call number.
|
423 |
+
$this->ajax_call_number = empty( $this->ajax_call_number ) ? 0 : $this->ajax_call_number;
|
424 |
+
|
425 |
+
// Error messages displayed on front page.
|
426 |
+
$this->frontend_error_messages = '';
|
427 |
+
|
428 |
+
// Create a date and time string to use for demo and log file names.
|
429 |
+
$demo_import_start_time = date( apply_filters( 'rrdi/date_format_for_file_names', 'Y-m-d__H-i-s' ) );
|
430 |
+
|
431 |
+
// Define log file path.
|
432 |
+
$this->log_file_path = RRDI_Helpers::get_log_path( $demo_import_start_time );
|
433 |
+
|
434 |
+
// Get selected file index or set it to 0.
|
435 |
+
$this->selected_index = empty( $_POST['selected'] ) ? 0 : absint( $_POST['selected'] );
|
436 |
+
|
437 |
+
/**
|
438 |
+
* 1. Prepare import files.
|
439 |
+
* Manually uploaded import files or predefined import files via filter: rrdi/import_files
|
440 |
+
*/
|
441 |
+
if ( ! empty( $_FILES ) ) { // Using manual file uploads?
|
442 |
+
|
443 |
+
// Get paths for the uploaded files.
|
444 |
+
$this->selected_import_files = RRDI_Helpers::process_uploaded_files( $_FILES, $this->log_file_path );
|
445 |
+
|
446 |
+
// Set the name of the import files, because we used the uploaded files.
|
447 |
+
$this->import_files[ $this->selected_index ]['import_file_name'] = esc_html__( 'Manually uploaded files', 'rara-one-click-demo-import' );
|
448 |
+
} elseif ( ! empty( $this->import_files[ $this->selected_index ] ) ) { // Use predefined import files from wp filter: rrdi/import_files.
|
449 |
+
|
450 |
+
// Download the import files (content and widgets files) and save it to variable for later use.
|
451 |
+
$this->selected_import_files = RRDI_Helpers::download_import_files(
|
452 |
+
$this->import_files[ $this->selected_index ],
|
453 |
+
$demo_import_start_time
|
454 |
+
);
|
455 |
+
|
456 |
+
// Check Errors.
|
457 |
+
if ( is_wp_error( $this->selected_import_files ) ) {
|
458 |
+
|
459 |
+
// Write error to log file and send an AJAX response with the error.
|
460 |
+
RRDI_Helpers::log_error_and_send_ajax_response(
|
461 |
+
$this->selected_import_files->get_error_message(),
|
462 |
+
$this->log_file_path,
|
463 |
+
esc_html__( 'Downloaded files', 'rara-one-click-demo-import' )
|
464 |
+
);
|
465 |
+
}
|
466 |
+
|
467 |
+
// Add this message to log file.
|
468 |
+
$log_added = RRDI_Helpers::append_to_file(
|
469 |
+
sprintf(
|
470 |
+
__( 'The import files for: %s were successfully downloaded!', 'rara-one-click-demo-import' ),
|
471 |
+
$this->import_files[ $this->selected_index ]['import_file_name']
|
472 |
+
) . RRDI_Helpers::import_file_info( $this->selected_import_files ),
|
473 |
+
$this->log_file_path,
|
474 |
+
esc_html__( 'Downloaded files', 'rara-one-click-demo-import' )
|
475 |
+
);
|
476 |
+
} else {
|
477 |
+
|
478 |
+
// Send JSON Error response to the AJAX call.
|
479 |
+
wp_send_json( esc_html__( 'No import files specified!', 'rara-one-click-demo-import' ) );
|
480 |
+
}
|
481 |
+
}
|
482 |
+
|
483 |
+
/**
|
484 |
+
* 2. Import content.
|
485 |
+
* Returns any errors greater then the "error" logger level, that will be displayed on front page.
|
486 |
+
*/
|
487 |
+
$this->frontend_error_messages .= $this->import_content( $this->selected_import_files['content'] );
|
488 |
+
|
489 |
+
/**
|
490 |
+
* 3. Before widgets import setup.
|
491 |
+
*/
|
492 |
+
$action = 'rrdi/before_widgets_import';
|
493 |
+
if ( ( false !== has_action( $action ) ) && empty( $this->frontend_error_messages ) ) {
|
494 |
+
|
495 |
+
// Run the before_widgets_import action to setup other settings.
|
496 |
+
$this->do_import_action( $action, $this->import_files[ $this->selected_index ] );
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* 4. Import widgets.
|
501 |
+
*/
|
502 |
+
if ( ! empty( $this->selected_import_files['widgets'] ) && empty( $this->frontend_error_messages ) ) {
|
503 |
+
$this->import_widgets( $this->selected_import_files['widgets'] );
|
504 |
+
}
|
505 |
+
|
506 |
+
/**
|
507 |
+
* 5. Import customize options.
|
508 |
+
*/
|
509 |
+
if ( ! empty( $this->selected_import_files['customizer'] ) && empty( $this->frontend_error_messages ) ) {
|
510 |
+
$this->import_customizer( $this->selected_import_files['customizer'] );
|
511 |
+
}
|
512 |
+
|
513 |
+
/**
|
514 |
+
* 6. After import setup.
|
515 |
+
*/
|
516 |
+
$action = 'rrdi/after_import';
|
517 |
+
if ( ( false !== has_action( $action ) ) && empty( $this->frontend_error_messages ) ) {
|
518 |
+
|
519 |
+
// Run the after_import action to setup other settings.
|
520 |
+
$this->do_import_action( $action, $this->import_files[ $this->selected_index ] );
|
521 |
+
}
|
522 |
+
|
523 |
+
// Display final messages (success or error messages).
|
524 |
+
if ( empty( $this->frontend_error_messages ) ) {
|
525 |
+
$response['message'] = sprintf(
|
526 |
+
__( '%1$s%3$sCompleted Successfully!%4$s%2$sThe process has finished. Please check your page and make sure that everything has been imported correctly. If you want, you can now deactivate the %3$sRara One Click Demo Import%4$s plugin.%5$s', 'rara-one-click-demo-import' ),
|
527 |
+
'<div class="notice notice-success"><p>',
|
528 |
+
'<br>',
|
529 |
+
'<strong>',
|
530 |
+
'</strong>',
|
531 |
+
'</p></div>'
|
532 |
+
);
|
533 |
+
} else {
|
534 |
+
$response['message'] = $this->frontend_error_messages . '<br>';
|
535 |
+
$response['message'] .= sprintf(
|
536 |
+
__( '%1$sUnfortunately, demo import has finished with some errors.%2$sMore details about the errors can be found in this %3$s%5$slog file%6$s%4$s%7$s', 'rara-one-click-demo-import' ),
|
537 |
+
'<div class="notice notice-error"><p>',
|
538 |
+
'<br>',
|
539 |
+
'<strong>',
|
540 |
+
'</strong>',
|
541 |
+
'<a href="' . RRDI_Helpers::get_log_url( $this->log_file_path ) . '" target="_blank">',
|
542 |
+
'</a>',
|
543 |
+
'</p></div>'
|
544 |
+
);
|
545 |
+
}
|
546 |
+
|
547 |
+
wp_send_json( $response );
|
548 |
+
}
|
549 |
+
|
550 |
+
|
551 |
+
/**
|
552 |
+
* Import content from an WP XML file.
|
553 |
+
*
|
554 |
+
* @param string $import_file_path path to the import file.
|
555 |
+
*/
|
556 |
+
private function import_content( $import_file_path ) {
|
557 |
+
|
558 |
+
$this->microtime = microtime( true );
|
559 |
+
|
560 |
+
// This should be replaced with multiple AJAX calls (import in smaller chunks)
|
561 |
+
// so that it would not come to the Internal Error, because of the PHP script timeout.
|
562 |
+
// Also this function has no effect when PHP is running in safe mode
|
563 |
+
// http://php.net/manual/en/function.set-time-limit.php.
|
564 |
+
// Increase PHP max execution time. Just in case, even though the AJAX calls are only 25 sec long.
|
565 |
+
if ( strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) === false ) {
|
566 |
+
set_time_limit( apply_filters( 'rrdi/set_time_limit_for_demo_data_import', 300 ) );
|
567 |
+
}
|
568 |
+
|
569 |
+
// Disable import of authors.
|
570 |
+
add_filter( 'wxr_importer.pre_process.user', '__return_false' );
|
571 |
+
|
572 |
+
// Check, if we need to send another AJAX request and set the importing author to the current user.
|
573 |
+
add_filter( 'wxr_importer.pre_process.post', array( $this, 'new_ajax_request_maybe' ) );
|
574 |
+
|
575 |
+
// Disables generation of multiple image sizes (thumbnails) in the content import step.
|
576 |
+
if ( ! apply_filters( 'rrdi/regenerate_thumbnails_in_content_import', true ) ) {
|
577 |
+
add_filter(
|
578 |
+
'intermediate_image_sizes_advanced',
|
579 |
+
function() {
|
580 |
+
return null;
|
581 |
+
}
|
582 |
+
);
|
583 |
+
}
|
584 |
+
|
585 |
+
// Import content.
|
586 |
+
if ( ! empty( $import_file_path ) ) {
|
587 |
+
ob_start();
|
588 |
+
$this->importer->import( $import_file_path );
|
589 |
+
$message = ob_get_clean();
|
590 |
+
|
591 |
+
// Add this message to log file.
|
592 |
+
$log_added = RRDI_Helpers::append_to_file(
|
593 |
+
$message . PHP_EOL . esc_html__( 'Max execution time after content import = ', 'rara-one-click-demo-import' ) . ini_get( 'max_execution_time' ),
|
594 |
+
$this->log_file_path,
|
595 |
+
esc_html__( 'Importing content', 'rara-one-click-demo-import' )
|
596 |
+
);
|
597 |
+
}
|
598 |
+
|
599 |
+
// Delete content importer data for current import from DB.
|
600 |
+
delete_transient( 'RRDI_importer_data' );
|
601 |
+
|
602 |
+
// Return any error messages for the front page output (errors, critical, alert and emergency level messages only).
|
603 |
+
return $this->logger->error_output;
|
604 |
+
}
|
605 |
+
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Import widgets from WIE or JSON file.
|
609 |
+
*
|
610 |
+
* @param string $widget_import_file_path path to the widget import file.
|
611 |
+
*/
|
612 |
+
private function import_widgets( $widget_import_file_path ) {
|
613 |
+
|
614 |
+
// Widget import results.
|
615 |
+
$results = array();
|
616 |
+
|
617 |
+
// Create an instance of the Widget Importer.
|
618 |
+
$widget_importer = new RRDI_Widget_Importer();
|
619 |
+
|
620 |
+
// Import widgets.
|
621 |
+
if ( ! empty( $widget_import_file_path ) ) {
|
622 |
+
|
623 |
+
// Import widgets and return result.
|
624 |
+
$results = $widget_importer->import_widgets( $widget_import_file_path );
|
625 |
+
}
|
626 |
+
|
627 |
+
// Check for errors.
|
628 |
+
if ( is_wp_error( $results ) ) {
|
629 |
+
|
630 |
+
// Write error to log file and send an AJAX response with the error.
|
631 |
+
RRDI_Helpers::log_error_and_send_ajax_response(
|
632 |
+
$results->get_error_message(),
|
633 |
+
$this->log_file_path,
|
634 |
+
esc_html__( 'Importing widgets', 'rara-one-click-demo-import' )
|
635 |
+
);
|
636 |
+
}
|
637 |
+
|
638 |
+
ob_start();
|
639 |
+
$widget_importer->format_results_for_log( $results );
|
640 |
+
$message = ob_get_clean();
|
641 |
+
|
642 |
+
// Add this message to log file.
|
643 |
+
$log_added = RRDI_Helpers::append_to_file(
|
644 |
+
$message,
|
645 |
+
$this->log_file_path,
|
646 |
+
esc_html__( 'Importing widgets', 'rara-one-click-demo-import' )
|
647 |
+
);
|
648 |
+
}
|
649 |
+
|
650 |
+
|
651 |
+
/**
|
652 |
+
* Import customizer from a DAT file, generated by the Customizer Export/Import plugin.
|
653 |
+
*
|
654 |
+
* @param string $customizer_import_file_path path to the customizer import file.
|
655 |
+
*/
|
656 |
+
private function import_customizer( $customizer_import_file_path ) {
|
657 |
+
|
658 |
+
// Try to import the customizer settings.
|
659 |
+
$results = RRDI_Customizer_Importer::import_customizer_options( $customizer_import_file_path );
|
660 |
+
|
661 |
+
// Check for errors.
|
662 |
+
if ( is_wp_error( $results ) ) {
|
663 |
+
|
664 |
+
// Write error to log file and send an AJAX response with the error.
|
665 |
+
RRDI_Helpers::log_error_and_send_ajax_response(
|
666 |
+
$results->get_error_message(),
|
667 |
+
$this->log_file_path,
|
668 |
+
esc_html__( 'Importing customizer settings', 'rara-one-click-demo-import' )
|
669 |
+
);
|
670 |
+
}
|
671 |
+
|
672 |
+
// Add this message to log file.
|
673 |
+
$log_added = RRDI_Helpers::append_to_file(
|
674 |
+
esc_html__( 'Customizer settings import finished!', 'rara-one-click-demo-import' ),
|
675 |
+
$this->log_file_path,
|
676 |
+
esc_html__( 'Importing customizer settings', 'rara-one-click-demo-import' )
|
677 |
+
);
|
678 |
+
}
|
679 |
+
|
680 |
+
|
681 |
+
/**
|
682 |
+
* Setup other things in the passed wp action.
|
683 |
+
*
|
684 |
+
* @param string $action the action name to be executed.
|
685 |
+
* @param array $selected_import with information about the selected import.
|
686 |
+
*/
|
687 |
+
private function do_import_action( $action, $selected_import ) {
|
688 |
+
|
689 |
+
ob_start();
|
690 |
+
do_action( $action, $selected_import );
|
691 |
+
$message = ob_get_clean();
|
692 |
+
|
693 |
+
// Add this message to log file.
|
694 |
+
$log_added = RRDI_Helpers::append_to_file(
|
695 |
+
$message,
|
696 |
+
$this->log_file_path,
|
697 |
+
$action
|
698 |
+
);
|
699 |
+
}
|
700 |
+
|
701 |
+
|
702 |
+
/**
|
703 |
+
* Check if we need to create a new AJAX request, so that server does not timeout.
|
704 |
+
*
|
705 |
+
* @param array $data current post data.
|
706 |
+
* @return array
|
707 |
+
*/
|
708 |
+
public function new_ajax_request_maybe( $data ) {
|
709 |
+
$time = microtime( true ) - $this->microtime;
|
710 |
+
|
711 |
+
// We should make a new ajax call, if the time is right.
|
712 |
+
if ( $time > apply_filters( 'rrdi/time_for_one_ajax_call', 25 ) ) {
|
713 |
+
$this->ajax_call_number++;
|
714 |
+
$this->set_importer_data();
|
715 |
+
|
716 |
+
$response = array(
|
717 |
+
'status' => 'newAJAX',
|
718 |
+
'message' => 'New AJAX request!: ' . $time,
|
719 |
+
);
|
720 |
+
|
721 |
+
// Add any output to the log file and clear the buffers.
|
722 |
+
$message = ob_get_clean();
|
723 |
+
|
724 |
+
// Add message to log file.
|
725 |
+
$log_added = RRDI_Helpers::append_to_file(
|
726 |
+
__( 'Completed AJAX call number: ', 'rara-one-click-demo-import' ) . $this->ajax_call_number . PHP_EOL . $message,
|
727 |
+
$this->log_file_path,
|
728 |
+
''
|
729 |
+
);
|
730 |
+
|
731 |
+
wp_send_json( $response );
|
732 |
+
}
|
733 |
+
|
734 |
+
// Set importing author to the current user.
|
735 |
+
// Fixes the [WARNING] Could not find the author for ... log warning messages.
|
736 |
+
$current_user_obj = wp_get_current_user();
|
737 |
+
$data['post_author'] = $current_user_obj->user_login;
|
738 |
+
|
739 |
+
return $data;
|
740 |
+
}
|
741 |
+
|
742 |
+
/**
|
743 |
+
* Set current state of the content importer, so we can continue the import with new AJAX request.
|
744 |
+
*/
|
745 |
+
private function set_importer_data() {
|
746 |
+
$data = array(
|
747 |
+
'frontend_error_messages' => $this->frontend_error_messages,
|
748 |
+
'ajax_call_number' => $this->ajax_call_number,
|
749 |
+
'log_file_path' => $this->log_file_path,
|
750 |
+
'selected_index' => $this->selected_index,
|
751 |
+
'selected_import_files' => $this->selected_import_files,
|
752 |
+
);
|
753 |
+
|
754 |
+
$data = array_merge( $data, $this->importer->get_importer_data() );
|
755 |
+
|
756 |
+
set_transient( 'RRDI_importer_data', $data, 0.5 * HOUR_IN_SECONDS );
|
757 |
+
}
|
758 |
+
|
759 |
+
/**
|
760 |
+
* Get content importer data, so we can continue the import with this new AJAX request.
|
761 |
+
*/
|
762 |
+
private function get_importer_data() {
|
763 |
+
if ( $data = get_transient( 'RRDI_importer_data' ) ) {
|
764 |
+
$this->frontend_error_messages = empty( $data['frontend_error_messages'] ) ? '' : $data['frontend_error_messages'];
|
765 |
+
$this->ajax_call_number = empty( $data['ajax_call_number'] ) ? 1 : $data['ajax_call_number'];
|
766 |
+
$this->log_file_path = empty( $data['log_file_path'] ) ? '' : $data['log_file_path'];
|
767 |
+
$this->selected_index = empty( $data['selected_index'] ) ? 0 : $data['selected_index'];
|
768 |
+
$this->selected_import_files = empty( $data['selected_import_files'] ) ? array() : $data['selected_import_files'];
|
769 |
+
$this->importer->set_importer_data( $data );
|
770 |
+
|
771 |
+
return true;
|
772 |
+
}
|
773 |
+
return false;
|
774 |
+
}
|
775 |
+
|
776 |
+
/**
|
777 |
+
* Load the plugin textdomain, so that translations can be made.
|
778 |
+
*/
|
779 |
+
public function load_textdomain() {
|
780 |
+
load_plugin_textdomain( 'rara-one-click-demo-import', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
|
781 |
+
}
|
782 |
+
|
783 |
+
|
784 |
+
/**
|
785 |
+
* Get data from filters, after the theme has loaded and instantiate the importer.
|
786 |
+
*/
|
787 |
+
public function setup_plugin_with_filter_data() {
|
788 |
+
|
789 |
+
// Get info of import data files and filter it.
|
790 |
+
$this->import_files = RRDI_Helpers::validate_import_file_info( apply_filters( 'rrdi/import_files', array() ) );
|
791 |
+
|
792 |
+
// Importer options array.
|
793 |
+
$importer_options = apply_filters(
|
794 |
+
'rrdi/importer_options',
|
795 |
+
array(
|
796 |
+
'fetch_attachments' => true,
|
797 |
+
)
|
798 |
+
);
|
799 |
+
|
800 |
+
// Logger options for the logger used in the importer.
|
801 |
+
$logger_options = apply_filters(
|
802 |
+
'rrdi/logger_options',
|
803 |
+
array(
|
804 |
+
'logger_min_level' => 'warning',
|
805 |
+
)
|
806 |
+
);
|
807 |
+
|
808 |
+
// Configure logger instance and set it to the importer.
|
809 |
+
$this->logger = new RRDI_Logger();
|
810 |
+
$this->logger->min_level = $logger_options['logger_min_level'];
|
811 |
+
|
812 |
+
// Create importer instance with proper parameters.
|
813 |
+
$this->importer = new RRDI_Importer( $importer_options, $this->logger );
|
814 |
+
}
|
815 |
+
}
|
includes/class-rrdi-wxr-importer.php
CHANGED
@@ -1,51 +1,51 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WXR importer class used in the Rara One Click Demo Import plugin.
|
4 |
-
* Needed to extend the RDDI_WXR_Importer class to get/set the importer protected variables,
|
5 |
-
* for use in the multiple AJAX calls.
|
6 |
-
*
|
7 |
-
* @package rara-one-click-demo-import
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Include files.
|
11 |
-
require RRDI_PATH . 'includes/extras/class-wxr-importer.php';
|
12 |
-
|
13 |
-
class RRDI_WXR_Importer extends RDDI_WXR_Importer {
|
14 |
-
|
15 |
-
public function __construct( $options = array() ) {
|
16 |
-
parent::__construct( $options );
|
17 |
-
|
18 |
-
// Set current user to $mapping variable.
|
19 |
-
// Fixes the [WARNING] Could not find the author for ... log warning messages.
|
20 |
-
$current_user_obj = wp_get_current_user();
|
21 |
-
$this->mapping['user_slug'][ $current_user_obj->user_login ] = $current_user_obj->ID;
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Get all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
26 |
-
*/
|
27 |
-
public function get_importer_data() {
|
28 |
-
return array(
|
29 |
-
'mapping' => $this->mapping,
|
30 |
-
'requires_remapping' => $this->requires_remapping,
|
31 |
-
'exists' => $this->exists,
|
32 |
-
'user_slug_override' => $this->user_slug_override,
|
33 |
-
'url_remap' => $this->url_remap,
|
34 |
-
'featured_images' => $this->featured_images,
|
35 |
-
);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Sets all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
40 |
-
*
|
41 |
-
* @param array $data with set variables.
|
42 |
-
*/
|
43 |
-
public function set_importer_data( $data ) {
|
44 |
-
$this->mapping = empty( $data['mapping'] ) ? array() : $data['mapping'];
|
45 |
-
$this->requires_remapping = empty( $data['requires_remapping'] ) ? array() : $data['requires_remapping'];
|
46 |
-
$this->exists = empty( $data['exists'] ) ? array() : $data['exists'];
|
47 |
-
$this->user_slug_override = empty( $data['user_slug_override'] ) ? array() : $data['user_slug_override'];
|
48 |
-
$this->url_remap = empty( $data['url_remap'] ) ? array() : $data['url_remap'];
|
49 |
-
$this->featured_images = empty( $data['featured_images'] ) ? array() : $data['featured_images'];
|
50 |
-
}
|
51 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WXR importer class used in the Rara One Click Demo Import plugin.
|
4 |
+
* Needed to extend the RDDI_WXR_Importer class to get/set the importer protected variables,
|
5 |
+
* for use in the multiple AJAX calls.
|
6 |
+
*
|
7 |
+
* @package rara-one-click-demo-import
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Include files.
|
11 |
+
require RRDI_PATH . 'includes/extras/class-wxr-importer.php';
|
12 |
+
|
13 |
+
class RRDI_WXR_Importer extends RDDI_WXR_Importer {
|
14 |
+
|
15 |
+
public function __construct( $options = array() ) {
|
16 |
+
parent::__construct( $options );
|
17 |
+
|
18 |
+
// Set current user to $mapping variable.
|
19 |
+
// Fixes the [WARNING] Could not find the author for ... log warning messages.
|
20 |
+
$current_user_obj = wp_get_current_user();
|
21 |
+
$this->mapping['user_slug'][ $current_user_obj->user_login ] = $current_user_obj->ID;
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Get all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
26 |
+
*/
|
27 |
+
public function get_importer_data() {
|
28 |
+
return array(
|
29 |
+
'mapping' => $this->mapping,
|
30 |
+
'requires_remapping' => $this->requires_remapping,
|
31 |
+
'exists' => $this->exists,
|
32 |
+
'user_slug_override' => $this->user_slug_override,
|
33 |
+
'url_remap' => $this->url_remap,
|
34 |
+
'featured_images' => $this->featured_images,
|
35 |
+
);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Sets all protected variables from the RDDI_WXR_Importer needed for continuing the import.
|
40 |
+
*
|
41 |
+
* @param array $data with set variables.
|
42 |
+
*/
|
43 |
+
public function set_importer_data( $data ) {
|
44 |
+
$this->mapping = empty( $data['mapping'] ) ? array() : $data['mapping'];
|
45 |
+
$this->requires_remapping = empty( $data['requires_remapping'] ) ? array() : $data['requires_remapping'];
|
46 |
+
$this->exists = empty( $data['exists'] ) ? array() : $data['exists'];
|
47 |
+
$this->user_slug_override = empty( $data['user_slug_override'] ) ? array() : $data['user_slug_override'];
|
48 |
+
$this->url_remap = empty( $data['url_remap'] ) ? array() : $data['url_remap'];
|
49 |
+
$this->featured_images = empty( $data['featured_images'] ) ? array() : $data['featured_images'];
|
50 |
+
}
|
51 |
+
}
|
includes/extras/class-logger-cli.php
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class RDDI_WP_Importer_Logger_CLI extends RDDI_WP_Importer_Logger {
|
4 |
-
public $min_level = 'notice';
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Logs with an arbitrary level.
|
8 |
-
*
|
9 |
-
* @param mixed $level
|
10 |
-
* @param string $message
|
11 |
-
* @param array $context
|
12 |
-
* @return null
|
13 |
-
*/
|
14 |
-
public function log( $level, $message, array $context = array() ) {
|
15 |
-
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
|
16 |
-
return;
|
17 |
-
}
|
18 |
-
|
19 |
-
//phpcs:disable
|
20 |
-
printf(
|
21 |
-
'[%s] %s' . PHP_EOL,
|
22 |
-
strtoupper( $level ),
|
23 |
-
$message
|
24 |
-
);
|
25 |
-
// phpcs:enable
|
26 |
-
}
|
27 |
-
|
28 |
-
public static function level_to_numeric( $level ) {
|
29 |
-
$levels = array(
|
30 |
-
'emergency' => 8,
|
31 |
-
'alert' => 7,
|
32 |
-
'critical' => 6,
|
33 |
-
'error' => 5,
|
34 |
-
'warning' => 4,
|
35 |
-
'notice' => 3,
|
36 |
-
'info' => 2,
|
37 |
-
'debug' => 1,
|
38 |
-
);
|
39 |
-
if ( ! isset( $levels[ $level ] ) ) {
|
40 |
-
return 0;
|
41 |
-
}
|
42 |
-
|
43 |
-
return $levels[ $level ];
|
44 |
-
}
|
45 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class RDDI_WP_Importer_Logger_CLI extends RDDI_WP_Importer_Logger {
|
4 |
+
public $min_level = 'notice';
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Logs with an arbitrary level.
|
8 |
+
*
|
9 |
+
* @param mixed $level
|
10 |
+
* @param string $message
|
11 |
+
* @param array $context
|
12 |
+
* @return null
|
13 |
+
*/
|
14 |
+
public function log( $level, $message, array $context = array() ) {
|
15 |
+
if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
|
19 |
+
//phpcs:disable
|
20 |
+
printf(
|
21 |
+
'[%s] %s' . PHP_EOL,
|
22 |
+
strtoupper( $level ),
|
23 |
+
$message
|
24 |
+
);
|
25 |
+
// phpcs:enable
|
26 |
+
}
|
27 |
+
|
28 |
+
public static function level_to_numeric( $level ) {
|
29 |
+
$levels = array(
|
30 |
+
'emergency' => 8,
|
31 |
+
'alert' => 7,
|
32 |
+
'critical' => 6,
|
33 |
+
'error' => 5,
|
34 |
+
'warning' => 4,
|
35 |
+
'notice' => 3,
|
36 |
+
'info' => 2,
|
37 |
+
'debug' => 1,
|
38 |
+
);
|
39 |
+
if ( ! isset( $levels[ $level ] ) ) {
|
40 |
+
return 0;
|
41 |
+
}
|
42 |
+
|
43 |
+
return $levels[ $level ];
|
44 |
+
}
|
45 |
+
}
|
includes/extras/class-logger.php
CHANGED
@@ -1,136 +1,136 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Describes a logger instance
|
5 |
-
*
|
6 |
-
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
|
7 |
-
*
|
8 |
-
* The message MUST be a string or object implementing __toString().
|
9 |
-
*
|
10 |
-
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
-
* will be replaced by the context data in key "foo".
|
12 |
-
*
|
13 |
-
* The context array can contain arbitrary data, the only assumption that
|
14 |
-
* can be made by implementors is that if an Exception instance is given
|
15 |
-
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
-
*
|
17 |
-
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
-
* for the full interface specification.
|
19 |
-
*/
|
20 |
-
class RDDI_WP_Importer_Logger {
|
21 |
-
/**
|
22 |
-
* System is unusable.
|
23 |
-
*
|
24 |
-
* @param string $message
|
25 |
-
* @param array $context
|
26 |
-
* @return null
|
27 |
-
*/
|
28 |
-
public function emergency( $message, array $context = array() ) {
|
29 |
-
return $this->log( 'emergency', $message, $context );
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Action must be taken immediately.
|
34 |
-
*
|
35 |
-
* Example: Entire website down, database unavailable, etc. This should
|
36 |
-
* trigger the SMS alerts and wake you up.
|
37 |
-
*
|
38 |
-
* @param string $message
|
39 |
-
* @param array $context
|
40 |
-
* @return null
|
41 |
-
*/
|
42 |
-
public function alert( $message, array $context = array() ) {
|
43 |
-
return $this->log( 'alert', $message, $context );
|
44 |
-
}
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Critical conditions.
|
48 |
-
*
|
49 |
-
* Example: Application component unavailable, unexpected exception.
|
50 |
-
*
|
51 |
-
* @param string $message
|
52 |
-
* @param array $context
|
53 |
-
* @return null
|
54 |
-
*/
|
55 |
-
public function critical( $message, array $context = array() ) {
|
56 |
-
return $this->log( 'critical', $message, $context );
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Runtime errors that do not require immediate action but should typically
|
61 |
-
* be logged and monitored.
|
62 |
-
*
|
63 |
-
* @param string $message
|
64 |
-
* @param array $context
|
65 |
-
* @return null
|
66 |
-
*/
|
67 |
-
public function error( $message, array $context = array()) {
|
68 |
-
return $this->log( 'error', $message, $context );
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Exceptional occurrences that are not errors.
|
73 |
-
*
|
74 |
-
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
75 |
-
* that are not necessarily wrong.
|
76 |
-
*
|
77 |
-
* @param string $message
|
78 |
-
* @param array $context
|
79 |
-
* @return null
|
80 |
-
*/
|
81 |
-
public function warning( $message, array $context = array() ) {
|
82 |
-
return $this->log( 'warning', $message, $context );
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Normal but significant events.
|
87 |
-
*
|
88 |
-
* @param string $message
|
89 |
-
* @param array $context
|
90 |
-
* @return null
|
91 |
-
*/
|
92 |
-
public function notice( $message, array $context = array() ) {
|
93 |
-
return $this->log( 'notice', $message, $context );
|
94 |
-
}
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Interesting events.
|
98 |
-
*
|
99 |
-
* Example: User logs in, SQL logs.
|
100 |
-
*
|
101 |
-
* @param string $message
|
102 |
-
* @param array $context
|
103 |
-
* @return null
|
104 |
-
*/
|
105 |
-
public function info( $message, array $context = array() ) {
|
106 |
-
return $this->log( 'info', $message, $context );
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Detailed debug information.
|
111 |
-
*
|
112 |
-
* @param string $message
|
113 |
-
* @param array $context
|
114 |
-
* @return null
|
115 |
-
*/
|
116 |
-
public function debug( $message, array $context = array() ) {
|
117 |
-
return $this->log( 'debug', $message, $context );
|
118 |
-
}
|
119 |
-
|
120 |
-
/**
|
121 |
-
* Logs with an arbitrary level.
|
122 |
-
*
|
123 |
-
* @param mixed $level
|
124 |
-
* @param string $message
|
125 |
-
* @param array $context
|
126 |
-
* @return null
|
127 |
-
*/
|
128 |
-
public function log( $level, $message, array $context = array() ) {
|
129 |
-
$this->messages[] = array(
|
130 |
-
'timestamp' => time(),
|
131 |
-
'level' => $level,
|
132 |
-
'message' => $message,
|
133 |
-
'context' => $context,
|
134 |
-
);
|
135 |
-
}
|
136 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Describes a logger instance
|
5 |
+
*
|
6 |
+
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
|
7 |
+
*
|
8 |
+
* The message MUST be a string or object implementing __toString().
|
9 |
+
*
|
10 |
+
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
+
* will be replaced by the context data in key "foo".
|
12 |
+
*
|
13 |
+
* The context array can contain arbitrary data, the only assumption that
|
14 |
+
* can be made by implementors is that if an Exception instance is given
|
15 |
+
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
+
*
|
17 |
+
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
+
* for the full interface specification.
|
19 |
+
*/
|
20 |
+
class RDDI_WP_Importer_Logger {
|
21 |
+
/**
|
22 |
+
* System is unusable.
|
23 |
+
*
|
24 |
+
* @param string $message
|
25 |
+
* @param array $context
|
26 |
+
* @return null
|
27 |
+
*/
|
28 |
+
public function emergency( $message, array $context = array() ) {
|
29 |
+
return $this->log( 'emergency', $message, $context );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Action must be taken immediately.
|
34 |
+
*
|
35 |
+
* Example: Entire website down, database unavailable, etc. This should
|
36 |
+
* trigger the SMS alerts and wake you up.
|
37 |
+
*
|
38 |
+
* @param string $message
|
39 |
+
* @param array $context
|
40 |
+
* @return null
|
41 |
+
*/
|
42 |
+
public function alert( $message, array $context = array() ) {
|
43 |
+
return $this->log( 'alert', $message, $context );
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Critical conditions.
|
48 |
+
*
|
49 |
+
* Example: Application component unavailable, unexpected exception.
|
50 |
+
*
|
51 |
+
* @param string $message
|
52 |
+
* @param array $context
|
53 |
+
* @return null
|
54 |
+
*/
|
55 |
+
public function critical( $message, array $context = array() ) {
|
56 |
+
return $this->log( 'critical', $message, $context );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Runtime errors that do not require immediate action but should typically
|
61 |
+
* be logged and monitored.
|
62 |
+
*
|
63 |
+
* @param string $message
|
64 |
+
* @param array $context
|
65 |
+
* @return null
|
66 |
+
*/
|
67 |
+
public function error( $message, array $context = array()) {
|
68 |
+
return $this->log( 'error', $message, $context );
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Exceptional occurrences that are not errors.
|
73 |
+
*
|
74 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
75 |
+
* that are not necessarily wrong.
|
76 |
+
*
|
77 |
+
* @param string $message
|
78 |
+
* @param array $context
|
79 |
+
* @return null
|
80 |
+
*/
|
81 |
+
public function warning( $message, array $context = array() ) {
|
82 |
+
return $this->log( 'warning', $message, $context );
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Normal but significant events.
|
87 |
+
*
|
88 |
+
* @param string $message
|
89 |
+
* @param array $context
|
90 |
+
* @return null
|
91 |
+
*/
|
92 |
+
public function notice( $message, array $context = array() ) {
|
93 |
+
return $this->log( 'notice', $message, $context );
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Interesting events.
|
98 |
+
*
|
99 |
+
* Example: User logs in, SQL logs.
|
100 |
+
*
|
101 |
+
* @param string $message
|
102 |
+
* @param array $context
|
103 |
+
* @return null
|
104 |
+
*/
|
105 |
+
public function info( $message, array $context = array() ) {
|
106 |
+
return $this->log( 'info', $message, $context );
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Detailed debug information.
|
111 |
+
*
|
112 |
+
* @param string $message
|
113 |
+
* @param array $context
|
114 |
+
* @return null
|
115 |
+
*/
|
116 |
+
public function debug( $message, array $context = array() ) {
|
117 |
+
return $this->log( 'debug', $message, $context );
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Logs with an arbitrary level.
|
122 |
+
*
|
123 |
+
* @param mixed $level
|
124 |
+
* @param string $message
|
125 |
+
* @param array $context
|
126 |
+
* @return null
|
127 |
+
*/
|
128 |
+
public function log( $level, $message, array $context = array() ) {
|
129 |
+
$this->messages[] = array(
|
130 |
+
'timestamp' => time(),
|
131 |
+
'level' => $level,
|
132 |
+
'message' => $message,
|
133 |
+
'context' => $context,
|
134 |
+
);
|
135 |
+
}
|
136 |
+
}
|
includes/extras/class-wxr-importer.php
CHANGED
@@ -1,2250 +1,2250 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class RDDI_WXR_Importer {
|
4 |
-
/**
|
5 |
-
* Maximum supported WXR version
|
6 |
-
*/
|
7 |
-
const MAX_WXR_VERSION = 1.2;
|
8 |
-
|
9 |
-
/**
|
10 |
-
* Regular expression for checking if a post references an attachment
|
11 |
-
*
|
12 |
-
* Note: This is a quick, weak check just to exclude text-only posts. More
|
13 |
-
* vigorous checking is done later to verify.
|
14 |
-
*/
|
15 |
-
const REGEX_HAS_ATTACHMENT_REFS = '!
|
16 |
-
(
|
17 |
-
# Match anything with an image or attachment class
|
18 |
-
class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
|
19 |
-
|
|
20 |
-
# Match anything that looks like an upload URL
|
21 |
-
src=[\'"][^\'"]*(
|
22 |
-
[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
|
23 |
-
|
|
24 |
-
content/uploads[^\'"]+
|
25 |
-
)[\'"]
|
26 |
-
)!ix';
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Version of WXR we're importing.
|
30 |
-
*
|
31 |
-
* Defaults to 1.0 for compatibility. Typically overridden by a
|
32 |
-
* `<wp:wxr_version>` tag at the start of the file.
|
33 |
-
*
|
34 |
-
* @var string
|
35 |
-
*/
|
36 |
-
protected $version = '1.0';
|
37 |
-
|
38 |
-
// information to import from WXR file
|
39 |
-
protected $categories = array();
|
40 |
-
protected $tags = array();
|
41 |
-
protected $base_url = '';
|
42 |
-
|
43 |
-
// TODO: REMOVE THESE
|
44 |
-
protected $processed_terms = array();
|
45 |
-
protected $processed_posts = array();
|
46 |
-
protected $processed_menu_items = array();
|
47 |
-
protected $menu_item_orphans = array();
|
48 |
-
protected $missing_menu_items = array();
|
49 |
-
|
50 |
-
// NEW STYLE
|
51 |
-
protected $mapping = array();
|
52 |
-
protected $requires_remapping = array();
|
53 |
-
protected $exists = array();
|
54 |
-
protected $user_slug_override = array();
|
55 |
-
|
56 |
-
protected $url_remap = array();
|
57 |
-
protected $featured_images = array();
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Logger instance.
|
61 |
-
*
|
62 |
-
* @var RDDI_WP_Importer_Logger
|
63 |
-
*/
|
64 |
-
protected $logger;
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Constructor
|
68 |
-
*
|
69 |
-
* @param array $options {
|
70 |
-
* @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.)
|
71 |
-
* @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.)
|
72 |
-
* @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.)
|
73 |
-
* @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows deduplication and reimporting. Default is false.)
|
74 |
-
* @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
|
75 |
-
* @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.)
|
76 |
-
* @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
|
77 |
-
* }
|
78 |
-
*/
|
79 |
-
public function __construct( $options = array() ) {
|
80 |
-
// Initialize some important variables
|
81 |
-
$empty_types = array(
|
82 |
-
'post' => array(),
|
83 |
-
'comment' => array(),
|
84 |
-
'term' => array(),
|
85 |
-
'user' => array(),
|
86 |
-
);
|
87 |
-
|
88 |
-
$this->mapping = $empty_types;
|
89 |
-
$this->mapping['user_slug'] = array();
|
90 |
-
$this->mapping['term_id'] = array();
|
91 |
-
$this->requires_remapping = $empty_types;
|
92 |
-
$this->exists = $empty_types;
|
93 |
-
|
94 |
-
$this->options = wp_parse_args( $options, array(
|
95 |
-
'prefill_existing_posts' => true,
|
96 |
-
'prefill_existing_comments' => true,
|
97 |
-
'prefill_existing_terms' => true,
|
98 |
-
'update_attachment_guids' => false,
|
99 |
-
'fetch_attachments' => false,
|
100 |
-
'aggressive_url_search' => false,
|
101 |
-
'default_author' => null,
|
102 |
-
) );
|
103 |
-
}
|
104 |
-
|
105 |
-
public function set_logger( $logger ) {
|
106 |
-
$this->logger = $logger;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Get a stream reader for the file.
|
111 |
-
*
|
112 |
-
* @param string $file Path to the XML file.
|
113 |
-
* @return XMLReader|WP_Error Reader instance on success, error otherwise.
|
114 |
-
*/
|
115 |
-
protected function get_reader( $file ) {
|
116 |
-
// Avoid loading external entities for security
|
117 |
-
$old_value = null;
|
118 |
-
if ( function_exists( 'libxml_disable_entity_loader' ) ) {
|
119 |
-
// $old_value = libxml_disable_entity_loader( true );
|
120 |
-
}
|
121 |
-
|
122 |
-
$reader = new XMLReader();
|
123 |
-
$status = $reader->open( $file );
|
124 |
-
|
125 |
-
if ( ! is_null( $old_value ) ) {
|
126 |
-
// libxml_disable_entity_loader( $old_value );
|
127 |
-
}
|
128 |
-
|
129 |
-
if ( ! $status ) {
|
130 |
-
return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'rara-one-click-demo-import' ) );
|
131 |
-
}
|
132 |
-
|
133 |
-
return $reader;
|
134 |
-
}
|
135 |
-
|
136 |
-
/**
|
137 |
-
* The main controller for the actual import stage.
|
138 |
-
*
|
139 |
-
* @param string $file Path to the WXR file for importing
|
140 |
-
*/
|
141 |
-
public function get_preliminary_information( $file ) {
|
142 |
-
// Let's run the actual importer now, woot
|
143 |
-
$reader = $this->get_reader( $file );
|
144 |
-
if ( is_wp_error( $reader ) ) {
|
145 |
-
return $reader;
|
146 |
-
}
|
147 |
-
|
148 |
-
// Set the version to compatibility mode first
|
149 |
-
$this->version = '1.0';
|
150 |
-
|
151 |
-
// Start parsing!
|
152 |
-
$data = new WXR_Import_Info();
|
153 |
-
while ( $reader->read() ) {
|
154 |
-
// Only deal with element opens
|
155 |
-
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
156 |
-
continue;
|
157 |
-
}
|
158 |
-
|
159 |
-
switch ( $reader->name ) {
|
160 |
-
case 'wp:wxr_version':
|
161 |
-
// Upgrade to the correct version
|
162 |
-
$this->version = $reader->readString();
|
163 |
-
|
164 |
-
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
165 |
-
$this->logger->warning( sprintf(
|
166 |
-
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
167 |
-
$this->version,
|
168 |
-
self::MAX_WXR_VERSION
|
169 |
-
) );
|
170 |
-
}
|
171 |
-
|
172 |
-
// Handled everything in this node, move on to the next
|
173 |
-
$reader->next();
|
174 |
-
break;
|
175 |
-
|
176 |
-
case 'generator':
|
177 |
-
$data->generator = $reader->readString();
|
178 |
-
$reader->next();
|
179 |
-
break;
|
180 |
-
|
181 |
-
case 'title':
|
182 |
-
$data->title = $reader->readString();
|
183 |
-
$reader->next();
|
184 |
-
break;
|
185 |
-
|
186 |
-
case 'wp:base_site_url':
|
187 |
-
$data->siteurl = $reader->readString();
|
188 |
-
$reader->next();
|
189 |
-
break;
|
190 |
-
|
191 |
-
case 'wp:base_blog_url':
|
192 |
-
$data->home = $reader->readString();
|
193 |
-
$reader->next();
|
194 |
-
break;
|
195 |
-
|
196 |
-
case 'wp:author':
|
197 |
-
$node = $reader->expand();
|
198 |
-
|
199 |
-
$parsed = $this->parse_author_node( $node );
|
200 |
-
if ( is_wp_error( $parsed ) ) {
|
201 |
-
$this->log_error( $parsed );
|
202 |
-
|
203 |
-
// Skip the rest of this post
|
204 |
-
$reader->next();
|
205 |
-
break;
|
206 |
-
}
|
207 |
-
|
208 |
-
$data->users[] = $parsed;
|
209 |
-
|
210 |
-
// Handled everything in this node, move on to the next
|
211 |
-
$reader->next();
|
212 |
-
break;
|
213 |
-
|
214 |
-
case 'item':
|
215 |
-
$node = $reader->expand();
|
216 |
-
$parsed = $this->parse_post_node( $node );
|
217 |
-
if ( is_wp_error( $parsed ) ) {
|
218 |
-
$this->log_error( $parsed );
|
219 |
-
|
220 |
-
// Skip the rest of this post
|
221 |
-
$reader->next();
|
222 |
-
break;
|
223 |
-
}
|
224 |
-
|
225 |
-
if ( $parsed['data']['post_type'] === 'attachment' ) {
|
226 |
-
$data->media_count++;
|
227 |
-
} else {
|
228 |
-
$data->post_count++;
|
229 |
-
}
|
230 |
-
$data->comment_count += count( $parsed['comments'] );
|
231 |
-
|
232 |
-
// Handled everything in this node, move on to the next
|
233 |
-
$reader->next();
|
234 |
-
break;
|
235 |
-
|
236 |
-
case 'wp:category':
|
237 |
-
case 'wp:tag':
|
238 |
-
case 'wp:term':
|
239 |
-
$data->term_count++;
|
240 |
-
|
241 |
-
// Handled everything in this node, move on to the next
|
242 |
-
$reader->next();
|
243 |
-
break;
|
244 |
-
}
|
245 |
-
}
|
246 |
-
|
247 |
-
$data->version = $this->version;
|
248 |
-
|
249 |
-
return $data;
|
250 |
-
}
|
251 |
-
|
252 |
-
/**
|
253 |
-
* The main controller for the actual import stage.
|
254 |
-
*
|
255 |
-
* @param string $file Path to the WXR file for importing
|
256 |
-
*/
|
257 |
-
public function parse_authors( $file ) {
|
258 |
-
// Let's run the actual importer now, woot
|
259 |
-
$reader = $this->get_reader( $file );
|
260 |
-
if ( is_wp_error( $reader ) ) {
|
261 |
-
return $reader;
|
262 |
-
}
|
263 |
-
|
264 |
-
// Set the version to compatibility mode first
|
265 |
-
$this->version = '1.0';
|
266 |
-
|
267 |
-
// Start parsing!
|
268 |
-
$authors = array();
|
269 |
-
while ( $reader->read() ) {
|
270 |
-
// Only deal with element opens
|
271 |
-
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
272 |
-
continue;
|
273 |
-
}
|
274 |
-
|
275 |
-
switch ( $reader->name ) {
|
276 |
-
case 'wp:wxr_version':
|
277 |
-
// Upgrade to the correct version
|
278 |
-
$this->version = $reader->readString();
|
279 |
-
|
280 |
-
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
281 |
-
$this->logger->warning( sprintf(
|
282 |
-
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
283 |
-
$this->version,
|
284 |
-
self::MAX_WXR_VERSION
|
285 |
-
) );
|
286 |
-
}
|
287 |
-
|
288 |
-
// Handled everything in this node, move on to the next
|
289 |
-
$reader->next();
|
290 |
-
break;
|
291 |
-
|
292 |
-
case 'wp:author':
|
293 |
-
$node = $reader->expand();
|
294 |
-
|
295 |
-
$parsed = $this->parse_author_node( $node );
|
296 |
-
if ( is_wp_error( $parsed ) ) {
|
297 |
-
$this->log_error( $parsed );
|
298 |
-
|
299 |
-
// Skip the rest of this post
|
300 |
-
$reader->next();
|
301 |
-
break;
|
302 |
-
}
|
303 |
-
|
304 |
-
$authors[] = $parsed;
|
305 |
-
|
306 |
-
// Handled everything in this node, move on to the next
|
307 |
-
$reader->next();
|
308 |
-
break;
|
309 |
-
}
|
310 |
-
}
|
311 |
-
|
312 |
-
return $authors;
|
313 |
-
}
|
314 |
-
|
315 |
-
/**
|
316 |
-
* The main controller for the actual import stage.
|
317 |
-
*
|
318 |
-
* @param string $file Path to the WXR file for importing
|
319 |
-
*/
|
320 |
-
public function import( $file ) {
|
321 |
-
add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
|
322 |
-
add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
|
323 |
-
|
324 |
-
$result = $this->import_start( $file );
|
325 |
-
if ( is_wp_error( $result ) ) {
|
326 |
-
return $result;
|
327 |
-
}
|
328 |
-
|
329 |
-
// Let's run the actual importer now, woot
|
330 |
-
$reader = $this->get_reader( $file );
|
331 |
-
if ( is_wp_error( $reader ) ) {
|
332 |
-
return $reader;
|
333 |
-
}
|
334 |
-
|
335 |
-
// Set the version to compatibility mode first
|
336 |
-
$this->version = '1.0';
|
337 |
-
|
338 |
-
// Reset other variables
|
339 |
-
$this->base_url = '';
|
340 |
-
|
341 |
-
// Start parsing!
|
342 |
-
while ( $reader->read() ) {
|
343 |
-
// Only deal with element opens
|
344 |
-
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
345 |
-
continue;
|
346 |
-
}
|
347 |
-
|
348 |
-
switch ( $reader->name ) {
|
349 |
-
case 'wp:wxr_version':
|
350 |
-
// Upgrade to the correct version
|
351 |
-
$this->version = $reader->readString();
|
352 |
-
|
353 |
-
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
354 |
-
$this->logger->warning( sprintf(
|
355 |
-
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
356 |
-
$this->version,
|
357 |
-
self::MAX_WXR_VERSION
|
358 |
-
) );
|
359 |
-
}
|
360 |
-
|
361 |
-
// Handled everything in this node, move on to the next
|
362 |
-
$reader->next();
|
363 |
-
break;
|
364 |
-
|
365 |
-
case 'wp:base_site_url':
|
366 |
-
$this->base_url = $reader->readString();
|
367 |
-
|
368 |
-
// Handled everything in this node, move on to the next
|
369 |
-
$reader->next();
|
370 |
-
break;
|
371 |
-
|
372 |
-
case 'item':
|
373 |
-
$node = $reader->expand();
|
374 |
-
$parsed = $this->parse_post_node( $node );
|
375 |
-
if ( is_wp_error( $parsed ) ) {
|
376 |
-
$this->log_error( $parsed );
|
377 |
-
|
378 |
-
// Skip the rest of this post
|
379 |
-
$reader->next();
|
380 |
-
break;
|
381 |
-
}
|
382 |
-
|
383 |
-
$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
|
384 |
-
|
385 |
-
// Handled everything in this node, move on to the next
|
386 |
-
$reader->next();
|
387 |
-
break;
|
388 |
-
|
389 |
-
case 'wp:author':
|
390 |
-
$node = $reader->expand();
|
391 |
-
|
392 |
-
$parsed = $this->parse_author_node( $node );
|
393 |
-
if ( is_wp_error( $parsed ) ) {
|
394 |
-
$this->log_error( $parsed );
|
395 |
-
|
396 |
-
// Skip the rest of this post
|
397 |
-
$reader->next();
|
398 |
-
break;
|
399 |
-
}
|
400 |
-
|
401 |
-
$status = $this->process_author( $parsed['data'], $parsed['meta'] );
|
402 |
-
if ( is_wp_error( $status ) ) {
|
403 |
-
$this->log_error( $status );
|
404 |
-
}
|
405 |
-
|
406 |
-
// Handled everything in this node, move on to the next
|
407 |
-
$reader->next();
|
408 |
-
break;
|
409 |
-
|
410 |
-
case 'wp:category':
|
411 |
-
$node = $reader->expand();
|
412 |
-
|
413 |
-
$parsed = $this->parse_term_node( $node, 'category' );
|
414 |
-
if ( is_wp_error( $parsed ) ) {
|
415 |
-
$this->log_error( $parsed );
|
416 |
-
|
417 |
-
// Skip the rest of this post
|
418 |
-
$reader->next();
|
419 |
-
break;
|
420 |
-
}
|
421 |
-
|
422 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
423 |
-
|
424 |
-
// Handled everything in this node, move on to the next
|
425 |
-
$reader->next();
|
426 |
-
break;
|
427 |
-
|
428 |
-
case 'wp:tag':
|
429 |
-
$node = $reader->expand();
|
430 |
-
|
431 |
-
$parsed = $this->parse_term_node( $node, 'tag' );
|
432 |
-
if ( is_wp_error( $parsed ) ) {
|
433 |
-
$this->log_error( $parsed );
|
434 |
-
|
435 |
-
// Skip the rest of this post
|
436 |
-
$reader->next();
|
437 |
-
break;
|
438 |
-
}
|
439 |
-
|
440 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
441 |
-
|
442 |
-
// Handled everything in this node, move on to the next
|
443 |
-
$reader->next();
|
444 |
-
break;
|
445 |
-
|
446 |
-
case 'wp:term':
|
447 |
-
$node = $reader->expand();
|
448 |
-
|
449 |
-
$parsed = $this->parse_term_node( $node );
|
450 |
-
if ( is_wp_error( $parsed ) ) {
|
451 |
-
$this->log_error( $parsed );
|
452 |
-
|
453 |
-
// Skip the rest of this post
|
454 |
-
$reader->next();
|
455 |
-
break;
|
456 |
-
}
|
457 |
-
|
458 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
459 |
-
|
460 |
-
// Handled everything in this node, move on to the next
|
461 |
-
$reader->next();
|
462 |
-
break;
|
463 |
-
|
464 |
-
default:
|
465 |
-
// Skip this node, probably handled by something already
|
466 |
-
break;
|
467 |
-
}
|
468 |
-
}
|
469 |
-
|
470 |
-
// Now that we've done the main processing, do any required
|
471 |
-
// post-processing and remapping.
|
472 |
-
$this->post_process();
|
473 |
-
|
474 |
-
if ( $this->options['aggressive_url_search'] ) {
|
475 |
-
$this->replace_attachment_urls_in_content();
|
476 |
-
}
|
477 |
-
// $this->remap_featured_images();
|
478 |
-
|
479 |
-
$this->import_end();
|
480 |
-
}
|
481 |
-
|
482 |
-
/**
|
483 |
-
* Log an error instance to the logger.
|
484 |
-
*
|
485 |
-
* @param WP_Error $error Error instance to log.
|
486 |
-
*/
|
487 |
-
protected function log_error( WP_Error $error ) {
|
488 |
-
$this->logger->warning( $error->get_error_message() );
|
489 |
-
|
490 |
-
// Log the data as debug info too
|
491 |
-
$data = $error->get_error_data();
|
492 |
-
if ( ! empty( $data ) ) {
|
493 |
-
$this->logger->debug( var_export( $data, true ) );
|
494 |
-
}
|
495 |
-
}
|
496 |
-
|
497 |
-
/**
|
498 |
-
* Parses the WXR file and prepares us for the task of processing parsed data
|
499 |
-
*
|
500 |
-
* @param string $file Path to the WXR file for importing
|
501 |
-
*/
|
502 |
-
protected function import_start( $file ) {
|
503 |
-
if ( ! is_file( $file ) ) {
|
504 |
-
return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'rara-one-click-demo-import' ) );
|
505 |
-
}
|
506 |
-
|
507 |
-
// Suspend bunches of stuff in WP core
|
508 |
-
wp_defer_term_counting( true );
|
509 |
-
wp_defer_comment_counting( true );
|
510 |
-
wp_suspend_cache_invalidation( true );
|
511 |
-
|
512 |
-
// Prefill exists calls if told to
|
513 |
-
if ( $this->options['prefill_existing_posts'] ) {
|
514 |
-
$this->prefill_existing_posts();
|
515 |
-
}
|
516 |
-
if ( $this->options['prefill_existing_comments'] ) {
|
517 |
-
$this->prefill_existing_comments();
|
518 |
-
}
|
519 |
-
if ( $this->options['prefill_existing_terms'] ) {
|
520 |
-
$this->prefill_existing_terms();
|
521 |
-
}
|
522 |
-
|
523 |
-
/**
|
524 |
-
* Begin the import.
|
525 |
-
*
|
526 |
-
* Fires before the import process has begun. If you need to suspend
|
527 |
-
* caching or heavy processing on hooks, do so here.
|
528 |
-
*/
|
529 |
-
do_action( 'import_start' );
|
530 |
-
}
|
531 |
-
|
532 |
-
/**
|
533 |
-
* Performs post-import cleanup of files and the cache
|
534 |
-
*/
|
535 |
-
protected function import_end() {
|
536 |
-
// Re-enable stuff in core
|
537 |
-
wp_suspend_cache_invalidation( false );
|
538 |
-
wp_cache_flush();
|
539 |
-
foreach ( get_taxonomies() as $tax ) {
|
540 |
-
delete_option( "{$tax}_children" );
|
541 |
-
_get_term_hierarchy( $tax );
|
542 |
-
}
|
543 |
-
|
544 |
-
wp_defer_term_counting( false );
|
545 |
-
wp_defer_comment_counting( false );
|
546 |
-
|
547 |
-
/**
|
548 |
-
* Complete the import.
|
549 |
-
*
|
550 |
-
* Fires after the import process has finished. If you need to update
|
551 |
-
* your cache or re-enable processing, do so here.
|
552 |
-
*/
|
553 |
-
do_action( 'import_end' );
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* Set the user mapping.
|
558 |
-
*
|
559 |
-
* @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
|
560 |
-
*/
|
561 |
-
public function set_user_mapping( $mapping ) {
|
562 |
-
foreach ( $mapping as $map ) {
|
563 |
-
if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
|
564 |
-
$this->logger->warning( __( 'Invalid author mapping', 'rara-one-click-demo-import' ) );
|
565 |
-
$this->logger->debug( var_export( $map, true ) );
|
566 |
-
continue;
|
567 |
-
}
|
568 |
-
|
569 |
-
$old_slug = $map['old_slug'];
|
570 |
-
$old_id = $map['old_id'];
|
571 |
-
$new_id = $map['new_id'];
|
572 |
-
|
573 |
-
$this->mapping['user'][ $old_id ] = $new_id;
|
574 |
-
$this->mapping['user_slug'][ $old_slug ] = $new_id;
|
575 |
-
}
|
576 |
-
}
|
577 |
-
|
578 |
-
/**
|
579 |
-
* Set the user slug overrides.
|
580 |
-
*
|
581 |
-
* Allows overriding the slug in the import with a custom/renamed version.
|
582 |
-
*
|
583 |
-
* @param string[] $overrides Map of old slug to new slug.
|
584 |
-
*/
|
585 |
-
public function set_user_slug_overrides( $overrides ) {
|
586 |
-
foreach ( $overrides as $original => $renamed ) {
|
587 |
-
$this->user_slug_override[ $original ] = $renamed;
|
588 |
-
}
|
589 |
-
}
|
590 |
-
|
591 |
-
/**
|
592 |
-
* Parse a post node into post data.
|
593 |
-
*
|
594 |
-
* @param DOMElement $node Parent node of post data (typically `item`).
|
595 |
-
* @return array|WP_Error Post data array on success, error otherwise.
|
596 |
-
*/
|
597 |
-
protected function parse_post_node( $node ) {
|
598 |
-
$data = array();
|
599 |
-
$meta = array();
|
600 |
-
$comments = array();
|
601 |
-
$terms = array();
|
602 |
-
|
603 |
-
foreach ( $node->childNodes as $child ) {
|
604 |
-
// We only care about child elements
|
605 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
606 |
-
continue;
|
607 |
-
}
|
608 |
-
|
609 |
-
switch ( $child->tagName ) {
|
610 |
-
case 'wp:post_type':
|
611 |
-
$data['post_type'] = $child->textContent;
|
612 |
-
break;
|
613 |
-
|
614 |
-
case 'title':
|
615 |
-
$data['post_title'] = $child->textContent;
|
616 |
-
break;
|
617 |
-
|
618 |
-
case 'guid':
|
619 |
-
$data['guid'] = $child->textContent;
|
620 |
-
break;
|
621 |
-
|
622 |
-
case 'dc:creator':
|
623 |
-
$data['post_author'] = $child->textContent;
|
624 |
-
break;
|
625 |
-
|
626 |
-
case 'content:encoded':
|
627 |
-
$data['post_content'] = $child->textContent;
|
628 |
-
break;
|
629 |
-
|
630 |
-
case 'excerpt:encoded':
|
631 |
-
$data['post_excerpt'] = $child->textContent;
|
632 |
-
break;
|
633 |
-
|
634 |
-
case 'wp:post_id':
|
635 |
-
$data['post_id'] = $child->textContent;
|
636 |
-
break;
|
637 |
-
|
638 |
-
case 'wp:post_date':
|
639 |
-
$data['post_date'] = $child->textContent;
|
640 |
-
break;
|
641 |
-
|
642 |
-
case 'wp:post_date_gmt':
|
643 |
-
$data['post_date_gmt'] = $child->textContent;
|
644 |
-
break;
|
645 |
-
|
646 |
-
case 'wp:comment_status':
|
647 |
-
$data['comment_status'] = $child->textContent;
|
648 |
-
break;
|
649 |
-
|
650 |
-
case 'wp:ping_status':
|
651 |
-
$data['ping_status'] = $child->textContent;
|
652 |
-
break;
|
653 |
-
|
654 |
-
case 'wp:post_name':
|
655 |
-
$data['post_name'] = $child->textContent;
|
656 |
-
break;
|
657 |
-
|
658 |
-
case 'wp:status':
|
659 |
-
$data['post_status'] = $child->textContent;
|
660 |
-
|
661 |
-
if ( $data['post_status'] === 'auto-draft' ) {
|
662 |
-
// Bail now
|
663 |
-
return new WP_Error(
|
664 |
-
'wxr_importer.post.cannot_import_draft',
|
665 |
-
__( 'Cannot import auto-draft posts','rara-one-click-demo-import' ),
|
666 |
-
$data
|
667 |
-
);
|
668 |
-
}
|
669 |
-
break;
|
670 |
-
|
671 |
-
case 'wp:post_parent':
|
672 |
-
$data['post_parent'] = $child->textContent;
|
673 |
-
break;
|
674 |
-
|
675 |
-
case 'wp:menu_order':
|
676 |
-
$data['menu_order'] = $child->textContent;
|
677 |
-
break;
|
678 |
-
|
679 |
-
case 'wp:post_password':
|
680 |
-
$data['post_password'] = $child->textContent;
|
681 |
-
break;
|
682 |
-
|
683 |
-
case 'wp:is_sticky':
|
684 |
-
$data['is_sticky'] = $child->textContent;
|
685 |
-
break;
|
686 |
-
|
687 |
-
case 'wp:attachment_url':
|
688 |
-
$data['attachment_url'] = $child->textContent;
|
689 |
-
break;
|
690 |
-
|
691 |
-
case 'wp:postmeta':
|
692 |
-
$meta_item = $this->parse_meta_node( $child );
|
693 |
-
if ( ! empty( $meta_item ) ) {
|
694 |
-
$meta[] = $meta_item;
|
695 |
-
}
|
696 |
-
break;
|
697 |
-
|
698 |
-
case 'wp:comment':
|
699 |
-
$comment_item = $this->parse_comment_node( $child );
|
700 |
-
if ( ! empty( $comment_item ) ) {
|
701 |
-
$comments[] = $comment_item;
|
702 |
-
}
|
703 |
-
break;
|
704 |
-
|
705 |
-
case 'category':
|
706 |
-
$term_item = $this->parse_category_node( $child );
|
707 |
-
if ( ! empty( $term_item ) ) {
|
708 |
-
$terms[] = $term_item;
|
709 |
-
}
|
710 |
-
break;
|
711 |
-
}
|
712 |
-
}
|
713 |
-
|
714 |
-
return compact( 'data', 'meta', 'comments', 'terms' );
|
715 |
-
}
|
716 |
-
|
717 |
-
/**
|
718 |
-
* Create new posts based on import information
|
719 |
-
*
|
720 |
-
* Posts marked as having a parent which doesn't exist will become top level items.
|
721 |
-
* Doesn't create a new post if: the post type doesn't exist, the given post ID
|
722 |
-
* is already noted as imported or a post with the same title and date already exists.
|
723 |
-
* Note that new/updated terms, comments and meta are imported for the last of the above.
|
724 |
-
*/
|
725 |
-
protected function process_post( $data, $meta, $comments, $terms ) {
|
726 |
-
/**
|
727 |
-
* Pre-process post data.
|
728 |
-
*
|
729 |
-
* @param array $data Post data. (Return empty to skip.)
|
730 |
-
* @param array $meta Meta data.
|
731 |
-
* @param array $comments Comments on the post.
|
732 |
-
* @param array $terms Terms on the post.
|
733 |
-
*/
|
734 |
-
$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
|
735 |
-
if ( empty( $data ) ) {
|
736 |
-
return false;
|
737 |
-
}
|
738 |
-
|
739 |
-
$original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
|
740 |
-
$parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
|
741 |
-
$author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
|
742 |
-
|
743 |
-
// Have we already processed this?
|
744 |
-
if ( isset( $this->mapping['post'][ $original_id ] ) ) {
|
745 |
-
return;
|
746 |
-
}
|
747 |
-
|
748 |
-
$post_type_object = get_post_type_object( $data['post_type'] );
|
749 |
-
|
750 |
-
// Is this type even valid?
|
751 |
-
if ( ! $post_type_object ) {
|
752 |
-
$this->logger->warning( sprintf(
|
753 |
-
__( 'Failed to import "%s": Invalid post type %s', 'rara-one-click-demo-import' ),
|
754 |
-
$data['post_title'],
|
755 |
-
$data['post_type']
|
756 |
-
) );
|
757 |
-
return false;
|
758 |
-
}
|
759 |
-
|
760 |
-
$post_exists = $this->post_exists( $data );
|
761 |
-
if ( $post_exists ) {
|
762 |
-
$this->logger->info( sprintf(
|
763 |
-
__( '%s "%s" already exists.', 'rara-one-click-demo-import' ),
|
764 |
-
$post_type_object->labels->singular_name,
|
765 |
-
$data['post_title']
|
766 |
-
) );
|
767 |
-
|
768 |
-
// Even though this post already exists, new comments might need importing
|
769 |
-
$this->process_comments( $comments, $original_id, $data, $post_exists );
|
770 |
-
|
771 |
-
return false;
|
772 |
-
}
|
773 |
-
|
774 |
-
// Map the parent post, or mark it as one we need to fix
|
775 |
-
$requires_remapping = false;
|
776 |
-
if ( $parent_id ) {
|
777 |
-
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
778 |
-
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
779 |
-
} else {
|
780 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
781 |
-
$requires_remapping = true;
|
782 |
-
|
783 |
-
$data['post_parent'] = 0;
|
784 |
-
}
|
785 |
-
}
|
786 |
-
|
787 |
-
// Map the author, or mark it as one we need to fix
|
788 |
-
$author = sanitize_user( $data['post_author'], true );
|
789 |
-
if ( empty( $author ) ) {
|
790 |
-
// Missing or invalid author, use default if available.
|
791 |
-
$data['post_author'] = $this->options['default_author'];
|
792 |
-
} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
|
793 |
-
$data['post_author'] = $this->mapping['user_slug'][ $author ];
|
794 |
-
} else {
|
795 |
-
$meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author );
|
796 |
-
$requires_remapping = true;
|
797 |
-
|
798 |
-
$data['post_author'] = (int) get_current_user_id();
|
799 |
-
}
|
800 |
-
|
801 |
-
// Does the post look like it contains attachment images?
|
802 |
-
if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
|
803 |
-
$meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true );
|
804 |
-
$requires_remapping = true;
|
805 |
-
}
|
806 |
-
|
807 |
-
// Whitelist to just the keys we allow
|
808 |
-
$postdata = array(
|
809 |
-
'import_id' => $data['post_id'],
|
810 |
-
);
|
811 |
-
$allowed = array(
|
812 |
-
'post_author' => true,
|
813 |
-
'post_date' => true,
|
814 |
-
'post_date_gmt' => true,
|
815 |
-
'post_content' => true,
|
816 |
-
'post_excerpt' => true,
|
817 |
-
'post_title' => true,
|
818 |
-
'post_status' => true,
|
819 |
-
'post_name' => true,
|
820 |
-
'comment_status' => true,
|
821 |
-
'ping_status' => true,
|
822 |
-
'guid' => true,
|
823 |
-
'post_parent' => true,
|
824 |
-
'menu_order' => true,
|
825 |
-
'post_type' => true,
|
826 |
-
'post_password' => true,
|
827 |
-
);
|
828 |
-
foreach ( $data as $key => $value ) {
|
829 |
-
if ( ! isset( $allowed[ $key ] ) ) {
|
830 |
-
continue;
|
831 |
-
}
|
832 |
-
|
833 |
-
$postdata[ $key ] = $data[ $key ];
|
834 |
-
}
|
835 |
-
|
836 |
-
$postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
|
837 |
-
|
838 |
-
if ( 'attachment' === $postdata['post_type'] ) {
|
839 |
-
if ( ! $this->options['fetch_attachments'] ) {
|
840 |
-
$this->logger->notice( sprintf(
|
841 |
-
__( 'Skipping attachment "%s", fetching attachments disabled','rara-one-click-demo-import' ),
|
842 |
-
$data['post_title']
|
843 |
-
) );
|
844 |
-
return false;
|
845 |
-
}
|
846 |
-
$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
|
847 |
-
$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
|
848 |
-
} else {
|
849 |
-
$post_id = wp_insert_post( $postdata, true );
|
850 |
-
do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
|
851 |
-
}
|
852 |
-
|
853 |
-
if ( is_wp_error( $post_id ) ) {
|
854 |
-
$this->logger->error( sprintf(
|
855 |
-
__( 'Failed to import "%s" (%s)', 'rara-one-click-demo-import' ),
|
856 |
-
$data['post_title'],
|
857 |
-
$post_type_object->labels->singular_name
|
858 |
-
) );
|
859 |
-
$this->logger->debug( $post_id->get_error_message() );
|
860 |
-
|
861 |
-
/**
|
862 |
-
* Post processing failed.
|
863 |
-
*
|
864 |
-
* @param WP_Error $post_id Error object.
|
865 |
-
* @param array $data Raw data imported for the post.
|
866 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
867 |
-
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
868 |
-
* @param array $terms Raw term data, already processed.
|
869 |
-
*/
|
870 |
-
do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
|
871 |
-
return false;
|
872 |
-
}
|
873 |
-
|
874 |
-
// Ensure stickiness is handled correctly too
|
875 |
-
if ( $data['is_sticky'] === '1' ) {
|
876 |
-
stick_post( $post_id );
|
877 |
-
}
|
878 |
-
|
879 |
-
// map pre-import ID to local ID
|
880 |
-
$this->mapping['post'][ $original_id ] = (int) $post_id;
|
881 |
-
if ( $requires_remapping ) {
|
882 |
-
$this->requires_remapping['post'][ $post_id ] = true;
|
883 |
-
}
|
884 |
-
$this->mark_post_exists( $data, $post_id );
|
885 |
-
|
886 |
-
$this->logger->info( sprintf(
|
887 |
-
__( 'Imported "%s" (%s)', 'rara-one-click-demo-import' ),
|
888 |
-
$data['post_title'],
|
889 |
-
$post_type_object->labels->singular_name
|
890 |
-
) );
|
891 |
-
$this->logger->debug( sprintf(
|
892 |
-
__( 'Post %d remapped to %d', 'rara-one-click-demo-import' ),
|
893 |
-
$original_id,
|
894 |
-
$post_id
|
895 |
-
) );
|
896 |
-
|
897 |
-
// Handle the terms too
|
898 |
-
$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
|
899 |
-
|
900 |
-
if ( ! empty( $terms ) ) {
|
901 |
-
$term_ids = array();
|
902 |
-
foreach ( $terms as $term ) {
|
903 |
-
$taxonomy = $term['taxonomy'];
|
904 |
-
$key = sha1( $taxonomy . ':' . $term['slug'] );
|
905 |
-
|
906 |
-
if ( isset( $this->mapping['term'][ $key ] ) ) {
|
907 |
-
$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
|
908 |
-
} else {
|
909 |
-
$meta[] = array( 'key' => '_wxr_import_term', 'value' => $term );
|
910 |
-
$requires_remapping = true;
|
911 |
-
}
|
912 |
-
}
|
913 |
-
|
914 |
-
foreach ( $term_ids as $tax => $ids ) {
|
915 |
-
$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
|
916 |
-
do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
|
917 |
-
}
|
918 |
-
}
|
919 |
-
|
920 |
-
$this->process_comments( $comments, $post_id, $data );
|
921 |
-
$this->process_post_meta( $meta, $post_id, $data );
|
922 |
-
|
923 |
-
if ( 'nav_menu_item' === $data['post_type'] ) {
|
924 |
-
$this->process_menu_item_meta( $post_id, $data, $meta );
|
925 |
-
}
|
926 |
-
|
927 |
-
/**
|
928 |
-
* Post processing completed.
|
929 |
-
*
|
930 |
-
* @param int $post_id New post ID.
|
931 |
-
* @param array $data Raw data imported for the post.
|
932 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
933 |
-
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
934 |
-
* @param array $terms Raw term data, already processed.
|
935 |
-
*/
|
936 |
-
do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
|
937 |
-
}
|
938 |
-
|
939 |
-
/**
|
940 |
-
* Attempt to create a new menu item from import data
|
941 |
-
*
|
942 |
-
* Fails for draft, orphaned menu items and those without an associated nav_menu
|
943 |
-
* or an invalid nav_menu term. If the post type or term object which the menu item
|
944 |
-
* represents doesn't exist then the menu item will not be imported (waits until the
|
945 |
-
* end of the import to retry again before discarding).
|
946 |
-
*
|
947 |
-
* @param array $item Menu item details from WXR file
|
948 |
-
*/
|
949 |
-
protected function process_menu_item_meta( $post_id, $data, $meta ) {
|
950 |
-
|
951 |
-
$item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
952 |
-
$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
|
953 |
-
$object_id = null;
|
954 |
-
|
955 |
-
$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
|
956 |
-
|
957 |
-
$requires_remapping = false;
|
958 |
-
switch ( $item_type ) {
|
959 |
-
case 'taxonomy':
|
960 |
-
if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
|
961 |
-
$object_id = $this->mapping['term_id'][ $original_object_id ];
|
962 |
-
} else {
|
963 |
-
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
964 |
-
$requires_remapping = true;
|
965 |
-
}
|
966 |
-
break;
|
967 |
-
|
968 |
-
case 'post_type':
|
969 |
-
if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
|
970 |
-
$object_id = $this->mapping['post'][ $original_object_id ];
|
971 |
-
} else {
|
972 |
-
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
973 |
-
$requires_remapping = true;
|
974 |
-
}
|
975 |
-
break;
|
976 |
-
|
977 |
-
case 'custom':
|
978 |
-
// Custom refers to itself, wonderfully easy.
|
979 |
-
$object_id = $post_id;
|
980 |
-
break;
|
981 |
-
|
982 |
-
default:
|
983 |
-
// associated object is missing or not imported yet, we'll retry later
|
984 |
-
$this->missing_menu_items[] = $item;
|
985 |
-
$this->logger->debug( 'Unknown menu item type' );
|
986 |
-
break;
|
987 |
-
}
|
988 |
-
|
989 |
-
if ( $requires_remapping ) {
|
990 |
-
$this->requires_remapping['post'][ $post_id ] = true;
|
991 |
-
}
|
992 |
-
|
993 |
-
if ( empty( $object_id ) ) {
|
994 |
-
// Nothing needed here.
|
995 |
-
return;
|
996 |
-
}
|
997 |
-
|
998 |
-
$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
|
999 |
-
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
|
1000 |
-
}
|
1001 |
-
|
1002 |
-
/**
|
1003 |
-
* If fetching attachments is enabled then attempt to create a new attachment
|
1004 |
-
*
|
1005 |
-
* @param array $post Attachment post details from WXR
|
1006 |
-
* @param string $url URL to fetch attachment from
|
1007 |
-
* @return int|WP_Error Post ID on success, WP_Error otherwise
|
1008 |
-
*/
|
1009 |
-
protected function process_attachment( $post, $meta, $remote_url ) {
|
1010 |
-
// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
|
1011 |
-
// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
|
1012 |
-
$post['upload_date'] = $post['post_date'];
|
1013 |
-
foreach ( $meta as $meta_item ) {
|
1014 |
-
if ( $meta_item['key'] !== '_wp_attached_file' ) {
|
1015 |
-
continue;
|
1016 |
-
}
|
1017 |
-
|
1018 |
-
if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
|
1019 |
-
$post['upload_date'] = $matches[0];
|
1020 |
-
}
|
1021 |
-
break;
|
1022 |
-
}
|
1023 |
-
|
1024 |
-
// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
|
1025 |
-
if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
|
1026 |
-
$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
|
1027 |
-
}
|
1028 |
-
|
1029 |
-
$upload = $this->fetch_remote_file( $remote_url, $post );
|
1030 |
-
if ( is_wp_error( $upload ) ) {
|
1031 |
-
return $upload;
|
1032 |
-
}
|
1033 |
-
|
1034 |
-
$info = wp_check_filetype( $upload['file'] );
|
1035 |
-
if ( ! $info ) {
|
1036 |
-
return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'rara-one-click-demo-import' ) );
|
1037 |
-
}
|
1038 |
-
|
1039 |
-
$post['post_mime_type'] = $info['type'];
|
1040 |
-
|
1041 |
-
// WP really likes using the GUID for display. Allow updating it.
|
1042 |
-
// See https://core.trac.wordpress.org/ticket/33386
|
1043 |
-
if ( $this->options['update_attachment_guids'] ) {
|
1044 |
-
$post['guid'] = $upload['url'];
|
1045 |
-
}
|
1046 |
-
|
1047 |
-
// as per wp-admin/includes/upload.php
|
1048 |
-
$post_id = wp_insert_attachment( $post, $upload['file'] );
|
1049 |
-
if ( is_wp_error( $post_id ) ) {
|
1050 |
-
return $post_id;
|
1051 |
-
}
|
1052 |
-
|
1053 |
-
$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
|
1054 |
-
wp_update_attachment_metadata( $post_id, $attachment_metadata );
|
1055 |
-
|
1056 |
-
// Map this image URL later if we need to
|
1057 |
-
$this->url_remap[ $remote_url ] = $upload['url'];
|
1058 |
-
|
1059 |
-
// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
|
1060 |
-
if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
|
1061 |
-
$insecure_url = 'http' . substr( $remote_url, 5 );
|
1062 |
-
$this->url_remap[ $insecure_url ] = $upload['url'];
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
if ( $this->options['aggressive_url_search'] ) {
|
1066 |
-
// remap resized image URLs, works by stripping the extension and remapping the URL stub.
|
1067 |
-
/*if ( preg_match( '!^image/!', $info['type'] ) ) {
|
1068 |
-
$parts = pathinfo( $remote_url );
|
1069 |
-
$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
|
1070 |
-
|
1071 |
-
$parts_new = pathinfo( $upload['url'] );
|
1072 |
-
$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
|
1073 |
-
|
1074 |
-
$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
|
1075 |
-
}*/
|
1076 |
-
}
|
1077 |
-
|
1078 |
-
return $post_id;
|
1079 |
-
}
|
1080 |
-
|
1081 |
-
/**
|
1082 |
-
* Parse a meta node into meta data.
|
1083 |
-
*
|
1084 |
-
* @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
|
1085 |
-
* @return array|null Meta data array on success, or null on error.
|
1086 |
-
*/
|
1087 |
-
protected function parse_meta_node( $node ) {
|
1088 |
-
foreach ( $node->childNodes as $child ) {
|
1089 |
-
// We only care about child elements
|
1090 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1091 |
-
continue;
|
1092 |
-
}
|
1093 |
-
|
1094 |
-
switch ( $child->tagName ) {
|
1095 |
-
case 'wp:meta_key':
|
1096 |
-
$key = $child->textContent;
|
1097 |
-
break;
|
1098 |
-
|
1099 |
-
case 'wp:meta_value':
|
1100 |
-
$value = $child->textContent;
|
1101 |
-
break;
|
1102 |
-
}
|
1103 |
-
}
|
1104 |
-
|
1105 |
-
if ( empty( $key ) || empty( $value ) ) {
|
1106 |
-
return null;
|
1107 |
-
}
|
1108 |
-
|
1109 |
-
return compact( 'key', 'value' );
|
1110 |
-
}
|
1111 |
-
|
1112 |
-
/**
|
1113 |
-
* Process and import post meta items.
|
1114 |
-
*
|
1115 |
-
* @param array $meta List of meta data arrays
|
1116 |
-
* @param int $post_id Post to associate with
|
1117 |
-
* @param array $post Post data
|
1118 |
-
* @return int|WP_Error Number of meta items imported on success, error otherwise.
|
1119 |
-
*/
|
1120 |
-
protected function process_post_meta( $meta, $post_id, $post ) {
|
1121 |
-
if ( empty( $meta ) ) {
|
1122 |
-
return true;
|
1123 |
-
}
|
1124 |
-
|
1125 |
-
foreach ( $meta as $meta_item ) {
|
1126 |
-
/**
|
1127 |
-
* Pre-process post meta data.
|
1128 |
-
*
|
1129 |
-
* @param array $meta_item Meta data. (Return empty to skip.)
|
1130 |
-
* @param int $post_id Post the meta is attached to.
|
1131 |
-
*/
|
1132 |
-
$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
|
1133 |
-
if ( empty( $meta_item ) ) {
|
1134 |
-
return false;
|
1135 |
-
}
|
1136 |
-
|
1137 |
-
$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
|
1138 |
-
$value = false;
|
1139 |
-
|
1140 |
-
if ( '_edit_last' === $key ) {
|
1141 |
-
$value = intval( $meta_item['value'] );
|
1142 |
-
if ( ! isset( $this->mapping['user'][ $value ] ) ) {
|
1143 |
-
// Skip!
|
1144 |
-
continue;
|
1145 |
-
}
|
1146 |
-
|
1147 |
-
$value = $this->mapping['user'][ $value ];
|
1148 |
-
}
|
1149 |
-
|
1150 |
-
if ( $key ) {
|
1151 |
-
// export gets meta straight from the DB so could have a serialized string
|
1152 |
-
if ( ! $value ) {
|
1153 |
-
$value = maybe_unserialize( $meta_item['value'] );
|
1154 |
-
}
|
1155 |
-
|
1156 |
-
add_post_meta( $post_id, $key, $value );
|
1157 |
-
do_action( 'import_post_meta', $post_id, $key, $value );
|
1158 |
-
|
1159 |
-
// if the post has a featured image, take note of this in case of remap
|
1160 |
-
if ( '_thumbnail_id' === $key ) {
|
1161 |
-
$this->featured_images[ $post_id ] = (int) $value;
|
1162 |
-
}
|
1163 |
-
}
|
1164 |
-
}
|
1165 |
-
|
1166 |
-
return true;
|
1167 |
-
}
|
1168 |
-
|
1169 |
-
/**
|
1170 |
-
* Parse a comment node into comment data.
|
1171 |
-
*
|
1172 |
-
* @param DOMElement $node Parent node of comment data (typically `wp:comment`).
|
1173 |
-
* @return array Comment data array.
|
1174 |
-
*/
|
1175 |
-
protected function parse_comment_node( $node ) {
|
1176 |
-
$data = array(
|
1177 |
-
'commentmeta' => array(),
|
1178 |
-
);
|
1179 |
-
|
1180 |
-
foreach ( $node->childNodes as $child ) {
|
1181 |
-
// We only care about child elements
|
1182 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1183 |
-
continue;
|
1184 |
-
}
|
1185 |
-
|
1186 |
-
switch ( $child->tagName ) {
|
1187 |
-
case 'wp:comment_id':
|
1188 |
-
$data['comment_id'] = $child->textContent;
|
1189 |
-
break;
|
1190 |
-
case 'wp:comment_author':
|
1191 |
-
$data['comment_author'] = $child->textContent;
|
1192 |
-
break;
|
1193 |
-
|
1194 |
-
case 'wp:comment_author_email':
|
1195 |
-
$data['comment_author_email'] = $child->textContent;
|
1196 |
-
break;
|
1197 |
-
|
1198 |
-
case 'wp:comment_author_IP':
|
1199 |
-
$data['comment_author_IP'] = $child->textContent;
|
1200 |
-
break;
|
1201 |
-
|
1202 |
-
case 'wp:comment_author_url':
|
1203 |
-
$data['comment_author_url'] = $child->textContent;
|
1204 |
-
break;
|
1205 |
-
|
1206 |
-
case 'wp:comment_user_id':
|
1207 |
-
$data['comment_user_id'] = $child->textContent;
|
1208 |
-
break;
|
1209 |
-
|
1210 |
-
case 'wp:comment_date':
|
1211 |
-
$data['comment_date'] = $child->textContent;
|
1212 |
-
break;
|
1213 |
-
|
1214 |
-
case 'wp:comment_date_gmt':
|
1215 |
-
$data['comment_date_gmt'] = $child->textContent;
|
1216 |
-
break;
|
1217 |
-
|
1218 |
-
case 'wp:comment_content':
|
1219 |
-
$data['comment_content'] = $child->textContent;
|
1220 |
-
break;
|
1221 |
-
|
1222 |
-
case 'wp:comment_approved':
|
1223 |
-
$data['comment_approved'] = $child->textContent;
|
1224 |
-
break;
|
1225 |
-
|
1226 |
-
case 'wp:comment_type':
|
1227 |
-
$data['comment_type'] = $child->textContent;
|
1228 |
-
break;
|
1229 |
-
|
1230 |
-
case 'wp:comment_parent':
|
1231 |
-
$data['comment_parent'] = $child->textContent;
|
1232 |
-
break;
|
1233 |
-
|
1234 |
-
case 'wp:commentmeta':
|
1235 |
-
$meta_item = $this->parse_meta_node( $child );
|
1236 |
-
if ( ! empty( $meta_item ) ) {
|
1237 |
-
$data['commentmeta'][] = $meta_item;
|
1238 |
-
}
|
1239 |
-
break;
|
1240 |
-
}
|
1241 |
-
}
|
1242 |
-
|
1243 |
-
return $data;
|
1244 |
-
}
|
1245 |
-
|
1246 |
-
/**
|
1247 |
-
* Process and import comment data.
|
1248 |
-
*
|
1249 |
-
* @param array $comments List of comment data arrays.
|
1250 |
-
* @param int $post_id Post to associate with.
|
1251 |
-
* @param array $post Post data.
|
1252 |
-
* @return int|WP_Error Number of comments imported on success, error otherwise.
|
1253 |
-
*/
|
1254 |
-
protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
|
1255 |
-
|
1256 |
-
$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
|
1257 |
-
if ( empty( $comments ) ) {
|
1258 |
-
return 0;
|
1259 |
-
}
|
1260 |
-
|
1261 |
-
$num_comments = 0;
|
1262 |
-
|
1263 |
-
// Sort by ID to avoid excessive remapping later
|
1264 |
-
usort( $comments, array( $this, 'sort_comments_by_id' ) );
|
1265 |
-
|
1266 |
-
foreach ( $comments as $key => $comment ) {
|
1267 |
-
/**
|
1268 |
-
* Pre-process comment data
|
1269 |
-
*
|
1270 |
-
* @param array $comment Comment data. (Return empty to skip.)
|
1271 |
-
* @param int $post_id Post the comment is attached to.
|
1272 |
-
*/
|
1273 |
-
$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
|
1274 |
-
if ( empty( $comment ) ) {
|
1275 |
-
return false;
|
1276 |
-
}
|
1277 |
-
|
1278 |
-
$original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
|
1279 |
-
$parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
|
1280 |
-
$author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
|
1281 |
-
|
1282 |
-
// if this is a new post we can skip the comment_exists() check
|
1283 |
-
// TODO: Check comment_exists for performance
|
1284 |
-
if ( $post_exists ) {
|
1285 |
-
$existing = $this->comment_exists( $comment );
|
1286 |
-
if ( $existing ) {
|
1287 |
-
$this->mapping['comment'][ $original_id ] = $exists;
|
1288 |
-
continue;
|
1289 |
-
}
|
1290 |
-
}
|
1291 |
-
|
1292 |
-
// Remove meta from the main array
|
1293 |
-
$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
|
1294 |
-
unset( $comment['commentmeta'] );
|
1295 |
-
|
1296 |
-
// Map the parent comment, or mark it as one we need to fix
|
1297 |
-
$requires_remapping = false;
|
1298 |
-
if ( $parent_id ) {
|
1299 |
-
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1300 |
-
$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1301 |
-
} else {
|
1302 |
-
// Prepare for remapping later
|
1303 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1304 |
-
$requires_remapping = true;
|
1305 |
-
|
1306 |
-
// Wipe the parent for now
|
1307 |
-
$comment['comment_parent'] = 0;
|
1308 |
-
}
|
1309 |
-
}
|
1310 |
-
|
1311 |
-
// Map the author, or mark it as one we need to fix
|
1312 |
-
if ( $author_id ) {
|
1313 |
-
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1314 |
-
$comment['user_id'] = $this->mapping['user'][ $author_id ];
|
1315 |
-
} else {
|
1316 |
-
// Prepare for remapping later
|
1317 |
-
$meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id );
|
1318 |
-
$requires_remapping = true;
|
1319 |
-
|
1320 |
-
// Wipe the user for now
|
1321 |
-
$comment['user_id'] = 0;
|
1322 |
-
}
|
1323 |
-
}
|
1324 |
-
|
1325 |
-
// Run standard core filters
|
1326 |
-
$comment['comment_post_ID'] = $post_id;
|
1327 |
-
$comment = wp_filter_comment( $comment );
|
1328 |
-
|
1329 |
-
// wp_insert_comment expects slashed data
|
1330 |
-
$comment_id = wp_insert_comment( wp_slash( $comment ) );
|
1331 |
-
$this->mapping['comment'][ $original_id ] = $comment_id;
|
1332 |
-
if ( $requires_remapping ) {
|
1333 |
-
$this->requires_remapping['comment'][ $comment_id ] = true;
|
1334 |
-
}
|
1335 |
-
$this->mark_comment_exists( $comment, $comment_id );
|
1336 |
-
|
1337 |
-
/**
|
1338 |
-
* Comment has been imported.
|
1339 |
-
*
|
1340 |
-
* @param int $comment_id New comment ID
|
1341 |
-
* @param array $comment Comment inserted (`comment_id` item refers to the original ID)
|
1342 |
-
* @param int $post_id Post parent of the comment
|
1343 |
-
* @param array $post Post data
|
1344 |
-
*/
|
1345 |
-
do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
|
1346 |
-
|
1347 |
-
// Process the meta items
|
1348 |
-
foreach ( $meta as $meta_item ) {
|
1349 |
-
$value = maybe_unserialize( $meta_item['value'] );
|
1350 |
-
add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
|
1351 |
-
}
|
1352 |
-
|
1353 |
-
/**
|
1354 |
-
* Post processing completed.
|
1355 |
-
*
|
1356 |
-
* @param int $post_id New post ID.
|
1357 |
-
* @param array $comment Raw data imported for the comment.
|
1358 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
1359 |
-
* @param array $post_id Parent post ID.
|
1360 |
-
*/
|
1361 |
-
do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
|
1362 |
-
|
1363 |
-
$num_comments++;
|
1364 |
-
}
|
1365 |
-
|
1366 |
-
return $num_comments;
|
1367 |
-
}
|
1368 |
-
|
1369 |
-
protected function parse_category_node( $node ) {
|
1370 |
-
$data = array(
|
1371 |
-
// Default taxonomy to "category", since this is a `<category>` tag
|
1372 |
-
'taxonomy' => 'category',
|
1373 |
-
);
|
1374 |
-
$meta = array();
|
1375 |
-
|
1376 |
-
if ( $node->hasAttribute( 'domain' ) ) {
|
1377 |
-
$data['taxonomy'] = $node->getAttribute( 'domain' );
|
1378 |
-
}
|
1379 |
-
if ( $node->hasAttribute( 'nicename' ) ) {
|
1380 |
-
$data['slug'] = $node->getAttribute( 'nicename' );
|
1381 |
-
}
|
1382 |
-
|
1383 |
-
$data['name'] = $node->textContent;
|
1384 |
-
|
1385 |
-
if ( empty( $data['slug'] ) ) {
|
1386 |
-
return null;
|
1387 |
-
}
|
1388 |
-
|
1389 |
-
// Just for extra compatibility
|
1390 |
-
if ( $data['taxonomy'] === 'tag' ) {
|
1391 |
-
$data['taxonomy'] = 'post_tag';
|
1392 |
-
}
|
1393 |
-
|
1394 |
-
return $data;
|
1395 |
-
}
|
1396 |
-
|
1397 |
-
/**
|
1398 |
-
* Callback for `usort` to sort comments by ID
|
1399 |
-
*
|
1400 |
-
* @param array $a Comment data for the first comment
|
1401 |
-
* @param array $b Comment data for the second comment
|
1402 |
-
* @return int
|
1403 |
-
*/
|
1404 |
-
public static function sort_comments_by_id( $a, $b ) {
|
1405 |
-
if ( empty( $a['comment_id'] ) ) {
|
1406 |
-
return 1;
|
1407 |
-
}
|
1408 |
-
|
1409 |
-
if ( empty( $b['comment_id'] ) ) {
|
1410 |
-
return -1;
|
1411 |
-
}
|
1412 |
-
|
1413 |
-
return $a['comment_id'] - $b['comment_id'];
|
1414 |
-
}
|
1415 |
-
|
1416 |
-
protected function parse_author_node( $node ) {
|
1417 |
-
$data = array();
|
1418 |
-
$meta = array();
|
1419 |
-
foreach ( $node->childNodes as $child ) {
|
1420 |
-
// We only care about child elements
|
1421 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1422 |
-
continue;
|
1423 |
-
}
|
1424 |
-
|
1425 |
-
switch ( $child->tagName ) {
|
1426 |
-
case 'wp:author_login':
|
1427 |
-
$data['user_login'] = $child->textContent;
|
1428 |
-
break;
|
1429 |
-
|
1430 |
-
case 'wp:author_id':
|
1431 |
-
$data['ID'] = $child->textContent;
|
1432 |
-
break;
|
1433 |
-
|
1434 |
-
case 'wp:author_email':
|
1435 |
-
$data['user_email'] = $child->textContent;
|
1436 |
-
break;
|
1437 |
-
|
1438 |
-
case 'wp:author_display_name':
|
1439 |
-
$data['display_name'] = $child->textContent;
|
1440 |
-
break;
|
1441 |
-
|
1442 |
-
case 'wp:author_first_name':
|
1443 |
-
$data['first_name'] = $child->textContent;
|
1444 |
-
break;
|
1445 |
-
|
1446 |
-
case 'wp:author_last_name':
|
1447 |
-
$data['last_name'] = $child->textContent;
|
1448 |
-
break;
|
1449 |
-
}
|
1450 |
-
}
|
1451 |
-
|
1452 |
-
return compact( 'data', 'meta' );
|
1453 |
-
}
|
1454 |
-
|
1455 |
-
protected function process_author( $data, $meta ) {
|
1456 |
-
/**
|
1457 |
-
* Pre-process user data.
|
1458 |
-
*
|
1459 |
-
* @param array $data User data. (Return empty to skip.)
|
1460 |
-
* @param array $meta Meta data.
|
1461 |
-
*/
|
1462 |
-
$data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
|
1463 |
-
if ( empty( $data ) ) {
|
1464 |
-
return false;
|
1465 |
-
}
|
1466 |
-
|
1467 |
-
// Have we already handled this user?
|
1468 |
-
$original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
|
1469 |
-
$original_slug = $data['user_login'];
|
1470 |
-
|
1471 |
-
if ( isset( $this->mapping['user'][ $original_id ] ) ) {
|
1472 |
-
$existing = $this->mapping['user'][ $original_id ];
|
1473 |
-
|
1474 |
-
// Note the slug mapping if we need to too
|
1475 |
-
if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1476 |
-
$this->mapping['user_slug'][ $original_slug ] = $existing;
|
1477 |
-
}
|
1478 |
-
|
1479 |
-
return false;
|
1480 |
-
}
|
1481 |
-
|
1482 |
-
if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1483 |
-
$existing = $this->mapping['user_slug'][ $original_slug ];
|
1484 |
-
|
1485 |
-
// Ensure we note the mapping too
|
1486 |
-
$this->mapping['user'][ $original_id ] = $existing;
|
1487 |
-
|
1488 |
-
return false;
|
1489 |
-
}
|
1490 |
-
|
1491 |
-
// Allow overriding the user's slug
|
1492 |
-
$login = $original_slug;
|
1493 |
-
if ( isset( $this->user_slug_override[ $login ] ) ) {
|
1494 |
-
$login = $this->user_slug_override[ $login ];
|
1495 |
-
}
|
1496 |
-
|
1497 |
-
$userdata = array(
|
1498 |
-
'user_login' => sanitize_user( $login, true ),
|
1499 |
-
'user_pass' => wp_generate_password(),
|
1500 |
-
);
|
1501 |
-
|
1502 |
-
$allowed = array(
|
1503 |
-
'user_email' => true,
|
1504 |
-
'display_name' => true,
|
1505 |
-
'first_name' => true,
|
1506 |
-
'last_name' => true,
|
1507 |
-
);
|
1508 |
-
foreach ( $data as $key => $value ) {
|
1509 |
-
if ( ! isset( $allowed[ $key ] ) ) {
|
1510 |
-
continue;
|
1511 |
-
}
|
1512 |
-
|
1513 |
-
$userdata[ $key ] = $data[ $key ];
|
1514 |
-
}
|
1515 |
-
|
1516 |
-
$user_id = wp_insert_user( wp_slash( $userdata ) );
|
1517 |
-
if ( is_wp_error( $user_id ) ) {
|
1518 |
-
$this->logger->error( sprintf(
|
1519 |
-
__( 'Failed to import user "%s"', 'rara-one-click-demo-import' ),
|
1520 |
-
$userdata['user_login']
|
1521 |
-
) );
|
1522 |
-
$this->logger->debug( $user_id->get_error_message() );
|
1523 |
-
|
1524 |
-
/**
|
1525 |
-
* User processing failed.
|
1526 |
-
*
|
1527 |
-
* @param WP_Error $user_id Error object.
|
1528 |
-
* @param array $userdata Raw data imported for the user.
|
1529 |
-
*/
|
1530 |
-
do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
|
1531 |
-
return false;
|
1532 |
-
}
|
1533 |
-
|
1534 |
-
if ( $original_id ) {
|
1535 |
-
$this->mapping['user'][ $original_id ] = $user_id;
|
1536 |
-
}
|
1537 |
-
$this->mapping['user_slug'][ $original_slug ] = $user_id;
|
1538 |
-
|
1539 |
-
$this->logger->info( sprintf(
|
1540 |
-
__( 'Imported user "%s"', 'rara-one-click-demo-import' ),
|
1541 |
-
$userdata['user_login']
|
1542 |
-
) );
|
1543 |
-
$this->logger->debug( sprintf(
|
1544 |
-
__( 'User %d remapped to %d', 'rara-one-click-demo-import' ),
|
1545 |
-
$original_id,
|
1546 |
-
$user_id
|
1547 |
-
) );
|
1548 |
-
|
1549 |
-
// TODO: Implement meta handling once WXR includes it
|
1550 |
-
/**
|
1551 |
-
* User processing completed.
|
1552 |
-
*
|
1553 |
-
* @param int $user_id New user ID.
|
1554 |
-
* @param array $userdata Raw data imported for the user.
|
1555 |
-
*/
|
1556 |
-
do_action( 'wxr_importer.processed.user', $user_id, $userdata );
|
1557 |
-
}
|
1558 |
-
|
1559 |
-
protected function parse_term_node( $node, $type = 'term' ) {
|
1560 |
-
$data = array();
|
1561 |
-
$meta = array();
|
1562 |
-
|
1563 |
-
$tag_name = array(
|
1564 |
-
'id' => 'wp:term_id',
|
1565 |
-
'taxonomy' => 'wp:term_taxonomy',
|
1566 |
-
'slug' => 'wp:term_slug',
|
1567 |
-
'parent' => 'wp:term_parent',
|
1568 |
-
'name' => 'wp:term_name',
|
1569 |
-
'description' => 'wp:term_description',
|
1570 |
-
);
|
1571 |
-
$taxonomy = null;
|
1572 |
-
|
1573 |
-
// Special casing!
|
1574 |
-
switch ( $type ) {
|
1575 |
-
case 'category':
|
1576 |
-
$tag_name['slug'] = 'wp:category_nicename';
|
1577 |
-
$tag_name['parent'] = 'wp:category_parent';
|
1578 |
-
$tag_name['name'] = 'wp:cat_name';
|
1579 |
-
$tag_name['description'] = 'wp:category_description';
|
1580 |
-
$tag_name['taxonomy'] = null;
|
1581 |
-
|
1582 |
-
$data['taxonomy'] = 'category';
|
1583 |
-
break;
|
1584 |
-
|
1585 |
-
case 'tag':
|
1586 |
-
$tag_name['slug'] = 'wp:tag_slug';
|
1587 |
-
$tag_name['parent'] = null;
|
1588 |
-
$tag_name['name'] = 'wp:tag_name';
|
1589 |
-
$tag_name['description'] = 'wp:tag_description';
|
1590 |
-
$tag_name['taxonomy'] = null;
|
1591 |
-
|
1592 |
-
$data['taxonomy'] = 'post_tag';
|
1593 |
-
break;
|
1594 |
-
}
|
1595 |
-
|
1596 |
-
foreach ( $node->childNodes as $child ) {
|
1597 |
-
// We only care about child elements
|
1598 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1599 |
-
continue;
|
1600 |
-
}
|
1601 |
-
|
1602 |
-
$key = array_search( $child->tagName, $tag_name );
|
1603 |
-
if ( $key ) {
|
1604 |
-
$data[ $key ] = $child->textContent;
|
1605 |
-
}
|
1606 |
-
}
|
1607 |
-
|
1608 |
-
if ( empty( $data['taxonomy'] ) ) {
|
1609 |
-
return null;
|
1610 |
-
}
|
1611 |
-
|
1612 |
-
// Compatibility with WXR 1.0
|
1613 |
-
if ( $data['taxonomy'] === 'tag' ) {
|
1614 |
-
$data['taxonomy'] = 'post_tag';
|
1615 |
-
}
|
1616 |
-
|
1617 |
-
return compact( 'data', 'meta' );
|
1618 |
-
}
|
1619 |
-
|
1620 |
-
protected function process_term( $data, $meta ) {
|
1621 |
-
/**
|
1622 |
-
* Pre-process term data.
|
1623 |
-
*
|
1624 |
-
* @param array $data Term data. (Return empty to skip.)
|
1625 |
-
* @param array $meta Meta data.
|
1626 |
-
*/
|
1627 |
-
$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
|
1628 |
-
if ( empty( $data ) ) {
|
1629 |
-
return false;
|
1630 |
-
}
|
1631 |
-
|
1632 |
-
$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
|
1633 |
-
$parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
|
1634 |
-
|
1635 |
-
$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
1636 |
-
$existing = $this->term_exists( $data );
|
1637 |
-
if ( $existing ) {
|
1638 |
-
$this->mapping['term'][ $mapping_key ] = $existing;
|
1639 |
-
$this->mapping['term_id'][ $original_id ] = $existing;
|
1640 |
-
return false;
|
1641 |
-
}
|
1642 |
-
|
1643 |
-
// WP really likes to repeat itself in export files
|
1644 |
-
if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
|
1645 |
-
return false;
|
1646 |
-
}
|
1647 |
-
|
1648 |
-
$termdata = array();
|
1649 |
-
$allowed = array(
|
1650 |
-
'slug' => true,
|
1651 |
-
'description' => true,
|
1652 |
-
);
|
1653 |
-
|
1654 |
-
// Map the parent comment, or mark it as one we need to fix
|
1655 |
-
// TODO: add parent mapping and remapping
|
1656 |
-
/*$requires_remapping = false;
|
1657 |
-
if ( $parent_id ) {
|
1658 |
-
if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
|
1659 |
-
$data['parent'] = $this->mapping['term'][ $parent_id ];
|
1660 |
-
} else {
|
1661 |
-
// Prepare for remapping later
|
1662 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1663 |
-
$requires_remapping = true;
|
1664 |
-
|
1665 |
-
// Wipe the parent for now
|
1666 |
-
$data['parent'] = 0;
|
1667 |
-
}
|
1668 |
-
}*/
|
1669 |
-
|
1670 |
-
foreach ( $data as $key => $value ) {
|
1671 |
-
if ( ! isset( $allowed[ $key ] ) ) {
|
1672 |
-
continue;
|
1673 |
-
}
|
1674 |
-
|
1675 |
-
$termdata[ $key ] = $data[ $key ];
|
1676 |
-
}
|
1677 |
-
|
1678 |
-
$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
|
1679 |
-
if ( is_wp_error( $result ) ) {
|
1680 |
-
$this->logger->warning( sprintf(
|
1681 |
-
__( 'Failed to import %s %s', 'rara-one-click-demo-import' ),
|
1682 |
-
$data['taxonomy'],
|
1683 |
-
$data['name']
|
1684 |
-
) );
|
1685 |
-
$this->logger->debug( $result->get_error_message() );
|
1686 |
-
do_action( 'wp_import_insert_term_failed', $result, $data );
|
1687 |
-
|
1688 |
-
/**
|
1689 |
-
* Term processing failed.
|
1690 |
-
*
|
1691 |
-
* @param WP_Error $result Error object.
|
1692 |
-
* @param array $data Raw data imported for the term.
|
1693 |
-
* @param array $meta Meta data supplied for the term.
|
1694 |
-
*/
|
1695 |
-
do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
|
1696 |
-
return false;
|
1697 |
-
}
|
1698 |
-
|
1699 |
-
$term_id = $result['term_id'];
|
1700 |
-
|
1701 |
-
$this->mapping['term'][ $mapping_key ] = $term_id;
|
1702 |
-
$this->mapping['term_id'][ $original_id ] = $term_id;
|
1703 |
-
|
1704 |
-
$this->logger->info( sprintf(
|
1705 |
-
__( 'Imported "%s" (%s)', 'rara-one-click-demo-import' ),
|
1706 |
-
$data['name'],
|
1707 |
-
$data['taxonomy']
|
1708 |
-
) );
|
1709 |
-
$this->logger->debug( sprintf(
|
1710 |
-
__( 'Term %d remapped to %d', 'rara-one-click-demo-import' ),
|
1711 |
-
$original_id,
|
1712 |
-
$term_id
|
1713 |
-
) );
|
1714 |
-
|
1715 |
-
do_action( 'wp_import_insert_term', $term_id, $data );
|
1716 |
-
|
1717 |
-
/**
|
1718 |
-
* Term processing completed.
|
1719 |
-
*
|
1720 |
-
* @param int $term_id New term ID.
|
1721 |
-
* @param array $data Raw data imported for the term.
|
1722 |
-
*/
|
1723 |
-
do_action( 'wxr_importer.processed.term', $term_id, $data );
|
1724 |
-
}
|
1725 |
-
|
1726 |
-
/**
|
1727 |
-
* Attempt to download a remote file attachment
|
1728 |
-
*
|
1729 |
-
* @param string $url URL of item to fetch
|
1730 |
-
* @param array $post Attachment details
|
1731 |
-
* @return array|WP_Error Local file location details on success, WP_Error otherwise
|
1732 |
-
*/
|
1733 |
-
protected function fetch_remote_file( $url, $post ) {
|
1734 |
-
// extract the file name and extension from the url
|
1735 |
-
$file_name = basename( $url );
|
1736 |
-
|
1737 |
-
// get placeholder file in the upload dir with a unique, sanitized filename
|
1738 |
-
$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
|
1739 |
-
if ( $upload['error'] ) {
|
1740 |
-
return new WP_Error( 'upload_dir_error', $upload['error'] );
|
1741 |
-
}
|
1742 |
-
|
1743 |
-
// fetch the remote url and write it to the placeholder file
|
1744 |
-
$response = wp_remote_get( $url, array(
|
1745 |
-
'stream' => true,
|
1746 |
-
'filename' => $upload['file'],
|
1747 |
-
) );
|
1748 |
-
|
1749 |
-
// request failed
|
1750 |
-
if ( is_wp_error( $response ) ) {
|
1751 |
-
unlink( $upload['file'] );
|
1752 |
-
return $response;
|
1753 |
-
}
|
1754 |
-
|
1755 |
-
$code = (int) wp_remote_retrieve_response_code( $response );
|
1756 |
-
|
1757 |
-
// make sure the fetch was successful
|
1758 |
-
if ( $code !== 200 ) {
|
1759 |
-
unlink( $upload['file'] );
|
1760 |
-
return new WP_Error(
|
1761 |
-
'import_file_error',
|
1762 |
-
sprintf(
|
1763 |
-
__( 'Remote server returned %1$d %2$s for %3$s', 'rara-one-click-demo-import' ),
|
1764 |
-
$code,
|
1765 |
-
get_status_header_desc( $code ),
|
1766 |
-
$url
|
1767 |
-
)
|
1768 |
-
);
|
1769 |
-
}
|
1770 |
-
|
1771 |
-
$filesize = filesize( $upload['file'] );
|
1772 |
-
$headers = wp_remote_retrieve_headers( $response );
|
1773 |
-
|
1774 |
-
if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
|
1775 |
-
unlink( $upload['file'] );
|
1776 |
-
return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'rara-one-click-demo-import' ) );
|
1777 |
-
}
|
1778 |
-
|
1779 |
-
if ( 0 === $filesize ) {
|
1780 |
-
unlink( $upload['file'] );
|
1781 |
-
return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'rara-one-click-demo-import' ) );
|
1782 |
-
}
|
1783 |
-
|
1784 |
-
$max_size = (int) $this->max_attachment_size();
|
1785 |
-
if ( ! empty( $max_size ) && $filesize > $max_size ) {
|
1786 |
-
unlink( $upload['file'] );
|
1787 |
-
$message = sprintf( __( 'Remote file is too large, limit is %s', 'rara-one-click-demo-import' ), size_format( $max_size ) );
|
1788 |
-
return new WP_Error( 'import_file_error', $message );
|
1789 |
-
}
|
1790 |
-
|
1791 |
-
return $upload;
|
1792 |
-
}
|
1793 |
-
|
1794 |
-
protected function post_process() {
|
1795 |
-
// Time to tackle any left-over bits
|
1796 |
-
if ( ! empty( $this->requires_remapping['post'] ) ) {
|
1797 |
-
$this->post_process_posts( $this->requires_remapping['post'] );
|
1798 |
-
}
|
1799 |
-
if ( ! empty( $this->requires_remapping['comment'] ) ) {
|
1800 |
-
$this->post_process_comments( $this->requires_remapping['comment'] );
|
1801 |
-
}
|
1802 |
-
}
|
1803 |
-
|
1804 |
-
protected function post_process_posts( $todo ) {
|
1805 |
-
foreach ( $todo as $post_id => $_ ) {
|
1806 |
-
$this->logger->debug( sprintf(
|
1807 |
-
// Note: title intentionally not used to skip extra processing
|
1808 |
-
// for when debug logging is off
|
1809 |
-
__( 'Running post-processing for post %d', 'rara-one-click-demo-import' ),
|
1810 |
-
$post_id
|
1811 |
-
) );
|
1812 |
-
|
1813 |
-
$data = array();
|
1814 |
-
|
1815 |
-
$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
|
1816 |
-
if ( ! empty( $parent_id ) ) {
|
1817 |
-
// Have we imported the parent now?
|
1818 |
-
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
1819 |
-
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
1820 |
-
} else {
|
1821 |
-
$this->logger->warning( sprintf(
|
1822 |
-
__( 'Could not find the post parent for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1823 |
-
get_the_title( $post_id ),
|
1824 |
-
$post_id
|
1825 |
-
) );
|
1826 |
-
$this->logger->debug( sprintf(
|
1827 |
-
__( 'Post %d was imported with parent %d, but could not be found', 'rara-one-click-demo-import' ),
|
1828 |
-
$post_id,
|
1829 |
-
$parent_id
|
1830 |
-
) );
|
1831 |
-
}
|
1832 |
-
}
|
1833 |
-
|
1834 |
-
$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
|
1835 |
-
if ( ! empty( $author_slug ) ) {
|
1836 |
-
// Have we imported the user now?
|
1837 |
-
if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
|
1838 |
-
$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
|
1839 |
-
} else {
|
1840 |
-
$this->logger->warning( sprintf(
|
1841 |
-
__( 'Could not find the author for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1842 |
-
get_the_title( $post_id ),
|
1843 |
-
$post_id
|
1844 |
-
) );
|
1845 |
-
$this->logger->debug( sprintf(
|
1846 |
-
__( 'Post %d was imported with author "%s", but could not be found', 'rara-one-click-demo-import' ),
|
1847 |
-
$post_id,
|
1848 |
-
$author_slug
|
1849 |
-
) );
|
1850 |
-
}
|
1851 |
-
}
|
1852 |
-
|
1853 |
-
$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
|
1854 |
-
if ( ! empty( $has_attachments ) ) {
|
1855 |
-
$post = get_post( $post_id );
|
1856 |
-
$content = $post->post_content;
|
1857 |
-
|
1858 |
-
// Replace all the URLs we've got
|
1859 |
-
$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
|
1860 |
-
if ( $new_content !== $content ) {
|
1861 |
-
$data['post_content'] = $new_content;
|
1862 |
-
}
|
1863 |
-
}
|
1864 |
-
|
1865 |
-
if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
|
1866 |
-
$this->post_process_menu_item( $post_id );
|
1867 |
-
}
|
1868 |
-
|
1869 |
-
// Do we have updates to make?
|
1870 |
-
if ( empty( $data ) ) {
|
1871 |
-
$this->logger->debug( sprintf(
|
1872 |
-
__( 'Post %d was marked for post-processing, but none was required.', 'rara-one-click-demo-import' ),
|
1873 |
-
$post_id
|
1874 |
-
) );
|
1875 |
-
continue;
|
1876 |
-
}
|
1877 |
-
|
1878 |
-
// Run the update
|
1879 |
-
$data['ID'] = $post_id;
|
1880 |
-
$result = wp_update_post( $data, true );
|
1881 |
-
if ( is_wp_error( $result ) ) {
|
1882 |
-
$this->logger->warning( sprintf(
|
1883 |
-
__( 'Could not update "%s" (post #%d) with mapped data', 'rara-one-click-demo-import' ),
|
1884 |
-
get_the_title( $post_id ),
|
1885 |
-
$post_id
|
1886 |
-
) );
|
1887 |
-
$this->logger->debug( $result->get_error_message() );
|
1888 |
-
continue;
|
1889 |
-
}
|
1890 |
-
|
1891 |
-
// Clear out our temporary meta keys
|
1892 |
-
delete_post_meta( $post_id, '_wxr_import_parent' );
|
1893 |
-
delete_post_meta( $post_id, '_wxr_import_user_slug' );
|
1894 |
-
delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
|
1895 |
-
}
|
1896 |
-
}
|
1897 |
-
|
1898 |
-
protected function post_process_menu_item( $post_id ) {
|
1899 |
-
$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
|
1900 |
-
if ( empty( $menu_object_id ) ) {
|
1901 |
-
// No processing needed!
|
1902 |
-
return;
|
1903 |
-
}
|
1904 |
-
|
1905 |
-
$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
1906 |
-
switch ( $menu_item_type ) {
|
1907 |
-
case 'taxonomy':
|
1908 |
-
if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
|
1909 |
-
$menu_object = $this->mapping['term_id'][ $menu_object_id ];
|
1910 |
-
}
|
1911 |
-
break;
|
1912 |
-
|
1913 |
-
case 'post_type':
|
1914 |
-
if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
|
1915 |
-
$menu_object = $this->mapping['post'][ $menu_object_id ];
|
1916 |
-
}
|
1917 |
-
break;
|
1918 |
-
|
1919 |
-
default:
|
1920 |
-
// Cannot handle this.
|
1921 |
-
return;
|
1922 |
-
}
|
1923 |
-
|
1924 |
-
if ( ! empty( $menu_object ) ) {
|
1925 |
-
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
|
1926 |
-
} else {
|
1927 |
-
$this->logger->warning( sprintf(
|
1928 |
-
__( 'Could not find the menu object for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1929 |
-
get_the_title( $post_id ),
|
1930 |
-
$post_id
|
1931 |
-
) );
|
1932 |
-
$this->logger->debug( sprintf(
|
1933 |
-
__( 'Post %d was imported with object "%d" of type "%s", but could not be found', 'rara-one-click-demo-import' ),
|
1934 |
-
$post_id,
|
1935 |
-
$menu_object_id,
|
1936 |
-
$menu_item_type
|
1937 |
-
) );
|
1938 |
-
}
|
1939 |
-
|
1940 |
-
delete_post_meta( $post_id, '_wxr_import_menu_item' );
|
1941 |
-
}
|
1942 |
-
|
1943 |
-
|
1944 |
-
protected function post_process_comments( $todo ) {
|
1945 |
-
foreach ( $todo as $comment_id => $_ ) {
|
1946 |
-
$data = array();
|
1947 |
-
|
1948 |
-
$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
|
1949 |
-
if ( ! empty( $parent_id ) ) {
|
1950 |
-
// Have we imported the parent now?
|
1951 |
-
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1952 |
-
$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1953 |
-
} else {
|
1954 |
-
$this->logger->warning( sprintf(
|
1955 |
-
__( 'Could not find the comment parent for comment #%d', 'rara-one-click-demo-import' ),
|
1956 |
-
$comment_id
|
1957 |
-
) );
|
1958 |
-
$this->logger->debug( sprintf(
|
1959 |
-
__( 'Comment %d was imported with parent %d, but could not be found', 'rara-one-click-demo-import' ),
|
1960 |
-
$comment_id,
|
1961 |
-
$parent_id
|
1962 |
-
) );
|
1963 |
-
}
|
1964 |
-
}
|
1965 |
-
|
1966 |
-
$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
|
1967 |
-
if ( ! empty( $author_id ) ) {
|
1968 |
-
// Have we imported the user now?
|
1969 |
-
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1970 |
-
$data['user_id'] = $this->mapping['user'][ $author_id ];
|
1971 |
-
} else {
|
1972 |
-
$this->logger->warning( sprintf(
|
1973 |
-
__( 'Could not find the author for comment #%d', 'rara-one-click-demo-import' ),
|
1974 |
-
$comment_id
|
1975 |
-
) );
|
1976 |
-
$this->logger->debug( sprintf(
|
1977 |
-
__( 'Comment %d was imported with author %d, but could not be found', 'rara-one-click-demo-import' ),
|
1978 |
-
$comment_id,
|
1979 |
-
$author_id
|
1980 |
-
) );
|
1981 |
-
}
|
1982 |
-
}
|
1983 |
-
|
1984 |
-
// Do we have updates to make?
|
1985 |
-
if ( empty( $data ) ) {
|
1986 |
-
continue;
|
1987 |
-
}
|
1988 |
-
|
1989 |
-
// Run the update
|
1990 |
-
$data['comment_ID'] = $comment_ID;
|
1991 |
-
$result = wp_update_comment( wp_slash( $data ) );
|
1992 |
-
if ( empty( $result ) ) {
|
1993 |
-
$this->logger->warning( sprintf(
|
1994 |
-
__( 'Could not update comment #%d with mapped data', 'rara-one-click-demo-import' ),
|
1995 |
-
$comment_id
|
1996 |
-
) );
|
1997 |
-
continue;
|
1998 |
-
}
|
1999 |
-
|
2000 |
-
// Clear out our temporary meta keys
|
2001 |
-
delete_comment_meta( $comment_id, '_wxr_import_parent' );
|
2002 |
-
delete_comment_meta( $comment_id, '_wxr_import_user' );
|
2003 |
-
}
|
2004 |
-
}
|
2005 |
-
|
2006 |
-
/**
|
2007 |
-
* Use stored mapping information to update old attachment URLs
|
2008 |
-
*/
|
2009 |
-
protected function replace_attachment_urls_in_content() {
|
2010 |
-
global $wpdb;
|
2011 |
-
// make sure we do the longest urls first, in case one is a substring of another
|
2012 |
-
uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
|
2013 |
-
|
2014 |
-
foreach ( $this->url_remap as $from_url => $to_url ) {
|
2015 |
-
// remap urls in post_content
|
2016 |
-
$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
|
2017 |
-
$wpdb->query( $query );
|
2018 |
-
|
2019 |
-
// remap enclosure urls
|
2020 |
-
$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
|
2021 |
-
$result = $wpdb->query( $query );
|
2022 |
-
}
|
2023 |
-
}
|
2024 |
-
|
2025 |
-
/**
|
2026 |
-
* Update _thumbnail_id meta to new, imported attachment IDs
|
2027 |
-
*/
|
2028 |
-
function remap_featured_images() {
|
2029 |
-
// cycle through posts that have a featured image
|
2030 |
-
foreach ( $this->featured_images as $post_id => $value ) {
|
2031 |
-
if ( isset( $this->processed_posts[ $value ] ) ) {
|
2032 |
-
$new_id = $this->processed_posts[ $value ];
|
2033 |
-
|
2034 |
-
// only update if there's a difference
|
2035 |
-
if ( $new_id !== $value ) {
|
2036 |
-
update_post_meta( $post_id, '_thumbnail_id', $new_id );
|
2037 |
-
}
|
2038 |
-
}
|
2039 |
-
}
|
2040 |
-
}
|
2041 |
-
|
2042 |
-
/**
|
2043 |
-
* Decide if the given meta key maps to information we will want to import
|
2044 |
-
*
|
2045 |
-
* @param string $key The meta key to check
|
2046 |
-
* @return string|bool The key if we do want to import, false if not
|
2047 |
-
*/
|
2048 |
-
public function is_valid_meta_key( $key ) {
|
2049 |
-
// skip attachment metadata since we'll regenerate it from scratch
|
2050 |
-
// skip _edit_lock as not relevant for import
|
2051 |
-
if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
|
2052 |
-
return false;
|
2053 |
-
}
|
2054 |
-
|
2055 |
-
return $key;
|
2056 |
-
}
|
2057 |
-
|
2058 |
-
/**
|
2059 |
-
* Decide what the maximum file size for downloaded attachments is.
|
2060 |
-
* Default is 0 (unlimited), can be filtered via import_attachment_size_limit
|
2061 |
-
*
|
2062 |
-
* @return int Maximum attachment file size to import
|
2063 |
-
*/
|
2064 |
-
protected function max_attachment_size() {
|
2065 |
-
return apply_filters( 'import_attachment_size_limit', 0 );
|
2066 |
-
}
|
2067 |
-
|
2068 |
-
/**
|
2069 |
-
* Added to http_request_timeout filter to force timeout at 60 seconds during import
|
2070 |
-
*
|
2071 |
-
* @access protected
|
2072 |
-
* @return int 60
|
2073 |
-
*/
|
2074 |
-
function bump_request_timeout($val) {
|
2075 |
-
return 60;
|
2076 |
-
}
|
2077 |
-
|
2078 |
-
// return the difference in length between two strings
|
2079 |
-
function cmpr_strlen( $a, $b ) {
|
2080 |
-
return strlen( $b ) - strlen( $a );
|
2081 |
-
}
|
2082 |
-
|
2083 |
-
/**
|
2084 |
-
* Prefill existing post data.
|
2085 |
-
*
|
2086 |
-
* This preloads all GUIDs into memory, allowing us to avoid hitting the
|
2087 |
-
* database when we need to check for existence. With larger imports, this
|
2088 |
-
* becomes prohibitively slow to perform SELECT queries on each.
|
2089 |
-
*
|
2090 |
-
* By preloading all this data into memory, it's a constant-time lookup in
|
2091 |
-
* PHP instead. However, this does use a lot more memory, so for sites doing
|
2092 |
-
* small imports onto a large site, it may be a better tradeoff to use
|
2093 |
-
* on-the-fly checking instead.
|
2094 |
-
*/
|
2095 |
-
protected function prefill_existing_posts() {
|
2096 |
-
global $wpdb;
|
2097 |
-
$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
|
2098 |
-
|
2099 |
-
foreach ( $posts as $item ) {
|
2100 |
-
$this->exists['post'][ $item->guid ] = $item->ID;
|
2101 |
-
}
|
2102 |
-
}
|
2103 |
-
|
2104 |
-
/**
|
2105 |
-
* Does the post exist?
|
2106 |
-
*
|
2107 |
-
* @param array $data Post data to check against.
|
2108 |
-
* @return int|bool Existing post ID if it exists, false otherwise.
|
2109 |
-
*/
|
2110 |
-
protected function post_exists( $data ) {
|
2111 |
-
// Constant-time lookup if we prefilled
|
2112 |
-
$exists_key = $data['guid'];
|
2113 |
-
|
2114 |
-
if ( $this->options['prefill_existing_posts'] ) {
|
2115 |
-
return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
|
2116 |
-
}
|
2117 |
-
|
2118 |
-
// No prefilling, but might have already handled it
|
2119 |
-
if ( isset( $this->exists['post'][ $exists_key ] ) ) {
|
2120 |
-
return $this->exists['post'][ $exists_key ];
|
2121 |
-
}
|
2122 |
-
|
2123 |
-
// Still nothing, try post_exists, and cache it
|
2124 |
-
$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
|
2125 |
-
$this->exists['post'][ $exists_key ] = $exists;
|
2126 |
-
|
2127 |
-
return $exists;
|
2128 |
-
}
|
2129 |
-
|
2130 |
-
/**
|
2131 |
-
* Mark the post as existing.
|
2132 |
-
*
|
2133 |
-
* @param array $data Post data to mark as existing.
|
2134 |
-
* @param int $post_id Post ID.
|
2135 |
-
*/
|
2136 |
-
protected function mark_post_exists( $data, $post_id ) {
|
2137 |
-
$exists_key = $data['guid'];
|
2138 |
-
$this->exists['post'][ $exists_key ] = $post_id;
|
2139 |
-
}
|
2140 |
-
|
2141 |
-
/**
|
2142 |
-
* Prefill existing comment data.
|
2143 |
-
*
|
2144 |
-
* @see self::prefill_existing_posts() for justification of why this exists.
|
2145 |
-
*/
|
2146 |
-
protected function prefill_existing_comments() {
|
2147 |
-
global $wpdb;
|
2148 |
-
$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
|
2149 |
-
|
2150 |
-
foreach ( $posts as $item ) {
|
2151 |
-
$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
|
2152 |
-
$this->exists['comment'][ $exists_key ] = $item->comment_ID;
|
2153 |
-
}
|
2154 |
-
}
|
2155 |
-
|
2156 |
-
/**
|
2157 |
-
* Does the comment exist?
|
2158 |
-
*
|
2159 |
-
* @param array $data Comment data to check against.
|
2160 |
-
* @return int|bool Existing comment ID if it exists, false otherwise.
|
2161 |
-
*/
|
2162 |
-
protected function comment_exists( $data ) {
|
2163 |
-
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2164 |
-
|
2165 |
-
// Constant-time lookup if we prefilled
|
2166 |
-
if ( $this->options['prefill_existing_comments'] ) {
|
2167 |
-
return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
|
2168 |
-
}
|
2169 |
-
|
2170 |
-
// No prefilling, but might have already handled it
|
2171 |
-
if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
|
2172 |
-
return $this->exists['comment'][ $exists_key ];
|
2173 |
-
}
|
2174 |
-
|
2175 |
-
// Still nothing, try comment_exists, and cache it
|
2176 |
-
$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
|
2177 |
-
$this->exists['comment'][ $exists_key ] = $exists;
|
2178 |
-
|
2179 |
-
return $exists;
|
2180 |
-
}
|
2181 |
-
|
2182 |
-
/**
|
2183 |
-
* Mark the comment as existing.
|
2184 |
-
*
|
2185 |
-
* @param array $data Comment data to mark as existing.
|
2186 |
-
* @param int $comment_id Comment ID.
|
2187 |
-
*/
|
2188 |
-
protected function mark_comment_exists( $data, $comment_id ) {
|
2189 |
-
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2190 |
-
$this->exists['comment'][ $exists_key ] = $comment_id;
|
2191 |
-
}
|
2192 |
-
|
2193 |
-
/**
|
2194 |
-
* Prefill existing term data.
|
2195 |
-
*
|
2196 |
-
* @see self::prefill_existing_posts() for justification of why this exists.
|
2197 |
-
*/
|
2198 |
-
protected function prefill_existing_terms() {
|
2199 |
-
global $wpdb;
|
2200 |
-
$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
|
2201 |
-
$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
|
2202 |
-
$terms = $wpdb->get_results( $query );
|
2203 |
-
|
2204 |
-
foreach ( $terms as $item ) {
|
2205 |
-
$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
|
2206 |
-
$this->exists['term'][ $exists_key ] = $item->term_id;
|
2207 |
-
}
|
2208 |
-
}
|
2209 |
-
|
2210 |
-
/**
|
2211 |
-
* Does the term exist?
|
2212 |
-
*
|
2213 |
-
* @param array $data Term data to check against.
|
2214 |
-
* @return int|bool Existing term ID if it exists, false otherwise.
|
2215 |
-
*/
|
2216 |
-
protected function term_exists( $data ) {
|
2217 |
-
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2218 |
-
|
2219 |
-
// Constant-time lookup if we prefilled
|
2220 |
-
if ( $this->options['prefill_existing_terms'] ) {
|
2221 |
-
return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
|
2222 |
-
}
|
2223 |
-
|
2224 |
-
// No prefilling, but might have already handled it
|
2225 |
-
if ( isset( $this->exists['term'][ $exists_key ] ) ) {
|
2226 |
-
return $this->exists['term'][ $exists_key ];
|
2227 |
-
}
|
2228 |
-
|
2229 |
-
// Still nothing, try comment_exists, and cache it
|
2230 |
-
$exists = term_exists( $data['slug'], $data['taxonomy'] );
|
2231 |
-
if ( is_array( $exists ) ) {
|
2232 |
-
$exists = $exists['term_id'];
|
2233 |
-
}
|
2234 |
-
|
2235 |
-
$this->exists['term'][ $exists_key ] = $exists;
|
2236 |
-
|
2237 |
-
return $exists;
|
2238 |
-
}
|
2239 |
-
|
2240 |
-
/**
|
2241 |
-
* Mark the term as existing.
|
2242 |
-
*
|
2243 |
-
* @param array $data Term data to mark as existing.
|
2244 |
-
* @param int $term_id Term ID.
|
2245 |
-
*/
|
2246 |
-
protected function mark_term_exists( $data, $term_id ) {
|
2247 |
-
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2248 |
-
$this->exists['term'][ $exists_key ] = $term_id;
|
2249 |
-
}
|
2250 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class RDDI_WXR_Importer {
|
4 |
+
/**
|
5 |
+
* Maximum supported WXR version
|
6 |
+
*/
|
7 |
+
const MAX_WXR_VERSION = 1.2;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Regular expression for checking if a post references an attachment
|
11 |
+
*
|
12 |
+
* Note: This is a quick, weak check just to exclude text-only posts. More
|
13 |
+
* vigorous checking is done later to verify.
|
14 |
+
*/
|
15 |
+
const REGEX_HAS_ATTACHMENT_REFS = '!
|
16 |
+
(
|
17 |
+
# Match anything with an image or attachment class
|
18 |
+
class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
|
19 |
+
|
|
20 |
+
# Match anything that looks like an upload URL
|
21 |
+
src=[\'"][^\'"]*(
|
22 |
+
[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
|
23 |
+
|
|
24 |
+
content/uploads[^\'"]+
|
25 |
+
)[\'"]
|
26 |
+
)!ix';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Version of WXR we're importing.
|
30 |
+
*
|
31 |
+
* Defaults to 1.0 for compatibility. Typically overridden by a
|
32 |
+
* `<wp:wxr_version>` tag at the start of the file.
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
protected $version = '1.0';
|
37 |
+
|
38 |
+
// information to import from WXR file
|
39 |
+
protected $categories = array();
|
40 |
+
protected $tags = array();
|
41 |
+
protected $base_url = '';
|
42 |
+
|
43 |
+
// TODO: REMOVE THESE
|
44 |
+
protected $processed_terms = array();
|
45 |
+
protected $processed_posts = array();
|
46 |
+
protected $processed_menu_items = array();
|
47 |
+
protected $menu_item_orphans = array();
|
48 |
+
protected $missing_menu_items = array();
|
49 |
+
|
50 |
+
// NEW STYLE
|
51 |
+
protected $mapping = array();
|
52 |
+
protected $requires_remapping = array();
|
53 |
+
protected $exists = array();
|
54 |
+
protected $user_slug_override = array();
|
55 |
+
|
56 |
+
protected $url_remap = array();
|
57 |
+
protected $featured_images = array();
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Logger instance.
|
61 |
+
*
|
62 |
+
* @var RDDI_WP_Importer_Logger
|
63 |
+
*/
|
64 |
+
protected $logger;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Constructor
|
68 |
+
*
|
69 |
+
* @param array $options {
|
70 |
+
* @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.)
|
71 |
+
* @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.)
|
72 |
+
* @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.)
|
73 |
+
* @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows deduplication and reimporting. Default is false.)
|
74 |
+
* @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
|
75 |
+
* @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.)
|
76 |
+
* @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
|
77 |
+
* }
|
78 |
+
*/
|
79 |
+
public function __construct( $options = array() ) {
|
80 |
+
// Initialize some important variables
|
81 |
+
$empty_types = array(
|
82 |
+
'post' => array(),
|
83 |
+
'comment' => array(),
|
84 |
+
'term' => array(),
|
85 |
+
'user' => array(),
|
86 |
+
);
|
87 |
+
|
88 |
+
$this->mapping = $empty_types;
|
89 |
+
$this->mapping['user_slug'] = array();
|
90 |
+
$this->mapping['term_id'] = array();
|
91 |
+
$this->requires_remapping = $empty_types;
|
92 |
+
$this->exists = $empty_types;
|
93 |
+
|
94 |
+
$this->options = wp_parse_args( $options, array(
|
95 |
+
'prefill_existing_posts' => true,
|
96 |
+
'prefill_existing_comments' => true,
|
97 |
+
'prefill_existing_terms' => true,
|
98 |
+
'update_attachment_guids' => false,
|
99 |
+
'fetch_attachments' => false,
|
100 |
+
'aggressive_url_search' => false,
|
101 |
+
'default_author' => null,
|
102 |
+
) );
|
103 |
+
}
|
104 |
+
|
105 |
+
public function set_logger( $logger ) {
|
106 |
+
$this->logger = $logger;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Get a stream reader for the file.
|
111 |
+
*
|
112 |
+
* @param string $file Path to the XML file.
|
113 |
+
* @return XMLReader|WP_Error Reader instance on success, error otherwise.
|
114 |
+
*/
|
115 |
+
protected function get_reader( $file ) {
|
116 |
+
// Avoid loading external entities for security
|
117 |
+
$old_value = null;
|
118 |
+
if ( function_exists( 'libxml_disable_entity_loader' ) ) {
|
119 |
+
// $old_value = libxml_disable_entity_loader( true );
|
120 |
+
}
|
121 |
+
|
122 |
+
$reader = new XMLReader();
|
123 |
+
$status = $reader->open( $file );
|
124 |
+
|
125 |
+
if ( ! is_null( $old_value ) ) {
|
126 |
+
// libxml_disable_entity_loader( $old_value );
|
127 |
+
}
|
128 |
+
|
129 |
+
if ( ! $status ) {
|
130 |
+
return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'rara-one-click-demo-import' ) );
|
131 |
+
}
|
132 |
+
|
133 |
+
return $reader;
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* The main controller for the actual import stage.
|
138 |
+
*
|
139 |
+
* @param string $file Path to the WXR file for importing
|
140 |
+
*/
|
141 |
+
public function get_preliminary_information( $file ) {
|
142 |
+
// Let's run the actual importer now, woot
|
143 |
+
$reader = $this->get_reader( $file );
|
144 |
+
if ( is_wp_error( $reader ) ) {
|
145 |
+
return $reader;
|
146 |
+
}
|
147 |
+
|
148 |
+
// Set the version to compatibility mode first
|
149 |
+
$this->version = '1.0';
|
150 |
+
|
151 |
+
// Start parsing!
|
152 |
+
$data = new WXR_Import_Info();
|
153 |
+
while ( $reader->read() ) {
|
154 |
+
// Only deal with element opens
|
155 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
156 |
+
continue;
|
157 |
+
}
|
158 |
+
|
159 |
+
switch ( $reader->name ) {
|
160 |
+
case 'wp:wxr_version':
|
161 |
+
// Upgrade to the correct version
|
162 |
+
$this->version = $reader->readString();
|
163 |
+
|
164 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
165 |
+
$this->logger->warning( sprintf(
|
166 |
+
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
167 |
+
$this->version,
|
168 |
+
self::MAX_WXR_VERSION
|
169 |
+
) );
|
170 |
+
}
|
171 |
+
|
172 |
+
// Handled everything in this node, move on to the next
|
173 |
+
$reader->next();
|
174 |
+
break;
|
175 |
+
|
176 |
+
case 'generator':
|
177 |
+
$data->generator = $reader->readString();
|
178 |
+
$reader->next();
|
179 |
+
break;
|
180 |
+
|
181 |
+
case 'title':
|
182 |
+
$data->title = $reader->readString();
|
183 |
+
$reader->next();
|
184 |
+
break;
|
185 |
+
|
186 |
+
case 'wp:base_site_url':
|
187 |
+
$data->siteurl = $reader->readString();
|
188 |
+
$reader->next();
|
189 |
+
break;
|
190 |
+
|
191 |
+
case 'wp:base_blog_url':
|
192 |
+
$data->home = $reader->readString();
|
193 |
+
$reader->next();
|
194 |
+
break;
|
195 |
+
|
196 |
+
case 'wp:author':
|
197 |
+
$node = $reader->expand();
|
198 |
+
|
199 |
+
$parsed = $this->parse_author_node( $node );
|
200 |
+
if ( is_wp_error( $parsed ) ) {
|
201 |
+
$this->log_error( $parsed );
|
202 |
+
|
203 |
+
// Skip the rest of this post
|
204 |
+
$reader->next();
|
205 |
+
break;
|
206 |
+
}
|
207 |
+
|
208 |
+
$data->users[] = $parsed;
|
209 |
+
|
210 |
+
// Handled everything in this node, move on to the next
|
211 |
+
$reader->next();
|
212 |
+
break;
|
213 |
+
|
214 |
+
case 'item':
|
215 |
+
$node = $reader->expand();
|
216 |
+
$parsed = $this->parse_post_node( $node );
|
217 |
+
if ( is_wp_error( $parsed ) ) {
|
218 |
+
$this->log_error( $parsed );
|
219 |
+
|
220 |
+
// Skip the rest of this post
|
221 |
+
$reader->next();
|
222 |
+
break;
|
223 |
+
}
|
224 |
+
|
225 |
+
if ( $parsed['data']['post_type'] === 'attachment' ) {
|
226 |
+
$data->media_count++;
|
227 |
+
} else {
|
228 |
+
$data->post_count++;
|
229 |
+
}
|
230 |
+
$data->comment_count += count( $parsed['comments'] );
|
231 |
+
|
232 |
+
// Handled everything in this node, move on to the next
|
233 |
+
$reader->next();
|
234 |
+
break;
|
235 |
+
|
236 |
+
case 'wp:category':
|
237 |
+
case 'wp:tag':
|
238 |
+
case 'wp:term':
|
239 |
+
$data->term_count++;
|
240 |
+
|
241 |
+
// Handled everything in this node, move on to the next
|
242 |
+
$reader->next();
|
243 |
+
break;
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
$data->version = $this->version;
|
248 |
+
|
249 |
+
return $data;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* The main controller for the actual import stage.
|
254 |
+
*
|
255 |
+
* @param string $file Path to the WXR file for importing
|
256 |
+
*/
|
257 |
+
public function parse_authors( $file ) {
|
258 |
+
// Let's run the actual importer now, woot
|
259 |
+
$reader = $this->get_reader( $file );
|
260 |
+
if ( is_wp_error( $reader ) ) {
|
261 |
+
return $reader;
|
262 |
+
}
|
263 |
+
|
264 |
+
// Set the version to compatibility mode first
|
265 |
+
$this->version = '1.0';
|
266 |
+
|
267 |
+
// Start parsing!
|
268 |
+
$authors = array();
|
269 |
+
while ( $reader->read() ) {
|
270 |
+
// Only deal with element opens
|
271 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
272 |
+
continue;
|
273 |
+
}
|
274 |
+
|
275 |
+
switch ( $reader->name ) {
|
276 |
+
case 'wp:wxr_version':
|
277 |
+
// Upgrade to the correct version
|
278 |
+
$this->version = $reader->readString();
|
279 |
+
|
280 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
281 |
+
$this->logger->warning( sprintf(
|
282 |
+
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
283 |
+
$this->version,
|
284 |
+
self::MAX_WXR_VERSION
|
285 |
+
) );
|
286 |
+
}
|
287 |
+
|
288 |
+
// Handled everything in this node, move on to the next
|
289 |
+
$reader->next();
|
290 |
+
break;
|
291 |
+
|
292 |
+
case 'wp:author':
|
293 |
+
$node = $reader->expand();
|
294 |
+
|
295 |
+
$parsed = $this->parse_author_node( $node );
|
296 |
+
if ( is_wp_error( $parsed ) ) {
|
297 |
+
$this->log_error( $parsed );
|
298 |
+
|
299 |
+
// Skip the rest of this post
|
300 |
+
$reader->next();
|
301 |
+
break;
|
302 |
+
}
|
303 |
+
|
304 |
+
$authors[] = $parsed;
|
305 |
+
|
306 |
+
// Handled everything in this node, move on to the next
|
307 |
+
$reader->next();
|
308 |
+
break;
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
return $authors;
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* The main controller for the actual import stage.
|
317 |
+
*
|
318 |
+
* @param string $file Path to the WXR file for importing
|
319 |
+
*/
|
320 |
+
public function import( $file ) {
|
321 |
+
add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
|
322 |
+
add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
|
323 |
+
|
324 |
+
$result = $this->import_start( $file );
|
325 |
+
if ( is_wp_error( $result ) ) {
|
326 |
+
return $result;
|
327 |
+
}
|
328 |
+
|
329 |
+
// Let's run the actual importer now, woot
|
330 |
+
$reader = $this->get_reader( $file );
|
331 |
+
if ( is_wp_error( $reader ) ) {
|
332 |
+
return $reader;
|
333 |
+
}
|
334 |
+
|
335 |
+
// Set the version to compatibility mode first
|
336 |
+
$this->version = '1.0';
|
337 |
+
|
338 |
+
// Reset other variables
|
339 |
+
$this->base_url = '';
|
340 |
+
|
341 |
+
// Start parsing!
|
342 |
+
while ( $reader->read() ) {
|
343 |
+
// Only deal with element opens
|
344 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
345 |
+
continue;
|
346 |
+
}
|
347 |
+
|
348 |
+
switch ( $reader->name ) {
|
349 |
+
case 'wp:wxr_version':
|
350 |
+
// Upgrade to the correct version
|
351 |
+
$this->version = $reader->readString();
|
352 |
+
|
353 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
354 |
+
$this->logger->warning( sprintf(
|
355 |
+
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'rara-one-click-demo-import' ),
|
356 |
+
$this->version,
|
357 |
+
self::MAX_WXR_VERSION
|
358 |
+
) );
|
359 |
+
}
|
360 |
+
|
361 |
+
// Handled everything in this node, move on to the next
|
362 |
+
$reader->next();
|
363 |
+
break;
|
364 |
+
|
365 |
+
case 'wp:base_site_url':
|
366 |
+
$this->base_url = $reader->readString();
|
367 |
+
|
368 |
+
// Handled everything in this node, move on to the next
|
369 |
+
$reader->next();
|
370 |
+
break;
|
371 |
+
|
372 |
+
case 'item':
|
373 |
+
$node = $reader->expand();
|
374 |
+
$parsed = $this->parse_post_node( $node );
|
375 |
+
if ( is_wp_error( $parsed ) ) {
|
376 |
+
$this->log_error( $parsed );
|
377 |
+
|
378 |
+
// Skip the rest of this post
|
379 |
+
$reader->next();
|
380 |
+
break;
|
381 |
+
}
|
382 |
+
|
383 |
+
$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
|
384 |
+
|
385 |
+
// Handled everything in this node, move on to the next
|
386 |
+
$reader->next();
|
387 |
+
break;
|
388 |
+
|
389 |
+
case 'wp:author':
|
390 |
+
$node = $reader->expand();
|
391 |
+
|
392 |
+
$parsed = $this->parse_author_node( $node );
|
393 |
+
if ( is_wp_error( $parsed ) ) {
|
394 |
+
$this->log_error( $parsed );
|
395 |
+
|
396 |
+
// Skip the rest of this post
|
397 |
+
$reader->next();
|
398 |
+
break;
|
399 |
+
}
|
400 |
+
|
401 |
+
$status = $this->process_author( $parsed['data'], $parsed['meta'] );
|
402 |
+
if ( is_wp_error( $status ) ) {
|
403 |
+
$this->log_error( $status );
|
404 |
+
}
|
405 |
+
|
406 |
+
// Handled everything in this node, move on to the next
|
407 |
+
$reader->next();
|
408 |
+
break;
|
409 |
+
|
410 |
+
case 'wp:category':
|
411 |
+
$node = $reader->expand();
|
412 |
+
|
413 |
+
$parsed = $this->parse_term_node( $node, 'category' );
|
414 |
+
if ( is_wp_error( $parsed ) ) {
|
415 |
+
$this->log_error( $parsed );
|
416 |
+
|
417 |
+
// Skip the rest of this post
|
418 |
+
$reader->next();
|
419 |
+
break;
|
420 |
+
}
|
421 |
+
|
422 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
423 |
+
|
424 |
+
// Handled everything in this node, move on to the next
|
425 |
+
$reader->next();
|
426 |
+
break;
|
427 |
+
|
428 |
+
case 'wp:tag':
|
429 |
+
$node = $reader->expand();
|
430 |
+
|
431 |
+
$parsed = $this->parse_term_node( $node, 'tag' );
|
432 |
+
if ( is_wp_error( $parsed ) ) {
|
433 |
+
$this->log_error( $parsed );
|
434 |
+
|
435 |
+
// Skip the rest of this post
|
436 |
+
$reader->next();
|
437 |
+
break;
|
438 |
+
}
|
439 |
+
|
440 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
441 |
+
|
442 |
+
// Handled everything in this node, move on to the next
|
443 |
+
$reader->next();
|
444 |
+
break;
|
445 |
+
|
446 |
+
case 'wp:term':
|
447 |
+
$node = $reader->expand();
|
448 |
+
|
449 |
+
$parsed = $this->parse_term_node( $node );
|
450 |
+
if ( is_wp_error( $parsed ) ) {
|
451 |
+
$this->log_error( $parsed );
|
452 |
+
|
453 |
+
// Skip the rest of this post
|
454 |
+
$reader->next();
|
455 |
+
break;
|
456 |
+
}
|
457 |
+
|
458 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
459 |
+
|
460 |
+
// Handled everything in this node, move on to the next
|
461 |
+
$reader->next();
|
462 |
+
break;
|
463 |
+
|
464 |
+
default:
|
465 |
+
// Skip this node, probably handled by something already
|
466 |
+
break;
|
467 |
+
}
|
468 |
+
}
|
469 |
+
|
470 |
+
// Now that we've done the main processing, do any required
|
471 |
+
// post-processing and remapping.
|
472 |
+
$this->post_process();
|
473 |
+
|
474 |
+
if ( $this->options['aggressive_url_search'] ) {
|
475 |
+
$this->replace_attachment_urls_in_content();
|
476 |
+
}
|
477 |
+
// $this->remap_featured_images();
|
478 |
+
|
479 |
+
$this->import_end();
|
480 |
+
}
|
481 |
+
|
482 |
+
/**
|
483 |
+
* Log an error instance to the logger.
|
484 |
+
*
|
485 |
+
* @param WP_Error $error Error instance to log.
|
486 |
+
*/
|
487 |
+
protected function log_error( WP_Error $error ) {
|
488 |
+
$this->logger->warning( $error->get_error_message() );
|
489 |
+
|
490 |
+
// Log the data as debug info too
|
491 |
+
$data = $error->get_error_data();
|
492 |
+
if ( ! empty( $data ) ) {
|
493 |
+
$this->logger->debug( var_export( $data, true ) );
|
494 |
+
}
|
495 |
+
}
|
496 |
+
|
497 |
+
/**
|
498 |
+
* Parses the WXR file and prepares us for the task of processing parsed data
|
499 |
+
*
|
500 |
+
* @param string $file Path to the WXR file for importing
|
501 |
+
*/
|
502 |
+
protected function import_start( $file ) {
|
503 |
+
if ( ! is_file( $file ) ) {
|
504 |
+
return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'rara-one-click-demo-import' ) );
|
505 |
+
}
|
506 |
+
|
507 |
+
// Suspend bunches of stuff in WP core
|
508 |
+
wp_defer_term_counting( true );
|
509 |
+
wp_defer_comment_counting( true );
|
510 |
+
wp_suspend_cache_invalidation( true );
|
511 |
+
|
512 |
+
// Prefill exists calls if told to
|
513 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
514 |
+
$this->prefill_existing_posts();
|
515 |
+
}
|
516 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
517 |
+
$this->prefill_existing_comments();
|
518 |
+
}
|
519 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
520 |
+
$this->prefill_existing_terms();
|
521 |
+
}
|
522 |
+
|
523 |
+
/**
|
524 |
+
* Begin the import.
|
525 |
+
*
|
526 |
+
* Fires before the import process has begun. If you need to suspend
|
527 |
+
* caching or heavy processing on hooks, do so here.
|
528 |
+
*/
|
529 |
+
do_action( 'import_start' );
|
530 |
+
}
|
531 |
+
|
532 |
+
/**
|
533 |
+
* Performs post-import cleanup of files and the cache
|
534 |
+
*/
|
535 |
+
protected function import_end() {
|
536 |
+
// Re-enable stuff in core
|
537 |
+
wp_suspend_cache_invalidation( false );
|
538 |
+
wp_cache_flush();
|
539 |
+
foreach ( get_taxonomies() as $tax ) {
|
540 |
+
delete_option( "{$tax}_children" );
|
541 |
+
_get_term_hierarchy( $tax );
|
542 |
+
}
|
543 |
+
|
544 |
+
wp_defer_term_counting( false );
|
545 |
+
wp_defer_comment_counting( false );
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Complete the import.
|
549 |
+
*
|
550 |
+
* Fires after the import process has finished. If you need to update
|
551 |
+
* your cache or re-enable processing, do so here.
|
552 |
+
*/
|
553 |
+
do_action( 'import_end' );
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Set the user mapping.
|
558 |
+
*
|
559 |
+
* @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
|
560 |
+
*/
|
561 |
+
public function set_user_mapping( $mapping ) {
|
562 |
+
foreach ( $mapping as $map ) {
|
563 |
+
if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
|
564 |
+
$this->logger->warning( __( 'Invalid author mapping', 'rara-one-click-demo-import' ) );
|
565 |
+
$this->logger->debug( var_export( $map, true ) );
|
566 |
+
continue;
|
567 |
+
}
|
568 |
+
|
569 |
+
$old_slug = $map['old_slug'];
|
570 |
+
$old_id = $map['old_id'];
|
571 |
+
$new_id = $map['new_id'];
|
572 |
+
|
573 |
+
$this->mapping['user'][ $old_id ] = $new_id;
|
574 |
+
$this->mapping['user_slug'][ $old_slug ] = $new_id;
|
575 |
+
}
|
576 |
+
}
|
577 |
+
|
578 |
+
/**
|
579 |
+
* Set the user slug overrides.
|
580 |
+
*
|
581 |
+
* Allows overriding the slug in the import with a custom/renamed version.
|
582 |
+
*
|
583 |
+
* @param string[] $overrides Map of old slug to new slug.
|
584 |
+
*/
|
585 |
+
public function set_user_slug_overrides( $overrides ) {
|
586 |
+
foreach ( $overrides as $original => $renamed ) {
|
587 |
+
$this->user_slug_override[ $original ] = $renamed;
|
588 |
+
}
|
589 |
+
}
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Parse a post node into post data.
|
593 |
+
*
|
594 |
+
* @param DOMElement $node Parent node of post data (typically `item`).
|
595 |
+
* @return array|WP_Error Post data array on success, error otherwise.
|
596 |
+
*/
|
597 |
+
protected function parse_post_node( $node ) {
|
598 |
+
$data = array();
|
599 |
+
$meta = array();
|
600 |
+
$comments = array();
|
601 |
+
$terms = array();
|
602 |
+
|
603 |
+
foreach ( $node->childNodes as $child ) {
|
604 |
+
// We only care about child elements
|
605 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
606 |
+
continue;
|
607 |
+
}
|
608 |
+
|
609 |
+
switch ( $child->tagName ) {
|
610 |
+
case 'wp:post_type':
|
611 |
+
$data['post_type'] = $child->textContent;
|
612 |
+
break;
|
613 |
+
|
614 |
+
case 'title':
|
615 |
+
$data['post_title'] = $child->textContent;
|
616 |
+
break;
|
617 |
+
|
618 |
+
case 'guid':
|
619 |
+
$data['guid'] = $child->textContent;
|
620 |
+
break;
|
621 |
+
|
622 |
+
case 'dc:creator':
|
623 |
+
$data['post_author'] = $child->textContent;
|
624 |
+
break;
|
625 |
+
|
626 |
+
case 'content:encoded':
|
627 |
+
$data['post_content'] = $child->textContent;
|
628 |
+
break;
|
629 |
+
|
630 |
+
case 'excerpt:encoded':
|
631 |
+
$data['post_excerpt'] = $child->textContent;
|
632 |
+
break;
|
633 |
+
|
634 |
+
case 'wp:post_id':
|
635 |
+
$data['post_id'] = $child->textContent;
|
636 |
+
break;
|
637 |
+
|
638 |
+
case 'wp:post_date':
|
639 |
+
$data['post_date'] = $child->textContent;
|
640 |
+
break;
|
641 |
+
|
642 |
+
case 'wp:post_date_gmt':
|
643 |
+
$data['post_date_gmt'] = $child->textContent;
|
644 |
+
break;
|
645 |
+
|
646 |
+
case 'wp:comment_status':
|
647 |
+
$data['comment_status'] = $child->textContent;
|
648 |
+
break;
|
649 |
+
|
650 |
+
case 'wp:ping_status':
|
651 |
+
$data['ping_status'] = $child->textContent;
|
652 |
+
break;
|
653 |
+
|
654 |
+
case 'wp:post_name':
|
655 |
+
$data['post_name'] = $child->textContent;
|
656 |
+
break;
|
657 |
+
|
658 |
+
case 'wp:status':
|
659 |
+
$data['post_status'] = $child->textContent;
|
660 |
+
|
661 |
+
if ( $data['post_status'] === 'auto-draft' ) {
|
662 |
+
// Bail now
|
663 |
+
return new WP_Error(
|
664 |
+
'wxr_importer.post.cannot_import_draft',
|
665 |
+
__( 'Cannot import auto-draft posts','rara-one-click-demo-import' ),
|
666 |
+
$data
|
667 |
+
);
|
668 |
+
}
|
669 |
+
break;
|
670 |
+
|
671 |
+
case 'wp:post_parent':
|
672 |
+
$data['post_parent'] = $child->textContent;
|
673 |
+
break;
|
674 |
+
|
675 |
+
case 'wp:menu_order':
|
676 |
+
$data['menu_order'] = $child->textContent;
|
677 |
+
break;
|
678 |
+
|
679 |
+
case 'wp:post_password':
|
680 |
+
$data['post_password'] = $child->textContent;
|
681 |
+
break;
|
682 |
+
|
683 |
+
case 'wp:is_sticky':
|
684 |
+
$data['is_sticky'] = $child->textContent;
|
685 |
+
break;
|
686 |
+
|
687 |
+
case 'wp:attachment_url':
|
688 |
+
$data['attachment_url'] = $child->textContent;
|
689 |
+
break;
|
690 |
+
|
691 |
+
case 'wp:postmeta':
|
692 |
+
$meta_item = $this->parse_meta_node( $child );
|
693 |
+
if ( ! empty( $meta_item ) ) {
|
694 |
+
$meta[] = $meta_item;
|
695 |
+
}
|
696 |
+
break;
|
697 |
+
|
698 |
+
case 'wp:comment':
|
699 |
+
$comment_item = $this->parse_comment_node( $child );
|
700 |
+
if ( ! empty( $comment_item ) ) {
|
701 |
+
$comments[] = $comment_item;
|
702 |
+
}
|
703 |
+
break;
|
704 |
+
|
705 |
+
case 'category':
|
706 |
+
$term_item = $this->parse_category_node( $child );
|
707 |
+
if ( ! empty( $term_item ) ) {
|
708 |
+
$terms[] = $term_item;
|
709 |
+
}
|
710 |
+
break;
|
711 |
+
}
|
712 |
+
}
|
713 |
+
|
714 |
+
return compact( 'data', 'meta', 'comments', 'terms' );
|
715 |
+
}
|
716 |
+
|
717 |
+
/**
|
718 |
+
* Create new posts based on import information
|
719 |
+
*
|
720 |
+
* Posts marked as having a parent which doesn't exist will become top level items.
|
721 |
+
* Doesn't create a new post if: the post type doesn't exist, the given post ID
|
722 |
+
* is already noted as imported or a post with the same title and date already exists.
|
723 |
+
* Note that new/updated terms, comments and meta are imported for the last of the above.
|
724 |
+
*/
|
725 |
+
protected function process_post( $data, $meta, $comments, $terms ) {
|
726 |
+
/**
|
727 |
+
* Pre-process post data.
|
728 |
+
*
|
729 |
+
* @param array $data Post data. (Return empty to skip.)
|
730 |
+
* @param array $meta Meta data.
|
731 |
+
* @param array $comments Comments on the post.
|
732 |
+
* @param array $terms Terms on the post.
|
733 |
+
*/
|
734 |
+
$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
|
735 |
+
if ( empty( $data ) ) {
|
736 |
+
return false;
|
737 |
+
}
|
738 |
+
|
739 |
+
$original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
|
740 |
+
$parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
|
741 |
+
$author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
|
742 |
+
|
743 |
+
// Have we already processed this?
|
744 |
+
if ( isset( $this->mapping['post'][ $original_id ] ) ) {
|
745 |
+
return;
|
746 |
+
}
|
747 |
+
|
748 |
+
$post_type_object = get_post_type_object( $data['post_type'] );
|
749 |
+
|
750 |
+
// Is this type even valid?
|
751 |
+
if ( ! $post_type_object ) {
|
752 |
+
$this->logger->warning( sprintf(
|
753 |
+
__( 'Failed to import "%s": Invalid post type %s', 'rara-one-click-demo-import' ),
|
754 |
+
$data['post_title'],
|
755 |
+
$data['post_type']
|
756 |
+
) );
|
757 |
+
return false;
|
758 |
+
}
|
759 |
+
|
760 |
+
$post_exists = $this->post_exists( $data );
|
761 |
+
if ( $post_exists ) {
|
762 |
+
$this->logger->info( sprintf(
|
763 |
+
__( '%s "%s" already exists.', 'rara-one-click-demo-import' ),
|
764 |
+
$post_type_object->labels->singular_name,
|
765 |
+
$data['post_title']
|
766 |
+
) );
|
767 |
+
|
768 |
+
// Even though this post already exists, new comments might need importing
|
769 |
+
$this->process_comments( $comments, $original_id, $data, $post_exists );
|
770 |
+
|
771 |
+
return false;
|
772 |
+
}
|
773 |
+
|
774 |
+
// Map the parent post, or mark it as one we need to fix
|
775 |
+
$requires_remapping = false;
|
776 |
+
if ( $parent_id ) {
|
777 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
778 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
779 |
+
} else {
|
780 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
781 |
+
$requires_remapping = true;
|
782 |
+
|
783 |
+
$data['post_parent'] = 0;
|
784 |
+
}
|
785 |
+
}
|
786 |
+
|
787 |
+
// Map the author, or mark it as one we need to fix
|
788 |
+
$author = sanitize_user( $data['post_author'], true );
|
789 |
+
if ( empty( $author ) ) {
|
790 |
+
// Missing or invalid author, use default if available.
|
791 |
+
$data['post_author'] = $this->options['default_author'];
|
792 |
+
} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
|
793 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author ];
|
794 |
+
} else {
|
795 |
+
$meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author );
|
796 |
+
$requires_remapping = true;
|
797 |
+
|
798 |
+
$data['post_author'] = (int) get_current_user_id();
|
799 |
+
}
|
800 |
+
|
801 |
+
// Does the post look like it contains attachment images?
|
802 |
+
if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
|
803 |
+
$meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true );
|
804 |
+
$requires_remapping = true;
|
805 |
+
}
|
806 |
+
|
807 |
+
// Whitelist to just the keys we allow
|
808 |
+
$postdata = array(
|
809 |
+
'import_id' => $data['post_id'],
|
810 |
+
);
|
811 |
+
$allowed = array(
|
812 |
+
'post_author' => true,
|
813 |
+
'post_date' => true,
|
814 |
+
'post_date_gmt' => true,
|
815 |
+
'post_content' => true,
|
816 |
+
'post_excerpt' => true,
|
817 |
+
'post_title' => true,
|
818 |
+
'post_status' => true,
|
819 |
+
'post_name' => true,
|
820 |
+
'comment_status' => true,
|
821 |
+
'ping_status' => true,
|
822 |
+
'guid' => true,
|
823 |
+
'post_parent' => true,
|
824 |
+
'menu_order' => true,
|
825 |
+
'post_type' => true,
|
826 |
+
'post_password' => true,
|
827 |
+
);
|
828 |
+
foreach ( $data as $key => $value ) {
|
829 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
830 |
+
continue;
|
831 |
+
}
|
832 |
+
|
833 |
+
$postdata[ $key ] = $data[ $key ];
|
834 |
+
}
|
835 |
+
|
836 |
+
$postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
|
837 |
+
|
838 |
+
if ( 'attachment' === $postdata['post_type'] ) {
|
839 |
+
if ( ! $this->options['fetch_attachments'] ) {
|
840 |
+
$this->logger->notice( sprintf(
|
841 |
+
__( 'Skipping attachment "%s", fetching attachments disabled','rara-one-click-demo-import' ),
|
842 |
+
$data['post_title']
|
843 |
+
) );
|
844 |
+
return false;
|
845 |
+
}
|
846 |
+
$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
|
847 |
+
$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
|
848 |
+
} else {
|
849 |
+
$post_id = wp_insert_post( $postdata, true );
|
850 |
+
do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
|
851 |
+
}
|
852 |
+
|
853 |
+
if ( is_wp_error( $post_id ) ) {
|
854 |
+
$this->logger->error( sprintf(
|
855 |
+
__( 'Failed to import "%s" (%s)', 'rara-one-click-demo-import' ),
|
856 |
+
$data['post_title'],
|
857 |
+
$post_type_object->labels->singular_name
|
858 |
+
) );
|
859 |
+
$this->logger->debug( $post_id->get_error_message() );
|
860 |
+
|
861 |
+
/**
|
862 |
+
* Post processing failed.
|
863 |
+
*
|
864 |
+
* @param WP_Error $post_id Error object.
|
865 |
+
* @param array $data Raw data imported for the post.
|
866 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
867 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
868 |
+
* @param array $terms Raw term data, already processed.
|
869 |
+
*/
|
870 |
+
do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
|
871 |
+
return false;
|
872 |
+
}
|
873 |
+
|
874 |
+
// Ensure stickiness is handled correctly too
|
875 |
+
if ( $data['is_sticky'] === '1' ) {
|
876 |
+
stick_post( $post_id );
|
877 |
+
}
|
878 |
+
|
879 |
+
// map pre-import ID to local ID
|
880 |
+
$this->mapping['post'][ $original_id ] = (int) $post_id;
|
881 |
+
if ( $requires_remapping ) {
|
882 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
883 |
+
}
|
884 |
+
$this->mark_post_exists( $data, $post_id );
|
885 |
+
|
886 |
+
$this->logger->info( sprintf(
|
887 |
+
__( 'Imported "%s" (%s)', 'rara-one-click-demo-import' ),
|
888 |
+
$data['post_title'],
|
889 |
+
$post_type_object->labels->singular_name
|
890 |
+
) );
|
891 |
+
$this->logger->debug( sprintf(
|
892 |
+
__( 'Post %d remapped to %d', 'rara-one-click-demo-import' ),
|
893 |
+
$original_id,
|
894 |
+
$post_id
|
895 |
+
) );
|
896 |
+
|
897 |
+
// Handle the terms too
|
898 |
+
$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
|
899 |
+
|
900 |
+
if ( ! empty( $terms ) ) {
|
901 |
+
$term_ids = array();
|
902 |
+
foreach ( $terms as $term ) {
|
903 |
+
$taxonomy = $term['taxonomy'];
|
904 |
+
$key = sha1( $taxonomy . ':' . $term['slug'] );
|
905 |
+
|
906 |
+
if ( isset( $this->mapping['term'][ $key ] ) ) {
|
907 |
+
$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
|
908 |
+
} else {
|
909 |
+
$meta[] = array( 'key' => '_wxr_import_term', 'value' => $term );
|
910 |
+
$requires_remapping = true;
|
911 |
+
}
|
912 |
+
}
|
913 |
+
|
914 |
+
foreach ( $term_ids as $tax => $ids ) {
|
915 |
+
$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
|
916 |
+
do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
|
917 |
+
}
|
918 |
+
}
|
919 |
+
|
920 |
+
$this->process_comments( $comments, $post_id, $data );
|
921 |
+
$this->process_post_meta( $meta, $post_id, $data );
|
922 |
+
|
923 |
+
if ( 'nav_menu_item' === $data['post_type'] ) {
|
924 |
+
$this->process_menu_item_meta( $post_id, $data, $meta );
|
925 |
+
}
|
926 |
+
|
927 |
+
/**
|
928 |
+
* Post processing completed.
|
929 |
+
*
|
930 |
+
* @param int $post_id New post ID.
|
931 |
+
* @param array $data Raw data imported for the post.
|
932 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
933 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
934 |
+
* @param array $terms Raw term data, already processed.
|
935 |
+
*/
|
936 |
+
do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
|
937 |
+
}
|
938 |
+
|
939 |
+
/**
|
940 |
+
* Attempt to create a new menu item from import data
|
941 |
+
*
|
942 |
+
* Fails for draft, orphaned menu items and those without an associated nav_menu
|
943 |
+
* or an invalid nav_menu term. If the post type or term object which the menu item
|
944 |
+
* represents doesn't exist then the menu item will not be imported (waits until the
|
945 |
+
* end of the import to retry again before discarding).
|
946 |
+
*
|
947 |
+
* @param array $item Menu item details from WXR file
|
948 |
+
*/
|
949 |
+
protected function process_menu_item_meta( $post_id, $data, $meta ) {
|
950 |
+
|
951 |
+
$item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
952 |
+
$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
|
953 |
+
$object_id = null;
|
954 |
+
|
955 |
+
$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
|
956 |
+
|
957 |
+
$requires_remapping = false;
|
958 |
+
switch ( $item_type ) {
|
959 |
+
case 'taxonomy':
|
960 |
+
if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
|
961 |
+
$object_id = $this->mapping['term_id'][ $original_object_id ];
|
962 |
+
} else {
|
963 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
964 |
+
$requires_remapping = true;
|
965 |
+
}
|
966 |
+
break;
|
967 |
+
|
968 |
+
case 'post_type':
|
969 |
+
if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
|
970 |
+
$object_id = $this->mapping['post'][ $original_object_id ];
|
971 |
+
} else {
|
972 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
973 |
+
$requires_remapping = true;
|
974 |
+
}
|
975 |
+
break;
|
976 |
+
|
977 |
+
case 'custom':
|
978 |
+
// Custom refers to itself, wonderfully easy.
|
979 |
+
$object_id = $post_id;
|
980 |
+
break;
|
981 |
+
|
982 |
+
default:
|
983 |
+
// associated object is missing or not imported yet, we'll retry later
|
984 |
+
$this->missing_menu_items[] = $item;
|
985 |
+
$this->logger->debug( 'Unknown menu item type' );
|
986 |
+
break;
|
987 |
+
}
|
988 |
+
|
989 |
+
if ( $requires_remapping ) {
|
990 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
991 |
+
}
|
992 |
+
|
993 |
+
if ( empty( $object_id ) ) {
|
994 |
+
// Nothing needed here.
|
995 |
+
return;
|
996 |
+
}
|
997 |
+
|
998 |
+
$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
|
999 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
/**
|
1003 |
+
* If fetching attachments is enabled then attempt to create a new attachment
|
1004 |
+
*
|
1005 |
+
* @param array $post Attachment post details from WXR
|
1006 |
+
* @param string $url URL to fetch attachment from
|
1007 |
+
* @return int|WP_Error Post ID on success, WP_Error otherwise
|
1008 |
+
*/
|
1009 |
+
protected function process_attachment( $post, $meta, $remote_url ) {
|
1010 |
+
// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
|
1011 |
+
// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
|
1012 |
+
$post['upload_date'] = $post['post_date'];
|
1013 |
+
foreach ( $meta as $meta_item ) {
|
1014 |
+
if ( $meta_item['key'] !== '_wp_attached_file' ) {
|
1015 |
+
continue;
|
1016 |
+
}
|
1017 |
+
|
1018 |
+
if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
|
1019 |
+
$post['upload_date'] = $matches[0];
|
1020 |
+
}
|
1021 |
+
break;
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
|
1025 |
+
if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
|
1026 |
+
$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
$upload = $this->fetch_remote_file( $remote_url, $post );
|
1030 |
+
if ( is_wp_error( $upload ) ) {
|
1031 |
+
return $upload;
|
1032 |
+
}
|
1033 |
+
|
1034 |
+
$info = wp_check_filetype( $upload['file'] );
|
1035 |
+
if ( ! $info ) {
|
1036 |
+
return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'rara-one-click-demo-import' ) );
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
$post['post_mime_type'] = $info['type'];
|
1040 |
+
|
1041 |
+
// WP really likes using the GUID for display. Allow updating it.
|
1042 |
+
// See https://core.trac.wordpress.org/ticket/33386
|
1043 |
+
if ( $this->options['update_attachment_guids'] ) {
|
1044 |
+
$post['guid'] = $upload['url'];
|
1045 |
+
}
|
1046 |
+
|
1047 |
+
// as per wp-admin/includes/upload.php
|
1048 |
+
$post_id = wp_insert_attachment( $post, $upload['file'] );
|
1049 |
+
if ( is_wp_error( $post_id ) ) {
|
1050 |
+
return $post_id;
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
|
1054 |
+
wp_update_attachment_metadata( $post_id, $attachment_metadata );
|
1055 |
+
|
1056 |
+
// Map this image URL later if we need to
|
1057 |
+
$this->url_remap[ $remote_url ] = $upload['url'];
|
1058 |
+
|
1059 |
+
// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
|
1060 |
+
if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
|
1061 |
+
$insecure_url = 'http' . substr( $remote_url, 5 );
|
1062 |
+
$this->url_remap[ $insecure_url ] = $upload['url'];
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
if ( $this->options['aggressive_url_search'] ) {
|
1066 |
+
// remap resized image URLs, works by stripping the extension and remapping the URL stub.
|
1067 |
+
/*if ( preg_match( '!^image/!', $info['type'] ) ) {
|
1068 |
+
$parts = pathinfo( $remote_url );
|
1069 |
+
$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
|
1070 |
+
|
1071 |
+
$parts_new = pathinfo( $upload['url'] );
|
1072 |
+
$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
|
1073 |
+
|
1074 |
+
$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
|
1075 |
+
}*/
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
return $post_id;
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
/**
|
1082 |
+
* Parse a meta node into meta data.
|
1083 |
+
*
|
1084 |
+
* @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
|
1085 |
+
* @return array|null Meta data array on success, or null on error.
|
1086 |
+
*/
|
1087 |
+
protected function parse_meta_node( $node ) {
|
1088 |
+
foreach ( $node->childNodes as $child ) {
|
1089 |
+
// We only care about child elements
|
1090 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1091 |
+
continue;
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
switch ( $child->tagName ) {
|
1095 |
+
case 'wp:meta_key':
|
1096 |
+
$key = $child->textContent;
|
1097 |
+
break;
|
1098 |
+
|
1099 |
+
case 'wp:meta_value':
|
1100 |
+
$value = $child->textContent;
|
1101 |
+
break;
|
1102 |
+
}
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
if ( empty( $key ) || empty( $value ) ) {
|
1106 |
+
return null;
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
return compact( 'key', 'value' );
|
1110 |
+
}
|
1111 |
+
|
1112 |
+
/**
|
1113 |
+
* Process and import post meta items.
|
1114 |
+
*
|
1115 |
+
* @param array $meta List of meta data arrays
|
1116 |
+
* @param int $post_id Post to associate with
|
1117 |
+
* @param array $post Post data
|
1118 |
+
* @return int|WP_Error Number of meta items imported on success, error otherwise.
|
1119 |
+
*/
|
1120 |
+
protected function process_post_meta( $meta, $post_id, $post ) {
|
1121 |
+
if ( empty( $meta ) ) {
|
1122 |
+
return true;
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
foreach ( $meta as $meta_item ) {
|
1126 |
+
/**
|
1127 |
+
* Pre-process post meta data.
|
1128 |
+
*
|
1129 |
+
* @param array $meta_item Meta data. (Return empty to skip.)
|
1130 |
+
* @param int $post_id Post the meta is attached to.
|
1131 |
+
*/
|
1132 |
+
$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
|
1133 |
+
if ( empty( $meta_item ) ) {
|
1134 |
+
return false;
|
1135 |
+
}
|
1136 |
+
|
1137 |
+
$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
|
1138 |
+
$value = false;
|
1139 |
+
|
1140 |
+
if ( '_edit_last' === $key ) {
|
1141 |
+
$value = intval( $meta_item['value'] );
|
1142 |
+
if ( ! isset( $this->mapping['user'][ $value ] ) ) {
|
1143 |
+
// Skip!
|
1144 |
+
continue;
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
$value = $this->mapping['user'][ $value ];
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
if ( $key ) {
|
1151 |
+
// export gets meta straight from the DB so could have a serialized string
|
1152 |
+
if ( ! $value ) {
|
1153 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1154 |
+
}
|
1155 |
+
|
1156 |
+
add_post_meta( $post_id, $key, $value );
|
1157 |
+
do_action( 'import_post_meta', $post_id, $key, $value );
|
1158 |
+
|
1159 |
+
// if the post has a featured image, take note of this in case of remap
|
1160 |
+
if ( '_thumbnail_id' === $key ) {
|
1161 |
+
$this->featured_images[ $post_id ] = (int) $value;
|
1162 |
+
}
|
1163 |
+
}
|
1164 |
+
}
|
1165 |
+
|
1166 |
+
return true;
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
/**
|
1170 |
+
* Parse a comment node into comment data.
|
1171 |
+
*
|
1172 |
+
* @param DOMElement $node Parent node of comment data (typically `wp:comment`).
|
1173 |
+
* @return array Comment data array.
|
1174 |
+
*/
|
1175 |
+
protected function parse_comment_node( $node ) {
|
1176 |
+
$data = array(
|
1177 |
+
'commentmeta' => array(),
|
1178 |
+
);
|
1179 |
+
|
1180 |
+
foreach ( $node->childNodes as $child ) {
|
1181 |
+
// We only care about child elements
|
1182 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1183 |
+
continue;
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
switch ( $child->tagName ) {
|
1187 |
+
case 'wp:comment_id':
|
1188 |
+
$data['comment_id'] = $child->textContent;
|
1189 |
+
break;
|
1190 |
+
case 'wp:comment_author':
|
1191 |
+
$data['comment_author'] = $child->textContent;
|
1192 |
+
break;
|
1193 |
+
|
1194 |
+
case 'wp:comment_author_email':
|
1195 |
+
$data['comment_author_email'] = $child->textContent;
|
1196 |
+
break;
|
1197 |
+
|
1198 |
+
case 'wp:comment_author_IP':
|
1199 |
+
$data['comment_author_IP'] = $child->textContent;
|
1200 |
+
break;
|
1201 |
+
|
1202 |
+
case 'wp:comment_author_url':
|
1203 |
+
$data['comment_author_url'] = $child->textContent;
|
1204 |
+
break;
|
1205 |
+
|
1206 |
+
case 'wp:comment_user_id':
|
1207 |
+
$data['comment_user_id'] = $child->textContent;
|
1208 |
+
break;
|
1209 |
+
|
1210 |
+
case 'wp:comment_date':
|
1211 |
+
$data['comment_date'] = $child->textContent;
|
1212 |
+
break;
|
1213 |
+
|
1214 |
+
case 'wp:comment_date_gmt':
|
1215 |
+
$data['comment_date_gmt'] = $child->textContent;
|
1216 |
+
break;
|
1217 |
+
|
1218 |
+
case 'wp:comment_content':
|
1219 |
+
$data['comment_content'] = $child->textContent;
|
1220 |
+
break;
|
1221 |
+
|
1222 |
+
case 'wp:comment_approved':
|
1223 |
+
$data['comment_approved'] = $child->textContent;
|
1224 |
+
break;
|
1225 |
+
|
1226 |
+
case 'wp:comment_type':
|
1227 |
+
$data['comment_type'] = $child->textContent;
|
1228 |
+
break;
|
1229 |
+
|
1230 |
+
case 'wp:comment_parent':
|
1231 |
+
$data['comment_parent'] = $child->textContent;
|
1232 |
+
break;
|
1233 |
+
|
1234 |
+
case 'wp:commentmeta':
|
1235 |
+
$meta_item = $this->parse_meta_node( $child );
|
1236 |
+
if ( ! empty( $meta_item ) ) {
|
1237 |
+
$data['commentmeta'][] = $meta_item;
|
1238 |
+
}
|
1239 |
+
break;
|
1240 |
+
}
|
1241 |
+
}
|
1242 |
+
|
1243 |
+
return $data;
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
/**
|
1247 |
+
* Process and import comment data.
|
1248 |
+
*
|
1249 |
+
* @param array $comments List of comment data arrays.
|
1250 |
+
* @param int $post_id Post to associate with.
|
1251 |
+
* @param array $post Post data.
|
1252 |
+
* @return int|WP_Error Number of comments imported on success, error otherwise.
|
1253 |
+
*/
|
1254 |
+
protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
|
1255 |
+
|
1256 |
+
$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
|
1257 |
+
if ( empty( $comments ) ) {
|
1258 |
+
return 0;
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
$num_comments = 0;
|
1262 |
+
|
1263 |
+
// Sort by ID to avoid excessive remapping later
|
1264 |
+
usort( $comments, array( $this, 'sort_comments_by_id' ) );
|
1265 |
+
|
1266 |
+
foreach ( $comments as $key => $comment ) {
|
1267 |
+
/**
|
1268 |
+
* Pre-process comment data
|
1269 |
+
*
|
1270 |
+
* @param array $comment Comment data. (Return empty to skip.)
|
1271 |
+
* @param int $post_id Post the comment is attached to.
|
1272 |
+
*/
|
1273 |
+
$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
|
1274 |
+
if ( empty( $comment ) ) {
|
1275 |
+
return false;
|
1276 |
+
}
|
1277 |
+
|
1278 |
+
$original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
|
1279 |
+
$parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
|
1280 |
+
$author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
|
1281 |
+
|
1282 |
+
// if this is a new post we can skip the comment_exists() check
|
1283 |
+
// TODO: Check comment_exists for performance
|
1284 |
+
if ( $post_exists ) {
|
1285 |
+
$existing = $this->comment_exists( $comment );
|
1286 |
+
if ( $existing ) {
|
1287 |
+
$this->mapping['comment'][ $original_id ] = $exists;
|
1288 |
+
continue;
|
1289 |
+
}
|
1290 |
+
}
|
1291 |
+
|
1292 |
+
// Remove meta from the main array
|
1293 |
+
$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
|
1294 |
+
unset( $comment['commentmeta'] );
|
1295 |
+
|
1296 |
+
// Map the parent comment, or mark it as one we need to fix
|
1297 |
+
$requires_remapping = false;
|
1298 |
+
if ( $parent_id ) {
|
1299 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1300 |
+
$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1301 |
+
} else {
|
1302 |
+
// Prepare for remapping later
|
1303 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1304 |
+
$requires_remapping = true;
|
1305 |
+
|
1306 |
+
// Wipe the parent for now
|
1307 |
+
$comment['comment_parent'] = 0;
|
1308 |
+
}
|
1309 |
+
}
|
1310 |
+
|
1311 |
+
// Map the author, or mark it as one we need to fix
|
1312 |
+
if ( $author_id ) {
|
1313 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1314 |
+
$comment['user_id'] = $this->mapping['user'][ $author_id ];
|
1315 |
+
} else {
|
1316 |
+
// Prepare for remapping later
|
1317 |
+
$meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id );
|
1318 |
+
$requires_remapping = true;
|
1319 |
+
|
1320 |
+
// Wipe the user for now
|
1321 |
+
$comment['user_id'] = 0;
|
1322 |
+
}
|
1323 |
+
}
|
1324 |
+
|
1325 |
+
// Run standard core filters
|
1326 |
+
$comment['comment_post_ID'] = $post_id;
|
1327 |
+
$comment = wp_filter_comment( $comment );
|
1328 |
+
|
1329 |
+
// wp_insert_comment expects slashed data
|
1330 |
+
$comment_id = wp_insert_comment( wp_slash( $comment ) );
|
1331 |
+
$this->mapping['comment'][ $original_id ] = $comment_id;
|
1332 |
+
if ( $requires_remapping ) {
|
1333 |
+
$this->requires_remapping['comment'][ $comment_id ] = true;
|
1334 |
+
}
|
1335 |
+
$this->mark_comment_exists( $comment, $comment_id );
|
1336 |
+
|
1337 |
+
/**
|
1338 |
+
* Comment has been imported.
|
1339 |
+
*
|
1340 |
+
* @param int $comment_id New comment ID
|
1341 |
+
* @param array $comment Comment inserted (`comment_id` item refers to the original ID)
|
1342 |
+
* @param int $post_id Post parent of the comment
|
1343 |
+
* @param array $post Post data
|
1344 |
+
*/
|
1345 |
+
do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
|
1346 |
+
|
1347 |
+
// Process the meta items
|
1348 |
+
foreach ( $meta as $meta_item ) {
|
1349 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1350 |
+
add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
|
1351 |
+
}
|
1352 |
+
|
1353 |
+
/**
|
1354 |
+
* Post processing completed.
|
1355 |
+
*
|
1356 |
+
* @param int $post_id New post ID.
|
1357 |
+
* @param array $comment Raw data imported for the comment.
|
1358 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
1359 |
+
* @param array $post_id Parent post ID.
|
1360 |
+
*/
|
1361 |
+
do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
|
1362 |
+
|
1363 |
+
$num_comments++;
|
1364 |
+
}
|
1365 |
+
|
1366 |
+
return $num_comments;
|
1367 |
+
}
|
1368 |
+
|
1369 |
+
protected function parse_category_node( $node ) {
|
1370 |
+
$data = array(
|
1371 |
+
// Default taxonomy to "category", since this is a `<category>` tag
|
1372 |
+
'taxonomy' => 'category',
|
1373 |
+
);
|
1374 |
+
$meta = array();
|
1375 |
+
|
1376 |
+
if ( $node->hasAttribute( 'domain' ) ) {
|
1377 |
+
$data['taxonomy'] = $node->getAttribute( 'domain' );
|
1378 |
+
}
|
1379 |
+
if ( $node->hasAttribute( 'nicename' ) ) {
|
1380 |
+
$data['slug'] = $node->getAttribute( 'nicename' );
|
1381 |
+
}
|
1382 |
+
|
1383 |
+
$data['name'] = $node->textContent;
|
1384 |
+
|
1385 |
+
if ( empty( $data['slug'] ) ) {
|
1386 |
+
return null;
|
1387 |
+
}
|
1388 |
+
|
1389 |
+
// Just for extra compatibility
|
1390 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1391 |
+
$data['taxonomy'] = 'post_tag';
|
1392 |
+
}
|
1393 |
+
|
1394 |
+
return $data;
|
1395 |
+
}
|
1396 |
+
|
1397 |
+
/**
|
1398 |
+
* Callback for `usort` to sort comments by ID
|
1399 |
+
*
|
1400 |
+
* @param array $a Comment data for the first comment
|
1401 |
+
* @param array $b Comment data for the second comment
|
1402 |
+
* @return int
|
1403 |
+
*/
|
1404 |
+
public static function sort_comments_by_id( $a, $b ) {
|
1405 |
+
if ( empty( $a['comment_id'] ) ) {
|
1406 |
+
return 1;
|
1407 |
+
}
|
1408 |
+
|
1409 |
+
if ( empty( $b['comment_id'] ) ) {
|
1410 |
+
return -1;
|
1411 |
+
}
|
1412 |
+
|
1413 |
+
return $a['comment_id'] - $b['comment_id'];
|
1414 |
+
}
|
1415 |
+
|
1416 |
+
protected function parse_author_node( $node ) {
|
1417 |
+
$data = array();
|
1418 |
+
$meta = array();
|
1419 |
+
foreach ( $node->childNodes as $child ) {
|
1420 |
+
// We only care about child elements
|
1421 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1422 |
+
continue;
|
1423 |
+
}
|
1424 |
+
|
1425 |
+
switch ( $child->tagName ) {
|
1426 |
+
case 'wp:author_login':
|
1427 |
+
$data['user_login'] = $child->textContent;
|
1428 |
+
break;
|
1429 |
+
|
1430 |
+
case 'wp:author_id':
|
1431 |
+
$data['ID'] = $child->textContent;
|
1432 |
+
break;
|
1433 |
+
|
1434 |
+
case 'wp:author_email':
|
1435 |
+
$data['user_email'] = $child->textContent;
|
1436 |
+
break;
|
1437 |
+
|
1438 |
+
case 'wp:author_display_name':
|
1439 |
+
$data['display_name'] = $child->textContent;
|
1440 |
+
break;
|
1441 |
+
|
1442 |
+
case 'wp:author_first_name':
|
1443 |
+
$data['first_name'] = $child->textContent;
|
1444 |
+
break;
|
1445 |
+
|
1446 |
+
case 'wp:author_last_name':
|
1447 |
+
$data['last_name'] = $child->textContent;
|
1448 |
+
break;
|
1449 |
+
}
|
1450 |
+
}
|
1451 |
+
|
1452 |
+
return compact( 'data', 'meta' );
|
1453 |
+
}
|
1454 |
+
|
1455 |
+
protected function process_author( $data, $meta ) {
|
1456 |
+
/**
|
1457 |
+
* Pre-process user data.
|
1458 |
+
*
|
1459 |
+
* @param array $data User data. (Return empty to skip.)
|
1460 |
+
* @param array $meta Meta data.
|
1461 |
+
*/
|
1462 |
+
$data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
|
1463 |
+
if ( empty( $data ) ) {
|
1464 |
+
return false;
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
// Have we already handled this user?
|
1468 |
+
$original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
|
1469 |
+
$original_slug = $data['user_login'];
|
1470 |
+
|
1471 |
+
if ( isset( $this->mapping['user'][ $original_id ] ) ) {
|
1472 |
+
$existing = $this->mapping['user'][ $original_id ];
|
1473 |
+
|
1474 |
+
// Note the slug mapping if we need to too
|
1475 |
+
if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1476 |
+
$this->mapping['user_slug'][ $original_slug ] = $existing;
|
1477 |
+
}
|
1478 |
+
|
1479 |
+
return false;
|
1480 |
+
}
|
1481 |
+
|
1482 |
+
if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1483 |
+
$existing = $this->mapping['user_slug'][ $original_slug ];
|
1484 |
+
|
1485 |
+
// Ensure we note the mapping too
|
1486 |
+
$this->mapping['user'][ $original_id ] = $existing;
|
1487 |
+
|
1488 |
+
return false;
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
// Allow overriding the user's slug
|
1492 |
+
$login = $original_slug;
|
1493 |
+
if ( isset( $this->user_slug_override[ $login ] ) ) {
|
1494 |
+
$login = $this->user_slug_override[ $login ];
|
1495 |
+
}
|
1496 |
+
|
1497 |
+
$userdata = array(
|
1498 |
+
'user_login' => sanitize_user( $login, true ),
|
1499 |
+
'user_pass' => wp_generate_password(),
|
1500 |
+
);
|
1501 |
+
|
1502 |
+
$allowed = array(
|
1503 |
+
'user_email' => true,
|
1504 |
+
'display_name' => true,
|
1505 |
+
'first_name' => true,
|
1506 |
+
'last_name' => true,
|
1507 |
+
);
|
1508 |
+
foreach ( $data as $key => $value ) {
|
1509 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
1510 |
+
continue;
|
1511 |
+
}
|
1512 |
+
|
1513 |
+
$userdata[ $key ] = $data[ $key ];
|
1514 |
+
}
|
1515 |
+
|
1516 |
+
$user_id = wp_insert_user( wp_slash( $userdata ) );
|
1517 |
+
if ( is_wp_error( $user_id ) ) {
|
1518 |
+
$this->logger->error( sprintf(
|
1519 |
+
__( 'Failed to import user "%s"', 'rara-one-click-demo-import' ),
|
1520 |
+
$userdata['user_login']
|
1521 |
+
) );
|
1522 |
+
$this->logger->debug( $user_id->get_error_message() );
|
1523 |
+
|
1524 |
+
/**
|
1525 |
+
* User processing failed.
|
1526 |
+
*
|
1527 |
+
* @param WP_Error $user_id Error object.
|
1528 |
+
* @param array $userdata Raw data imported for the user.
|
1529 |
+
*/
|
1530 |
+
do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
|
1531 |
+
return false;
|
1532 |
+
}
|
1533 |
+
|
1534 |
+
if ( $original_id ) {
|
1535 |
+
$this->mapping['user'][ $original_id ] = $user_id;
|
1536 |
+
}
|
1537 |
+
$this->mapping['user_slug'][ $original_slug ] = $user_id;
|
1538 |
+
|
1539 |
+
$this->logger->info( sprintf(
|
1540 |
+
__( 'Imported user "%s"', 'rara-one-click-demo-import' ),
|
1541 |
+
$userdata['user_login']
|
1542 |
+
) );
|
1543 |
+
$this->logger->debug( sprintf(
|
1544 |
+
__( 'User %d remapped to %d', 'rara-one-click-demo-import' ),
|
1545 |
+
$original_id,
|
1546 |
+
$user_id
|
1547 |
+
) );
|
1548 |
+
|
1549 |
+
// TODO: Implement meta handling once WXR includes it
|
1550 |
+
/**
|
1551 |
+
* User processing completed.
|
1552 |
+
*
|
1553 |
+
* @param int $user_id New user ID.
|
1554 |
+
* @param array $userdata Raw data imported for the user.
|
1555 |
+
*/
|
1556 |
+
do_action( 'wxr_importer.processed.user', $user_id, $userdata );
|
1557 |
+
}
|
1558 |
+
|
1559 |
+
protected function parse_term_node( $node, $type = 'term' ) {
|
1560 |
+
$data = array();
|
1561 |
+
$meta = array();
|
1562 |
+
|
1563 |
+
$tag_name = array(
|
1564 |
+
'id' => 'wp:term_id',
|
1565 |
+
'taxonomy' => 'wp:term_taxonomy',
|
1566 |
+
'slug' => 'wp:term_slug',
|
1567 |
+
'parent' => 'wp:term_parent',
|
1568 |
+
'name' => 'wp:term_name',
|
1569 |
+
'description' => 'wp:term_description',
|
1570 |
+
);
|
1571 |
+
$taxonomy = null;
|
1572 |
+
|
1573 |
+
// Special casing!
|
1574 |
+
switch ( $type ) {
|
1575 |
+
case 'category':
|
1576 |
+
$tag_name['slug'] = 'wp:category_nicename';
|
1577 |
+
$tag_name['parent'] = 'wp:category_parent';
|
1578 |
+
$tag_name['name'] = 'wp:cat_name';
|
1579 |
+
$tag_name['description'] = 'wp:category_description';
|
1580 |
+
$tag_name['taxonomy'] = null;
|
1581 |
+
|
1582 |
+
$data['taxonomy'] = 'category';
|
1583 |
+
break;
|
1584 |
+
|
1585 |
+
case 'tag':
|
1586 |
+
$tag_name['slug'] = 'wp:tag_slug';
|
1587 |
+
$tag_name['parent'] = null;
|
1588 |
+
$tag_name['name'] = 'wp:tag_name';
|
1589 |
+
$tag_name['description'] = 'wp:tag_description';
|
1590 |
+
$tag_name['taxonomy'] = null;
|
1591 |
+
|
1592 |
+
$data['taxonomy'] = 'post_tag';
|
1593 |
+
break;
|
1594 |
+
}
|
1595 |
+
|
1596 |
+
foreach ( $node->childNodes as $child ) {
|
1597 |
+
// We only care about child elements
|
1598 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1599 |
+
continue;
|
1600 |
+
}
|
1601 |
+
|
1602 |
+
$key = array_search( $child->tagName, $tag_name );
|
1603 |
+
if ( $key ) {
|
1604 |
+
$data[ $key ] = $child->textContent;
|
1605 |
+
}
|
1606 |
+
}
|
1607 |
+
|
1608 |
+
if ( empty( $data['taxonomy'] ) ) {
|
1609 |
+
return null;
|
1610 |
+
}
|
1611 |
+
|
1612 |
+
// Compatibility with WXR 1.0
|
1613 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1614 |
+
$data['taxonomy'] = 'post_tag';
|
1615 |
+
}
|
1616 |
+
|
1617 |
+
return compact( 'data', 'meta' );
|
1618 |
+
}
|
1619 |
+
|
1620 |
+
protected function process_term( $data, $meta ) {
|
1621 |
+
/**
|
1622 |
+
* Pre-process term data.
|
1623 |
+
*
|
1624 |
+
* @param array $data Term data. (Return empty to skip.)
|
1625 |
+
* @param array $meta Meta data.
|
1626 |
+
*/
|
1627 |
+
$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
|
1628 |
+
if ( empty( $data ) ) {
|
1629 |
+
return false;
|
1630 |
+
}
|
1631 |
+
|
1632 |
+
$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
|
1633 |
+
$parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
|
1634 |
+
|
1635 |
+
$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
1636 |
+
$existing = $this->term_exists( $data );
|
1637 |
+
if ( $existing ) {
|
1638 |
+
$this->mapping['term'][ $mapping_key ] = $existing;
|
1639 |
+
$this->mapping['term_id'][ $original_id ] = $existing;
|
1640 |
+
return false;
|
1641 |
+
}
|
1642 |
+
|
1643 |
+
// WP really likes to repeat itself in export files
|
1644 |
+
if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
|
1645 |
+
return false;
|
1646 |
+
}
|
1647 |
+
|
1648 |
+
$termdata = array();
|
1649 |
+
$allowed = array(
|
1650 |
+
'slug' => true,
|
1651 |
+
'description' => true,
|
1652 |
+
);
|
1653 |
+
|
1654 |
+
// Map the parent comment, or mark it as one we need to fix
|
1655 |
+
// TODO: add parent mapping and remapping
|
1656 |
+
/*$requires_remapping = false;
|
1657 |
+
if ( $parent_id ) {
|
1658 |
+
if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
|
1659 |
+
$data['parent'] = $this->mapping['term'][ $parent_id ];
|
1660 |
+
} else {
|
1661 |
+
// Prepare for remapping later
|
1662 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1663 |
+
$requires_remapping = true;
|
1664 |
+
|
1665 |
+
// Wipe the parent for now
|
1666 |
+
$data['parent'] = 0;
|
1667 |
+
}
|
1668 |
+
}*/
|
1669 |
+
|
1670 |
+
foreach ( $data as $key => $value ) {
|
1671 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
1672 |
+
continue;
|
1673 |
+
}
|
1674 |
+
|
1675 |
+
$termdata[ $key ] = $data[ $key ];
|
1676 |
+
}
|
1677 |
+
|
1678 |
+
$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
|
1679 |
+
if ( is_wp_error( $result ) ) {
|
1680 |
+
$this->logger->warning( sprintf(
|
1681 |
+
__( 'Failed to import %s %s', 'rara-one-click-demo-import' ),
|
1682 |
+
$data['taxonomy'],
|
1683 |
+
$data['name']
|
1684 |
+
) );
|
1685 |
+
$this->logger->debug( $result->get_error_message() );
|
1686 |
+
do_action( 'wp_import_insert_term_failed', $result, $data );
|
1687 |
+
|
1688 |
+
/**
|
1689 |
+
* Term processing failed.
|
1690 |
+
*
|
1691 |
+
* @param WP_Error $result Error object.
|
1692 |
+
* @param array $data Raw data imported for the term.
|
1693 |
+
* @param array $meta Meta data supplied for the term.
|
1694 |
+
*/
|
1695 |
+
do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
|
1696 |
+
return false;
|
1697 |
+
}
|
1698 |
+
|
1699 |
+
$term_id = $result['term_id'];
|
1700 |
+
|
1701 |
+
$this->mapping['term'][ $mapping_key ] = $term_id;
|
1702 |
+
$this->mapping['term_id'][ $original_id ] = $term_id;
|
1703 |
+
|
1704 |
+
$this->logger->info( sprintf(
|
1705 |
+
__( 'Imported "%s" (%s)', 'rara-one-click-demo-import' ),
|
1706 |
+
$data['name'],
|
1707 |
+
$data['taxonomy']
|
1708 |
+
) );
|
1709 |
+
$this->logger->debug( sprintf(
|
1710 |
+
__( 'Term %d remapped to %d', 'rara-one-click-demo-import' ),
|
1711 |
+
$original_id,
|
1712 |
+
$term_id
|
1713 |
+
) );
|
1714 |
+
|
1715 |
+
do_action( 'wp_import_insert_term', $term_id, $data );
|
1716 |
+
|
1717 |
+
/**
|
1718 |
+
* Term processing completed.
|
1719 |
+
*
|
1720 |
+
* @param int $term_id New term ID.
|
1721 |
+
* @param array $data Raw data imported for the term.
|
1722 |
+
*/
|
1723 |
+
do_action( 'wxr_importer.processed.term', $term_id, $data );
|
1724 |
+
}
|
1725 |
+
|
1726 |
+
/**
|
1727 |
+
* Attempt to download a remote file attachment
|
1728 |
+
*
|
1729 |
+
* @param string $url URL of item to fetch
|
1730 |
+
* @param array $post Attachment details
|
1731 |
+
* @return array|WP_Error Local file location details on success, WP_Error otherwise
|
1732 |
+
*/
|
1733 |
+
protected function fetch_remote_file( $url, $post ) {
|
1734 |
+
// extract the file name and extension from the url
|
1735 |
+
$file_name = basename( $url );
|
1736 |
+
|
1737 |
+
// get placeholder file in the upload dir with a unique, sanitized filename
|
1738 |
+
$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
|
1739 |
+
if ( $upload['error'] ) {
|
1740 |
+
return new WP_Error( 'upload_dir_error', $upload['error'] );
|
1741 |
+
}
|
1742 |
+
|
1743 |
+
// fetch the remote url and write it to the placeholder file
|
1744 |
+
$response = wp_remote_get( $url, array(
|
1745 |
+
'stream' => true,
|
1746 |
+
'filename' => $upload['file'],
|
1747 |
+
) );
|
1748 |
+
|
1749 |
+
// request failed
|
1750 |
+
if ( is_wp_error( $response ) ) {
|
1751 |
+
unlink( $upload['file'] );
|
1752 |
+
return $response;
|
1753 |
+
}
|
1754 |
+
|
1755 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
1756 |
+
|
1757 |
+
// make sure the fetch was successful
|
1758 |
+
if ( $code !== 200 ) {
|
1759 |
+
unlink( $upload['file'] );
|
1760 |
+
return new WP_Error(
|
1761 |
+
'import_file_error',
|
1762 |
+
sprintf(
|
1763 |
+
__( 'Remote server returned %1$d %2$s for %3$s', 'rara-one-click-demo-import' ),
|
1764 |
+
$code,
|
1765 |
+
get_status_header_desc( $code ),
|
1766 |
+
$url
|
1767 |
+
)
|
1768 |
+
);
|
1769 |
+
}
|
1770 |
+
|
1771 |
+
$filesize = filesize( $upload['file'] );
|
1772 |
+
$headers = wp_remote_retrieve_headers( $response );
|
1773 |
+
|
1774 |
+
if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
|
1775 |
+
unlink( $upload['file'] );
|
1776 |
+
return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'rara-one-click-demo-import' ) );
|
1777 |
+
}
|
1778 |
+
|
1779 |
+
if ( 0 === $filesize ) {
|
1780 |
+
unlink( $upload['file'] );
|
1781 |
+
return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'rara-one-click-demo-import' ) );
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
$max_size = (int) $this->max_attachment_size();
|
1785 |
+
if ( ! empty( $max_size ) && $filesize > $max_size ) {
|
1786 |
+
unlink( $upload['file'] );
|
1787 |
+
$message = sprintf( __( 'Remote file is too large, limit is %s', 'rara-one-click-demo-import' ), size_format( $max_size ) );
|
1788 |
+
return new WP_Error( 'import_file_error', $message );
|
1789 |
+
}
|
1790 |
+
|
1791 |
+
return $upload;
|
1792 |
+
}
|
1793 |
+
|
1794 |
+
protected function post_process() {
|
1795 |
+
// Time to tackle any left-over bits
|
1796 |
+
if ( ! empty( $this->requires_remapping['post'] ) ) {
|
1797 |
+
$this->post_process_posts( $this->requires_remapping['post'] );
|
1798 |
+
}
|
1799 |
+
if ( ! empty( $this->requires_remapping['comment'] ) ) {
|
1800 |
+
$this->post_process_comments( $this->requires_remapping['comment'] );
|
1801 |
+
}
|
1802 |
+
}
|
1803 |
+
|
1804 |
+
protected function post_process_posts( $todo ) {
|
1805 |
+
foreach ( $todo as $post_id => $_ ) {
|
1806 |
+
$this->logger->debug( sprintf(
|
1807 |
+
// Note: title intentionally not used to skip extra processing
|
1808 |
+
// for when debug logging is off
|
1809 |
+
__( 'Running post-processing for post %d', 'rara-one-click-demo-import' ),
|
1810 |
+
$post_id
|
1811 |
+
) );
|
1812 |
+
|
1813 |
+
$data = array();
|
1814 |
+
|
1815 |
+
$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
|
1816 |
+
if ( ! empty( $parent_id ) ) {
|
1817 |
+
// Have we imported the parent now?
|
1818 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
1819 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
1820 |
+
} else {
|
1821 |
+
$this->logger->warning( sprintf(
|
1822 |
+
__( 'Could not find the post parent for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1823 |
+
get_the_title( $post_id ),
|
1824 |
+
$post_id
|
1825 |
+
) );
|
1826 |
+
$this->logger->debug( sprintf(
|
1827 |
+
__( 'Post %d was imported with parent %d, but could not be found', 'rara-one-click-demo-import' ),
|
1828 |
+
$post_id,
|
1829 |
+
$parent_id
|
1830 |
+
) );
|
1831 |
+
}
|
1832 |
+
}
|
1833 |
+
|
1834 |
+
$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
|
1835 |
+
if ( ! empty( $author_slug ) ) {
|
1836 |
+
// Have we imported the user now?
|
1837 |
+
if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
|
1838 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
|
1839 |
+
} else {
|
1840 |
+
$this->logger->warning( sprintf(
|
1841 |
+
__( 'Could not find the author for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1842 |
+
get_the_title( $post_id ),
|
1843 |
+
$post_id
|
1844 |
+
) );
|
1845 |
+
$this->logger->debug( sprintf(
|
1846 |
+
__( 'Post %d was imported with author "%s", but could not be found', 'rara-one-click-demo-import' ),
|
1847 |
+
$post_id,
|
1848 |
+
$author_slug
|
1849 |
+
) );
|
1850 |
+
}
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
|
1854 |
+
if ( ! empty( $has_attachments ) ) {
|
1855 |
+
$post = get_post( $post_id );
|
1856 |
+
$content = $post->post_content;
|
1857 |
+
|
1858 |
+
// Replace all the URLs we've got
|
1859 |
+
$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
|
1860 |
+
if ( $new_content !== $content ) {
|
1861 |
+
$data['post_content'] = $new_content;
|
1862 |
+
}
|
1863 |
+
}
|
1864 |
+
|
1865 |
+
if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
|
1866 |
+
$this->post_process_menu_item( $post_id );
|
1867 |
+
}
|
1868 |
+
|
1869 |
+
// Do we have updates to make?
|
1870 |
+
if ( empty( $data ) ) {
|
1871 |
+
$this->logger->debug( sprintf(
|
1872 |
+
__( 'Post %d was marked for post-processing, but none was required.', 'rara-one-click-demo-import' ),
|
1873 |
+
$post_id
|
1874 |
+
) );
|
1875 |
+
continue;
|
1876 |
+
}
|
1877 |
+
|
1878 |
+
// Run the update
|
1879 |
+
$data['ID'] = $post_id;
|
1880 |
+
$result = wp_update_post( $data, true );
|
1881 |
+
if ( is_wp_error( $result ) ) {
|
1882 |
+
$this->logger->warning( sprintf(
|
1883 |
+
__( 'Could not update "%s" (post #%d) with mapped data', 'rara-one-click-demo-import' ),
|
1884 |
+
get_the_title( $post_id ),
|
1885 |
+
$post_id
|
1886 |
+
) );
|
1887 |
+
$this->logger->debug( $result->get_error_message() );
|
1888 |
+
continue;
|
1889 |
+
}
|
1890 |
+
|
1891 |
+
// Clear out our temporary meta keys
|
1892 |
+
delete_post_meta( $post_id, '_wxr_import_parent' );
|
1893 |
+
delete_post_meta( $post_id, '_wxr_import_user_slug' );
|
1894 |
+
delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
|
1895 |
+
}
|
1896 |
+
}
|
1897 |
+
|
1898 |
+
protected function post_process_menu_item( $post_id ) {
|
1899 |
+
$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
|
1900 |
+
if ( empty( $menu_object_id ) ) {
|
1901 |
+
// No processing needed!
|
1902 |
+
return;
|
1903 |
+
}
|
1904 |
+
|
1905 |
+
$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
1906 |
+
switch ( $menu_item_type ) {
|
1907 |
+
case 'taxonomy':
|
1908 |
+
if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
|
1909 |
+
$menu_object = $this->mapping['term_id'][ $menu_object_id ];
|
1910 |
+
}
|
1911 |
+
break;
|
1912 |
+
|
1913 |
+
case 'post_type':
|
1914 |
+
if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
|
1915 |
+
$menu_object = $this->mapping['post'][ $menu_object_id ];
|
1916 |
+
}
|
1917 |
+
break;
|
1918 |
+
|
1919 |
+
default:
|
1920 |
+
// Cannot handle this.
|
1921 |
+
return;
|
1922 |
+
}
|
1923 |
+
|
1924 |
+
if ( ! empty( $menu_object ) ) {
|
1925 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
|
1926 |
+
} else {
|
1927 |
+
$this->logger->warning( sprintf(
|
1928 |
+
__( 'Could not find the menu object for "%s" (post #%d)', 'rara-one-click-demo-import' ),
|
1929 |
+
get_the_title( $post_id ),
|
1930 |
+
$post_id
|
1931 |
+
) );
|
1932 |
+
$this->logger->debug( sprintf(
|
1933 |
+
__( 'Post %d was imported with object "%d" of type "%s", but could not be found', 'rara-one-click-demo-import' ),
|
1934 |
+
$post_id,
|
1935 |
+
$menu_object_id,
|
1936 |
+
$menu_item_type
|
1937 |
+
) );
|
1938 |
+
}
|
1939 |
+
|
1940 |
+
delete_post_meta( $post_id, '_wxr_import_menu_item' );
|
1941 |
+
}
|
1942 |
+
|
1943 |
+
|
1944 |
+
protected function post_process_comments( $todo ) {
|
1945 |
+
foreach ( $todo as $comment_id => $_ ) {
|
1946 |
+
$data = array();
|
1947 |
+
|
1948 |
+
$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
|
1949 |
+
if ( ! empty( $parent_id ) ) {
|
1950 |
+
// Have we imported the parent now?
|
1951 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1952 |
+
$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1953 |
+
} else {
|
1954 |
+
$this->logger->warning( sprintf(
|
1955 |
+
__( 'Could not find the comment parent for comment #%d', 'rara-one-click-demo-import' ),
|
1956 |
+
$comment_id
|
1957 |
+
) );
|
1958 |
+
$this->logger->debug( sprintf(
|
1959 |
+
__( 'Comment %d was imported with parent %d, but could not be found', 'rara-one-click-demo-import' ),
|
1960 |
+
$comment_id,
|
1961 |
+
$parent_id
|
1962 |
+
) );
|
1963 |
+
}
|
1964 |
+
}
|
1965 |
+
|
1966 |
+
$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
|
1967 |
+
if ( ! empty( $author_id ) ) {
|
1968 |
+
// Have we imported the user now?
|
1969 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1970 |
+
$data['user_id'] = $this->mapping['user'][ $author_id ];
|
1971 |
+
} else {
|
1972 |
+
$this->logger->warning( sprintf(
|
1973 |
+
__( 'Could not find the author for comment #%d', 'rara-one-click-demo-import' ),
|
1974 |
+
$comment_id
|
1975 |
+
) );
|
1976 |
+
$this->logger->debug( sprintf(
|
1977 |
+
__( 'Comment %d was imported with author %d, but could not be found', 'rara-one-click-demo-import' ),
|
1978 |
+
$comment_id,
|
1979 |
+
$author_id
|
1980 |
+
) );
|
1981 |
+
}
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
// Do we have updates to make?
|
1985 |
+
if ( empty( $data ) ) {
|
1986 |
+
continue;
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
// Run the update
|
1990 |
+
$data['comment_ID'] = $comment_ID;
|
1991 |
+
$result = wp_update_comment( wp_slash( $data ) );
|
1992 |
+
if ( empty( $result ) ) {
|
1993 |
+
$this->logger->warning( sprintf(
|
1994 |
+
__( 'Could not update comment #%d with mapped data', 'rara-one-click-demo-import' ),
|
1995 |
+
$comment_id
|
1996 |
+
) );
|
1997 |
+
continue;
|
1998 |
+
}
|
1999 |
+
|
2000 |
+
// Clear out our temporary meta keys
|
2001 |
+
delete_comment_meta( $comment_id, '_wxr_import_parent' );
|
2002 |
+
delete_comment_meta( $comment_id, '_wxr_import_user' );
|
2003 |
+
}
|
2004 |
+
}
|
2005 |
+
|
2006 |
+
/**
|
2007 |
+
* Use stored mapping information to update old attachment URLs
|
2008 |
+
*/
|
2009 |
+
protected function replace_attachment_urls_in_content() {
|
2010 |
+
global $wpdb;
|
2011 |
+
// make sure we do the longest urls first, in case one is a substring of another
|
2012 |
+
uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
|
2013 |
+
|
2014 |
+
foreach ( $this->url_remap as $from_url => $to_url ) {
|
2015 |
+
// remap urls in post_content
|
2016 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
|
2017 |
+
$wpdb->query( $query );
|
2018 |
+
|
2019 |
+
// remap enclosure urls
|
2020 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
|
2021 |
+
$result = $wpdb->query( $query );
|
2022 |
+
}
|
2023 |
+
}
|
2024 |
+
|
2025 |
+
/**
|
2026 |
+
* Update _thumbnail_id meta to new, imported attachment IDs
|
2027 |
+
*/
|
2028 |
+
function remap_featured_images() {
|
2029 |
+
// cycle through posts that have a featured image
|
2030 |
+
foreach ( $this->featured_images as $post_id => $value ) {
|
2031 |
+
if ( isset( $this->processed_posts[ $value ] ) ) {
|
2032 |
+
$new_id = $this->processed_posts[ $value ];
|
2033 |
+
|
2034 |
+
// only update if there's a difference
|
2035 |
+
if ( $new_id !== $value ) {
|
2036 |
+
update_post_meta( $post_id, '_thumbnail_id', $new_id );
|
2037 |
+
}
|
2038 |
+
}
|
2039 |
+
}
|
2040 |
+
}
|
2041 |
+
|
2042 |
+
/**
|
2043 |
+
* Decide if the given meta key maps to information we will want to import
|
2044 |
+
*
|
2045 |
+
* @param string $key The meta key to check
|
2046 |
+
* @return string|bool The key if we do want to import, false if not
|
2047 |
+
*/
|
2048 |
+
public function is_valid_meta_key( $key ) {
|
2049 |
+
// skip attachment metadata since we'll regenerate it from scratch
|
2050 |
+
// skip _edit_lock as not relevant for import
|
2051 |
+
if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
|
2052 |
+
return false;
|
2053 |
+
}
|
2054 |
+
|
2055 |
+
return $key;
|
2056 |
+
}
|
2057 |
+
|
2058 |
+
/**
|
2059 |
+
* Decide what the maximum file size for downloaded attachments is.
|
2060 |
+
* Default is 0 (unlimited), can be filtered via import_attachment_size_limit
|
2061 |
+
*
|
2062 |
+
* @return int Maximum attachment file size to import
|
2063 |
+
*/
|
2064 |
+
protected function max_attachment_size() {
|
2065 |
+
return apply_filters( 'import_attachment_size_limit', 0 );
|
2066 |
+
}
|
2067 |
+
|
2068 |
+
/**
|
2069 |
+
* Added to http_request_timeout filter to force timeout at 60 seconds during import
|
2070 |
+
*
|
2071 |
+
* @access protected
|
2072 |
+
* @return int 60
|
2073 |
+
*/
|
2074 |
+
function bump_request_timeout($val) {
|
2075 |
+
return 60;
|
2076 |
+
}
|
2077 |
+
|
2078 |
+
// return the difference in length between two strings
|
2079 |
+
function cmpr_strlen( $a, $b ) {
|
2080 |
+
return strlen( $b ) - strlen( $a );
|
2081 |
+
}
|
2082 |
+
|
2083 |
+
/**
|
2084 |
+
* Prefill existing post data.
|
2085 |
+
*
|
2086 |
+
* This preloads all GUIDs into memory, allowing us to avoid hitting the
|
2087 |
+
* database when we need to check for existence. With larger imports, this
|
2088 |
+
* becomes prohibitively slow to perform SELECT queries on each.
|
2089 |
+
*
|
2090 |
+
* By preloading all this data into memory, it's a constant-time lookup in
|
2091 |
+
* PHP instead. However, this does use a lot more memory, so for sites doing
|
2092 |
+
* small imports onto a large site, it may be a better tradeoff to use
|
2093 |
+
* on-the-fly checking instead.
|
2094 |
+
*/
|
2095 |
+
protected function prefill_existing_posts() {
|
2096 |
+
global $wpdb;
|
2097 |
+
$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
|
2098 |
+
|
2099 |
+
foreach ( $posts as $item ) {
|
2100 |
+
$this->exists['post'][ $item->guid ] = $item->ID;
|
2101 |
+
}
|
2102 |
+
}
|
2103 |
+
|
2104 |
+
/**
|
2105 |
+
* Does the post exist?
|
2106 |
+
*
|
2107 |
+
* @param array $data Post data to check against.
|
2108 |
+
* @return int|bool Existing post ID if it exists, false otherwise.
|
2109 |
+
*/
|
2110 |
+
protected function post_exists( $data ) {
|
2111 |
+
// Constant-time lookup if we prefilled
|
2112 |
+
$exists_key = $data['guid'];
|
2113 |
+
|
2114 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
2115 |
+
return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
|
2116 |
+
}
|
2117 |
+
|
2118 |
+
// No prefilling, but might have already handled it
|
2119 |
+
if ( isset( $this->exists['post'][ $exists_key ] ) ) {
|
2120 |
+
return $this->exists['post'][ $exists_key ];
|
2121 |
+
}
|
2122 |
+
|
2123 |
+
// Still nothing, try post_exists, and cache it
|
2124 |
+
$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
|
2125 |
+
$this->exists['post'][ $exists_key ] = $exists;
|
2126 |
+
|
2127 |
+
return $exists;
|
2128 |
+
}
|
2129 |
+
|
2130 |
+
/**
|
2131 |
+
* Mark the post as existing.
|
2132 |
+
*
|
2133 |
+
* @param array $data Post data to mark as existing.
|
2134 |
+
* @param int $post_id Post ID.
|
2135 |
+
*/
|
2136 |
+
protected function mark_post_exists( $data, $post_id ) {
|
2137 |
+
$exists_key = $data['guid'];
|
2138 |
+
$this->exists['post'][ $exists_key ] = $post_id;
|
2139 |
+
}
|
2140 |
+
|
2141 |
+
/**
|
2142 |
+
* Prefill existing comment data.
|
2143 |
+
*
|
2144 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
2145 |
+
*/
|
2146 |
+
protected function prefill_existing_comments() {
|
2147 |
+
global $wpdb;
|
2148 |
+
$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
|
2149 |
+
|
2150 |
+
foreach ( $posts as $item ) {
|
2151 |
+
$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
|
2152 |
+
$this->exists['comment'][ $exists_key ] = $item->comment_ID;
|
2153 |
+
}
|
2154 |
+
}
|
2155 |
+
|
2156 |
+
/**
|
2157 |
+
* Does the comment exist?
|
2158 |
+
*
|
2159 |
+
* @param array $data Comment data to check against.
|
2160 |
+
* @return int|bool Existing comment ID if it exists, false otherwise.
|
2161 |
+
*/
|
2162 |
+
protected function comment_exists( $data ) {
|
2163 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2164 |
+
|
2165 |
+
// Constant-time lookup if we prefilled
|
2166 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
2167 |
+
return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
|
2168 |
+
}
|
2169 |
+
|
2170 |
+
// No prefilling, but might have already handled it
|
2171 |
+
if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
|
2172 |
+
return $this->exists['comment'][ $exists_key ];
|
2173 |
+
}
|
2174 |
+
|
2175 |
+
// Still nothing, try comment_exists, and cache it
|
2176 |
+
$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
|
2177 |
+
$this->exists['comment'][ $exists_key ] = $exists;
|
2178 |
+
|
2179 |
+
return $exists;
|
2180 |
+
}
|
2181 |
+
|
2182 |
+
/**
|
2183 |
+
* Mark the comment as existing.
|
2184 |
+
*
|
2185 |
+
* @param array $data Comment data to mark as existing.
|
2186 |
+
* @param int $comment_id Comment ID.
|
2187 |
+
*/
|
2188 |
+
protected function mark_comment_exists( $data, $comment_id ) {
|
2189 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2190 |
+
$this->exists['comment'][ $exists_key ] = $comment_id;
|
2191 |
+
}
|
2192 |
+
|
2193 |
+
/**
|
2194 |
+
* Prefill existing term data.
|
2195 |
+
*
|
2196 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
2197 |
+
*/
|
2198 |
+
protected function prefill_existing_terms() {
|
2199 |
+
global $wpdb;
|
2200 |
+
$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
|
2201 |
+
$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
|
2202 |
+
$terms = $wpdb->get_results( $query );
|
2203 |
+
|
2204 |
+
foreach ( $terms as $item ) {
|
2205 |
+
$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
|
2206 |
+
$this->exists['term'][ $exists_key ] = $item->term_id;
|
2207 |
+
}
|
2208 |
+
}
|
2209 |
+
|
2210 |
+
/**
|
2211 |
+
* Does the term exist?
|
2212 |
+
*
|
2213 |
+
* @param array $data Term data to check against.
|
2214 |
+
* @return int|bool Existing term ID if it exists, false otherwise.
|
2215 |
+
*/
|
2216 |
+
protected function term_exists( $data ) {
|
2217 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2218 |
+
|
2219 |
+
// Constant-time lookup if we prefilled
|
2220 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
2221 |
+
return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
|
2222 |
+
}
|
2223 |
+
|
2224 |
+
// No prefilling, but might have already handled it
|
2225 |
+
if ( isset( $this->exists['term'][ $exists_key ] ) ) {
|
2226 |
+
return $this->exists['term'][ $exists_key ];
|
2227 |
+
}
|
2228 |
+
|
2229 |
+
// Still nothing, try comment_exists, and cache it
|
2230 |
+
$exists = term_exists( $data['slug'], $data['taxonomy'] );
|
2231 |
+
if ( is_array( $exists ) ) {
|
2232 |
+
$exists = $exists['term_id'];
|
2233 |
+
}
|
2234 |
+
|
2235 |
+
$this->exists['term'][ $exists_key ] = $exists;
|
2236 |
+
|
2237 |
+
return $exists;
|
2238 |
+
}
|
2239 |
+
|
2240 |
+
/**
|
2241 |
+
* Mark the term as existing.
|
2242 |
+
*
|
2243 |
+
* @param array $data Term data to mark as existing.
|
2244 |
+
* @param int $term_id Term ID.
|
2245 |
+
*/
|
2246 |
+
protected function mark_term_exists( $data, $term_id ) {
|
2247 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2248 |
+
$this->exists['term'][ $exists_key ] = $term_id;
|
2249 |
+
}
|
2250 |
+
}
|
includes/settings/installed-demos.php
CHANGED
@@ -1,237 +1,237 @@
|
|
1 |
-
<div class="RRDI__intro-notice notice notice-warning is-dismissible">
|
2 |
-
<p><?php
|
3 |
-
echo apply_filters( 'rrdi_before_import_msg', esc_html__( 'Before you begin, make sure all the required plugins are activated.', 'rara-one-click-demo-import' ) ); ?>
|
4 |
-
</p>
|
5 |
-
</div>
|
6 |
-
<div class="rrdi wrap about-wrap">
|
7 |
-
<?php
|
8 |
-
|
9 |
-
// Display warrning if PHP safe mode is enabled, since we wont be able to change the max_execution_time.
|
10 |
-
if ( ini_get( 'safe_mode' ) ) {
|
11 |
-
printf(
|
12 |
-
esc_html__( '%1$sWarning: your server is using %2$sPHP safe mode%3$s. This means that you might experience server timeout errors.%4$s', 'rara-one-click-demo-import' ),
|
13 |
-
'<div class="notice notice-warning is-dismissible"><p>',
|
14 |
-
'<strong>',
|
15 |
-
'</strong>',
|
16 |
-
'</p></div>'
|
17 |
-
);
|
18 |
-
}
|
19 |
-
|
20 |
-
// Start output buffer for displaying the plugin intro text.
|
21 |
-
ob_start();
|
22 |
-
?>
|
23 |
-
|
24 |
-
<div class="RRDI__intro-text">
|
25 |
-
|
26 |
-
<p class="about-description">
|
27 |
-
<?php
|
28 |
-
$link = '<a href="https://rarathemes.com/">Rara Theme</a>';
|
29 |
-
$doc = '<a href="https://rarathemes.com/documentation/" target="_blank">documentation</a>';
|
30 |
-
$bold = '<b>';
|
31 |
-
$boldclose = '</b>';
|
32 |
-
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
33 |
-
|
34 |
-
$msg = sprintf( __( 'If you are using premium themes by %1$s, just click Import Now button below. Alternatively, you can download zip files from the %2$s page of your theme and upload it as mentioned in Demo Import tab. As simple as that.', 'rara-one-click-demo-import' ), $link, $doc );
|
35 |
-
echo wp_kses(
|
36 |
-
apply_filters( 'rrdi_import_instruction', $msg ),
|
37 |
-
array(
|
38 |
-
'a' => array(
|
39 |
-
'href' => array(),
|
40 |
-
'target' => array(),
|
41 |
-
),
|
42 |
-
'b' => array(),
|
43 |
-
)
|
44 |
-
);
|
45 |
-
?>
|
46 |
-
</p>
|
47 |
-
|
48 |
-
<h3><?php esc_html_e( 'The following data will be imported:', 'rara-one-click-demo-import' ); ?></h3>
|
49 |
-
|
50 |
-
<ul>
|
51 |
-
<li><?php esc_html_e( 'Posts', 'rara-one-click-demo-import' ); ?></li>
|
52 |
-
<li><?php esc_html_e( 'Pages', 'rara-one-click-demo-import' ); ?></li>
|
53 |
-
<li><?php esc_html_e( 'Images', 'rara-one-click-demo-import' ); ?></li>
|
54 |
-
<li><?php esc_html_e( 'Widgets', 'rara-one-click-demo-import' ); ?></li>
|
55 |
-
<li><?php esc_html_e( 'Menus', 'rara-one-click-demo-import' ); ?></li>
|
56 |
-
<li><?php esc_html_e( 'Settings', 'rara-one-click-demo-import' ); ?></li>
|
57 |
-
</ul>
|
58 |
-
<?php
|
59 |
-
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
60 |
-
?>
|
61 |
-
<p><h4>
|
62 |
-
<?php
|
63 |
-
$msg = sprintf( __( 'Note: To import demo content for the free themes, please follow the step-by-step instructions mentioned in the %1$s Demo Import %2$s tab.', 'rara-one-click-demo-import' ), $bold, $boldclose );
|
64 |
-
echo wp_kses( apply_filters( 'rrdi_fresh_install_instruction', $msg ), array( 'b' => array() ) );
|
65 |
-
?>
|
66 |
-
</h4></p>
|
67 |
-
<p><h4>
|
68 |
-
<?php
|
69 |
-
echo wp_kses(
|
70 |
-
sprintf(
|
71 |
-
__( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ),
|
72 |
-
$wpreset
|
73 |
-
),
|
74 |
-
array(
|
75 |
-
'a' => array(
|
76 |
-
'href' => array(),
|
77 |
-
'target' => array(),
|
78 |
-
),
|
79 |
-
)
|
80 |
-
);
|
81 |
-
?>
|
82 |
-
</h4></p>
|
83 |
-
<hr>
|
84 |
-
|
85 |
-
</div>
|
86 |
-
|
87 |
-
<?php
|
88 |
-
$plugin_intro_text = ob_get_clean();
|
89 |
-
|
90 |
-
// Display the plugin intro text (can be replaced with custom text through the filter below).
|
91 |
-
echo wp_kses_post( apply_filters( 'rrdi/plugin_intro_text', $plugin_intro_text ) );
|
92 |
-
|
93 |
-
$my_theme = wp_get_theme();
|
94 |
-
$td = $my_theme->get( 'TextDomain' );
|
95 |
-
|
96 |
-
if ( strpos( $td, 'pro' ) === false && ! empty( $this->import_files ) ) {
|
97 |
-
?>
|
98 |
-
|
99 |
-
<div class="RRDI__file-upload-container">
|
100 |
-
<?php
|
101 |
-
$bold = '<b>';
|
102 |
-
$boldclose = '</b>';
|
103 |
-
?>
|
104 |
-
<br><h4 style="color:red">
|
105 |
-
<?php
|
106 |
-
echo wp_kses(
|
107 |
-
sprintf( __( 'Note: For free themes, always upload the appropriate demo zip file from %1$s Demo Import %2$s tab and import demo data as mentioned there.', 'rara-one-click-demo-import' ), $bold, $boldclose ),
|
108 |
-
array(
|
109 |
-
'a' => array(
|
110 |
-
'href' => array(),
|
111 |
-
'target' => array(),
|
112 |
-
),
|
113 |
-
'b' => array(),
|
114 |
-
)
|
115 |
-
);
|
116 |
-
?>
|
117 |
-
</h4>
|
118 |
-
</div>
|
119 |
-
<?php
|
120 |
-
}
|
121 |
-
|
122 |
-
// Check the folder contains at least 1 valid demo config.
|
123 |
-
$upload_dir = wp_upload_dir();
|
124 |
-
$path = $upload_dir['basedir'] . '/rara-demo-pack/';
|
125 |
-
$working_dir = getcwd();
|
126 |
-
chdir( $path ); // chdir to requested dir
|
127 |
-
$ret_val = false;
|
128 |
-
if ( $p = opendir( $path ) ) {
|
129 |
-
while ( false !== ( $file = readdir( $p ) ) ) {
|
130 |
-
if ( $file[0] != '.' && is_dir( $file ) ) {
|
131 |
-
$list[] = date( 'YmdHis', filemtime( $path . '/' . $file ) ) . $path . '/' . $file;
|
132 |
-
}
|
133 |
-
}
|
134 |
-
if ( isset( $list ) ) {
|
135 |
-
rsort( $list );
|
136 |
-
$ret_val = $list[0];
|
137 |
-
}
|
138 |
-
}
|
139 |
-
chdir( $working_dir ); // chdir back to script's dir
|
140 |
-
|
141 |
-
$my_theme = wp_get_theme();
|
142 |
-
$td = $my_theme->get( 'TextDomain' );
|
143 |
-
|
144 |
-
$sr = explode( '/', $ret_val );
|
145 |
-
$sr = end( $sr );
|
146 |
-
|
147 |
-
if ( empty( $this->import_files ) ) :
|
148 |
-
?>
|
149 |
-
|
150 |
-
<?php elseif ( 1 < count( $this->import_files ) ) : ?>
|
151 |
-
|
152 |
-
<div class="RRDI__multi-select-import">
|
153 |
-
|
154 |
-
<h2><?php esc_html_e( 'Choose which demo you want to import:', 'rara-one-click-demo-import' ); ?></h2>
|
155 |
-
|
156 |
-
<select id="RRDI__demo-import-files" class="RRDI__demo-import-files">
|
157 |
-
<?php foreach ( $this->import_files as $index => $import_file ) : ?>
|
158 |
-
<option value="<?php echo esc_attr( $index ); ?>">
|
159 |
-
<?php echo esc_html( $import_file['import_file_name'] ); ?>
|
160 |
-
</option>
|
161 |
-
<?php endforeach; ?>
|
162 |
-
</select>
|
163 |
-
|
164 |
-
<?php
|
165 |
-
// Check if at least one preview image is defined, so we can prepare the structure for display.
|
166 |
-
$preview_image_is_defined = false;
|
167 |
-
foreach ( $this->import_files as $import_file ) {
|
168 |
-
if ( isset( $import_file['import_preview_image_url'] ) ) {
|
169 |
-
$preview_image_is_defined = true;
|
170 |
-
break;
|
171 |
-
}
|
172 |
-
}
|
173 |
-
|
174 |
-
if ( $preview_image_is_defined ) :
|
175 |
-
?>
|
176 |
-
|
177 |
-
<div class="RRDI__demo-import-preview-container">
|
178 |
-
|
179 |
-
<p><?php esc_html_e( 'Import preview:', 'rara-one-click-demo-import' ); ?></p>
|
180 |
-
|
181 |
-
<p class="RRDI__demo-import-preview-image-message js-rrdi-preview-image-message">
|
182 |
-
<?php
|
183 |
-
if ( ! isset( $this->import_files[0]['import_preview_image_url'] ) ) {
|
184 |
-
esc_html_e( 'No preview image defined for this import.', 'rara-one-click-demo-import' );
|
185 |
-
}
|
186 |
-
// Leave the img tag below and the p tag above available for later changes via JS.
|
187 |
-
?>
|
188 |
-
</p>
|
189 |
-
|
190 |
-
<img id="RRDI__demo-import-preview-image" class="js-rrdi-preview-image" src="<?php echo ! empty( $this->import_files[0]['import_preview_image_url'] ) ? esc_url( $this->import_files[0]['import_preview_image_url'] ) : ''; ?>">
|
191 |
-
|
192 |
-
</div>
|
193 |
-
|
194 |
-
<?php endif; ?>
|
195 |
-
|
196 |
-
</div>
|
197 |
-
|
198 |
-
<?php
|
199 |
-
endif;
|
200 |
-
|
201 |
-
$upload_dir = wp_upload_dir();
|
202 |
-
|
203 |
-
$directory = $upload_dir['basedir'] . '/rara-demo-pack/';
|
204 |
-
|
205 |
-
// get all files in specified directory
|
206 |
-
$files = glob( $directory . '*', GLOB_ONLYDIR );
|
207 |
-
|
208 |
-
// print each file name
|
209 |
-
foreach ( $files as $file ) {
|
210 |
-
// check to see if the file is a folder/directory
|
211 |
-
if ( is_dir( $file ) ) {
|
212 |
-
$arr[] = basename( $file );
|
213 |
-
}
|
214 |
-
}
|
215 |
-
|
216 |
-
$my_theme = wp_get_theme();
|
217 |
-
|
218 |
-
if ( is_array( $this->import_files ) && ! empty( $this->import_files[0]['import_notice'] ) ) {
|
219 |
-
?>
|
220 |
-
<div class="RRDI__demo-import-notice js-rrdi-demo-import-notice">
|
221 |
-
<?php echo wp_kses_post( $this->import_files[0]['import_notice'] ); ?>
|
222 |
-
</div>
|
223 |
-
<?php
|
224 |
-
}
|
225 |
-
?>
|
226 |
-
|
227 |
-
<p class="RRDI__button-container">
|
228 |
-
<button class="RRDI__button button button-hero button-primary js-rrdi-import-data"><?php esc_html_e( 'Import Now', 'rara-one-click-demo-import' ); ?></button>
|
229 |
-
<span><?php esc_html_e( 'Click the button to begin the importing process. Please be patient, the process might take a few minutes.', 'rara-one-click-demo-import' ); ?></span>
|
230 |
-
</p>
|
231 |
-
|
232 |
-
<p class="RRDI__ajax-loader js-rrdi-ajax-loader">
|
233 |
-
<span class="spinner"></span> <?php esc_html_e( 'Importing now, please wait!', 'rara-one-click-demo-import' ); ?>
|
234 |
-
</p>
|
235 |
-
|
236 |
-
<div class="RRDI__response js-rrdi-ajax-response"></div>
|
237 |
-
</div>
|
1 |
+
<div class="RRDI__intro-notice notice notice-warning is-dismissible">
|
2 |
+
<p><?php
|
3 |
+
echo apply_filters( 'rrdi_before_import_msg', esc_html__( 'Before you begin, make sure all the required plugins are activated.', 'rara-one-click-demo-import' ) ); ?>
|
4 |
+
</p>
|
5 |
+
</div>
|
6 |
+
<div class="rrdi wrap about-wrap">
|
7 |
+
<?php
|
8 |
+
|
9 |
+
// Display warrning if PHP safe mode is enabled, since we wont be able to change the max_execution_time.
|
10 |
+
if ( ini_get( 'safe_mode' ) ) {
|
11 |
+
printf(
|
12 |
+
esc_html__( '%1$sWarning: your server is using %2$sPHP safe mode%3$s. This means that you might experience server timeout errors.%4$s', 'rara-one-click-demo-import' ),
|
13 |
+
'<div class="notice notice-warning is-dismissible"><p>',
|
14 |
+
'<strong>',
|
15 |
+
'</strong>',
|
16 |
+
'</p></div>'
|
17 |
+
);
|
18 |
+
}
|
19 |
+
|
20 |
+
// Start output buffer for displaying the plugin intro text.
|
21 |
+
ob_start();
|
22 |
+
?>
|
23 |
+
|
24 |
+
<div class="RRDI__intro-text">
|
25 |
+
|
26 |
+
<p class="about-description">
|
27 |
+
<?php
|
28 |
+
$link = '<a href="https://rarathemes.com/">Rara Theme</a>';
|
29 |
+
$doc = '<a href="https://rarathemes.com/documentation/" target="_blank">documentation</a>';
|
30 |
+
$bold = '<b>';
|
31 |
+
$boldclose = '</b>';
|
32 |
+
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
33 |
+
|
34 |
+
$msg = sprintf( __( 'If you are using premium themes by %1$s, just click Import Now button below. Alternatively, you can download zip files from the %2$s page of your theme and upload it as mentioned in Demo Import tab. As simple as that.', 'rara-one-click-demo-import' ), $link, $doc );
|
35 |
+
echo wp_kses(
|
36 |
+
apply_filters( 'rrdi_import_instruction', $msg ),
|
37 |
+
array(
|
38 |
+
'a' => array(
|
39 |
+
'href' => array(),
|
40 |
+
'target' => array(),
|
41 |
+
),
|
42 |
+
'b' => array(),
|
43 |
+
)
|
44 |
+
);
|
45 |
+
?>
|
46 |
+
</p>
|
47 |
+
|
48 |
+
<h3><?php esc_html_e( 'The following data will be imported:', 'rara-one-click-demo-import' ); ?></h3>
|
49 |
+
|
50 |
+
<ul>
|
51 |
+
<li><?php esc_html_e( 'Posts', 'rara-one-click-demo-import' ); ?></li>
|
52 |
+
<li><?php esc_html_e( 'Pages', 'rara-one-click-demo-import' ); ?></li>
|
53 |
+
<li><?php esc_html_e( 'Images', 'rara-one-click-demo-import' ); ?></li>
|
54 |
+
<li><?php esc_html_e( 'Widgets', 'rara-one-click-demo-import' ); ?></li>
|
55 |
+
<li><?php esc_html_e( 'Menus', 'rara-one-click-demo-import' ); ?></li>
|
56 |
+
<li><?php esc_html_e( 'Settings', 'rara-one-click-demo-import' ); ?></li>
|
57 |
+
</ul>
|
58 |
+
<?php
|
59 |
+
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
60 |
+
?>
|
61 |
+
<p><h4>
|
62 |
+
<?php
|
63 |
+
$msg = sprintf( __( 'Note: To import demo content for the free themes, please follow the step-by-step instructions mentioned in the %1$s Demo Import %2$s tab.', 'rara-one-click-demo-import' ), $bold, $boldclose );
|
64 |
+
echo wp_kses( apply_filters( 'rrdi_fresh_install_instruction', $msg ), array( 'b' => array() ) );
|
65 |
+
?>
|
66 |
+
</h4></p>
|
67 |
+
<p><h4>
|
68 |
+
<?php
|
69 |
+
echo wp_kses(
|
70 |
+
sprintf(
|
71 |
+
__( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ),
|
72 |
+
$wpreset
|
73 |
+
),
|
74 |
+
array(
|
75 |
+
'a' => array(
|
76 |
+
'href' => array(),
|
77 |
+
'target' => array(),
|
78 |
+
),
|
79 |
+
)
|
80 |
+
);
|
81 |
+
?>
|
82 |
+
</h4></p>
|
83 |
+
<hr>
|
84 |
+
|
85 |
+
</div>
|
86 |
+
|
87 |
+
<?php
|
88 |
+
$plugin_intro_text = ob_get_clean();
|
89 |
+
|
90 |
+
// Display the plugin intro text (can be replaced with custom text through the filter below).
|
91 |
+
echo wp_kses_post( apply_filters( 'rrdi/plugin_intro_text', $plugin_intro_text ) );
|
92 |
+
|
93 |
+
$my_theme = wp_get_theme();
|
94 |
+
$td = $my_theme->get( 'TextDomain' );
|
95 |
+
|
96 |
+
if ( strpos( $td, 'pro' ) === false && ! empty( $this->import_files ) ) {
|
97 |
+
?>
|
98 |
+
|
99 |
+
<div class="RRDI__file-upload-container">
|
100 |
+
<?php
|
101 |
+
$bold = '<b>';
|
102 |
+
$boldclose = '</b>';
|
103 |
+
?>
|
104 |
+
<br><h4 style="color:red">
|
105 |
+
<?php
|
106 |
+
echo wp_kses(
|
107 |
+
sprintf( __( 'Note: For free themes, always upload the appropriate demo zip file from %1$s Demo Import %2$s tab and import demo data as mentioned there.', 'rara-one-click-demo-import' ), $bold, $boldclose ),
|
108 |
+
array(
|
109 |
+
'a' => array(
|
110 |
+
'href' => array(),
|
111 |
+
'target' => array(),
|
112 |
+
),
|
113 |
+
'b' => array(),
|
114 |
+
)
|
115 |
+
);
|
116 |
+
?>
|
117 |
+
</h4>
|
118 |
+
</div>
|
119 |
+
<?php
|
120 |
+
}
|
121 |
+
|
122 |
+
// Check the folder contains at least 1 valid demo config.
|
123 |
+
$upload_dir = wp_upload_dir();
|
124 |
+
$path = $upload_dir['basedir'] . '/rara-demo-pack/';
|
125 |
+
$working_dir = getcwd();
|
126 |
+
chdir( $path ); // chdir to requested dir
|
127 |
+
$ret_val = false;
|
128 |
+
if ( $p = opendir( $path ) ) {
|
129 |
+
while ( false !== ( $file = readdir( $p ) ) ) {
|
130 |
+
if ( $file[0] != '.' && is_dir( $file ) ) {
|
131 |
+
$list[] = date( 'YmdHis', filemtime( $path . '/' . $file ) ) . $path . '/' . $file;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
if ( isset( $list ) ) {
|
135 |
+
rsort( $list );
|
136 |
+
$ret_val = $list[0];
|
137 |
+
}
|
138 |
+
}
|
139 |
+
chdir( $working_dir ); // chdir back to script's dir
|
140 |
+
|
141 |
+
$my_theme = wp_get_theme();
|
142 |
+
$td = $my_theme->get( 'TextDomain' );
|
143 |
+
|
144 |
+
$sr = explode( '/', $ret_val );
|
145 |
+
$sr = end( $sr );
|
146 |
+
|
147 |
+
if ( empty( $this->import_files ) ) :
|
148 |
+
?>
|
149 |
+
|
150 |
+
<?php elseif ( 1 < count( $this->import_files ) ) : ?>
|
151 |
+
|
152 |
+
<div class="RRDI__multi-select-import">
|
153 |
+
|
154 |
+
<h2><?php esc_html_e( 'Choose which demo you want to import:', 'rara-one-click-demo-import' ); ?></h2>
|
155 |
+
|
156 |
+
<select id="RRDI__demo-import-files" class="RRDI__demo-import-files">
|
157 |
+
<?php foreach ( $this->import_files as $index => $import_file ) : ?>
|
158 |
+
<option value="<?php echo esc_attr( $index ); ?>">
|
159 |
+
<?php echo esc_html( $import_file['import_file_name'] ); ?>
|
160 |
+
</option>
|
161 |
+
<?php endforeach; ?>
|
162 |
+
</select>
|
163 |
+
|
164 |
+
<?php
|
165 |
+
// Check if at least one preview image is defined, so we can prepare the structure for display.
|
166 |
+
$preview_image_is_defined = false;
|
167 |
+
foreach ( $this->import_files as $import_file ) {
|
168 |
+
if ( isset( $import_file['import_preview_image_url'] ) ) {
|
169 |
+
$preview_image_is_defined = true;
|
170 |
+
break;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
if ( $preview_image_is_defined ) :
|
175 |
+
?>
|
176 |
+
|
177 |
+
<div class="RRDI__demo-import-preview-container">
|
178 |
+
|
179 |
+
<p><?php esc_html_e( 'Import preview:', 'rara-one-click-demo-import' ); ?></p>
|
180 |
+
|
181 |
+
<p class="RRDI__demo-import-preview-image-message js-rrdi-preview-image-message">
|
182 |
+
<?php
|
183 |
+
if ( ! isset( $this->import_files[0]['import_preview_image_url'] ) ) {
|
184 |
+
esc_html_e( 'No preview image defined for this import.', 'rara-one-click-demo-import' );
|
185 |
+
}
|
186 |
+
// Leave the img tag below and the p tag above available for later changes via JS.
|
187 |
+
?>
|
188 |
+
</p>
|
189 |
+
|
190 |
+
<img id="RRDI__demo-import-preview-image" class="js-rrdi-preview-image" src="<?php echo ! empty( $this->import_files[0]['import_preview_image_url'] ) ? esc_url( $this->import_files[0]['import_preview_image_url'] ) : ''; ?>">
|
191 |
+
|
192 |
+
</div>
|
193 |
+
|
194 |
+
<?php endif; ?>
|
195 |
+
|
196 |
+
</div>
|
197 |
+
|
198 |
+
<?php
|
199 |
+
endif;
|
200 |
+
|
201 |
+
$upload_dir = wp_upload_dir();
|
202 |
+
|
203 |
+
$directory = $upload_dir['basedir'] . '/rara-demo-pack/';
|
204 |
+
|
205 |
+
// get all files in specified directory
|
206 |
+
$files = glob( $directory . '*', GLOB_ONLYDIR );
|
207 |
+
|
208 |
+
// print each file name
|
209 |
+
foreach ( $files as $file ) {
|
210 |
+
// check to see if the file is a folder/directory
|
211 |
+
if ( is_dir( $file ) ) {
|
212 |
+
$arr[] = basename( $file );
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
$my_theme = wp_get_theme();
|
217 |
+
|
218 |
+
if ( is_array( $this->import_files ) && ! empty( $this->import_files[0]['import_notice'] ) ) {
|
219 |
+
?>
|
220 |
+
<div class="RRDI__demo-import-notice js-rrdi-demo-import-notice">
|
221 |
+
<?php echo wp_kses_post( $this->import_files[0]['import_notice'] ); ?>
|
222 |
+
</div>
|
223 |
+
<?php
|
224 |
+
}
|
225 |
+
?>
|
226 |
+
|
227 |
+
<p class="RRDI__button-container">
|
228 |
+
<button class="RRDI__button button button-hero button-primary js-rrdi-import-data"><?php esc_html_e( 'Import Now', 'rara-one-click-demo-import' ); ?></button>
|
229 |
+
<span><?php esc_html_e( 'Click the button to begin the importing process. Please be patient, the process might take a few minutes.', 'rara-one-click-demo-import' ); ?></span>
|
230 |
+
</p>
|
231 |
+
|
232 |
+
<p class="RRDI__ajax-loader js-rrdi-ajax-loader">
|
233 |
+
<span class="spinner"></span> <?php esc_html_e( 'Importing now, please wait!', 'rara-one-click-demo-import' ); ?>
|
234 |
+
</p>
|
235 |
+
|
236 |
+
<div class="RRDI__response js-rrdi-ajax-response"></div>
|
237 |
+
</div>
|
includes/settings/intro.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
<?php
|
2 |
-
echo '<div class="rddi-import-intro">';
|
3 |
-
echo '<p>Demo Import works very well under normal circumstances. However, sometimes issues are seen which can be due to different reasons, mostly due to hosting issues. If you are using shared hosting plan, then there is high chance that demo import might not work on your server because your server might have some limitation.</p>';
|
4 |
-
|
5 |
-
echo '<p>For the demo import to work properly, the <b>PHP configuration</b> on your server should be:</p>';
|
6 |
-
echo '<ul>
|
7 |
-
<li>Maximum Execution Time <span>360</span></li>
|
8 |
-
<li>Memory Limit <span>256M</span></li>
|
9 |
-
<li>Post Max Size <span>32M</span></li>
|
10 |
-
<li>Upload Max Filesize <span>32M</span></li>
|
11 |
-
</ul>';
|
12 |
-
|
13 |
-
$link = '<a href="https://rarathemes.com/blog/best-wordpress-hosting/" target="_blank">10 best WordPress Hosting</a>';
|
14 |
-
|
15 |
-
echo '<p>' . sprintf( __( 'Please request your hosting to give you the above configuration and then try the demo import again. If you are constantly having an issue with the hosting, you may want to consider to move to better WordPress hosting. We have reviewed %1$s. If the issue is not fixed after the above configuration, please let us know for the further assistance.', 'rara-one-click-demo-import' ), esc_url( $link ) ) . '</p>';
|
16 |
-
|
17 |
-
$snapshot = '<a href="https://wordpress.org/plugins/wp-serverinfo/" target="_blank">WP Server Info</a>';
|
18 |
-
?>
|
19 |
-
<p><h4><?php echo sprintf( __( 'You can check the PHP configuartion of your site by using any plugins like %1$s.', 'rara-one-click-demo-import' ), esc_url( $snapshot ) ); ?></h4></p>
|
20 |
-
<?php
|
21 |
-
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
22 |
-
?>
|
23 |
-
<p><h4><?php echo sprintf( __( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ), esc_url( $wpreset ) ); ?></h4></p>
|
24 |
-
</div>
|
1 |
+
<?php
|
2 |
+
echo '<div class="rddi-import-intro">';
|
3 |
+
echo '<p>Demo Import works very well under normal circumstances. However, sometimes issues are seen which can be due to different reasons, mostly due to hosting issues. If you are using shared hosting plan, then there is high chance that demo import might not work on your server because your server might have some limitation.</p>';
|
4 |
+
|
5 |
+
echo '<p>For the demo import to work properly, the <b>PHP configuration</b> on your server should be:</p>';
|
6 |
+
echo '<ul>
|
7 |
+
<li>Maximum Execution Time <span>360</span></li>
|
8 |
+
<li>Memory Limit <span>256M</span></li>
|
9 |
+
<li>Post Max Size <span>32M</span></li>
|
10 |
+
<li>Upload Max Filesize <span>32M</span></li>
|
11 |
+
</ul>';
|
12 |
+
|
13 |
+
$link = '<a href="https://rarathemes.com/blog/best-wordpress-hosting/" target="_blank">10 best WordPress Hosting</a>';
|
14 |
+
|
15 |
+
echo '<p>' . sprintf( __( 'Please request your hosting to give you the above configuration and then try the demo import again. If you are constantly having an issue with the hosting, you may want to consider to move to better WordPress hosting. We have reviewed %1$s. If the issue is not fixed after the above configuration, please let us know for the further assistance.', 'rara-one-click-demo-import' ), esc_url( $link ) ) . '</p>';
|
16 |
+
|
17 |
+
$snapshot = '<a href="https://wordpress.org/plugins/wp-serverinfo/" target="_blank">WP Server Info</a>';
|
18 |
+
?>
|
19 |
+
<p><h4><?php echo sprintf( __( 'You can check the PHP configuartion of your site by using any plugins like %1$s.', 'rara-one-click-demo-import' ), esc_url( $snapshot ) ); ?></h4></p>
|
20 |
+
<?php
|
21 |
+
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
22 |
+
?>
|
23 |
+
<p><h4><?php echo sprintf( __( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ), esc_url( $wpreset ) ); ?></h4></p>
|
24 |
+
</div>
|
includes/settings/welcome.php
CHANGED
@@ -1,52 +1,52 @@
|
|
1 |
-
<div class="upload-theme">
|
2 |
-
<p class="install-help"><?php _e( 'If you have a demo pack in a .zip format, you may install it by uploading it here.', 'rara-one-click-demo-import' ); ?></p>
|
3 |
-
<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo esc_url( self_admin_url( 'themes.php?page=rara-demo-import&action=upload-demo' ) ); ?>">
|
4 |
-
<?php wp_nonce_field( 'demo-upload' ); ?>
|
5 |
-
<label class="screen-reader-text" for="demozip"><?php _e( 'Demo zip file', 'rara-one-click-demo-import' ); ?></label>
|
6 |
-
<input type="file" id="demozip" name="demozip" />
|
7 |
-
<?php submit_button( __( 'Install Now', 'rara-one-click-demo-import' ), 'button', 'install-demo-submit', false ); ?>
|
8 |
-
</form>
|
9 |
-
</div>
|
10 |
-
<ol>
|
11 |
-
<h3><?php _e( 'A Step-by-Step Guide to Import the Demo Content', 'rara-one-click-demo-import' ); ?></h3>
|
12 |
-
<li>
|
13 |
-
<?php
|
14 |
-
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
15 |
-
$doc = '<a href="https://rarathemes.com/documentation/" target="_blank">documentation</a>';
|
16 |
-
$support = '<a href="https://rarathemes.com/support-ticket/" target="_blank">contact our support team</a>';
|
17 |
-
echo wp_kses(
|
18 |
-
sprintf( __( 'Download the demo file from your theme %1$s page. If you are unable to download the demo file, please %2$s.', 'rara-one-click-demo-import' ), $doc, $support ),
|
19 |
-
array(
|
20 |
-
'a' => array(
|
21 |
-
'href' => array(),
|
22 |
-
'target' => array(),
|
23 |
-
),
|
24 |
-
)
|
25 |
-
);
|
26 |
-
?>
|
27 |
-
</li>
|
28 |
-
<li>
|
29 |
-
<?php
|
30 |
-
$link = '<a href="https://rarathemes.com/" target="_blank">Rara Theme</a>';
|
31 |
-
$demos = '<a href="https://rarathemes.com/" target="_blank">Theme Demos</a>';
|
32 |
-
$bold = '<b>';
|
33 |
-
$boldclose = '</b>';
|
34 |
-
echo wp_kses( sprintf( __( 'Click on the %1$sUpload Demo File%2$s button above.', 'rara-one-click-demo-import' ), $bold, $boldclose ), array( 'b' => array() ) );
|
35 |
-
?>
|
36 |
-
</li>
|
37 |
-
<li><?php echo wp_kses( sprintf( __( 'Click on %1$sChoose File%2$s button and upload the demo file downloaded in step 1. Then, click on the %3$sInstall Now%4$s button.', 'rara-one-click-demo-import' ), $bold, $boldclose, $bold, $boldclose ), array( 'b' => array() ) ); ?></li>
|
38 |
-
<li><?php echo wp_kses( sprintf( __( 'Click on the %1$sImport Demo Now!%2$s button to begin demo installation. It will take few minutes to successfully import the demo.', 'rara-one-click-demo-import' ), $bold, $boldclose ), array( 'b' => array() ) ); ?></li>
|
39 |
-
<h4>
|
40 |
-
<?php
|
41 |
-
echo wp_kses(
|
42 |
-
sprintf( __( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ), $wpreset ),
|
43 |
-
array(
|
44 |
-
'a' => array(
|
45 |
-
'href' => array(),
|
46 |
-
'target' => array(),
|
47 |
-
),
|
48 |
-
)
|
49 |
-
);
|
50 |
-
?>
|
51 |
-
</h4>
|
52 |
-
</ol>
|
1 |
+
<div class="upload-theme">
|
2 |
+
<p class="install-help"><?php _e( 'If you have a demo pack in a .zip format, you may install it by uploading it here.', 'rara-one-click-demo-import' ); ?></p>
|
3 |
+
<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo esc_url( self_admin_url( 'themes.php?page=rara-demo-import&action=upload-demo' ) ); ?>">
|
4 |
+
<?php wp_nonce_field( 'demo-upload' ); ?>
|
5 |
+
<label class="screen-reader-text" for="demozip"><?php _e( 'Demo zip file', 'rara-one-click-demo-import' ); ?></label>
|
6 |
+
<input type="file" id="demozip" name="demozip" />
|
7 |
+
<?php submit_button( __( 'Install Now', 'rara-one-click-demo-import' ), 'button', 'install-demo-submit', false ); ?>
|
8 |
+
</form>
|
9 |
+
</div>
|
10 |
+
<ol>
|
11 |
+
<h3><?php _e( 'A Step-by-Step Guide to Import the Demo Content', 'rara-one-click-demo-import' ); ?></h3>
|
12 |
+
<li>
|
13 |
+
<?php
|
14 |
+
$wpreset = '<a href="https://wordpress.org/plugins/wp-reset" target="_blank">WP Reset</a>';
|
15 |
+
$doc = '<a href="https://rarathemes.com/documentation/" target="_blank">documentation</a>';
|
16 |
+
$support = '<a href="https://rarathemes.com/support-ticket/" target="_blank">contact our support team</a>';
|
17 |
+
echo wp_kses(
|
18 |
+
sprintf( __( 'Download the demo file from your theme %1$s page. If you are unable to download the demo file, please %2$s.', 'rara-one-click-demo-import' ), $doc, $support ),
|
19 |
+
array(
|
20 |
+
'a' => array(
|
21 |
+
'href' => array(),
|
22 |
+
'target' => array(),
|
23 |
+
),
|
24 |
+
)
|
25 |
+
);
|
26 |
+
?>
|
27 |
+
</li>
|
28 |
+
<li>
|
29 |
+
<?php
|
30 |
+
$link = '<a href="https://rarathemes.com/" target="_blank">Rara Theme</a>';
|
31 |
+
$demos = '<a href="https://rarathemes.com/" target="_blank">Theme Demos</a>';
|
32 |
+
$bold = '<b>';
|
33 |
+
$boldclose = '</b>';
|
34 |
+
echo wp_kses( sprintf( __( 'Click on the %1$sUpload Demo File%2$s button above.', 'rara-one-click-demo-import' ), $bold, $boldclose ), array( 'b' => array() ) );
|
35 |
+
?>
|
36 |
+
</li>
|
37 |
+
<li><?php echo wp_kses( sprintf( __( 'Click on %1$sChoose File%2$s button and upload the demo file downloaded in step 1. Then, click on the %3$sInstall Now%4$s button.', 'rara-one-click-demo-import' ), $bold, $boldclose, $bold, $boldclose ), array( 'b' => array() ) ); ?></li>
|
38 |
+
<li><?php echo wp_kses( sprintf( __( 'Click on the %1$sImport Demo Now!%2$s button to begin demo installation. It will take few minutes to successfully import the demo.', 'rara-one-click-demo-import' ), $bold, $boldclose ), array( 'b' => array() ) ); ?></li>
|
39 |
+
<h4>
|
40 |
+
<?php
|
41 |
+
echo wp_kses(
|
42 |
+
sprintf( __( 'Note: We highly recommend to import the demo content on a fresh WordPress installation. You can reset your website to a fresh WordPress installation using a reset plugin like %1$s.', 'rara-one-click-demo-import' ), $wpreset ),
|
43 |
+
array(
|
44 |
+
'a' => array(
|
45 |
+
'href' => array(),
|
46 |
+
'target' => array(),
|
47 |
+
),
|
48 |
+
)
|
49 |
+
);
|
50 |
+
?>
|
51 |
+
</h4>
|
52 |
+
</ol>
|
includes/vendor/class-demo-installer-skin.php
CHANGED
@@ -1,64 +1,61 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Upgrader API: Plugin_Upgrader_Skin class
|
4 |
-
*
|
5 |
-
* Demo Installer Skin for the WordPress Demo Importer.
|
6 |
-
*
|
7 |
-
* @class RDDI_Demo_Installer_Skin
|
8 |
-
* @extends WP_Upgrader_Skin
|
9 |
-
* @version 1.0.0
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
$
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
}
|
63 |
-
}
|
64 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Upgrader API: Plugin_Upgrader_Skin class
|
4 |
+
*
|
5 |
+
* Demo Installer Skin for the WordPress Demo Importer.
|
6 |
+
*
|
7 |
+
* @class RDDI_Demo_Installer_Skin
|
8 |
+
* @extends WP_Upgrader_Skin
|
9 |
+
* @version 1.0.0
|
10 |
+
*/
|
11 |
+
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
+
exit;
|
14 |
+
}
|
15 |
+
|
16 |
+
/**
|
17 |
+
* RDDI_Demo_Installer_Skin Class.
|
18 |
+
*/
|
19 |
+
class RDDI_Demo_Installer_Skin extends WP_Upgrader_Skin {
|
20 |
+
public $type;
|
21 |
+
|
22 |
+
/**
|
23 |
+
*
|
24 |
+
* @param array $args
|
25 |
+
*/
|
26 |
+
public function __construct( $args = array() ) {
|
27 |
+
$defaults = array( 'type' => 'web', 'url' => '', 'demo' => '', 'nonce' => '', 'title' => '' );
|
28 |
+
$args = wp_parse_args( $args, $defaults );
|
29 |
+
|
30 |
+
$this->type = $args['type'];
|
31 |
+
|
32 |
+
parent::__construct( $args );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @access public
|
37 |
+
*/
|
38 |
+
public function after() {
|
39 |
+
$install_actions = array();
|
40 |
+
|
41 |
+
$from = isset( $_GET['from'] ) ? wp_unslash( $_GET['from'] ) : 'demos';
|
42 |
+
|
43 |
+
if ( 'web' == $this->type ) {
|
44 |
+
$install_actions['demos_page'] = '<a class="demo-importer" href="' . admin_url( 'themes.php?page=rara-demo-import&browse=uploads' ) . '" target="_parent">' . __( 'Return to Demo Importer', 'rara-one-click-demo-import' ) . '</a>';
|
45 |
+
} elseif ( 'upload' == $this->type && 'demos' == $from ) {
|
46 |
+
$install_actions['demos_page'] = '<a class="demo-importer" href="' . admin_url( 'themes.php?page=rara-demo-import&browse=uploads' ) . '">' . __( 'Return to Demo Importer', 'rara-one-click-demo-import' ) . '</a>';
|
47 |
+
} else {
|
48 |
+
$install_actions['demos_page'] = '<a class="demo-importer" href="' . admin_url( 'themes.php?page=rara-demo-import&browse=uploads' ) . '" target="_parent">' . __( 'Return to Demos page', 'rara-one-click-demo-import' ) . '</a>';
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Filters the list of action links available following a single demo installation.
|
53 |
+
* @param array $install_actions Array of demo action links.
|
54 |
+
*/
|
55 |
+
$install_actions = apply_filters_deprecated( 'themegrill_demo_install_complete_actions', array( $install_actions ), '1.3.1', 'rrdi_demo_install_complete_actions' );
|
56 |
+
|
57 |
+
if ( ! empty( $install_actions ) ) {
|
58 |
+
$this->feedback( implode( ' | ', (array) $install_actions ) );
|
59 |
+
}
|
60 |
+
}
|
61 |
+
}
|
|
|
|
|
|
includes/vendor/class-demo-upgrader.php
CHANGED
@@ -1,353 +1,353 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Upgrade API: RDDI_Demo_Upgrader class
|
4 |
-
*
|
5 |
-
* Core class used for upgrading/installing demos.
|
6 |
-
*
|
7 |
-
* It is designed to upgrade/install demo from a local zip, remote zip URL,
|
8 |
-
* or uploaded zip file.
|
9 |
-
*
|
10 |
-
* @see WP_Upgrader
|
11 |
-
*/
|
12 |
-
class RDDI_Demo_Upgrader extends WP_Upgrader {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Result of the demo upgrade offer.
|
16 |
-
*
|
17 |
-
* @since 2.8.0
|
18 |
-
* @access public
|
19 |
-
* @var array|WP_Error $result
|
20 |
-
* @see WP_Upgrader::$result
|
21 |
-
*/
|
22 |
-
public $result;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Whether multiple demos are being upgraded/installed in bulk.
|
26 |
-
*
|
27 |
-
* @since 2.9.0
|
28 |
-
* @access public
|
29 |
-
* @var bool $bulk
|
30 |
-
*/
|
31 |
-
public $bulk = false;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Initialize the install strings.
|
35 |
-
*
|
36 |
-
* @since 2.8.0
|
37 |
-
* @access public
|
38 |
-
*/
|
39 |
-
public function install_strings() {
|
40 |
-
$this->strings['no_package'] = __( 'Install package not available.', 'rara-one-click-demo-import' );
|
41 |
-
$this->strings['downloading_package'] = __( '', 'rara-one-click-demo-import' );
|
42 |
-
$this->strings['unpack_package'] = __( '', 'rara-one-click-demo-import' );
|
43 |
-
$this->strings['remove_old'] = __( '', 'rara-one-click-demo-import' );
|
44 |
-
$this->strings['remove_old_failed'] = __( '', 'rara-one-click-demo-import' );
|
45 |
-
$this->strings['installing_package'] = __( '', 'rara-one-click-demo-import' );
|
46 |
-
$this->strings['no_files'] = __( 'The demo contains no files.', 'rara-one-click-demo-import' );
|
47 |
-
$this->strings['process_failed'] = __( '', 'rara-one-click-demo-import' );
|
48 |
-
$bold = '<b>';
|
49 |
-
$boldclose = '</b>';
|
50 |
-
$this->strings['process_success'] = __( 'Click the button below to begin the import process.' , 'rara-one-click-demo-import' ).'<p class="RRDI__ajax-loader js-rrdi-ajax-loader"><span class="spinner"></span>'.'</p><button class="RRDI__button button button-hero button-primary js-rrdi-import-data">'.__('Import Demo Now!','rara-one-click-demo-import').'</button><div class="RRDI__response js-rrdi-ajax-response"></div>'.'<p><a class="home-page-url" target="_blank" href="'.esc_url( home_url( '/' ) ).'">Check the front page</a>';
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Install a demo package.
|
55 |
-
*
|
56 |
-
* @since 2.8.0
|
57 |
-
* @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional.
|
58 |
-
* @access public
|
59 |
-
*
|
60 |
-
* @param string $package The full local path or URI of the package.
|
61 |
-
* @param array $args {
|
62 |
-
* Optional. Other arguments for installing a demo package. Default empty array.
|
63 |
-
*
|
64 |
-
* @type bool $clear_update_cache Whether to clear the updates cache if successful.
|
65 |
-
* Default true.
|
66 |
-
* }
|
67 |
-
*
|
68 |
-
* @return bool|WP_Error True if the install was successful, false or a WP_Error object otherwise.
|
69 |
-
*/
|
70 |
-
public function install( $package, $args = array() ) {
|
71 |
-
$upload_dir = wp_upload_dir();
|
72 |
-
|
73 |
-
$defaults = array(
|
74 |
-
'clear_update_cache' => true,
|
75 |
-
);
|
76 |
-
$parsed_args = wp_parse_args( $args, $defaults );
|
77 |
-
|
78 |
-
$this->init();
|
79 |
-
$this->install_strings();
|
80 |
-
add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
|
81 |
-
|
82 |
-
$this->run( array(
|
83 |
-
'package' => $package,
|
84 |
-
'destination' => $upload_dir['basedir'] . '/rara-demo-pack',
|
85 |
-
'clear_destination' => true, // Do overwrite files.
|
86 |
-
'protect_destination' => true,
|
87 |
-
'clear_working' => true,
|
88 |
-
'hook_extra' => array(
|
89 |
-
'type' => 'demo',
|
90 |
-
'action' => 'install',
|
91 |
-
),
|
92 |
-
) );
|
93 |
-
|
94 |
-
remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
|
95 |
-
|
96 |
-
if ( ! $this->result || is_wp_error( $this->result ) ) {
|
97 |
-
return $this->result;
|
98 |
-
}
|
99 |
-
|
100 |
-
return true;
|
101 |
-
}
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Check that the package source contains a valid demo.
|
105 |
-
*
|
106 |
-
* Hooked to the {@see 'upgrader_source_selection'} filter by RDDI_Demo_Upgrader::install().
|
107 |
-
* It will return an error if the demo doesn't have rara-demo-config.php
|
108 |
-
* files.
|
109 |
-
*
|
110 |
-
* @since 3.3.0
|
111 |
-
* @access public
|
112 |
-
*
|
113 |
-
* @global WP_Filesystem_Base $wp_filesystem Subclass
|
114 |
-
* @global array $wp_theme_directories
|
115 |
-
*
|
116 |
-
* @param string $source The full path to the package source.
|
117 |
-
* @return string|WP_Error The source or a WP_Error.
|
118 |
-
*/
|
119 |
-
public function check_package( $source ) {
|
120 |
-
global $wp_filesystem, $wp_theme_directories;
|
121 |
-
|
122 |
-
|
123 |
-
if ( is_wp_error( $source ) )
|
124 |
-
return $source;
|
125 |
-
// Check the folder contains a valid demo.
|
126 |
-
$working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source );
|
127 |
-
|
128 |
-
if ( ! is_dir( $working_directory ) ) // Sanity check, if the above fails, let's not prevent installation.
|
129 |
-
return $source;
|
130 |
-
|
131 |
-
// A proper archive should have a rara-demo-config.php file in the single subdirectory
|
132 |
-
if ( ! file_exists( $working_directory . 'import-hooks.php' ) ) {
|
133 |
-
return new WP_Error( 'incompatible_archive_no_demos', $this->strings['incompatible_archive'], __( 'No valid demos were found.', 'rara-one-click-demo-import' ) );
|
134 |
-
}
|
135 |
-
|
136 |
-
return $source;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Install a package.
|
141 |
-
*
|
142 |
-
* Copies the contents of a package form a source directory, and installs them in
|
143 |
-
* a destination directory. Optionally removes the source. It can also optionally
|
144 |
-
* clear out the destination folder if it already exists.
|
145 |
-
*
|
146 |
-
* Stuck with this until a fix for https://core.trac.wordpress.org/ticket/38946.
|
147 |
-
* We use a custom upgrader, just like WordPress does.
|
148 |
-
*
|
149 |
-
* @since 2.8.0
|
150 |
-
* @access public
|
151 |
-
*
|
152 |
-
* @global WP_Filesystem_Base $wp_filesystem Subclass
|
153 |
-
* @global array $wp_theme_directories
|
154 |
-
*
|
155 |
-
* @param array|string $args {
|
156 |
-
* Optional. Array or string of arguments for installing a package. Default empty array.
|
157 |
-
*
|
158 |
-
* @type string $source Required path to the package source. Default empty.
|
159 |
-
* @type string $destination Required path to a folder to install the package in.
|
160 |
-
* Default empty.
|
161 |
-
* @type bool $clear_destination Whether to delete any files already in the destination
|
162 |
-
* folder. Default false.
|
163 |
-
* @type bool $clear_working Whether to delete the files from the working directory
|
164 |
-
* after copying to the destination. Default false.
|
165 |
-
* @type bool $protect_destination Whether to protect against deleting any files already
|
166 |
-
* in the destination folder. Default false.
|
167 |
-
* @type bool $abort_if_destination_exists Whether to abort the installation if
|
168 |
-
* the destination folder already exists. Default true.
|
169 |
-
* @type array $hook_extra Extra arguments to pass to the filter hooks called by
|
170 |
-
* WP_Upgrader::install_package(). Default empty array.
|
171 |
-
* }
|
172 |
-
*
|
173 |
-
* @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure.
|
174 |
-
*/
|
175 |
-
public function install_package( $args = array() ) {
|
176 |
-
global $wp_filesystem, $wp_theme_directories;
|
177 |
-
|
178 |
-
$defaults = array(
|
179 |
-
'source' => '', // Please always pass this
|
180 |
-
'destination' => '', // and this
|
181 |
-
'clear_destination' => false,
|
182 |
-
'clear_working' => false,
|
183 |
-
'protect_destination' => true, // If fixed in core then it will be false :)
|
184 |
-
'abort_if_destination_exists' => true,
|
185 |
-
'hook_extra' => array(),
|
186 |
-
);
|
187 |
-
|
188 |
-
$args = wp_parse_args( $args, $defaults );
|
189 |
-
|
190 |
-
// These were previously extract()'d.
|
191 |
-
$source = $args['source'];
|
192 |
-
$destination = $args['destination'];
|
193 |
-
$clear_destination = $args['clear_destination'];
|
194 |
-
|
195 |
-
@set_time_limit( 300 );
|
196 |
-
|
197 |
-
if ( empty( $source ) || empty( $destination ) ) {
|
198 |
-
return new WP_Error( 'bad_request', $this->strings['bad_request'] );
|
199 |
-
}
|
200 |
-
$this->skin->feedback( 'installing_package' );
|
201 |
-
|
202 |
-
/**
|
203 |
-
* Filters the install response before the installation has started.
|
204 |
-
*
|
205 |
-
* Returning a truthy value, or one that could be evaluated as a WP_Error
|
206 |
-
* will effectively short-circuit the installation, returning that value
|
207 |
-
* instead.
|
208 |
-
*
|
209 |
-
* @since 2.8.0
|
210 |
-
*
|
211 |
-
* @param bool|WP_Error $response Response.
|
212 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
213 |
-
*/
|
214 |
-
$res = apply_filters( 'upgrader_pre_install', true, $args['hook_extra'] );
|
215 |
-
|
216 |
-
if ( is_wp_error( $res ) ) {
|
217 |
-
return $res;
|
218 |
-
}
|
219 |
-
|
220 |
-
// Retain the Original source and destinations
|
221 |
-
$remote_source = $args['source'];
|
222 |
-
$local_destination = $destination;
|
223 |
-
|
224 |
-
$source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) );
|
225 |
-
$remote_destination = $wp_filesystem->find_folder( $local_destination );
|
226 |
-
|
227 |
-
// Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
|
228 |
-
if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { // Only one folder? Then we want its contents.
|
229 |
-
$source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] );
|
230 |
-
} elseif ( count( $source_files ) == 0 ) {
|
231 |
-
return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
|
232 |
-
} else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename.
|
233 |
-
$source = trailingslashit( $args['source'] );
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Filters the source file location for the upgrade package.
|
238 |
-
*
|
239 |
-
* @since 2.8.0
|
240 |
-
* @since 4.4.0 The $hook_extra parameter became available.
|
241 |
-
*
|
242 |
-
* @param string $source File source location.
|
243 |
-
* @param string $remote_source Remote file source location.
|
244 |
-
* @param WP_Upgrader $this WP_Upgrader instance.
|
245 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
246 |
-
*/
|
247 |
-
$source = apply_filters( 'upgrader_source_selection', $source, $remote_source, $this, $args['hook_extra'] );
|
248 |
-
|
249 |
-
if ( is_wp_error( $source ) ) {
|
250 |
-
return $source;
|
251 |
-
}
|
252 |
-
|
253 |
-
// Has the source location changed? If so, we need a new source_files list.
|
254 |
-
if ( $source !== $remote_source ) {
|
255 |
-
$source_files = array_keys( $wp_filesystem->dirlist( $source ) );
|
256 |
-
}
|
257 |
-
|
258 |
-
/*
|
259 |
-
* Protection against deleting files in any important base directories.
|
260 |
-
* Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the
|
261 |
-
* destination directory (WP_PLUGIN_DIR / wp-content/themes) intending
|
262 |
-
* to copy the directory into the directory, whilst they pass the source
|
263 |
-
* as the actual files to copy.
|
264 |
-
*/
|
265 |
-
$protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' );
|
266 |
-
|
267 |
-
if ( is_array( $wp_theme_directories ) ) {
|
268 |
-
$protected_directories = array_merge( $protected_directories, $wp_theme_directories );
|
269 |
-
}
|
270 |
-
|
271 |
-
if ( in_array( $destination, $protected_directories ) || $args['protect_destination'] ) {
|
272 |
-
$remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) );
|
273 |
-
$destination = trailingslashit( $destination ) . trailingslashit( basename( $source ) );
|
274 |
-
}
|
275 |
-
|
276 |
-
if ( $clear_destination ) {
|
277 |
-
// We're going to clear the destination if there's something there.
|
278 |
-
$this->skin->feedback( 'remove_old' );
|
279 |
-
|
280 |
-
$removed = $this->clear_destination( $remote_destination );
|
281 |
-
|
282 |
-
/**
|
283 |
-
* Filters whether the upgrader cleared the destination.
|
284 |
-
*
|
285 |
-
* @since 2.8.0
|
286 |
-
*
|
287 |
-
* @param mixed $removed Whether the destination was cleared. true on success, WP_Error on failure
|
288 |
-
* @param string $local_destination The local package destination.
|
289 |
-
* @param string $remote_destination The remote package destination.
|
290 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
291 |
-
*/
|
292 |
-
$removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
|
293 |
-
|
294 |
-
if ( is_wp_error( $removed ) ) {
|
295 |
-
return $removed;
|
296 |
-
}
|
297 |
-
} elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists( $remote_destination ) ) {
|
298 |
-
// If we're not clearing the destination folder and something exists there already, Bail.
|
299 |
-
// But first check to see if there are actually any files in the folder.
|
300 |
-
$_files = $wp_filesystem->dirlist( $remote_destination );
|
301 |
-
if ( ! empty( $_files ) ) {
|
302 |
-
$wp_filesystem->delete( $remote_source, true ); // Clear out the source files.
|
303 |
-
return new WP_Error( 'folder_exists', $this->strings['folder_exists'], $remote_destination );
|
304 |
-
}
|
305 |
-
}
|
306 |
-
|
307 |
-
// Create destination if needed
|
308 |
-
if ( ! $wp_filesystem->exists( $remote_destination ) ) {
|
309 |
-
if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) {
|
310 |
-
return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
|
311 |
-
}
|
312 |
-
}
|
313 |
-
// Copy new version of item into place.
|
314 |
-
$result = copy_dir( $source, $remote_destination );
|
315 |
-
if ( is_wp_error( $result ) ) {
|
316 |
-
if ( $args['clear_working'] ) {
|
317 |
-
$wp_filesystem->delete( $remote_source, true );
|
318 |
-
}
|
319 |
-
return $result;
|
320 |
-
}
|
321 |
-
|
322 |
-
// Clear the Working folder?
|
323 |
-
if ( $args['clear_working'] ) {
|
324 |
-
$wp_filesystem->delete( $remote_source, true );
|
325 |
-
}
|
326 |
-
|
327 |
-
$destination_name = basename( str_replace( $local_destination, '', $destination ) );
|
328 |
-
if ( '.' == $destination_name ) {
|
329 |
-
$destination_name = '';
|
330 |
-
}
|
331 |
-
|
332 |
-
$this->result = compact( 'source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination' );
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Filters the install response after the installation has finished.
|
336 |
-
*
|
337 |
-
* @since 2.8.0
|
338 |
-
*
|
339 |
-
* @param bool $response Install response.
|
340 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
341 |
-
* @param array $result Installation result data.
|
342 |
-
*/
|
343 |
-
$res = apply_filters( 'upgrader_post_install', true, $args['hook_extra'], $this->result );
|
344 |
-
|
345 |
-
if ( is_wp_error( $res ) ) {
|
346 |
-
$this->result = $res;
|
347 |
-
return $res;
|
348 |
-
}
|
349 |
-
|
350 |
-
// Bombard the calling function will all the info which we've just used.
|
351 |
-
return $this->result;
|
352 |
-
}
|
353 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Upgrade API: RDDI_Demo_Upgrader class
|
4 |
+
*
|
5 |
+
* Core class used for upgrading/installing demos.
|
6 |
+
*
|
7 |
+
* It is designed to upgrade/install demo from a local zip, remote zip URL,
|
8 |
+
* or uploaded zip file.
|
9 |
+
*
|
10 |
+
* @see WP_Upgrader
|
11 |
+
*/
|
12 |
+
class RDDI_Demo_Upgrader extends WP_Upgrader {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Result of the demo upgrade offer.
|
16 |
+
*
|
17 |
+
* @since 2.8.0
|
18 |
+
* @access public
|
19 |
+
* @var array|WP_Error $result
|
20 |
+
* @see WP_Upgrader::$result
|
21 |
+
*/
|
22 |
+
public $result;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Whether multiple demos are being upgraded/installed in bulk.
|
26 |
+
*
|
27 |
+
* @since 2.9.0
|
28 |
+
* @access public
|
29 |
+
* @var bool $bulk
|
30 |
+
*/
|
31 |
+
public $bulk = false;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Initialize the install strings.
|
35 |
+
*
|
36 |
+
* @since 2.8.0
|
37 |
+
* @access public
|
38 |
+
*/
|
39 |
+
public function install_strings() {
|
40 |
+
$this->strings['no_package'] = __( 'Install package not available.', 'rara-one-click-demo-import' );
|
41 |
+
$this->strings['downloading_package'] = __( '', 'rara-one-click-demo-import' );
|
42 |
+
$this->strings['unpack_package'] = __( '', 'rara-one-click-demo-import' );
|
43 |
+
$this->strings['remove_old'] = __( '', 'rara-one-click-demo-import' );
|
44 |
+
$this->strings['remove_old_failed'] = __( '', 'rara-one-click-demo-import' );
|
45 |
+
$this->strings['installing_package'] = __( '', 'rara-one-click-demo-import' );
|
46 |
+
$this->strings['no_files'] = __( 'The demo contains no files.', 'rara-one-click-demo-import' );
|
47 |
+
$this->strings['process_failed'] = __( '', 'rara-one-click-demo-import' );
|
48 |
+
$bold = '<b>';
|
49 |
+
$boldclose = '</b>';
|
50 |
+
$this->strings['process_success'] = __( 'Click the button below to begin the import process.' , 'rara-one-click-demo-import' ).'<p class="RRDI__ajax-loader js-rrdi-ajax-loader"><span class="spinner"></span>'.'</p><button class="RRDI__button button button-hero button-primary js-rrdi-import-data">'.__('Import Demo Now!','rara-one-click-demo-import').'</button><div class="RRDI__response js-rrdi-ajax-response"></div>'.'<p><a class="home-page-url" target="_blank" href="'.esc_url( home_url( '/' ) ).'">Check the front page</a>';
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Install a demo package.
|
55 |
+
*
|
56 |
+
* @since 2.8.0
|
57 |
+
* @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional.
|
58 |
+
* @access public
|
59 |
+
*
|
60 |
+
* @param string $package The full local path or URI of the package.
|
61 |
+
* @param array $args {
|
62 |
+
* Optional. Other arguments for installing a demo package. Default empty array.
|
63 |
+
*
|
64 |
+
* @type bool $clear_update_cache Whether to clear the updates cache if successful.
|
65 |
+
* Default true.
|
66 |
+
* }
|
67 |
+
*
|
68 |
+
* @return bool|WP_Error True if the install was successful, false or a WP_Error object otherwise.
|
69 |
+
*/
|
70 |
+
public function install( $package, $args = array() ) {
|
71 |
+
$upload_dir = wp_upload_dir();
|
72 |
+
|
73 |
+
$defaults = array(
|
74 |
+
'clear_update_cache' => true,
|
75 |
+
);
|
76 |
+
$parsed_args = wp_parse_args( $args, $defaults );
|
77 |
+
|
78 |
+
$this->init();
|
79 |
+
$this->install_strings();
|
80 |
+
add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
|
81 |
+
|
82 |
+
$this->run( array(
|
83 |
+
'package' => $package,
|
84 |
+
'destination' => $upload_dir['basedir'] . '/rara-demo-pack',
|
85 |
+
'clear_destination' => true, // Do overwrite files.
|
86 |
+
'protect_destination' => true,
|
87 |
+
'clear_working' => true,
|
88 |
+
'hook_extra' => array(
|
89 |
+
'type' => 'demo',
|
90 |
+
'action' => 'install',
|
91 |
+
),
|
92 |
+
) );
|
93 |
+
|
94 |
+
remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
|
95 |
+
|
96 |
+
if ( ! $this->result || is_wp_error( $this->result ) ) {
|
97 |
+
return $this->result;
|
98 |
+
}
|
99 |
+
|
100 |
+
return true;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Check that the package source contains a valid demo.
|
105 |
+
*
|
106 |
+
* Hooked to the {@see 'upgrader_source_selection'} filter by RDDI_Demo_Upgrader::install().
|
107 |
+
* It will return an error if the demo doesn't have rara-demo-config.php
|
108 |
+
* files.
|
109 |
+
*
|
110 |
+
* @since 3.3.0
|
111 |
+
* @access public
|
112 |
+
*
|
113 |
+
* @global WP_Filesystem_Base $wp_filesystem Subclass
|
114 |
+
* @global array $wp_theme_directories
|
115 |
+
*
|
116 |
+
* @param string $source The full path to the package source.
|
117 |
+
* @return string|WP_Error The source or a WP_Error.
|
118 |
+
*/
|
119 |
+
public function check_package( $source ) {
|
120 |
+
global $wp_filesystem, $wp_theme_directories;
|
121 |
+
|
122 |
+
|
123 |
+
if ( is_wp_error( $source ) )
|
124 |
+
return $source;
|
125 |
+
// Check the folder contains a valid demo.
|
126 |
+
$working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source );
|
127 |
+
|
128 |
+
if ( ! is_dir( $working_directory ) ) // Sanity check, if the above fails, let's not prevent installation.
|
129 |
+
return $source;
|
130 |
+
|
131 |
+
// A proper archive should have a rara-demo-config.php file in the single subdirectory
|
132 |
+
if ( ! file_exists( $working_directory . 'import-hooks.php' ) ) {
|
133 |
+
return new WP_Error( 'incompatible_archive_no_demos', $this->strings['incompatible_archive'], __( 'No valid demos were found.', 'rara-one-click-demo-import' ) );
|
134 |
+
}
|
135 |
+
|
136 |
+
return $source;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Install a package.
|
141 |
+
*
|
142 |
+
* Copies the contents of a package form a source directory, and installs them in
|
143 |
+
* a destination directory. Optionally removes the source. It can also optionally
|
144 |
+
* clear out the destination folder if it already exists.
|
145 |
+
*
|
146 |
+
* Stuck with this until a fix for https://core.trac.wordpress.org/ticket/38946.
|
147 |
+
* We use a custom upgrader, just like WordPress does.
|
148 |
+
*
|
149 |
+
* @since 2.8.0
|
150 |
+
* @access public
|
151 |
+
*
|
152 |
+
* @global WP_Filesystem_Base $wp_filesystem Subclass
|
153 |
+
* @global array $wp_theme_directories
|
154 |
+
*
|
155 |
+
* @param array|string $args {
|
156 |
+
* Optional. Array or string of arguments for installing a package. Default empty array.
|
157 |
+
*
|
158 |
+
* @type string $source Required path to the package source. Default empty.
|
159 |
+
* @type string $destination Required path to a folder to install the package in.
|
160 |
+
* Default empty.
|
161 |
+
* @type bool $clear_destination Whether to delete any files already in the destination
|
162 |
+
* folder. Default false.
|
163 |
+
* @type bool $clear_working Whether to delete the files from the working directory
|
164 |
+
* after copying to the destination. Default false.
|
165 |
+
* @type bool $protect_destination Whether to protect against deleting any files already
|
166 |
+
* in the destination folder. Default false.
|
167 |
+
* @type bool $abort_if_destination_exists Whether to abort the installation if
|
168 |
+
* the destination folder already exists. Default true.
|
169 |
+
* @type array $hook_extra Extra arguments to pass to the filter hooks called by
|
170 |
+
* WP_Upgrader::install_package(). Default empty array.
|
171 |
+
* }
|
172 |
+
*
|
173 |
+
* @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure.
|
174 |
+
*/
|
175 |
+
public function install_package( $args = array() ) {
|
176 |
+
global $wp_filesystem, $wp_theme_directories;
|
177 |
+
|
178 |
+
$defaults = array(
|
179 |
+
'source' => '', // Please always pass this
|
180 |
+
'destination' => '', // and this
|
181 |
+
'clear_destination' => false,
|
182 |
+
'clear_working' => false,
|
183 |
+
'protect_destination' => true, // If fixed in core then it will be false :)
|
184 |
+
'abort_if_destination_exists' => true,
|
185 |
+
'hook_extra' => array(),
|
186 |
+
);
|
187 |
+
|
188 |
+
$args = wp_parse_args( $args, $defaults );
|
189 |
+
|
190 |
+
// These were previously extract()'d.
|
191 |
+
$source = $args['source'];
|
192 |
+
$destination = $args['destination'];
|
193 |
+
$clear_destination = $args['clear_destination'];
|
194 |
+
|
195 |
+
@set_time_limit( 300 );
|
196 |
+
|
197 |
+
if ( empty( $source ) || empty( $destination ) ) {
|
198 |
+
return new WP_Error( 'bad_request', $this->strings['bad_request'] );
|
199 |
+
}
|
200 |
+
$this->skin->feedback( 'installing_package' );
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Filters the install response before the installation has started.
|
204 |
+
*
|
205 |
+
* Returning a truthy value, or one that could be evaluated as a WP_Error
|
206 |
+
* will effectively short-circuit the installation, returning that value
|
207 |
+
* instead.
|
208 |
+
*
|
209 |
+
* @since 2.8.0
|
210 |
+
*
|
211 |
+
* @param bool|WP_Error $response Response.
|
212 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
213 |
+
*/
|
214 |
+
$res = apply_filters( 'upgrader_pre_install', true, $args['hook_extra'] );
|
215 |
+
|
216 |
+
if ( is_wp_error( $res ) ) {
|
217 |
+
return $res;
|
218 |
+
}
|
219 |
+
|
220 |
+
// Retain the Original source and destinations
|
221 |
+
$remote_source = $args['source'];
|
222 |
+
$local_destination = $destination;
|
223 |
+
|
224 |
+
$source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) );
|
225 |
+
$remote_destination = $wp_filesystem->find_folder( $local_destination );
|
226 |
+
|
227 |
+
// Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
|
228 |
+
if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { // Only one folder? Then we want its contents.
|
229 |
+
$source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] );
|
230 |
+
} elseif ( count( $source_files ) == 0 ) {
|
231 |
+
return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
|
232 |
+
} else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename.
|
233 |
+
$source = trailingslashit( $args['source'] );
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Filters the source file location for the upgrade package.
|
238 |
+
*
|
239 |
+
* @since 2.8.0
|
240 |
+
* @since 4.4.0 The $hook_extra parameter became available.
|
241 |
+
*
|
242 |
+
* @param string $source File source location.
|
243 |
+
* @param string $remote_source Remote file source location.
|
244 |
+
* @param WP_Upgrader $this WP_Upgrader instance.
|
245 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
246 |
+
*/
|
247 |
+
$source = apply_filters( 'upgrader_source_selection', $source, $remote_source, $this, $args['hook_extra'] );
|
248 |
+
|
249 |
+
if ( is_wp_error( $source ) ) {
|
250 |
+
return $source;
|
251 |
+
}
|
252 |
+
|
253 |
+
// Has the source location changed? If so, we need a new source_files list.
|
254 |
+
if ( $source !== $remote_source ) {
|
255 |
+
$source_files = array_keys( $wp_filesystem->dirlist( $source ) );
|
256 |
+
}
|
257 |
+
|
258 |
+
/*
|
259 |
+
* Protection against deleting files in any important base directories.
|
260 |
+
* Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the
|
261 |
+
* destination directory (WP_PLUGIN_DIR / wp-content/themes) intending
|
262 |
+
* to copy the directory into the directory, whilst they pass the source
|
263 |
+
* as the actual files to copy.
|
264 |
+
*/
|
265 |
+
$protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' );
|
266 |
+
|
267 |
+
if ( is_array( $wp_theme_directories ) ) {
|
268 |
+
$protected_directories = array_merge( $protected_directories, $wp_theme_directories );
|
269 |
+
}
|
270 |
+
|
271 |
+
if ( in_array( $destination, $protected_directories ) || $args['protect_destination'] ) {
|
272 |
+
$remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) );
|
273 |
+
$destination = trailingslashit( $destination ) . trailingslashit( basename( $source ) );
|
274 |
+
}
|
275 |
+
|
276 |
+
if ( $clear_destination ) {
|
277 |
+
// We're going to clear the destination if there's something there.
|
278 |
+
$this->skin->feedback( 'remove_old' );
|
279 |
+
|
280 |
+
$removed = $this->clear_destination( $remote_destination );
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Filters whether the upgrader cleared the destination.
|
284 |
+
*
|
285 |
+
* @since 2.8.0
|
286 |
+
*
|
287 |
+
* @param mixed $removed Whether the destination was cleared. true on success, WP_Error on failure
|
288 |
+
* @param string $local_destination The local package destination.
|
289 |
+
* @param string $remote_destination The remote package destination.
|
290 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
291 |
+
*/
|
292 |
+
$removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
|
293 |
+
|
294 |
+
if ( is_wp_error( $removed ) ) {
|
295 |
+
return $removed;
|
296 |
+
}
|
297 |
+
} elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists( $remote_destination ) ) {
|
298 |
+
// If we're not clearing the destination folder and something exists there already, Bail.
|
299 |
+
// But first check to see if there are actually any files in the folder.
|
300 |
+
$_files = $wp_filesystem->dirlist( $remote_destination );
|
301 |
+
if ( ! empty( $_files ) ) {
|
302 |
+
$wp_filesystem->delete( $remote_source, true ); // Clear out the source files.
|
303 |
+
return new WP_Error( 'folder_exists', $this->strings['folder_exists'], $remote_destination );
|
304 |
+
}
|
305 |
+
}
|
306 |
+
|
307 |
+
// Create destination if needed
|
308 |
+
if ( ! $wp_filesystem->exists( $remote_destination ) ) {
|
309 |
+
if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) {
|
310 |
+
return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
|
311 |
+
}
|
312 |
+
}
|
313 |
+
// Copy new version of item into place.
|
314 |
+
$result = copy_dir( $source, $remote_destination );
|
315 |
+
if ( is_wp_error( $result ) ) {
|
316 |
+
if ( $args['clear_working'] ) {
|
317 |
+
$wp_filesystem->delete( $remote_source, true );
|
318 |
+
}
|
319 |
+
return $result;
|
320 |
+
}
|
321 |
+
|
322 |
+
// Clear the Working folder?
|
323 |
+
if ( $args['clear_working'] ) {
|
324 |
+
$wp_filesystem->delete( $remote_source, true );
|
325 |
+
}
|
326 |
+
|
327 |
+
$destination_name = basename( str_replace( $local_destination, '', $destination ) );
|
328 |
+
if ( '.' == $destination_name ) {
|
329 |
+
$destination_name = '';
|
330 |
+
}
|
331 |
+
|
332 |
+
$this->result = compact( 'source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination' );
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Filters the install response after the installation has finished.
|
336 |
+
*
|
337 |
+
* @since 2.8.0
|
338 |
+
*
|
339 |
+
* @param bool $response Install response.
|
340 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
341 |
+
* @param array $result Installation result data.
|
342 |
+
*/
|
343 |
+
$res = apply_filters( 'upgrader_post_install', true, $args['hook_extra'], $this->result );
|
344 |
+
|
345 |
+
if ( is_wp_error( $res ) ) {
|
346 |
+
$this->result = $res;
|
347 |
+
return $res;
|
348 |
+
}
|
349 |
+
|
350 |
+
// Bombard the calling function will all the info which we've just used.
|
351 |
+
return $this->result;
|
352 |
+
}
|
353 |
+
}
|
includes/vendor/class-rrdi-customizer-importer.php
CHANGED
@@ -1,193 +1,193 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class for the customizer importer used in the Rara One Click Demo Import plugin.
|
4 |
-
*
|
5 |
-
* Code is mostly from the Customizer Export/Import plugin.
|
6 |
-
*
|
7 |
-
* @see https://wordpress.org/plugins/customizer-export-import/
|
8 |
-
* @package rara-one-click-demo-import
|
9 |
-
*/
|
10 |
-
|
11 |
-
class RRDI_Customizer_Importer {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Imports uploaded mods and calls WordPress core customize_save actions so
|
15 |
-
* themes that hook into them can act before mods are saved to the database.
|
16 |
-
*
|
17 |
-
* Update: WP core customize_save actions were removed, because of some errors.
|
18 |
-
*
|
19 |
-
* @since 1.0.1
|
20 |
-
* @param string $import_file_path Path to the import file.
|
21 |
-
* @return void|WP_Error
|
22 |
-
*/
|
23 |
-
public static function import_customizer_options( $import_file_path ) {
|
24 |
-
|
25 |
-
// Setup global vars.
|
26 |
-
global $wp_customize;
|
27 |
-
|
28 |
-
// Setup internal vars.
|
29 |
-
$template = get_template();
|
30 |
-
|
31 |
-
// Make sure we have an import file.
|
32 |
-
if ( ! file_exists( $import_file_path ) ) {
|
33 |
-
return new WP_Error(
|
34 |
-
'missing_cutomizer_import_file',
|
35 |
-
sprintf(
|
36 |
-
esc_html__( 'The customizer import file is missing! File path: %s', 'rara-one-click-demo-import' ),
|
37 |
-
$import_file_path
|
38 |
-
)
|
39 |
-
);
|
40 |
-
}
|
41 |
-
// Get the upload data.
|
42 |
-
$raw = RRDI_Helpers::data_from_file( $import_file_path );
|
43 |
-
|
44 |
-
// Make sure we got the data.
|
45 |
-
if ( is_wp_error( $raw ) ) {
|
46 |
-
return $raw;
|
47 |
-
}
|
48 |
-
|
49 |
-
$data = unserialize( $raw );
|
50 |
-
|
51 |
-
// Data checks.
|
52 |
-
if ( ! is_array( $data ) && ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) ) {
|
53 |
-
return new WP_Error(
|
54 |
-
'customizer_import_data_error',
|
55 |
-
esc_html__( 'No correct file format. Please make sure to use the correct customizer import file.', 'rara-one-click-demo-import' )
|
56 |
-
);
|
57 |
-
}
|
58 |
-
if ( $data['template'] !== $template ) {
|
59 |
-
return new WP_Error(
|
60 |
-
'customizer_import_wrong_theme',
|
61 |
-
esc_html__( 'The customizer import file is not suitable for current theme. You can only import customizer settings for the same theme or a child theme.', 'rara-one-click-demo-import' )
|
62 |
-
);
|
63 |
-
}
|
64 |
-
|
65 |
-
// Import images.
|
66 |
-
if ( apply_filters( 'rrdi/customizer_import_images', true ) ) {
|
67 |
-
$data['mods'] = self::import_customizer_images( $data['mods'] );
|
68 |
-
}
|
69 |
-
|
70 |
-
// Import custom options.
|
71 |
-
if ( isset( $data['options'] ) ) {
|
72 |
-
|
73 |
-
// Require modified customizer options class.
|
74 |
-
if ( ! class_exists( 'WP_Customize_Setting' ) ) {
|
75 |
-
require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
|
76 |
-
}
|
77 |
-
require RRDI_PATH . 'includes/class-rrdi-customizer-option.php';
|
78 |
-
|
79 |
-
foreach ( $data['options'] as $option_key => $option_value ) {
|
80 |
-
$option = new RRDI_Customizer_Option( $wp_customize, $option_key, array(
|
81 |
-
'default' => '',
|
82 |
-
'type' => 'option',
|
83 |
-
'capability' => 'edit_theme_options',
|
84 |
-
) );
|
85 |
-
|
86 |
-
$option->import( $option_value );
|
87 |
-
}
|
88 |
-
}
|
89 |
-
|
90 |
-
// Loop through the mods.
|
91 |
-
foreach ( $data['mods'] as $key => $val ) {
|
92 |
-
|
93 |
-
// Save the mod.
|
94 |
-
set_theme_mod( $key, $val );
|
95 |
-
}
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* Helper function: Customizer import - imports images for settings saved as mods.
|
100 |
-
*
|
101 |
-
* @since 1.0.1
|
102 |
-
* @param array $mods An array of customizer mods.
|
103 |
-
* @return array The mods array with any new import data.
|
104 |
-
*/
|
105 |
-
private static function import_customizer_images( $mods ) {
|
106 |
-
foreach ( $mods as $key => $val ) {
|
107 |
-
if ( self::customizer_is_image_url( $val ) ) {
|
108 |
-
$data = self::customizer_sideload_image( $val );
|
109 |
-
if ( ! is_wp_error( $data ) ) {
|
110 |
-
$mods[ $key ] = $data->url;
|
111 |
-
|
112 |
-
// Handle header image controls.
|
113 |
-
if ( isset( $mods[ $key . '_data' ] ) ) {
|
114 |
-
$mods[ $key . '_data' ] = $data;
|
115 |
-
update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
|
116 |
-
}
|
117 |
-
}
|
118 |
-
}
|
119 |
-
}
|
120 |
-
|
121 |
-
return $mods;
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Helper function: Customizer import
|
126 |
-
* Taken from the core media_sideload_image function and
|
127 |
-
* modified to return an array of data instead of html.
|
128 |
-
*
|
129 |
-
* @since 1.0.1.
|
130 |
-
* @param string $file The image file path.
|
131 |
-
* @return array An array of image data.
|
132 |
-
*/
|
133 |
-
private static function customizer_sideload_image( $file ) {
|
134 |
-
$data = new stdClass();
|
135 |
-
|
136 |
-
if ( ! function_exists( 'media_handle_sideload' ) ) {
|
137 |
-
require_once( ABSPATH . 'wp-admin/includes/media.php' );
|
138 |
-
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
139 |
-
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
140 |
-
}
|
141 |
-
if ( ! empty( $file ) ) {
|
142 |
-
|
143 |
-
// Set variables for storage, fix file filename for query strings.
|
144 |
-
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
|
145 |
-
$file_array = array();
|
146 |
-
$file_array['name'] = basename( $matches[0] );
|
147 |
-
|
148 |
-
// Download file to temp location.
|
149 |
-
$file_array['tmp_name'] = download_url( $file );
|
150 |
-
|
151 |
-
// If error storing temporarily, return the error.
|
152 |
-
if ( is_wp_error( $file_array['tmp_name'] ) ) {
|
153 |
-
return $file_array['tmp_name'];
|
154 |
-
}
|
155 |
-
|
156 |
-
// Do the validation and storage stuff.
|
157 |
-
$id = media_handle_sideload( $file_array, 0 );
|
158 |
-
|
159 |
-
// If error storing permanently, unlink.
|
160 |
-
if ( is_wp_error( $id ) ) {
|
161 |
-
unlink( $file_array['tmp_name'] );
|
162 |
-
return $id;
|
163 |
-
}
|
164 |
-
|
165 |
-
// Build the object to return.
|
166 |
-
$meta = wp_get_attachment_metadata( $id );
|
167 |
-
$data->attachment_id = $id;
|
168 |
-
$data->url = wp_get_attachment_url( $id );
|
169 |
-
$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
|
170 |
-
$data->height = $meta['height'];
|
171 |
-
$data->width = $meta['width'];
|
172 |
-
}
|
173 |
-
|
174 |
-
return $data;
|
175 |
-
}
|
176 |
-
|
177 |
-
/**
|
178 |
-
* Checks to see whether a string is an image url or not.
|
179 |
-
*
|
180 |
-
* @since 1.0.1
|
181 |
-
* @param string $string The string to check.
|
182 |
-
* @return bool Whether the string is an image url or not.
|
183 |
-
*/
|
184 |
-
private static function customizer_is_image_url( $string = '' ) {
|
185 |
-
if ( is_string( $string ) ) {
|
186 |
-
if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
|
187 |
-
return true;
|
188 |
-
}
|
189 |
-
}
|
190 |
-
|
191 |
-
return false;
|
192 |
-
}
|
193 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class for the customizer importer used in the Rara One Click Demo Import plugin.
|
4 |
+
*
|
5 |
+
* Code is mostly from the Customizer Export/Import plugin.
|
6 |
+
*
|
7 |
+
* @see https://wordpress.org/plugins/customizer-export-import/
|
8 |
+
* @package rara-one-click-demo-import
|
9 |
+
*/
|
10 |
+
|
11 |
+
class RRDI_Customizer_Importer {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Imports uploaded mods and calls WordPress core customize_save actions so
|
15 |
+
* themes that hook into them can act before mods are saved to the database.
|
16 |
+
*
|
17 |
+
* Update: WP core customize_save actions were removed, because of some errors.
|
18 |
+
*
|
19 |
+
* @since 1.0.1
|
20 |
+
* @param string $import_file_path Path to the import file.
|
21 |
+
* @return void|WP_Error
|
22 |
+
*/
|
23 |
+
public static function import_customizer_options( $import_file_path ) {
|
24 |
+
|
25 |
+
// Setup global vars.
|
26 |
+
global $wp_customize;
|
27 |
+
|
28 |
+
// Setup internal vars.
|
29 |
+
$template = get_template();
|
30 |
+
|
31 |
+
// Make sure we have an import file.
|
32 |
+
if ( ! file_exists( $import_file_path ) ) {
|
33 |
+
return new WP_Error(
|
34 |
+
'missing_cutomizer_import_file',
|
35 |
+
sprintf(
|
36 |
+
esc_html__( 'The customizer import file is missing! File path: %s', 'rara-one-click-demo-import' ),
|
37 |
+
$import_file_path
|
38 |
+
)
|
39 |
+
);
|
40 |
+
}
|
41 |
+
// Get the upload data.
|
42 |
+
$raw = RRDI_Helpers::data_from_file( $import_file_path );
|
43 |
+
|
44 |
+
// Make sure we got the data.
|
45 |
+
if ( is_wp_error( $raw ) ) {
|
46 |
+
return $raw;
|
47 |
+
}
|
48 |
+
|
49 |
+
$data = unserialize( $raw );
|
50 |
+
|
51 |
+
// Data checks.
|
52 |
+
if ( ! is_array( $data ) && ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) ) {
|
53 |
+
return new WP_Error(
|
54 |
+
'customizer_import_data_error',
|
55 |
+
esc_html__( 'No correct file format. Please make sure to use the correct customizer import file.', 'rara-one-click-demo-import' )
|
56 |
+
);
|
57 |
+
}
|
58 |
+
if ( $data['template'] !== $template ) {
|
59 |
+
return new WP_Error(
|
60 |
+
'customizer_import_wrong_theme',
|
61 |
+
esc_html__( 'The customizer import file is not suitable for current theme. You can only import customizer settings for the same theme or a child theme.', 'rara-one-click-demo-import' )
|
62 |
+
);
|
63 |
+
}
|
64 |
+
|
65 |
+
// Import images.
|
66 |
+
if ( apply_filters( 'rrdi/customizer_import_images', true ) ) {
|
67 |
+
$data['mods'] = self::import_customizer_images( $data['mods'] );
|
68 |
+
}
|
69 |
+
|
70 |
+
// Import custom options.
|
71 |
+
if ( isset( $data['options'] ) ) {
|
72 |
+
|
73 |
+
// Require modified customizer options class.
|
74 |
+
if ( ! class_exists( 'WP_Customize_Setting' ) ) {
|
75 |
+
require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
|
76 |
+
}
|
77 |
+
require RRDI_PATH . 'includes/class-rrdi-customizer-option.php';
|
78 |
+
|
79 |
+
foreach ( $data['options'] as $option_key => $option_value ) {
|
80 |
+
$option = new RRDI_Customizer_Option( $wp_customize, $option_key, array(
|
81 |
+
'default' => '',
|
82 |
+
'type' => 'option',
|
83 |
+
'capability' => 'edit_theme_options',
|
84 |
+
) );
|
85 |
+
|
86 |
+
$option->import( $option_value );
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
// Loop through the mods.
|
91 |
+
foreach ( $data['mods'] as $key => $val ) {
|
92 |
+
|
93 |
+
// Save the mod.
|
94 |
+
set_theme_mod( $key, $val );
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Helper function: Customizer import - imports images for settings saved as mods.
|
100 |
+
*
|
101 |
+
* @since 1.0.1
|
102 |
+
* @param array $mods An array of customizer mods.
|
103 |
+
* @return array The mods array with any new import data.
|
104 |
+
*/
|
105 |
+
private static function import_customizer_images( $mods ) {
|
106 |
+
foreach ( $mods as $key => $val ) {
|
107 |
+
if ( self::customizer_is_image_url( $val ) ) {
|
108 |
+
$data = self::customizer_sideload_image( $val );
|
109 |
+
if ( ! is_wp_error( $data ) ) {
|
110 |
+
$mods[ $key ] = $data->url;
|
111 |
+
|
112 |
+
// Handle header image controls.
|
113 |
+
if ( isset( $mods[ $key . '_data' ] ) ) {
|
114 |
+
$mods[ $key . '_data' ] = $data;
|
115 |
+
update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
|
116 |
+
}
|
117 |
+
}
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
return $mods;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Helper function: Customizer import
|
126 |
+
* Taken from the core media_sideload_image function and
|
127 |
+
* modified to return an array of data instead of html.
|
128 |
+
*
|
129 |
+
* @since 1.0.1.
|
130 |
+
* @param string $file The image file path.
|
131 |
+
* @return array An array of image data.
|
132 |
+
*/
|
133 |
+
private static function customizer_sideload_image( $file ) {
|
134 |
+
$data = new stdClass();
|
135 |
+
|
136 |
+
if ( ! function_exists( 'media_handle_sideload' ) ) {
|
137 |
+
require_once( ABSPATH . 'wp-admin/includes/media.php' );
|
138 |
+
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
139 |
+
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
140 |
+
}
|
141 |
+
if ( ! empty( $file ) ) {
|
142 |
+
|
143 |
+
// Set variables for storage, fix file filename for query strings.
|
144 |
+
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
|
145 |
+
$file_array = array();
|
146 |
+
$file_array['name'] = basename( $matches[0] );
|
147 |
+
|
148 |
+
// Download file to temp location.
|
149 |
+
$file_array['tmp_name'] = download_url( $file );
|
150 |
+
|
151 |
+
// If error storing temporarily, return the error.
|
152 |
+
if ( is_wp_error( $file_array['tmp_name'] ) ) {
|
153 |
+
return $file_array['tmp_name'];
|
154 |
+
}
|
155 |
+
|
156 |
+
// Do the validation and storage stuff.
|
157 |
+
$id = media_handle_sideload( $file_array, 0 );
|
158 |
+
|
159 |
+
// If error storing permanently, unlink.
|
160 |
+
if ( is_wp_error( $id ) ) {
|
161 |
+
unlink( $file_array['tmp_name'] );
|
162 |
+
return $id;
|
163 |
+
}
|
164 |
+
|
165 |
+
// Build the object to return.
|
166 |
+
$meta = wp_get_attachment_metadata( $id );
|
167 |
+
$data->attachment_id = $id;
|
168 |
+
$data->url = wp_get_attachment_url( $id );
|
169 |
+
$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
|
170 |
+
$data->height = $meta['height'];
|
171 |
+
$data->width = $meta['width'];
|
172 |
+
}
|
173 |
+
|
174 |
+
return $data;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Checks to see whether a string is an image url or not.
|
179 |
+
*
|
180 |
+
* @since 1.0.1
|
181 |
+
* @param string $string The string to check.
|
182 |
+
* @return bool Whether the string is an image url or not.
|
183 |
+
*/
|
184 |
+
private static function customizer_is_image_url( $string = '' ) {
|
185 |
+
if ( is_string( $string ) ) {
|
186 |
+
if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
|
187 |
+
return true;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
return false;
|
192 |
+
}
|
193 |
+
}
|
includes/vendor/class-rrdi-widget-importer.php
CHANGED
@@ -1,304 +1,304 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class for the widget importer used in the Rara One Click Demo Import plugin.
|
4 |
-
*
|
5 |
-
* Code is mostly from the Widget Importer & Exporter plugin.
|
6 |
-
*
|
7 |
-
* @see https://wordpress.org/plugins/widget-importer-exporter/
|
8 |
-
* @package rara-one-click-demo-import
|
9 |
-
*/
|
10 |
-
|
11 |
-
class RRDI_Widget_Importer {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Imports widgets from a json file.
|
15 |
-
*
|
16 |
-
* @param string $data_file path to json file with WordPress widget export data.
|
17 |
-
*/
|
18 |
-
public function import_widgets( $data_file ) {
|
19 |
-
|
20 |
-
// Get widgets data from file.
|
21 |
-
$data = $this->process_import_file( $data_file );
|
22 |
-
|
23 |
-
// Return from this function if there was an error.
|
24 |
-
if ( is_wp_error( $data ) ) {
|
25 |
-
return $data;
|
26 |
-
}
|
27 |
-
|
28 |
-
// Import the widget data and save the results.
|
29 |
-
return $this->import_data( $data );
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Process import file - this parses the widget data and returns it.
|
34 |
-
*
|
35 |
-
* @param string $file path to json file.
|
36 |
-
* @return object $data decoded JSON string
|
37 |
-
*/
|
38 |
-
private function process_import_file( $file ) {
|
39 |
-
|
40 |
-
// File exists?
|
41 |
-
if ( ! file_exists( $file ) ) {
|
42 |
-
return new WP_Error(
|
43 |
-
'widget_import_file_not_found',
|
44 |
-
__( 'Widget import file could not be found.', 'rara-one-click-demo-import' )
|
45 |
-
);
|
46 |
-
}
|
47 |
-
|
48 |
-
// Get file contents and decode.
|
49 |
-
$data = RRDI_Helpers::data_from_file( $file );
|
50 |
-
|
51 |
-
// Return from this function if there was an error.
|
52 |
-
if ( is_wp_error( $data ) ) {
|
53 |
-
return $data;
|
54 |
-
}
|
55 |
-
|
56 |
-
return json_decode( $data );
|
57 |
-
}
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Import widget JSON data
|
63 |
-
*
|
64 |
-
* @global array $wp_registered_sidebars
|
65 |
-
* @param object $data JSON widget data.
|
66 |
-
* @return array $results
|
67 |
-
*/
|
68 |
-
private function import_data( $data ) {
|
69 |
-
|
70 |
-
global $wp_registered_sidebars;
|
71 |
-
|
72 |
-
// Have valid data? If no data or could not decode.
|
73 |
-
if ( empty( $data ) || ! is_object( $data ) ) {
|
74 |
-
return new WP_Error(
|
75 |
-
'corrupted_widget_import_data',
|
76 |
-
__( 'Widget import data could not be read. Please try a different file.', 'rara-one-click-demo-import' )
|
77 |
-
);
|
78 |
-
}
|
79 |
-
|
80 |
-
// Hook before import.
|
81 |
-
do_action( 'rrdi/widget_importer_before_widgets_import' );
|
82 |
-
$data = apply_filters( 'rrdi/before_widgets_import_data', $data );
|
83 |
-
|
84 |
-
// Get all available widgets site supports.
|
85 |
-
$available_widgets = $this->available_widgets();
|
86 |
-
|
87 |
-
// Get all existing widget instances.
|
88 |
-
$widget_instances = array();
|
89 |
-
|
90 |
-
foreach ( $available_widgets as $widget_data ) {
|
91 |
-
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
92 |
-
}
|
93 |
-
|
94 |
-
// Begin results.
|
95 |
-
$results = array();
|
96 |
-
|
97 |
-
// Loop import data's sidebars.
|
98 |
-
foreach ( $data as $sidebar_id => $widgets ) {
|
99 |
-
|
100 |
-
// Skip inactive widgets (should not be in export file).
|
101 |
-
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
102 |
-
continue;
|
103 |
-
}
|
104 |
-
|
105 |
-
// Check if sidebar is available on this site. Otherwise add widgets to inactive, and say so.
|
106 |
-
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
107 |
-
$sidebar_available = true;
|
108 |
-
$use_sidebar_id = $sidebar_id;
|
109 |
-
$sidebar_message_type = 'success';
|
110 |
-
$sidebar_message = '';
|
111 |
-
}
|
112 |
-
else {
|
113 |
-
$sidebar_available = false;
|
114 |
-
$use_sidebar_id = 'wp_inactive_widgets'; // Add to inactive if sidebar does not exist in theme.
|
115 |
-
$sidebar_message_type = 'error';
|
116 |
-
$sidebar_message = __( 'Sidebar does not exist in theme (moving widget to Inactive)', 'rara-one-click-demo-import' );
|
117 |
-
}
|
118 |
-
|
119 |
-
// Result for sidebar.
|
120 |
-
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id; // Sidebar name if theme supports it; otherwise ID.
|
121 |
-
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
122 |
-
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
123 |
-
$results[ $sidebar_id ]['widgets'] = array();
|
124 |
-
|
125 |
-
// Loop widgets.
|
126 |
-
foreach ( $widgets as $widget_instance_id => $widget ) {
|
127 |
-
|
128 |
-
$fail = false;
|
129 |
-
|
130 |
-
// Get id_base (remove -# from end) and instance ID number.
|
131 |
-
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
132 |
-
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
133 |
-
|
134 |
-
// Does site support this widget?
|
135 |
-
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
136 |
-
$fail = true;
|
137 |
-
$widget_message_type = 'error';
|
138 |
-
$widget_message = __( 'Site does not support widget', 'rara-one-click-demo-import' ); // Explain why widget not imported.
|
139 |
-
}
|
140 |
-
|
141 |
-
// Filter to modify settings object before conversion to array and import.
|
142 |
-
// Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below).
|
143 |
-
// Ideally the newer wie_widget_settings_array below will be used instead of this.
|
144 |
-
$widget = apply_filters( 'rrdi/widget_settings', $widget ); // Object.
|
145 |
-
|
146 |
-
// Convert multidimensional objects to multidimensional arrays.
|
147 |
-
// Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays.
|
148 |
-
// Without this, they are imported as objects and cause fatal error on Widgets page.
|
149 |
-
// If this creates problems for plugins that do actually intend settings in objects then may need to consider other approach: https://wordpress.org/support/topic/problem-with-array-of-arrays.
|
150 |
-
// It is probably much more likely that arrays are used than objects, however.
|
151 |
-
$widget = json_decode( json_encode( $widget ), true );
|
152 |
-
|
153 |
-
// Filter to modify settings array.
|
154 |
-
// This is preferred over the older wie_widget_settings filter above.
|
155 |
-
// Do before identical check because changes may make it identical to end result (such as URL replacements).
|
156 |
-
$widget = apply_filters( 'rrdi/widget_settings_array', $widget );
|
157 |
-
|
158 |
-
// Does widget with identical settings already exist in same sidebar?
|
159 |
-
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
160 |
-
|
161 |
-
// Get existing widgets in this sidebar.
|
162 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
163 |
-
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // Check Inactive if that's where will go.
|
164 |
-
|
165 |
-
// Loop widgets with ID base.
|
166 |
-
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
167 |
-
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
168 |
-
|
169 |
-
// Is widget in same sidebar and has identical settings?
|
170 |
-
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
171 |
-
$fail = true;
|
172 |
-
$widget_message_type = 'warning';
|
173 |
-
$widget_message = __( 'Widget already exists', 'rara-one-click-demo-import' ); // Explain why widget not imported.
|
174 |
-
|
175 |
-
break;
|
176 |
-
}
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
// No failure.
|
181 |
-
if ( ! $fail ) {
|
182 |
-
|
183 |
-
// Add widget instance.
|
184 |
-
$single_widget_instances = get_option( 'widget_' . $id_base ); // All instances for that widget ID base, get fresh every time.
|
185 |
-
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // Start fresh if have to.
|
186 |
-
$single_widget_instances[] = $widget; // Add it.
|
187 |
-
|
188 |
-
// Get the key it was given.
|
189 |
-
end( $single_widget_instances );
|
190 |
-
$new_instance_id_number = key( $single_widget_instances );
|
191 |
-
|
192 |
-
// If key is 0, make it 1.
|
193 |
-
// When 0, an issue can occur where adding a widget causes data from other widget to load, and the widget doesn't stick (reload wipes it).
|
194 |
-
if ( '0' === strval( $new_instance_id_number ) ) {
|
195 |
-
$new_instance_id_number = 1;
|
196 |
-
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
197 |
-
unset( $single_widget_instances[0] );
|
198 |
-
}
|
199 |
-
|
200 |
-
// Move _multiwidget to end of array for uniformity.
|
201 |
-
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
202 |
-
$multiwidget = $single_widget_instances['_multiwidget'];
|
203 |
-
unset( $single_widget_instances['_multiwidget'] );
|
204 |
-
$single_widget_instances['_multiwidget'] = $multiwidget;
|
205 |
-
}
|
206 |
-
|
207 |
-
// Update option with new widget.
|
208 |
-
update_option( 'widget_' . $id_base, $single_widget_instances );
|
209 |
-
|
210 |
-
// Assign widget instance to sidebar.
|
211 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' ); // Which sidebars have which widgets, get fresh every time.
|
212 |
-
$new_instance_id = $id_base . '-' . $new_instance_id_number; // Use ID number from new widget instance.
|
213 |
-
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id; // Add new instance to sidebar.
|
214 |
-
update_option( 'sidebars_widgets', $sidebars_widgets ); // Save the amended data.
|
215 |
-
|
216 |
-
// After widget import action.
|
217 |
-
$after_widget_import = array(
|
218 |
-
'sidebar' => $use_sidebar_id,
|
219 |
-
'sidebar_old' => $sidebar_id,
|
220 |
-
'widget' => $widget,
|
221 |
-
'widget_type' => $id_base,
|
222 |
-
'widget_id' => $new_instance_id,
|
223 |
-
'widget_id_old' => $widget_instance_id,
|
224 |
-
'widget_id_num' => $new_instance_id_number,
|
225 |
-
'widget_id_num_old' => $instance_id_number,
|
226 |
-
);
|
227 |
-
do_action( 'rrdi/widget_importer_after_single_widget_import', $after_widget_import );
|
228 |
-
|
229 |
-
// Success message.
|
230 |
-
if ( $sidebar_available ) {
|
231 |
-
$widget_message_type = 'success';
|
232 |
-
$widget_message = __( 'Imported', 'rara-one-click-demo-import' );
|
233 |
-
}
|
234 |
-
else {
|
235 |
-
$widget_message_type = 'warning';
|
236 |
-
$widget_message = __( 'Imported to Inactive', 'rara-one-click-demo-import' );
|
237 |
-
}
|
238 |
-
}
|
239 |
-
|
240 |
-
// Result for widget instance.
|
241 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base; // Widget name or ID if name not available (not supported by site).
|
242 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget['title'] ) ? $widget['title'] : __( 'No Title', 'rara-one-click-demo-import' ); // Show "No Title" if widget instance is untitled.
|
243 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
244 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
245 |
-
|
246 |
-
}
|
247 |
-
}
|
248 |
-
|
249 |
-
// Hook after import.
|
250 |
-
do_action( 'rrdi/widget_importer_after_widgets_import' );
|
251 |
-
|
252 |
-
// Return results.
|
253 |
-
return apply_filters( 'rrdi/widget_import_results', $results );
|
254 |
-
}
|
255 |
-
|
256 |
-
|
257 |
-
/**
|
258 |
-
* Available widgets.
|
259 |
-
*
|
260 |
-
* Gather site's widgets into array with ID base, name, etc.
|
261 |
-
*
|
262 |
-
* @global array $wp_registered_widget_controls
|
263 |
-
* @return array $available_widgets, Widget information
|
264 |
-
*/
|
265 |
-
private function available_widgets() {
|
266 |
-
|
267 |
-
global $wp_registered_widget_controls;
|
268 |
-
|
269 |
-
$widget_controls = $wp_registered_widget_controls;
|
270 |
-
$available_widgets = array();
|
271 |
-
|
272 |
-
foreach ( $widget_controls as $widget ) {
|
273 |
-
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
274 |
-
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
275 |
-
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
276 |
-
}
|
277 |
-
}
|
278 |
-
|
279 |
-
return apply_filters( 'rrdi/available_widgets', $available_widgets );
|
280 |
-
}
|
281 |
-
|
282 |
-
|
283 |
-
/**
|
284 |
-
* Format results for log file
|
285 |
-
*
|
286 |
-
* @param array $results widget import results.
|
287 |
-
*/
|
288 |
-
public function format_results_for_log( $results ) {
|
289 |
-
|
290 |
-
if ( empty( $results ) ) {
|
291 |
-
esc_html_e( 'No results for widget import!', 'rara-one-click-demo-import' );
|
292 |
-
}
|
293 |
-
|
294 |
-
// Loop sidebars.
|
295 |
-
foreach ( $results as $sidebar ) {
|
296 |
-
echo esc_html( $sidebar['name'] ) . ' : ' . esc_html( $sidebar['message'] ) . PHP_EOL . PHP_EOL;
|
297 |
-
// Loop widgets.
|
298 |
-
foreach ( $sidebar['widgets'] as $widget ) {
|
299 |
-
echo esc_html( $widget['name'] ) . ' - ' . esc_html( $widget['title'] ) . ' - ' . esc_html( $widget['message'] ) . PHP_EOL;
|
300 |
-
}
|
301 |
-
echo PHP_EOL;
|
302 |
-
}
|
303 |
-
}
|
304 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class for the widget importer used in the Rara One Click Demo Import plugin.
|
4 |
+
*
|
5 |
+
* Code is mostly from the Widget Importer & Exporter plugin.
|
6 |
+
*
|
7 |
+
* @see https://wordpress.org/plugins/widget-importer-exporter/
|
8 |
+
* @package rara-one-click-demo-import
|
9 |
+
*/
|
10 |
+
|
11 |
+
class RRDI_Widget_Importer {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Imports widgets from a json file.
|
15 |
+
*
|
16 |
+
* @param string $data_file path to json file with WordPress widget export data.
|
17 |
+
*/
|
18 |
+
public function import_widgets( $data_file ) {
|
19 |
+
|
20 |
+
// Get widgets data from file.
|
21 |
+
$data = $this->process_import_file( $data_file );
|
22 |
+
|
23 |
+
// Return from this function if there was an error.
|
24 |
+
if ( is_wp_error( $data ) ) {
|
25 |
+
return $data;
|
26 |
+
}
|
27 |
+
|
28 |
+
// Import the widget data and save the results.
|
29 |
+
return $this->import_data( $data );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Process import file - this parses the widget data and returns it.
|
34 |
+
*
|
35 |
+
* @param string $file path to json file.
|
36 |
+
* @return object $data decoded JSON string
|
37 |
+
*/
|
38 |
+
private function process_import_file( $file ) {
|
39 |
+
|
40 |
+
// File exists?
|
41 |
+
if ( ! file_exists( $file ) ) {
|
42 |
+
return new WP_Error(
|
43 |
+
'widget_import_file_not_found',
|
44 |
+
__( 'Widget import file could not be found.', 'rara-one-click-demo-import' )
|
45 |
+
);
|
46 |
+
}
|
47 |
+
|
48 |
+
// Get file contents and decode.
|
49 |
+
$data = RRDI_Helpers::data_from_file( $file );
|
50 |
+
|
51 |
+
// Return from this function if there was an error.
|
52 |
+
if ( is_wp_error( $data ) ) {
|
53 |
+
return $data;
|
54 |
+
}
|
55 |
+
|
56 |
+
return json_decode( $data );
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Import widget JSON data
|
63 |
+
*
|
64 |
+
* @global array $wp_registered_sidebars
|
65 |
+
* @param object $data JSON widget data.
|
66 |
+
* @return array $results
|
67 |
+
*/
|
68 |
+
private function import_data( $data ) {
|
69 |
+
|
70 |
+
global $wp_registered_sidebars;
|
71 |
+
|
72 |
+
// Have valid data? If no data or could not decode.
|
73 |
+
if ( empty( $data ) || ! is_object( $data ) ) {
|
74 |
+
return new WP_Error(
|
75 |
+
'corrupted_widget_import_data',
|
76 |
+
__( 'Widget import data could not be read. Please try a different file.', 'rara-one-click-demo-import' )
|
77 |
+
);
|
78 |
+
}
|
79 |
+
|
80 |
+
// Hook before import.
|
81 |
+
do_action( 'rrdi/widget_importer_before_widgets_import' );
|
82 |
+
$data = apply_filters( 'rrdi/before_widgets_import_data', $data );
|
83 |
+
|
84 |
+
// Get all available widgets site supports.
|
85 |
+
$available_widgets = $this->available_widgets();
|
86 |
+
|
87 |
+
// Get all existing widget instances.
|
88 |
+
$widget_instances = array();
|
89 |
+
|
90 |
+
foreach ( $available_widgets as $widget_data ) {
|
91 |
+
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
92 |
+
}
|
93 |
+
|
94 |
+
// Begin results.
|
95 |
+
$results = array();
|
96 |
+
|
97 |
+
// Loop import data's sidebars.
|
98 |
+
foreach ( $data as $sidebar_id => $widgets ) {
|
99 |
+
|
100 |
+
// Skip inactive widgets (should not be in export file).
|
101 |
+
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
102 |
+
continue;
|
103 |
+
}
|
104 |
+
|
105 |
+
// Check if sidebar is available on this site. Otherwise add widgets to inactive, and say so.
|
106 |
+
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
107 |
+
$sidebar_available = true;
|
108 |
+
$use_sidebar_id = $sidebar_id;
|
109 |
+
$sidebar_message_type = 'success';
|
110 |
+
$sidebar_message = '';
|
111 |
+
}
|
112 |
+
else {
|
113 |
+
$sidebar_available = false;
|
114 |
+
$use_sidebar_id = 'wp_inactive_widgets'; // Add to inactive if sidebar does not exist in theme.
|
115 |
+
$sidebar_message_type = 'error';
|
116 |
+
$sidebar_message = __( 'Sidebar does not exist in theme (moving widget to Inactive)', 'rara-one-click-demo-import' );
|
117 |
+
}
|
118 |
+
|
119 |
+
// Result for sidebar.
|
120 |
+
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id; // Sidebar name if theme supports it; otherwise ID.
|
121 |
+
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
122 |
+
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
123 |
+
$results[ $sidebar_id ]['widgets'] = array();
|
124 |
+
|
125 |
+
// Loop widgets.
|
126 |
+
foreach ( $widgets as $widget_instance_id => $widget ) {
|
127 |
+
|
128 |
+
$fail = false;
|
129 |
+
|
130 |
+
// Get id_base (remove -# from end) and instance ID number.
|
131 |
+
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
132 |
+
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
133 |
+
|
134 |
+
// Does site support this widget?
|
135 |
+
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
136 |
+
$fail = true;
|
137 |
+
$widget_message_type = 'error';
|
138 |
+
$widget_message = __( 'Site does not support widget', 'rara-one-click-demo-import' ); // Explain why widget not imported.
|
139 |
+
}
|
140 |
+
|
141 |
+
// Filter to modify settings object before conversion to array and import.
|
142 |
+
// Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below).
|
143 |
+
// Ideally the newer wie_widget_settings_array below will be used instead of this.
|
144 |
+
$widget = apply_filters( 'rrdi/widget_settings', $widget ); // Object.
|
145 |
+
|
146 |
+
// Convert multidimensional objects to multidimensional arrays.
|
147 |
+
// Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays.
|
148 |
+
// Without this, they are imported as objects and cause fatal error on Widgets page.
|
149 |
+
// If this creates problems for plugins that do actually intend settings in objects then may need to consider other approach: https://wordpress.org/support/topic/problem-with-array-of-arrays.
|
150 |
+
// It is probably much more likely that arrays are used than objects, however.
|
151 |
+
$widget = json_decode( json_encode( $widget ), true );
|
152 |
+
|
153 |
+
// Filter to modify settings array.
|
154 |
+
// This is preferred over the older wie_widget_settings filter above.
|
155 |
+
// Do before identical check because changes may make it identical to end result (such as URL replacements).
|
156 |
+
$widget = apply_filters( 'rrdi/widget_settings_array', $widget );
|
157 |
+
|
158 |
+
// Does widget with identical settings already exist in same sidebar?
|
159 |
+
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
160 |
+
|
161 |
+
// Get existing widgets in this sidebar.
|
162 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
163 |
+
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // Check Inactive if that's where will go.
|
164 |
+
|
165 |
+
// Loop widgets with ID base.
|
166 |
+
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
167 |
+
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
168 |
+
|
169 |
+
// Is widget in same sidebar and has identical settings?
|
170 |
+
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
171 |
+
$fail = true;
|
172 |
+
$widget_message_type = 'warning';
|
173 |
+
$widget_message = __( 'Widget already exists', 'rara-one-click-demo-import' ); // Explain why widget not imported.
|
174 |
+
|
175 |
+
break;
|
176 |
+
}
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
// No failure.
|
181 |
+
if ( ! $fail ) {
|
182 |
+
|
183 |
+
// Add widget instance.
|
184 |
+
$single_widget_instances = get_option( 'widget_' . $id_base ); // All instances for that widget ID base, get fresh every time.
|
185 |
+
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // Start fresh if have to.
|
186 |
+
$single_widget_instances[] = $widget; // Add it.
|
187 |
+
|
188 |
+
// Get the key it was given.
|
189 |
+
end( $single_widget_instances );
|
190 |
+
$new_instance_id_number = key( $single_widget_instances );
|
191 |
+
|
192 |
+
// If key is 0, make it 1.
|
193 |
+
// When 0, an issue can occur where adding a widget causes data from other widget to load, and the widget doesn't stick (reload wipes it).
|
194 |
+
if ( '0' === strval( $new_instance_id_number ) ) {
|
195 |
+
$new_instance_id_number = 1;
|
196 |
+
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
197 |
+
unset( $single_widget_instances[0] );
|
198 |
+
}
|
199 |
+
|
200 |
+
// Move _multiwidget to end of array for uniformity.
|
201 |
+
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
202 |
+
$multiwidget = $single_widget_instances['_multiwidget'];
|
203 |
+
unset( $single_widget_instances['_multiwidget'] );
|
204 |
+
$single_widget_instances['_multiwidget'] = $multiwidget;
|
205 |
+
}
|
206 |
+
|
207 |
+
// Update option with new widget.
|
208 |
+
update_option( 'widget_' . $id_base, $single_widget_instances );
|
209 |
+
|
210 |
+
// Assign widget instance to sidebar.
|
211 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' ); // Which sidebars have which widgets, get fresh every time.
|
212 |
+
$new_instance_id = $id_base . '-' . $new_instance_id_number; // Use ID number from new widget instance.
|
213 |
+
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id; // Add new instance to sidebar.
|
214 |
+
update_option( 'sidebars_widgets', $sidebars_widgets ); // Save the amended data.
|
215 |
+
|
216 |
+
// After widget import action.
|
217 |
+
$after_widget_import = array(
|
218 |
+
'sidebar' => $use_sidebar_id,
|
219 |
+
'sidebar_old' => $sidebar_id,
|
220 |
+
'widget' => $widget,
|
221 |
+
'widget_type' => $id_base,
|
222 |
+
'widget_id' => $new_instance_id,
|
223 |
+
'widget_id_old' => $widget_instance_id,
|
224 |
+
'widget_id_num' => $new_instance_id_number,
|
225 |
+
'widget_id_num_old' => $instance_id_number,
|
226 |
+
);
|
227 |
+
do_action( 'rrdi/widget_importer_after_single_widget_import', $after_widget_import );
|
228 |
+
|
229 |
+
// Success message.
|
230 |
+
if ( $sidebar_available ) {
|
231 |
+
$widget_message_type = 'success';
|
232 |
+
$widget_message = __( 'Imported', 'rara-one-click-demo-import' );
|
233 |
+
}
|
234 |
+
else {
|
235 |
+
$widget_message_type = 'warning';
|
236 |
+
$widget_message = __( 'Imported to Inactive', 'rara-one-click-demo-import' );
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
// Result for widget instance.
|
241 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base; // Widget name or ID if name not available (not supported by site).
|
242 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget['title'] ) ? $widget['title'] : __( 'No Title', 'rara-one-click-demo-import' ); // Show "No Title" if widget instance is untitled.
|
243 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
244 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
245 |
+
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
// Hook after import.
|
250 |
+
do_action( 'rrdi/widget_importer_after_widgets_import' );
|
251 |
+
|
252 |
+
// Return results.
|
253 |
+
return apply_filters( 'rrdi/widget_import_results', $results );
|
254 |
+
}
|
255 |
+
|
256 |
+
|
257 |
+
/**
|
258 |
+
* Available widgets.
|
259 |
+
*
|
260 |
+
* Gather site's widgets into array with ID base, name, etc.
|
261 |
+
*
|
262 |
+
* @global array $wp_registered_widget_controls
|
263 |
+
* @return array $available_widgets, Widget information
|
264 |
+
*/
|
265 |
+
private function available_widgets() {
|
266 |
+
|
267 |
+
global $wp_registered_widget_controls;
|
268 |
+
|
269 |
+
$widget_controls = $wp_registered_widget_controls;
|
270 |
+
$available_widgets = array();
|
271 |
+
|
272 |
+
foreach ( $widget_controls as $widget ) {
|
273 |
+
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
274 |
+
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
275 |
+
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
276 |
+
}
|
277 |
+
}
|
278 |
+
|
279 |
+
return apply_filters( 'rrdi/available_widgets', $available_widgets );
|
280 |
+
}
|
281 |
+
|
282 |
+
|
283 |
+
/**
|
284 |
+
* Format results for log file
|
285 |
+
*
|
286 |
+
* @param array $results widget import results.
|
287 |
+
*/
|
288 |
+
public function format_results_for_log( $results ) {
|
289 |
+
|
290 |
+
if ( empty( $results ) ) {
|
291 |
+
esc_html_e( 'No results for widget import!', 'rara-one-click-demo-import' );
|
292 |
+
}
|
293 |
+
|
294 |
+
// Loop sidebars.
|
295 |
+
foreach ( $results as $sidebar ) {
|
296 |
+
echo esc_html( $sidebar['name'] ) . ' : ' . esc_html( $sidebar['message'] ) . PHP_EOL . PHP_EOL;
|
297 |
+
// Loop widgets.
|
298 |
+
foreach ( $sidebar['widgets'] as $widget ) {
|
299 |
+
echo esc_html( $widget['name'] ) . ' - ' . esc_html( $widget['title'] ) . ' - ' . esc_html( $widget['message'] ) . PHP_EOL;
|
300 |
+
}
|
301 |
+
echo PHP_EOL;
|
302 |
+
}
|
303 |
+
}
|
304 |
+
}
|
languages/rara-one-click-demo-import.pot
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
# This file is distributed under the GPL3.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
-
"Project-Id-Version: RARA One Click Demo Import 1.3.
|
6 |
"Report-Msgid-Bugs-To: \n"
|
7 |
-
"POT-Creation-Date: 2022-
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=utf-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
@@ -493,12 +493,12 @@ msgid ""
|
|
493 |
"will take few minutes to successfully import the demo."
|
494 |
msgstr ""
|
495 |
|
496 |
-
#: includes/vendor/class-demo-installer-skin.php:
|
497 |
-
#: includes/vendor/class-demo-installer-skin.php:
|
498 |
msgid "Return to Demo Importer"
|
499 |
msgstr ""
|
500 |
|
501 |
-
#: includes/vendor/class-demo-installer-skin.php:
|
502 |
msgid "Return to Demos page"
|
503 |
msgstr ""
|
504 |
|
2 |
# This file is distributed under the GPL3.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"Project-Id-Version: RARA One Click Demo Import 1.3.1\n"
|
6 |
"Report-Msgid-Bugs-To: \n"
|
7 |
+
"POT-Creation-Date: 2022-07-27 08:29:15+00:00\n"
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=utf-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
493 |
"will take few minutes to successfully import the demo."
|
494 |
msgstr ""
|
495 |
|
496 |
+
#: includes/vendor/class-demo-installer-skin.php:44
|
497 |
+
#: includes/vendor/class-demo-installer-skin.php:46
|
498 |
msgid "Return to Demo Importer"
|
499 |
msgstr ""
|
500 |
|
501 |
+
#: includes/vendor/class-demo-installer-skin.php:48
|
502 |
msgid "Return to Demos page"
|
503 |
msgstr ""
|
504 |
|
rara-one-click-demo-import.php
CHANGED
@@ -1,26 +1,26 @@
|
|
1 |
-
<?php
|
2 |
-
/*
|
3 |
-
Plugin Name: RARA One Click Demo Import
|
4 |
-
Plugin URI: https://wordpress.org/plugins/rara-one-click-demo-import/
|
5 |
-
Description: Import demo content, widgets and settings of themes made by RaraTheme with just one click.
|
6 |
-
Version: 1.3.
|
7 |
-
Author: raratheme
|
8 |
-
Author URI: https://www.rarathemes.com
|
9 |
-
License: GPL3
|
10 |
-
License URI: http://www.gnu.org/licenses/gpl.html
|
11 |
-
Text Domain: rara-one-click-demo-import
|
12 |
-
*/
|
13 |
-
|
14 |
-
// Block direct access to the main plugin file.
|
15 |
-
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
16 |
-
|
17 |
-
define( 'RRDI_PATH', plugin_dir_path( __FILE__ ) );
|
18 |
-
|
19 |
-
// Current version of the plugin.
|
20 |
-
define( 'RRDI_VERSION', '1.3.
|
21 |
-
|
22 |
-
// Path/URL to root of this plugin, with trailing slash.
|
23 |
-
define( 'RRDI_URL', plugin_dir_url( __FILE__ ) );
|
24 |
-
|
25 |
-
require RRDI_PATH . 'includes/class-rrdi-init.php';
|
26 |
-
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: RARA One Click Demo Import
|
4 |
+
Plugin URI: https://wordpress.org/plugins/rara-one-click-demo-import/
|
5 |
+
Description: Import demo content, widgets and settings of themes made by RaraTheme with just one click.
|
6 |
+
Version: 1.3.1
|
7 |
+
Author: raratheme
|
8 |
+
Author URI: https://www.rarathemes.com
|
9 |
+
License: GPL3
|
10 |
+
License URI: http://www.gnu.org/licenses/gpl.html
|
11 |
+
Text Domain: rara-one-click-demo-import
|
12 |
+
*/
|
13 |
+
|
14 |
+
// Block direct access to the main plugin file.
|
15 |
+
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
16 |
+
|
17 |
+
define( 'RRDI_PATH', plugin_dir_path( __FILE__ ) );
|
18 |
+
|
19 |
+
// Current version of the plugin.
|
20 |
+
define( 'RRDI_VERSION', '1.3.1' );
|
21 |
+
|
22 |
+
// Path/URL to root of this plugin, with trailing slash.
|
23 |
+
define( 'RRDI_URL', plugin_dir_url( __FILE__ ) );
|
24 |
+
|
25 |
+
require RRDI_PATH . 'includes/class-rrdi-init.php';
|
26 |
+
|
readme.txt
CHANGED
@@ -1,176 +1,180 @@
|
|
1 |
-
=== Rara One Click Demo Import ===
|
2 |
-
Contributors: raratheme
|
3 |
-
Tags: import, content, demo, data, widgets, settings
|
4 |
-
Requires at least: 4.4.0
|
5 |
-
Tested up to:
|
6 |
-
Requires PHP: 5.6
|
7 |
-
Stable tag: 1.3.
|
8 |
-
License: GPLv3 or later
|
9 |
-
|
10 |
-
Make your website look like the live demo of the theme with a click!
|
11 |
-
|
12 |
-
== Description ==
|
13 |
-
|
14 |
-
Do you love the demos of the themes made by Rara Theme? Or, need a guideline for setting up the themes?
|
15 |
-
|
16 |
-
Then, all you need is this plugin!
|
17 |
-
|
18 |
-
Rara One Click Demo Import plugin will help you import the demo content, including settings of the widgets and the customizer, with a click.
|
19 |
-
|
20 |
-
The demo content will make your website look like the preview of a theme so that you get a basic guideline for making your website.
|
21 |
-
|
22 |
-
Once installed and activated, Rara One Click Demo Import will be accessible through **Appearance > Rara Demo Import**.
|
23 |
-
|
24 |
-
If you use Premium themes made by Rara Themes, go to Pro Theme Demo Import tab and just click on ‘Import Now’ button and your website will look like the demo of the activated theme in no time.
|
25 |
-
|
26 |
-
If you use free themes made by Rara Themes, download the demo files from your [Theme Documentation](https://rarathemes.com/documentation/) page, upload it using ‘Upload Demo File’ button on this plugin, and click Import Now. As simple as that.
|
27 |
-
|
28 |
-
You can find the detail documentation [here](https://rarathemes.com/blog/import-demo-content-rara-themes/)
|
29 |
-
|
30 |
-
If you need help, contact our support team [here](https://rarathemes.com/support-ticket/).
|
31 |
-
|
32 |
-
This plugin is based on the 'Theme Demo Import' plugin by Themely, https://wordpress.org/plugins/theme-demo-import/
|
33 |
-
|
34 |
-
As well as the improved WP Import 2.0 plugin by @humanmade, https://github.com/humanmade/WordPress-Importer.
|
35 |
-
|
36 |
-
== Installation ==
|
37 |
-
**Method 1:**
|
38 |
-
|
39 |
-
On your WordPress admin dashboard
|
40 |
-
Visit ‘Plugins > Add New’
|
41 |
-
Search for ‘RARA One Click Demo Import’ and install the plugin.
|
42 |
-
Activate ‘RARA One Click Demo Import ’ from your Plugins page.
|
43 |
-
|
44 |
-
**Method 2:**
|
45 |
-
|
46 |
-
Download the plugin from WordPress.org repository
|
47 |
-
On your WordPress admin dashboard, go to ‘Plugins> Add New> Upload Plugin’.
|
48 |
-
Upload the downloaded plugin file (rara-one-click-demo-import.zip) and click ‘Install Now’
|
49 |
-
Activate ‘Rara One Click Demo Import’ from your Plugins page.
|
50 |
-
|
51 |
-
Once the plugin is activated, you will find the actual import page in **Appearance > Rara Demo Import**
|
52 |
-
|
53 |
-
== Frequently Asked Questions ==
|
54 |
-
|
55 |
-
= I have activated the Rara One Click Demo Import plugin. Where can I find the plugin? =
|
56 |
-
|
57 |
-
You will find the plugin in *wp-admin -> Appearance -> Rara Demo Import*.
|
58 |
-
|
59 |
-
= Where are the demo import files and the log files saved? =
|
60 |
-
|
61 |
-
The files used in the demo import will be saved to the default WordPress uploads directory. An example of that directory would be: `../wp-content/uploads/2017/03/`.
|
62 |
-
|
63 |
-
The log file will be registered in the *wp-admin -> Media* section.
|
64 |
-
|
65 |
-
= I can't activate the plugin because of a fatal error. What can I do? =
|
66 |
-
|
67 |
-
*Update: There is an admin error notice, stating that the minimal PHP version required for this plugin is 5.3.2.*
|
68 |
-
|
69 |
-
You want to activate the plugin, but this error shows up:
|
70 |
-
|
71 |
-
*Plugin could not be activated because it triggered a fatal error*
|
72 |
-
|
73 |
-
This happens because your hosting server is using a very old version of PHP. This plugin requires PHP version of at least **5.3.x**, but we recommend version *5.6.x*. Please contact your hosting company and ask them to update the PHP version for your site.
|
74 |
-
|
75 |
-
== Screenshots ==
|
76 |
-
|
77 |
-
1. Upload Demo Button
|
78 |
-
2. Pro Theme Demo Screen
|
79 |
-
3. Free Theme Demo Import
|
80 |
-
|
81 |
-
== License ==
|
82 |
-
|
83 |
-
Rara One Click Demo Import uses the script of
|
84 |
-
'Theme Demo Import' plugin by Themely,
|
85 |
-
https://wordpress.org/plugins/theme-demo-import/
|
86 |
-
Licensed under the GNU General Public License v2.0,
|
87 |
-
http://www.gnu.org/licenses/gpl-2.0.html
|
88 |
-
|
89 |
-
Rara One Click Demo Import uses 'Wordpress Importer' plugin script
|
90 |
-
https://github.com/humanmade/WordPress-Importer
|
91 |
-
(C) 2016 @humanmade
|
92 |
-
Licensed under the GNU General Public License v2.0,
|
93 |
-
http://www.gnu.org/licenses/gpl-2.0.html
|
94 |
-
|
95 |
-
|
96 |
-
== Copyright ==
|
97 |
-
|
98 |
-
Rara One Click Demo Import is distributed under the terms of the GNU GPL.
|
99 |
-
|
100 |
-
This program is free software; you can redistribute it and/or modify
|
101 |
-
it under the terms of the GNU General Public License as published by
|
102 |
-
the Free Software Foundation; either version 2 of the License, or
|
103 |
-
any later version (at your own risk).
|
104 |
-
|
105 |
-
This program is distributed in the hope that it will be useful,
|
106 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
107 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
108 |
-
GNU General Public License for more details.
|
109 |
-
|
110 |
-
You should have received a copy of the GNU General Public License along
|
111 |
-
with this program; if not, write to the Free Software Foundation, Inc.,
|
112 |
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
113 |
-
|
114 |
-
== Changelog ==
|
115 |
-
|
116 |
-
= 1.3.
|
117 |
-
*
|
118 |
-
* Fixes: Minor Bug Fixes.
|
119 |
-
|
120 |
-
= 1.
|
121 |
-
*
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
*
|
141 |
-
|
142 |
-
= 1.
|
143 |
-
*
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
*
|
154 |
-
|
155 |
-
= 1.0.
|
156 |
-
*
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
* COMPATIBILITY TEST
|
167 |
-
|
168 |
-
= 1.0.
|
169 |
-
*
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
*
|
174 |
-
|
175 |
-
= 1.0.
|
|
|
|
|
|
|
|
|
176 |
* INITIAL RELEASE
|
1 |
+
=== Rara One Click Demo Import ===
|
2 |
+
Contributors: raratheme
|
3 |
+
Tags: import, content, demo, data, widgets, settings
|
4 |
+
Requires at least: 4.4.0
|
5 |
+
Tested up to: 6.0
|
6 |
+
Requires PHP: 5.6
|
7 |
+
Stable tag: 1.3.1
|
8 |
+
License: GPLv3 or later
|
9 |
+
|
10 |
+
Make your website look like the live demo of the theme with a click!
|
11 |
+
|
12 |
+
== Description ==
|
13 |
+
|
14 |
+
Do you love the demos of the themes made by Rara Theme? Or, need a guideline for setting up the themes?
|
15 |
+
|
16 |
+
Then, all you need is this plugin!
|
17 |
+
|
18 |
+
Rara One Click Demo Import plugin will help you import the demo content, including settings of the widgets and the customizer, with a click.
|
19 |
+
|
20 |
+
The demo content will make your website look like the preview of a theme so that you get a basic guideline for making your website.
|
21 |
+
|
22 |
+
Once installed and activated, Rara One Click Demo Import will be accessible through **Appearance > Rara Demo Import**.
|
23 |
+
|
24 |
+
If you use Premium themes made by Rara Themes, go to Pro Theme Demo Import tab and just click on ‘Import Now’ button and your website will look like the demo of the activated theme in no time.
|
25 |
+
|
26 |
+
If you use free themes made by Rara Themes, download the demo files from your [Theme Documentation](https://rarathemes.com/documentation/) page, upload it using ‘Upload Demo File’ button on this plugin, and click Import Now. As simple as that.
|
27 |
+
|
28 |
+
You can find the detail documentation [here](https://rarathemes.com/blog/import-demo-content-rara-themes/)
|
29 |
+
|
30 |
+
If you need help, contact our support team [here](https://rarathemes.com/support-ticket/).
|
31 |
+
|
32 |
+
This plugin is based on the 'Theme Demo Import' plugin by Themely, https://wordpress.org/plugins/theme-demo-import/
|
33 |
+
|
34 |
+
As well as the improved WP Import 2.0 plugin by @humanmade, https://github.com/humanmade/WordPress-Importer.
|
35 |
+
|
36 |
+
== Installation ==
|
37 |
+
**Method 1:**
|
38 |
+
|
39 |
+
On your WordPress admin dashboard
|
40 |
+
Visit ‘Plugins > Add New’
|
41 |
+
Search for ‘RARA One Click Demo Import’ and install the plugin.
|
42 |
+
Activate ‘RARA One Click Demo Import ’ from your Plugins page.
|
43 |
+
|
44 |
+
**Method 2:**
|
45 |
+
|
46 |
+
Download the plugin from WordPress.org repository
|
47 |
+
On your WordPress admin dashboard, go to ‘Plugins> Add New> Upload Plugin’.
|
48 |
+
Upload the downloaded plugin file (rara-one-click-demo-import.zip) and click ‘Install Now’
|
49 |
+
Activate ‘Rara One Click Demo Import’ from your Plugins page.
|
50 |
+
|
51 |
+
Once the plugin is activated, you will find the actual import page in **Appearance > Rara Demo Import**
|
52 |
+
|
53 |
+
== Frequently Asked Questions ==
|
54 |
+
|
55 |
+
= I have activated the Rara One Click Demo Import plugin. Where can I find the plugin? =
|
56 |
+
|
57 |
+
You will find the plugin in *wp-admin -> Appearance -> Rara Demo Import*.
|
58 |
+
|
59 |
+
= Where are the demo import files and the log files saved? =
|
60 |
+
|
61 |
+
The files used in the demo import will be saved to the default WordPress uploads directory. An example of that directory would be: `../wp-content/uploads/2017/03/`.
|
62 |
+
|
63 |
+
The log file will be registered in the *wp-admin -> Media* section.
|
64 |
+
|
65 |
+
= I can't activate the plugin because of a fatal error. What can I do? =
|
66 |
+
|
67 |
+
*Update: There is an admin error notice, stating that the minimal PHP version required for this plugin is 5.3.2.*
|
68 |
+
|
69 |
+
You want to activate the plugin, but this error shows up:
|
70 |
+
|
71 |
+
*Plugin could not be activated because it triggered a fatal error*
|
72 |
+
|
73 |
+
This happens because your hosting server is using a very old version of PHP. This plugin requires PHP version of at least **5.3.x**, but we recommend version *5.6.x*. Please contact your hosting company and ask them to update the PHP version for your site.
|
74 |
+
|
75 |
+
== Screenshots ==
|
76 |
+
|
77 |
+
1. Upload Demo Button
|
78 |
+
2. Pro Theme Demo Screen
|
79 |
+
3. Free Theme Demo Import
|
80 |
+
|
81 |
+
== License ==
|
82 |
+
|
83 |
+
Rara One Click Demo Import uses the script of
|
84 |
+
'Theme Demo Import' plugin by Themely,
|
85 |
+
https://wordpress.org/plugins/theme-demo-import/
|
86 |
+
Licensed under the GNU General Public License v2.0,
|
87 |
+
http://www.gnu.org/licenses/gpl-2.0.html
|
88 |
+
|
89 |
+
Rara One Click Demo Import uses 'Wordpress Importer' plugin script
|
90 |
+
https://github.com/humanmade/WordPress-Importer
|
91 |
+
(C) 2016 @humanmade
|
92 |
+
Licensed under the GNU General Public License v2.0,
|
93 |
+
http://www.gnu.org/licenses/gpl-2.0.html
|
94 |
+
|
95 |
+
|
96 |
+
== Copyright ==
|
97 |
+
|
98 |
+
Rara One Click Demo Import is distributed under the terms of the GNU GPL.
|
99 |
+
|
100 |
+
This program is free software; you can redistribute it and/or modify
|
101 |
+
it under the terms of the GNU General Public License as published by
|
102 |
+
the Free Software Foundation; either version 2 of the License, or
|
103 |
+
any later version (at your own risk).
|
104 |
+
|
105 |
+
This program is distributed in the hope that it will be useful,
|
106 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
107 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
108 |
+
GNU General Public License for more details.
|
109 |
+
|
110 |
+
You should have received a copy of the GNU General Public License along
|
111 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
112 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
113 |
+
|
114 |
+
== Changelog ==
|
115 |
+
|
116 |
+
= 1.3.1 =
|
117 |
+
* Fixes: Deprecated an incorrect name filter.
|
118 |
+
* Fixes: Minor Bug Fixes.
|
119 |
+
|
120 |
+
= 1.3.0 =
|
121 |
+
* fixes: Fixed CSRF related security issues in demo file upload.
|
122 |
+
* Fixes: Minor Bug Fixes.
|
123 |
+
|
124 |
+
= 1.2.9 =
|
125 |
+
* WORDPRESS 5.6 AND PHP 8 COMPATIBILITY FIXES
|
126 |
+
|
127 |
+
= 1.2.8 =
|
128 |
+
* ARRAY OFFSET ACCESS SYNTAX WITH CURLY BRACES FIXED
|
129 |
+
|
130 |
+
= 1.2.7 =
|
131 |
+
* LINKS UPDATED
|
132 |
+
|
133 |
+
= 1.2.6 =
|
134 |
+
* UPLOAD BUTTON ISSUE FIXED
|
135 |
+
|
136 |
+
= 1.2.5 =
|
137 |
+
* INFORMATION ADDED
|
138 |
+
|
139 |
+
= 1.2.1 =
|
140 |
+
* COMPATIBILITY TEST
|
141 |
+
|
142 |
+
= 1.2.0 =
|
143 |
+
* MAJOR UPDATE
|
144 |
+
* DEMO FILE ZIP NAME STANDARDS
|
145 |
+
|
146 |
+
= 1.1.0 =
|
147 |
+
* WARNING MESSAGE FIXED
|
148 |
+
|
149 |
+
= 1.0.9 =
|
150 |
+
* WARNING MESSAGE FIXED
|
151 |
+
|
152 |
+
= 1.0.8 =
|
153 |
+
* CODE CLEAN UP & DESIGN FIXES
|
154 |
+
|
155 |
+
= 1.0.7 =
|
156 |
+
* CODE CLEAN UP
|
157 |
+
* SOME OPTIONAL FUNCTIONS REMOVED
|
158 |
+
|
159 |
+
= 1.0.6 =
|
160 |
+
* DEMO IMPORT PROCESS EASED
|
161 |
+
|
162 |
+
= 1.0.5 =
|
163 |
+
* RARA THEME DEPENDENT
|
164 |
+
|
165 |
+
= 1.0.4 =
|
166 |
+
* COMPATIBILITY TEST
|
167 |
+
|
168 |
+
= 1.0.3 =
|
169 |
+
* PLUGIN DEPENDENCY CHECK
|
170 |
+
* COMPATIBILITY TEST
|
171 |
+
|
172 |
+
= 1.0.2 =
|
173 |
+
* CODE CLEANUP
|
174 |
+
|
175 |
+
= 1.0.1 =
|
176 |
+
* CLASSES ADDED
|
177 |
+
* FILTERS ADDED
|
178 |
+
|
179 |
+
= 1.0.0 =
|
180 |
* INITIAL RELEASE
|