Version Description
- Fixed #3052,#3050,#3044,#3043,#3014 ,#3008,#3006,#3071,#3061
Download this release
Release Info
Developer | Unyson |
Plugin | Unyson |
Version | 2.7.11 |
Comparing to | |
See all releases |
Code changes from version 2.7.10 to 2.7.11
- framework/LICENSE +674 -674
- framework/autoload.php +306 -303
- framework/bin/load-latest-fonts.php +172 -172
- framework/bootstrap.php +79 -79
- framework/core/Fw.php +79 -79
- framework/core/class-fw-manifest.php +571 -564
- framework/core/components/backend.php +2062 -2054
- framework/core/components/backend/class-fw-settings-form-theme.php +217 -217
- framework/core/components/extensions.php +688 -685
- framework/core/components/extensions/class-fw-extension-default.php +11 -11
- framework/core/components/extensions/manager/available-extensions.php +336 -334
- framework/core/components/extensions/manager/class--fw-extensions-manager.php +3670 -3671
- framework/core/components/extensions/manager/includes/available-ext/class--fw-available-extensions-register.php +7 -7
- framework/core/components/extensions/manager/includes/available-ext/class-fw-available-extension.php +131 -131
- framework/core/components/extensions/manager/includes/class--fw-extensions-delete-upgrader-skin.php +28 -28
- framework/core/components/extensions/manager/includes/class--fw-extensions-install-upgrader-skin.php +28 -28
- framework/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source-register.php +9 -9
- framework/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source.php +21 -20
- framework/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-custom.php +209 -0
- framework/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-github.php +188 -187
- framework/core/components/extensions/manager/includes/download-source/types/init.php +10 -12
- framework/core/components/extensions/manager/includes/parsedown/LICENSE.txt +19 -19
- framework/core/components/extensions/manager/includes/parsedown/Parsedown.php +1527 -1527
- framework/core/components/extensions/manager/static/extension-page.css +22 -22
- framework/core/components/extensions/manager/static/extension-page.js +2 -2
- framework/core/components/extensions/manager/static/extensions-page.css +260 -260
- framework/core/components/extensions/manager/static/extensions-page.js +107 -107
- framework/core/components/extensions/manager/static/unyson-font-icon/fonts/icomoon.svg +10 -10
- framework/core/components/extensions/manager/static/unyson-font-icon/style.css +28 -28
- framework/core/components/extensions/manager/views/delete-form.php +54 -54
- framework/core/components/extensions/manager/views/extension-page-header.php +50 -50
- framework/core/components/extensions/manager/views/extension.php +246 -229
- framework/core/components/extensions/manager/views/extensions-page.php +267 -242
- framework/core/components/extensions/manager/views/install-form.php +51 -51
- framework/core/components/theme.php +203 -203
- framework/core/exceptions/class-fw-option-type-exception.php +39 -39
- framework/core/extends/class-fw-container-type.php +233 -233
- framework/core/extends/class-fw-extension.php +514 -514
- framework/core/extends/class-fw-option-type.php +465 -453
- framework/core/extends/interface-fw-option-handler.php +13 -13
- framework/extensions/blog/class-fw-extension-blog.php +89 -89
- framework/extensions/blog/manifest.php +13 -13
- framework/extensions/update/class-fw-extension-update.php +1005 -963
- framework/extensions/update/config.php +9 -9
- framework/extensions/update/extensions/custom-update/class-fw-extension-custom-update.php +254 -0
- framework/extensions/update/extensions/custom-update/manifest.php +5 -0
- framework/extensions/update/extensions/github-update/class-fw-extension-github-update.php +433 -443
- framework/extensions/update/extensions/github-update/manifest.php +5 -5
- framework/extensions/update/includes/classes/class--fw-ext-update-extensions-list-table.php +128 -128
- framework/extensions/update/includes/classes/class--fw-ext-update-extensions-upgrader-skin.php +36 -36
- framework/extensions/update/includes/classes/class--fw-ext-update-framework-upgrader-skin.php +33 -33
- framework/extensions/update/includes/classes/class--fw-ext-update-theme-upgrader-skin.php +33 -33
- framework/extensions/update/includes/extends/class-fw-ext-update-service.php +105 -105
- framework/extensions/update/manifest.php +10 -10
- framework/extensions/update/static.php +14 -14
- framework/extensions/update/static/css/admin-update-page.css +2 -2
- framework/extensions/update/views/updates-list.php +118 -113
- framework/helpers/class-fw-access-key.php +43 -43
- framework/helpers/class-fw-cache.php +308 -308
- framework/helpers/class-fw-callback.php +131 -131
- framework/helpers/class-fw-db-options-model.php +330 -319
- framework/helpers/class-fw-dumper.php +123 -123
- framework/helpers/class-fw-flash-messages.php +218 -218
- framework/helpers/class-fw-form.php +650 -650
- framework/helpers/class-fw-request.php +15 -90
framework/LICENSE
CHANGED
@@ -1,674 +1,674 @@
|
|
1 |
-
GNU GENERAL PUBLIC LICENSE
|
2 |
-
Version 3, 29 June 2007
|
3 |
-
|
4 |
-
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
5 |
-
Everyone is permitted to copy and distribute verbatim copies
|
6 |
-
of this license document, but changing it is not allowed.
|
7 |
-
|
8 |
-
Preamble
|
9 |
-
|
10 |
-
The GNU General Public License is a free, copyleft license for
|
11 |
-
software and other kinds of works.
|
12 |
-
|
13 |
-
The licenses for most software and other practical works are designed
|
14 |
-
to take away your freedom to share and change the works. By contrast,
|
15 |
-
the GNU General Public License is intended to guarantee your freedom to
|
16 |
-
share and change all versions of a program--to make sure it remains free
|
17 |
-
software for all its users. We, the Free Software Foundation, use the
|
18 |
-
GNU General Public License for most of our software; it applies also to
|
19 |
-
any other work released this way by its authors. You can apply it to
|
20 |
-
your programs, too.
|
21 |
-
|
22 |
-
When we speak of free software, we are referring to freedom, not
|
23 |
-
price. Our General Public Licenses are designed to make sure that you
|
24 |
-
have the freedom to distribute copies of free software (and charge for
|
25 |
-
them if you wish), that you receive source code or can get it if you
|
26 |
-
want it, that you can change the software or use pieces of it in new
|
27 |
-
free programs, and that you know you can do these things.
|
28 |
-
|
29 |
-
To protect your rights, we need to prevent others from denying you
|
30 |
-
these rights or asking you to surrender the rights. Therefore, you have
|
31 |
-
certain responsibilities if you distribute copies of the software, or if
|
32 |
-
you modify it: responsibilities to respect the freedom of others.
|
33 |
-
|
34 |
-
For example, if you distribute copies of such a program, whether
|
35 |
-
gratis or for a fee, you must pass on to the recipients the same
|
36 |
-
freedoms that you received. You must make sure that they, too, receive
|
37 |
-
or can get the source code. And you must show them these terms so they
|
38 |
-
know their rights.
|
39 |
-
|
40 |
-
Developers that use the GNU GPL protect your rights with two steps:
|
41 |
-
(1) assert copyright on the software, and (2) offer you this License
|
42 |
-
giving you legal permission to copy, distribute and/or modify it.
|
43 |
-
|
44 |
-
For the developers' and authors' protection, the GPL clearly explains
|
45 |
-
that there is no warranty for this free software. For both users' and
|
46 |
-
authors' sake, the GPL requires that modified versions be marked as
|
47 |
-
changed, so that their problems will not be attributed erroneously to
|
48 |
-
authors of previous versions.
|
49 |
-
|
50 |
-
Some devices are designed to deny users access to install or run
|
51 |
-
modified versions of the software inside them, although the manufacturer
|
52 |
-
can do so. This is fundamentally incompatible with the aim of
|
53 |
-
protecting users' freedom to change the software. The systematic
|
54 |
-
pattern of such abuse occurs in the area of products for individuals to
|
55 |
-
use, which is precisely where it is most unacceptable. Therefore, we
|
56 |
-
have designed this version of the GPL to prohibit the practice for those
|
57 |
-
products. If such problems arise substantially in other domains, we
|
58 |
-
stand ready to extend this provision to those domains in future versions
|
59 |
-
of the GPL, as needed to protect the freedom of users.
|
60 |
-
|
61 |
-
Finally, every program is threatened constantly by software patents.
|
62 |
-
States should not allow patents to restrict development and use of
|
63 |
-
software on general-purpose computers, but in those that do, we wish to
|
64 |
-
avoid the special danger that patents applied to a free program could
|
65 |
-
make it effectively proprietary. To prevent this, the GPL assures that
|
66 |
-
patents cannot be used to render the program non-free.
|
67 |
-
|
68 |
-
The precise terms and conditions for copying, distribution and
|
69 |
-
modification follow.
|
70 |
-
|
71 |
-
TERMS AND CONDITIONS
|
72 |
-
|
73 |
-
0. Definitions.
|
74 |
-
|
75 |
-
"This License" refers to version 3 of the GNU General Public License.
|
76 |
-
|
77 |
-
"Copyright" also means copyright-like laws that apply to other kinds of
|
78 |
-
works, such as semiconductor masks.
|
79 |
-
|
80 |
-
"The Program" refers to any copyrightable work licensed under this
|
81 |
-
License. Each licensee is addressed as "you". "Licensees" and
|
82 |
-
"recipients" may be individuals or organizations.
|
83 |
-
|
84 |
-
To "modify" a work means to copy from or adapt all or part of the work
|
85 |
-
in a fashion requiring copyright permission, other than the making of an
|
86 |
-
exact copy. The resulting work is called a "modified version" of the
|
87 |
-
earlier work or a work "based on" the earlier work.
|
88 |
-
|
89 |
-
A "covered work" means either the unmodified Program or a work based
|
90 |
-
on the Program.
|
91 |
-
|
92 |
-
To "propagate" a work means to do anything with it that, without
|
93 |
-
permission, would make you directly or secondarily liable for
|
94 |
-
infringement under applicable copyright law, except executing it on a
|
95 |
-
computer or modifying a private copy. Propagation includes copying,
|
96 |
-
distribution (with or without modification), making available to the
|
97 |
-
public, and in some countries other activities as well.
|
98 |
-
|
99 |
-
To "convey" a work means any kind of propagation that enables other
|
100 |
-
parties to make or receive copies. Mere interaction with a user through
|
101 |
-
a computer network, with no transfer of a copy, is not conveying.
|
102 |
-
|
103 |
-
An interactive user interface displays "Appropriate Legal Notices"
|
104 |
-
to the extent that it includes a convenient and prominently visible
|
105 |
-
feature that (1) displays an appropriate copyright notice, and (2)
|
106 |
-
tells the user that there is no warranty for the work (except to the
|
107 |
-
extent that warranties are provided), that licensees may convey the
|
108 |
-
work under this License, and how to view a copy of this License. If
|
109 |
-
the interface presents a list of user commands or options, such as a
|
110 |
-
menu, a prominent item in the list meets this criterion.
|
111 |
-
|
112 |
-
1. Source Code.
|
113 |
-
|
114 |
-
The "source code" for a work means the preferred form of the work
|
115 |
-
for making modifications to it. "Object code" means any non-source
|
116 |
-
form of a work.
|
117 |
-
|
118 |
-
A "Standard Interface" means an interface that either is an official
|
119 |
-
standard defined by a recognized standards body, or, in the case of
|
120 |
-
interfaces specified for a particular programming language, one that
|
121 |
-
is widely used among developers working in that language.
|
122 |
-
|
123 |
-
The "System Libraries" of an executable work include anything, other
|
124 |
-
than the work as a whole, that (a) is included in the normal form of
|
125 |
-
packaging a Major Component, but which is not part of that Major
|
126 |
-
Component, and (b) serves only to enable use of the work with that
|
127 |
-
Major Component, or to implement a Standard Interface for which an
|
128 |
-
implementation is available to the public in source code form. A
|
129 |
-
"Major Component", in this context, means a major essential component
|
130 |
-
(kernel, window system, and so on) of the specific operating system
|
131 |
-
(if any) on which the executable work runs, or a compiler used to
|
132 |
-
produce the work, or an object code interpreter used to run it.
|
133 |
-
|
134 |
-
The "Corresponding Source" for a work in object code form means all
|
135 |
-
the source code needed to generate, install, and (for an executable
|
136 |
-
work) run the object code and to modify the work, including scripts to
|
137 |
-
control those activities. However, it does not include the work's
|
138 |
-
System Libraries, or general-purpose tools or generally available free
|
139 |
-
programs which are used unmodified in performing those activities but
|
140 |
-
which are not part of the work. For example, Corresponding Source
|
141 |
-
includes interface definition files associated with source files for
|
142 |
-
the work, and the source code for shared libraries and dynamically
|
143 |
-
linked subprograms that the work is specifically designed to require,
|
144 |
-
such as by intimate data communication or control flow between those
|
145 |
-
subprograms and other parts of the work.
|
146 |
-
|
147 |
-
The Corresponding Source need not include anything that users
|
148 |
-
can regenerate automatically from other parts of the Corresponding
|
149 |
-
Source.
|
150 |
-
|
151 |
-
The Corresponding Source for a work in source code form is that
|
152 |
-
same work.
|
153 |
-
|
154 |
-
2. Basic Permissions.
|
155 |
-
|
156 |
-
All rights granted under this License are granted for the term of
|
157 |
-
copyright on the Program, and are irrevocable provided the stated
|
158 |
-
conditions are met. This License explicitly affirms your unlimited
|
159 |
-
permission to run the unmodified Program. The output from running a
|
160 |
-
covered work is covered by this License only if the output, given its
|
161 |
-
content, constitutes a covered work. This License acknowledges your
|
162 |
-
rights of fair use or other equivalent, as provided by copyright law.
|
163 |
-
|
164 |
-
You may make, run and propagate covered works that you do not
|
165 |
-
convey, without conditions so long as your license otherwise remains
|
166 |
-
in force. You may convey covered works to others for the sole purpose
|
167 |
-
of having them make modifications exclusively for you, or provide you
|
168 |
-
with facilities for running those works, provided that you comply with
|
169 |
-
the terms of this License in conveying all material for which you do
|
170 |
-
not control copyright. Those thus making or running the covered works
|
171 |
-
for you must do so exclusively on your behalf, under your direction
|
172 |
-
and control, on terms that prohibit them from making any copies of
|
173 |
-
your copyrighted material outside their relationship with you.
|
174 |
-
|
175 |
-
Conveying under any other circumstances is permitted solely under
|
176 |
-
the conditions stated below. Sublicensing is not allowed; section 10
|
177 |
-
makes it unnecessary.
|
178 |
-
|
179 |
-
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
180 |
-
|
181 |
-
No covered work shall be deemed part of an effective technological
|
182 |
-
measure under any applicable law fulfilling obligations under article
|
183 |
-
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
184 |
-
similar laws prohibiting or restricting circumvention of such
|
185 |
-
measures.
|
186 |
-
|
187 |
-
When you convey a covered work, you waive any legal power to forbid
|
188 |
-
circumvention of technological measures to the extent such circumvention
|
189 |
-
is effected by exercising rights under this License with respect to
|
190 |
-
the covered work, and you disclaim any intention to limit operation or
|
191 |
-
modification of the work as a means of enforcing, against the work's
|
192 |
-
users, your or third parties' legal rights to forbid circumvention of
|
193 |
-
technological measures.
|
194 |
-
|
195 |
-
4. Conveying Verbatim Copies.
|
196 |
-
|
197 |
-
You may convey verbatim copies of the Program's source code as you
|
198 |
-
receive it, in any medium, provided that you conspicuously and
|
199 |
-
appropriately publish on each copy an appropriate copyright notice;
|
200 |
-
keep intact all notices stating that this License and any
|
201 |
-
non-permissive terms added in accord with section 7 apply to the code;
|
202 |
-
keep intact all notices of the absence of any warranty; and give all
|
203 |
-
recipients a copy of this License along with the Program.
|
204 |
-
|
205 |
-
You may charge any price or no price for each copy that you convey,
|
206 |
-
and you may offer support or warranty protection for a fee.
|
207 |
-
|
208 |
-
5. Conveying Modified Source Versions.
|
209 |
-
|
210 |
-
You may convey a work based on the Program, or the modifications to
|
211 |
-
produce it from the Program, in the form of source code under the
|
212 |
-
terms of section 4, provided that you also meet all of these conditions:
|
213 |
-
|
214 |
-
a) The work must carry prominent notices stating that you modified
|
215 |
-
it, and giving a relevant date.
|
216 |
-
|
217 |
-
b) The work must carry prominent notices stating that it is
|
218 |
-
released under this License and any conditions added under section
|
219 |
-
7. This requirement modifies the requirement in section 4 to
|
220 |
-
"keep intact all notices".
|
221 |
-
|
222 |
-
c) You must license the entire work, as a whole, under this
|
223 |
-
License to anyone who comes into possession of a copy. This
|
224 |
-
License will therefore apply, along with any applicable section 7
|
225 |
-
additional terms, to the whole of the work, and all its parts,
|
226 |
-
regardless of how they are packaged. This License gives no
|
227 |
-
permission to license the work in any other way, but it does not
|
228 |
-
invalidate such permission if you have separately received it.
|
229 |
-
|
230 |
-
d) If the work has interactive user interfaces, each must display
|
231 |
-
Appropriate Legal Notices; however, if the Program has interactive
|
232 |
-
interfaces that do not display Appropriate Legal Notices, your
|
233 |
-
work need not make them do so.
|
234 |
-
|
235 |
-
A compilation of a covered work with other separate and independent
|
236 |
-
works, which are not by their nature extensions of the covered work,
|
237 |
-
and which are not combined with it such as to form a larger program,
|
238 |
-
in or on a volume of a storage or distribution medium, is called an
|
239 |
-
"aggregate" if the compilation and its resulting copyright are not
|
240 |
-
used to limit the access or legal rights of the compilation's users
|
241 |
-
beyond what the individual works permit. Inclusion of a covered work
|
242 |
-
in an aggregate does not cause this License to apply to the other
|
243 |
-
parts of the aggregate.
|
244 |
-
|
245 |
-
6. Conveying Non-Source Forms.
|
246 |
-
|
247 |
-
You may convey a covered work in object code form under the terms
|
248 |
-
of sections 4 and 5, provided that you also convey the
|
249 |
-
machine-readable Corresponding Source under the terms of this License,
|
250 |
-
in one of these ways:
|
251 |
-
|
252 |
-
a) Convey the object code in, or embodied in, a physical product
|
253 |
-
(including a physical distribution medium), accompanied by the
|
254 |
-
Corresponding Source fixed on a durable physical medium
|
255 |
-
customarily used for software interchange.
|
256 |
-
|
257 |
-
b) Convey the object code in, or embodied in, a physical product
|
258 |
-
(including a physical distribution medium), accompanied by a
|
259 |
-
written offer, valid for at least three years and valid for as
|
260 |
-
long as you offer spare parts or customer support for that product
|
261 |
-
model, to give anyone who possesses the object code either (1) a
|
262 |
-
copy of the Corresponding Source for all the software in the
|
263 |
-
product that is covered by this License, on a durable physical
|
264 |
-
medium customarily used for software interchange, for a price no
|
265 |
-
more than your reasonable cost of physically performing this
|
266 |
-
conveying of source, or (2) access to copy the
|
267 |
-
Corresponding Source from a network server at no charge.
|
268 |
-
|
269 |
-
c) Convey individual copies of the object code with a copy of the
|
270 |
-
written offer to provide the Corresponding Source. This
|
271 |
-
alternative is allowed only occasionally and noncommercially, and
|
272 |
-
only if you received the object code with such an offer, in accord
|
273 |
-
with subsection 6b.
|
274 |
-
|
275 |
-
d) Convey the object code by offering access from a designated
|
276 |
-
place (gratis or for a charge), and offer equivalent access to the
|
277 |
-
Corresponding Source in the same way through the same place at no
|
278 |
-
further charge. You need not require recipients to copy the
|
279 |
-
Corresponding Source along with the object code. If the place to
|
280 |
-
copy the object code is a network server, the Corresponding Source
|
281 |
-
may be on a different server (operated by you or a third party)
|
282 |
-
that supports equivalent copying facilities, provided you maintain
|
283 |
-
clear directions next to the object code saying where to find the
|
284 |
-
Corresponding Source. Regardless of what server hosts the
|
285 |
-
Corresponding Source, you remain obligated to ensure that it is
|
286 |
-
available for as long as needed to satisfy these requirements.
|
287 |
-
|
288 |
-
e) Convey the object code using peer-to-peer transmission, provided
|
289 |
-
you inform other peers where the object code and Corresponding
|
290 |
-
Source of the work are being offered to the general public at no
|
291 |
-
charge under subsection 6d.
|
292 |
-
|
293 |
-
A separable portion of the object code, whose source code is excluded
|
294 |
-
from the Corresponding Source as a System Library, need not be
|
295 |
-
included in conveying the object code work.
|
296 |
-
|
297 |
-
A "User Product" is either (1) a "consumer product", which means any
|
298 |
-
tangible personal property which is normally used for personal, family,
|
299 |
-
or household purposes, or (2) anything designed or sold for incorporation
|
300 |
-
into a dwelling. In determining whether a product is a consumer product,
|
301 |
-
doubtful cases shall be resolved in favor of coverage. For a particular
|
302 |
-
product received by a particular user, "normally used" refers to a
|
303 |
-
typical or common use of that class of product, regardless of the status
|
304 |
-
of the particular user or of the way in which the particular user
|
305 |
-
actually uses, or expects or is expected to use, the product. A product
|
306 |
-
is a consumer product regardless of whether the product has substantial
|
307 |
-
commercial, industrial or non-consumer uses, unless such uses represent
|
308 |
-
the only significant mode of use of the product.
|
309 |
-
|
310 |
-
"Installation Information" for a User Product means any methods,
|
311 |
-
procedures, authorization keys, or other information required to install
|
312 |
-
and execute modified versions of a covered work in that User Product from
|
313 |
-
a modified version of its Corresponding Source. The information must
|
314 |
-
suffice to ensure that the continued functioning of the modified object
|
315 |
-
code is in no case prevented or interfered with solely because
|
316 |
-
modification has been made.
|
317 |
-
|
318 |
-
If you convey an object code work under this section in, or with, or
|
319 |
-
specifically for use in, a User Product, and the conveying occurs as
|
320 |
-
part of a transaction in which the right of possession and use of the
|
321 |
-
User Product is transferred to the recipient in perpetuity or for a
|
322 |
-
fixed term (regardless of how the transaction is characterized), the
|
323 |
-
Corresponding Source conveyed under this section must be accompanied
|
324 |
-
by the Installation Information. But this requirement does not apply
|
325 |
-
if neither you nor any third party retains the ability to install
|
326 |
-
modified object code on the User Product (for example, the work has
|
327 |
-
been installed in ROM).
|
328 |
-
|
329 |
-
The requirement to provide Installation Information does not include a
|
330 |
-
requirement to continue to provide support service, warranty, or updates
|
331 |
-
for a work that has been modified or installed by the recipient, or for
|
332 |
-
the User Product in which it has been modified or installed. Access to a
|
333 |
-
network may be denied when the modification itself materially and
|
334 |
-
adversely affects the operation of the network or violates the rules and
|
335 |
-
protocols for communication across the network.
|
336 |
-
|
337 |
-
Corresponding Source conveyed, and Installation Information provided,
|
338 |
-
in accord with this section must be in a format that is publicly
|
339 |
-
documented (and with an implementation available to the public in
|
340 |
-
source code form), and must require no special password or key for
|
341 |
-
unpacking, reading or copying.
|
342 |
-
|
343 |
-
7. Additional Terms.
|
344 |
-
|
345 |
-
"Additional permissions" are terms that supplement the terms of this
|
346 |
-
License by making exceptions from one or more of its conditions.
|
347 |
-
Additional permissions that are applicable to the entire Program shall
|
348 |
-
be treated as though they were included in this License, to the extent
|
349 |
-
that they are valid under applicable law. If additional permissions
|
350 |
-
apply only to part of the Program, that part may be used separately
|
351 |
-
under those permissions, but the entire Program remains governed by
|
352 |
-
this License without regard to the additional permissions.
|
353 |
-
|
354 |
-
When you convey a copy of a covered work, you may at your option
|
355 |
-
remove any additional permissions from that copy, or from any part of
|
356 |
-
it. (Additional permissions may be written to require their own
|
357 |
-
removal in certain cases when you modify the work.) You may place
|
358 |
-
additional permissions on material, added by you to a covered work,
|
359 |
-
for which you have or can give appropriate copyright permission.
|
360 |
-
|
361 |
-
Notwithstanding any other provision of this License, for material you
|
362 |
-
add to a covered work, you may (if authorized by the copyright holders of
|
363 |
-
that material) supplement the terms of this License with terms:
|
364 |
-
|
365 |
-
a) Disclaiming warranty or limiting liability differently from the
|
366 |
-
terms of sections 15 and 16 of this License; or
|
367 |
-
|
368 |
-
b) Requiring preservation of specified reasonable legal notices or
|
369 |
-
author attributions in that material or in the Appropriate Legal
|
370 |
-
Notices displayed by works containing it; or
|
371 |
-
|
372 |
-
c) Prohibiting misrepresentation of the origin of that material, or
|
373 |
-
requiring that modified versions of such material be marked in
|
374 |
-
reasonable ways as different from the original version; or
|
375 |
-
|
376 |
-
d) Limiting the use for publicity purposes of names of licensors or
|
377 |
-
authors of the material; or
|
378 |
-
|
379 |
-
e) Declining to grant rights under trademark law for use of some
|
380 |
-
trade names, trademarks, or service marks; or
|
381 |
-
|
382 |
-
f) Requiring indemnification of licensors and authors of that
|
383 |
-
material by anyone who conveys the material (or modified versions of
|
384 |
-
it) with contractual assumptions of liability to the recipient, for
|
385 |
-
any liability that these contractual assumptions directly impose on
|
386 |
-
those licensors and authors.
|
387 |
-
|
388 |
-
All other non-permissive additional terms are considered "further
|
389 |
-
restrictions" within the meaning of section 10. If the Program as you
|
390 |
-
received it, or any part of it, contains a notice stating that it is
|
391 |
-
governed by this License along with a term that is a further
|
392 |
-
restriction, you may remove that term. If a license document contains
|
393 |
-
a further restriction but permits relicensing or conveying under this
|
394 |
-
License, you may add to a covered work material governed by the terms
|
395 |
-
of that license document, provided that the further restriction does
|
396 |
-
not survive such relicensing or conveying.
|
397 |
-
|
398 |
-
If you add terms to a covered work in accord with this section, you
|
399 |
-
must place, in the relevant source files, a statement of the
|
400 |
-
additional terms that apply to those files, or a notice indicating
|
401 |
-
where to find the applicable terms.
|
402 |
-
|
403 |
-
Additional terms, permissive or non-permissive, may be stated in the
|
404 |
-
form of a separately written license, or stated as exceptions;
|
405 |
-
the above requirements apply either way.
|
406 |
-
|
407 |
-
8. Termination.
|
408 |
-
|
409 |
-
You may not propagate or modify a covered work except as expressly
|
410 |
-
provided under this License. Any attempt otherwise to propagate or
|
411 |
-
modify it is void, and will automatically terminate your rights under
|
412 |
-
this License (including any patent licenses granted under the third
|
413 |
-
paragraph of section 11).
|
414 |
-
|
415 |
-
However, if you cease all violation of this License, then your
|
416 |
-
license from a particular copyright holder is reinstated (a)
|
417 |
-
provisionally, unless and until the copyright holder explicitly and
|
418 |
-
finally terminates your license, and (b) permanently, if the copyright
|
419 |
-
holder fails to notify you of the violation by some reasonable means
|
420 |
-
prior to 60 days after the cessation.
|
421 |
-
|
422 |
-
Moreover, your license from a particular copyright holder is
|
423 |
-
reinstated permanently if the copyright holder notifies you of the
|
424 |
-
violation by some reasonable means, this is the first time you have
|
425 |
-
received notice of violation of this License (for any work) from that
|
426 |
-
copyright holder, and you cure the violation prior to 30 days after
|
427 |
-
your receipt of the notice.
|
428 |
-
|
429 |
-
Termination of your rights under this section does not terminate the
|
430 |
-
licenses of parties who have received copies or rights from you under
|
431 |
-
this License. If your rights have been terminated and not permanently
|
432 |
-
reinstated, you do not qualify to receive new licenses for the same
|
433 |
-
material under section 10.
|
434 |
-
|
435 |
-
9. Acceptance Not Required for Having Copies.
|
436 |
-
|
437 |
-
You are not required to accept this License in order to receive or
|
438 |
-
run a copy of the Program. Ancillary propagation of a covered work
|
439 |
-
occurring solely as a consequence of using peer-to-peer transmission
|
440 |
-
to receive a copy likewise does not require acceptance. However,
|
441 |
-
nothing other than this License grants you permission to propagate or
|
442 |
-
modify any covered work. These actions infringe copyright if you do
|
443 |
-
not accept this License. Therefore, by modifying or propagating a
|
444 |
-
covered work, you indicate your acceptance of this License to do so.
|
445 |
-
|
446 |
-
10. Automatic Licensing of Downstream Recipients.
|
447 |
-
|
448 |
-
Each time you convey a covered work, the recipient automatically
|
449 |
-
receives a license from the original licensors, to run, modify and
|
450 |
-
propagate that work, subject to this License. You are not responsible
|
451 |
-
for enforcing compliance by third parties with this License.
|
452 |
-
|
453 |
-
An "entity transaction" is a transaction transferring control of an
|
454 |
-
organization, or substantially all assets of one, or subdividing an
|
455 |
-
organization, or merging organizations. If propagation of a covered
|
456 |
-
work results from an entity transaction, each party to that
|
457 |
-
transaction who receives a copy of the work also receives whatever
|
458 |
-
licenses to the work the party's predecessor in interest had or could
|
459 |
-
give under the previous paragraph, plus a right to possession of the
|
460 |
-
Corresponding Source of the work from the predecessor in interest, if
|
461 |
-
the predecessor has it or can get it with reasonable efforts.
|
462 |
-
|
463 |
-
You may not impose any further restrictions on the exercise of the
|
464 |
-
rights granted or affirmed under this License. For example, you may
|
465 |
-
not impose a license fee, royalty, or other charge for exercise of
|
466 |
-
rights granted under this License, and you may not initiate litigation
|
467 |
-
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
468 |
-
any patent claim is infringed by making, using, selling, offering for
|
469 |
-
sale, or importing the Program or any portion of it.
|
470 |
-
|
471 |
-
11. Patents.
|
472 |
-
|
473 |
-
A "contributor" is a copyright holder who authorizes use under this
|
474 |
-
License of the Program or a work on which the Program is based. The
|
475 |
-
work thus licensed is called the contributor's "contributor version".
|
476 |
-
|
477 |
-
A contributor's "essential patent claims" are all patent claims
|
478 |
-
owned or controlled by the contributor, whether already acquired or
|
479 |
-
hereafter acquired, that would be infringed by some manner, permitted
|
480 |
-
by this License, of making, using, or selling its contributor version,
|
481 |
-
but do not include claims that would be infringed only as a
|
482 |
-
consequence of further modification of the contributor version. For
|
483 |
-
purposes of this definition, "control" includes the right to grant
|
484 |
-
patent sublicenses in a manner consistent with the requirements of
|
485 |
-
this License.
|
486 |
-
|
487 |
-
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
488 |
-
patent license under the contributor's essential patent claims, to
|
489 |
-
make, use, sell, offer for sale, import and otherwise run, modify and
|
490 |
-
propagate the contents of its contributor version.
|
491 |
-
|
492 |
-
In the following three paragraphs, a "patent license" is any express
|
493 |
-
agreement or commitment, however denominated, not to enforce a patent
|
494 |
-
(such as an express permission to practice a patent or covenant not to
|
495 |
-
sue for patent infringement). To "grant" such a patent license to a
|
496 |
-
party means to make such an agreement or commitment not to enforce a
|
497 |
-
patent against the party.
|
498 |
-
|
499 |
-
If you convey a covered work, knowingly relying on a patent license,
|
500 |
-
and the Corresponding Source of the work is not available for anyone
|
501 |
-
to copy, free of charge and under the terms of this License, through a
|
502 |
-
publicly available network server or other readily accessible means,
|
503 |
-
then you must either (1) cause the Corresponding Source to be so
|
504 |
-
available, or (2) arrange to deprive yourself of the benefit of the
|
505 |
-
patent license for this particular work, or (3) arrange, in a manner
|
506 |
-
consistent with the requirements of this License, to extend the patent
|
507 |
-
license to downstream recipients. "Knowingly relying" means you have
|
508 |
-
actual knowledge that, but for the patent license, your conveying the
|
509 |
-
covered work in a country, or your recipient's use of the covered work
|
510 |
-
in a country, would infringe one or more identifiable patents in that
|
511 |
-
country that you have reason to believe are valid.
|
512 |
-
|
513 |
-
If, pursuant to or in connection with a single transaction or
|
514 |
-
arrangement, you convey, or propagate by procuring conveyance of, a
|
515 |
-
covered work, and grant a patent license to some of the parties
|
516 |
-
receiving the covered work authorizing them to use, propagate, modify
|
517 |
-
or convey a specific copy of the covered work, then the patent license
|
518 |
-
you grant is automatically extended to all recipients of the covered
|
519 |
-
work and works based on it.
|
520 |
-
|
521 |
-
A patent license is "discriminatory" if it does not include within
|
522 |
-
the scope of its coverage, prohibits the exercise of, or is
|
523 |
-
conditioned on the non-exercise of one or more of the rights that are
|
524 |
-
specifically granted under this License. You may not convey a covered
|
525 |
-
work if you are a party to an arrangement with a third party that is
|
526 |
-
in the business of distributing software, under which you make payment
|
527 |
-
to the third party based on the extent of your activity of conveying
|
528 |
-
the work, and under which the third party grants, to any of the
|
529 |
-
parties who would receive the covered work from you, a discriminatory
|
530 |
-
patent license (a) in connection with copies of the covered work
|
531 |
-
conveyed by you (or copies made from those copies), or (b) primarily
|
532 |
-
for and in connection with specific products or compilations that
|
533 |
-
contain the covered work, unless you entered into that arrangement,
|
534 |
-
or that patent license was granted, prior to 28 March 2007.
|
535 |
-
|
536 |
-
Nothing in this License shall be construed as excluding or limiting
|
537 |
-
any implied license or other defenses to infringement that may
|
538 |
-
otherwise be available to you under applicable patent law.
|
539 |
-
|
540 |
-
12. No Surrender of Others' Freedom.
|
541 |
-
|
542 |
-
If conditions are imposed on you (whether by court order, agreement or
|
543 |
-
otherwise) that contradict the conditions of this License, they do not
|
544 |
-
excuse you from the conditions of this License. If you cannot convey a
|
545 |
-
covered work so as to satisfy simultaneously your obligations under this
|
546 |
-
License and any other pertinent obligations, then as a consequence you may
|
547 |
-
not convey it at all. For example, if you agree to terms that obligate you
|
548 |
-
to collect a royalty for further conveying from those to whom you convey
|
549 |
-
the Program, the only way you could satisfy both those terms and this
|
550 |
-
License would be to refrain entirely from conveying the Program.
|
551 |
-
|
552 |
-
13. Use with the GNU Affero General Public License.
|
553 |
-
|
554 |
-
Notwithstanding any other provision of this License, you have
|
555 |
-
permission to link or combine any covered work with a work licensed
|
556 |
-
under version 3 of the GNU Affero General Public License into a single
|
557 |
-
combined work, and to convey the resulting work. The terms of this
|
558 |
-
License will continue to apply to the part which is the covered work,
|
559 |
-
but the special requirements of the GNU Affero General Public License,
|
560 |
-
section 13, concerning interaction through a network will apply to the
|
561 |
-
combination as such.
|
562 |
-
|
563 |
-
14. Revised Versions of this License.
|
564 |
-
|
565 |
-
The Free Software Foundation may publish revised and/or new versions of
|
566 |
-
the GNU General Public License from time to time. Such new versions will
|
567 |
-
be similar in spirit to the present version, but may differ in detail to
|
568 |
-
address new problems or concerns.
|
569 |
-
|
570 |
-
Each version is given a distinguishing version number. If the
|
571 |
-
Program specifies that a certain numbered version of the GNU General
|
572 |
-
Public License "or any later version" applies to it, you have the
|
573 |
-
option of following the terms and conditions either of that numbered
|
574 |
-
version or of any later version published by the Free Software
|
575 |
-
Foundation. If the Program does not specify a version number of the
|
576 |
-
GNU General Public License, you may choose any version ever published
|
577 |
-
by the Free Software Foundation.
|
578 |
-
|
579 |
-
If the Program specifies that a proxy can decide which future
|
580 |
-
versions of the GNU General Public License can be used, that proxy's
|
581 |
-
public statement of acceptance of a version permanently authorizes you
|
582 |
-
to choose that version for the Program.
|
583 |
-
|
584 |
-
Later license versions may give you additional or different
|
585 |
-
permissions. However, no additional obligations are imposed on any
|
586 |
-
author or copyright holder as a result of your choosing to follow a
|
587 |
-
later version.
|
588 |
-
|
589 |
-
15. Disclaimer of Warranty.
|
590 |
-
|
591 |
-
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
592 |
-
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
593 |
-
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
594 |
-
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
595 |
-
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
596 |
-
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
597 |
-
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
598 |
-
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
599 |
-
|
600 |
-
16. Limitation of Liability.
|
601 |
-
|
602 |
-
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
603 |
-
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
604 |
-
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
605 |
-
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
606 |
-
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
607 |
-
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
608 |
-
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
609 |
-
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
610 |
-
SUCH DAMAGES.
|
611 |
-
|
612 |
-
17. Interpretation of Sections 15 and 16.
|
613 |
-
|
614 |
-
If the disclaimer of warranty and limitation of liability provided
|
615 |
-
above cannot be given local legal effect according to their terms,
|
616 |
-
reviewing courts shall apply local law that most closely approximates
|
617 |
-
an absolute waiver of all civil liability in connection with the
|
618 |
-
Program, unless a warranty or assumption of liability accompanies a
|
619 |
-
copy of the Program in return for a fee.
|
620 |
-
|
621 |
-
END OF TERMS AND CONDITIONS
|
622 |
-
|
623 |
-
How to Apply These Terms to Your New Programs
|
624 |
-
|
625 |
-
If you develop a new program, and you want it to be of the greatest
|
626 |
-
possible use to the public, the best way to achieve this is to make it
|
627 |
-
free software which everyone can redistribute and change under these terms.
|
628 |
-
|
629 |
-
To do so, attach the following notices to the program. It is safest
|
630 |
-
to attach them to the start of each source file to most effectively
|
631 |
-
state the exclusion of warranty; and each file should have at least
|
632 |
-
the "copyright" line and a pointer to where the full notice is found.
|
633 |
-
|
634 |
-
{one line to give the program's name and a brief idea of what it does.}
|
635 |
-
Copyright (C) {year} {name of author}
|
636 |
-
|
637 |
-
This program is free software: you can redistribute it and/or modify
|
638 |
-
it under the terms of the GNU General Public License as published by
|
639 |
-
the Free Software Foundation, either version 3 of the License, or
|
640 |
-
(at your option) any later version.
|
641 |
-
|
642 |
-
This program is distributed in the hope that it will be useful,
|
643 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
644 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
645 |
-
GNU General Public License for more details.
|
646 |
-
|
647 |
-
You should have received a copy of the GNU General Public License
|
648 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
649 |
-
|
650 |
-
Also add information on how to contact you by electronic and paper mail.
|
651 |
-
|
652 |
-
If the program does terminal interaction, make it output a short
|
653 |
-
notice like this when it starts in an interactive mode:
|
654 |
-
|
655 |
-
{project} Copyright (C) {year} {fullname}
|
656 |
-
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
657 |
-
This is free software, and you are welcome to redistribute it
|
658 |
-
under certain conditions; type `show c' for details.
|
659 |
-
|
660 |
-
The hypothetical commands `show w' and `show c' should show the appropriate
|
661 |
-
parts of the General Public License. Of course, your program's commands
|
662 |
-
might be different; for a GUI interface, you would use an "about box".
|
663 |
-
|
664 |
-
You should also get your employer (if you work as a programmer) or school,
|
665 |
-
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
666 |
-
For more information on this, and how to apply and follow the GNU GPL, see
|
667 |
-
<http://www.gnu.org/licenses/>.
|
668 |
-
|
669 |
-
The GNU General Public License does not permit incorporating your program
|
670 |
-
into proprietary programs. If your program is a subroutine library, you
|
671 |
-
may consider it more useful to permit linking proprietary applications with
|
672 |
-
the library. If this is what you want to do, use the GNU Lesser General
|
673 |
-
Public License instead of this License. But first, please read
|
674 |
-
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
1 |
+
GNU GENERAL PUBLIC LICENSE
|
2 |
+
Version 3, 29 June 2007
|
3 |
+
|
4 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
5 |
+
Everyone is permitted to copy and distribute verbatim copies
|
6 |
+
of this license document, but changing it is not allowed.
|
7 |
+
|
8 |
+
Preamble
|
9 |
+
|
10 |
+
The GNU General Public License is a free, copyleft license for
|
11 |
+
software and other kinds of works.
|
12 |
+
|
13 |
+
The licenses for most software and other practical works are designed
|
14 |
+
to take away your freedom to share and change the works. By contrast,
|
15 |
+
the GNU General Public License is intended to guarantee your freedom to
|
16 |
+
share and change all versions of a program--to make sure it remains free
|
17 |
+
software for all its users. We, the Free Software Foundation, use the
|
18 |
+
GNU General Public License for most of our software; it applies also to
|
19 |
+
any other work released this way by its authors. You can apply it to
|
20 |
+
your programs, too.
|
21 |
+
|
22 |
+
When we speak of free software, we are referring to freedom, not
|
23 |
+
price. Our General Public Licenses are designed to make sure that you
|
24 |
+
have the freedom to distribute copies of free software (and charge for
|
25 |
+
them if you wish), that you receive source code or can get it if you
|
26 |
+
want it, that you can change the software or use pieces of it in new
|
27 |
+
free programs, and that you know you can do these things.
|
28 |
+
|
29 |
+
To protect your rights, we need to prevent others from denying you
|
30 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
31 |
+
certain responsibilities if you distribute copies of the software, or if
|
32 |
+
you modify it: responsibilities to respect the freedom of others.
|
33 |
+
|
34 |
+
For example, if you distribute copies of such a program, whether
|
35 |
+
gratis or for a fee, you must pass on to the recipients the same
|
36 |
+
freedoms that you received. You must make sure that they, too, receive
|
37 |
+
or can get the source code. And you must show them these terms so they
|
38 |
+
know their rights.
|
39 |
+
|
40 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
41 |
+
(1) assert copyright on the software, and (2) offer you this License
|
42 |
+
giving you legal permission to copy, distribute and/or modify it.
|
43 |
+
|
44 |
+
For the developers' and authors' protection, the GPL clearly explains
|
45 |
+
that there is no warranty for this free software. For both users' and
|
46 |
+
authors' sake, the GPL requires that modified versions be marked as
|
47 |
+
changed, so that their problems will not be attributed erroneously to
|
48 |
+
authors of previous versions.
|
49 |
+
|
50 |
+
Some devices are designed to deny users access to install or run
|
51 |
+
modified versions of the software inside them, although the manufacturer
|
52 |
+
can do so. This is fundamentally incompatible with the aim of
|
53 |
+
protecting users' freedom to change the software. The systematic
|
54 |
+
pattern of such abuse occurs in the area of products for individuals to
|
55 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
56 |
+
have designed this version of the GPL to prohibit the practice for those
|
57 |
+
products. If such problems arise substantially in other domains, we
|
58 |
+
stand ready to extend this provision to those domains in future versions
|
59 |
+
of the GPL, as needed to protect the freedom of users.
|
60 |
+
|
61 |
+
Finally, every program is threatened constantly by software patents.
|
62 |
+
States should not allow patents to restrict development and use of
|
63 |
+
software on general-purpose computers, but in those that do, we wish to
|
64 |
+
avoid the special danger that patents applied to a free program could
|
65 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
66 |
+
patents cannot be used to render the program non-free.
|
67 |
+
|
68 |
+
The precise terms and conditions for copying, distribution and
|
69 |
+
modification follow.
|
70 |
+
|
71 |
+
TERMS AND CONDITIONS
|
72 |
+
|
73 |
+
0. Definitions.
|
74 |
+
|
75 |
+
"This License" refers to version 3 of the GNU General Public License.
|
76 |
+
|
77 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
78 |
+
works, such as semiconductor masks.
|
79 |
+
|
80 |
+
"The Program" refers to any copyrightable work licensed under this
|
81 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
82 |
+
"recipients" may be individuals or organizations.
|
83 |
+
|
84 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
85 |
+
in a fashion requiring copyright permission, other than the making of an
|
86 |
+
exact copy. The resulting work is called a "modified version" of the
|
87 |
+
earlier work or a work "based on" the earlier work.
|
88 |
+
|
89 |
+
A "covered work" means either the unmodified Program or a work based
|
90 |
+
on the Program.
|
91 |
+
|
92 |
+
To "propagate" a work means to do anything with it that, without
|
93 |
+
permission, would make you directly or secondarily liable for
|
94 |
+
infringement under applicable copyright law, except executing it on a
|
95 |
+
computer or modifying a private copy. Propagation includes copying,
|
96 |
+
distribution (with or without modification), making available to the
|
97 |
+
public, and in some countries other activities as well.
|
98 |
+
|
99 |
+
To "convey" a work means any kind of propagation that enables other
|
100 |
+
parties to make or receive copies. Mere interaction with a user through
|
101 |
+
a computer network, with no transfer of a copy, is not conveying.
|
102 |
+
|
103 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
104 |
+
to the extent that it includes a convenient and prominently visible
|
105 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
106 |
+
tells the user that there is no warranty for the work (except to the
|
107 |
+
extent that warranties are provided), that licensees may convey the
|
108 |
+
work under this License, and how to view a copy of this License. If
|
109 |
+
the interface presents a list of user commands or options, such as a
|
110 |
+
menu, a prominent item in the list meets this criterion.
|
111 |
+
|
112 |
+
1. Source Code.
|
113 |
+
|
114 |
+
The "source code" for a work means the preferred form of the work
|
115 |
+
for making modifications to it. "Object code" means any non-source
|
116 |
+
form of a work.
|
117 |
+
|
118 |
+
A "Standard Interface" means an interface that either is an official
|
119 |
+
standard defined by a recognized standards body, or, in the case of
|
120 |
+
interfaces specified for a particular programming language, one that
|
121 |
+
is widely used among developers working in that language.
|
122 |
+
|
123 |
+
The "System Libraries" of an executable work include anything, other
|
124 |
+
than the work as a whole, that (a) is included in the normal form of
|
125 |
+
packaging a Major Component, but which is not part of that Major
|
126 |
+
Component, and (b) serves only to enable use of the work with that
|
127 |
+
Major Component, or to implement a Standard Interface for which an
|
128 |
+
implementation is available to the public in source code form. A
|
129 |
+
"Major Component", in this context, means a major essential component
|
130 |
+
(kernel, window system, and so on) of the specific operating system
|
131 |
+
(if any) on which the executable work runs, or a compiler used to
|
132 |
+
produce the work, or an object code interpreter used to run it.
|
133 |
+
|
134 |
+
The "Corresponding Source" for a work in object code form means all
|
135 |
+
the source code needed to generate, install, and (for an executable
|
136 |
+
work) run the object code and to modify the work, including scripts to
|
137 |
+
control those activities. However, it does not include the work's
|
138 |
+
System Libraries, or general-purpose tools or generally available free
|
139 |
+
programs which are used unmodified in performing those activities but
|
140 |
+
which are not part of the work. For example, Corresponding Source
|
141 |
+
includes interface definition files associated with source files for
|
142 |
+
the work, and the source code for shared libraries and dynamically
|
143 |
+
linked subprograms that the work is specifically designed to require,
|
144 |
+
such as by intimate data communication or control flow between those
|
145 |
+
subprograms and other parts of the work.
|
146 |
+
|
147 |
+
The Corresponding Source need not include anything that users
|
148 |
+
can regenerate automatically from other parts of the Corresponding
|
149 |
+
Source.
|
150 |
+
|
151 |
+
The Corresponding Source for a work in source code form is that
|
152 |
+
same work.
|
153 |
+
|
154 |
+
2. Basic Permissions.
|
155 |
+
|
156 |
+
All rights granted under this License are granted for the term of
|
157 |
+
copyright on the Program, and are irrevocable provided the stated
|
158 |
+
conditions are met. This License explicitly affirms your unlimited
|
159 |
+
permission to run the unmodified Program. The output from running a
|
160 |
+
covered work is covered by this License only if the output, given its
|
161 |
+
content, constitutes a covered work. This License acknowledges your
|
162 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
163 |
+
|
164 |
+
You may make, run and propagate covered works that you do not
|
165 |
+
convey, without conditions so long as your license otherwise remains
|
166 |
+
in force. You may convey covered works to others for the sole purpose
|
167 |
+
of having them make modifications exclusively for you, or provide you
|
168 |
+
with facilities for running those works, provided that you comply with
|
169 |
+
the terms of this License in conveying all material for which you do
|
170 |
+
not control copyright. Those thus making or running the covered works
|
171 |
+
for you must do so exclusively on your behalf, under your direction
|
172 |
+
and control, on terms that prohibit them from making any copies of
|
173 |
+
your copyrighted material outside their relationship with you.
|
174 |
+
|
175 |
+
Conveying under any other circumstances is permitted solely under
|
176 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
177 |
+
makes it unnecessary.
|
178 |
+
|
179 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
180 |
+
|
181 |
+
No covered work shall be deemed part of an effective technological
|
182 |
+
measure under any applicable law fulfilling obligations under article
|
183 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
184 |
+
similar laws prohibiting or restricting circumvention of such
|
185 |
+
measures.
|
186 |
+
|
187 |
+
When you convey a covered work, you waive any legal power to forbid
|
188 |
+
circumvention of technological measures to the extent such circumvention
|
189 |
+
is effected by exercising rights under this License with respect to
|
190 |
+
the covered work, and you disclaim any intention to limit operation or
|
191 |
+
modification of the work as a means of enforcing, against the work's
|
192 |
+
users, your or third parties' legal rights to forbid circumvention of
|
193 |
+
technological measures.
|
194 |
+
|
195 |
+
4. Conveying Verbatim Copies.
|
196 |
+
|
197 |
+
You may convey verbatim copies of the Program's source code as you
|
198 |
+
receive it, in any medium, provided that you conspicuously and
|
199 |
+
appropriately publish on each copy an appropriate copyright notice;
|
200 |
+
keep intact all notices stating that this License and any
|
201 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
202 |
+
keep intact all notices of the absence of any warranty; and give all
|
203 |
+
recipients a copy of this License along with the Program.
|
204 |
+
|
205 |
+
You may charge any price or no price for each copy that you convey,
|
206 |
+
and you may offer support or warranty protection for a fee.
|
207 |
+
|
208 |
+
5. Conveying Modified Source Versions.
|
209 |
+
|
210 |
+
You may convey a work based on the Program, or the modifications to
|
211 |
+
produce it from the Program, in the form of source code under the
|
212 |
+
terms of section 4, provided that you also meet all of these conditions:
|
213 |
+
|
214 |
+
a) The work must carry prominent notices stating that you modified
|
215 |
+
it, and giving a relevant date.
|
216 |
+
|
217 |
+
b) The work must carry prominent notices stating that it is
|
218 |
+
released under this License and any conditions added under section
|
219 |
+
7. This requirement modifies the requirement in section 4 to
|
220 |
+
"keep intact all notices".
|
221 |
+
|
222 |
+
c) You must license the entire work, as a whole, under this
|
223 |
+
License to anyone who comes into possession of a copy. This
|
224 |
+
License will therefore apply, along with any applicable section 7
|
225 |
+
additional terms, to the whole of the work, and all its parts,
|
226 |
+
regardless of how they are packaged. This License gives no
|
227 |
+
permission to license the work in any other way, but it does not
|
228 |
+
invalidate such permission if you have separately received it.
|
229 |
+
|
230 |
+
d) If the work has interactive user interfaces, each must display
|
231 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
232 |
+
interfaces that do not display Appropriate Legal Notices, your
|
233 |
+
work need not make them do so.
|
234 |
+
|
235 |
+
A compilation of a covered work with other separate and independent
|
236 |
+
works, which are not by their nature extensions of the covered work,
|
237 |
+
and which are not combined with it such as to form a larger program,
|
238 |
+
in or on a volume of a storage or distribution medium, is called an
|
239 |
+
"aggregate" if the compilation and its resulting copyright are not
|
240 |
+
used to limit the access or legal rights of the compilation's users
|
241 |
+
beyond what the individual works permit. Inclusion of a covered work
|
242 |
+
in an aggregate does not cause this License to apply to the other
|
243 |
+
parts of the aggregate.
|
244 |
+
|
245 |
+
6. Conveying Non-Source Forms.
|
246 |
+
|
247 |
+
You may convey a covered work in object code form under the terms
|
248 |
+
of sections 4 and 5, provided that you also convey the
|
249 |
+
machine-readable Corresponding Source under the terms of this License,
|
250 |
+
in one of these ways:
|
251 |
+
|
252 |
+
a) Convey the object code in, or embodied in, a physical product
|
253 |
+
(including a physical distribution medium), accompanied by the
|
254 |
+
Corresponding Source fixed on a durable physical medium
|
255 |
+
customarily used for software interchange.
|
256 |
+
|
257 |
+
b) Convey the object code in, or embodied in, a physical product
|
258 |
+
(including a physical distribution medium), accompanied by a
|
259 |
+
written offer, valid for at least three years and valid for as
|
260 |
+
long as you offer spare parts or customer support for that product
|
261 |
+
model, to give anyone who possesses the object code either (1) a
|
262 |
+
copy of the Corresponding Source for all the software in the
|
263 |
+
product that is covered by this License, on a durable physical
|
264 |
+
medium customarily used for software interchange, for a price no
|
265 |
+
more than your reasonable cost of physically performing this
|
266 |
+
conveying of source, or (2) access to copy the
|
267 |
+
Corresponding Source from a network server at no charge.
|
268 |
+
|
269 |
+
c) Convey individual copies of the object code with a copy of the
|
270 |
+
written offer to provide the Corresponding Source. This
|
271 |
+
alternative is allowed only occasionally and noncommercially, and
|
272 |
+
only if you received the object code with such an offer, in accord
|
273 |
+
with subsection 6b.
|
274 |
+
|
275 |
+
d) Convey the object code by offering access from a designated
|
276 |
+
place (gratis or for a charge), and offer equivalent access to the
|
277 |
+
Corresponding Source in the same way through the same place at no
|
278 |
+
further charge. You need not require recipients to copy the
|
279 |
+
Corresponding Source along with the object code. If the place to
|
280 |
+
copy the object code is a network server, the Corresponding Source
|
281 |
+
may be on a different server (operated by you or a third party)
|
282 |
+
that supports equivalent copying facilities, provided you maintain
|
283 |
+
clear directions next to the object code saying where to find the
|
284 |
+
Corresponding Source. Regardless of what server hosts the
|
285 |
+
Corresponding Source, you remain obligated to ensure that it is
|
286 |
+
available for as long as needed to satisfy these requirements.
|
287 |
+
|
288 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
289 |
+
you inform other peers where the object code and Corresponding
|
290 |
+
Source of the work are being offered to the general public at no
|
291 |
+
charge under subsection 6d.
|
292 |
+
|
293 |
+
A separable portion of the object code, whose source code is excluded
|
294 |
+
from the Corresponding Source as a System Library, need not be
|
295 |
+
included in conveying the object code work.
|
296 |
+
|
297 |
+
A "User Product" is either (1) a "consumer product", which means any
|
298 |
+
tangible personal property which is normally used for personal, family,
|
299 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
300 |
+
into a dwelling. In determining whether a product is a consumer product,
|
301 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
302 |
+
product received by a particular user, "normally used" refers to a
|
303 |
+
typical or common use of that class of product, regardless of the status
|
304 |
+
of the particular user or of the way in which the particular user
|
305 |
+
actually uses, or expects or is expected to use, the product. A product
|
306 |
+
is a consumer product regardless of whether the product has substantial
|
307 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
308 |
+
the only significant mode of use of the product.
|
309 |
+
|
310 |
+
"Installation Information" for a User Product means any methods,
|
311 |
+
procedures, authorization keys, or other information required to install
|
312 |
+
and execute modified versions of a covered work in that User Product from
|
313 |
+
a modified version of its Corresponding Source. The information must
|
314 |
+
suffice to ensure that the continued functioning of the modified object
|
315 |
+
code is in no case prevented or interfered with solely because
|
316 |
+
modification has been made.
|
317 |
+
|
318 |
+
If you convey an object code work under this section in, or with, or
|
319 |
+
specifically for use in, a User Product, and the conveying occurs as
|
320 |
+
part of a transaction in which the right of possession and use of the
|
321 |
+
User Product is transferred to the recipient in perpetuity or for a
|
322 |
+
fixed term (regardless of how the transaction is characterized), the
|
323 |
+
Corresponding Source conveyed under this section must be accompanied
|
324 |
+
by the Installation Information. But this requirement does not apply
|
325 |
+
if neither you nor any third party retains the ability to install
|
326 |
+
modified object code on the User Product (for example, the work has
|
327 |
+
been installed in ROM).
|
328 |
+
|
329 |
+
The requirement to provide Installation Information does not include a
|
330 |
+
requirement to continue to provide support service, warranty, or updates
|
331 |
+
for a work that has been modified or installed by the recipient, or for
|
332 |
+
the User Product in which it has been modified or installed. Access to a
|
333 |
+
network may be denied when the modification itself materially and
|
334 |
+
adversely affects the operation of the network or violates the rules and
|
335 |
+
protocols for communication across the network.
|
336 |
+
|
337 |
+
Corresponding Source conveyed, and Installation Information provided,
|
338 |
+
in accord with this section must be in a format that is publicly
|
339 |
+
documented (and with an implementation available to the public in
|
340 |
+
source code form), and must require no special password or key for
|
341 |
+
unpacking, reading or copying.
|
342 |
+
|
343 |
+
7. Additional Terms.
|
344 |
+
|
345 |
+
"Additional permissions" are terms that supplement the terms of this
|
346 |
+
License by making exceptions from one or more of its conditions.
|
347 |
+
Additional permissions that are applicable to the entire Program shall
|
348 |
+
be treated as though they were included in this License, to the extent
|
349 |
+
that they are valid under applicable law. If additional permissions
|
350 |
+
apply only to part of the Program, that part may be used separately
|
351 |
+
under those permissions, but the entire Program remains governed by
|
352 |
+
this License without regard to the additional permissions.
|
353 |
+
|
354 |
+
When you convey a copy of a covered work, you may at your option
|
355 |
+
remove any additional permissions from that copy, or from any part of
|
356 |
+
it. (Additional permissions may be written to require their own
|
357 |
+
removal in certain cases when you modify the work.) You may place
|
358 |
+
additional permissions on material, added by you to a covered work,
|
359 |
+
for which you have or can give appropriate copyright permission.
|
360 |
+
|
361 |
+
Notwithstanding any other provision of this License, for material you
|
362 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
363 |
+
that material) supplement the terms of this License with terms:
|
364 |
+
|
365 |
+
a) Disclaiming warranty or limiting liability differently from the
|
366 |
+
terms of sections 15 and 16 of this License; or
|
367 |
+
|
368 |
+
b) Requiring preservation of specified reasonable legal notices or
|
369 |
+
author attributions in that material or in the Appropriate Legal
|
370 |
+
Notices displayed by works containing it; or
|
371 |
+
|
372 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
373 |
+
requiring that modified versions of such material be marked in
|
374 |
+
reasonable ways as different from the original version; or
|
375 |
+
|
376 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
377 |
+
authors of the material; or
|
378 |
+
|
379 |
+
e) Declining to grant rights under trademark law for use of some
|
380 |
+
trade names, trademarks, or service marks; or
|
381 |
+
|
382 |
+
f) Requiring indemnification of licensors and authors of that
|
383 |
+
material by anyone who conveys the material (or modified versions of
|
384 |
+
it) with contractual assumptions of liability to the recipient, for
|
385 |
+
any liability that these contractual assumptions directly impose on
|
386 |
+
those licensors and authors.
|
387 |
+
|
388 |
+
All other non-permissive additional terms are considered "further
|
389 |
+
restrictions" within the meaning of section 10. If the Program as you
|
390 |
+
received it, or any part of it, contains a notice stating that it is
|
391 |
+
governed by this License along with a term that is a further
|
392 |
+
restriction, you may remove that term. If a license document contains
|
393 |
+
a further restriction but permits relicensing or conveying under this
|
394 |
+
License, you may add to a covered work material governed by the terms
|
395 |
+
of that license document, provided that the further restriction does
|
396 |
+
not survive such relicensing or conveying.
|
397 |
+
|
398 |
+
If you add terms to a covered work in accord with this section, you
|
399 |
+
must place, in the relevant source files, a statement of the
|
400 |
+
additional terms that apply to those files, or a notice indicating
|
401 |
+
where to find the applicable terms.
|
402 |
+
|
403 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
404 |
+
form of a separately written license, or stated as exceptions;
|
405 |
+
the above requirements apply either way.
|
406 |
+
|
407 |
+
8. Termination.
|
408 |
+
|
409 |
+
You may not propagate or modify a covered work except as expressly
|
410 |
+
provided under this License. Any attempt otherwise to propagate or
|
411 |
+
modify it is void, and will automatically terminate your rights under
|
412 |
+
this License (including any patent licenses granted under the third
|
413 |
+
paragraph of section 11).
|
414 |
+
|
415 |
+
However, if you cease all violation of this License, then your
|
416 |
+
license from a particular copyright holder is reinstated (a)
|
417 |
+
provisionally, unless and until the copyright holder explicitly and
|
418 |
+
finally terminates your license, and (b) permanently, if the copyright
|
419 |
+
holder fails to notify you of the violation by some reasonable means
|
420 |
+
prior to 60 days after the cessation.
|
421 |
+
|
422 |
+
Moreover, your license from a particular copyright holder is
|
423 |
+
reinstated permanently if the copyright holder notifies you of the
|
424 |
+
violation by some reasonable means, this is the first time you have
|
425 |
+
received notice of violation of this License (for any work) from that
|
426 |
+
copyright holder, and you cure the violation prior to 30 days after
|
427 |
+
your receipt of the notice.
|
428 |
+
|
429 |
+
Termination of your rights under this section does not terminate the
|
430 |
+
licenses of parties who have received copies or rights from you under
|
431 |
+
this License. If your rights have been terminated and not permanently
|
432 |
+
reinstated, you do not qualify to receive new licenses for the same
|
433 |
+
material under section 10.
|
434 |
+
|
435 |
+
9. Acceptance Not Required for Having Copies.
|
436 |
+
|
437 |
+
You are not required to accept this License in order to receive or
|
438 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
439 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
440 |
+
to receive a copy likewise does not require acceptance. However,
|
441 |
+
nothing other than this License grants you permission to propagate or
|
442 |
+
modify any covered work. These actions infringe copyright if you do
|
443 |
+
not accept this License. Therefore, by modifying or propagating a
|
444 |
+
covered work, you indicate your acceptance of this License to do so.
|
445 |
+
|
446 |
+
10. Automatic Licensing of Downstream Recipients.
|
447 |
+
|
448 |
+
Each time you convey a covered work, the recipient automatically
|
449 |
+
receives a license from the original licensors, to run, modify and
|
450 |
+
propagate that work, subject to this License. You are not responsible
|
451 |
+
for enforcing compliance by third parties with this License.
|
452 |
+
|
453 |
+
An "entity transaction" is a transaction transferring control of an
|
454 |
+
organization, or substantially all assets of one, or subdividing an
|
455 |
+
organization, or merging organizations. If propagation of a covered
|
456 |
+
work results from an entity transaction, each party to that
|
457 |
+
transaction who receives a copy of the work also receives whatever
|
458 |
+
licenses to the work the party's predecessor in interest had or could
|
459 |
+
give under the previous paragraph, plus a right to possession of the
|
460 |
+
Corresponding Source of the work from the predecessor in interest, if
|
461 |
+
the predecessor has it or can get it with reasonable efforts.
|
462 |
+
|
463 |
+
You may not impose any further restrictions on the exercise of the
|
464 |
+
rights granted or affirmed under this License. For example, you may
|
465 |
+
not impose a license fee, royalty, or other charge for exercise of
|
466 |
+
rights granted under this License, and you may not initiate litigation
|
467 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
468 |
+
any patent claim is infringed by making, using, selling, offering for
|
469 |
+
sale, or importing the Program or any portion of it.
|
470 |
+
|
471 |
+
11. Patents.
|
472 |
+
|
473 |
+
A "contributor" is a copyright holder who authorizes use under this
|
474 |
+
License of the Program or a work on which the Program is based. The
|
475 |
+
work thus licensed is called the contributor's "contributor version".
|
476 |
+
|
477 |
+
A contributor's "essential patent claims" are all patent claims
|
478 |
+
owned or controlled by the contributor, whether already acquired or
|
479 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
480 |
+
by this License, of making, using, or selling its contributor version,
|
481 |
+
but do not include claims that would be infringed only as a
|
482 |
+
consequence of further modification of the contributor version. For
|
483 |
+
purposes of this definition, "control" includes the right to grant
|
484 |
+
patent sublicenses in a manner consistent with the requirements of
|
485 |
+
this License.
|
486 |
+
|
487 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
488 |
+
patent license under the contributor's essential patent claims, to
|
489 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
490 |
+
propagate the contents of its contributor version.
|
491 |
+
|
492 |
+
In the following three paragraphs, a "patent license" is any express
|
493 |
+
agreement or commitment, however denominated, not to enforce a patent
|
494 |
+
(such as an express permission to practice a patent or covenant not to
|
495 |
+
sue for patent infringement). To "grant" such a patent license to a
|
496 |
+
party means to make such an agreement or commitment not to enforce a
|
497 |
+
patent against the party.
|
498 |
+
|
499 |
+
If you convey a covered work, knowingly relying on a patent license,
|
500 |
+
and the Corresponding Source of the work is not available for anyone
|
501 |
+
to copy, free of charge and under the terms of this License, through a
|
502 |
+
publicly available network server or other readily accessible means,
|
503 |
+
then you must either (1) cause the Corresponding Source to be so
|
504 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
505 |
+
patent license for this particular work, or (3) arrange, in a manner
|
506 |
+
consistent with the requirements of this License, to extend the patent
|
507 |
+
license to downstream recipients. "Knowingly relying" means you have
|
508 |
+
actual knowledge that, but for the patent license, your conveying the
|
509 |
+
covered work in a country, or your recipient's use of the covered work
|
510 |
+
in a country, would infringe one or more identifiable patents in that
|
511 |
+
country that you have reason to believe are valid.
|
512 |
+
|
513 |
+
If, pursuant to or in connection with a single transaction or
|
514 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
515 |
+
covered work, and grant a patent license to some of the parties
|
516 |
+
receiving the covered work authorizing them to use, propagate, modify
|
517 |
+
or convey a specific copy of the covered work, then the patent license
|
518 |
+
you grant is automatically extended to all recipients of the covered
|
519 |
+
work and works based on it.
|
520 |
+
|
521 |
+
A patent license is "discriminatory" if it does not include within
|
522 |
+
the scope of its coverage, prohibits the exercise of, or is
|
523 |
+
conditioned on the non-exercise of one or more of the rights that are
|
524 |
+
specifically granted under this License. You may not convey a covered
|
525 |
+
work if you are a party to an arrangement with a third party that is
|
526 |
+
in the business of distributing software, under which you make payment
|
527 |
+
to the third party based on the extent of your activity of conveying
|
528 |
+
the work, and under which the third party grants, to any of the
|
529 |
+
parties who would receive the covered work from you, a discriminatory
|
530 |
+
patent license (a) in connection with copies of the covered work
|
531 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
532 |
+
for and in connection with specific products or compilations that
|
533 |
+
contain the covered work, unless you entered into that arrangement,
|
534 |
+
or that patent license was granted, prior to 28 March 2007.
|
535 |
+
|
536 |
+
Nothing in this License shall be construed as excluding or limiting
|
537 |
+
any implied license or other defenses to infringement that may
|
538 |
+
otherwise be available to you under applicable patent law.
|
539 |
+
|
540 |
+
12. No Surrender of Others' Freedom.
|
541 |
+
|
542 |
+
If conditions are imposed on you (whether by court order, agreement or
|
543 |
+
otherwise) that contradict the conditions of this License, they do not
|
544 |
+
excuse you from the conditions of this License. If you cannot convey a
|
545 |
+
covered work so as to satisfy simultaneously your obligations under this
|
546 |
+
License and any other pertinent obligations, then as a consequence you may
|
547 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
548 |
+
to collect a royalty for further conveying from those to whom you convey
|
549 |
+
the Program, the only way you could satisfy both those terms and this
|
550 |
+
License would be to refrain entirely from conveying the Program.
|
551 |
+
|
552 |
+
13. Use with the GNU Affero General Public License.
|
553 |
+
|
554 |
+
Notwithstanding any other provision of this License, you have
|
555 |
+
permission to link or combine any covered work with a work licensed
|
556 |
+
under version 3 of the GNU Affero General Public License into a single
|
557 |
+
combined work, and to convey the resulting work. The terms of this
|
558 |
+
License will continue to apply to the part which is the covered work,
|
559 |
+
but the special requirements of the GNU Affero General Public License,
|
560 |
+
section 13, concerning interaction through a network will apply to the
|
561 |
+
combination as such.
|
562 |
+
|
563 |
+
14. Revised Versions of this License.
|
564 |
+
|
565 |
+
The Free Software Foundation may publish revised and/or new versions of
|
566 |
+
the GNU General Public License from time to time. Such new versions will
|
567 |
+
be similar in spirit to the present version, but may differ in detail to
|
568 |
+
address new problems or concerns.
|
569 |
+
|
570 |
+
Each version is given a distinguishing version number. If the
|
571 |
+
Program specifies that a certain numbered version of the GNU General
|
572 |
+
Public License "or any later version" applies to it, you have the
|
573 |
+
option of following the terms and conditions either of that numbered
|
574 |
+
version or of any later version published by the Free Software
|
575 |
+
Foundation. If the Program does not specify a version number of the
|
576 |
+
GNU General Public License, you may choose any version ever published
|
577 |
+
by the Free Software Foundation.
|
578 |
+
|
579 |
+
If the Program specifies that a proxy can decide which future
|
580 |
+
versions of the GNU General Public License can be used, that proxy's
|
581 |
+
public statement of acceptance of a version permanently authorizes you
|
582 |
+
to choose that version for the Program.
|
583 |
+
|
584 |
+
Later license versions may give you additional or different
|
585 |
+
permissions. However, no additional obligations are imposed on any
|
586 |
+
author or copyright holder as a result of your choosing to follow a
|
587 |
+
later version.
|
588 |
+
|
589 |
+
15. Disclaimer of Warranty.
|
590 |
+
|
591 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
592 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
593 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
594 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
595 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
596 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
597 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
598 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
599 |
+
|
600 |
+
16. Limitation of Liability.
|
601 |
+
|
602 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
603 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
604 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
605 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
606 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
607 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
608 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
609 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
610 |
+
SUCH DAMAGES.
|
611 |
+
|
612 |
+
17. Interpretation of Sections 15 and 16.
|
613 |
+
|
614 |
+
If the disclaimer of warranty and limitation of liability provided
|
615 |
+
above cannot be given local legal effect according to their terms,
|
616 |
+
reviewing courts shall apply local law that most closely approximates
|
617 |
+
an absolute waiver of all civil liability in connection with the
|
618 |
+
Program, unless a warranty or assumption of liability accompanies a
|
619 |
+
copy of the Program in return for a fee.
|
620 |
+
|
621 |
+
END OF TERMS AND CONDITIONS
|
622 |
+
|
623 |
+
How to Apply These Terms to Your New Programs
|
624 |
+
|
625 |
+
If you develop a new program, and you want it to be of the greatest
|
626 |
+
possible use to the public, the best way to achieve this is to make it
|
627 |
+
free software which everyone can redistribute and change under these terms.
|
628 |
+
|
629 |
+
To do so, attach the following notices to the program. It is safest
|
630 |
+
to attach them to the start of each source file to most effectively
|
631 |
+
state the exclusion of warranty; and each file should have at least
|
632 |
+
the "copyright" line and a pointer to where the full notice is found.
|
633 |
+
|
634 |
+
{one line to give the program's name and a brief idea of what it does.}
|
635 |
+
Copyright (C) {year} {name of author}
|
636 |
+
|
637 |
+
This program is free software: you can redistribute it and/or modify
|
638 |
+
it under the terms of the GNU General Public License as published by
|
639 |
+
the Free Software Foundation, either version 3 of the License, or
|
640 |
+
(at your option) any later version.
|
641 |
+
|
642 |
+
This program is distributed in the hope that it will be useful,
|
643 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
644 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
645 |
+
GNU General Public License for more details.
|
646 |
+
|
647 |
+
You should have received a copy of the GNU General Public License
|
648 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
649 |
+
|
650 |
+
Also add information on how to contact you by electronic and paper mail.
|
651 |
+
|
652 |
+
If the program does terminal interaction, make it output a short
|
653 |
+
notice like this when it starts in an interactive mode:
|
654 |
+
|
655 |
+
{project} Copyright (C) {year} {fullname}
|
656 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
657 |
+
This is free software, and you are welcome to redistribute it
|
658 |
+
under certain conditions; type `show c' for details.
|
659 |
+
|
660 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
661 |
+
parts of the General Public License. Of course, your program's commands
|
662 |
+
might be different; for a GUI interface, you would use an "about box".
|
663 |
+
|
664 |
+
You should also get your employer (if you work as a programmer) or school,
|
665 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
666 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
667 |
+
<http://www.gnu.org/licenses/>.
|
668 |
+
|
669 |
+
The GNU General Public License does not permit incorporating your program
|
670 |
+
into proprietary programs. If your program is a subroutine library, you
|
671 |
+
may consider it more useful to permit linking proprietary applications with
|
672 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
673 |
+
Public License instead of this License. But first, please read
|
674 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
framework/autoload.php
CHANGED
@@ -1,304 +1,307 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
spl_autoload_register( '_fw_core_autoload' );
|
6 |
-
function _fw_core_autoload( $class ) {
|
7 |
-
switch ( $class ) {
|
8 |
-
case 'FW_Manifest' :
|
9 |
-
case 'FW_Framework_Manifest' :
|
10 |
-
case 'FW_Theme_Manifest' :
|
11 |
-
case 'FW_Extension_Manifest' :
|
12 |
-
require_once dirname( __FILE__ ) . '/core/class-fw-manifest.php';
|
13 |
-
break;
|
14 |
-
}
|
15 |
-
}
|
16 |
-
|
17 |
-
spl_autoload_register( '_fw_core_components_autoload' );
|
18 |
-
function _fw_core_components_autoload( $class ) {
|
19 |
-
switch ( $class ) {
|
20 |
-
case '_FW_Component_Backend' :
|
21 |
-
require_once dirname( __FILE__ ) . '/core/components/backend.php';
|
22 |
-
break;
|
23 |
-
case '_FW_Component_Extensions' :
|
24 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions.php';
|
25 |
-
break;
|
26 |
-
case '_FW_Component_Theme' :
|
27 |
-
require_once dirname( __FILE__ ) . '/core/components/theme.php';
|
28 |
-
break;
|
29 |
-
case 'FW_Settings_Form_Theme' :
|
30 |
-
require_once dirname( __FILE__ ) . '/core/components/backend/class-fw-settings-form-theme.php';
|
31 |
-
break;
|
32 |
-
}
|
33 |
-
}
|
34 |
-
|
35 |
-
spl_autoload_register( '_fw_core_components_extensions_autoload' );
|
36 |
-
function _fw_core_components_extensions_autoload( $class ) {
|
37 |
-
switch ( $class ) {
|
38 |
-
case 'FW_Extension_Default' :
|
39 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/class-fw-extension-default.php';
|
40 |
-
break;
|
41 |
-
case '_FW_Extensions_Manager' :
|
42 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/class--fw-extensions-manager.php';
|
43 |
-
break;
|
44 |
-
case '_FW_Extensions_Delete_Upgrader_Skin' :
|
45 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/class--fw-extensions-delete-upgrader-skin.php';
|
46 |
-
break;
|
47 |
-
case '_FW_Extensions_Install_Upgrader_Skin' :
|
48 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/class--fw-extensions-install-upgrader-skin.php';
|
49 |
-
break;
|
50 |
-
case 'Parsedown' :
|
51 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/parsedown/Parsedown.php';
|
52 |
-
break;
|
53 |
-
case 'FW_Ext_Download_Source' :
|
54 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source.php';
|
55 |
-
break;
|
56 |
-
case '_FW_Ext_Download_Source_Register' :
|
57 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source-register.php';
|
58 |
-
break;
|
59 |
-
case 'FW_Ext_Download_Source_Github' :
|
60 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-github.php';
|
61 |
-
break;
|
62 |
-
case '
|
63 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/
|
64 |
-
break;
|
65 |
-
case '
|
66 |
-
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/available-ext/class
|
67 |
-
break;
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
case '
|
78 |
-
require_once dirname( __FILE__ ) . '/core/extends/class-fw-
|
79 |
-
break;
|
80 |
-
case '
|
81 |
-
require_once dirname( __FILE__ ) . '/core/extends/class-fw-
|
82 |
-
break;
|
83 |
-
case '
|
84 |
-
require_once dirname( __FILE__ ) . '/core/extends/
|
85 |
-
break;
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
case '
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
'
|
108 |
-
'
|
109 |
-
'
|
110 |
-
'
|
111 |
-
'
|
112 |
-
'
|
113 |
-
'
|
114 |
-
'
|
115 |
-
'
|
116 |
-
'
|
117 |
-
'
|
118 |
-
'
|
119 |
-
'
|
120 |
-
'
|
121 |
-
'
|
122 |
-
'
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
case '
|
138 |
-
require_once dirname( __FILE__ ) . '/includes/container-types/
|
139 |
-
break;
|
140 |
-
case '
|
141 |
-
require_once dirname( __FILE__ ) . '/includes/container-types/
|
142 |
-
break;
|
143 |
-
case '
|
144 |
-
require_once dirname( __FILE__ ) . '/includes/container-types/
|
145 |
-
break;
|
146 |
-
case '
|
147 |
-
require_once dirname( __FILE__ ) . '/includes/container-types/
|
148 |
-
break;
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
case '
|
159 |
-
require_once dirname( __FILE__ ) . '/includes/customizer/class--fw-customizer-
|
160 |
-
break;
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
case '
|
171 |
-
require_once dirname( __FILE__ ) . '/includes/option-storage/class
|
172 |
-
break;
|
173 |
-
case '
|
174 |
-
require_once dirname( __FILE__ ) . '/includes/option-storage/
|
175 |
-
break;
|
176 |
-
case '
|
177 |
-
require_once dirname( __FILE__ ) . '/includes/option-storage/type/class-fw-option-storage-type-
|
178 |
-
break;
|
179 |
-
case '
|
180 |
-
require_once dirname( __FILE__ ) . '/includes/option-storage/type/class-fw-option-storage-type-
|
181 |
-
break;
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
case '
|
192 |
-
|
193 |
-
|
194 |
-
case '
|
195 |
-
case '
|
196 |
-
case '
|
197 |
-
case '
|
198 |
-
case '
|
199 |
-
case '
|
200 |
-
case '
|
201 |
-
case '
|
202 |
-
case '
|
203 |
-
case '
|
204 |
-
case '
|
205 |
-
case '
|
206 |
-
case '
|
207 |
-
|
208 |
-
|
209 |
-
case '
|
210 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
211 |
-
break;
|
212 |
-
case '
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
case '
|
217 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/addable-
|
218 |
-
break;
|
219 |
-
case '
|
220 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
221 |
-
break;
|
222 |
-
case '
|
223 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
224 |
-
break;
|
225 |
-
case '
|
226 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
227 |
-
break;
|
228 |
-
case '
|
229 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
230 |
-
break;
|
231 |
-
case '
|
232 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/datetime-
|
233 |
-
break;
|
234 |
-
case '
|
235 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
236 |
-
break;
|
237 |
-
case '
|
238 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
239 |
-
break;
|
240 |
-
case '
|
241 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/icon
|
242 |
-
break;
|
243 |
-
case '
|
244 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
245 |
-
break;
|
246 |
-
case '
|
247 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
248 |
-
break;
|
249 |
-
case '
|
250 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
251 |
-
break;
|
252 |
-
case '
|
253 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/multi
|
254 |
-
break;
|
255 |
-
case '
|
256 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/multi-
|
257 |
-
break;
|
258 |
-
case '
|
259 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/multi-
|
260 |
-
break;
|
261 |
-
case '
|
262 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
263 |
-
break;
|
264 |
-
case '
|
265 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
266 |
-
break;
|
267 |
-
case '
|
268 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
269 |
-
break;
|
270 |
-
case '
|
271 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
272 |
-
break;
|
273 |
-
case '
|
274 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
275 |
-
break;
|
276 |
-
case '
|
277 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
278 |
-
break;
|
279 |
-
case '
|
280 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/slider/class-fw-option-type-
|
281 |
-
break;
|
282 |
-
case '
|
283 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
284 |
-
break;
|
285 |
-
case '
|
286 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
287 |
-
break;
|
288 |
-
case '
|
289 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/typography
|
290 |
-
break;
|
291 |
-
case '
|
292 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
293 |
-
break;
|
294 |
-
case '
|
295 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
296 |
-
break;
|
297 |
-
case '
|
298 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/
|
299 |
-
break;
|
300 |
-
case '
|
301 |
-
require_once dirname( __FILE__ ) . '/includes/option-types/icon-v2/includes/class-fw-icon-v2-
|
302 |
-
break;
|
303 |
-
|
|
|
|
|
|
|
304 |
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
spl_autoload_register( '_fw_core_autoload' );
|
6 |
+
function _fw_core_autoload( $class ) {
|
7 |
+
switch ( $class ) {
|
8 |
+
case 'FW_Manifest' :
|
9 |
+
case 'FW_Framework_Manifest' :
|
10 |
+
case 'FW_Theme_Manifest' :
|
11 |
+
case 'FW_Extension_Manifest' :
|
12 |
+
require_once dirname( __FILE__ ) . '/core/class-fw-manifest.php';
|
13 |
+
break;
|
14 |
+
}
|
15 |
+
}
|
16 |
+
|
17 |
+
spl_autoload_register( '_fw_core_components_autoload' );
|
18 |
+
function _fw_core_components_autoload( $class ) {
|
19 |
+
switch ( $class ) {
|
20 |
+
case '_FW_Component_Backend' :
|
21 |
+
require_once dirname( __FILE__ ) . '/core/components/backend.php';
|
22 |
+
break;
|
23 |
+
case '_FW_Component_Extensions' :
|
24 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions.php';
|
25 |
+
break;
|
26 |
+
case '_FW_Component_Theme' :
|
27 |
+
require_once dirname( __FILE__ ) . '/core/components/theme.php';
|
28 |
+
break;
|
29 |
+
case 'FW_Settings_Form_Theme' :
|
30 |
+
require_once dirname( __FILE__ ) . '/core/components/backend/class-fw-settings-form-theme.php';
|
31 |
+
break;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
spl_autoload_register( '_fw_core_components_extensions_autoload' );
|
36 |
+
function _fw_core_components_extensions_autoload( $class ) {
|
37 |
+
switch ( $class ) {
|
38 |
+
case 'FW_Extension_Default' :
|
39 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/class-fw-extension-default.php';
|
40 |
+
break;
|
41 |
+
case '_FW_Extensions_Manager' :
|
42 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/class--fw-extensions-manager.php';
|
43 |
+
break;
|
44 |
+
case '_FW_Extensions_Delete_Upgrader_Skin' :
|
45 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/class--fw-extensions-delete-upgrader-skin.php';
|
46 |
+
break;
|
47 |
+
case '_FW_Extensions_Install_Upgrader_Skin' :
|
48 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/class--fw-extensions-install-upgrader-skin.php';
|
49 |
+
break;
|
50 |
+
case 'Parsedown' :
|
51 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/parsedown/Parsedown.php';
|
52 |
+
break;
|
53 |
+
case 'FW_Ext_Download_Source' :
|
54 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source.php';
|
55 |
+
break;
|
56 |
+
case '_FW_Ext_Download_Source_Register' :
|
57 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source-register.php';
|
58 |
+
break;
|
59 |
+
case 'FW_Ext_Download_Source_Github' :
|
60 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-github.php';
|
61 |
+
break;
|
62 |
+
case 'FW_Ext_Download_Source_Custom' :
|
63 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-custom.php';
|
64 |
+
break;
|
65 |
+
case '_FW_Available_Extensions_Register' :
|
66 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/available-ext/class--fw-available-extensions-register.php';
|
67 |
+
break;
|
68 |
+
case 'FW_Available_Extension' :
|
69 |
+
require_once dirname( __FILE__ ) . '/core/components/extensions/manager/includes/available-ext/class-fw-available-extension.php';
|
70 |
+
break;
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
spl_autoload_register( '_fw_core_extends_autoload' );
|
75 |
+
function _fw_core_extends_autoload( $class ) {
|
76 |
+
switch ( $class ) {
|
77 |
+
case 'FW_Container_Type' :
|
78 |
+
require_once dirname( __FILE__ ) . '/core/extends/class-fw-container-type.php';
|
79 |
+
break;
|
80 |
+
case 'FW_Option_Type' :
|
81 |
+
require_once dirname( __FILE__ ) . '/core/extends/class-fw-option-type.php';
|
82 |
+
break;
|
83 |
+
case 'FW_Extension' :
|
84 |
+
require_once dirname( __FILE__ ) . '/core/extends/class-fw-extension.php';
|
85 |
+
break;
|
86 |
+
case 'FW_Option_Handler' :
|
87 |
+
require_once dirname( __FILE__ ) . '/core/extends/interface-fw-option-handler.php';
|
88 |
+
break;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
spl_autoload_register( '_fw_code_exceptions_autoload' );
|
93 |
+
function _fw_code_exceptions_autoload( $class ) {
|
94 |
+
switch ( $class ) {
|
95 |
+
case 'FW_Option_Type_Exception' :
|
96 |
+
case 'FW_Option_Type_Exception_Not_Found' :
|
97 |
+
case 'FW_Option_Type_Exception_Invalid_Class' :
|
98 |
+
case 'FW_Option_Type_Exception_Already_Registered' :
|
99 |
+
require_once dirname( __FILE__ ) . '/core/exceptions/class-fw-option-type-exception.php';
|
100 |
+
break;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
// Autoload helper classes
|
105 |
+
function _fw_autoload_helper_classes($class) {
|
106 |
+
static $class_to_file = array(
|
107 |
+
'FW_Dumper' => 'class-fw-dumper',
|
108 |
+
'FW_Cache' => 'class-fw-cache',
|
109 |
+
'FW_Callback' => 'class-fw-callback',
|
110 |
+
'FW_Access_Key' => 'class-fw-access-key',
|
111 |
+
'FW_WP_Filesystem' => 'class-fw-wp-filesystem',
|
112 |
+
'FW_Form' => 'class-fw-form',
|
113 |
+
'FW_Form_Not_Found_Exception' => 'exceptions/class-fw-form-not-found-exception',
|
114 |
+
'FW_Form_Invalid_Submission_Exception' => 'exceptions/class-fw-form-invalid-submission-exception',
|
115 |
+
'FW_Settings_Form' => 'class-fw-settings-form',
|
116 |
+
'FW_Request' => 'class-fw-request',
|
117 |
+
'FW_Session' => 'class-fw-session',
|
118 |
+
'FW_WP_Option' => 'class-fw-wp-option',
|
119 |
+
'FW_WP_Meta' => 'class-fw-wp-meta',
|
120 |
+
'FW_Db_Options_Model' => 'class-fw-db-options-model',
|
121 |
+
'FW_Flash_Messages' => 'class-fw-flash-messages',
|
122 |
+
'FW_Resize' => 'class-fw-resize',
|
123 |
+
'FW_WP_List_Table' => 'class-fw-wp-list-table',
|
124 |
+
'FW_Type' => 'type/class-fw-type',
|
125 |
+
'FW_Type_Register' => 'type/class-fw-type-register',
|
126 |
+
);
|
127 |
+
|
128 |
+
if (isset($class_to_file[$class])) {
|
129 |
+
require dirname(__FILE__) .'/helpers/'. $class_to_file[$class] .'.php';
|
130 |
+
}
|
131 |
+
}
|
132 |
+
spl_autoload_register('_fw_autoload_helper_classes');
|
133 |
+
|
134 |
+
spl_autoload_register( '_fw_includes_container_types_autoload' );
|
135 |
+
function _fw_includes_container_types_autoload( $class ) {
|
136 |
+
switch ( $class ) {
|
137 |
+
case 'FW_Container_Type_Undefined' :
|
138 |
+
require_once dirname( __FILE__ ) . '/includes/container-types/class-fw-container-type-undefined.php';
|
139 |
+
break;
|
140 |
+
case 'FW_Container_Type_Group' :
|
141 |
+
require_once dirname( __FILE__ ) . '/includes/container-types/simple.php';
|
142 |
+
break;
|
143 |
+
case 'FW_Container_Type_Box' :
|
144 |
+
require_once dirname( __FILE__ ) . '/includes/container-types/box/class-fw-container-type-box.php';
|
145 |
+
break;
|
146 |
+
case 'FW_Container_Type_Popup' :
|
147 |
+
require_once dirname( __FILE__ ) . '/includes/container-types/popup/class-fw-container-type-popup.php';
|
148 |
+
break;
|
149 |
+
case 'FW_Container_Type_Tab' :
|
150 |
+
require_once dirname( __FILE__ ) . '/includes/container-types/tab/class-fw-container-type-tab.php';
|
151 |
+
break;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
spl_autoload_register( '_fw_includes_customizer_autoload' );
|
156 |
+
function _fw_includes_customizer_autoload( $class ) {
|
157 |
+
switch ( $class ) {
|
158 |
+
case '_FW_Customizer_Control_Option_Wrapper' :
|
159 |
+
require_once dirname( __FILE__ ) . '/includes/customizer/class--fw-customizer-control-option-wrapper.php';
|
160 |
+
break;
|
161 |
+
case '_FW_Customizer_Setting_Option' :
|
162 |
+
require_once dirname( __FILE__ ) . '/includes/customizer/class--fw-customizer-setting-option.php';
|
163 |
+
break;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
spl_autoload_register( '_fw_includes_option_storage_autoload' );
|
168 |
+
function _fw_includes_option_storage_autoload( $class ) {
|
169 |
+
switch ( $class ) {
|
170 |
+
case '_FW_Option_Storage_Type_Register' :
|
171 |
+
require_once dirname( __FILE__ ) . '/includes/option-storage/class--fw-option-storage-type-register.php';
|
172 |
+
break;
|
173 |
+
case 'FW_Option_Storage_Type' :
|
174 |
+
require_once dirname( __FILE__ ) . '/includes/option-storage/class-fw-option-storage-type.php';
|
175 |
+
break;
|
176 |
+
case 'FW_Option_Storage_Type_Post_Meta' :
|
177 |
+
require_once dirname( __FILE__ ) . '/includes/option-storage/type/class-fw-option-storage-type-post-meta.php';
|
178 |
+
break;
|
179 |
+
case 'FW_Option_Storage_Type_Term_Meta' :
|
180 |
+
require_once dirname( __FILE__ ) . '/includes/option-storage/type/class-fw-option-storage-type-term-meta.php';
|
181 |
+
break;
|
182 |
+
case 'FW_Option_Storage_Type_WP_Option' :
|
183 |
+
require_once dirname( __FILE__ ) . '/includes/option-storage/type/class-fw-option-storage-type-wp-option.php';
|
184 |
+
break;
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
spl_autoload_register( '_fw_includes_option_types_autoload' );
|
189 |
+
function _fw_includes_option_types_autoload( $class ) {
|
190 |
+
switch ( $class ) {
|
191 |
+
case 'FW_Option_Type_Undefined' :
|
192 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/class-fw-option-type-undefined.php';
|
193 |
+
break;
|
194 |
+
case 'FW_Option_Type_Hidden' :
|
195 |
+
case 'FW_Option_Type_Text' :
|
196 |
+
case 'FW_Option_Type_Short_Text' :
|
197 |
+
case 'FW_Option_Type_Password' :
|
198 |
+
case 'FW_Option_Type_Textarea' :
|
199 |
+
case 'FW_Option_Type_Html' :
|
200 |
+
case 'FW_Option_Type_Html_Fixed' :
|
201 |
+
case 'FW_Option_Type_Html_Full' :
|
202 |
+
case 'FW_Option_Type_Checkbox' :
|
203 |
+
case 'FW_Option_Type_Checkboxes' :
|
204 |
+
case 'FW_Option_Type_Radio' :
|
205 |
+
case 'FW_Option_Type_Select' :
|
206 |
+
case 'FW_Option_Type_Short_Select' :
|
207 |
+
case 'FW_Option_Type_Select_Multiple' :
|
208 |
+
case 'FW_Option_Type_Unique' :
|
209 |
+
case 'FW_Option_Type_GMap_Key' :
|
210 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/simple.php';
|
211 |
+
break;
|
212 |
+
case 'FW_Option_Type_Addable_Box' :
|
213 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/addable-box/class-fw-option-type-addable-box.php';
|
214 |
+
break;
|
215 |
+
case 'FW_Option_Type_Addable_Popup' :
|
216 |
+
case 'FW_Option_Type_Addable_Popup_Full' :
|
217 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/addable-popup/class-fw-option-type-addable-popup.php';
|
218 |
+
break;
|
219 |
+
case 'FW_Option_Type_Addable_Option' :
|
220 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/addable-option/class-fw-option-type-addable-option.php';
|
221 |
+
break;
|
222 |
+
case 'FW_Option_Type_Background_Image' :
|
223 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/background-image/class-fw-option-type-background-image.php';
|
224 |
+
break;
|
225 |
+
case 'FW_Option_Type_Color_Picker' :
|
226 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/color-picker/class-fw-option-type-color-picker.php';
|
227 |
+
break;
|
228 |
+
case 'FW_Option_Type_Date_Picker' :
|
229 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/date-picker/class-fw-option-type-wp-date-picker.php';
|
230 |
+
break;
|
231 |
+
case 'FW_Option_Type_Datetime_Picker' :
|
232 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/datetime-picker/class-fw-option-type-datetime-picker.php';
|
233 |
+
break;
|
234 |
+
case 'FW_Option_Type_Datetime_Range' :
|
235 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/datetime-range/class-fw-option-type-datetime-range.php';
|
236 |
+
break;
|
237 |
+
case 'FW_Option_Type_Gradient' :
|
238 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/gradient/class-fw-option-type-gradient.php';
|
239 |
+
break;
|
240 |
+
case 'FW_Option_Type_Icon' :
|
241 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/icon/class-fw-option-type-icon.php';
|
242 |
+
break;
|
243 |
+
case 'FW_Option_Type_Icon_v2' :
|
244 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/icon-v2/class-fw-option-type-icon-v2.php';
|
245 |
+
break;
|
246 |
+
case 'FW_Option_Type_Image_Picker' :
|
247 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/image-picker/class-fw-option-type-image-picker.php';
|
248 |
+
break;
|
249 |
+
case 'FW_Option_Type_Map' :
|
250 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/map/class-fw-option-type-map.php';
|
251 |
+
break;
|
252 |
+
case 'FW_Option_Type_Multi' :
|
253 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/multi/class-fw-option-type-multi.php';
|
254 |
+
break;
|
255 |
+
case 'FW_Option_Type_Multi_Picker' :
|
256 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/multi-picker/class-fw-option-type-multi-picker.php';
|
257 |
+
break;
|
258 |
+
case 'FW_Option_Type_Multi_Select' :
|
259 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/multi-select/class-fw-option-type-multi-select.php';
|
260 |
+
break;
|
261 |
+
case 'FW_Option_Type_Multi_Upload' :
|
262 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/multi-upload/class-fw-option-type-multi-upload.php';
|
263 |
+
break;
|
264 |
+
case 'FW_Option_Type_Oembed' :
|
265 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/oembed/class-fw-option-type-oembed.php';
|
266 |
+
break;
|
267 |
+
case 'FW_Option_Type_Popup' :
|
268 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/popup/class-fw-option-type-popup.php';
|
269 |
+
break;
|
270 |
+
case 'FW_Option_Type_Radio_Text' :
|
271 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/radio-text/class-fw-option-type-radio-text.php';
|
272 |
+
break;
|
273 |
+
case 'FW_Option_Type_Range_Slider' :
|
274 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/range-slider/class-fw-option-type-range-slider.php';
|
275 |
+
break;
|
276 |
+
case 'FW_Option_Type_Rgba_Color_Picker' :
|
277 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/rgba-color-picker/class-fw-option-type-rgba-color-picker.php';
|
278 |
+
break;
|
279 |
+
case 'FW_Option_Type_Slider' :
|
280 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/slider/class-fw-option-type-slider.php';
|
281 |
+
break;
|
282 |
+
case 'FW_Option_Type_Slider_Short' :
|
283 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/slider/class-fw-option-type-short-slider.php';
|
284 |
+
break;
|
285 |
+
case 'FW_Option_Type_Switch' :
|
286 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/switch/class-fw-option-type-switch.php';
|
287 |
+
break;
|
288 |
+
case 'FW_Option_Type_Typography' :
|
289 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/typography/class-fw-option-type-typography.php';
|
290 |
+
break;
|
291 |
+
case 'FW_Option_Type_Typography_v2' :
|
292 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/typography-v2/class-fw-option-type-typography-v2.php';
|
293 |
+
break;
|
294 |
+
case 'FW_Option_Type_Upload' :
|
295 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/upload/class-fw-option-type-upload.php';
|
296 |
+
break;
|
297 |
+
case 'FW_Option_Type_Wp_Editor' :
|
298 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/wp-editor/class-fw-option-type-wp-editor.php';
|
299 |
+
break;
|
300 |
+
case 'FW_Icon_V2_Favorites_Manager' :
|
301 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/icon-v2/includes/class-fw-icon-v2-favorites.php';
|
302 |
+
break;
|
303 |
+
case 'FW_Icon_V2_Packs_Loader' :
|
304 |
+
require_once dirname( __FILE__ ) . '/includes/option-types/icon-v2/includes/class-fw-icon-v2-packs-loader.php';
|
305 |
+
break;
|
306 |
+
}
|
307 |
}
|
framework/bin/load-latest-fonts.php
CHANGED
@@ -1,172 +1,172 @@
|
|
1 |
-
#!/usr/bin/env php
|
2 |
-
|
3 |
-
<?php
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Download latest font packs from their sources.
|
7 |
-
*/
|
8 |
-
|
9 |
-
function get_libs_dir() {
|
10 |
-
return dirname(__FILE__) . '/../static/libs/';
|
11 |
-
}
|
12 |
-
|
13 |
-
$packs = array(
|
14 |
-
array(
|
15 |
-
'name' => 'entypo',
|
16 |
-
'github-repo' => 'danielbruce/entypo',
|
17 |
-
'css-file' => 'font/entypo.css',
|
18 |
-
|
19 |
-
'fonts' => array(
|
20 |
-
'font/entypo.eot',
|
21 |
-
'font/entypo.svg',
|
22 |
-
'font/entypo.ttf',
|
23 |
-
'font/entypo.woff'
|
24 |
-
),
|
25 |
-
|
26 |
-
'replace' => array(
|
27 |
-
array(
|
28 |
-
'from' => "icon-",
|
29 |
-
'to' => "entypo-"
|
30 |
-
),
|
31 |
-
|
32 |
-
array(
|
33 |
-
'from' => "url('entypo",
|
34 |
-
'to' => "url('../fonts/entypo"
|
35 |
-
),
|
36 |
-
)
|
37 |
-
),
|
38 |
-
|
39 |
-
'linearicons' => array(
|
40 |
-
'name' => 'lnr',
|
41 |
-
'css-file' => 'https://cdn.linearicons.com/free/1.0.0/icon-font.min.css',
|
42 |
-
),
|
43 |
-
|
44 |
-
'typicons' => array(
|
45 |
-
'name' => 'typcn',
|
46 |
-
'github-repo' => 'stephenhutchings/typicons.font',
|
47 |
-
|
48 |
-
'css-file' => 'src/font/typicons.css',
|
49 |
-
|
50 |
-
'fonts' => array(
|
51 |
-
'src/font/typicons.eot',
|
52 |
-
'src/font/typicons.svg',
|
53 |
-
'src/font/typicons.ttf',
|
54 |
-
'src/font/typicons.woff'
|
55 |
-
),
|
56 |
-
|
57 |
-
'replace' => array(
|
58 |
-
array(
|
59 |
-
'from' => "url('typicons",
|
60 |
-
'to' => "url('../fonts/typicons"
|
61 |
-
)
|
62 |
-
)
|
63 |
-
),
|
64 |
-
|
65 |
-
'font-awesome' => array(
|
66 |
-
'name' => 'font-awesome',
|
67 |
-
'github-repo' => 'FortAwesome/Font-Awesome',
|
68 |
-
'css-file' => 'css/font-awesome.min.css',
|
69 |
-
'css-file-output' => 'font-awesome.min.css',
|
70 |
-
'fonts' => array(
|
71 |
-
'fonts/FontAwesome.otf',
|
72 |
-
'fonts/fontawesome-webfont.eot',
|
73 |
-
'fonts/fontawesome-webfont.svg',
|
74 |
-
'fonts/fontawesome-webfont.ttf',
|
75 |
-
'fonts/fontawesome-webfont.woff',
|
76 |
-
'fonts/fontawesome-webfont.woff2'
|
77 |
-
)
|
78 |
-
)
|
79 |
-
);
|
80 |
-
|
81 |
-
foreach ($packs as $pack) {
|
82 |
-
create_pack_directory($pack);
|
83 |
-
|
84 |
-
download_css($pack);
|
85 |
-
download_fonts($pack);
|
86 |
-
perform_replacements($pack);
|
87 |
-
}
|
88 |
-
|
89 |
-
function create_pack_directory($pack) {
|
90 |
-
if (file_exists(get_libs_dir() . $pack['name'])) return;
|
91 |
-
|
92 |
-
mkdir(get_libs_dir() . $pack['name']);
|
93 |
-
mkdir(get_libs_dir() . $pack['name'] . '/css');
|
94 |
-
mkdir(get_libs_dir() . $pack['name'] . '/fonts');
|
95 |
-
|
96 |
-
echo 'install ' . $pack['name'] . "\n";
|
97 |
-
}
|
98 |
-
|
99 |
-
function download_css($pack) {
|
100 |
-
if (! isset($pack['css-file'])) { return; }
|
101 |
-
|
102 |
-
$url = github_or_network_for($pack['css-file'], $pack);
|
103 |
-
|
104 |
-
$file_name = $pack['name'] . '.css';
|
105 |
-
|
106 |
-
if (isset($pack['css-file-output'])) {
|
107 |
-
$file_name = $pack['css-file-output'];
|
108 |
-
}
|
109 |
-
|
110 |
-
download_file(
|
111 |
-
$url,
|
112 |
-
// __DIR__ . '/static/css/' . $pack['name'] . '.css'
|
113 |
-
get_libs_dir() . $pack['name'] . '/css/' . $file_name
|
114 |
-
);
|
115 |
-
}
|
116 |
-
|
117 |
-
function download_fonts($pack) {
|
118 |
-
if (! isset($pack['fonts'])) { return; }
|
119 |
-
|
120 |
-
foreach ($pack['fonts'] as $font) {
|
121 |
-
download_file(
|
122 |
-
github_or_network_for($font, $pack),
|
123 |
-
// __DIR__ . '/static/fonts/' . basename( $font )
|
124 |
-
get_libs_dir() . $pack['name'] . '/fonts/' . basename( $font )
|
125 |
-
);
|
126 |
-
}
|
127 |
-
}
|
128 |
-
|
129 |
-
function perform_replacements($pack) {
|
130 |
-
if (! isset($pack['replace'])) { return; }
|
131 |
-
|
132 |
-
// $file_path = __DIR__ . '/static/css/' . $pack['name'] . '.css';
|
133 |
-
$file_path = get_libs_dir() . $pack['name'] . '/css/' . $pack['name'] . '.css';
|
134 |
-
|
135 |
-
$data = file_get_contents($file_path);
|
136 |
-
|
137 |
-
foreach ($pack['replace'] as $recipe) {
|
138 |
-
$data = str_replace(
|
139 |
-
$recipe['from'],
|
140 |
-
$recipe['to'],
|
141 |
-
$data
|
142 |
-
);
|
143 |
-
}
|
144 |
-
|
145 |
-
file_put_contents($file_path, $data);
|
146 |
-
}
|
147 |
-
|
148 |
-
function github_or_network_for($base_url, $pack) {
|
149 |
-
if (! isset($pack['github-repo'])) { return $base_url; }
|
150 |
-
|
151 |
-
return 'https://raw.githubusercontent.com/' .
|
152 |
-
$pack['github-repo'] .
|
153 |
-
'/master/' . $base_url;
|
154 |
-
}
|
155 |
-
|
156 |
-
function download_file($url, $destination) {
|
157 |
-
echo 'downloading ' . $destination . "\n";
|
158 |
-
$ch = curl_init();
|
159 |
-
curl_setopt($ch, CURLOPT_URL, $url);
|
160 |
-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
161 |
-
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
162 |
-
curl_setopt( $ch, CURLOPT_ENCODING, "UTF-8" );
|
163 |
-
|
164 |
-
$data = curl_exec ($ch);
|
165 |
-
$error = curl_error($ch);
|
166 |
-
|
167 |
-
curl_close ($ch);
|
168 |
-
|
169 |
-
$file = fopen($destination, "w+");
|
170 |
-
fputs($file, $data);
|
171 |
-
fclose($file);
|
172 |
-
}
|
1 |
+
#!/usr/bin/env php
|
2 |
+
|
3 |
+
<?php
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Download latest font packs from their sources.
|
7 |
+
*/
|
8 |
+
|
9 |
+
function get_libs_dir() {
|
10 |
+
return dirname(__FILE__) . '/../static/libs/';
|
11 |
+
}
|
12 |
+
|
13 |
+
$packs = array(
|
14 |
+
array(
|
15 |
+
'name' => 'entypo',
|
16 |
+
'github-repo' => 'danielbruce/entypo',
|
17 |
+
'css-file' => 'font/entypo.css',
|
18 |
+
|
19 |
+
'fonts' => array(
|
20 |
+
'font/entypo.eot',
|
21 |
+
'font/entypo.svg',
|
22 |
+
'font/entypo.ttf',
|
23 |
+
'font/entypo.woff'
|
24 |
+
),
|
25 |
+
|
26 |
+
'replace' => array(
|
27 |
+
array(
|
28 |
+
'from' => "icon-",
|
29 |
+
'to' => "entypo-"
|
30 |
+
),
|
31 |
+
|
32 |
+
array(
|
33 |
+
'from' => "url('entypo",
|
34 |
+
'to' => "url('../fonts/entypo"
|
35 |
+
),
|
36 |
+
)
|
37 |
+
),
|
38 |
+
|
39 |
+
'linearicons' => array(
|
40 |
+
'name' => 'lnr',
|
41 |
+
'css-file' => 'https://cdn.linearicons.com/free/1.0.0/icon-font.min.css',
|
42 |
+
),
|
43 |
+
|
44 |
+
'typicons' => array(
|
45 |
+
'name' => 'typcn',
|
46 |
+
'github-repo' => 'stephenhutchings/typicons.font',
|
47 |
+
|
48 |
+
'css-file' => 'src/font/typicons.css',
|
49 |
+
|
50 |
+
'fonts' => array(
|
51 |
+
'src/font/typicons.eot',
|
52 |
+
'src/font/typicons.svg',
|
53 |
+
'src/font/typicons.ttf',
|
54 |
+
'src/font/typicons.woff'
|
55 |
+
),
|
56 |
+
|
57 |
+
'replace' => array(
|
58 |
+
array(
|
59 |
+
'from' => "url('typicons",
|
60 |
+
'to' => "url('../fonts/typicons"
|
61 |
+
)
|
62 |
+
)
|
63 |
+
),
|
64 |
+
|
65 |
+
'font-awesome' => array(
|
66 |
+
'name' => 'font-awesome',
|
67 |
+
'github-repo' => 'FortAwesome/Font-Awesome',
|
68 |
+
'css-file' => 'css/font-awesome.min.css',
|
69 |
+
'css-file-output' => 'font-awesome.min.css',
|
70 |
+
'fonts' => array(
|
71 |
+
'fonts/FontAwesome.otf',
|
72 |
+
'fonts/fontawesome-webfont.eot',
|
73 |
+
'fonts/fontawesome-webfont.svg',
|
74 |
+
'fonts/fontawesome-webfont.ttf',
|
75 |
+
'fonts/fontawesome-webfont.woff',
|
76 |
+
'fonts/fontawesome-webfont.woff2'
|
77 |
+
)
|
78 |
+
)
|
79 |
+
);
|
80 |
+
|
81 |
+
foreach ($packs as $pack) {
|
82 |
+
create_pack_directory($pack);
|
83 |
+
|
84 |
+
download_css($pack);
|
85 |
+
download_fonts($pack);
|
86 |
+
perform_replacements($pack);
|
87 |
+
}
|
88 |
+
|
89 |
+
function create_pack_directory($pack) {
|
90 |
+
if (file_exists(get_libs_dir() . $pack['name'])) return;
|
91 |
+
|
92 |
+
mkdir(get_libs_dir() . $pack['name']);
|
93 |
+
mkdir(get_libs_dir() . $pack['name'] . '/css');
|
94 |
+
mkdir(get_libs_dir() . $pack['name'] . '/fonts');
|
95 |
+
|
96 |
+
echo 'install ' . $pack['name'] . "\n";
|
97 |
+
}
|
98 |
+
|
99 |
+
function download_css($pack) {
|
100 |
+
if (! isset($pack['css-file'])) { return; }
|
101 |
+
|
102 |
+
$url = github_or_network_for($pack['css-file'], $pack);
|
103 |
+
|
104 |
+
$file_name = $pack['name'] . '.css';
|
105 |
+
|
106 |
+
if (isset($pack['css-file-output'])) {
|
107 |
+
$file_name = $pack['css-file-output'];
|
108 |
+
}
|
109 |
+
|
110 |
+
download_file(
|
111 |
+
$url,
|
112 |
+
// __DIR__ . '/static/css/' . $pack['name'] . '.css'
|
113 |
+
get_libs_dir() . $pack['name'] . '/css/' . $file_name
|
114 |
+
);
|
115 |
+
}
|
116 |
+
|
117 |
+
function download_fonts($pack) {
|
118 |
+
if (! isset($pack['fonts'])) { return; }
|
119 |
+
|
120 |
+
foreach ($pack['fonts'] as $font) {
|
121 |
+
download_file(
|
122 |
+
github_or_network_for($font, $pack),
|
123 |
+
// __DIR__ . '/static/fonts/' . basename( $font )
|
124 |
+
get_libs_dir() . $pack['name'] . '/fonts/' . basename( $font )
|
125 |
+
);
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
function perform_replacements($pack) {
|
130 |
+
if (! isset($pack['replace'])) { return; }
|
131 |
+
|
132 |
+
// $file_path = __DIR__ . '/static/css/' . $pack['name'] . '.css';
|
133 |
+
$file_path = get_libs_dir() . $pack['name'] . '/css/' . $pack['name'] . '.css';
|
134 |
+
|
135 |
+
$data = file_get_contents($file_path);
|
136 |
+
|
137 |
+
foreach ($pack['replace'] as $recipe) {
|
138 |
+
$data = str_replace(
|
139 |
+
$recipe['from'],
|
140 |
+
$recipe['to'],
|
141 |
+
$data
|
142 |
+
);
|
143 |
+
}
|
144 |
+
|
145 |
+
file_put_contents($file_path, $data);
|
146 |
+
}
|
147 |
+
|
148 |
+
function github_or_network_for($base_url, $pack) {
|
149 |
+
if (! isset($pack['github-repo'])) { return $base_url; }
|
150 |
+
|
151 |
+
return 'https://raw.githubusercontent.com/' .
|
152 |
+
$pack['github-repo'] .
|
153 |
+
'/master/' . $base_url;
|
154 |
+
}
|
155 |
+
|
156 |
+
function download_file($url, $destination) {
|
157 |
+
echo 'downloading ' . $destination . "\n";
|
158 |
+
$ch = curl_init();
|
159 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
160 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
161 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
162 |
+
curl_setopt( $ch, CURLOPT_ENCODING, "UTF-8" );
|
163 |
+
|
164 |
+
$data = curl_exec ($ch);
|
165 |
+
$error = curl_error($ch);
|
166 |
+
|
167 |
+
curl_close ($ch);
|
168 |
+
|
169 |
+
$file = fopen($destination, "w+");
|
170 |
+
fputs($file, $data);
|
171 |
+
fclose($file);
|
172 |
+
}
|
framework/bootstrap.php
CHANGED
@@ -1,79 +1,79 @@
|
|
1 |
-
<?php if (!defined('ABSPATH')) die('Forbidden');
|
2 |
-
|
3 |
-
if ( defined( 'WP_CLI' ) && WP_CLI && ! isset( $_SERVER['HTTP_HOST'] ) ) {
|
4 |
-
$_SERVER['HTTP_HOST'] = 'unyson.io';
|
5 |
-
$_SERVER['SERVER_NAME'] = 'unyson';
|
6 |
-
$_SERVER['SERVER_PORT'] = '80';
|
7 |
-
}
|
8 |
-
|
9 |
-
if (defined('FW')) {
|
10 |
-
/**
|
11 |
-
* The framework is already loaded.
|
12 |
-
*/
|
13 |
-
} else {
|
14 |
-
define('FW', true);
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Load the framework on 'after_setup_theme' action when the theme information is available
|
18 |
-
* To prevent `undefined constant TEMPLATEPATH` errors when the framework is used as plugin
|
19 |
-
*/
|
20 |
-
add_action('after_setup_theme', '_action_init_framework');
|
21 |
-
|
22 |
-
function _action_init_framework() {
|
23 |
-
if (did_action('fw_init')) {
|
24 |
-
return;
|
25 |
-
}
|
26 |
-
|
27 |
-
do_action('fw_before_init');
|
28 |
-
|
29 |
-
$dir = dirname(__FILE__);
|
30 |
-
|
31 |
-
require $dir .'/autoload.php';
|
32 |
-
|
33 |
-
// Load helper functions
|
34 |
-
foreach (array('general', 'meta', 'fw-storage', 'database') as $file) {
|
35 |
-
require $dir .'/helpers/'. $file .'.php';
|
36 |
-
}
|
37 |
-
|
38 |
-
// Load core
|
39 |
-
{
|
40 |
-
require $dir .'/core/Fw.php';
|
41 |
-
|
42 |
-
fw();
|
43 |
-
}
|
44 |
-
|
45 |
-
require $dir .'/includes/hooks.php';
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Init components
|
49 |
-
*/
|
50 |
-
{
|
51 |
-
$components = array(
|
52 |
-
/**
|
53 |
-
* Load the theme's hooks.php first, to give users the possibility to add_action()
|
54 |
-
* for `extensions` and `backend` components actions that can happen while their initialization
|
55 |
-
*/
|
56 |
-
'theme',
|
57 |
-
/**
|
58 |
-
* Load extensions before backend, to give extensions the possibility to add_action()
|
59 |
-
* for the `backend` component actions that can happen while its initialization
|
60 |
-
*/
|
61 |
-
'extensions',
|
62 |
-
'backend'
|
63 |
-
);
|
64 |
-
|
65 |
-
foreach ($components as $component) {
|
66 |
-
fw()->{$component}->_init();
|
67 |
-
}
|
68 |
-
|
69 |
-
foreach ($components as $component) {
|
70 |
-
fw()->{$component}->_after_components_init();
|
71 |
-
}
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* The framework is loaded
|
76 |
-
*/
|
77 |
-
do_action('fw_init');
|
78 |
-
}
|
79 |
-
}
|
1 |
+
<?php if (!defined('ABSPATH')) die('Forbidden');
|
2 |
+
|
3 |
+
if ( defined( 'WP_CLI' ) && WP_CLI && ! isset( $_SERVER['HTTP_HOST'] ) ) {
|
4 |
+
$_SERVER['HTTP_HOST'] = 'unyson.io';
|
5 |
+
$_SERVER['SERVER_NAME'] = 'unyson';
|
6 |
+
$_SERVER['SERVER_PORT'] = '80';
|
7 |
+
}
|
8 |
+
|
9 |
+
if (defined('FW')) {
|
10 |
+
/**
|
11 |
+
* The framework is already loaded.
|
12 |
+
*/
|
13 |
+
} else {
|
14 |
+
define('FW', true);
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Load the framework on 'after_setup_theme' action when the theme information is available
|
18 |
+
* To prevent `undefined constant TEMPLATEPATH` errors when the framework is used as plugin
|
19 |
+
*/
|
20 |
+
add_action('after_setup_theme', '_action_init_framework');
|
21 |
+
|
22 |
+
function _action_init_framework() {
|
23 |
+
if (did_action('fw_init')) {
|
24 |
+
return;
|
25 |
+
}
|
26 |
+
|
27 |
+
do_action('fw_before_init');
|
28 |
+
|
29 |
+
$dir = dirname(__FILE__);
|
30 |
+
|
31 |
+
require $dir .'/autoload.php';
|
32 |
+
|
33 |
+
// Load helper functions
|
34 |
+
foreach (array('general', 'meta', 'fw-storage', 'database') as $file) {
|
35 |
+
require $dir .'/helpers/'. $file .'.php';
|
36 |
+
}
|
37 |
+
|
38 |
+
// Load core
|
39 |
+
{
|
40 |
+
require $dir .'/core/Fw.php';
|
41 |
+
|
42 |
+
fw();
|
43 |
+
}
|
44 |
+
|
45 |
+
require $dir .'/includes/hooks.php';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Init components
|
49 |
+
*/
|
50 |
+
{
|
51 |
+
$components = array(
|
52 |
+
/**
|
53 |
+
* Load the theme's hooks.php first, to give users the possibility to add_action()
|
54 |
+
* for `extensions` and `backend` components actions that can happen while their initialization
|
55 |
+
*/
|
56 |
+
'theme',
|
57 |
+
/**
|
58 |
+
* Load extensions before backend, to give extensions the possibility to add_action()
|
59 |
+
* for the `backend` component actions that can happen while its initialization
|
60 |
+
*/
|
61 |
+
'extensions',
|
62 |
+
'backend'
|
63 |
+
);
|
64 |
+
|
65 |
+
foreach ($components as $component) {
|
66 |
+
fw()->{$component}->_init();
|
67 |
+
}
|
68 |
+
|
69 |
+
foreach ($components as $component) {
|
70 |
+
fw()->{$component}->_after_components_init();
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* The framework is loaded
|
76 |
+
*/
|
77 |
+
do_action('fw_init');
|
78 |
+
}
|
79 |
+
}
|
framework/core/Fw.php
CHANGED
@@ -1,79 +1,79 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Main framework class that contains everything
|
5 |
-
*
|
6 |
-
* Convention: All public properties should be only instances of the components (except special property: manifest)
|
7 |
-
*/
|
8 |
-
final class _Fw
|
9 |
-
{
|
10 |
-
/** @var bool If already loaded */
|
11 |
-
private static $loaded = false;
|
12 |
-
|
13 |
-
/** @var FW_Framework_Manifest */
|
14 |
-
public $manifest;
|
15 |
-
|
16 |
-
/** @var _FW_Component_Extensions */
|
17 |
-
public $extensions;
|
18 |
-
|
19 |
-
/** @var _FW_Component_Backend */
|
20 |
-
public $backend;
|
21 |
-
|
22 |
-
/** @var _FW_Component_Theme */
|
23 |
-
public $theme;
|
24 |
-
|
25 |
-
public function __construct()
|
26 |
-
{
|
27 |
-
if (self::$loaded) {
|
28 |
-
trigger_error('Framework already loaded', E_USER_ERROR);
|
29 |
-
} else {
|
30 |
-
self::$loaded = true;
|
31 |
-
}
|
32 |
-
|
33 |
-
$fw_dir = fw_get_framework_directory();
|
34 |
-
|
35 |
-
// manifest
|
36 |
-
{
|
37 |
-
require $fw_dir .'/manifest.php';
|
38 |
-
/** @var array $manifest */
|
39 |
-
|
40 |
-
$this->manifest = new FW_Framework_Manifest($manifest);
|
41 |
-
|
42 |
-
add_action('fw_init', array($this, '_check_requirements'), 1);
|
43 |
-
}
|
44 |
-
|
45 |
-
// components
|
46 |
-
{
|
47 |
-
$this->extensions = new _FW_Component_Extensions();
|
48 |
-
$this->backend = new _FW_Component_Backend();
|
49 |
-
$this->theme = new _FW_Component_Theme();
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* @internal
|
55 |
-
*/
|
56 |
-
public function _check_requirements()
|
57 |
-
{
|
58 |
-
if (is_admin() && !$this->manifest->check_requirements()) {
|
59 |
-
FW_Flash_Messages::add(
|
60 |
-
'fw_requirements',
|
61 |
-
__('Framework requirements not met:', 'fw') .' '. $this->manifest->get_not_met_requirement_text(),
|
62 |
-
'warning'
|
63 |
-
);
|
64 |
-
}
|
65 |
-
}
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* @return _FW Framework instance
|
70 |
-
*/
|
71 |
-
function fw() {
|
72 |
-
static $FW = null; // cache
|
73 |
-
|
74 |
-
if ($FW === null) {
|
75 |
-
$FW = new _Fw();
|
76 |
-
}
|
77 |
-
|
78 |
-
return $FW;
|
79 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Main framework class that contains everything
|
5 |
+
*
|
6 |
+
* Convention: All public properties should be only instances of the components (except special property: manifest)
|
7 |
+
*/
|
8 |
+
final class _Fw
|
9 |
+
{
|
10 |
+
/** @var bool If already loaded */
|
11 |
+
private static $loaded = false;
|
12 |
+
|
13 |
+
/** @var FW_Framework_Manifest */
|
14 |
+
public $manifest;
|
15 |
+
|
16 |
+
/** @var _FW_Component_Extensions */
|
17 |
+
public $extensions;
|
18 |
+
|
19 |
+
/** @var _FW_Component_Backend */
|
20 |
+
public $backend;
|
21 |
+
|
22 |
+
/** @var _FW_Component_Theme */
|
23 |
+
public $theme;
|
24 |
+
|
25 |
+
public function __construct()
|
26 |
+
{
|
27 |
+
if (self::$loaded) {
|
28 |
+
trigger_error('Framework already loaded', E_USER_ERROR);
|
29 |
+
} else {
|
30 |
+
self::$loaded = true;
|
31 |
+
}
|
32 |
+
|
33 |
+
$fw_dir = fw_get_framework_directory();
|
34 |
+
|
35 |
+
// manifest
|
36 |
+
{
|
37 |
+
require $fw_dir .'/manifest.php';
|
38 |
+
/** @var array $manifest */
|
39 |
+
|
40 |
+
$this->manifest = new FW_Framework_Manifest($manifest);
|
41 |
+
|
42 |
+
add_action('fw_init', array($this, '_check_requirements'), 1);
|
43 |
+
}
|
44 |
+
|
45 |
+
// components
|
46 |
+
{
|
47 |
+
$this->extensions = new _FW_Component_Extensions();
|
48 |
+
$this->backend = new _FW_Component_Backend();
|
49 |
+
$this->theme = new _FW_Component_Theme();
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @internal
|
55 |
+
*/
|
56 |
+
public function _check_requirements()
|
57 |
+
{
|
58 |
+
if (is_admin() && !$this->manifest->check_requirements()) {
|
59 |
+
FW_Flash_Messages::add(
|
60 |
+
'fw_requirements',
|
61 |
+
__('Framework requirements not met:', 'fw') .' '. $this->manifest->get_not_met_requirement_text(),
|
62 |
+
'warning'
|
63 |
+
);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @return _FW Framework instance
|
70 |
+
*/
|
71 |
+
function fw() {
|
72 |
+
static $FW = null; // cache
|
73 |
+
|
74 |
+
if ($FW === null) {
|
75 |
+
$FW = new _Fw();
|
76 |
+
}
|
77 |
+
|
78 |
+
return $FW;
|
79 |
+
}
|
framework/core/class-fw-manifest.php
CHANGED
@@ -1,565 +1,572 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
abstract class FW_Manifest
|
4 |
-
{
|
5 |
-
/**
|
6 |
-
* @var array
|
7 |
-
*/
|
8 |
-
protected $manifest;
|
9 |
-
|
10 |
-
/**
|
11 |
-
* The first requirement that was not met
|
12 |
-
* (that marks that the requirements are not met)
|
13 |
-
*
|
14 |
-
* @var array
|
15 |
-
* array(
|
16 |
-
* 'requirement' => 'wordpress|framework',
|
17 |
-
* 'requirements' => array('min_version' => '1.2.3', ...)
|
18 |
-
* )
|
19 |
-
* or
|
20 |
-
* array(
|
21 |
-
* 'requirement' => 'extensions',
|
22 |
-
* 'extension' => 'extension_name',
|
23 |
-
* 'requirements' => array('min_version' => '1.2.3', ...)
|
24 |
-
* )
|
25 |
-
*/
|
26 |
-
private $not_met_requirement;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* When an requirement that sure will not change is not met and have no sense to execute check_requirements() again
|
30 |
-
* @var bool
|
31 |
-
*/
|
32 |
-
private $not_met_is_final = false;
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Not met requirement and skipped (not verified) requirements after $this->not_met_requirement was found
|
36 |
-
* @var array
|
37 |
-
*/
|
38 |
-
private $requirements_for_verification;
|
39 |
-
|
40 |
-
private $requirements_verification_never_called = true;
|
41 |
-
|
42 |
-
/**
|
43 |
-
* @param array $manifest
|
44 |
-
*/
|
45 |
-
protected function __construct(array $manifest)
|
46 |
-
{
|
47 |
-
$manifest = array_merge(array(
|
48 |
-
'name' => null, // title
|
49 |
-
'uri' => null,
|
50 |
-
'description' => null,
|
51 |
-
'version' => '0.0.0',
|
52 |
-
'author' => null,
|
53 |
-
'author_uri' => null,
|
54 |
-
|
55 |
-
// Custom fields
|
56 |
-
'requirements' => array(),
|
57 |
-
), $manifest);
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Merge $manifest['requirements']
|
61 |
-
*/
|
62 |
-
{
|
63 |
-
$requirements = $manifest['requirements'];
|
64 |
-
|
65 |
-
$manifest['requirements'] = array();
|
66 |
-
|
67 |
-
foreach ($this->get_default_requirements() as $default_requirement => $default_requirements) {
|
68 |
-
$manifest['requirements'][ $default_requirement ] = isset($requirements[$default_requirement])
|
69 |
-
? array_merge(
|
70 |
-
$default_requirements,
|
71 |
-
$requirements[$default_requirement]
|
72 |
-
)
|
73 |
-
: $default_requirements;
|
74 |
-
}
|
75 |
-
|
76 |
-
unset($requirements);
|
77 |
-
}
|
78 |
-
|
79 |
-
$this->requirements_for_verification = $manifest['requirements'];
|
80 |
-
|
81 |
-
$this->manifest = $manifest;
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* @return array { 'requirement' => array('min_version' => '..', 'max_version' => '..') }
|
86 |
-
*/
|
87 |
-
abstract protected function get_default_requirements();
|
88 |
-
|
89 |
-
/**
|
90 |
-
* @return bool
|
91 |
-
*/
|
92 |
-
public function requirements_met()
|
93 |
-
{
|
94 |
-
if ($this->not_met_is_final) {
|
95 |
-
return false;
|
96 |
-
}
|
97 |
-
|
98 |
-
if ($this->requirements_verification_never_called) {
|
99 |
-
$this->requirements_verification_never_called = false;
|
100 |
-
|
101 |
-
$this->check_requirements();
|
102 |
-
}
|
103 |
-
|
104 |
-
return empty($this->requirements_for_verification) && empty($this->not_met_requirement);
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* @return bool
|
109 |
-
*/
|
110 |
-
public function check_requirements()
|
111 |
-
{
|
112 |
-
if ($this->not_met_is_final) {
|
113 |
-
return false;
|
114 |
-
}
|
115 |
-
|
116 |
-
if ($this->requirements_met()) {
|
117 |
-
return true;
|
118 |
-
}
|
119 |
-
|
120 |
-
$this->not_met_requirement = array();
|
121 |
-
|
122 |
-
global $wp_version;
|
123 |
-
|
124 |
-
foreach ($this->requirements_for_verification as $requirement => $requirements) {
|
125 |
-
switch ($requirement) {
|
126 |
-
case 'php':
|
127 |
-
if ( ! function_exists( 'phpversion' ) ) {
|
128 |
-
break;
|
129 |
-
}
|
130 |
-
if (
|
131 |
-
isset($requirements['min_version'])
|
132 |
-
&&
|
133 |
-
version_compare(phpversion(), $requirements['min_version'], '<')
|
134 |
-
) {
|
135 |
-
$this->not_met_requirement = array(
|
136 |
-
'requirement' => $requirement,
|
137 |
-
'requirements' => $requirements
|
138 |
-
);
|
139 |
-
$this->not_met_is_final = true;
|
140 |
-
break 2;
|
141 |
-
}
|
142 |
-
|
143 |
-
if (
|
144 |
-
isset($requirements['max_version'])
|
145 |
-
&&
|
146 |
-
version_compare(phpversion(), $requirements['max_version'], '>')
|
147 |
-
) {
|
148 |
-
$this->not_met_requirement = array(
|
149 |
-
'requirement' => $requirement,
|
150 |
-
'requirements' => $requirements
|
151 |
-
);
|
152 |
-
$this->not_met_is_final = true;
|
153 |
-
break 2;
|
154 |
-
}
|
155 |
-
|
156 |
-
// met
|
157 |
-
unset($this->requirements_for_verification[$requirement]);
|
158 |
-
break;
|
159 |
-
case 'wordpress':
|
160 |
-
if (
|
161 |
-
isset($requirements['min_version'])
|
162 |
-
&&
|
163 |
-
version_compare($wp_version, $requirements['min_version'], '<')
|
164 |
-
) {
|
165 |
-
$this->not_met_requirement = array(
|
166 |
-
'requirement' => $requirement,
|
167 |
-
'requirements' => $requirements
|
168 |
-
);
|
169 |
-
$this->not_met_is_final = true;
|
170 |
-
break 2;
|
171 |
-
}
|
172 |
-
|
173 |
-
if (
|
174 |
-
isset($requirements['max_version'])
|
175 |
-
&&
|
176 |
-
version_compare($wp_version, $requirements['max_version'], '>')
|
177 |
-
) {
|
178 |
-
$this->not_met_requirement = array(
|
179 |
-
'requirement' => $requirement,
|
180 |
-
'requirements' => $requirements
|
181 |
-
);
|
182 |
-
$this->not_met_is_final = true;
|
183 |
-
break 2;
|
184 |
-
}
|
185 |
-
|
186 |
-
// met
|
187 |
-
unset($this->requirements_for_verification[$requirement]);
|
188 |
-
break;
|
189 |
-
case 'framework':
|
190 |
-
if (
|
191 |
-
isset($requirements['min_version'])
|
192 |
-
&&
|
193 |
-
version_compare(fw()->manifest->get_version(), $requirements['min_version'], '<')
|
194 |
-
) {
|
195 |
-
$this->not_met_requirement = array(
|
196 |
-
'requirement' => $requirement,
|
197 |
-
'requirements' => $requirements
|
198 |
-
);
|
199 |
-
$this->not_met_is_final = true;
|
200 |
-
break 2;
|
201 |
-
}
|
202 |
-
|
203 |
-
if (
|
204 |
-
isset($requirements['max_version'])
|
205 |
-
&&
|
206 |
-
version_compare(fw()->manifest->get_version(), $requirements['max_version'], '>')
|
207 |
-
) {
|
208 |
-
$this->not_met_requirement = array(
|
209 |
-
'requirement' => $requirement,
|
210 |
-
'requirements' => $requirements
|
211 |
-
);
|
212 |
-
$this->not_met_is_final = true;
|
213 |
-
break 2;
|
214 |
-
}
|
215 |
-
|
216 |
-
// met
|
217 |
-
unset($this->requirements_for_verification[$requirement]);
|
218 |
-
break;
|
219 |
-
case 'extensions':
|
220 |
-
$extensions =& $requirements;
|
221 |
-
|
222 |
-
foreach ($extensions as $extension => $extension_requirements) {
|
223 |
-
$extension_instance = fw()->extensions->get($extension);
|
224 |
-
|
225 |
-
if (!$extension_instance) {
|
226 |
-
/**
|
227 |
-
* extension in requirements does not exists
|
228 |
-
* maybe try call this method later and maybe will exist, or it really does not exists
|
229 |
-
*/
|
230 |
-
$this->not_met_requirement = array(
|
231 |
-
'requirement' => $requirement,
|
232 |
-
'extension' => $extension,
|
233 |
-
'requirements' => $extension_requirements
|
234 |
-
);
|
235 |
-
break 3;
|
236 |
-
}
|
237 |
-
|
238 |
-
if (
|
239 |
-
isset($extension_requirements['min_version'])
|
240 |
-
&&
|
241 |
-
version_compare($extension_instance->manifest->get_version(), $extension_requirements['min_version'], '<')
|
242 |
-
) {
|
243 |
-
$this->not_met_requirement = array(
|
244 |
-
'requirement' => $requirement,
|
245 |
-
'extension' => $extension,
|
246 |
-
'requirements' => $extension_requirements
|
247 |
-
);
|
248 |
-
$this->not_met_is_final = true;
|
249 |
-
break 3;
|
250 |
-
}
|
251 |
-
|
252 |
-
if (
|
253 |
-
isset($extension_requirements['max_version'])
|
254 |
-
&&
|
255 |
-
version_compare($extension_instance->manifest->get_version(), $extension_requirements['max_version'], '>')
|
256 |
-
) {
|
257 |
-
$this->not_met_requirement = array(
|
258 |
-
'requirement' => $requirement,
|
259 |
-
'extension' => $extension,
|
260 |
-
'requirements' => $extension_requirements
|
261 |
-
);
|
262 |
-
$this->not_met_is_final = true;
|
263 |
-
break 3;
|
264 |
-
}
|
265 |
-
|
266 |
-
// met
|
267 |
-
unset($this->requirements_for_verification[$requirement][$extension]);
|
268 |
-
}
|
269 |
-
|
270 |
-
if (empty($this->requirements_for_verification[$requirement])) {
|
271 |
-
// all extensions requirements met
|
272 |
-
unset($this->requirements_for_verification[$requirement]);
|
273 |
-
}
|
274 |
-
break;
|
275 |
-
}
|
276 |
-
}
|
277 |
-
|
278 |
-
return $this->requirements_met();
|
279 |
-
}
|
280 |
-
|
281 |
-
public function get_version()
|
282 |
-
{
|
283 |
-
return $this->manifest['version'];
|
284 |
-
}
|
285 |
-
|
286 |
-
public function get_name()
|
287 |
-
{
|
288 |
-
return $this->manifest['name'];
|
289 |
-
}
|
290 |
-
|
291 |
-
/**
|
292 |
-
* @param string $multi_key
|
293 |
-
* @param mixed $default_value
|
294 |
-
* @return mixed
|
295 |
-
*/
|
296 |
-
public function get($multi_key, $default_value = null)
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
*
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
)
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
fw
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
$requirement
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
)
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
/*'
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
/*'
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
$
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
*
|
531 |
-
*
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
'
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
/*'
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
/*'
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
abstract class FW_Manifest
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* @var array
|
7 |
+
*/
|
8 |
+
protected $manifest;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The first requirement that was not met
|
12 |
+
* (that marks that the requirements are not met)
|
13 |
+
*
|
14 |
+
* @var array
|
15 |
+
* array(
|
16 |
+
* 'requirement' => 'wordpress|framework',
|
17 |
+
* 'requirements' => array('min_version' => '1.2.3', ...)
|
18 |
+
* )
|
19 |
+
* or
|
20 |
+
* array(
|
21 |
+
* 'requirement' => 'extensions',
|
22 |
+
* 'extension' => 'extension_name',
|
23 |
+
* 'requirements' => array('min_version' => '1.2.3', ...)
|
24 |
+
* )
|
25 |
+
*/
|
26 |
+
private $not_met_requirement;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* When an requirement that sure will not change is not met and have no sense to execute check_requirements() again
|
30 |
+
* @var bool
|
31 |
+
*/
|
32 |
+
private $not_met_is_final = false;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Not met requirement and skipped (not verified) requirements after $this->not_met_requirement was found
|
36 |
+
* @var array
|
37 |
+
*/
|
38 |
+
private $requirements_for_verification;
|
39 |
+
|
40 |
+
private $requirements_verification_never_called = true;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @param array $manifest
|
44 |
+
*/
|
45 |
+
protected function __construct(array $manifest)
|
46 |
+
{
|
47 |
+
$manifest = array_merge(array(
|
48 |
+
'name' => null, // title
|
49 |
+
'uri' => null,
|
50 |
+
'description' => null,
|
51 |
+
'version' => '0.0.0',
|
52 |
+
'author' => null,
|
53 |
+
'author_uri' => null,
|
54 |
+
|
55 |
+
// Custom fields
|
56 |
+
'requirements' => array(),
|
57 |
+
), $manifest);
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Merge $manifest['requirements']
|
61 |
+
*/
|
62 |
+
{
|
63 |
+
$requirements = $manifest['requirements'];
|
64 |
+
|
65 |
+
$manifest['requirements'] = array();
|
66 |
+
|
67 |
+
foreach ($this->get_default_requirements() as $default_requirement => $default_requirements) {
|
68 |
+
$manifest['requirements'][ $default_requirement ] = isset($requirements[$default_requirement])
|
69 |
+
? array_merge(
|
70 |
+
$default_requirements,
|
71 |
+
$requirements[$default_requirement]
|
72 |
+
)
|
73 |
+
: $default_requirements;
|
74 |
+
}
|
75 |
+
|
76 |
+
unset($requirements);
|
77 |
+
}
|
78 |
+
|
79 |
+
$this->requirements_for_verification = $manifest['requirements'];
|
80 |
+
|
81 |
+
$this->manifest = $manifest;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @return array { 'requirement' => array('min_version' => '..', 'max_version' => '..') }
|
86 |
+
*/
|
87 |
+
abstract protected function get_default_requirements();
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @return bool
|
91 |
+
*/
|
92 |
+
public function requirements_met()
|
93 |
+
{
|
94 |
+
if ($this->not_met_is_final) {
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
+
if ($this->requirements_verification_never_called) {
|
99 |
+
$this->requirements_verification_never_called = false;
|
100 |
+
|
101 |
+
$this->check_requirements();
|
102 |
+
}
|
103 |
+
|
104 |
+
return empty($this->requirements_for_verification) && empty($this->not_met_requirement);
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* @return bool
|
109 |
+
*/
|
110 |
+
public function check_requirements()
|
111 |
+
{
|
112 |
+
if ($this->not_met_is_final) {
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
|
116 |
+
if ($this->requirements_met()) {
|
117 |
+
return true;
|
118 |
+
}
|
119 |
+
|
120 |
+
$this->not_met_requirement = array();
|
121 |
+
|
122 |
+
global $wp_version;
|
123 |
+
|
124 |
+
foreach ($this->requirements_for_verification as $requirement => $requirements) {
|
125 |
+
switch ($requirement) {
|
126 |
+
case 'php':
|
127 |
+
if ( ! function_exists( 'phpversion' ) ) {
|
128 |
+
break;
|
129 |
+
}
|
130 |
+
if (
|
131 |
+
isset($requirements['min_version'])
|
132 |
+
&&
|
133 |
+
version_compare(phpversion(), $requirements['min_version'], '<')
|
134 |
+
) {
|
135 |
+
$this->not_met_requirement = array(
|
136 |
+
'requirement' => $requirement,
|
137 |
+
'requirements' => $requirements
|
138 |
+
);
|
139 |
+
$this->not_met_is_final = true;
|
140 |
+
break 2;
|
141 |
+
}
|
142 |
+
|
143 |
+
if (
|
144 |
+
isset($requirements['max_version'])
|
145 |
+
&&
|
146 |
+
version_compare(phpversion(), $requirements['max_version'], '>')
|
147 |
+
) {
|
148 |
+
$this->not_met_requirement = array(
|
149 |
+
'requirement' => $requirement,
|
150 |
+
'requirements' => $requirements
|
151 |
+
);
|
152 |
+
$this->not_met_is_final = true;
|
153 |
+
break 2;
|
154 |
+
}
|
155 |
+
|
156 |
+
// met
|
157 |
+
unset($this->requirements_for_verification[$requirement]);
|
158 |
+
break;
|
159 |
+
case 'wordpress':
|
160 |
+
if (
|
161 |
+
isset($requirements['min_version'])
|
162 |
+
&&
|
163 |
+
version_compare($wp_version, $requirements['min_version'], '<')
|
164 |
+
) {
|
165 |
+
$this->not_met_requirement = array(
|
166 |
+
'requirement' => $requirement,
|
167 |
+
'requirements' => $requirements
|
168 |
+
);
|
169 |
+
$this->not_met_is_final = true;
|
170 |
+
break 2;
|
171 |
+
}
|
172 |
+
|
173 |
+
if (
|
174 |
+
isset($requirements['max_version'])
|
175 |
+
&&
|
176 |
+
version_compare($wp_version, $requirements['max_version'], '>')
|
177 |
+
) {
|
178 |
+
$this->not_met_requirement = array(
|
179 |
+
'requirement' => $requirement,
|
180 |
+
'requirements' => $requirements
|
181 |
+
);
|
182 |
+
$this->not_met_is_final = true;
|
183 |
+
break 2;
|
184 |
+
}
|
185 |
+
|
186 |
+
// met
|
187 |
+
unset($this->requirements_for_verification[$requirement]);
|
188 |
+
break;
|
189 |
+
case 'framework':
|
190 |
+
if (
|
191 |
+
isset($requirements['min_version'])
|
192 |
+
&&
|
193 |
+
version_compare(fw()->manifest->get_version(), $requirements['min_version'], '<')
|
194 |
+
) {
|
195 |
+
$this->not_met_requirement = array(
|
196 |
+
'requirement' => $requirement,
|
197 |
+
'requirements' => $requirements
|
198 |
+
);
|
199 |
+
$this->not_met_is_final = true;
|
200 |
+
break 2;
|
201 |
+
}
|
202 |
+
|
203 |
+
if (
|
204 |
+
isset($requirements['max_version'])
|
205 |
+
&&
|
206 |
+
version_compare(fw()->manifest->get_version(), $requirements['max_version'], '>')
|
207 |
+
) {
|
208 |
+
$this->not_met_requirement = array(
|
209 |
+
'requirement' => $requirement,
|
210 |
+
'requirements' => $requirements
|
211 |
+
);
|
212 |
+
$this->not_met_is_final = true;
|
213 |
+
break 2;
|
214 |
+
}
|
215 |
+
|
216 |
+
// met
|
217 |
+
unset($this->requirements_for_verification[$requirement]);
|
218 |
+
break;
|
219 |
+
case 'extensions':
|
220 |
+
$extensions =& $requirements;
|
221 |
+
|
222 |
+
foreach ($extensions as $extension => $extension_requirements) {
|
223 |
+
$extension_instance = fw()->extensions->get($extension);
|
224 |
+
|
225 |
+
if (!$extension_instance) {
|
226 |
+
/**
|
227 |
+
* extension in requirements does not exists
|
228 |
+
* maybe try call this method later and maybe will exist, or it really does not exists
|
229 |
+
*/
|
230 |
+
$this->not_met_requirement = array(
|
231 |
+
'requirement' => $requirement,
|
232 |
+
'extension' => $extension,
|
233 |
+
'requirements' => $extension_requirements
|
234 |
+
);
|
235 |
+
break 3;
|
236 |
+
}
|
237 |
+
|
238 |
+
if (
|
239 |
+
isset($extension_requirements['min_version'])
|
240 |
+
&&
|
241 |
+
version_compare($extension_instance->manifest->get_version(), $extension_requirements['min_version'], '<')
|
242 |
+
) {
|
243 |
+
$this->not_met_requirement = array(
|
244 |
+
'requirement' => $requirement,
|
245 |
+
'extension' => $extension,
|
246 |
+
'requirements' => $extension_requirements
|
247 |
+
);
|
248 |
+
$this->not_met_is_final = true;
|
249 |
+
break 3;
|
250 |
+
}
|
251 |
+
|
252 |
+
if (
|
253 |
+
isset($extension_requirements['max_version'])
|
254 |
+
&&
|
255 |
+
version_compare($extension_instance->manifest->get_version(), $extension_requirements['max_version'], '>')
|
256 |
+
) {
|
257 |
+
$this->not_met_requirement = array(
|
258 |
+
'requirement' => $requirement,
|
259 |
+
'extension' => $extension,
|
260 |
+
'requirements' => $extension_requirements
|
261 |
+
);
|
262 |
+
$this->not_met_is_final = true;
|
263 |
+
break 3;
|
264 |
+
}
|
265 |
+
|
266 |
+
// met
|
267 |
+
unset($this->requirements_for_verification[$requirement][$extension]);
|
268 |
+
}
|
269 |
+
|
270 |
+
if (empty($this->requirements_for_verification[$requirement])) {
|
271 |
+
// all extensions requirements met
|
272 |
+
unset($this->requirements_for_verification[$requirement]);
|
273 |
+
}
|
274 |
+
break;
|
275 |
+
}
|
276 |
+
}
|
277 |
+
|
278 |
+
return $this->requirements_met();
|
279 |
+
}
|
280 |
+
|
281 |
+
public function get_version()
|
282 |
+
{
|
283 |
+
return $this->manifest['version'];
|
284 |
+
}
|
285 |
+
|
286 |
+
public function get_name()
|
287 |
+
{
|
288 |
+
return $this->manifest['name'];
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* @param string $multi_key
|
293 |
+
* @param mixed $default_value
|
294 |
+
* @return mixed
|
295 |
+
*/
|
296 |
+
public function get( $multi_key, $default_value = null ) {
|
297 |
+
return fw_akg( $multi_key, $this->manifest, $default_value );
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Get entire manifest.
|
302 |
+
* @return array
|
303 |
+
*/
|
304 |
+
public function get_manifest() {
|
305 |
+
return $this->manifest;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Call this only after check_requirements() failed
|
310 |
+
* @return array
|
311 |
+
*/
|
312 |
+
public function get_not_met_requirement()
|
313 |
+
{
|
314 |
+
return $this->not_met_requirement;
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Return user friendly requirement as text
|
319 |
+
* Call this only after check_requirements() failed
|
320 |
+
* @return string
|
321 |
+
*/
|
322 |
+
public function get_not_met_requirement_text()
|
323 |
+
{
|
324 |
+
if (!$this->not_met_requirement) {
|
325 |
+
return '';
|
326 |
+
}
|
327 |
+
|
328 |
+
$requirement = array();
|
329 |
+
|
330 |
+
foreach ($this->not_met_requirement['requirements'] as $req_key => $req) {
|
331 |
+
switch ($req_key) {
|
332 |
+
case 'min_version':
|
333 |
+
$requirement[] = __('minimum required version is', 'fw') .' '. $req;
|
334 |
+
break;
|
335 |
+
case 'max_version':
|
336 |
+
$requirement[] = __('maximum required version is', 'fw') .' '. $req;
|
337 |
+
break;
|
338 |
+
}
|
339 |
+
}
|
340 |
+
|
341 |
+
$requirement = implode(' '. __('and', 'fw') .' ', $requirement);
|
342 |
+
|
343 |
+
switch ($this->not_met_requirement['requirement']) {
|
344 |
+
case 'php':
|
345 |
+
if ( ! function_exists( 'phpversion' ) ) {
|
346 |
+
break;
|
347 |
+
}
|
348 |
+
|
349 |
+
$requirement = sprintf(
|
350 |
+
__('Current PHP version is %s, %s', 'fw'),
|
351 |
+
phpversion(), $requirement
|
352 |
+
);
|
353 |
+
break;
|
354 |
+
case 'wordpress':
|
355 |
+
global $wp_version;
|
356 |
+
|
357 |
+
$requirement = sprintf(
|
358 |
+
__('Current WordPress version is %s, %s', 'fw'),
|
359 |
+
$wp_version, $requirement
|
360 |
+
);
|
361 |
+
break;
|
362 |
+
case 'framework':
|
363 |
+
$requirement = sprintf(
|
364 |
+
__('Current Framework version is %s, %s', 'fw'),
|
365 |
+
fw()->manifest->get_version(), $requirement
|
366 |
+
);
|
367 |
+
break;
|
368 |
+
case 'extensions':
|
369 |
+
$extension = fw()->extensions->get($this->not_met_requirement['extension']);
|
370 |
+
|
371 |
+
if ($extension) {
|
372 |
+
$requirement = sprintf(
|
373 |
+
__('Current version of the %s extension is %s, %s', 'fw'),
|
374 |
+
$extension->manifest->get_name(), $extension->manifest->get_version(), $requirement
|
375 |
+
);
|
376 |
+
} else {
|
377 |
+
if (empty($requirement)) {
|
378 |
+
$requirement = sprintf(
|
379 |
+
__('%s extension is required', 'fw'),
|
380 |
+
ucfirst($this->not_met_requirement['extension'])
|
381 |
+
);
|
382 |
+
} else {
|
383 |
+
$requirement = sprintf(
|
384 |
+
__('%s extension is required (%s)', 'fw'),
|
385 |
+
ucfirst($this->not_met_requirement['extension']), $requirement
|
386 |
+
);
|
387 |
+
}
|
388 |
+
}
|
389 |
+
break;
|
390 |
+
default:
|
391 |
+
$requirement = 'Unknown requirement "'. $this->not_met_requirement['requirement'] .'"';
|
392 |
+
}
|
393 |
+
|
394 |
+
return $requirement;
|
395 |
+
}
|
396 |
+
}
|
397 |
+
|
398 |
+
class FW_Framework_Manifest extends FW_Manifest
|
399 |
+
{
|
400 |
+
public function __construct(array $manifest)
|
401 |
+
{
|
402 |
+
if (empty($manifest['name'])) {
|
403 |
+
$manifest['name'] = __('Framework', 'fw');
|
404 |
+
}
|
405 |
+
|
406 |
+
parent::__construct($manifest);
|
407 |
+
}
|
408 |
+
|
409 |
+
protected function get_default_requirements()
|
410 |
+
{
|
411 |
+
return array(
|
412 |
+
'php' => array(
|
413 |
+
'min_version' => '5.2.4',
|
414 |
+
/*'max_version' => '10000.0.0',*/
|
415 |
+
),
|
416 |
+
'wordpress' => array(
|
417 |
+
'min_version' => '4.0',
|
418 |
+
/*'max_version' => '10000.0.0',*/
|
419 |
+
),
|
420 |
+
);
|
421 |
+
}
|
422 |
+
}
|
423 |
+
|
424 |
+
class FW_Theme_Manifest extends FW_Manifest
|
425 |
+
{
|
426 |
+
public function __construct(array $manifest)
|
427 |
+
{
|
428 |
+
$manifest_defaults = array(
|
429 |
+
/**
|
430 |
+
* You can use this in a wp_option id,
|
431 |
+
* so that option value will be different on a theme with different id.
|
432 |
+
*
|
433 |
+
* fixme: default value should be get_option( 'stylesheet' ) but it can't be changed now
|
434 |
+
* because there can be themes that has saved Theme Settings in wp_option: 'fw_theme_settings_options:default'
|
435 |
+
* changing this default value will result in Theme Settings options "reset".
|
436 |
+
*/
|
437 |
+
'id' => 'default',
|
438 |
+
'supported_extensions' => array(
|
439 |
+
/*
|
440 |
+
'extension_name' => array(),
|
441 |
+
*/
|
442 |
+
),
|
443 |
+
);
|
444 |
+
|
445 |
+
$theme = wp_get_theme();
|
446 |
+
|
447 |
+
foreach(array(
|
448 |
+
'name' => 'Name',
|
449 |
+
'uri' => 'ThemeURI',
|
450 |
+
'description' => 'Description',
|
451 |
+
'version' => 'Version',
|
452 |
+
'author' => 'Author',
|
453 |
+
'author_uri' => 'AuthorURI',
|
454 |
+
) as $manifest_key => $stylesheet_header) {
|
455 |
+
$header_value = trim($theme->get($stylesheet_header));
|
456 |
+
|
457 |
+
if ( is_child_theme() && $theme->parent() ) {
|
458 |
+
switch ($manifest_key) {
|
459 |
+
case 'version':
|
460 |
+
case 'uri':
|
461 |
+
case 'author':
|
462 |
+
case 'author_uri':
|
463 |
+
case 'license':
|
464 |
+
// force parent theme value
|
465 |
+
$header_value = $theme->parent()->get($stylesheet_header);
|
466 |
+
break;
|
467 |
+
default:
|
468 |
+
if (!$header_value) {
|
469 |
+
// use parent theme value only if child theme value is empty
|
470 |
+
$header_value = $theme->parent()->get($stylesheet_header);
|
471 |
+
}
|
472 |
+
}
|
473 |
+
}
|
474 |
+
|
475 |
+
if ($header_value) {
|
476 |
+
$manifest_defaults[$manifest_key] = $header_value;
|
477 |
+
}
|
478 |
+
}
|
479 |
+
|
480 |
+
parent::__construct(array_merge($manifest_defaults, $manifest));
|
481 |
+
}
|
482 |
+
|
483 |
+
protected function get_default_requirements()
|
484 |
+
{
|
485 |
+
return array(
|
486 |
+
'php' => array(
|
487 |
+
'min_version' => '5.2.4',
|
488 |
+
/*'max_version' => '10000.0.0',*/
|
489 |
+
),
|
490 |
+
'wordpress' => array(
|
491 |
+
'min_version' => '4.0',
|
492 |
+
/*'max_version' => '10000.0.0',*/
|
493 |
+
),
|
494 |
+
'framework' => array(
|
495 |
+
/*'min_version' => '0.0.0',
|
496 |
+
'max_version' => '1000.0.0'*/
|
497 |
+
),
|
498 |
+
'extensions' => array(
|
499 |
+
/*'extension_name' => array(
|
500 |
+
'min_version' => '0.0.0',
|
501 |
+
'max_version' => '1000.0.0'
|
502 |
+
)*/
|
503 |
+
)
|
504 |
+
);
|
505 |
+
}
|
506 |
+
|
507 |
+
public function get_id()
|
508 |
+
{
|
509 |
+
return $this->manifest['id'];
|
510 |
+
}
|
511 |
+
}
|
512 |
+
|
513 |
+
class FW_Extension_Manifest extends FW_Manifest
|
514 |
+
{
|
515 |
+
public function __construct(array $manifest)
|
516 |
+
{
|
517 |
+
parent::__construct($manifest);
|
518 |
+
|
519 |
+
unset($manifest);
|
520 |
+
|
521 |
+
// unset unnecessary keys
|
522 |
+
unset($this->manifest['id']);
|
523 |
+
|
524 |
+
$this->manifest = array_merge(array(
|
525 |
+
/**
|
526 |
+
* @type bool Display on the Extensions page or it's a hidden extension
|
527 |
+
*/
|
528 |
+
'display' => false,
|
529 |
+
/**
|
530 |
+
* @type bool If extension can exist alone
|
531 |
+
* false - There is no sense for it to exist alone, it exists only when is required by some other extension.
|
532 |
+
* true - Can exist alone without bothering about other extensions.
|
533 |
+
*/
|
534 |
+
'standalone' => false,
|
535 |
+
/**
|
536 |
+
* @type string Thumbnail used on the Extensions page
|
537 |
+
* All framework extensions has thumbnails set in the available extensions list
|
538 |
+
* but if your extension is not in that list and id located in the theme, you can set the thumbnail via this parameter
|
539 |
+
*/
|
540 |
+
'thumbnail' => null,
|
541 |
+
), $this->manifest);
|
542 |
+
}
|
543 |
+
|
544 |
+
protected function get_default_requirements()
|
545 |
+
{
|
546 |
+
return array(
|
547 |
+
'php' => array(
|
548 |
+
'min_version' => '5.2.4',
|
549 |
+
/*'max_version' => '10000.0.0',*/
|
550 |
+
),
|
551 |
+
'wordpress' => array(
|
552 |
+
'min_version' => '4.0',
|
553 |
+
/*'max_version' => '10000.0.0',*/
|
554 |
+
),
|
555 |
+
'framework' => array(
|
556 |
+
/*'min_version' => '0.0.0',
|
557 |
+
'max_version' => '1000.0.0'*/
|
558 |
+
),
|
559 |
+
'extensions' => array(
|
560 |
+
/*'extension_name' => array(
|
561 |
+
'min_version' => '0.0.0',
|
562 |
+
'max_version' => '1000.0.0'
|
563 |
+
)*/
|
564 |
+
)
|
565 |
+
);
|
566 |
+
}
|
567 |
+
|
568 |
+
public function get_required_extensions()
|
569 |
+
{
|
570 |
+
return $this->manifest['requirements']['extensions'];
|
571 |
+
}
|
572 |
}
|
framework/core/components/backend.php
CHANGED
@@ -1,2054 +1,2062 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Backend functionality
|
7 |
-
*/
|
8 |
-
final class _FW_Component_Backend {
|
9 |
-
|
10 |
-
/** @var
|
11 |
-
private $
|
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 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
* @
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
* @
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
'
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
*
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
add_action('
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
* @
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
* @
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
'
|
361 |
-
),
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
'
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
'
|
393 |
-
'
|
394 |
-
'
|
395 |
-
'
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
fw
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
*
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
* @
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
'
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
'
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
'
|
585 |
-
|
586 |
-
|
587 |
-
'
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
*
|
608 |
-
*
|
609 |
-
* @
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
$
|
664 |
-
$
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
'
|
673 |
-
|
674 |
-
$
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
'
|
698 |
-
'
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
'
|
730 |
-
'
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
echo
|
744 |
-
echo '
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
.'
|
751 |
-
.'
|
752 |
-
.'
|
753 |
-
.'});'
|
754 |
-
.'
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
*
|
790 |
-
* @param
|
791 |
-
* @param
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
*
|
804 |
-
*
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
*
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
*
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
*
|
866 |
-
* - '
|
867 |
-
*
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
*
|
873 |
-
* -
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
* @param $
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
*
|
916 |
-
*
|
917 |
-
*
|
918 |
-
*
|
919 |
-
* @
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
$
|
928 |
-
$
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
'
|
946 |
-
|
947 |
-
.'<
|
948 |
-
.'<
|
949 |
-
.'<
|
950 |
-
.
|
951 |
-
."\n '
|
952 |
-
."\n
|
953 |
-
.
|
954 |
-
.'<p
|
955 |
-
'
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
"
|
976 |
-
"
|
977 |
-
|
978 |
-
$
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
*
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
$
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
$
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
*
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
*
|
1120 |
-
*
|
1121 |
-
*
|
1122 |
-
* -
|
1123 |
-
* -
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
*
|
1177 |
-
*
|
1178 |
-
*
|
1179 |
-
* -
|
1180 |
-
*
|
1181 |
-
*
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
*
|
1225 |
-
*
|
1226 |
-
*
|
1227 |
-
* -
|
1228 |
-
*
|
1229 |
-
*
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
$
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
*
|
1287 |
-
*
|
1288 |
-
* @param array $
|
1289 |
-
* @param array $
|
1290 |
-
* @param
|
1291 |
-
*
|
1292 |
-
*
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
*
|
1307 |
-
*
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
*
|
1313 |
-
*
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
'
|
1327 |
-
'
|
1328 |
-
'
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
'
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
'
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
$
|
1388 |
-
$
|
1389 |
-
$
|
1390 |
-
|
1391 |
-
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
'
|
1404 |
-
|
1405 |
-
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
-
|
1410 |
-
|
1411 |
-
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
|
1417 |
-
|
1418 |
-
*
|
1419 |
-
*
|
1420 |
-
*
|
1421 |
-
*
|
1422 |
-
*
|
1423 |
-
|
1424 |
-
|
1425 |
-
|
1426 |
-
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
|
1431 |
-
|
1432 |
-
|
1433 |
-
|
1434 |
-
*
|
1435 |
-
*
|
1436 |
-
|
1437 |
-
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
*
|
1442 |
-
*
|
1443 |
-
|
1444 |
-
|
1445 |
-
|
1446 |
-
|
1447 |
-
|
1448 |
-
|
1449 |
-
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
'
|
1460 |
-
'
|
1461 |
-
'
|
1462 |
-
|
1463 |
-
|
1464 |
-
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
* @
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
*
|
1482 |
-
*
|
1483 |
-
* @param
|
1484 |
-
* @param array $
|
1485 |
-
* @param
|
1486 |
-
*
|
1487 |
-
*
|
1488 |
-
|
1489 |
-
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
if (
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
) {
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
|
1504 |
-
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
}
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
|
1518 |
-
|
1519 |
-
'
|
1520 |
-
|
1521 |
-
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
|
1529 |
-
|
1530 |
-
|
1531 |
-
|
1532 |
-
|
1533 |
-
|
1534 |
-
|
1535 |
-
|
1536 |
-
|
1537 |
-
|
1538 |
-
|
1539 |
-
|
1540 |
-
|
1541 |
-
|
1542 |
-
|
1543 |
-
|
1544 |
-
|
1545 |
-
|
1546 |
-
|
1547 |
-
|
1548 |
-
|
1549 |
-
|
1550 |
-
'
|
1551 |
-
|
1552 |
-
|
1553 |
-
|
1554 |
-
|
1555 |
-
|
1556 |
-
|
1557 |
-
|
1558 |
-
|
1559 |
-
)
|
1560 |
-
|
1561 |
-
|
1562 |
-
|
1563 |
-
|
1564 |
-
|
1565 |
-
|
1566 |
-
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
1572 |
-
|
1573 |
-
|
1574 |
-
|
1575 |
-
|
1576 |
-
|
1577 |
-
|
1578 |
-
|
1579 |
-
|
1580 |
-
|
1581 |
-
|
1582 |
-
|
1583 |
-
|
1584 |
-
|
1585 |
-
|
1586 |
-
|
1587 |
-
|
1588 |
-
|
1589 |
-
|
1590 |
-
|
1591 |
-
|
1592 |
-
|
1593 |
-
|
1594 |
-
|
1595 |
-
|
1596 |
-
|
1597 |
-
|
1598 |
-
|
1599 |
-
|
1600 |
-
|
1601 |
-
|
1602 |
-
|
1603 |
-
|
1604 |
-
|
1605 |
-
|
1606 |
-
|
1607 |
-
|
1608 |
-
|
1609 |
-
|
1610 |
-
|
1611 |
-
|
1612 |
-
|
1613 |
-
|
1614 |
-
|
1615 |
-
|
1616 |
-
|
1617 |
-
|
1618 |
-
|
1619 |
-
|
1620 |
-
|
1621 |
-
|
1622 |
-
|
1623 |
-
|
1624 |
-
|
1625 |
-
|
1626 |
-
|
1627 |
-
|
1628 |
-
|
1629 |
-
|
1630 |
-
|
1631 |
-
|
1632 |
-
|
1633 |
-
'<span>' . $placeholders['title'] . '</span>'
|
1634 |
-
|
1635 |
-
|
1636 |
-
|
1637 |
-
|
1638 |
-
|
1639 |
-
|
1640 |
-
|
1641 |
-
|
1642 |
-
|
1643 |
-
|
1644 |
-
|
1645 |
-
|
1646 |
-
|
1647 |
-
|
1648 |
-
|
1649 |
-
|
1650 |
-
|
1651 |
-
|
1652 |
-
|
1653 |
-
|
1654 |
-
|
1655 |
-
|
1656 |
-
|
1657 |
-
|
1658 |
-
|
1659 |
-
|
1660 |
-
|
1661 |
-
|
1662 |
-
|
1663 |
-
|
1664 |
-
|
1665 |
-
|
1666 |
-
|
1667 |
-
|
1668 |
-
$
|
1669 |
-
$
|
1670 |
-
$
|
1671 |
-
$
|
1672 |
-
|
1673 |
-
|
1674 |
-
|
1675 |
-
|
1676 |
-
|
1677 |
-
|
1678 |
-
|
1679 |
-
|
1680 |
-
|
1681 |
-
|
1682 |
-
|
1683 |
-
|
1684 |
-
|
1685 |
-
|
1686 |
-
|
1687 |
-
|
1688 |
-
|
1689 |
-
|
1690 |
-
|
1691 |
-
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
|
1696 |
-
|
1697 |
-
|
1698 |
-
|
1699 |
-
|
1700 |
-
|
1701 |
-
|
1702 |
-
|
1703 |
-
|
1704 |
-
|
1705 |
-
|
1706 |
-
|
1707 |
-
|
1708 |
-
|
1709 |
-
|
1710 |
-
|
1711 |
-
|
1712 |
-
|
1713 |
-
|
1714 |
-
|
1715 |
-
|
1716 |
-
|
1717 |
-
|
1718 |
-
|
1719 |
-
|
1720 |
-
|
1721 |
-
|
1722 |
-
|
1723 |
-
|
1724 |
-
|
1725 |
-
|
1726 |
-
|
1727 |
-
|
1728 |
-
|
1729 |
-
|
1730 |
-
|
1731 |
-
|
1732 |
-
|
1733 |
-
|
1734 |
-
if (
|
1735 |
-
|
1736 |
-
|
1737 |
-
|
1738 |
-
|
1739 |
-
|
1740 |
-
|
1741 |
-
|
1742 |
-
|
1743 |
-
|
1744 |
-
|
1745 |
-
|
1746 |
-
|
1747 |
-
|
1748 |
-
|
1749 |
-
|
1750 |
-
|
1751 |
-
|
1752 |
-
|
1753 |
-
|
1754 |
-
|
1755 |
-
*
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
1759 |
-
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
1765 |
-
|
1766 |
-
|
1767 |
-
* @
|
1768 |
-
|
1769 |
-
|
1770 |
-
|
1771 |
-
|
1772 |
-
|
1773 |
-
|
1774 |
-
|
1775 |
-
|
1776 |
-
|
1777 |
-
|
1778 |
-
|
1779 |
-
|
1780 |
-
|
1781 |
-
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
|
1787 |
-
|
1788 |
-
|
1789 |
-
|
1790 |
-
|
1791 |
-
|
1792 |
-
|
1793 |
-
if (
|
1794 |
-
|
1795 |
-
|
1796 |
-
|
1797 |
-
|
1798 |
-
|
1799 |
-
|
1800 |
-
|
1801 |
-
|
1802 |
-
|
1803 |
-
|
1804 |
-
|
1805 |
-
|
1806 |
-
|
1807 |
-
|
1808 |
-
|
1809 |
-
|
1810 |
-
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
|
1816 |
-
|
1817 |
-
|
1818 |
-
|
1819 |
-
|
1820 |
-
|
1821 |
-
|
1822 |
-
|
1823 |
-
|
1824 |
-
|
1825 |
-
|
1826 |
-
|
1827 |
-
|
1828 |
-
|
1829 |
-
|
1830 |
-
|
1831 |
-
|
1832 |
-
|
1833 |
-
|
1834 |
-
|
1835 |
-
|
1836 |
-
|
1837 |
-
|
1838 |
-
|
1839 |
-
|
1840 |
-
|
1841 |
-
|
1842 |
-
|
1843 |
-
|
1844 |
-
|
1845 |
-
|
1846 |
-
|
1847 |
-
'
|
1848 |
-
|
1849 |
-
|
1850 |
-
)
|
1851 |
-
|
1852 |
-
|
1853 |
-
|
1854 |
-
|
1855 |
-
|
1856 |
-
|
1857 |
-
|
1858 |
-
|
1859 |
-
|
1860 |
-
|
1861 |
-
|
1862 |
-
|
1863 |
-
|
1864 |
-
|
1865 |
-
|
1866 |
-
|
1867 |
-
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
-
|
1872 |
-
|
1873 |
-
|
1874 |
-
|
1875 |
-
|
1876 |
-
|
1877 |
-
|
1878 |
-
|
1879 |
-
|
1880 |
-
|
1881 |
-
|
1882 |
-
|
1883 |
-
|
1884 |
-
|
1885 |
-
|
1886 |
-
|
1887 |
-
|
1888 |
-
|
1889 |
-
|
1890 |
-
$
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
1895 |
-
|
1896 |
-
|
1897 |
-
|
1898 |
-
|
1899 |
-
|
1900 |
-
|
1901 |
-
|
1902 |
-
|
1903 |
-
|
1904 |
-
'
|
1905 |
-
|
1906 |
-
|
1907 |
-
|
1908 |
-
|
1909 |
-
|
1910 |
-
|
1911 |
-
|
1912 |
-
|
1913 |
-
|
1914 |
-
|
1915 |
-
|
1916 |
-
|
1917 |
-
|
1918 |
-
|
1919 |
-
|
1920 |
-
|
1921 |
-
|
1922 |
-
|
1923 |
-
|
1924 |
-
|
1925 |
-
|
1926 |
-
|
1927 |
-
|
1928 |
-
|
1929 |
-
|
1930 |
-
|
1931 |
-
|
1932 |
-
|
1933 |
-
|
1934 |
-
|
1935 |
-
|
1936 |
-
|
1937 |
-
|
1938 |
-
|
1939 |
-
|
1940 |
-
$
|
1941 |
-
|
1942 |
-
|
1943 |
-
|
1944 |
-
|
1945 |
-
|
1946 |
-
|
1947 |
-
|
1948 |
-
|
1949 |
-
|
1950 |
-
|
1951 |
-
|
1952 |
-
|
1953 |
-
|
1954 |
-
|
1955 |
-
|
1956 |
-
|
1957 |
-
|
1958 |
-
|
1959 |
-
|
1960 |
-
|
1961 |
-
|
1962 |
-
|
1963 |
-
|
1964 |
-
|
1965 |
-
|
1966 |
-
|
1967 |
-
|
1968 |
-
|
1969 |
-
|
1970 |
-
|
1971 |
-
|
1972 |
-
|
1973 |
-
|
1974 |
-
|
1975 |
-
|
1976 |
-
|
1977 |
-
|
1978 |
-
}
|
1979 |
-
|
1980 |
-
|
1981 |
-
|
1982 |
-
|
1983 |
-
|
1984 |
-
|
1985 |
-
|
1986 |
-
|
1987 |
-
|
1988 |
-
|
1989 |
-
|
1990 |
-
|
1991 |
-
|
1992 |
-
|
1993 |
-
|
1994 |
-
|
1995 |
-
|
1996 |
-
|
1997 |
-
)
|
1998 |
-
|
1999 |
-
|
2000 |
-
|
2001 |
-
|
2002 |
-
|
2003 |
-
|
2004 |
-
|
2005 |
-
|
2006 |
-
|
2007 |
-
|
2008 |
-
|
2009 |
-
|
2010 |
-
|
2011 |
-
|
2012 |
-
|
2013 |
-
|
2014 |
-
|
2015 |
-
|
2016 |
-
|
2017 |
-
|
2018 |
-
|
2019 |
-
|
2020 |
-
|
2021 |
-
|
2022 |
-
|
2023 |
-
|
2024 |
-
|
2025 |
-
|
2026 |
-
|
2027 |
-
|
2028 |
-
|
2029 |
-
|
2030 |
-
|
2031 |
-
|
2032 |
-
|
2033 |
-
|
2034 |
-
|
2035 |
-
|
2036 |
-
|
2037 |
-
|
2038 |
-
|
2039 |
-
|
2040 |
-
|
2041 |
-
|
2042 |
-
|
2043 |
-
|
2044 |
-
*
|
2045 |
-
*
|
2046 |
-
|
2047 |
-
|
2048 |
-
|
2049 |
-
|
2050 |
-
|
2051 |
-
|
2052 |
-
|
2053 |
-
|
2054 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Backend functionality
|
7 |
+
*/
|
8 |
+
final class _FW_Component_Backend {
|
9 |
+
|
10 |
+
/** @var FW_Settings_Form */
|
11 |
+
private $settings_form;
|
12 |
+
|
13 |
+
private $available_render_designs = array(
|
14 |
+
'default', 'taxonomy', 'customizer', 'empty'
|
15 |
+
);
|
16 |
+
|
17 |
+
private $default_render_design = 'default';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* The singleton instance of Parsedown class that is used across
|
21 |
+
* whole framework.
|
22 |
+
*
|
23 |
+
* @since 2.6.9
|
24 |
+
*/
|
25 |
+
private $markdown_parser = null;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Contains all option types
|
29 |
+
* @var FW_Option_Type[]
|
30 |
+
*/
|
31 |
+
private $option_types = array();
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var FW_Option_Type_Undefined
|
35 |
+
*/
|
36 |
+
private $undefined_option_type;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Store container types for registration, until they will be required
|
40 |
+
* @var array|false
|
41 |
+
* array Can have some pending container types in it
|
42 |
+
* false Container types already requested and was registered, so do not use pending anymore
|
43 |
+
*/
|
44 |
+
private $container_types_pending_registration = array();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Contains all container types
|
48 |
+
* @var FW_Container_Type[]
|
49 |
+
*/
|
50 |
+
private $container_types = array();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @var FW_Container_Type_Undefined
|
54 |
+
*/
|
55 |
+
private $undefined_container_type;
|
56 |
+
|
57 |
+
private $static_registered = false;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @var FW_Access_Key
|
61 |
+
*/
|
62 |
+
private $access_key;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @internal
|
66 |
+
*/
|
67 |
+
public function _get_settings_page_slug() {
|
68 |
+
return 'fw-settings';
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @return string
|
73 |
+
* @since 2.6.3
|
74 |
+
*/
|
75 |
+
public function get_options_name_attr_prefix() {
|
76 |
+
return 'fw_options';
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @return string
|
81 |
+
* @since 2.6.3
|
82 |
+
*/
|
83 |
+
public function get_options_id_attr_prefix() {
|
84 |
+
return 'fw-option-';
|
85 |
+
}
|
86 |
+
|
87 |
+
private function get_current_edit_taxonomy() {
|
88 |
+
static $cache_current_taxonomy_data = null;
|
89 |
+
|
90 |
+
if ( $cache_current_taxonomy_data !== null ) {
|
91 |
+
return $cache_current_taxonomy_data;
|
92 |
+
}
|
93 |
+
|
94 |
+
$result = array(
|
95 |
+
'taxonomy' => null,
|
96 |
+
'term_id' => 0,
|
97 |
+
);
|
98 |
+
|
99 |
+
do {
|
100 |
+
if ( ! is_admin() ) {
|
101 |
+
break;
|
102 |
+
}
|
103 |
+
|
104 |
+
// code from /wp-admin/admin.php line 110
|
105 |
+
{
|
106 |
+
if ( isset( $_REQUEST['taxonomy'] ) && taxonomy_exists( $_REQUEST['taxonomy'] ) ) {
|
107 |
+
$taxnow = $_REQUEST['taxonomy'];
|
108 |
+
} else {
|
109 |
+
$taxnow = '';
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
if ( empty( $taxnow ) ) {
|
114 |
+
break;
|
115 |
+
}
|
116 |
+
|
117 |
+
$result['taxonomy'] = $taxnow;
|
118 |
+
|
119 |
+
if ( empty( $_REQUEST['tag_ID'] ) ) {
|
120 |
+
return $result;
|
121 |
+
}
|
122 |
+
|
123 |
+
// code from /wp-admin/edit-tags.php
|
124 |
+
{
|
125 |
+
$tag_ID = (int) $_REQUEST['tag_ID'];
|
126 |
+
}
|
127 |
+
|
128 |
+
$result['term_id'] = $tag_ID;
|
129 |
+
} while ( false );
|
130 |
+
|
131 |
+
$cache_current_taxonomy_data = $result;
|
132 |
+
|
133 |
+
return $cache_current_taxonomy_data;
|
134 |
+
}
|
135 |
+
|
136 |
+
public function __construct() {}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* @internal
|
140 |
+
*/
|
141 |
+
public function _init() {
|
142 |
+
if ( is_admin() ) {
|
143 |
+
$this->settings_form = new FW_Settings_Form_Theme('theme-settings');
|
144 |
+
}
|
145 |
+
|
146 |
+
$this->add_actions();
|
147 |
+
$this->add_filters();
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @internal
|
152 |
+
*/
|
153 |
+
public function _after_components_init() {}
|
154 |
+
|
155 |
+
private function get_access_key()
|
156 |
+
{
|
157 |
+
if (!$this->access_key) {
|
158 |
+
$this->access_key = new FW_Access_Key('fw_backend');
|
159 |
+
}
|
160 |
+
|
161 |
+
return $this->access_key;
|
162 |
+
}
|
163 |
+
|
164 |
+
private function add_actions() {
|
165 |
+
if ( is_admin() ) {
|
166 |
+
add_action('add_meta_boxes', array($this, '_action_create_post_meta_boxes'), 10, 2);
|
167 |
+
add_action('init', array($this, '_action_init'), 20);
|
168 |
+
add_action('admin_enqueue_scripts', array($this, '_action_admin_register_scripts'),
|
169 |
+
/**
|
170 |
+
* Usually when someone register/enqueue a script/style to be used in other places
|
171 |
+
* in 'admin_enqueue_scripts' actions with default (not set) priority 10, they use priority 9.
|
172 |
+
* Use here priority 8, in case those scripts/styles used in actions with priority 9
|
173 |
+
* are using scripts/styles registered here
|
174 |
+
*/
|
175 |
+
8
|
176 |
+
);
|
177 |
+
add_action('admin_enqueue_scripts', array($this, '_action_admin_enqueue_scripts'),
|
178 |
+
/**
|
179 |
+
* In case some custom defined option types are using script/styles registered
|
180 |
+
* in actions with default priority 10 (make sure the enqueue is executed after register)
|
181 |
+
*/
|
182 |
+
11
|
183 |
+
);
|
184 |
+
|
185 |
+
// render and submit options from javascript
|
186 |
+
{
|
187 |
+
add_action('wp_ajax_fw_backend_options_render', array($this, '_action_ajax_options_render'));
|
188 |
+
add_action('wp_ajax_fw_backend_options_get_values', array($this, '_action_ajax_options_get_values'));
|
189 |
+
add_action('wp_ajax_fw_backend_options_get_values_json', array($this, '_action_ajax_options_get_values_json'));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
add_action('save_post', array($this, '_action_save_post'), 7, 3);
|
194 |
+
add_action('wp_restore_post_revision', array($this, '_action_restore_post_revision'), 10, 2);
|
195 |
+
add_action('_wp_put_post_revision', array($this, '_action__wp_put_post_revision'));
|
196 |
+
|
197 |
+
add_action('customize_register', array($this, '_action_customize_register'), 7);
|
198 |
+
}
|
199 |
+
|
200 |
+
private function add_filters() {
|
201 |
+
if ( is_admin() ) {
|
202 |
+
add_filter('admin_footer_text', array($this, '_filter_admin_footer_text'), 11);
|
203 |
+
add_filter('update_footer', array($this, '_filter_footer_version'), 11);
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* @param string|FW_Option_Type $option_type_class
|
209 |
+
* @param string|null $type
|
210 |
+
*
|
211 |
+
* @internal
|
212 |
+
*/
|
213 |
+
private function register_option_type( $option_type_class, $type = null ) {
|
214 |
+
if ( $type == null ) {
|
215 |
+
try {
|
216 |
+
$type = $this->get_instance( $option_type_class )->get_type();
|
217 |
+
} catch ( FW_Option_Type_Exception_Invalid_Class $exception ) {
|
218 |
+
if ( ! is_subclass_of( $option_type_class, 'FW_Option_Type' ) ) {
|
219 |
+
trigger_error( 'Invalid option type class ' . get_class( $option_type_class ), E_USER_WARNING );
|
220 |
+
|
221 |
+
return;
|
222 |
+
}
|
223 |
+
}
|
224 |
+
}
|
225 |
+
|
226 |
+
if ( isset( $this->option_types[ $type ] ) ) {
|
227 |
+
trigger_error( 'Option type "' . $type . '" already registered', E_USER_WARNING );
|
228 |
+
|
229 |
+
return;
|
230 |
+
}
|
231 |
+
|
232 |
+
$this->option_types[$type] = $option_type_class;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* @param string|FW_Container_Type $container_type_class
|
237 |
+
* @param string|null $type
|
238 |
+
*
|
239 |
+
* @internal
|
240 |
+
*/
|
241 |
+
private function register_container_type( $container_type_class, $type = null ) {
|
242 |
+
if ( $type == null ) {
|
243 |
+
try {
|
244 |
+
$type = $this->get_instance( $container_type_class )->get_type();
|
245 |
+
} catch ( FW_Option_Type_Exception_Invalid_Class $exception ) {
|
246 |
+
if ( ! is_subclass_of( $container_type_class, 'FW_Container_Type' ) ) {
|
247 |
+
trigger_error( 'Invalid container type class ' . get_class( $container_type_class ), E_USER_WARNING );
|
248 |
+
|
249 |
+
return;
|
250 |
+
}
|
251 |
+
}
|
252 |
+
}
|
253 |
+
|
254 |
+
if ( isset( $this->container_types[ $type ] ) ) {
|
255 |
+
trigger_error( 'Container type "' . $type . '" already registered', E_USER_WARNING );
|
256 |
+
|
257 |
+
return;
|
258 |
+
}
|
259 |
+
|
260 |
+
$this->container_types[$type] = $container_type_class;
|
261 |
+
}
|
262 |
+
|
263 |
+
private function register_static() {
|
264 |
+
if (
|
265 |
+
!doing_action('admin_enqueue_scripts')
|
266 |
+
&&
|
267 |
+
!did_action('admin_enqueue_scripts')
|
268 |
+
) {
|
269 |
+
/**
|
270 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
271 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
272 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
273 |
+
*/
|
274 |
+
return;
|
275 |
+
}
|
276 |
+
|
277 |
+
if ( $this->static_registered ) {
|
278 |
+
return;
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Register styles/scripts only in admin area, on frontend it's not allowed to use styles/scripts from framework backend core
|
283 |
+
* because they are meant to be used only in backend and can be changed in the future.
|
284 |
+
* If you want to use a style/script from framework backend core, copy it to your theme and enqueue as a theme style/script.
|
285 |
+
*/
|
286 |
+
if ( ! is_admin() ) {
|
287 |
+
$this->static_registered = true;
|
288 |
+
|
289 |
+
return;
|
290 |
+
}
|
291 |
+
|
292 |
+
wp_register_script(
|
293 |
+
'fw-events',
|
294 |
+
fw_get_framework_directory_uri( '/static/js/fw-events.js' ),
|
295 |
+
array(),
|
296 |
+
fw()->manifest->get_version(),
|
297 |
+
true
|
298 |
+
);
|
299 |
+
|
300 |
+
wp_register_script(
|
301 |
+
'fw-ie-fixes',
|
302 |
+
fw_get_framework_directory_uri( '/static/js/ie-fixes.js' ),
|
303 |
+
array(),
|
304 |
+
fw()->manifest->get_version(),
|
305 |
+
true
|
306 |
+
);
|
307 |
+
|
308 |
+
{
|
309 |
+
wp_register_style(
|
310 |
+
'qtip',
|
311 |
+
fw_get_framework_directory_uri( '/static/libs/qtip/css/jquery.qtip.min.css' ),
|
312 |
+
array(),
|
313 |
+
fw()->manifest->get_version()
|
314 |
+
);
|
315 |
+
wp_register_script(
|
316 |
+
'qtip',
|
317 |
+
fw_get_framework_directory_uri( '/static/libs/qtip/jquery.qtip.min.js' ),
|
318 |
+
array( 'jquery' ),
|
319 |
+
fw()->manifest->get_version()
|
320 |
+
);
|
321 |
+
}
|
322 |
+
|
323 |
+
/**
|
324 |
+
* Important!
|
325 |
+
* Call wp_enqueue_media() before wp_enqueue_script('fw') (or using 'fw' in your script dependencies)
|
326 |
+
* otherwise fw.OptionsModal won't work
|
327 |
+
*/
|
328 |
+
{
|
329 |
+
wp_register_style(
|
330 |
+
'fw',
|
331 |
+
fw_get_framework_directory_uri( '/static/css/fw.css' ),
|
332 |
+
array( 'qtip' ),
|
333 |
+
fw()->manifest->get_version()
|
334 |
+
);
|
335 |
+
|
336 |
+
wp_register_script(
|
337 |
+
'fw-reactive-options-registry',
|
338 |
+
fw_get_framework_directory_uri(
|
339 |
+
'/static/js/fw-reactive-options-registry.js'
|
340 |
+
),
|
341 |
+
array('fw', 'fw-events'),
|
342 |
+
false
|
343 |
+
);
|
344 |
+
|
345 |
+
wp_register_script(
|
346 |
+
'fw-reactive-options-simple-options',
|
347 |
+
fw_get_framework_directory_uri(
|
348 |
+
'/static/js/fw-reactive-options-simple-options.js'
|
349 |
+
),
|
350 |
+
array('fw', 'fw-events', 'fw-reactive-options-undefined-option'),
|
351 |
+
false
|
352 |
+
);
|
353 |
+
|
354 |
+
wp_register_script(
|
355 |
+
'fw-reactive-options-undefined-option',
|
356 |
+
fw_get_framework_directory_uri(
|
357 |
+
'/static/js/fw-reactive-options-undefined-option.js'
|
358 |
+
),
|
359 |
+
array(
|
360 |
+
'fw', 'fw-events', 'fw-reactive-options-registry'
|
361 |
+
),
|
362 |
+
false
|
363 |
+
);
|
364 |
+
|
365 |
+
wp_register_script(
|
366 |
+
'fw-reactive-options',
|
367 |
+
fw_get_framework_directory_uri('/static/js/fw-reactive-options.js'),
|
368 |
+
array(
|
369 |
+
'fw', 'fw-events', 'fw-reactive-options-undefined-option',
|
370 |
+
'fw-reactive-options-simple-options'
|
371 |
+
),
|
372 |
+
false
|
373 |
+
);
|
374 |
+
|
375 |
+
wp_register_script(
|
376 |
+
'fw',
|
377 |
+
fw_get_framework_directory_uri( '/static/js/fw.js' ),
|
378 |
+
array( 'jquery', 'fw-events', 'backbone', 'qtip' ),
|
379 |
+
fw()->manifest->get_version(),
|
380 |
+
false // false fixes https://github.com/ThemeFuse/Unyson/issues/1625#issuecomment-224219454
|
381 |
+
);
|
382 |
+
|
383 |
+
wp_localize_script( 'fw', '_fw_localized', array(
|
384 |
+
'FW_URI' => fw_get_framework_directory_uri(),
|
385 |
+
'SITE_URI' => site_url(),
|
386 |
+
'LOADER_URI' => apply_filters( 'fw_loader_image', fw_get_framework_directory_uri() . '/static/img/logo.svg' ),
|
387 |
+
'l10n' => array_merge(
|
388 |
+
$l10n = array(
|
389 |
+
'modal_save_btn' => __( 'Save', 'fw' ),
|
390 |
+
'done' => __( 'Done', 'fw' ),
|
391 |
+
'ah_sorry' => __( 'Ah, Sorry', 'fw' ),
|
392 |
+
'reset' => __( 'Reset', 'fw' ),
|
393 |
+
'apply' => __( 'Apply', 'fw' ),
|
394 |
+
'cancel' => __( 'Cancel', 'fw' ),
|
395 |
+
'ok' => __( 'Ok', 'fw' )
|
396 |
+
),
|
397 |
+
/**
|
398 |
+
* fixes https://github.com/ThemeFuse/Unyson/issues/2381
|
399 |
+
* @since 2.6.14
|
400 |
+
*/
|
401 |
+
apply_filters('fw_js_l10n', $l10n)
|
402 |
+
),
|
403 |
+
'options_modal' => array(
|
404 |
+
/** @since 2.6.13 */
|
405 |
+
'default_reset_bnt_disabled' => apply_filters('fw:option-modal:default:reset-btn-disabled', false)
|
406 |
+
),
|
407 |
+
) );
|
408 |
+
}
|
409 |
+
|
410 |
+
{
|
411 |
+
wp_register_style(
|
412 |
+
'fw-backend-options',
|
413 |
+
fw_get_framework_directory_uri( '/static/css/backend-options.css' ),
|
414 |
+
array( 'fw' ),
|
415 |
+
fw()->manifest->get_version()
|
416 |
+
);
|
417 |
+
|
418 |
+
wp_register_script(
|
419 |
+
'fw-backend-options',
|
420 |
+
fw_get_framework_directory_uri( '/static/js/backend-options.js' ),
|
421 |
+
array( 'fw', 'fw-events', 'fw-reactive-options', 'postbox', 'jquery-ui-tabs' ),
|
422 |
+
fw()->manifest->get_version(),
|
423 |
+
true
|
424 |
+
);
|
425 |
+
|
426 |
+
wp_localize_script( 'fw', '_fw_backend_options_localized', array(
|
427 |
+
'lazy_tabs' => fw()->theme->get_config('lazy_tabs')
|
428 |
+
) );
|
429 |
+
}
|
430 |
+
|
431 |
+
{
|
432 |
+
wp_register_style(
|
433 |
+
'fw-selectize',
|
434 |
+
fw_get_framework_directory_uri( '/static/libs/selectize/selectize.css' ),
|
435 |
+
array(),
|
436 |
+
fw()->manifest->get_version()
|
437 |
+
);
|
438 |
+
wp_register_script(
|
439 |
+
'fw-selectize',
|
440 |
+
fw_get_framework_directory_uri( '/static/libs/selectize/selectize.min.js' ),
|
441 |
+
array( 'jquery', 'fw-ie-fixes' ),
|
442 |
+
fw()->manifest->get_version(),
|
443 |
+
true
|
444 |
+
);
|
445 |
+
}
|
446 |
+
|
447 |
+
{
|
448 |
+
wp_register_script(
|
449 |
+
'fw-mousewheel',
|
450 |
+
fw_get_framework_directory_uri( '/static/libs/mousewheel/jquery.mousewheel.min.js' ),
|
451 |
+
array( 'jquery' ),
|
452 |
+
fw()->manifest->get_version(),
|
453 |
+
true
|
454 |
+
);
|
455 |
+
}
|
456 |
+
|
457 |
+
{
|
458 |
+
wp_register_style(
|
459 |
+
'fw-jscrollpane',
|
460 |
+
fw_get_framework_directory_uri( '/static/libs/jscrollpane/jquery.jscrollpane.css' ),
|
461 |
+
array(),
|
462 |
+
fw()->manifest->get_version()
|
463 |
+
);
|
464 |
+
wp_register_script( 'fw-jscrollpane',
|
465 |
+
fw_get_framework_directory_uri( '/static/libs/jscrollpane/jquery.jscrollpane.min.js' ),
|
466 |
+
array( 'jquery', 'fw-mousewheel' ),
|
467 |
+
fw()->manifest->get_version(),
|
468 |
+
true
|
469 |
+
);
|
470 |
+
}
|
471 |
+
|
472 |
+
wp_register_style(
|
473 |
+
'font-awesome',
|
474 |
+
fw_get_framework_directory_uri( '/static/libs/font-awesome/css/font-awesome.min.css' ),
|
475 |
+
array(),
|
476 |
+
fw()->manifest->get_version()
|
477 |
+
);
|
478 |
+
/**
|
479 |
+
* backwards compatibility, in case extensions are not up-to-date
|
480 |
+
* todo: remove in next major version
|
481 |
+
* https://github.com/ThemeFuse/Unyson/issues/2198
|
482 |
+
* @deprecated
|
483 |
+
*/
|
484 |
+
wp_register_style('fw-font-awesome', fw_get_framework_directory_uri( '/static/libs/font-awesome/css/font-awesome.min.css' ));
|
485 |
+
|
486 |
+
wp_register_script(
|
487 |
+
'backbone-relational',
|
488 |
+
fw_get_framework_directory_uri( '/static/libs/backbone-relational/backbone-relational.js' ),
|
489 |
+
array( 'backbone' ),
|
490 |
+
fw()->manifest->get_version(),
|
491 |
+
true
|
492 |
+
);
|
493 |
+
|
494 |
+
wp_register_script(
|
495 |
+
'fw-uri',
|
496 |
+
fw_get_framework_directory_uri( '/static/libs/uri/URI.js' ),
|
497 |
+
array(),
|
498 |
+
fw()->manifest->get_version(),
|
499 |
+
true
|
500 |
+
);
|
501 |
+
|
502 |
+
wp_register_script(
|
503 |
+
'fw-moment',
|
504 |
+
/**
|
505 |
+
* IMPORTANT: At the end of the script is added this line:
|
506 |
+
* moment.locale(document.documentElement.lang.slice(0, 2)); // fixes https://github.com/ThemeFuse/Unyson/issues/1767
|
507 |
+
*/
|
508 |
+
fw_get_framework_directory_uri( '/static/libs/moment/moment-with-locales.min.js' ),
|
509 |
+
array(),
|
510 |
+
fw()->manifest->get_version(),
|
511 |
+
true
|
512 |
+
);
|
513 |
+
|
514 |
+
wp_register_script(
|
515 |
+
'fw-form-helpers',
|
516 |
+
fw_get_framework_directory_uri( '/static/js/fw-form-helpers.js' ),
|
517 |
+
array( 'jquery' ),
|
518 |
+
fw()->manifest->get_version(),
|
519 |
+
true
|
520 |
+
);
|
521 |
+
|
522 |
+
wp_register_style(
|
523 |
+
'fw-unycon',
|
524 |
+
fw_get_framework_directory_uri( '/static/libs/unycon/unycon.css' ),
|
525 |
+
array(),
|
526 |
+
fw()->manifest->get_version()
|
527 |
+
);
|
528 |
+
|
529 |
+
$this->static_registered = true;
|
530 |
+
}
|
531 |
+
|
532 |
+
/**
|
533 |
+
* @param $class
|
534 |
+
*
|
535 |
+
* @return FW_Option_Type
|
536 |
+
* @throws FW_Option_Type_Exception_Invalid_Class
|
537 |
+
*/
|
538 |
+
protected function get_instance( $class ) {
|
539 |
+
if ( ! class_exists( $class )
|
540 |
+
|| (
|
541 |
+
! is_subclass_of( $class, 'FW_Option_Type' )
|
542 |
+
&&
|
543 |
+
! is_subclass_of( $class, 'FW_Container_Type' )
|
544 |
+
)
|
545 |
+
) {
|
546 |
+
throw new FW_Option_Type_Exception_Invalid_Class( $class );
|
547 |
+
}
|
548 |
+
|
549 |
+
return new $class;
|
550 |
+
}
|
551 |
+
|
552 |
+
public function _filter_admin_footer_text( $html ) {
|
553 |
+
if (
|
554 |
+
(
|
555 |
+
current_user_can( 'update_themes' )
|
556 |
+
||
|
557 |
+
current_user_can( 'update_plugins' )
|
558 |
+
)
|
559 |
+
&&
|
560 |
+
fw_current_screen_match(array(
|
561 |
+
'only' => array(
|
562 |
+
array('parent_base' => fw()->extensions->manager->get_page_slug()) // Unyson Extensions page
|
563 |
+
)
|
564 |
+
))
|
565 |
+
) {
|
566 |
+
return ( empty( $html ) ? '' : $html . '<br/>' )
|
567 |
+
. '<em>'
|
568 |
+
. str_replace(
|
569 |
+
array(
|
570 |
+
'{wp_review_link}',
|
571 |
+
'{facebook_share_link}',
|
572 |
+
'{twitter_share_link}',
|
573 |
+
),
|
574 |
+
array(
|
575 |
+
fw_html_tag('a', array(
|
576 |
+
'target' => '_blank',
|
577 |
+
'href' => 'https://wordpress.org/support/view/plugin-reviews/unyson?filter=5#postform',
|
578 |
+
), __('leave a review', 'fw')),
|
579 |
+
fw_html_tag('a', array(
|
580 |
+
'target' => '_blank',
|
581 |
+
'href' => 'https://www.facebook.com/sharer/sharer.php?'. http_build_query(array(
|
582 |
+
'u' => 'http://unyson.io',
|
583 |
+
)),
|
584 |
+
'onclick' => 'return !window.open(this.href, \'Facebook\', \'width=640,height=300\')',
|
585 |
+
), __('Facebook', 'fw')),
|
586 |
+
fw_html_tag('a', array(
|
587 |
+
'target' => '_blank',
|
588 |
+
'href' => 'https://twitter.com/home?'. http_build_query(array(
|
589 |
+
'status' => __('Unyson WordPress Framework is the fastest and easiest way to develop a premium theme. I highly recommend it', 'fw')
|
590 |
+
.' http://unyson.io/ #UnysonWP',
|
591 |
+
)),
|
592 |
+
'onclick' => 'return !window.open(this.href, \'Twitter\', \'width=640,height=430\')',
|
593 |
+
), __('Twitter', 'fw')),
|
594 |
+
),
|
595 |
+
__('If you like Unyson, {wp_review_link}, share on {facebook_share_link} or {twitter_share_link}.', 'fw')
|
596 |
+
)
|
597 |
+
. '</em>';
|
598 |
+
} else {
|
599 |
+
return $html;
|
600 |
+
}
|
601 |
+
}
|
602 |
+
|
603 |
+
/**
|
604 |
+
* Print framework version in the admin footer
|
605 |
+
*
|
606 |
+
* @param string $html
|
607 |
+
*
|
608 |
+
* @return string
|
609 |
+
* @internal
|
610 |
+
*/
|
611 |
+
public function _filter_footer_version( $html ) {
|
612 |
+
if ( current_user_can( 'update_themes' ) || current_user_can( 'update_plugins' ) ) {
|
613 |
+
return ( empty( $html ) ? '' : $html . ' | ' ) . fw()->manifest->get_name() . ' ' . fw()->manifest->get_version();
|
614 |
+
} else {
|
615 |
+
return $html;
|
616 |
+
}
|
617 |
+
}
|
618 |
+
|
619 |
+
/**
|
620 |
+
* @param string $post_type
|
621 |
+
* @param WP_Post $post
|
622 |
+
*/
|
623 |
+
public function _action_create_post_meta_boxes( $post_type, $post ) {
|
624 |
+
if ( 'comment' === $post_type || ( isset( $_GET['vc_action'] ) && $_GET['vc_action'] === 'vc_inline' ) ) {
|
625 |
+
/**
|
626 |
+
* 1. https://github.com/ThemeFuse/Unyson/issues/3052
|
627 |
+
* 2. This is wrong, comment is not a post(type) it is stored in a separate db table and has a separate meta (wp_comments and wp_commentmeta)
|
628 |
+
*/
|
629 |
+
return;
|
630 |
+
}
|
631 |
+
|
632 |
+
$options = fw()->theme->get_post_options( $post_type );
|
633 |
+
|
634 |
+
if ( empty( $options ) ) {
|
635 |
+
return;
|
636 |
+
}
|
637 |
+
|
638 |
+
$collected = array();
|
639 |
+
|
640 |
+
fw_collect_options( $collected, $options, array(
|
641 |
+
'limit_option_types' => false,
|
642 |
+
'limit_container_types' => false,
|
643 |
+
'limit_level' => 1,
|
644 |
+
) );
|
645 |
+
|
646 |
+
if ( empty( $collected ) ) {
|
647 |
+
return;
|
648 |
+
}
|
649 |
+
|
650 |
+
$values = fw_get_db_post_option( $post->ID );
|
651 |
+
|
652 |
+
foreach ( $collected as $id => &$option ) {
|
653 |
+
if ( isset( $option['options'] ) && ( $option['type'] === 'box' || $option['type'] === 'group' ) ) {
|
654 |
+
$context = isset( $option['context'] ) ? $option['context'] : 'normal';
|
655 |
+
$priority = isset( $option['priority'] ) ? $option['priority'] : 'default';
|
656 |
+
|
657 |
+
add_meta_box(
|
658 |
+
"fw-options-box-{$id}",
|
659 |
+
empty( $option['title'] ) ? ' ' : $option['title'],
|
660 |
+
array( $this, 'render_meta_box' ),
|
661 |
+
$post_type,
|
662 |
+
$context,
|
663 |
+
$priority,
|
664 |
+
$this->render_options( $option['options'], $values )
|
665 |
+
);
|
666 |
+
} else { // this is not a box, wrap it in auto-generated box
|
667 |
+
add_meta_box(
|
668 |
+
'fw-options-box:auto-generated:' . time() . ':' . fw_unique_increment(),
|
669 |
+
' ',
|
670 |
+
array( $this, 'render_meta_box' ),
|
671 |
+
$post_type,
|
672 |
+
'normal',
|
673 |
+
'default',
|
674 |
+
$this->render_options( array( $id => $option ), $values )
|
675 |
+
);
|
676 |
+
}
|
677 |
+
}
|
678 |
+
}
|
679 |
+
|
680 |
+
public function render_meta_box( $post, $args ) {
|
681 |
+
echo $args['args'];
|
682 |
+
}
|
683 |
+
|
684 |
+
/**
|
685 |
+
* @param object $term
|
686 |
+
*/
|
687 |
+
public function _action_create_taxonomy_options( $term ) {
|
688 |
+
$options = fw()->theme->get_taxonomy_options( $term->taxonomy );
|
689 |
+
|
690 |
+
if ( empty( $options ) ) {
|
691 |
+
return;
|
692 |
+
}
|
693 |
+
|
694 |
+
$collected = array();
|
695 |
+
|
696 |
+
fw_collect_options( $collected, $options, array(
|
697 |
+
'limit_option_types' => false,
|
698 |
+
'limit_container_types' => false,
|
699 |
+
'limit_level' => 1,
|
700 |
+
) );
|
701 |
+
|
702 |
+
if ( empty( $collected ) ) {
|
703 |
+
return;
|
704 |
+
}
|
705 |
+
|
706 |
+
$values = fw_get_db_term_option( $term->term_id, $term->taxonomy );
|
707 |
+
|
708 |
+
// fixes word_press style: .form-field input { width: 95% }
|
709 |
+
echo '<style type="text/css">.fw-option-type-radio input, .fw-option-type-checkbox input { width: auto; }</style>';
|
710 |
+
|
711 |
+
do_action( 'fw_backend_options_render:taxonomy:before' );
|
712 |
+
echo $this->render_options( $collected, $values, array(), 'taxonomy' );
|
713 |
+
do_action( 'fw_backend_options_render:taxonomy:after' );
|
714 |
+
}
|
715 |
+
|
716 |
+
/**
|
717 |
+
* @param string $taxonomy
|
718 |
+
*/
|
719 |
+
public function _action_create_add_taxonomy_options( $taxonomy ) {
|
720 |
+
$options = fw()->theme->get_taxonomy_options( $taxonomy );
|
721 |
+
|
722 |
+
if ( empty( $options ) ) {
|
723 |
+
return;
|
724 |
+
}
|
725 |
+
|
726 |
+
$collected = array();
|
727 |
+
|
728 |
+
fw_collect_options( $collected, $options, array(
|
729 |
+
'limit_option_types' => false,
|
730 |
+
'limit_container_types' => false,
|
731 |
+
'limit_level' => 1,
|
732 |
+
) );
|
733 |
+
|
734 |
+
if ( empty( $collected ) ) {
|
735 |
+
return;
|
736 |
+
}
|
737 |
+
|
738 |
+
// fixes word_press style: .form-field input { width: 95% }
|
739 |
+
echo '<style type="text/css">.fw-option-type-radio input, .fw-option-type-checkbox input { width: auto; }</style>';
|
740 |
+
|
741 |
+
do_action( 'fw_backend_options_render:taxonomy:before' );
|
742 |
+
|
743 |
+
echo '<div class="fw-force-xs">';
|
744 |
+
echo $this->render_options( $collected, array(), array(), 'taxonomy' );
|
745 |
+
echo '</div>';
|
746 |
+
|
747 |
+
do_action( 'fw_backend_options_render:taxonomy:after' );
|
748 |
+
|
749 |
+
echo '<script type="text/javascript">'
|
750 |
+
.'jQuery(function($){'
|
751 |
+
.' $("#submit").on("click", function(){'
|
752 |
+
.' $("html, body").animate({ scrollTop: $("#col-left").offset().top });'
|
753 |
+
.' });'
|
754 |
+
.'});'
|
755 |
+
.'</script>';
|
756 |
+
}
|
757 |
+
|
758 |
+
public function _action_init() {
|
759 |
+
$current_edit_taxonomy = $this->get_current_edit_taxonomy();
|
760 |
+
|
761 |
+
if ( $current_edit_taxonomy['taxonomy'] ) {
|
762 |
+
add_action(
|
763 |
+
$current_edit_taxonomy['taxonomy'] . '_edit_form',
|
764 |
+
array( $this, '_action_create_taxonomy_options' )
|
765 |
+
);
|
766 |
+
|
767 |
+
if (fw()->theme->get_config('taxonomy_create_has_unyson_options', true)) {
|
768 |
+
add_action(
|
769 |
+
$current_edit_taxonomy['taxonomy'] . '_add_form_fields',
|
770 |
+
array( $this, '_action_create_add_taxonomy_options' )
|
771 |
+
);
|
772 |
+
}
|
773 |
+
}
|
774 |
+
|
775 |
+
if ( ! empty( $_POST ) ) {
|
776 |
+
// is form submit
|
777 |
+
add_action( 'edited_term', array( $this, '_action_term_edit' ), 10, 3 );
|
778 |
+
|
779 |
+
if ($current_edit_taxonomy['taxonomy']) {
|
780 |
+
add_action(
|
781 |
+
'create_' . $current_edit_taxonomy['taxonomy'],
|
782 |
+
array($this, '_action_save_taxonomy_fields')
|
783 |
+
);
|
784 |
+
}
|
785 |
+
}
|
786 |
+
}
|
787 |
+
|
788 |
+
/**
|
789 |
+
* Save meta from $_POST to fw options (post meta)
|
790 |
+
* @param int $post_id
|
791 |
+
* @param WP_Post $post
|
792 |
+
* @param bool $update
|
793 |
+
*/
|
794 |
+
public function _action_save_post( $post_id, $post, $update ) {
|
795 |
+
if (
|
796 |
+
isset($_POST['post_ID'])
|
797 |
+
&&
|
798 |
+
intval($_POST['post_ID']) === intval($post_id)
|
799 |
+
&&
|
800 |
+
!empty($_POST[ $this->get_options_name_attr_prefix() ]) // this happens on Quick Edit
|
801 |
+
) {
|
802 |
+
/**
|
803 |
+
* This happens on regular post form submit
|
804 |
+
* All data from $_POST belongs this $post
|
805 |
+
* so we save them in its post meta
|
806 |
+
*/
|
807 |
+
|
808 |
+
static $post_options_save_happened = false;
|
809 |
+
if ($post_options_save_happened) {
|
810 |
+
/**
|
811 |
+
* Prevent multiple options save for same post
|
812 |
+
* It can happen from a recursion or wp_update_post() for same post id
|
813 |
+
*/
|
814 |
+
return;
|
815 |
+
} else {
|
816 |
+
$post_options_save_happened = true;
|
817 |
+
}
|
818 |
+
|
819 |
+
$old_values = (array)fw_get_db_post_option($post_id);
|
820 |
+
|
821 |
+
fw_set_db_post_option(
|
822 |
+
$post_id,
|
823 |
+
null,
|
824 |
+
fw_get_options_values_from_input(
|
825 |
+
fw()->theme->get_post_options($post->post_type)
|
826 |
+
)
|
827 |
+
);
|
828 |
+
|
829 |
+
/**
|
830 |
+
* @deprecated
|
831 |
+
* Use the 'fw_post_options_update' action
|
832 |
+
*/
|
833 |
+
do_action( 'fw_save_post_options', $post_id, $post, $old_values );
|
834 |
+
} elseif ($original_post_id = wp_is_post_autosave( $post_id )) {
|
835 |
+
do {
|
836 |
+
$parent = get_post($post->post_parent);
|
837 |
+
|
838 |
+
if ( ! $parent instanceof WP_Post ) {
|
839 |
+
break;
|
840 |
+
}
|
841 |
+
|
842 |
+
if (
|
843 |
+
isset($_POST['post_ID'])
|
844 |
+
&&
|
845 |
+
intval($_POST['post_ID']) === intval($parent->ID)
|
846 |
+
) {} else {
|
847 |
+
break;
|
848 |
+
}
|
849 |
+
|
850 |
+
if (empty($_POST[ $this->get_options_name_attr_prefix() ])) {
|
851 |
+
// this happens on Quick Edit
|
852 |
+
break;
|
853 |
+
}
|
854 |
+
|
855 |
+
fw_set_db_post_option(
|
856 |
+
$post->ID,
|
857 |
+
null,
|
858 |
+
fw_get_options_values_from_input(
|
859 |
+
fw()->theme->get_post_options($parent->post_type)
|
860 |
+
)
|
861 |
+
);
|
862 |
+
} while(false);
|
863 |
+
} elseif ($original_post_id = wp_is_post_revision( $post_id )) {
|
864 |
+
/**
|
865 |
+
* Do nothing, the
|
866 |
+
* - '_wp_put_post_revision'
|
867 |
+
* - 'wp_restore_post_revision'
|
868 |
+
* actions will handle this
|
869 |
+
*/
|
870 |
+
} else {
|
871 |
+
/**
|
872 |
+
* This happens on:
|
873 |
+
* - post add (auto-draft): do nothing
|
874 |
+
* - revision restore: do nothing, that is handled by the 'wp_restore_post_revision' action
|
875 |
+
*/
|
876 |
+
}
|
877 |
+
}
|
878 |
+
|
879 |
+
/**
|
880 |
+
* @param $post_id
|
881 |
+
* @param $revision_id
|
882 |
+
*/
|
883 |
+
public function _action_restore_post_revision($post_id, $revision_id)
|
884 |
+
{
|
885 |
+
/**
|
886 |
+
* Copy options meta from revision to post
|
887 |
+
*/
|
888 |
+
fw_set_db_post_option(
|
889 |
+
$post_id,
|
890 |
+
null,
|
891 |
+
(array)fw_get_db_post_option($revision_id, null, array())
|
892 |
+
);
|
893 |
+
}
|
894 |
+
|
895 |
+
/**
|
896 |
+
* @param $revision_id
|
897 |
+
*/
|
898 |
+
public function _action__wp_put_post_revision($revision_id)
|
899 |
+
{
|
900 |
+
/**
|
901 |
+
* Copy options meta from post to revision
|
902 |
+
*/
|
903 |
+
fw_set_db_post_option(
|
904 |
+
$revision_id,
|
905 |
+
null,
|
906 |
+
(array)fw_get_db_post_option(
|
907 |
+
wp_is_post_revision($revision_id),
|
908 |
+
null,
|
909 |
+
array()
|
910 |
+
)
|
911 |
+
);
|
912 |
+
}
|
913 |
+
|
914 |
+
/**
|
915 |
+
* Update all post meta `fw_option:<option-id>` with values from post options that has the 'save-in-separate-meta' parameter
|
916 |
+
*
|
917 |
+
* @param int $post_id
|
918 |
+
*
|
919 |
+
* @return bool
|
920 |
+
* @deprecated since 2.5.0
|
921 |
+
*/
|
922 |
+
public function _sync_post_separate_meta( $post_id ) {
|
923 |
+
if ( ! ( $post_type = get_post_type( $post_id ) ) ) {
|
924 |
+
return false;
|
925 |
+
}
|
926 |
+
|
927 |
+
$meta_prefix = 'fw_option:';
|
928 |
+
$only_options = fw_extract_only_options( fw()->theme->get_post_options( $post_type ) );
|
929 |
+
$separate_meta_options = array();
|
930 |
+
|
931 |
+
// Collect all options that needs to be saved in separate meta
|
932 |
+
{
|
933 |
+
$options_values = fw_get_db_post_option( $post_id );
|
934 |
+
|
935 |
+
foreach ($only_options as $option_id => $option) {
|
936 |
+
if (
|
937 |
+
isset( $option['save-in-separate-meta'] )
|
938 |
+
&&
|
939 |
+
$option['save-in-separate-meta']
|
940 |
+
&&
|
941 |
+
array_key_exists( $option_id, $options_values )
|
942 |
+
) {
|
943 |
+
if (defined('WP_DEBUG') && WP_DEBUG) {
|
944 |
+
FW_Flash_Messages::add(
|
945 |
+
'save-in-separate-meta:deprecated',
|
946 |
+
'<p>The <code>save-in-separate-meta</code> option parameter is <strong>deprecated</strong>.</p>'
|
947 |
+
.'<p>Please replace</p>'
|
948 |
+
.'<pre>\'save-in-separate-meta\' => true</pre>'
|
949 |
+
.'<p>with</p>'
|
950 |
+
.'<pre>\'fw-storage\' => array('
|
951 |
+
."\n 'type' => 'post-meta',"
|
952 |
+
."\n 'post-meta' => 'fw_option:{your-option-id}',"
|
953 |
+
."\n)</pre>"
|
954 |
+
.'<p>in <code>{theme}'. fw_get_framework_customizations_dir_rel_path('/theme/options/posts/'. $post_type .'.php') .'</code></p>'
|
955 |
+
.'<p><a href="'. esc_attr('http://manual.unyson.io/en/latest/options/storage.html#content') .'" target="_blank">'. esc_html__('Info about fw-storage', 'fw') .'</a></p>',
|
956 |
+
'warning'
|
957 |
+
);
|
958 |
+
}
|
959 |
+
|
960 |
+
$separate_meta_options[ $meta_prefix . $option_id ] = $options_values[ $option_id ];
|
961 |
+
}
|
962 |
+
}
|
963 |
+
|
964 |
+
unset( $options_values );
|
965 |
+
}
|
966 |
+
|
967 |
+
// Delete meta that starts with $meta_prefix
|
968 |
+
{
|
969 |
+
/** @var wpdb $wpdb */
|
970 |
+
global $wpdb;
|
971 |
+
|
972 |
+
foreach (
|
973 |
+
$wpdb->get_results(
|
974 |
+
$wpdb->prepare(
|
975 |
+
"SELECT meta_key " .
|
976 |
+
"FROM {$wpdb->postmeta} " .
|
977 |
+
"WHERE meta_key LIKE %s AND post_id = %d",
|
978 |
+
$wpdb->esc_like( $meta_prefix ) . '%',
|
979 |
+
$post_id
|
980 |
+
)
|
981 |
+
) as $row
|
982 |
+
) {
|
983 |
+
if (
|
984 |
+
array_key_exists( $row->meta_key, $separate_meta_options )
|
985 |
+
||
|
986 |
+
( // skip options containing 'fw-storage'
|
987 |
+
($option_id = substr($row->meta_key, 10))
|
988 |
+
&&
|
989 |
+
isset($only_options[$option_id]['fw-storage'])
|
990 |
+
)
|
991 |
+
) {
|
992 |
+
/**
|
993 |
+
* This meta exists and will be updated below.
|
994 |
+
* Do not delete for performance reasons, instead of delete->insert will be performed only update
|
995 |
+
*/
|
996 |
+
continue;
|
997 |
+
} else {
|
998 |
+
// this option does not exist anymore
|
999 |
+
delete_post_meta( $post_id, $row->meta_key );
|
1000 |
+
}
|
1001 |
+
}
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
foreach ( $separate_meta_options as $meta_key => $option_value ) {
|
1005 |
+
fw_update_post_meta($post_id, $meta_key, $option_value );
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
return true;
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
/**
|
1012 |
+
* @param int $term_id
|
1013 |
+
*/
|
1014 |
+
public function _action_save_taxonomy_fields( $term_id ) {
|
1015 |
+
if (
|
1016 |
+
isset( $_POST['action'] )
|
1017 |
+
&&
|
1018 |
+
'add-tag' === $_POST['action']
|
1019 |
+
&&
|
1020 |
+
isset( $_POST['taxonomy'] )
|
1021 |
+
&&
|
1022 |
+
($taxonomy = get_taxonomy( $_POST['taxonomy'] ))
|
1023 |
+
&&
|
1024 |
+
current_user_can($taxonomy->cap->edit_terms)
|
1025 |
+
) { /* ok */ } else { return; }
|
1026 |
+
|
1027 |
+
$options = fw()->theme->get_taxonomy_options( $taxonomy->name );
|
1028 |
+
if ( empty( $options ) ) {
|
1029 |
+
return;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
fw_set_db_term_option(
|
1033 |
+
$term_id,
|
1034 |
+
$taxonomy->name,
|
1035 |
+
null,
|
1036 |
+
fw_get_options_values_from_input($options)
|
1037 |
+
);
|
1038 |
+
|
1039 |
+
do_action( 'fw_save_term_options', $term_id, $taxonomy->name, array() );
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
public function _action_term_edit( $term_id, $tt_id, $taxonomy ) {
|
1043 |
+
if (
|
1044 |
+
isset( $_POST['action'] )
|
1045 |
+
&&
|
1046 |
+
'editedtag' === $_POST['action']
|
1047 |
+
&&
|
1048 |
+
isset( $_POST['taxonomy'] )
|
1049 |
+
&&
|
1050 |
+
($taxonomy = get_taxonomy( $_POST['taxonomy'] ))
|
1051 |
+
&&
|
1052 |
+
current_user_can($taxonomy->cap->edit_terms)
|
1053 |
+
) { /* ok */ } else { return; }
|
1054 |
+
|
1055 |
+
if (intval(FW_Request::POST('tag_ID')) != $term_id) {
|
1056 |
+
// the $_POST values belongs to another term, do not save them into this one
|
1057 |
+
return;
|
1058 |
+
}
|
1059 |
+
|
1060 |
+
$options = fw()->theme->get_taxonomy_options( $taxonomy->name );
|
1061 |
+
if ( empty( $options ) ) {
|
1062 |
+
return;
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
$old_values = (array) fw_get_db_term_option( $term_id, $taxonomy->name );
|
1066 |
+
|
1067 |
+
fw_set_db_term_option(
|
1068 |
+
$term_id,
|
1069 |
+
$taxonomy->name,
|
1070 |
+
null,
|
1071 |
+
fw_get_options_values_from_input($options)
|
1072 |
+
);
|
1073 |
+
|
1074 |
+
do_action( 'fw_save_term_options', $term_id, $taxonomy->name, $old_values );
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
public function _action_admin_register_scripts() {
|
1078 |
+
$this->register_static();
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
public function _action_admin_enqueue_scripts() {
|
1082 |
+
/**
|
1083 |
+
* Enqueue settings options static in <head>
|
1084 |
+
* @see FW_Settings_Form_Theme::_action_admin_enqueue_scripts()
|
1085 |
+
*/
|
1086 |
+
|
1087 |
+
/**
|
1088 |
+
* Enqueue post options static in <head>
|
1089 |
+
*/
|
1090 |
+
{
|
1091 |
+
if ( 'post' === get_current_screen()->base && get_the_ID() ) {
|
1092 |
+
fw()->backend->enqueue_options_static(
|
1093 |
+
fw()->theme->get_post_options( get_post_type() )
|
1094 |
+
);
|
1095 |
+
|
1096 |
+
do_action( 'fw_admin_enqueue_scripts:post', get_post() );
|
1097 |
+
}
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
/**
|
1101 |
+
* Enqueue term options static in <head>
|
1102 |
+
*/
|
1103 |
+
{
|
1104 |
+
if (
|
1105 |
+
in_array(get_current_screen()->base, array('edit-tags', 'term'), true)
|
1106 |
+
&&
|
1107 |
+
get_current_screen()->taxonomy
|
1108 |
+
) {
|
1109 |
+
fw()->backend->enqueue_options_static(
|
1110 |
+
fw()->theme->get_taxonomy_options( get_current_screen()->taxonomy )
|
1111 |
+
);
|
1112 |
+
|
1113 |
+
do_action( 'fw_admin_enqueue_scripts:term', get_current_screen()->taxonomy );
|
1114 |
+
}
|
1115 |
+
}
|
1116 |
+
}
|
1117 |
+
|
1118 |
+
/**
|
1119 |
+
* Render options html from input json
|
1120 |
+
*
|
1121 |
+
* POST vars:
|
1122 |
+
* - options: '[{option_id: {...}}, {option_id: {...}}, ...]' // Required // String JSON
|
1123 |
+
* - values: {option_id: value, option_id: {...}, ...} // Optional // Object
|
1124 |
+
* - data: {id_prefix: 'fw_options-a-b-', name_prefix: 'fw_options[a][b]'} // Optional // Object
|
1125 |
+
*/
|
1126 |
+
public function _action_ajax_options_render() {
|
1127 |
+
// options
|
1128 |
+
{
|
1129 |
+
if ( ! isset( $_POST['options'] ) ) {
|
1130 |
+
wp_send_json_error( array(
|
1131 |
+
'message' => 'No options'
|
1132 |
+
) );
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
$options = json_decode( FW_Request::POST( 'options' ), true );
|
1136 |
+
|
1137 |
+
if ( ! $options ) {
|
1138 |
+
wp_send_json_error( array(
|
1139 |
+
'message' => 'Wrong options'
|
1140 |
+
) );
|
1141 |
+
}
|
1142 |
+
}
|
1143 |
+
|
1144 |
+
// values
|
1145 |
+
{
|
1146 |
+
if ( isset( $_POST['values'] ) ) {
|
1147 |
+
$values = FW_Request::POST( 'values' );
|
1148 |
+
|
1149 |
+
if (is_string($values)) {
|
1150 |
+
$values = json_decode($values, true);
|
1151 |
+
}
|
1152 |
+
} else {
|
1153 |
+
$values = array();
|
1154 |
+
}
|
1155 |
+
|
1156 |
+
$values = array_intersect_key($values, fw_extract_only_options($options));
|
1157 |
+
}
|
1158 |
+
|
1159 |
+
// data
|
1160 |
+
{
|
1161 |
+
if ( isset( $_POST['data'] ) ) {
|
1162 |
+
$data = FW_Request::POST( 'data' );
|
1163 |
+
} else {
|
1164 |
+
$data = array();
|
1165 |
+
}
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
wp_send_json_success( array(
|
1169 |
+
'html' => fw()->backend->render_options( $options, $values, $data ),
|
1170 |
+
/** @since 2.6.1 */
|
1171 |
+
'default_values' => fw_get_options_values_from_input($options, array()),
|
1172 |
+
) );
|
1173 |
+
}
|
1174 |
+
|
1175 |
+
/**
|
1176 |
+
* Get options values from html generated with 'fw_backend_options_render' ajax action
|
1177 |
+
*
|
1178 |
+
* POST vars:
|
1179 |
+
* - options: '[{option_id: {...}}, {option_id: {...}}, ...]' // Required // String JSON
|
1180 |
+
* - fw_options... // Use a jQuery "ajax form submit" to emulate real form submit
|
1181 |
+
*
|
1182 |
+
* Tip: Inside form html, add: <input type="hidden" name="options" value="[...json...]">
|
1183 |
+
*/
|
1184 |
+
public function _action_ajax_options_get_values() {
|
1185 |
+
// options
|
1186 |
+
{
|
1187 |
+
if ( ! isset( $_POST['options'] ) ) {
|
1188 |
+
wp_send_json_error( array(
|
1189 |
+
'message' => 'No options'
|
1190 |
+
) );
|
1191 |
+
}
|
1192 |
+
|
1193 |
+
$options = FW_Request::POST( 'options' );
|
1194 |
+
|
1195 |
+
if (is_string( $options )) {
|
1196 |
+
$options = json_decode( FW_Request::POST( 'options' ), true );
|
1197 |
+
}
|
1198 |
+
|
1199 |
+
if ( ! $options ) {
|
1200 |
+
wp_send_json_error( array(
|
1201 |
+
'message' => 'Wrong options'
|
1202 |
+
) );
|
1203 |
+
}
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
// name_prefix
|
1207 |
+
{
|
1208 |
+
if ( isset( $_POST['name_prefix'] ) ) {
|
1209 |
+
$name_prefix = FW_Request::POST( 'name_prefix' );
|
1210 |
+
} else {
|
1211 |
+
$name_prefix = $this->get_options_name_attr_prefix();
|
1212 |
+
}
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
wp_send_json_success( array(
|
1216 |
+
'values' => fw_get_options_values_from_input(
|
1217 |
+
$options,
|
1218 |
+
FW_Request::POST( fw_html_attr_name_to_array_multi_key( $name_prefix ), array() )
|
1219 |
+
)
|
1220 |
+
) );
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
/**
|
1224 |
+
* Get options values from html generated with 'fw_backend_options_render' ajax action
|
1225 |
+
*
|
1226 |
+
* POST vars:
|
1227 |
+
* - options: '[{option_id: {...}}, {option_id: {...}}, ...]' // Required // String JSON
|
1228 |
+
* - values: {option_id: {...}}
|
1229 |
+
*
|
1230 |
+
* Tip: Inside form html, add: <input type="hidden" name="options" value="[...json...]">
|
1231 |
+
*/
|
1232 |
+
public function _action_ajax_options_get_values_json() {
|
1233 |
+
// options
|
1234 |
+
{
|
1235 |
+
if ( ! isset( $_POST['options'] ) ) {
|
1236 |
+
wp_send_json_error( array(
|
1237 |
+
'message' => 'No options'
|
1238 |
+
) );
|
1239 |
+
}
|
1240 |
+
|
1241 |
+
$options = FW_Request::POST( 'options' );
|
1242 |
+
|
1243 |
+
if (is_string( $options )) {
|
1244 |
+
$options = json_decode( FW_Request::POST( 'options' ), true );
|
1245 |
+
}
|
1246 |
+
|
1247 |
+
if ( ! $options ) {
|
1248 |
+
wp_send_json_error( array(
|
1249 |
+
'message' => 'Wrong options'
|
1250 |
+
) );
|
1251 |
+
}
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
// values
|
1255 |
+
{
|
1256 |
+
if ( ! isset( $_POST['values'] ) ) {
|
1257 |
+
wp_send_json_error( array(
|
1258 |
+
'message' => 'No values'
|
1259 |
+
) );
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
$values = FW_Request::POST( 'values' );
|
1263 |
+
|
1264 |
+
if (is_string( $values )) {
|
1265 |
+
$values = json_decode( FW_Request::POST( 'values' ), true );
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
if (! is_array($values)) {
|
1269 |
+
if ( ! $values ) {
|
1270 |
+
wp_send_json_error(array(
|
1271 |
+
'message' => 'Wrong values'
|
1272 |
+
));
|
1273 |
+
}
|
1274 |
+
}
|
1275 |
+
}
|
1276 |
+
|
1277 |
+
wp_send_json_success( array(
|
1278 |
+
'values' => fw_get_options_values_from_input(
|
1279 |
+
$options,
|
1280 |
+
$values
|
1281 |
+
)
|
1282 |
+
) );
|
1283 |
+
}
|
1284 |
+
|
1285 |
+
/**
|
1286 |
+
* Render options array and return the generated HTML
|
1287 |
+
*
|
1288 |
+
* @param array $options
|
1289 |
+
* @param array $values Correct values returned by fw_get_options_values_from_input()
|
1290 |
+
* @param array $options_data {id_prefix => ..., name_prefix => ...}
|
1291 |
+
* @param string $design
|
1292 |
+
*
|
1293 |
+
* @return string HTML
|
1294 |
+
*/
|
1295 |
+
public function render_options( $options, $values = array(), $options_data = array(), $design = null ) {
|
1296 |
+
if (empty($design)) {
|
1297 |
+
$design = $this->default_render_design;
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
if (
|
1301 |
+
!doing_action('admin_enqueue_scripts')
|
1302 |
+
&&
|
1303 |
+
!did_action('admin_enqueue_scripts')
|
1304 |
+
) {
|
1305 |
+
/**
|
1306 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
1307 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
1308 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
1309 |
+
*/
|
1310 |
+
} else {
|
1311 |
+
/**
|
1312 |
+
* register scripts and styles
|
1313 |
+
* in case if this method is called before enqueue_scripts action
|
1314 |
+
* and option types has some of these in their dependencies
|
1315 |
+
*/
|
1316 |
+
$this->register_static();
|
1317 |
+
|
1318 |
+
wp_enqueue_media();
|
1319 |
+
wp_enqueue_style( 'fw-backend-options' );
|
1320 |
+
wp_enqueue_script( 'fw-backend-options' );
|
1321 |
+
}
|
1322 |
+
|
1323 |
+
$collected = array();
|
1324 |
+
|
1325 |
+
fw_collect_options( $collected, $options, array(
|
1326 |
+
'limit_option_types' => false,
|
1327 |
+
'limit_container_types' => false,
|
1328 |
+
'limit_level' => 1,
|
1329 |
+
'info_wrapper' => true,
|
1330 |
+
) );
|
1331 |
+
|
1332 |
+
if ( empty( $collected ) ) {
|
1333 |
+
return false;
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
$html = '';
|
1337 |
+
|
1338 |
+
$option = reset( $collected );
|
1339 |
+
|
1340 |
+
$collected_type = array(
|
1341 |
+
'group' => $option['group'],
|
1342 |
+
'type' => $option['option']['type'],
|
1343 |
+
);
|
1344 |
+
$collected_type_options = array(
|
1345 |
+
$option['id'] => &$option['option']
|
1346 |
+
);
|
1347 |
+
|
1348 |
+
while ( $collected_type_options ) {
|
1349 |
+
$option = next( $collected );
|
1350 |
+
|
1351 |
+
if ( $option ) {
|
1352 |
+
if (
|
1353 |
+
$option['group'] === $collected_type['group']
|
1354 |
+
&&
|
1355 |
+
$option['option']['type'] === $collected_type['type']
|
1356 |
+
) {
|
1357 |
+
$collected_type_options[ $option['id'] ] = &$option['option'];
|
1358 |
+
continue;
|
1359 |
+
}
|
1360 |
+
}
|
1361 |
+
|
1362 |
+
switch ( $collected_type['group'] ) {
|
1363 |
+
case 'container':
|
1364 |
+
if ($design === 'taxonomy') {
|
1365 |
+
$html .= fw_render_view(
|
1366 |
+
fw_get_framework_directory('/views/backend-container-design-'. $design .'.php'),
|
1367 |
+
array(
|
1368 |
+
'type' => $collected_type['type'],
|
1369 |
+
'html' => $this->container_type($collected_type['type'])->render(
|
1370 |
+
$collected_type_options, $values, $options_data
|
1371 |
+
),
|
1372 |
+
)
|
1373 |
+
);
|
1374 |
+
} else {
|
1375 |
+
$html .= $this->container_type($collected_type['type'])->render(
|
1376 |
+
$collected_type_options, $values, $options_data
|
1377 |
+
);
|
1378 |
+
}
|
1379 |
+
break;
|
1380 |
+
case 'option':
|
1381 |
+
foreach ( $collected_type_options as $id => &$_option ) {
|
1382 |
+
$data = $options_data; // do not change directly to not affect next loops
|
1383 |
+
|
1384 |
+
$data['value'] = isset( $values[ $id ] ) ? $values[ $id ] : null;
|
1385 |
+
|
1386 |
+
$html .= $this->render_option(
|
1387 |
+
$id,
|
1388 |
+
$_option,
|
1389 |
+
$data,
|
1390 |
+
$design
|
1391 |
+
);
|
1392 |
+
}
|
1393 |
+
unset($_option);
|
1394 |
+
break;
|
1395 |
+
default:
|
1396 |
+
$html .= '<p><em>' . __( 'Unknown collected group', 'fw' ) . ': ' . $collected_type['group'] . '</em></p>';
|
1397 |
+
}
|
1398 |
+
|
1399 |
+
unset( $collected_type, $collected_type_options );
|
1400 |
+
|
1401 |
+
if ( $option ) {
|
1402 |
+
$collected_type = array(
|
1403 |
+
'group' => $option['group'],
|
1404 |
+
'type' => $option['option']['type'],
|
1405 |
+
);
|
1406 |
+
$collected_type_options = array(
|
1407 |
+
$option['id'] => &$option['option']
|
1408 |
+
);
|
1409 |
+
} else {
|
1410 |
+
$collected_type_options = array();
|
1411 |
+
}
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
return $html;
|
1415 |
+
}
|
1416 |
+
|
1417 |
+
/**
|
1418 |
+
* Enqueue options static
|
1419 |
+
*
|
1420 |
+
* Useful when you have dynamic options html on the page (for e.g. options modal)
|
1421 |
+
* and in order to initialize that html properly, the option types scripts styles must be enqueued on the page
|
1422 |
+
*
|
1423 |
+
* @param array $options
|
1424 |
+
*/
|
1425 |
+
public function enqueue_options_static( $options ) {
|
1426 |
+
static $static_enqueue = true;
|
1427 |
+
|
1428 |
+
if (
|
1429 |
+
!doing_action('admin_enqueue_scripts')
|
1430 |
+
&&
|
1431 |
+
!did_action('admin_enqueue_scripts')
|
1432 |
+
) {
|
1433 |
+
/**
|
1434 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
1435 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
1436 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
1437 |
+
*/
|
1438 |
+
return;
|
1439 |
+
} else {
|
1440 |
+
/**
|
1441 |
+
* register scripts and styles
|
1442 |
+
* in case if this method is called before enqueue_scripts action
|
1443 |
+
* and option types has some of these in their dependencies
|
1444 |
+
*/
|
1445 |
+
if ($static_enqueue) {
|
1446 |
+
$this->register_static();
|
1447 |
+
|
1448 |
+
wp_enqueue_media();
|
1449 |
+
wp_enqueue_style( 'fw-backend-options' );
|
1450 |
+
wp_enqueue_script( 'fw-backend-options' );
|
1451 |
+
|
1452 |
+
$static_enqueue = false;
|
1453 |
+
}
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
$collected = array();
|
1457 |
+
|
1458 |
+
fw_collect_options( $collected, $options, array(
|
1459 |
+
'limit_option_types' => false,
|
1460 |
+
'limit_container_types' => false,
|
1461 |
+
'limit_level' => 0,
|
1462 |
+
'callback' => array(__CLASS__, '_callback_fw_collect_options_enqueue_static'),
|
1463 |
+
) );
|
1464 |
+
|
1465 |
+
unset($collected);
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
/**
|
1469 |
+
* @internal
|
1470 |
+
* @param array $data
|
1471 |
+
*/
|
1472 |
+
public static function _callback_fw_collect_options_enqueue_static($data) {
|
1473 |
+
if ($data['group'] === 'option') {
|
1474 |
+
fw()->backend->option_type($data['option']['type'])->enqueue_static($data['id'], $data['option']);
|
1475 |
+
} elseif ($data['group'] === 'container') {
|
1476 |
+
fw()->backend->container_type($data['option']['type'])->enqueue_static($data['id'], $data['option']);
|
1477 |
+
}
|
1478 |
+
}
|
1479 |
+
|
1480 |
+
/**
|
1481 |
+
* Render option enclosed in backend design
|
1482 |
+
*
|
1483 |
+
* @param string $id
|
1484 |
+
* @param array $option
|
1485 |
+
* @param array $data
|
1486 |
+
* @param string $design default or taxonomy
|
1487 |
+
*
|
1488 |
+
* @return string
|
1489 |
+
*/
|
1490 |
+
public function render_option( $id, $option, $data = array(), $design = null ) {
|
1491 |
+
|
1492 |
+
$maybe_forced_design = fw()->backend->option_type( $option['type'] )->get_forced_render_design();
|
1493 |
+
|
1494 |
+
if (empty($design)) {
|
1495 |
+
$design = $this->default_render_design;
|
1496 |
+
}
|
1497 |
+
|
1498 |
+
if ($maybe_forced_design) {
|
1499 |
+
$design = $maybe_forced_design;
|
1500 |
+
}
|
1501 |
+
|
1502 |
+
if (
|
1503 |
+
!doing_action('admin_enqueue_scripts')
|
1504 |
+
&&
|
1505 |
+
!did_action('admin_enqueue_scripts')
|
1506 |
+
) {
|
1507 |
+
/**
|
1508 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
1509 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
1510 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
1511 |
+
*/
|
1512 |
+
} else {
|
1513 |
+
$this->register_static();
|
1514 |
+
}
|
1515 |
+
|
1516 |
+
|
1517 |
+
if ( ! in_array( $design, $this->available_render_designs ) ) {
|
1518 |
+
trigger_error( 'Invalid render design specified: ' . $design, E_USER_WARNING );
|
1519 |
+
$design = 'post';
|
1520 |
+
}
|
1521 |
+
|
1522 |
+
if ( ! isset( $data['id_prefix'] ) ) {
|
1523 |
+
$data['id_prefix'] = $this->get_options_id_attr_prefix();
|
1524 |
+
}
|
1525 |
+
|
1526 |
+
$data = apply_filters(
|
1527 |
+
'fw:backend:option-render:data',
|
1528 |
+
$data
|
1529 |
+
);
|
1530 |
+
|
1531 |
+
return fw_render_view(fw_get_framework_directory('/views/backend-option-design-'. $design .'.php'), array(
|
1532 |
+
'id' => $id,
|
1533 |
+
'option' => $option,
|
1534 |
+
'data' => $data,
|
1535 |
+
) );
|
1536 |
+
}
|
1537 |
+
|
1538 |
+
/**
|
1539 |
+
* Render a meta box
|
1540 |
+
*
|
1541 |
+
* @param string $id
|
1542 |
+
* @param string $title
|
1543 |
+
* @param string $content HTML
|
1544 |
+
* @param array $other Optional elements
|
1545 |
+
*
|
1546 |
+
* @return string Generated meta box html
|
1547 |
+
*/
|
1548 |
+
public function render_box( $id, $title, $content, $other = array() ) {
|
1549 |
+
if ( ! function_exists( 'add_meta_box' ) ) {
|
1550 |
+
trigger_error( 'Try call this method later (\'admin_init\' action), add_meta_box() function does not exists yet.',
|
1551 |
+
E_USER_WARNING );
|
1552 |
+
|
1553 |
+
return '';
|
1554 |
+
}
|
1555 |
+
|
1556 |
+
$other = array_merge( array(
|
1557 |
+
'html_before_title' => false,
|
1558 |
+
'html_after_title' => false,
|
1559 |
+
'attr' => array(),
|
1560 |
+
), $other );
|
1561 |
+
|
1562 |
+
{
|
1563 |
+
$placeholders = array(
|
1564 |
+
'id' => '{{meta_box_id}}',
|
1565 |
+
'title' => '{{meta_box_title}}',
|
1566 |
+
'content' => '{{meta_box_content}}',
|
1567 |
+
);
|
1568 |
+
|
1569 |
+
// other placeholders
|
1570 |
+
{
|
1571 |
+
$placeholders['html_before_title'] = '{{meta_box_html_before_title}}';
|
1572 |
+
$placeholders['html_after_title'] = '{{meta_box_html_after_title}}';
|
1573 |
+
$placeholders['attr'] = '{{meta_box_attr}}';
|
1574 |
+
$placeholders['attr_class'] = '{{meta_box_attr_class}}';
|
1575 |
+
}
|
1576 |
+
}
|
1577 |
+
|
1578 |
+
$cache_key = 'fw_meta_box_template';
|
1579 |
+
|
1580 |
+
try {
|
1581 |
+
$meta_box_template = FW_Cache::get( $cache_key );
|
1582 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
1583 |
+
$temp_screen_id = 'fw-temp-meta-box-screen-id-' . fw_unique_increment();
|
1584 |
+
$context = 'normal';
|
1585 |
+
|
1586 |
+
add_meta_box(
|
1587 |
+
$placeholders['id'],
|
1588 |
+
$placeholders['title'],
|
1589 |
+
array( $this, 'render_meta_box' ),
|
1590 |
+
$temp_screen_id,
|
1591 |
+
$context,
|
1592 |
+
'default',
|
1593 |
+
$placeholders['content']
|
1594 |
+
);
|
1595 |
+
|
1596 |
+
ob_start();
|
1597 |
+
|
1598 |
+
do_meta_boxes( $temp_screen_id, $context, null );
|
1599 |
+
|
1600 |
+
$meta_box_template = ob_get_clean();
|
1601 |
+
|
1602 |
+
remove_meta_box( $id, $temp_screen_id, $context );
|
1603 |
+
|
1604 |
+
// remove wrapper div, leave only meta box div
|
1605 |
+
{
|
1606 |
+
// <div ...>
|
1607 |
+
{
|
1608 |
+
$meta_box_template = str_replace(
|
1609 |
+
'<div id="' . $context . '-sortables" class="meta-box-sortables">',
|
1610 |
+
'',
|
1611 |
+
$meta_box_template
|
1612 |
+
);
|
1613 |
+
}
|
1614 |
+
|
1615 |
+
// </div>
|
1616 |
+
{
|
1617 |
+
$meta_box_template = explode( '</div>', $meta_box_template );
|
1618 |
+
array_pop( $meta_box_template );
|
1619 |
+
$meta_box_template = implode( '</div>', $meta_box_template );
|
1620 |
+
}
|
1621 |
+
}
|
1622 |
+
|
1623 |
+
// add 'fw-postbox' class and some attr related placeholders
|
1624 |
+
$meta_box_template = str_replace(
|
1625 |
+
'class="postbox',
|
1626 |
+
$placeholders['attr'] . ' class="postbox fw-postbox' . $placeholders['attr_class'],
|
1627 |
+
$meta_box_template
|
1628 |
+
);
|
1629 |
+
|
1630 |
+
// add html_before|after_title placeholders
|
1631 |
+
{
|
1632 |
+
$meta_box_template = str_replace(
|
1633 |
+
'<span>' . $placeholders['title'] . '</span>',
|
1634 |
+
|
1635 |
+
/**
|
1636 |
+
* used <small> not <span> because there is a lot of css and js
|
1637 |
+
* that thinks inside <h2 class="hndle"> there is only one <span>
|
1638 |
+
* so do not brake their logic
|
1639 |
+
*/
|
1640 |
+
'<small class="fw-html-before-title">' . $placeholders['html_before_title'] . '</small>' .
|
1641 |
+
'<span>' . $placeholders['title'] . '</span>' .
|
1642 |
+
'<small class="fw-html-after-title">' . $placeholders['html_after_title'] . '</small>',
|
1643 |
+
|
1644 |
+
$meta_box_template
|
1645 |
+
);
|
1646 |
+
}
|
1647 |
+
|
1648 |
+
FW_Cache::set( $cache_key, $meta_box_template );
|
1649 |
+
}
|
1650 |
+
|
1651 |
+
// prepare attributes
|
1652 |
+
{
|
1653 |
+
$attr_class = '';
|
1654 |
+
if ( isset( $other['attr']['class'] ) ) {
|
1655 |
+
$attr_class = ' ' . $other['attr']['class'];
|
1656 |
+
|
1657 |
+
unset( $other['attr']['class'] );
|
1658 |
+
}
|
1659 |
+
|
1660 |
+
unset( $other['attr']['id'] );
|
1661 |
+
}
|
1662 |
+
|
1663 |
+
// replace placeholders with data/content
|
1664 |
+
return str_replace(
|
1665 |
+
array(
|
1666 |
+
$placeholders['id'],
|
1667 |
+
$placeholders['title'],
|
1668 |
+
$placeholders['content'],
|
1669 |
+
$placeholders['html_before_title'],
|
1670 |
+
$placeholders['html_after_title'],
|
1671 |
+
$placeholders['attr'],
|
1672 |
+
$placeholders['attr_class'],
|
1673 |
+
),
|
1674 |
+
array(
|
1675 |
+
esc_attr( $id ),
|
1676 |
+
$title,
|
1677 |
+
$content,
|
1678 |
+
$other['html_before_title'],
|
1679 |
+
$other['html_after_title'],
|
1680 |
+
fw_attr_to_html( $other['attr'] ),
|
1681 |
+
esc_attr( $attr_class )
|
1682 |
+
),
|
1683 |
+
$meta_box_template
|
1684 |
+
);
|
1685 |
+
}
|
1686 |
+
|
1687 |
+
/**
|
1688 |
+
* @param FW_Access_Key $access_key
|
1689 |
+
* @param string|FW_Option_Type $option_type_class
|
1690 |
+
*
|
1691 |
+
* @internal
|
1692 |
+
*/
|
1693 |
+
public function _register_option_type( FW_Access_Key $access_key, $option_type_class, $type= null ) {
|
1694 |
+
if ( $access_key->get_key() !== 'fw_option_type' ) {
|
1695 |
+
trigger_error( 'Call denied', E_USER_ERROR );
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
$this->register_option_type( $option_type_class, $type );
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
/**
|
1702 |
+
* @param FW_Access_Key $access_key
|
1703 |
+
* @param string|FW_Container_Type $container_type_class
|
1704 |
+
*
|
1705 |
+
* @internal
|
1706 |
+
*/
|
1707 |
+
public function _register_container_type( FW_Access_Key $access_key, $container_type_class ) {
|
1708 |
+
if ( $access_key->get_key() !== 'fw_container_type' ) {
|
1709 |
+
trigger_error( 'Call denied', E_USER_ERROR );
|
1710 |
+
}
|
1711 |
+
|
1712 |
+
$this->register_container_type( $container_type_class );
|
1713 |
+
}
|
1714 |
+
|
1715 |
+
/**
|
1716 |
+
* @param string $type
|
1717 |
+
* @return FW_Option_Type
|
1718 |
+
*/
|
1719 |
+
public function option_type( $type ) {
|
1720 |
+
static $did_options_init = false;
|
1721 |
+
if ( ! $did_options_init ) {
|
1722 |
+
$did_options_init = true;
|
1723 |
+
do_action( 'fw_option_types_init' );
|
1724 |
+
}
|
1725 |
+
|
1726 |
+
if ( isset( $this->option_types[ $type ] ) ) {
|
1727 |
+
if (is_string($this->option_types[$type])) {
|
1728 |
+
$this->option_types[$type] = $this->get_instance($this->option_types[$type]);
|
1729 |
+
$this->option_types[$type]->_call_init($this->get_access_key());
|
1730 |
+
}
|
1731 |
+
|
1732 |
+
return $this->option_types[$type];
|
1733 |
+
} else {
|
1734 |
+
if ( is_admin() && apply_filters('fw_backend_undefined_option_type_warn_user', true, $type) ) {
|
1735 |
+
FW_Flash_Messages::add(
|
1736 |
+
'fw-get-option-type-undefined-' . $type,
|
1737 |
+
sprintf( __( 'Undefined option type: %s', 'fw' ), $type ),
|
1738 |
+
'warning'
|
1739 |
+
);
|
1740 |
+
}
|
1741 |
+
|
1742 |
+
if ( ! $this->undefined_option_type ) {
|
1743 |
+
$this->undefined_option_type = new FW_Option_Type_Undefined();
|
1744 |
+
}
|
1745 |
+
|
1746 |
+
return $this->undefined_option_type;
|
1747 |
+
}
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
/**
|
1751 |
+
* Return an array with all option types names
|
1752 |
+
*
|
1753 |
+
* @return array
|
1754 |
+
*
|
1755 |
+
* @since 2.6.11
|
1756 |
+
*/
|
1757 |
+
public function get_option_types() {
|
1758 |
+
$this->option_type('text'); // trigger init
|
1759 |
+
return array_keys( $this->option_types );
|
1760 |
+
}
|
1761 |
+
|
1762 |
+
/**
|
1763 |
+
* Return an array with all container types names
|
1764 |
+
*
|
1765 |
+
* @return array
|
1766 |
+
*
|
1767 |
+
* @since 2.6.11
|
1768 |
+
*/
|
1769 |
+
public function get_container_types() {
|
1770 |
+
$this->container_type('box'); // trigger init
|
1771 |
+
return array_keys( $this->container_types );
|
1772 |
+
}
|
1773 |
+
|
1774 |
+
/**
|
1775 |
+
* @param string $type
|
1776 |
+
* @return FW_Container_Type
|
1777 |
+
*/
|
1778 |
+
public function container_type( $type ) {
|
1779 |
+
static $did_containers_init = false;
|
1780 |
+
if ( ! $did_containers_init ) {
|
1781 |
+
$did_containers_init = true;
|
1782 |
+
do_action( 'fw_container_types_init' );
|
1783 |
+
}
|
1784 |
+
|
1785 |
+
if ( isset( $this->container_types[ $type ] ) ) {
|
1786 |
+
if ( is_string( $this->container_types[ $type ] ) ) {
|
1787 |
+
$this->container_types[ $type ] = $this->get_instance( $this->container_types[$type] );
|
1788 |
+
$this->container_types[ $type ]->_call_init( $this->get_access_key() );
|
1789 |
+
}
|
1790 |
+
|
1791 |
+
return $this->container_types[ $type ];
|
1792 |
+
} else {
|
1793 |
+
if ( is_admin() ) {
|
1794 |
+
FW_Flash_Messages::add(
|
1795 |
+
'fw-get-container-type-undefined-' . $type,
|
1796 |
+
sprintf( __( 'Undefined container type: %s', 'fw' ), $type ),
|
1797 |
+
'warning'
|
1798 |
+
);
|
1799 |
+
}
|
1800 |
+
|
1801 |
+
if ( ! $this->undefined_container_type ) {
|
1802 |
+
$this->undefined_container_type = new FW_Container_Type_Undefined();
|
1803 |
+
}
|
1804 |
+
|
1805 |
+
return $this->undefined_container_type;
|
1806 |
+
}
|
1807 |
+
}
|
1808 |
+
|
1809 |
+
/**
|
1810 |
+
* @param WP_Customize_Manager $wp_customize
|
1811 |
+
* @internal
|
1812 |
+
*/
|
1813 |
+
public function _action_customize_register($wp_customize) {
|
1814 |
+
if (is_admin()) {
|
1815 |
+
add_action('admin_enqueue_scripts', array($this, '_action_enqueue_customizer_static'));
|
1816 |
+
}
|
1817 |
+
|
1818 |
+
$this->customizer_register_options(
|
1819 |
+
$wp_customize,
|
1820 |
+
fw()->theme->get_customizer_options()
|
1821 |
+
);
|
1822 |
+
}
|
1823 |
+
|
1824 |
+
/**
|
1825 |
+
* @internal
|
1826 |
+
*/
|
1827 |
+
public function _action_enqueue_customizer_static()
|
1828 |
+
{
|
1829 |
+
{
|
1830 |
+
$options_for_enqueue = array();
|
1831 |
+
$customizer_options = fw()->theme->get_customizer_options();
|
1832 |
+
|
1833 |
+
/**
|
1834 |
+
* In customizer options is allowed to have container with unspecified (or not existing) 'type'
|
1835 |
+
* fw()->backend->enqueue_options_static() tries to enqueue both options and container static
|
1836 |
+
* not existing container types will throw notices.
|
1837 |
+
* To prevent that, extract and send it only options (without containers)
|
1838 |
+
*/
|
1839 |
+
fw_collect_options($options_for_enqueue, $customizer_options, array(
|
1840 |
+
'callback' => array(__CLASS__, '_callback_fw_collect_options_enqueue_static'),
|
1841 |
+
));
|
1842 |
+
|
1843 |
+
unset($options_for_enqueue, $customizer_options);
|
1844 |
+
}
|
1845 |
+
|
1846 |
+
wp_enqueue_script(
|
1847 |
+
'fw-backend-customizer',
|
1848 |
+
fw_get_framework_directory_uri( '/static/js/backend-customizer.js' ),
|
1849 |
+
array( 'jquery', 'fw-events', 'backbone', 'fw-backend-options' ),
|
1850 |
+
fw()->manifest->get_version(),
|
1851 |
+
true
|
1852 |
+
);
|
1853 |
+
wp_localize_script(
|
1854 |
+
'fw-backend-customizer',
|
1855 |
+
'_fw_backend_customizer_localized',
|
1856 |
+
array(
|
1857 |
+
'change_timeout' => apply_filters('fw_customizer_option_change_timeout', 333),
|
1858 |
+
)
|
1859 |
+
);
|
1860 |
+
|
1861 |
+
do_action('fw_admin_enqueue_scripts:customizer');
|
1862 |
+
}
|
1863 |
+
|
1864 |
+
/**
|
1865 |
+
* @param WP_Customize_Manager $wp_customize
|
1866 |
+
* @param array $options
|
1867 |
+
* @param array $parent_data {'type':'...','id':'...'}
|
1868 |
+
*/
|
1869 |
+
private function customizer_register_options($wp_customize, $options, $parent_data = array()) {
|
1870 |
+
$collected = array();
|
1871 |
+
|
1872 |
+
fw_collect_options( $collected, $options, array(
|
1873 |
+
'limit_option_types' => false,
|
1874 |
+
'limit_container_types' => false,
|
1875 |
+
'limit_level' => 1,
|
1876 |
+
'info_wrapper' => true,
|
1877 |
+
) );
|
1878 |
+
|
1879 |
+
if ( empty( $collected ) ) {
|
1880 |
+
return;
|
1881 |
+
}
|
1882 |
+
|
1883 |
+
foreach ($collected as &$opt) {
|
1884 |
+
switch ($opt['group']) {
|
1885 |
+
case 'container':
|
1886 |
+
// Check if has container options
|
1887 |
+
{
|
1888 |
+
$_collected = array();
|
1889 |
+
|
1890 |
+
fw_collect_options( $_collected, $opt['option']['options'], array(
|
1891 |
+
'limit_option_types' => array(),
|
1892 |
+
'limit_container_types' => false,
|
1893 |
+
'limit_level' => 1,
|
1894 |
+
'limit' => 1,
|
1895 |
+
'info_wrapper' => false,
|
1896 |
+
) );
|
1897 |
+
|
1898 |
+
$has_containers = !empty($_collected);
|
1899 |
+
|
1900 |
+
unset($_collected);
|
1901 |
+
}
|
1902 |
+
|
1903 |
+
$children_data = array(
|
1904 |
+
'group' => 'container',
|
1905 |
+
'id' => $opt['id']
|
1906 |
+
);
|
1907 |
+
|
1908 |
+
$args = array(
|
1909 |
+
'title' => empty($opt['option']['title'])
|
1910 |
+
? fw_id_to_title($opt['id'])
|
1911 |
+
: $opt['option']['title'],
|
1912 |
+
'description' => empty($opt['option']['desc'])
|
1913 |
+
? ''
|
1914 |
+
: $opt['option']['desc'],
|
1915 |
+
);
|
1916 |
+
|
1917 |
+
if (isset($opt['option']['wp-customizer-args']) && is_array($opt['option']['wp-customizer-args'])) {
|
1918 |
+
$args = array_merge($opt['option']['wp-customizer-args'], $args);
|
1919 |
+
}
|
1920 |
+
|
1921 |
+
if ($has_containers) {
|
1922 |
+
if ($parent_data) {
|
1923 |
+
trigger_error($opt['id'] .' panel can\'t have a parent ('. $parent_data['id'] .')', E_USER_WARNING);
|
1924 |
+
break;
|
1925 |
+
}
|
1926 |
+
|
1927 |
+
$wp_customize->add_panel($opt['id'], $args);
|
1928 |
+
|
1929 |
+
$children_data['customizer_type'] = 'panel';
|
1930 |
+
} else {
|
1931 |
+
if ($parent_data) {
|
1932 |
+
if ($parent_data['customizer_type'] === 'panel') {
|
1933 |
+
$args['panel'] = $parent_data['id'];
|
1934 |
+
} else {
|
1935 |
+
trigger_error($opt['id'] .' section can have only panel parent ('. $parent_data['id'] .')', E_USER_WARNING);
|
1936 |
+
break;
|
1937 |
+
}
|
1938 |
+
}
|
1939 |
+
|
1940 |
+
$wp_customize->add_section($opt['id'], $args);
|
1941 |
+
|
1942 |
+
$children_data['customizer_type'] = 'section';
|
1943 |
+
}
|
1944 |
+
|
1945 |
+
$this->customizer_register_options(
|
1946 |
+
$wp_customize,
|
1947 |
+
$opt['option']['options'],
|
1948 |
+
$children_data
|
1949 |
+
);
|
1950 |
+
|
1951 |
+
unset($children_data);
|
1952 |
+
break;
|
1953 |
+
case 'option':
|
1954 |
+
$setting_id = $this->get_options_name_attr_prefix() .'['. $opt['id'] .']';
|
1955 |
+
|
1956 |
+
{
|
1957 |
+
$args_control = array(
|
1958 |
+
'label' => empty($opt['option']['label'])
|
1959 |
+
? fw_id_to_title($opt['id'])
|
1960 |
+
: $opt['option']['label'],
|
1961 |
+
'description' => empty($opt['option']['desc'])
|
1962 |
+
? ''
|
1963 |
+
: $opt['option']['desc'],
|
1964 |
+
'settings' => $setting_id,
|
1965 |
+
);
|
1966 |
+
|
1967 |
+
if (isset($opt['option']['wp-customizer-args']) && is_array($opt['option']['wp-customizer-args'])) {
|
1968 |
+
$args_control = array_merge($opt['option']['wp-customizer-args'], $args_control);
|
1969 |
+
}
|
1970 |
+
|
1971 |
+
if ($parent_data) {
|
1972 |
+
if ($parent_data['customizer_type'] === 'section') {
|
1973 |
+
$args_control['section'] = $parent_data['id'];
|
1974 |
+
} else {
|
1975 |
+
trigger_error('Invalid control parent: '. $parent_data['customizer_type'], E_USER_WARNING);
|
1976 |
+
break;
|
1977 |
+
}
|
1978 |
+
} else { // the option is not placed in a section, create a section automatically
|
1979 |
+
$args_control['section'] = 'fw_option_auto_section_'. $opt['id'];
|
1980 |
+
|
1981 |
+
$wp_customize->add_section($args_control['section'], array(
|
1982 |
+
'title' => empty($opt['option']['label'])
|
1983 |
+
? fw_id_to_title($opt['id'])
|
1984 |
+
: $opt['option']['label'],
|
1985 |
+
));
|
1986 |
+
}
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
{
|
1990 |
+
$args_setting = array(
|
1991 |
+
'default' => fw()->backend->option_type($opt['option']['type'])->get_value_from_input($opt['option'], null),
|
1992 |
+
'fw_option' => $opt['option'],
|
1993 |
+
'fw_option_id' => $opt['id'],
|
1994 |
+
);
|
1995 |
+
|
1996 |
+
if (isset($opt['option']['wp-customizer-setting-args']) && is_array($opt['option']['wp-customizer-setting-args'])) {
|
1997 |
+
$args_setting = array_merge($opt['option']['wp-customizer-setting-args'], $args_setting);
|
1998 |
+
}
|
1999 |
+
|
2000 |
+
$wp_customize->add_setting(
|
2001 |
+
new _FW_Customizer_Setting_Option(
|
2002 |
+
$wp_customize,
|
2003 |
+
$setting_id,
|
2004 |
+
$args_setting
|
2005 |
+
)
|
2006 |
+
);
|
2007 |
+
|
2008 |
+
unset($args_setting);
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
// control must be registered after setting
|
2012 |
+
$wp_customize->add_control(
|
2013 |
+
new _FW_Customizer_Control_Option_Wrapper(
|
2014 |
+
$wp_customize,
|
2015 |
+
$opt['id'],
|
2016 |
+
$args_control
|
2017 |
+
)
|
2018 |
+
);
|
2019 |
+
break;
|
2020 |
+
default:
|
2021 |
+
trigger_error('Unknown group: '. $opt['group'], E_USER_WARNING);
|
2022 |
+
}
|
2023 |
+
}
|
2024 |
+
}
|
2025 |
+
|
2026 |
+
/**
|
2027 |
+
* For e.g. an option-type was rendered using 'customizer' design,
|
2028 |
+
* but inside it uses render_options() but it doesn't know the current render design
|
2029 |
+
* and the options will be rendered with 'default' design.
|
2030 |
+
* This method allows to specify the default design that will be used if not specified on render_options()
|
2031 |
+
* @param null|string $design
|
2032 |
+
* @internal
|
2033 |
+
*/
|
2034 |
+
public function _set_default_render_design($design = null)
|
2035 |
+
{
|
2036 |
+
if (empty($design) || !in_array($design, $this->available_render_designs)) {
|
2037 |
+
$this->default_render_design = 'default';
|
2038 |
+
} else {
|
2039 |
+
$this->default_render_design = $design;
|
2040 |
+
}
|
2041 |
+
}
|
2042 |
+
|
2043 |
+
/**
|
2044 |
+
* Get markdown parser with autoloading and caching
|
2045 |
+
*
|
2046 |
+
* Usage:
|
2047 |
+
* fw()->backend->get_markdown_parser()
|
2048 |
+
*
|
2049 |
+
* @param bool $fresh_instance Whether to force return a fresh instance of the class
|
2050 |
+
*
|
2051 |
+
* @return Parsedown
|
2052 |
+
*
|
2053 |
+
* @since 2.6.9
|
2054 |
+
*/
|
2055 |
+
public function get_markdown_parser($fresh_instance = false) {
|
2056 |
+
if (! $this->markdown_parser || $fresh_instance) {
|
2057 |
+
$this->markdown_parser = new Parsedown();
|
2058 |
+
}
|
2059 |
+
|
2060 |
+
return $this->markdown_parser;
|
2061 |
+
}
|
2062 |
+
}
|
framework/core/components/backend/class-fw-settings-form-theme.php
CHANGED
@@ -1,218 +1,218 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Used in fw()->backend
|
5 |
-
* @internal
|
6 |
-
*/
|
7 |
-
class FW_Settings_Form_Theme extends FW_Settings_Form {
|
8 |
-
protected function _init() {
|
9 |
-
$this
|
10 |
-
->set_is_ajax_submit( fw()->theme->get_config('settings_form_ajax_submit') )
|
11 |
-
->set_is_side_tabs( fw()->theme->get_config('settings_form_side_tabs') )
|
12 |
-
->set_string( 'title', __('Theme Settings', 'fw') );
|
13 |
-
|
14 |
-
{
|
15 |
-
add_action('admin_init', array($this, '_action_get_title_from_menu'));
|
16 |
-
add_action('admin_menu', array($this, '_action_admin_menu'));
|
17 |
-
add_action('admin_enqueue_scripts', array($this, '_action_admin_enqueue_scripts'),
|
18 |
-
/**
|
19 |
-
* In case some custom defined option types are using script/styles registered
|
20 |
-
* in actions with default priority 10 (make sure the enqueue is executed after register)
|
21 |
-
* @see _FW_Component_Backend::add_actions()
|
22 |
-
*/
|
23 |
-
11
|
24 |
-
);
|
25 |
-
}
|
26 |
-
}
|
27 |
-
|
28 |
-
public function get_options() {
|
29 |
-
return fw()->theme->get_settings_options();
|
30 |
-
}
|
31 |
-
|
32 |
-
public function set_values($values) {
|
33 |
-
fw_set_db_settings_option(null, $values);
|
34 |
-
|
35 |
-
return $this;
|
36 |
-
}
|
37 |
-
|
38 |
-
public function get_values() {
|
39 |
-
return fw_get_db_settings_option();
|
40 |
-
}
|
41 |
-
|
42 |
-
/**
|
43 |
-
* User can overwrite Theme Settings menu, move it and change its title
|
44 |
-
* extract that title from WP menu
|
45 |
-
* @internal
|
46 |
-
*/
|
47 |
-
public function _action_get_title_from_menu() {
|
48 |
-
if ($this->get_is_side_tabs()) {
|
49 |
-
$title = fw()->theme->manifest->get_name();
|
50 |
-
|
51 |
-
if (fw()->theme->manifest->get('author')) {
|
52 |
-
if (fw()->theme->manifest->get('author_uri')) {
|
53 |
-
$title .= ' '. fw_html_tag('a', array(
|
54 |
-
'href' => fw()->theme->manifest->get('author_uri'),
|
55 |
-
'target' => '_blank'
|
56 |
-
), '<small>' . __('by', 'fw') . ' ' . fw()->theme->manifest->get('author') . '</small>');
|
57 |
-
} else {
|
58 |
-
$title .= ' <small>' . fw()->theme->manifest->get('author') . '</small>';
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
$this->set_string('title', $title);
|
63 |
-
} else {
|
64 |
-
// Extract page title from menu title
|
65 |
-
do {
|
66 |
-
global $menu, $submenu;
|
67 |
-
|
68 |
-
if (is_array($menu)) {
|
69 |
-
foreach ($menu as $_menu) {
|
70 |
-
if ($_menu[2] === fw()->backend->_get_settings_page_slug()) {
|
71 |
-
$title = $_menu[0];
|
72 |
-
break 2;
|
73 |
-
}
|
74 |
-
}
|
75 |
-
}
|
76 |
-
|
77 |
-
if (is_array($submenu)) {
|
78 |
-
foreach ($submenu as $_menu) {
|
79 |
-
foreach ($_menu as $_submenu) {
|
80 |
-
if ($_submenu[2] === fw()->backend->_get_settings_page_slug()) {
|
81 |
-
$title = $_submenu[0];
|
82 |
-
break 3;
|
83 |
-
}
|
84 |
-
}
|
85 |
-
}
|
86 |
-
}
|
87 |
-
} while(false);
|
88 |
-
|
89 |
-
if (isset($title)) {
|
90 |
-
$this->set_string('title', $title);
|
91 |
-
}
|
92 |
-
}
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* @internal
|
97 |
-
*/
|
98 |
-
public function _action_admin_menu() {
|
99 |
-
$data = array(
|
100 |
-
'capability' => 'manage_options',
|
101 |
-
'slug' => fw()->backend->_get_settings_page_slug(),
|
102 |
-
'content_callback' => array( $this, 'render' ),
|
103 |
-
);
|
104 |
-
|
105 |
-
if ( ! current_user_can( $data['capability'] ) ) {
|
106 |
-
return;
|
107 |
-
}
|
108 |
-
|
109 |
-
if ( ! fw()->theme->locate_path('/options/settings.php') ) {
|
110 |
-
return;
|
111 |
-
}
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Collect $hookname that contains $data['slug'] before the action
|
115 |
-
* and skip them in verification after action
|
116 |
-
*/
|
117 |
-
{
|
118 |
-
global $_registered_pages;
|
119 |
-
|
120 |
-
$found_hooknames = array();
|
121 |
-
|
122 |
-
if ( ! empty( $_registered_pages ) ) {
|
123 |
-
foreach ( $_registered_pages as $hookname => $b ) {
|
124 |
-
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
125 |
-
$found_hooknames[ $hookname ] = true;
|
126 |
-
}
|
127 |
-
}
|
128 |
-
}
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Use this action if you what to add the settings page in a custom place in menu
|
133 |
-
* Usage example http://pastebin.com/gvAjGRm1
|
134 |
-
*/
|
135 |
-
do_action( 'fw_backend_add_custom_settings_menu', $data );
|
136 |
-
|
137 |
-
/**
|
138 |
-
* Check if settings menu was added in the action above
|
139 |
-
*/
|
140 |
-
{
|
141 |
-
$menu_exists = false;
|
142 |
-
|
143 |
-
if ( ! empty( $_registered_pages ) ) {
|
144 |
-
foreach ( $_registered_pages as $hookname => $b ) {
|
145 |
-
if ( isset( $found_hooknames[ $hookname ] ) ) {
|
146 |
-
continue;
|
147 |
-
}
|
148 |
-
|
149 |
-
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
150 |
-
$menu_exists = true;
|
151 |
-
break;
|
152 |
-
}
|
153 |
-
}
|
154 |
-
}
|
155 |
-
}
|
156 |
-
|
157 |
-
if ( $menu_exists ) {
|
158 |
-
return;
|
159 |
-
}
|
160 |
-
|
161 |
-
add_theme_page(
|
162 |
-
__( 'Theme Settings', 'fw' ),
|
163 |
-
__( 'Theme Settings', 'fw' ),
|
164 |
-
$data['capability'],
|
165 |
-
$data['slug'],
|
166 |
-
$data['content_callback']
|
167 |
-
);
|
168 |
-
|
169 |
-
add_action( 'admin_menu', array( $this, '_action_admin_change_theme_settings_order' ), 9999 );
|
170 |
-
}
|
171 |
-
|
172 |
-
/**
|
173 |
-
* @internal
|
174 |
-
*/
|
175 |
-
public function _action_admin_change_theme_settings_order() {
|
176 |
-
global $submenu;
|
177 |
-
|
178 |
-
if ( ! isset( $submenu['themes.php'] ) ) {
|
179 |
-
// probably current user doesn't have this item in menu
|
180 |
-
return;
|
181 |
-
}
|
182 |
-
|
183 |
-
$id = fw()->backend->_get_settings_page_slug();
|
184 |
-
$index = null;
|
185 |
-
|
186 |
-
foreach ( $submenu['themes.php'] as $key => $sm ) {
|
187 |
-
if ( $sm[2] == $id ) {
|
188 |
-
$index = $key;
|
189 |
-
break;
|
190 |
-
}
|
191 |
-
}
|
192 |
-
|
193 |
-
if ( ! empty( $index ) ) {
|
194 |
-
$item = $submenu['themes.php'][ $index ];
|
195 |
-
unset( $submenu['themes.php'][ $index ] );
|
196 |
-
array_unshift( $submenu['themes.php'], $item );
|
197 |
-
}
|
198 |
-
}
|
199 |
-
|
200 |
-
/**
|
201 |
-
* @internal
|
202 |
-
*/
|
203 |
-
public function _action_admin_enqueue_scripts()
|
204 |
-
{
|
205 |
-
global $plugin_page;
|
206 |
-
|
207 |
-
/**
|
208 |
-
* Enqueue settings options static in <head>
|
209 |
-
*/
|
210 |
-
{
|
211 |
-
if (fw()->backend->_get_settings_page_slug() === $plugin_page) {
|
212 |
-
$this->enqueue_static();
|
213 |
-
|
214 |
-
do_action('fw_admin_enqueue_scripts:settings');
|
215 |
-
}
|
216 |
-
}
|
217 |
-
}
|
218 |
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Used in fw()->backend
|
5 |
+
* @internal
|
6 |
+
*/
|
7 |
+
class FW_Settings_Form_Theme extends FW_Settings_Form {
|
8 |
+
protected function _init() {
|
9 |
+
$this
|
10 |
+
->set_is_ajax_submit( fw()->theme->get_config('settings_form_ajax_submit') )
|
11 |
+
->set_is_side_tabs( fw()->theme->get_config('settings_form_side_tabs') )
|
12 |
+
->set_string( 'title', __('Theme Settings', 'fw') );
|
13 |
+
|
14 |
+
{
|
15 |
+
add_action('admin_init', array($this, '_action_get_title_from_menu'));
|
16 |
+
add_action('admin_menu', array($this, '_action_admin_menu'));
|
17 |
+
add_action('admin_enqueue_scripts', array($this, '_action_admin_enqueue_scripts'),
|
18 |
+
/**
|
19 |
+
* In case some custom defined option types are using script/styles registered
|
20 |
+
* in actions with default priority 10 (make sure the enqueue is executed after register)
|
21 |
+
* @see _FW_Component_Backend::add_actions()
|
22 |
+
*/
|
23 |
+
11
|
24 |
+
);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
public function get_options() {
|
29 |
+
return fw()->theme->get_settings_options();
|
30 |
+
}
|
31 |
+
|
32 |
+
public function set_values($values) {
|
33 |
+
fw_set_db_settings_option(null, $values);
|
34 |
+
|
35 |
+
return $this;
|
36 |
+
}
|
37 |
+
|
38 |
+
public function get_values() {
|
39 |
+
return fw_get_db_settings_option();
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* User can overwrite Theme Settings menu, move it and change its title
|
44 |
+
* extract that title from WP menu
|
45 |
+
* @internal
|
46 |
+
*/
|
47 |
+
public function _action_get_title_from_menu() {
|
48 |
+
if ($this->get_is_side_tabs()) {
|
49 |
+
$title = fw()->theme->manifest->get_name();
|
50 |
+
|
51 |
+
if (fw()->theme->manifest->get('author')) {
|
52 |
+
if (fw()->theme->manifest->get('author_uri')) {
|
53 |
+
$title .= ' '. fw_html_tag('a', array(
|
54 |
+
'href' => fw()->theme->manifest->get('author_uri'),
|
55 |
+
'target' => '_blank'
|
56 |
+
), '<small>' . __('by', 'fw') . ' ' . fw()->theme->manifest->get('author') . '</small>');
|
57 |
+
} else {
|
58 |
+
$title .= ' <small>' . fw()->theme->manifest->get('author') . '</small>';
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
$this->set_string('title', $title);
|
63 |
+
} else {
|
64 |
+
// Extract page title from menu title
|
65 |
+
do {
|
66 |
+
global $menu, $submenu;
|
67 |
+
|
68 |
+
if (is_array($menu)) {
|
69 |
+
foreach ($menu as $_menu) {
|
70 |
+
if ($_menu[2] === fw()->backend->_get_settings_page_slug()) {
|
71 |
+
$title = $_menu[0];
|
72 |
+
break 2;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
if (is_array($submenu)) {
|
78 |
+
foreach ($submenu as $_menu) {
|
79 |
+
foreach ($_menu as $_submenu) {
|
80 |
+
if ($_submenu[2] === fw()->backend->_get_settings_page_slug()) {
|
81 |
+
$title = $_submenu[0];
|
82 |
+
break 3;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
}
|
86 |
+
}
|
87 |
+
} while(false);
|
88 |
+
|
89 |
+
if (isset($title)) {
|
90 |
+
$this->set_string('title', $title);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @internal
|
97 |
+
*/
|
98 |
+
public function _action_admin_menu() {
|
99 |
+
$data = array(
|
100 |
+
'capability' => 'manage_options',
|
101 |
+
'slug' => fw()->backend->_get_settings_page_slug(),
|
102 |
+
'content_callback' => array( $this, 'render' ),
|
103 |
+
);
|
104 |
+
|
105 |
+
if ( ! current_user_can( $data['capability'] ) ) {
|
106 |
+
return;
|
107 |
+
}
|
108 |
+
|
109 |
+
if ( ! fw()->theme->locate_path('/options/settings.php') ) {
|
110 |
+
return;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Collect $hookname that contains $data['slug'] before the action
|
115 |
+
* and skip them in verification after action
|
116 |
+
*/
|
117 |
+
{
|
118 |
+
global $_registered_pages;
|
119 |
+
|
120 |
+
$found_hooknames = array();
|
121 |
+
|
122 |
+
if ( ! empty( $_registered_pages ) ) {
|
123 |
+
foreach ( $_registered_pages as $hookname => $b ) {
|
124 |
+
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
125 |
+
$found_hooknames[ $hookname ] = true;
|
126 |
+
}
|
127 |
+
}
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Use this action if you what to add the settings page in a custom place in menu
|
133 |
+
* Usage example http://pastebin.com/gvAjGRm1
|
134 |
+
*/
|
135 |
+
do_action( 'fw_backend_add_custom_settings_menu', $data );
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Check if settings menu was added in the action above
|
139 |
+
*/
|
140 |
+
{
|
141 |
+
$menu_exists = false;
|
142 |
+
|
143 |
+
if ( ! empty( $_registered_pages ) ) {
|
144 |
+
foreach ( $_registered_pages as $hookname => $b ) {
|
145 |
+
if ( isset( $found_hooknames[ $hookname ] ) ) {
|
146 |
+
continue;
|
147 |
+
}
|
148 |
+
|
149 |
+
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
150 |
+
$menu_exists = true;
|
151 |
+
break;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( $menu_exists ) {
|
158 |
+
return;
|
159 |
+
}
|
160 |
+
|
161 |
+
add_theme_page(
|
162 |
+
__( 'Theme Settings', 'fw' ),
|
163 |
+
__( 'Theme Settings', 'fw' ),
|
164 |
+
$data['capability'],
|
165 |
+
$data['slug'],
|
166 |
+
$data['content_callback']
|
167 |
+
);
|
168 |
+
|
169 |
+
add_action( 'admin_menu', array( $this, '_action_admin_change_theme_settings_order' ), 9999 );
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* @internal
|
174 |
+
*/
|
175 |
+
public function _action_admin_change_theme_settings_order() {
|
176 |
+
global $submenu;
|
177 |
+
|
178 |
+
if ( ! isset( $submenu['themes.php'] ) ) {
|
179 |
+
// probably current user doesn't have this item in menu
|
180 |
+
return;
|
181 |
+
}
|
182 |
+
|
183 |
+
$id = fw()->backend->_get_settings_page_slug();
|
184 |
+
$index = null;
|
185 |
+
|
186 |
+
foreach ( $submenu['themes.php'] as $key => $sm ) {
|
187 |
+
if ( $sm[2] == $id ) {
|
188 |
+
$index = $key;
|
189 |
+
break;
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
if ( ! empty( $index ) ) {
|
194 |
+
$item = $submenu['themes.php'][ $index ];
|
195 |
+
unset( $submenu['themes.php'][ $index ] );
|
196 |
+
array_unshift( $submenu['themes.php'], $item );
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* @internal
|
202 |
+
*/
|
203 |
+
public function _action_admin_enqueue_scripts()
|
204 |
+
{
|
205 |
+
global $plugin_page;
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Enqueue settings options static in <head>
|
209 |
+
*/
|
210 |
+
{
|
211 |
+
if (fw()->backend->_get_settings_page_slug() === $plugin_page) {
|
212 |
+
$this->enqueue_static();
|
213 |
+
|
214 |
+
do_action('fw_admin_enqueue_scripts:settings');
|
215 |
+
}
|
216 |
+
}
|
217 |
+
}
|
218 |
}
|
framework/core/components/extensions.php
CHANGED
@@ -1,685 +1,688 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Extensions component
|
5 |
-
*/
|
6 |
-
final class _FW_Component_Extensions
|
7 |
-
{
|
8 |
-
/**
|
9 |
-
* All existing extensions
|
10 |
-
* @var FW_Extension[] { 'extension_name' => instance }
|
11 |
-
*/
|
12 |
-
private static $all_extensions = array();
|
13 |
-
|
14 |
-
/**
|
15 |
-
* All existing extensions names arranged in hierarchical tree like they are in directories
|
16 |
-
* @var array
|
17 |
-
*/
|
18 |
-
private static $all_extensions_tree = array();
|
19 |
-
|
20 |
-
/**
|
21 |
-
* Active extensions
|
22 |
-
*
|
23 |
-
* On every extension activation, it will be pushed at the end of this array.
|
24 |
-
* The extensions order is important when including files.
|
25 |
-
* If extension A requires extension B, extension B is activated before extension A,
|
26 |
-
* and all files of the extension B (hooks.php, static.php, etc.) must be included before extension A
|
27 |
-
* For e.g. extension A may have in static.php:
|
28 |
-
* wp_enqueue_script( 'ext-A-script', 'script.js', array( 'ext-B-script' ) );
|
29 |
-
* so 'ext-B-script' must be registered before 'ext-A-script'
|
30 |
-
*
|
31 |
-
* @var FW_Extension[] { 'extension_name' => instance }
|
32 |
-
*/
|
33 |
-
private static $active_extensions = array();
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Active extensions names arranged in hierarchical tree like they are in directories
|
37 |
-
* @var array
|
38 |
-
*/
|
39 |
-
private static $active_extensions_tree = array();
|
40 |
-
|
41 |
-
/**
|
42 |
-
* @var array { 'extension_name' => array('required_by', 'required_by') }
|
43 |
-
*/
|
44 |
-
private static $extensions_required_by_extensions = array();
|
45 |
-
|
46 |
-
/**
|
47 |
-
* @var array { 'extension_name' => &array() }
|
48 |
-
*/
|
49 |
-
private static $extension_to_all_tree = array();
|
50 |
-
|
51 |
-
/**
|
52 |
-
* @var array { 'extension_name' => &array() }
|
53 |
-
*/
|
54 |
-
private static $extension_to_active_tree = array();
|
55 |
-
|
56 |
-
/**
|
57 |
-
* @var FW_Access_Key
|
58 |
-
*/
|
59 |
-
private static $access_key;
|
60 |
-
|
61 |
-
/** @var FW_Extension_Manifest[] All extensions manifests */
|
62 |
-
private static $manifests = array();
|
63 |
-
|
64 |
-
/**
|
65 |
-
* @var null|_FW_Extensions_Manager
|
66 |
-
*/
|
67 |
-
public $manager;
|
68 |
-
|
69 |
-
/**
|
70 |
-
* Option name that stores the active extensions array
|
71 |
-
* @internal
|
72 |
-
*/
|
73 |
-
public function _get_active_extensions_db_option_name()
|
74 |
-
{
|
75 |
-
return 'fw_active_extensions';
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* @param null|string $extension_name Check if an extension is set as active in database
|
80 |
-
* @internal
|
81 |
-
* @return array|bool
|
82 |
-
*/
|
83 |
-
public function _get_db_active_extensions($extension_name = null)
|
84 |
-
{
|
85 |
-
$extensions = get_option($this->_get_active_extensions_db_option_name(), array());
|
86 |
-
|
87 |
-
if ($extension_name) {
|
88 |
-
return isset($extensions[$extension_name]);
|
89 |
-
} else {
|
90 |
-
return $extensions;
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
94 |
-
public function __construct() {
|
95 |
-
$this->manager = new _FW_Extensions_Manager();
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* @param string $extension_name
|
100 |
-
* @param FW_Access_Key $access_key
|
101 |
-
* @return FW_Extension_Manifest|null
|
102 |
-
* @internal
|
103 |
-
* @since 2.6.9
|
104 |
-
*/
|
105 |
-
public static function _get_manifest($extension_name, FW_Access_Key $access_key) {
|
106 |
-
if (!in_array($access_key->get_key(), array('extension', self::$access_key->get_key()), true)) {
|
107 |
-
trigger_error('Method call denied', E_USER_ERROR);
|
108 |
-
}
|
109 |
-
|
110 |
-
if (isset(self::$all_extensions[$extension_name])) {
|
111 |
-
if (!isset(self::$manifests[$extension_name])) {
|
112 |
-
$manifest = fw_get_variables_from_file(
|
113 |
-
self::$all_extensions[$extension_name]['path'] .'/manifest.php', array('manifest' => array())
|
114 |
-
);
|
115 |
-
$manifest = $manifest['manifest'];
|
116 |
-
|
117 |
-
if (empty($manifest['name'])) {
|
118 |
-
$manifest['name'] = fw_id_to_title($extension_name);
|
119 |
-
}
|
120 |
-
|
121 |
-
self::$manifests[$extension_name] = new FW_Extension_Manifest($manifest);
|
122 |
-
}
|
123 |
-
|
124 |
-
return self::$manifests[$extension_name];
|
125 |
-
} else {
|
126 |
-
return null;
|
127 |
-
}
|
128 |
-
}
|
129 |
-
|
130 |
-
/**
|
131 |
-
* Load extension from directory
|
132 |
-
*
|
133 |
-
* @param array $data
|
134 |
-
*/
|
135 |
-
private static function load_extensions($data)
|
136 |
-
{
|
137 |
-
/**
|
138 |
-
* Do not check all keys
|
139 |
-
* if one not set, then sure others are not set (this is a private method)
|
140 |
-
*/
|
141 |
-
if (!isset($data['all_extensions_tree'])) {
|
142 |
-
$data['all_extensions_tree'] = &self::$all_extensions_tree;
|
143 |
-
$data['all_extensions'] = &self::$all_extensions;
|
144 |
-
$data['current_depth'] = 1;
|
145 |
-
$data['rel_path'] = '';
|
146 |
-
$data['parent'] = null;
|
147 |
-
}
|
148 |
-
|
149 |
-
$dirs = glob($data['path'] .'/*', GLOB_ONLYDIR);
|
150 |
-
|
151 |
-
if (empty($dirs)) {
|
152 |
-
return;
|
153 |
-
}
|
154 |
-
|
155 |
-
if ($data['current_depth'] > 1) {
|
156 |
-
$customizations_locations = array();
|
157 |
-
|
158 |
-
foreach ($data['customizations_locations'] as $customization_path => $customization_uri) {
|
159 |
-
$customizations_locations[ $customization_path .'/extensions' ] = $customization_uri .'/extensions';
|
160 |
-
}
|
161 |
-
|
162 |
-
$data['customizations_locations'] = $customizations_locations;
|
163 |
-
}
|
164 |
-
|
165 |
-
foreach ($dirs as $extension_dir) {
|
166 |
-
$extension_name = basename($extension_dir);
|
167 |
-
|
168 |
-
{
|
169 |
-
$customizations_locations = array();
|
170 |
-
|
171 |
-
foreach ($data['customizations_locations'] as $customization_path => $customization_uri) {
|
172 |
-
$customizations_locations[ $customization_path .'/'. $extension_name ] = $customization_uri .'/'. $extension_name;
|
173 |
-
}
|
174 |
-
}
|
175 |
-
|
176 |
-
if (isset($data['all_extensions'][$extension_name])) {
|
177 |
-
if ($data['all_extensions'][$extension_name]['parent'] !== $data['parent']) {
|
178 |
-
// extension with the same name exists in another tree
|
179 |
-
trigger_error(
|
180 |
-
'Extension "'. $extension_name .'" is already defined '.
|
181 |
-
'in "'. $data['all_extensions'][$extension_name]['path'] .'" '.
|
182 |
-
'found again in "'. $extension_dir .'"',
|
183 |
-
E_USER_ERROR
|
184 |
-
);
|
185 |
-
}
|
186 |
-
|
187 |
-
// this is a directory with customizations for an extension
|
188 |
-
|
189 |
-
self::load_extensions(array(
|
190 |
-
'rel_path' => $data['rel_path'] .'/'. $extension_name .'/extensions',
|
191 |
-
'path' => $data['path'] .'/'. $extension_name .'/extensions',
|
192 |
-
'uri' => $data['uri'] .'/'. $extension_name .'/extensions',
|
193 |
-
'customizations_locations' => $customizations_locations,
|
194 |
-
|
195 |
-
'all_extensions_tree' => &$data['all_extensions_tree'][$extension_name],
|
196 |
-
'all_extensions' => &$data['all_extensions'],
|
197 |
-
'current_depth' => $data['current_depth'] + 1,
|
198 |
-
'parent' => $extension_name,
|
199 |
-
));
|
200 |
-
} else {
|
201 |
-
if (file_exists($extension_dir .'/manifest.php')) {
|
202 |
-
$data['all_extensions_tree'][$extension_name] = array();
|
203 |
-
|
204 |
-
self::$extension_to_all_tree[$extension_name] = &$data['all_extensions_tree'][$extension_name];
|
205 |
-
|
206 |
-
$data['all_extensions'][$extension_name] = array(
|
207 |
-
'rel_path' => $data['rel_path'] .'/'. $extension_name,
|
208 |
-
'path' => $data['path'] .'/'. $extension_name,
|
209 |
-
'uri' => $data['uri'] .'/'. $extension_name,
|
210 |
-
'parent' => $data['parent'],
|
211 |
-
'depth' => $data['current_depth'],
|
212 |
-
'customizations_locations' => $customizations_locations,
|
213 |
-
'instance' => null, // created on activation
|
214 |
-
);
|
215 |
-
} else {
|
216 |
-
/**
|
217 |
-
* The manifest file does not exist, do not load this extension.
|
218 |
-
* Maybe it's a directory with configurations for a not existing extension.
|
219 |
-
*/
|
220 |
-
continue;
|
221 |
-
}
|
222 |
-
|
223 |
-
self::load_extensions(array(
|
224 |
-
'rel_path' => $data['all_extensions'][$extension_name]['rel_path'] .'/extensions',
|
225 |
-
'path' => $data['all_extensions'][$extension_name]['path'] .'/extensions',
|
226 |
-
'uri' => $data['all_extensions'][$extension_name]['uri'] .'/extensions',
|
227 |
-
'customizations_locations' => $customizations_locations,
|
228 |
-
|
229 |
-
'parent' => $extension_name,
|
230 |
-
'all_extensions_tree' => &$data['all_extensions_tree'][$extension_name],
|
231 |
-
'all_extensions' => &$data['all_extensions'],
|
232 |
-
'current_depth' => $data['current_depth'] + 1,
|
233 |
-
));
|
234 |
-
}
|
235 |
-
}
|
236 |
-
}
|
237 |
-
|
238 |
-
/**
|
239 |
-
* Include file from all extension's locations: framework, parent, child
|
240 |
-
* @param string|FW_Extension $extension
|
241 |
-
* @param string $file_rel_path
|
242 |
-
* @param bool $themeFirst
|
243 |
-
* false - [framework, parent, child]
|
244 |
-
* true - [child, parent, framework]
|
245 |
-
* @param bool $onlyFirstFound
|
246 |
-
*/
|
247 |
-
private static function include_extension_file_all_locations($extension, $file_rel_path, $themeFirst = false, $onlyFirstFound = false)
|
248 |
-
{
|
249 |
-
if (is_string($extension)) {
|
250 |
-
$extension = fw()->extensions->get($extension);
|
251 |
-
}
|
252 |
-
|
253 |
-
$paths = $extension->get_customizations_locations();
|
254 |
-
$paths[$extension->get_path()] = $extension->get_uri();
|
255 |
-
|
256 |
-
if (!$themeFirst) {
|
257 |
-
$paths = array_reverse($paths);
|
258 |
-
}
|
259 |
-
|
260 |
-
foreach ($paths as $path => $uri) {
|
261 |
-
if (fw_include_file_isolated($path . $file_rel_path)) {
|
262 |
-
if ($onlyFirstFound) {
|
263 |
-
return;
|
264 |
-
}
|
265 |
-
}
|
266 |
-
}
|
267 |
-
}
|
268 |
-
|
269 |
-
/**
|
270 |
-
* Include all files from directory, from all extension's locations: framework, child, parent
|
271 |
-
* @param string|FW_Extension $extension
|
272 |
-
* @param string $dir_rel_path
|
273 |
-
* @param bool $themeFirst
|
274 |
-
* false - [framework, parent, child]
|
275 |
-
* true - [child, parent, framework]
|
276 |
-
*/
|
277 |
-
private static function include_extension_directory_all_locations($extension, $dir_rel_path, $themeFirst = false)
|
278 |
-
{
|
279 |
-
if (is_string($extension)) {
|
280 |
-
$extension = fw()->extensions->get($extension);
|
281 |
-
}
|
282 |
-
|
283 |
-
$paths = $extension->get_customizations_locations();
|
284 |
-
$paths[$extension->get_path()] = $extension->get_uri();
|
285 |
-
|
286 |
-
if (!$themeFirst) {
|
287 |
-
$paths = array_reverse($paths);
|
288 |
-
}
|
289 |
-
|
290 |
-
foreach ($paths as $path => $uri) {
|
291 |
-
$files = glob($path . $dir_rel_path .'/*.php');
|
292 |
-
|
293 |
-
if ($files) {
|
294 |
-
foreach ($files as $dir_file_path) {
|
295 |
-
fw_include_file_isolated($dir_file_path);
|
296 |
-
}
|
297 |
-
}
|
298 |
-
}
|
299 |
-
}
|
300 |
-
|
301 |
-
public function get_locations()
|
302 |
-
{
|
303 |
-
$cache_key = 'fw_extensions_locations';
|
304 |
-
|
305 |
-
try {
|
306 |
-
return FW_Cache::get($cache_key);
|
307 |
-
} catch (FW_Cache_Not_Found_Exception $e) {
|
308 |
-
/**
|
309 |
-
* { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
|
310 |
-
*/
|
311 |
-
$custom_locations = apply_filters('fw_extensions_locations', array());
|
312 |
-
|
313 |
-
{
|
314 |
-
$customizations_locations = array();
|
315 |
-
|
316 |
-
if (is_child_theme()) {
|
317 |
-
$customizations_locations[fw_get_stylesheet_customizations_directory('/extensions')]
|
318 |
-
= fw_get_stylesheet_customizations_directory_uri('/extensions');
|
319 |
-
}
|
320 |
-
|
321 |
-
$customizations_locations[fw_get_template_customizations_directory('/extensions')]
|
322 |
-
= fw_get_template_customizations_directory_uri('/extensions');
|
323 |
-
|
324 |
-
$customizations_locations += $custom_locations;
|
325 |
-
}
|
326 |
-
|
327 |
-
$locations = array();
|
328 |
-
|
329 |
-
$locations[ fw_get_framework_directory('/extensions') ] = array(
|
330 |
-
'path' => fw_get_framework_directory('/extensions'),
|
331 |
-
'uri' => fw_get_framework_directory_uri('/extensions'),
|
332 |
-
'customizations_locations' => $customizations_locations,
|
333 |
-
'is' => array(
|
334 |
-
'framework' => true,
|
335 |
-
'custom' => false,
|
336 |
-
'theme' => false,
|
337 |
-
),
|
338 |
-
);
|
339 |
-
|
340 |
-
foreach ($custom_locations as $path => $uri) {
|
341 |
-
unset($customizations_locations[$path]);
|
342 |
-
$locations[ $path ] = array(
|
343 |
-
'path' => $path,
|
344 |
-
'uri' => $uri,
|
345 |
-
'customizations_locations' => $customizations_locations,
|
346 |
-
'is' => array(
|
347 |
-
'framework' => false,
|
348 |
-
'custom' => true,
|
349 |
-
'theme' => false,
|
350 |
-
),
|
351 |
-
);
|
352 |
-
}
|
353 |
-
|
354 |
-
array_pop($customizations_locations);
|
355 |
-
$locations[ fw_get_template_customizations_directory('/extensions') ] = array(
|
356 |
-
'path' => fw_get_template_customizations_directory('/extensions'),
|
357 |
-
'uri' => fw_get_template_customizations_directory_uri('/extensions'),
|
358 |
-
'customizations_locations' => $customizations_locations,
|
359 |
-
'is' => array(
|
360 |
-
'framework' => false,
|
361 |
-
'custom' => false,
|
362 |
-
'theme' => true,
|
363 |
-
),
|
364 |
-
);
|
365 |
-
|
366 |
-
if (is_child_theme()) {
|
367 |
-
array_pop($customizations_locations);
|
368 |
-
$locations[ fw_get_stylesheet_customizations_directory('/extensions') ] = array(
|
369 |
-
'path' => fw_get_stylesheet_customizations_directory('/extensions'),
|
370 |
-
'uri' => fw_get_stylesheet_customizations_directory_uri('/extensions'),
|
371 |
-
'customizations_locations' => $customizations_locations,
|
372 |
-
'is' => array(
|
373 |
-
'framework' => false,
|
374 |
-
'custom' => false,
|
375 |
-
'theme' => true,
|
376 |
-
),
|
377 |
-
);
|
378 |
-
}
|
379 |
-
|
380 |
-
/**
|
381 |
-
* @since 2.6.9
|
382 |
-
*/
|
383 |
-
$locations = apply_filters('fw_extensions_locations_after', $locations);
|
384 |
-
|
385 |
-
FW_Cache::set($cache_key, $locations);
|
386 |
-
|
387 |
-
return $locations;
|
388 |
-
}
|
389 |
-
}
|
390 |
-
|
391 |
-
private function load_all_extensions()
|
392 |
-
{
|
393 |
-
foreach ($this->get_locations() as $location) {
|
394 |
-
self::load_extensions(array(
|
395 |
-
'path' => $location['path'],
|
396 |
-
'uri' => $location['uri'],
|
397 |
-
'customizations_locations' => $location['customizations_locations'],
|
398 |
-
));
|
399 |
-
}
|
400 |
-
}
|
401 |
-
|
402 |
-
/**
|
403 |
-
* Activate extensions from given tree point
|
404 |
-
*
|
405 |
-
* @param null|string $parent_extension_name
|
406 |
-
*/
|
407 |
-
private function activate_extensions($parent_extension_name = null)
|
408 |
-
{
|
409 |
-
if ($parent_extension_name === null) {
|
410 |
-
$all_tree = &self::$all_extensions_tree;
|
411 |
-
} else {
|
412 |
-
$all_tree = &self::$extension_to_all_tree[$parent_extension_name];
|
413 |
-
}
|
414 |
-
|
415 |
-
foreach ($all_tree as $extension_name => &$sub_extensions) {
|
416 |
-
if (fw()->extensions->get($extension_name)) {
|
417 |
-
continue; // already active
|
418 |
-
}
|
419 |
-
|
420 |
-
$manifest = self::_get_manifest($extension_name, self::$access_key);
|
421 |
-
|
422 |
-
{
|
423 |
-
$class_file_name = 'class-fw-extension-'. $extension_name .'.php';
|
424 |
-
|
425 |
-
if (fw_include_file_isolated(self::$all_extensions[$extension_name]['path'] .'/'. $class_file_name)) {
|
426 |
-
$class_name = 'FW_Extension_'. fw_dirname_to_classname($extension_name);
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
'
|
449 |
-
'
|
450 |
-
'
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
}
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
self::$
|
520 |
-
self::$extension_to_active_tree[$extension_name] = &self::$
|
521 |
-
}
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
*
|
577 |
-
* @
|
578 |
-
*
|
579 |
-
* @
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
|
|
|
|
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Extensions component
|
5 |
+
*/
|
6 |
+
final class _FW_Component_Extensions
|
7 |
+
{
|
8 |
+
/**
|
9 |
+
* All existing extensions
|
10 |
+
* @var FW_Extension[] { 'extension_name' => instance }
|
11 |
+
*/
|
12 |
+
private static $all_extensions = array();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* All existing extensions names arranged in hierarchical tree like they are in directories
|
16 |
+
* @var array
|
17 |
+
*/
|
18 |
+
private static $all_extensions_tree = array();
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Active extensions
|
22 |
+
*
|
23 |
+
* On every extension activation, it will be pushed at the end of this array.
|
24 |
+
* The extensions order is important when including files.
|
25 |
+
* If extension A requires extension B, extension B is activated before extension A,
|
26 |
+
* and all files of the extension B (hooks.php, static.php, etc.) must be included before extension A
|
27 |
+
* For e.g. extension A may have in static.php:
|
28 |
+
* wp_enqueue_script( 'ext-A-script', 'script.js', array( 'ext-B-script' ) );
|
29 |
+
* so 'ext-B-script' must be registered before 'ext-A-script'
|
30 |
+
*
|
31 |
+
* @var FW_Extension[] { 'extension_name' => instance }
|
32 |
+
*/
|
33 |
+
private static $active_extensions = array();
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Active extensions names arranged in hierarchical tree like they are in directories
|
37 |
+
* @var array
|
38 |
+
*/
|
39 |
+
private static $active_extensions_tree = array();
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @var array { 'extension_name' => array('required_by', 'required_by') }
|
43 |
+
*/
|
44 |
+
private static $extensions_required_by_extensions = array();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @var array { 'extension_name' => &array() }
|
48 |
+
*/
|
49 |
+
private static $extension_to_all_tree = array();
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @var array { 'extension_name' => &array() }
|
53 |
+
*/
|
54 |
+
private static $extension_to_active_tree = array();
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @var FW_Access_Key
|
58 |
+
*/
|
59 |
+
private static $access_key;
|
60 |
+
|
61 |
+
/** @var FW_Extension_Manifest[] All extensions manifests */
|
62 |
+
private static $manifests = array();
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @var null|_FW_Extensions_Manager
|
66 |
+
*/
|
67 |
+
public $manager;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Option name that stores the active extensions array
|
71 |
+
* @internal
|
72 |
+
*/
|
73 |
+
public function _get_active_extensions_db_option_name()
|
74 |
+
{
|
75 |
+
return 'fw_active_extensions';
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @param null|string $extension_name Check if an extension is set as active in database
|
80 |
+
* @internal
|
81 |
+
* @return array|bool
|
82 |
+
*/
|
83 |
+
public function _get_db_active_extensions($extension_name = null)
|
84 |
+
{
|
85 |
+
$extensions = get_option($this->_get_active_extensions_db_option_name(), array());
|
86 |
+
|
87 |
+
if ($extension_name) {
|
88 |
+
return isset($extensions[$extension_name]);
|
89 |
+
} else {
|
90 |
+
return $extensions;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
public function __construct() {
|
95 |
+
$this->manager = new _FW_Extensions_Manager();
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* @param string $extension_name
|
100 |
+
* @param FW_Access_Key $access_key
|
101 |
+
* @return FW_Extension_Manifest|null
|
102 |
+
* @internal
|
103 |
+
* @since 2.6.9
|
104 |
+
*/
|
105 |
+
public static function _get_manifest($extension_name, FW_Access_Key $access_key) {
|
106 |
+
if ( ! in_array( $access_key->get_key(), array( 'extension', self::$access_key->get_key() ), true ) ) {
|
107 |
+
trigger_error( 'Method call denied', E_USER_ERROR );
|
108 |
+
}
|
109 |
+
|
110 |
+
if (isset(self::$all_extensions[$extension_name])) {
|
111 |
+
if (!isset(self::$manifests[$extension_name])) {
|
112 |
+
$manifest = fw_get_variables_from_file(
|
113 |
+
self::$all_extensions[$extension_name]['path'] .'/manifest.php', array('manifest' => array())
|
114 |
+
);
|
115 |
+
$manifest = $manifest['manifest'];
|
116 |
+
|
117 |
+
if (empty($manifest['name'])) {
|
118 |
+
$manifest['name'] = fw_id_to_title($extension_name);
|
119 |
+
}
|
120 |
+
|
121 |
+
self::$manifests[$extension_name] = new FW_Extension_Manifest($manifest);
|
122 |
+
}
|
123 |
+
|
124 |
+
return self::$manifests[$extension_name];
|
125 |
+
} else {
|
126 |
+
return null;
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Load extension from directory
|
132 |
+
*
|
133 |
+
* @param array $data
|
134 |
+
*/
|
135 |
+
private static function load_extensions($data)
|
136 |
+
{
|
137 |
+
/**
|
138 |
+
* Do not check all keys
|
139 |
+
* if one not set, then sure others are not set (this is a private method)
|
140 |
+
*/
|
141 |
+
if (!isset($data['all_extensions_tree'])) {
|
142 |
+
$data['all_extensions_tree'] = &self::$all_extensions_tree;
|
143 |
+
$data['all_extensions'] = &self::$all_extensions;
|
144 |
+
$data['current_depth'] = 1;
|
145 |
+
$data['rel_path'] = '';
|
146 |
+
$data['parent'] = null;
|
147 |
+
}
|
148 |
+
|
149 |
+
$dirs = glob($data['path'] .'/*', GLOB_ONLYDIR);
|
150 |
+
|
151 |
+
if (empty($dirs)) {
|
152 |
+
return;
|
153 |
+
}
|
154 |
+
|
155 |
+
if ($data['current_depth'] > 1) {
|
156 |
+
$customizations_locations = array();
|
157 |
+
|
158 |
+
foreach ($data['customizations_locations'] as $customization_path => $customization_uri) {
|
159 |
+
$customizations_locations[ $customization_path .'/extensions' ] = $customization_uri .'/extensions';
|
160 |
+
}
|
161 |
+
|
162 |
+
$data['customizations_locations'] = $customizations_locations;
|
163 |
+
}
|
164 |
+
|
165 |
+
foreach ($dirs as $extension_dir) {
|
166 |
+
$extension_name = basename($extension_dir);
|
167 |
+
|
168 |
+
{
|
169 |
+
$customizations_locations = array();
|
170 |
+
|
171 |
+
foreach ($data['customizations_locations'] as $customization_path => $customization_uri) {
|
172 |
+
$customizations_locations[ $customization_path .'/'. $extension_name ] = $customization_uri .'/'. $extension_name;
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
if (isset($data['all_extensions'][$extension_name])) {
|
177 |
+
if ($data['all_extensions'][$extension_name]['parent'] !== $data['parent']) {
|
178 |
+
// extension with the same name exists in another tree
|
179 |
+
trigger_error(
|
180 |
+
'Extension "'. $extension_name .'" is already defined '.
|
181 |
+
'in "'. $data['all_extensions'][$extension_name]['path'] .'" '.
|
182 |
+
'found again in "'. $extension_dir .'"',
|
183 |
+
E_USER_ERROR
|
184 |
+
);
|
185 |
+
}
|
186 |
+
|
187 |
+
// this is a directory with customizations for an extension
|
188 |
+
|
189 |
+
self::load_extensions(array(
|
190 |
+
'rel_path' => $data['rel_path'] .'/'. $extension_name .'/extensions',
|
191 |
+
'path' => $data['path'] .'/'. $extension_name .'/extensions',
|
192 |
+
'uri' => $data['uri'] .'/'. $extension_name .'/extensions',
|
193 |
+
'customizations_locations' => $customizations_locations,
|
194 |
+
|
195 |
+
'all_extensions_tree' => &$data['all_extensions_tree'][$extension_name],
|
196 |
+
'all_extensions' => &$data['all_extensions'],
|
197 |
+
'current_depth' => $data['current_depth'] + 1,
|
198 |
+
'parent' => $extension_name,
|
199 |
+
));
|
200 |
+
} else {
|
201 |
+
if (file_exists($extension_dir .'/manifest.php')) {
|
202 |
+
$data['all_extensions_tree'][$extension_name] = array();
|
203 |
+
|
204 |
+
self::$extension_to_all_tree[$extension_name] = &$data['all_extensions_tree'][$extension_name];
|
205 |
+
|
206 |
+
$data['all_extensions'][$extension_name] = array(
|
207 |
+
'rel_path' => $data['rel_path'] .'/'. $extension_name,
|
208 |
+
'path' => $data['path'] .'/'. $extension_name,
|
209 |
+
'uri' => $data['uri'] .'/'. $extension_name,
|
210 |
+
'parent' => $data['parent'],
|
211 |
+
'depth' => $data['current_depth'],
|
212 |
+
'customizations_locations' => $customizations_locations,
|
213 |
+
'instance' => null, // created on activation
|
214 |
+
);
|
215 |
+
} else {
|
216 |
+
/**
|
217 |
+
* The manifest file does not exist, do not load this extension.
|
218 |
+
* Maybe it's a directory with configurations for a not existing extension.
|
219 |
+
*/
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
|
223 |
+
self::load_extensions(array(
|
224 |
+
'rel_path' => $data['all_extensions'][$extension_name]['rel_path'] .'/extensions',
|
225 |
+
'path' => $data['all_extensions'][$extension_name]['path'] .'/extensions',
|
226 |
+
'uri' => $data['all_extensions'][$extension_name]['uri'] .'/extensions',
|
227 |
+
'customizations_locations' => $customizations_locations,
|
228 |
+
|
229 |
+
'parent' => $extension_name,
|
230 |
+
'all_extensions_tree' => &$data['all_extensions_tree'][$extension_name],
|
231 |
+
'all_extensions' => &$data['all_extensions'],
|
232 |
+
'current_depth' => $data['current_depth'] + 1,
|
233 |
+
));
|
234 |
+
}
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Include file from all extension's locations: framework, parent, child
|
240 |
+
* @param string|FW_Extension $extension
|
241 |
+
* @param string $file_rel_path
|
242 |
+
* @param bool $themeFirst
|
243 |
+
* false - [framework, parent, child]
|
244 |
+
* true - [child, parent, framework]
|
245 |
+
* @param bool $onlyFirstFound
|
246 |
+
*/
|
247 |
+
private static function include_extension_file_all_locations($extension, $file_rel_path, $themeFirst = false, $onlyFirstFound = false)
|
248 |
+
{
|
249 |
+
if (is_string($extension)) {
|
250 |
+
$extension = fw()->extensions->get($extension);
|
251 |
+
}
|
252 |
+
|
253 |
+
$paths = $extension->get_customizations_locations();
|
254 |
+
$paths[$extension->get_path()] = $extension->get_uri();
|
255 |
+
|
256 |
+
if (!$themeFirst) {
|
257 |
+
$paths = array_reverse($paths);
|
258 |
+
}
|
259 |
+
|
260 |
+
foreach ($paths as $path => $uri) {
|
261 |
+
if (fw_include_file_isolated($path . $file_rel_path)) {
|
262 |
+
if ($onlyFirstFound) {
|
263 |
+
return;
|
264 |
+
}
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Include all files from directory, from all extension's locations: framework, child, parent
|
271 |
+
* @param string|FW_Extension $extension
|
272 |
+
* @param string $dir_rel_path
|
273 |
+
* @param bool $themeFirst
|
274 |
+
* false - [framework, parent, child]
|
275 |
+
* true - [child, parent, framework]
|
276 |
+
*/
|
277 |
+
private static function include_extension_directory_all_locations($extension, $dir_rel_path, $themeFirst = false)
|
278 |
+
{
|
279 |
+
if (is_string($extension)) {
|
280 |
+
$extension = fw()->extensions->get($extension);
|
281 |
+
}
|
282 |
+
|
283 |
+
$paths = $extension->get_customizations_locations();
|
284 |
+
$paths[$extension->get_path()] = $extension->get_uri();
|
285 |
+
|
286 |
+
if (!$themeFirst) {
|
287 |
+
$paths = array_reverse($paths);
|
288 |
+
}
|
289 |
+
|
290 |
+
foreach ($paths as $path => $uri) {
|
291 |
+
$files = glob($path . $dir_rel_path .'/*.php');
|
292 |
+
|
293 |
+
if ($files) {
|
294 |
+
foreach ($files as $dir_file_path) {
|
295 |
+
fw_include_file_isolated($dir_file_path);
|
296 |
+
}
|
297 |
+
}
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
public function get_locations()
|
302 |
+
{
|
303 |
+
$cache_key = 'fw_extensions_locations';
|
304 |
+
|
305 |
+
try {
|
306 |
+
return FW_Cache::get($cache_key);
|
307 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
308 |
+
/**
|
309 |
+
* { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
|
310 |
+
*/
|
311 |
+
$custom_locations = apply_filters('fw_extensions_locations', array());
|
312 |
+
|
313 |
+
{
|
314 |
+
$customizations_locations = array();
|
315 |
+
|
316 |
+
if (is_child_theme()) {
|
317 |
+
$customizations_locations[fw_get_stylesheet_customizations_directory('/extensions')]
|
318 |
+
= fw_get_stylesheet_customizations_directory_uri('/extensions');
|
319 |
+
}
|
320 |
+
|
321 |
+
$customizations_locations[fw_get_template_customizations_directory('/extensions')]
|
322 |
+
= fw_get_template_customizations_directory_uri('/extensions');
|
323 |
+
|
324 |
+
$customizations_locations += $custom_locations;
|
325 |
+
}
|
326 |
+
|
327 |
+
$locations = array();
|
328 |
+
|
329 |
+
$locations[ fw_get_framework_directory('/extensions') ] = array(
|
330 |
+
'path' => fw_get_framework_directory('/extensions'),
|
331 |
+
'uri' => fw_get_framework_directory_uri('/extensions'),
|
332 |
+
'customizations_locations' => $customizations_locations,
|
333 |
+
'is' => array(
|
334 |
+
'framework' => true,
|
335 |
+
'custom' => false,
|
336 |
+
'theme' => false,
|
337 |
+
),
|
338 |
+
);
|
339 |
+
|
340 |
+
foreach ($custom_locations as $path => $uri) {
|
341 |
+
unset($customizations_locations[$path]);
|
342 |
+
$locations[ $path ] = array(
|
343 |
+
'path' => $path,
|
344 |
+
'uri' => $uri,
|
345 |
+
'customizations_locations' => $customizations_locations,
|
346 |
+
'is' => array(
|
347 |
+
'framework' => false,
|
348 |
+
'custom' => true,
|
349 |
+
'theme' => false,
|
350 |
+
),
|
351 |
+
);
|
352 |
+
}
|
353 |
+
|
354 |
+
array_pop($customizations_locations);
|
355 |
+
$locations[ fw_get_template_customizations_directory('/extensions') ] = array(
|
356 |
+
'path' => fw_get_template_customizations_directory('/extensions'),
|
357 |
+
'uri' => fw_get_template_customizations_directory_uri('/extensions'),
|
358 |
+
'customizations_locations' => $customizations_locations,
|
359 |
+
'is' => array(
|
360 |
+
'framework' => false,
|
361 |
+
'custom' => false,
|
362 |
+
'theme' => true,
|
363 |
+
),
|
364 |
+
);
|
365 |
+
|
366 |
+
if (is_child_theme()) {
|
367 |
+
array_pop($customizations_locations);
|
368 |
+
$locations[ fw_get_stylesheet_customizations_directory('/extensions') ] = array(
|
369 |
+
'path' => fw_get_stylesheet_customizations_directory('/extensions'),
|
370 |
+
'uri' => fw_get_stylesheet_customizations_directory_uri('/extensions'),
|
371 |
+
'customizations_locations' => $customizations_locations,
|
372 |
+
'is' => array(
|
373 |
+
'framework' => false,
|
374 |
+
'custom' => false,
|
375 |
+
'theme' => true,
|
376 |
+
),
|
377 |
+
);
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* @since 2.6.9
|
382 |
+
*/
|
383 |
+
$locations = apply_filters('fw_extensions_locations_after', $locations);
|
384 |
+
|
385 |
+
FW_Cache::set($cache_key, $locations);
|
386 |
+
|
387 |
+
return $locations;
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
private function load_all_extensions()
|
392 |
+
{
|
393 |
+
foreach ($this->get_locations() as $location) {
|
394 |
+
self::load_extensions(array(
|
395 |
+
'path' => $location['path'],
|
396 |
+
'uri' => $location['uri'],
|
397 |
+
'customizations_locations' => $location['customizations_locations'],
|
398 |
+
));
|
399 |
+
}
|
400 |
+
}
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Activate extensions from given tree point
|
404 |
+
*
|
405 |
+
* @param null|string $parent_extension_name
|
406 |
+
*/
|
407 |
+
private function activate_extensions($parent_extension_name = null)
|
408 |
+
{
|
409 |
+
if ($parent_extension_name === null) {
|
410 |
+
$all_tree = &self::$all_extensions_tree;
|
411 |
+
} else {
|
412 |
+
$all_tree = &self::$extension_to_all_tree[$parent_extension_name];
|
413 |
+
}
|
414 |
+
|
415 |
+
foreach ($all_tree as $extension_name => &$sub_extensions) {
|
416 |
+
if (fw()->extensions->get($extension_name)) {
|
417 |
+
continue; // already active
|
418 |
+
}
|
419 |
+
|
420 |
+
$manifest = self::_get_manifest($extension_name, self::$access_key);
|
421 |
+
|
422 |
+
{
|
423 |
+
$class_file_name = 'class-fw-extension-'. $extension_name .'.php';
|
424 |
+
|
425 |
+
if (fw_include_file_isolated(self::$all_extensions[$extension_name]['path'] .'/'. $class_file_name)) {
|
426 |
+
$class_name = 'FW_Extension_'. fw_dirname_to_classname($extension_name);
|
427 |
+
|
428 |
+
} else {
|
429 |
+
|
430 |
+
$parent_class_name = '';
|
431 |
+
if ( self::$all_extensions[ $extension_name ]['parent'] ) {
|
432 |
+
$parent_class_name = get_class( fw()->extensions->get( self::$all_extensions[ $extension_name ]['parent'] ) );
|
433 |
+
}
|
434 |
+
|
435 |
+
// check if parent extension has been defined custom Default class for its child extensions
|
436 |
+
if ( class_exists( $parent_class_name . '_Default' ) ) {
|
437 |
+
$class_name = $parent_class_name . '_Default';
|
438 |
+
} else {
|
439 |
+
$class_name = 'FW_Extension_Default';
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
if (!is_subclass_of($class_name, 'FW_Extension')) {
|
444 |
+
trigger_error('Extension "'. $extension_name .'" must extend FW_Extension class', E_USER_ERROR);
|
445 |
+
}
|
446 |
+
|
447 |
+
self::$all_extensions[$extension_name]['instance'] = new $class_name(array(
|
448 |
+
'rel_path' => self::$all_extensions[$extension_name]['rel_path'],
|
449 |
+
'path' => self::$all_extensions[$extension_name]['path'],
|
450 |
+
'uri' => self::$all_extensions[$extension_name]['uri'],
|
451 |
+
'parent' => fw()->extensions->get(self::$all_extensions[$extension_name]['parent']),
|
452 |
+
'depth' => self::$all_extensions[$extension_name]['depth'],
|
453 |
+
'customizations_locations' => self::$all_extensions[$extension_name]['customizations_locations'],
|
454 |
+
));
|
455 |
+
}
|
456 |
+
|
457 |
+
$extension = &self::$all_extensions[$extension_name]['instance'];
|
458 |
+
|
459 |
+
if ($manifest->check_requirements()) {
|
460 |
+
if (!$this->_get_db_active_extensions($extension_name)) {
|
461 |
+
// extension is not set as active
|
462 |
+
} elseif (
|
463 |
+
$extension->get_parent()
|
464 |
+
&&
|
465 |
+
!$extension->get_parent()->_child_extension_is_valid($extension)
|
466 |
+
) {
|
467 |
+
// extension does not pass parent extension rules
|
468 |
+
if (is_admin()) {
|
469 |
+
// show warning only in admin side
|
470 |
+
FW_Flash_Messages::add(
|
471 |
+
'fw-invalid-extension',
|
472 |
+
sprintf(__('Extension %s is invalid.', 'fw'), $extension->get_name()),
|
473 |
+
'warning'
|
474 |
+
);
|
475 |
+
}
|
476 |
+
} else {
|
477 |
+
// all requirements met, activate extension
|
478 |
+
$this->activate_extension($extension_name);
|
479 |
+
}
|
480 |
+
} else {
|
481 |
+
// requirements not met, tell required extensions that this extension is waiting for them
|
482 |
+
|
483 |
+
foreach ($manifest->get_required_extensions() as $required_extension_name => $requirements) {
|
484 |
+
if (!isset(self::$extensions_required_by_extensions[$required_extension_name])) {
|
485 |
+
self::$extensions_required_by_extensions[$required_extension_name] = array();
|
486 |
+
}
|
487 |
+
|
488 |
+
self::$extensions_required_by_extensions[$required_extension_name][] = $extension_name;
|
489 |
+
}
|
490 |
+
}
|
491 |
+
}
|
492 |
+
unset($sub_extensions);
|
493 |
+
}
|
494 |
+
|
495 |
+
/**
|
496 |
+
* @param string $extension_name
|
497 |
+
* @return bool
|
498 |
+
*/
|
499 |
+
private function activate_extension($extension_name)
|
500 |
+
{
|
501 |
+
if (fw()->extensions->get($extension_name)) {
|
502 |
+
return false; // already active
|
503 |
+
}
|
504 |
+
|
505 |
+
if (!self::_get_manifest($extension_name, self::$access_key)->requirements_met()) {
|
506 |
+
trigger_error('Wrong '. __METHOD__ .' call', E_USER_WARNING);
|
507 |
+
return false;
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* Add to active extensions so inside includes/ and extension it will be accessible from fw()->extensions->get(...)
|
512 |
+
* self::$all_extensions[$extension_name]['instance'] is created in $this->activate_extensions()
|
513 |
+
*/
|
514 |
+
self::$active_extensions[$extension_name] = &self::$all_extensions[$extension_name]['instance'];
|
515 |
+
|
516 |
+
$parent = self::$all_extensions[$extension_name]['instance']->get_parent();
|
517 |
+
|
518 |
+
if ($parent) {
|
519 |
+
self::$extension_to_active_tree[ $parent->get_name() ][$extension_name] = array();
|
520 |
+
self::$extension_to_active_tree[$extension_name] = &self::$extension_to_active_tree[ $parent->get_name() ][$extension_name];
|
521 |
+
} else {
|
522 |
+
self::$active_extensions_tree[$extension_name] = array();
|
523 |
+
self::$extension_to_active_tree[$extension_name] = &self::$active_extensions_tree[$extension_name];
|
524 |
+
}
|
525 |
+
|
526 |
+
self::include_extension_directory_all_locations($extension_name, '/includes');
|
527 |
+
self::include_extension_file_all_locations($extension_name, '/helpers.php');
|
528 |
+
self::include_extension_file_all_locations($extension_name, '/hooks.php');
|
529 |
+
|
530 |
+
if (self::$all_extensions[$extension_name]['instance']->_call_init(self::$access_key) !== false) {
|
531 |
+
$this->activate_extensions($extension_name);
|
532 |
+
}
|
533 |
+
|
534 |
+
// check if other extensions are waiting for this extension and try to activate them
|
535 |
+
if (isset(self::$extensions_required_by_extensions[$extension_name])) {
|
536 |
+
foreach (self::$extensions_required_by_extensions[$extension_name] as $waiting_extension_name) {
|
537 |
+
if (self::_get_manifest($waiting_extension_name, self::$access_key)->check_requirements()) {
|
538 |
+
$waiting_extension = self::$all_extensions[$waiting_extension_name]['instance'];
|
539 |
+
|
540 |
+
if (!$this->_get_db_active_extensions($waiting_extension_name)) {
|
541 |
+
// extension is set as active
|
542 |
+
} elseif (
|
543 |
+
$waiting_extension->get_parent()
|
544 |
+
&&
|
545 |
+
!$waiting_extension->get_parent()->_child_extension_is_valid($waiting_extension)
|
546 |
+
) {
|
547 |
+
// extension does not pass parent extension rules
|
548 |
+
if (is_admin()) {
|
549 |
+
// show warning only in admin side
|
550 |
+
FW_Flash_Messages::add(
|
551 |
+
'fw-invalid-extension',
|
552 |
+
sprintf(__('Extension %s is invalid.', 'fw'), $waiting_extension_name),
|
553 |
+
'warning'
|
554 |
+
);
|
555 |
+
}
|
556 |
+
} else {
|
557 |
+
$this->activate_extension($waiting_extension_name);
|
558 |
+
}
|
559 |
+
}
|
560 |
+
}
|
561 |
+
|
562 |
+
unset(self::$extensions_required_by_extensions[$extension_name]);
|
563 |
+
}
|
564 |
+
|
565 |
+
return true;
|
566 |
+
}
|
567 |
+
|
568 |
+
private function add_actions()
|
569 |
+
{
|
570 |
+
add_action('init', array($this, '_action_init'));
|
571 |
+
add_action('wp_enqueue_scripts', array($this, '_action_enqueue_scripts'));
|
572 |
+
add_action('admin_enqueue_scripts', array($this, '_action_enqueue_scripts'));
|
573 |
+
}
|
574 |
+
|
575 |
+
/**
|
576 |
+
* Give extensions possibility to access their active_tree
|
577 |
+
* @internal
|
578 |
+
*
|
579 |
+
* @param FW_Access_Key $access_key
|
580 |
+
* @param $extension_name
|
581 |
+
*
|
582 |
+
* @return array
|
583 |
+
*/
|
584 |
+
public function _get_extension_tree(FW_Access_Key $access_key, $extension_name)
|
585 |
+
{
|
586 |
+
if ($access_key->get_key() !== 'extension') {
|
587 |
+
trigger_error('Call denied', E_USER_ERROR);
|
588 |
+
}
|
589 |
+
|
590 |
+
return self::$extension_to_active_tree[$extension_name];
|
591 |
+
}
|
592 |
+
|
593 |
+
/**
|
594 |
+
* @internal
|
595 |
+
*/
|
596 |
+
public function _init()
|
597 |
+
{
|
598 |
+
self::$access_key = new FW_Access_Key('fw_extensions');
|
599 |
+
|
600 |
+
/**
|
601 |
+
* Extensions are about to activate.
|
602 |
+
* You can add subclasses to FW_Extension at this point.
|
603 |
+
*/
|
604 |
+
do_action('fw_extensions_before_init');
|
605 |
+
|
606 |
+
$this->load_all_extensions();
|
607 |
+
$this->add_actions();
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* @internal
|
612 |
+
*/
|
613 |
+
public function _after_components_init()
|
614 |
+
{
|
615 |
+
$this->activate_extensions();
|
616 |
+
|
617 |
+
/**
|
618 |
+
* Extensions are activated
|
619 |
+
* Now $this->get_children() inside extensions is available
|
620 |
+
*/
|
621 |
+
do_action('fw_extensions_init');
|
622 |
+
}
|
623 |
+
|
624 |
+
public function _action_init()
|
625 |
+
{
|
626 |
+
foreach (self::$active_extensions as &$extension) {
|
627 |
+
/** register posts and taxonomies */
|
628 |
+
self::include_extension_file_all_locations($extension, '/posts.php');
|
629 |
+
}
|
630 |
+
}
|
631 |
+
|
632 |
+
public function _action_enqueue_scripts()
|
633 |
+
{
|
634 |
+
foreach (self::$active_extensions as &$extension) {
|
635 |
+
/** js and css */
|
636 |
+
self::include_extension_file_all_locations($extension, '/static.php', true, true);
|
637 |
+
}
|
638 |
+
}
|
639 |
+
|
640 |
+
/**
|
641 |
+
* @param string $extension_name returned by FW_Extension::get_name()
|
642 |
+
* @return FW_Extension|null
|
643 |
+
*/
|
644 |
+
public function get($extension_name)
|
645 |
+
{
|
646 |
+
if (isset(self::$active_extensions[$extension_name])) {
|
647 |
+
return self::$active_extensions[$extension_name];
|
648 |
+
} else {
|
649 |
+
return null;
|
650 |
+
}
|
651 |
+
}
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Get all active extensions
|
655 |
+
* @return FW_Extension[]
|
656 |
+
*/
|
657 |
+
public function get_all()
|
658 |
+
{
|
659 |
+
return self::$active_extensions;
|
660 |
+
}
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Get extensions tree (how they are arranged in directories)
|
664 |
+
* @return array
|
665 |
+
*/
|
666 |
+
public function get_tree()
|
667 |
+
{
|
668 |
+
return self::$active_extensions_tree;
|
669 |
+
}
|
670 |
+
|
671 |
+
/**
|
672 |
+
* @return false
|
673 |
+
* @deprecated Use $extension->locate_path()
|
674 |
+
*/
|
675 |
+
public function locate_path()
|
676 |
+
{
|
677 |
+
return false;
|
678 |
+
}
|
679 |
+
|
680 |
+
/**
|
681 |
+
* @return false
|
682 |
+
* @deprecated Use $extension->locate_URI()
|
683 |
+
*/
|
684 |
+
public function locate_path_URI()
|
685 |
+
{
|
686 |
+
return false;
|
687 |
+
}
|
688 |
+
}
|
framework/core/components/extensions/class-fw-extension-default.php
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Instances of this class will be created for extensions without class
|
5 |
-
*/
|
6 |
-
class FW_Extension_Default extends FW_Extension
|
7 |
-
{
|
8 |
-
protected function _init()
|
9 |
-
{
|
10 |
-
}
|
11 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Instances of this class will be created for extensions without class
|
5 |
+
*/
|
6 |
+
class FW_Extension_Default extends FW_Extension
|
7 |
+
{
|
8 |
+
protected function _init()
|
9 |
+
{
|
10 |
+
}
|
11 |
+
}
|
framework/core/components/extensions/manager/available-extensions.php
CHANGED
@@ -1,334 +1,336 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
$thumbnails_uri = fw_get_framework_directory_uri( '/core/components/extensions/manager/static/img/thumbnails' );
|
6 |
-
$github_account = 'ThemeFuse';
|
7 |
-
|
8 |
-
$extensions = array(
|
9 |
-
'page-builder' => array(
|
10 |
-
'display' => true,
|
11 |
-
'parent' => 'shortcodes',
|
12 |
-
'name' => __( 'Page Builder', 'fw' ),
|
13 |
-
'description' => __( "Let's you easily build countless pages with the help of the drag and drop visual page builder that comes with a lot of already created shortcodes.", 'fw' ),
|
14 |
-
'thumbnail' => $thumbnails_uri . '/page-builder.jpg',
|
15 |
-
'download' => array(
|
16 |
-
'source' => 'github',
|
17 |
-
'opts' => array(
|
18 |
-
'user_repo' => $github_account . '/Unyson-PageBuilder-Extension'
|
19 |
-
)
|
20 |
-
),
|
21 |
-
),
|
22 |
-
|
23 |
-
'wp-shortcodes' => array(
|
24 |
-
'display' => true,
|
25 |
-
'parent' => 'shortcodes',
|
26 |
-
'name' => __( 'WordPress Shortcodes', 'fw' ),
|
27 |
-
'description' => __(
|
28 |
-
'Lets you insert Unyson shortcodes inside any wp-editor',
|
29 |
-
'fw'
|
30 |
-
),
|
31 |
-
'thumbnail' => $thumbnails_uri . '/wp-shortcodes.jpg',
|
32 |
-
'download' => array(
|
33 |
-
'source' => 'github',
|
34 |
-
'opts' => array(
|
35 |
-
'user_repo' => 'ThemeFuse/Unyson-WP-Shortcodes-Extension',
|
36 |
-
),
|
37 |
-
),
|
38 |
-
),
|
39 |
-
|
40 |
-
'backups' => array(
|
41 |
-
'display' => true,
|
42 |
-
'parent' => null,
|
43 |
-
'name' => __( 'Backup & Demo Content', 'fw' ),
|
44 |
-
'description' => __( 'This extension lets you create an automated backup schedule, import demo content or even create a demo content archive for migration purposes.', 'fw' ),
|
45 |
-
'thumbnail' => $thumbnails_uri . '/backups.jpg',
|
46 |
-
'download' => array(
|
47 |
-
'source' => 'github',
|
48 |
-
'opts' => array(
|
49 |
-
'user_repo' => $github_account . '/Unyson-Backups-Extension',
|
50 |
-
),
|
51 |
-
),
|
52 |
-
),
|
53 |
-
|
54 |
-
'sidebars' => array(
|
55 |
-
'display' => true,
|
56 |
-
'parent' => null,
|
57 |
-
'name' => __( 'Sidebars', 'fw' ),
|
58 |
-
'description' => __( 'Brings a new layer of customization freedom to your website by letting you add more than one sidebar to a page, or different sidebars on different pages.', 'fw' ),
|
59 |
-
'thumbnail' => $thumbnails_uri . '/sidebars.jpg',
|
60 |
-
'download' => array(
|
61 |
-
'source' => 'github',
|
62 |
-
'opts' => array(
|
63 |
-
'user_repo' => $github_account . '/Unyson-Sidebars-Extension',
|
64 |
-
),
|
65 |
-
),
|
66 |
-
),
|
67 |
-
|
68 |
-
'slider' => array(
|
69 |
-
'display' => true,
|
70 |
-
'parent' => 'media',
|
71 |
-
'name' => __( 'Sliders', 'fw' ),
|
72 |
-
'description' => __( 'Adds a sliders module to your website from where you\'ll be able to create different built in jQuery sliders for your homepage and rest of the pages.', 'fw' ),
|
73 |
-
'thumbnail' => $thumbnails_uri . '/sliders.jpg',
|
74 |
-
'download' => array(
|
75 |
-
'source' => 'github',
|
76 |
-
'opts' => array(
|
77 |
-
'user_repo' => $github_account . '/Unyson-Sliders-Extension',
|
78 |
-
),
|
79 |
-
),
|
80 |
-
),
|
81 |
-
|
82 |
-
'portfolio' => array(
|
83 |
-
'display' => true,
|
84 |
-
'parent' => null,
|
85 |
-
'name' => __( 'Portfolio', 'fw' ),
|
86 |
-
'description' => __( 'This extension will add a fully fledged portfolio module that will let you display your projects using the built in portfolio pages.', 'fw' ),
|
87 |
-
'thumbnail' => $thumbnails_uri . '/portfolio.jpg',
|
88 |
-
'download' => array(
|
89 |
-
'source' => 'github',
|
90 |
-
'opts' => array(
|
91 |
-
'user_repo' => $github_account . '/Unyson-Portfolio-Extension',
|
92 |
-
),
|
93 |
-
),
|
94 |
-
),
|
95 |
-
|
96 |
-
'megamenu' => array(
|
97 |
-
'display' => true,
|
98 |
-
'parent' => null,
|
99 |
-
'name' => __( 'Mega Menu', 'fw' ),
|
100 |
-
'description' => __( 'The Mega Menu extension adds a user-friendly drop down menu that will let you easily create highly customized menu configurations.', 'fw' ),
|
101 |
-
'thumbnail' => $thumbnails_uri . '/mega-menu.jpg',
|
102 |
-
'download' => array(
|
103 |
-
'source' => 'github',
|
104 |
-
'opts' => array(
|
105 |
-
'user_repo' => $github_account . '/Unyson-MegaMenu-Extension',
|
106 |
-
),
|
107 |
-
),
|
108 |
-
),
|
109 |
-
|
110 |
-
'breadcrumbs' => array(
|
111 |
-
'display' => true,
|
112 |
-
'parent' => null,
|
113 |
-
'name' => __( 'Breadcrumbs', 'fw' ),
|
114 |
-
'description' => __( 'Creates a simplified navigation menu for the pages that can be placed anywhere in the theme. This will make navigating the website much easier.', 'fw' ),
|
115 |
-
'thumbnail' => $thumbnails_uri . '/breadcrumbs.jpg',
|
116 |
-
'download' => array(
|
117 |
-
'source' => 'github',
|
118 |
-
'opts' => array(
|
119 |
-
'user_repo' => $github_account . '/Unyson-Breadcrumbs-Extension',
|
120 |
-
),
|
121 |
-
),
|
122 |
-
),
|
123 |
-
|
124 |
-
'seo' => array(
|
125 |
-
'display' => true,
|
126 |
-
'parent' => null,
|
127 |
-
'name' => __( 'SEO', 'fw' ),
|
128 |
-
'description' => __( 'This extension will enable you to have a fully optimized WordPress website by adding optimized meta titles, keywords and descriptions.', 'fw' ),
|
129 |
-
'thumbnail' => $thumbnails_uri . '/seo.jpg',
|
130 |
-
'download' => array(
|
131 |
-
'source' => 'github',
|
132 |
-
'opts' => array(
|
133 |
-
'user_repo' => $github_account . '/Unyson-SEO-Extension',
|
134 |
-
),
|
135 |
-
),
|
136 |
-
),
|
137 |
-
|
138 |
-
'events' => array(
|
139 |
-
'display' => true,
|
140 |
-
'parent' => null,
|
141 |
-
'name' => __( 'Events', 'fw' ),
|
142 |
-
'description' => __( 'This extension adds a fully fledged Events module to your theme. It comes with built in pages that contain a calendar where events can be added.', 'fw' ),
|
143 |
-
'thumbnail' => $thumbnails_uri . '/events.jpg',
|
144 |
-
'download' => array(
|
145 |
-
'source' => 'github',
|
146 |
-
'opts' => array(
|
147 |
-
'user_repo' => $github_account . '/Unyson-Events-Extension',
|
148 |
-
),
|
149 |
-
),
|
150 |
-
),
|
151 |
-
|
152 |
-
'analytics' => array(
|
153 |
-
'display' => true,
|
154 |
-
'parent' => null,
|
155 |
-
'name' => __( 'Analytics', 'fw' ),
|
156 |
-
'description' => __( 'Enables the possibility to add the Google Analytics tracking code that will let you get all the analytics about visitors, page views and more.', 'fw' ),
|
157 |
-
'thumbnail' => $thumbnails_uri . '/analytics.jpg',
|
158 |
-
'download' => array(
|
159 |
-
'source' => 'github',
|
160 |
-
'opts' => array(
|
161 |
-
'user_repo' => $github_account . '/Unyson-Analytics-Extension',
|
162 |
-
),
|
163 |
-
),
|
164 |
-
),
|
165 |
-
|
166 |
-
'feedback' => array(
|
167 |
-
'display' => true,
|
168 |
-
'parent' => null,
|
169 |
-
'name' => __( 'Feedback', 'fw' ),
|
170 |
-
'description' => __( 'Adds the possibility to leave feedback (comments, reviews and rating) about your products, articles, etc. This replaces the default comments system.', 'fw' ),
|
171 |
-
'thumbnail' => $thumbnails_uri . '/feedback.jpg',
|
172 |
-
'download' => array(
|
173 |
-
'source' => 'github',
|
174 |
-
'opts' => array(
|
175 |
-
'user_repo' => $github_account . '/Unyson-Feedback-Extension',
|
176 |
-
),
|
177 |
-
),
|
178 |
-
),
|
179 |
-
|
180 |
-
'learning' => array(
|
181 |
-
'display' => true,
|
182 |
-
'parent' => null,
|
183 |
-
'name' => __( 'Learning', 'fw' ),
|
184 |
-
'description' => __( 'This extension adds a Learning module to your theme. Using this extension you can add courses, lessons and tests for your users to take.', 'fw' ),
|
185 |
-
'thumbnail' => $thumbnails_uri . '/learning.jpg',
|
186 |
-
'download' => array(
|
187 |
-
'source' => 'github',
|
188 |
-
'opts' => array(
|
189 |
-
'user_repo' => $github_account . '/Unyson-Learning-Extension',
|
190 |
-
),
|
191 |
-
),
|
192 |
-
),
|
193 |
-
|
194 |
-
'shortcodes' => array(
|
195 |
-
'display' => false,
|
196 |
-
'parent' => null,
|
197 |
-
'name' => __( 'Shortcodes', 'fw' ),
|
198 |
-
'description' => '',
|
199 |
-
'thumbnail' => 'about:blank',
|
200 |
-
'download' => array(
|
201 |
-
'source' => 'github',
|
202 |
-
'opts' => array(
|
203 |
-
'user_repo' => $github_account . '/Unyson-Shortcodes-Extension',
|
204 |
-
),
|
205 |
-
),
|
206 |
-
),
|
207 |
-
|
208 |
-
'builder' => array(
|
209 |
-
'display' => false,
|
210 |
-
'parent' => null,
|
211 |
-
'name' => __( 'Builder', 'fw' ),
|
212 |
-
'description' => '',
|
213 |
-
'thumbnail' => 'about:blank',
|
214 |
-
'download' => array(
|
215 |
-
'source' => 'github',
|
216 |
-
'opts' => array(
|
217 |
-
'user_repo' => $github_account . '/Unyson-Builder-Extension',
|
218 |
-
),
|
219 |
-
),
|
220 |
-
),
|
221 |
-
|
222 |
-
'forms' => array(
|
223 |
-
'display' => false,
|
224 |
-
'parent' => null,
|
225 |
-
'name' => __( 'Forms', 'fw' ),
|
226 |
-
'description' => __( 'This extension adds the possibility to create a contact form. Use the drag & drop form builder to create any contact form you\'ll ever want or need.', 'fw' ),
|
227 |
-
'thumbnail' => $thumbnails_uri . '/forms.jpg',
|
228 |
-
'download' => array(
|
229 |
-
'source' => 'github',
|
230 |
-
'opts' => array(
|
231 |
-
'user_repo' => $github_account . '/Unyson-Forms-Extension',
|
232 |
-
),
|
233 |
-
),
|
234 |
-
),
|
235 |
-
|
236 |
-
'mailer' => array(
|
237 |
-
'display' => false,
|
238 |
-
'parent' => null,
|
239 |
-
'name' => __( 'Mailer', 'fw' ),
|
240 |
-
'description' => __( 'This extension will let you set some global email options and it is used by other extensions (like Forms) to send emails.', 'fw' ),
|
241 |
-
'thumbnail' => $thumbnails_uri . '/mailer.jpg',
|
242 |
-
'download' => array(
|
243 |
-
'source' => 'github',
|
244 |
-
'opts' => array(
|
245 |
-
'user_repo' => $github_account . '/Unyson-Mailer-Extension',
|
246 |
-
),
|
247 |
-
),
|
248 |
-
),
|
249 |
-
|
250 |
-
'social' => array(
|
251 |
-
'display' => true,
|
252 |
-
'parent' => null,
|
253 |
-
'name' => __( 'Social', 'fw' ),
|
254 |
-
'description' => __( 'Use this extension to configure all your social related APIs. Other extensions will use the Social extension to connect to your social accounts.', 'fw' ),
|
255 |
-
'thumbnail' => $thumbnails_uri . '/social.jpg',
|
256 |
-
'download' => array(
|
257 |
-
'source' => 'github',
|
258 |
-
'opts' => array(
|
259 |
-
'user_repo' => $github_account . '/Unyson-Social-Extension',
|
260 |
-
),
|
261 |
-
),
|
262 |
-
),
|
263 |
-
|
264 |
-
'backup' => array(
|
265 |
-
'display' => true,
|
266 |
-
'parent' => null,
|
267 |
-
'name' => __( 'Backup', 'fw' ),
|
268 |
-
'description' => __( 'This extension lets you set up daily, weekly or monthly backup schedule. You can choose between a full backup or a data base only backup.', 'fw' ),
|
269 |
-
'thumbnail' => $thumbnails_uri . '/backup.jpg',
|
270 |
-
'download' => array(
|
271 |
-
'source' => 'github',
|
272 |
-
'opts' => array(
|
273 |
-
'user_repo' => $github_account . '/Unyson-Backup-Extension',
|
274 |
-
),
|
275 |
-
),
|
276 |
-
),
|
277 |
-
|
278 |
-
'media' => array(
|
279 |
-
'display' => false,
|
280 |
-
'parent' => null,
|
281 |
-
'name' => __( 'Media', 'fw' ),
|
282 |
-
'description' => '',
|
283 |
-
'thumbnail' => 'about:blank',
|
284 |
-
'download' => array(
|
285 |
-
'source' => 'github',
|
286 |
-
'opts' => array(
|
287 |
-
'user_repo' => $github_account . '/Unyson-Empty-Extension',
|
288 |
-
),
|
289 |
-
),
|
290 |
-
),
|
291 |
-
|
292 |
-
'population-method' => array(
|
293 |
-
'display' => false,
|
294 |
-
'parent' => 'media',
|
295 |
-
'name' => __( 'Population method', 'fw' ),
|
296 |
-
'description' => '',
|
297 |
-
'thumbnail' => 'about:blank',
|
298 |
-
'download' => array(
|
299 |
-
'source' => 'github',
|
300 |
-
'opts' => array(
|
301 |
-
'user_repo' => $github_account . '/Unyson-PopulationMethods-Extension',
|
302 |
-
),
|
303 |
-
),
|
304 |
-
),
|
305 |
-
|
306 |
-
'
|
307 |
-
'display' => true,
|
308 |
-
'parent' => null,
|
309 |
-
'name' => __( '
|
310 |
-
'description' => __( 'This extension lets you
|
311 |
-
'thumbnail' => $thumbnails_uri . '/
|
312 |
-
'download' => array(
|
313 |
-
'source'
|
314 |
-
'
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
'
|
324 |
-
'
|
325 |
-
'
|
326 |
-
'
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
)
|
334 |
-
|
|
|
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
$thumbnails_uri = fw_get_framework_directory_uri( '/core/components/extensions/manager/static/img/thumbnails' );
|
6 |
+
$github_account = 'ThemeFuse';
|
7 |
+
|
8 |
+
$extensions = array(
|
9 |
+
'page-builder' => array(
|
10 |
+
'display' => true,
|
11 |
+
'parent' => 'shortcodes',
|
12 |
+
'name' => __( 'Page Builder', 'fw' ),
|
13 |
+
'description' => __( "Let's you easily build countless pages with the help of the drag and drop visual page builder that comes with a lot of already created shortcodes.", 'fw' ),
|
14 |
+
'thumbnail' => $thumbnails_uri . '/page-builder.jpg',
|
15 |
+
'download' => array(
|
16 |
+
'source' => 'github',
|
17 |
+
'opts' => array(
|
18 |
+
'user_repo' => $github_account . '/Unyson-PageBuilder-Extension'
|
19 |
+
)
|
20 |
+
),
|
21 |
+
),
|
22 |
+
|
23 |
+
'wp-shortcodes' => array(
|
24 |
+
'display' => true,
|
25 |
+
'parent' => 'shortcodes',
|
26 |
+
'name' => __( 'WordPress Shortcodes', 'fw' ),
|
27 |
+
'description' => __(
|
28 |
+
'Lets you insert Unyson shortcodes inside any wp-editor',
|
29 |
+
'fw'
|
30 |
+
),
|
31 |
+
'thumbnail' => $thumbnails_uri . '/wp-shortcodes.jpg',
|
32 |
+
'download' => array(
|
33 |
+
'source' => 'github',
|
34 |
+
'opts' => array(
|
35 |
+
'user_repo' => 'ThemeFuse/Unyson-WP-Shortcodes-Extension',
|
36 |
+
),
|
37 |
+
),
|
38 |
+
),
|
39 |
+
|
40 |
+
'backups' => array(
|
41 |
+
'display' => true,
|
42 |
+
'parent' => null,
|
43 |
+
'name' => __( 'Backup & Demo Content', 'fw' ),
|
44 |
+
'description' => __( 'This extension lets you create an automated backup schedule, import demo content or even create a demo content archive for migration purposes.', 'fw' ),
|
45 |
+
'thumbnail' => $thumbnails_uri . '/backups.jpg',
|
46 |
+
'download' => array(
|
47 |
+
'source' => 'github',
|
48 |
+
'opts' => array(
|
49 |
+
'user_repo' => $github_account . '/Unyson-Backups-Extension',
|
50 |
+
),
|
51 |
+
),
|
52 |
+
),
|
53 |
+
|
54 |
+
'sidebars' => array(
|
55 |
+
'display' => true,
|
56 |
+
'parent' => null,
|
57 |
+
'name' => __( 'Sidebars', 'fw' ),
|
58 |
+
'description' => __( 'Brings a new layer of customization freedom to your website by letting you add more than one sidebar to a page, or different sidebars on different pages.', 'fw' ),
|
59 |
+
'thumbnail' => $thumbnails_uri . '/sidebars.jpg',
|
60 |
+
'download' => array(
|
61 |
+
'source' => 'github',
|
62 |
+
'opts' => array(
|
63 |
+
'user_repo' => $github_account . '/Unyson-Sidebars-Extension',
|
64 |
+
),
|
65 |
+
),
|
66 |
+
),
|
67 |
+
|
68 |
+
'slider' => array(
|
69 |
+
'display' => true,
|
70 |
+
'parent' => 'media',
|
71 |
+
'name' => __( 'Sliders', 'fw' ),
|
72 |
+
'description' => __( 'Adds a sliders module to your website from where you\'ll be able to create different built in jQuery sliders for your homepage and rest of the pages.', 'fw' ),
|
73 |
+
'thumbnail' => $thumbnails_uri . '/sliders.jpg',
|
74 |
+
'download' => array(
|
75 |
+
'source' => 'github',
|
76 |
+
'opts' => array(
|
77 |
+
'user_repo' => $github_account . '/Unyson-Sliders-Extension',
|
78 |
+
),
|
79 |
+
),
|
80 |
+
),
|
81 |
+
|
82 |
+
'portfolio' => array(
|
83 |
+
'display' => true,
|
84 |
+
'parent' => null,
|
85 |
+
'name' => __( 'Portfolio', 'fw' ),
|
86 |
+
'description' => __( 'This extension will add a fully fledged portfolio module that will let you display your projects using the built in portfolio pages.', 'fw' ),
|
87 |
+
'thumbnail' => $thumbnails_uri . '/portfolio.jpg',
|
88 |
+
'download' => array(
|
89 |
+
'source' => 'github',
|
90 |
+
'opts' => array(
|
91 |
+
'user_repo' => $github_account . '/Unyson-Portfolio-Extension',
|
92 |
+
),
|
93 |
+
),
|
94 |
+
),
|
95 |
+
|
96 |
+
'megamenu' => array(
|
97 |
+
'display' => true,
|
98 |
+
'parent' => null,
|
99 |
+
'name' => __( 'Mega Menu', 'fw' ),
|
100 |
+
'description' => __( 'The Mega Menu extension adds a user-friendly drop down menu that will let you easily create highly customized menu configurations.', 'fw' ),
|
101 |
+
'thumbnail' => $thumbnails_uri . '/mega-menu.jpg',
|
102 |
+
'download' => array(
|
103 |
+
'source' => 'github',
|
104 |
+
'opts' => array(
|
105 |
+
'user_repo' => $github_account . '/Unyson-MegaMenu-Extension',
|
106 |
+
),
|
107 |
+
),
|
108 |
+
),
|
109 |
+
|
110 |
+
'breadcrumbs' => array(
|
111 |
+
'display' => true,
|
112 |
+
'parent' => null,
|
113 |
+
'name' => __( 'Breadcrumbs', 'fw' ),
|
114 |
+
'description' => __( 'Creates a simplified navigation menu for the pages that can be placed anywhere in the theme. This will make navigating the website much easier.', 'fw' ),
|
115 |
+
'thumbnail' => $thumbnails_uri . '/breadcrumbs.jpg',
|
116 |
+
'download' => array(
|
117 |
+
'source' => 'github',
|
118 |
+
'opts' => array(
|
119 |
+
'user_repo' => $github_account . '/Unyson-Breadcrumbs-Extension',
|
120 |
+
),
|
121 |
+
),
|
122 |
+
),
|
123 |
+
|
124 |
+
'seo' => array(
|
125 |
+
'display' => true,
|
126 |
+
'parent' => null,
|
127 |
+
'name' => __( 'SEO', 'fw' ),
|
128 |
+
'description' => __( 'This extension will enable you to have a fully optimized WordPress website by adding optimized meta titles, keywords and descriptions.', 'fw' ),
|
129 |
+
'thumbnail' => $thumbnails_uri . '/seo.jpg',
|
130 |
+
'download' => array(
|
131 |
+
'source' => 'github',
|
132 |
+
'opts' => array(
|
133 |
+
'user_repo' => $github_account . '/Unyson-SEO-Extension',
|
134 |
+
),
|
135 |
+
),
|
136 |
+
),
|
137 |
+
|
138 |
+
'events' => array(
|
139 |
+
'display' => true,
|
140 |
+
'parent' => null,
|
141 |
+
'name' => __( 'Events', 'fw' ),
|
142 |
+
'description' => __( 'This extension adds a fully fledged Events module to your theme. It comes with built in pages that contain a calendar where events can be added.', 'fw' ),
|
143 |
+
'thumbnail' => $thumbnails_uri . '/events.jpg',
|
144 |
+
'download' => array(
|
145 |
+
'source' => 'github',
|
146 |
+
'opts' => array(
|
147 |
+
'user_repo' => $github_account . '/Unyson-Events-Extension',
|
148 |
+
),
|
149 |
+
),
|
150 |
+
),
|
151 |
+
|
152 |
+
'analytics' => array(
|
153 |
+
'display' => true,
|
154 |
+
'parent' => null,
|
155 |
+
'name' => __( 'Analytics', 'fw' ),
|
156 |
+
'description' => __( 'Enables the possibility to add the Google Analytics tracking code that will let you get all the analytics about visitors, page views and more.', 'fw' ),
|
157 |
+
'thumbnail' => $thumbnails_uri . '/analytics.jpg',
|
158 |
+
'download' => array(
|
159 |
+
'source' => 'github',
|
160 |
+
'opts' => array(
|
161 |
+
'user_repo' => $github_account . '/Unyson-Analytics-Extension',
|
162 |
+
),
|
163 |
+
),
|
164 |
+
),
|
165 |
+
|
166 |
+
'feedback' => array(
|
167 |
+
'display' => true,
|
168 |
+
'parent' => null,
|
169 |
+
'name' => __( 'Feedback', 'fw' ),
|
170 |
+
'description' => __( 'Adds the possibility to leave feedback (comments, reviews and rating) about your products, articles, etc. This replaces the default comments system.', 'fw' ),
|
171 |
+
'thumbnail' => $thumbnails_uri . '/feedback.jpg',
|
172 |
+
'download' => array(
|
173 |
+
'source' => 'github',
|
174 |
+
'opts' => array(
|
175 |
+
'user_repo' => $github_account . '/Unyson-Feedback-Extension',
|
176 |
+
),
|
177 |
+
),
|
178 |
+
),
|
179 |
+
|
180 |
+
'learning' => array(
|
181 |
+
'display' => true,
|
182 |
+
'parent' => null,
|
183 |
+
'name' => __( 'Learning', 'fw' ),
|
184 |
+
'description' => __( 'This extension adds a Learning module to your theme. Using this extension you can add courses, lessons and tests for your users to take.', 'fw' ),
|
185 |
+
'thumbnail' => $thumbnails_uri . '/learning.jpg',
|
186 |
+
'download' => array(
|
187 |
+
'source' => 'github',
|
188 |
+
'opts' => array(
|
189 |
+
'user_repo' => $github_account . '/Unyson-Learning-Extension',
|
190 |
+
),
|
191 |
+
),
|
192 |
+
),
|
193 |
+
|
194 |
+
'shortcodes' => array(
|
195 |
+
'display' => false,
|
196 |
+
'parent' => null,
|
197 |
+
'name' => __( 'Shortcodes', 'fw' ),
|
198 |
+
'description' => '',
|
199 |
+
'thumbnail' => 'about:blank',
|
200 |
+
'download' => array(
|
201 |
+
'source' => 'github',
|
202 |
+
'opts' => array(
|
203 |
+
'user_repo' => $github_account . '/Unyson-Shortcodes-Extension',
|
204 |
+
),
|
205 |
+
),
|
206 |
+
),
|
207 |
+
|
208 |
+
'builder' => array(
|
209 |
+
'display' => false,
|
210 |
+
'parent' => null,
|
211 |
+
'name' => __( 'Builder', 'fw' ),
|
212 |
+
'description' => '',
|
213 |
+
'thumbnail' => 'about:blank',
|
214 |
+
'download' => array(
|
215 |
+
'source' => 'github',
|
216 |
+
'opts' => array(
|
217 |
+
'user_repo' => $github_account . '/Unyson-Builder-Extension',
|
218 |
+
),
|
219 |
+
),
|
220 |
+
),
|
221 |
+
|
222 |
+
'forms' => array(
|
223 |
+
'display' => false,
|
224 |
+
'parent' => null,
|
225 |
+
'name' => __( 'Forms', 'fw' ),
|
226 |
+
'description' => __( 'This extension adds the possibility to create a contact form. Use the drag & drop form builder to create any contact form you\'ll ever want or need.', 'fw' ),
|
227 |
+
'thumbnail' => $thumbnails_uri . '/forms.jpg',
|
228 |
+
'download' => array(
|
229 |
+
'source' => 'github',
|
230 |
+
'opts' => array(
|
231 |
+
'user_repo' => $github_account . '/Unyson-Forms-Extension',
|
232 |
+
),
|
233 |
+
),
|
234 |
+
),
|
235 |
+
|
236 |
+
'mailer' => array(
|
237 |
+
'display' => false,
|
238 |
+
'parent' => null,
|
239 |
+
'name' => __( 'Mailer', 'fw' ),
|
240 |
+
'description' => __( 'This extension will let you set some global email options and it is used by other extensions (like Forms) to send emails.', 'fw' ),
|
241 |
+
'thumbnail' => $thumbnails_uri . '/mailer.jpg',
|
242 |
+
'download' => array(
|
243 |
+
'source' => 'github',
|
244 |
+
'opts' => array(
|
245 |
+
'user_repo' => $github_account . '/Unyson-Mailer-Extension',
|
246 |
+
),
|
247 |
+
),
|
248 |
+
),
|
249 |
+
|
250 |
+
'social' => array(
|
251 |
+
'display' => true,
|
252 |
+
'parent' => null,
|
253 |
+
'name' => __( 'Social', 'fw' ),
|
254 |
+
'description' => __( 'Use this extension to configure all your social related APIs. Other extensions will use the Social extension to connect to your social accounts.', 'fw' ),
|
255 |
+
'thumbnail' => $thumbnails_uri . '/social.jpg',
|
256 |
+
'download' => array(
|
257 |
+
'source' => 'github',
|
258 |
+
'opts' => array(
|
259 |
+
'user_repo' => $github_account . '/Unyson-Social-Extension',
|
260 |
+
),
|
261 |
+
),
|
262 |
+
),
|
263 |
+
|
264 |
+
'backup' => array(
|
265 |
+
'display' => true,
|
266 |
+
'parent' => null,
|
267 |
+
'name' => __( 'Backup', 'fw' ),
|
268 |
+
'description' => __( 'This extension lets you set up daily, weekly or monthly backup schedule. You can choose between a full backup or a data base only backup.', 'fw' ),
|
269 |
+
'thumbnail' => $thumbnails_uri . '/backup.jpg',
|
270 |
+
'download' => array(
|
271 |
+
'source' => 'github',
|
272 |
+
'opts' => array(
|
273 |
+
'user_repo' => $github_account . '/Unyson-Backup-Extension',
|
274 |
+
),
|
275 |
+
),
|
276 |
+
),
|
277 |
+
|
278 |
+
'media' => array(
|
279 |
+
'display' => false,
|
280 |
+
'parent' => null,
|
281 |
+
'name' => __( 'Media', 'fw' ),
|
282 |
+
'description' => '',
|
283 |
+
'thumbnail' => 'about:blank',
|
284 |
+
'download' => array(
|
285 |
+
'source' => 'github',
|
286 |
+
'opts' => array(
|
287 |
+
'user_repo' => $github_account . '/Unyson-Empty-Extension',
|
288 |
+
),
|
289 |
+
),
|
290 |
+
),
|
291 |
+
|
292 |
+
'population-method' => array(
|
293 |
+
'display' => false,
|
294 |
+
'parent' => 'media',
|
295 |
+
'name' => __( 'Population method', 'fw' ),
|
296 |
+
'description' => '',
|
297 |
+
'thumbnail' => 'about:blank',
|
298 |
+
'download' => array(
|
299 |
+
'source' => 'github',
|
300 |
+
'opts' => array(
|
301 |
+
'user_repo' => $github_account . '/Unyson-PopulationMethods-Extension',
|
302 |
+
),
|
303 |
+
),
|
304 |
+
),
|
305 |
+
|
306 |
+
'translatepress' => array(
|
307 |
+
'display' => true,
|
308 |
+
'parent' => null,
|
309 |
+
'name' => __( 'Translate Press', 'fw' ),
|
310 |
+
'description' => __( 'This extension lets you translate your website in any language or even add multiple languages for your users to change at their will from the front-end.', 'fw' ),
|
311 |
+
'thumbnail' => $thumbnails_uri . '/translation.jpg',
|
312 |
+
'download' => array(
|
313 |
+
'source' => 'custom',
|
314 |
+
'url_set' => 'options-general.php?page=translate-press',
|
315 |
+
'opts' => array(
|
316 |
+
'plugin' => 'translatepress-multilingual/index.php',
|
317 |
+
'remote' => 'https://downloads.wordpress.org/plugin/translatepress-multilingual'
|
318 |
+
)
|
319 |
+
)
|
320 |
+
),
|
321 |
+
|
322 |
+
'styling' => array(
|
323 |
+
'display' => true,
|
324 |
+
'parent' => null,
|
325 |
+
'name' => __( 'Styling', 'fw' ),
|
326 |
+
'description' => __( 'This extension lets you control the website visual style. Starting from predefined styles to changing specific fonts and colors across the website.', 'fw' ),
|
327 |
+
'thumbnail' => $thumbnails_uri . '/styling.jpg',
|
328 |
+
'download' => array(
|
329 |
+
'source' => 'github',
|
330 |
+
'opts' => array(
|
331 |
+
'user_repo' => $github_account . '/Unyson-Styling-Extension',
|
332 |
+
),
|
333 |
+
),
|
334 |
+
)
|
335 |
+
);
|
336 |
+
|
framework/core/components/extensions/manager/class--fw-extensions-manager.php
CHANGED
@@ -1,3671 +1,3670 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Install/Activate/Deactivate/Remove Extensions
|
5 |
-
* @internal
|
6 |
-
*/
|
7 |
-
final class _FW_Extensions_Manager
|
8 |
-
{
|
9 |
-
/**
|
10 |
-
* @var FW_Form
|
11 |
-
*/
|
12 |
-
private $extension_settings_form;
|
13 |
-
|
14 |
-
private $manifest_default_values = array(
|
15 |
-
'display' => false,
|
16 |
-
'standalone' => false,
|
17 |
-
);
|
18 |
-
|
19 |
-
private $default_thumbnail = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2PUsHf9DwAC8AGtfm5YCAAAAABJRU5ErkJgggAA';
|
20 |
-
|
21 |
-
/**
|
22 |
-
* @var FW_Access_Key
|
23 |
-
*/
|
24 |
-
private static $access_key;
|
25 |
-
|
26 |
-
private static function get_access_key() {
|
27 |
-
if (!self::$access_key) {
|
28 |
-
self::$access_key = new FW_Access_Key('fw_ext_manager');
|
29 |
-
}
|
30 |
-
|
31 |
-
return self::$access_key;
|
32 |
-
}
|
33 |
-
|
34 |
-
public function __construct()
|
35 |
-
{
|
36 |
-
// In any case/permission, make sure to not miss the plugin update actions to prevent extensions delete
|
37 |
-
{
|
38 |
-
add_action('fw_plugin_pre_update', array($this, '_action_plugin_pre_update'));
|
39 |
-
add_action('fw_plugin_post_update', array($this, '_action_plugin_post_update'));
|
40 |
-
}
|
41 |
-
|
42 |
-
// Preserve {theme}/framework-customizations/theme/available-extensions.php
|
43 |
-
{
|
44 |
-
add_filter('upgrader_pre_install', array($this, '_filter_theme_available_extensions_copy'), 999, 2);
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Must be executed after
|
48 |
-
* https://github.com/WordPress/WordPress/blob/4.6/wp-admin/includes/class-theme-upgrader.php#L204-L205
|
49 |
-
*/
|
50 |
-
add_action('upgrader_process_complete', array($this, '_action_theme_available_extensions_restore'), 999, 2);
|
51 |
-
}
|
52 |
-
|
53 |
-
add_action('fw_plugin_activate', array($this, '_action_plugin_activate_install_compatible_extensions'), 100);
|
54 |
-
add_action('fw_after_plugin_activate', array($this, '_action_after_plugin_activate'), 100);
|
55 |
-
add_action('after_switch_theme', array($this, '_action_theme_switch'));
|
56 |
-
|
57 |
-
if (!is_admin()) {
|
58 |
-
return;
|
59 |
-
}
|
60 |
-
|
61 |
-
if (!$this->can_activate() && !$this->can_install()) {
|
62 |
-
return;
|
63 |
-
}
|
64 |
-
|
65 |
-
/** Actions */
|
66 |
-
{
|
67 |
-
add_action('fw_init', array($this, '_action_fw_init'));
|
68 |
-
add_action('admin_menu', array($this, '_action_admin_menu'));
|
69 |
-
add_action('network_admin_menu', array($this, '_action_admin_menu'));
|
70 |
-
add_action('admin_footer', array($this, '_action_admin_footer'));
|
71 |
-
add_action('admin_enqueue_scripts', array($this, '_action_enqueue_scripts'));
|
72 |
-
add_action('admin_notices', array($this, '_action_admin_notices'));
|
73 |
-
|
74 |
-
if ($this->can_install()) {
|
75 |
-
add_action('wp_ajax_fw_extensions_check_direct_fs_access', array($this, '_action_ajax_check_direct_fs_access'));
|
76 |
-
add_action('wp_ajax_fw_extensions_install', array($this, '_action_ajax_install'));
|
77 |
-
add_action('wp_ajax_fw_extensions_uninstall', array($this, '_action_ajax_uninstall'));
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
/** Filters */
|
82 |
-
{
|
83 |
-
add_filter('fw_plugin_action_list', array($this, '_filter_plugin_action_list'));
|
84 |
-
}
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* If current user can:
|
89 |
-
* - activate extension
|
90 |
-
* - disable extensions
|
91 |
-
* - save extension settings options
|
92 |
-
* @return bool
|
93 |
-
*/
|
94 |
-
public function can_activate()
|
95 |
-
{
|
96 |
-
if ( fw_is_cli() ) {
|
97 |
-
return true;
|
98 |
-
}
|
99 |
-
|
100 |
-
$can_activate = current_user_can('manage_options');
|
101 |
-
|
102 |
-
if ($can_activate) {
|
103 |
-
// also you can use this method to get the capability
|
104 |
-
$can_activate = 'manage_options';
|
105 |
-
}
|
106 |
-
|
107 |
-
if (!$can_activate) {
|
108 |
-
// make sure if can install, then also can activate. (can install) > (can activate)
|
109 |
-
$can_activate = $this->can_install();
|
110 |
-
}
|
111 |
-
|
112 |
-
return $can_activate;
|
113 |
-
}
|
114 |
-
|
115 |
-
/**
|
116 |
-
* If current user can:
|
117 |
-
* - install extensions
|
118 |
-
* - delete extensions
|
119 |
-
* @return bool
|
120 |
-
*/
|
121 |
-
public function can_install()
|
122 |
-
{
|
123 |
-
if ( fw_is_cli() ) {
|
124 |
-
return true;
|
125 |
-
}
|
126 |
-
|
127 |
-
$capability = 'install_plugins';
|
128 |
-
|
129 |
-
if (is_multisite()) {
|
130 |
-
// only network admin can change files that affects the entire network
|
131 |
-
$can_install = current_user_can_for_blog(get_current_blog_id(), $capability);
|
132 |
-
} else {
|
133 |
-
$can_install = current_user_can($capability);
|
134 |
-
}
|
135 |
-
|
136 |
-
if ($can_install) {
|
137 |
-
// also you can use this method to get the capability
|
138 |
-
$can_install = $capability;
|
139 |
-
}
|
140 |
-
|
141 |
-
return $can_install;
|
142 |
-
}
|
143 |
-
|
144 |
-
public function get_page_slug()
|
145 |
-
{
|
146 |
-
return 'fw-extensions';
|
147 |
-
}
|
148 |
-
|
149 |
-
private function get_cache_key($sub_key)
|
150 |
-
{
|
151 |
-
return 'fw_extensions_manager/'. $sub_key;
|
152 |
-
}
|
153 |
-
|
154 |
-
private function get_uri($append = '')
|
155 |
-
{
|
156 |
-
return fw_get_framework_directory_uri('/core/components/extensions/manager'. $append);
|
157 |
-
}
|
158 |
-
|
159 |
-
private function get_nonce($form) {
|
160 |
-
switch ($form) {
|
161 |
-
case 'install':
|
162 |
-
return array(
|
163 |
-
'name' => '_nonce_fw_extensions_install',
|
164 |
-
'action' => 'install',
|
165 |
-
);
|
166 |
-
case 'delete':
|
167 |
-
return array(
|
168 |
-
'name' => '_nonce_fw_extensions_delete',
|
169 |
-
'action' => 'delete',
|
170 |
-
);
|
171 |
-
case 'activate':
|
172 |
-
return array(
|
173 |
-
'name' => '_nonce_fw_extensions_activate',
|
174 |
-
'action' => 'activate',
|
175 |
-
);
|
176 |
-
case 'deactivate':
|
177 |
-
return array(
|
178 |
-
'name' => '_nonce_fw_extensions_deactivate',
|
179 |
-
'action' => 'deactivate',
|
180 |
-
);
|
181 |
-
default:
|
182 |
-
return array(
|
183 |
-
'name' => '_nonce_fw_extensions',
|
184 |
-
'action' => 'default',
|
185 |
-
);
|
186 |
-
}
|
187 |
-
}
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Extensions available for download
|
191 |
-
* @return array {name => data}
|
192 |
-
*
|
193 |
-
* @since 2.6.9
|
194 |
-
*/
|
195 |
-
public function get_available_extensions()
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
$
|
203 |
-
|
204 |
-
|
205 |
-
);
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
*
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
)
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
'
|
241 |
-
'
|
242 |
-
'
|
243 |
-
'
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
$installed_extensions
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
wp_send_json_error();
|
289 |
-
}
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
$this->
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
}
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
'activated' =>
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
$succeeded_extensions
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
$succeeded_extensions
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
'
|
676 |
-
$
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
$
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
}
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
)
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
'
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
if ($lists['
|
877 |
-
$lists['supported'][$
|
878 |
-
'name'
|
879 |
-
'description' => $lists['
|
880 |
-
);
|
881 |
-
}
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
'
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
'
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
)
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
$
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
}
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
/**
|
1077 |
-
* @type bool
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
$
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
}
|
1199 |
-
|
1200 |
-
$
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
'
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
$
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
if (
|
1234 |
-
|
1235 |
-
} else {
|
1236 |
-
|
1237 |
-
}
|
1238 |
-
}
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
if (
|
1252 |
-
|
1253 |
-
$
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
)
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
)
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
'
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
-
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
|
1404 |
-
|
1405 |
-
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
-
|
1410 |
-
|
1411 |
-
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
|
1417 |
-
|
1418 |
-
|
1419 |
-
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
-
|
1424 |
-
|
1425 |
-
|
1426 |
-
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
|
1431 |
-
|
1432 |
-
|
1433 |
-
|
1434 |
-
|
1435 |
-
|
1436 |
-
|
1437 |
-
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
1444 |
-
)
|
1445 |
-
|
1446 |
-
|
1447 |
-
|
1448 |
-
|
1449 |
-
) {
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
|
1462 |
-
|
1463 |
-
|
1464 |
-
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
|
1482 |
-
|
1483 |
-
|
1484 |
-
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
|
1504 |
-
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
|
1518 |
-
|
1519 |
-
|
1520 |
-
|
1521 |
-
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
|
1529 |
-
|
1530 |
-
|
1531 |
-
|
1532 |
-
|
1533 |
-
|
1534 |
-
|
1535 |
-
|
1536 |
-
|
1537 |
-
|
1538 |
-
|
1539 |
-
|
1540 |
-
|
1541 |
-
|
1542 |
-
|
1543 |
-
|
1544 |
-
|
1545 |
-
|
1546 |
-
|
1547 |
-
|
1548 |
-
|
1549 |
-
|
1550 |
-
|
1551 |
-
|
1552 |
-
|
1553 |
-
|
1554 |
-
|
1555 |
-
|
1556 |
-
|
1557 |
-
|
1558 |
-
|
1559 |
-
|
1560 |
-
|
1561 |
-
|
1562 |
-
|
1563 |
-
|
1564 |
-
|
1565 |
-
|
1566 |
-
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
1572 |
-
|
1573 |
-
|
1574 |
-
|
1575 |
-
|
1576 |
-
|
1577 |
-
|
1578 |
-
|
1579 |
-
|
1580 |
-
|
1581 |
-
|
1582 |
-
|
1583 |
-
|
1584 |
-
|
1585 |
-
|
1586 |
-
|
1587 |
-
|
1588 |
-
|
1589 |
-
|
1590 |
-
|
1591 |
-
|
1592 |
-
|
1593 |
-
|
1594 |
-
|
1595 |
-
|
1596 |
-
|
1597 |
-
|
1598 |
-
)
|
1599 |
-
|
1600 |
-
|
1601 |
-
|
1602 |
-
|
1603 |
-
|
1604 |
-
|
1605 |
-
|
1606 |
-
|
1607 |
-
|
1608 |
-
|
1609 |
-
|
1610 |
-
|
1611 |
-
|
1612 |
-
|
1613 |
-
|
1614 |
-
|
1615 |
-
|
1616 |
-
|
1617 |
-
|
1618 |
-
|
1619 |
-
|
1620 |
-
|
1621 |
-
|
1622 |
-
|
1623 |
-
|
1624 |
-
|
1625 |
-
|
1626 |
-
|
1627 |
-
|
1628 |
-
|
1629 |
-
|
1630 |
-
|
1631 |
-
|
1632 |
-
|
1633 |
-
|
1634 |
-
|
1635 |
-
|
1636 |
-
|
1637 |
-
|
1638 |
-
$
|
1639 |
-
|
1640 |
-
|
1641 |
-
|
1642 |
-
|
1643 |
-
|
1644 |
-
|
1645 |
-
}
|
1646 |
-
|
1647 |
-
|
1648 |
-
|
1649 |
-
|
1650 |
-
|
1651 |
-
|
1652 |
-
|
1653 |
-
|
1654 |
-
|
1655 |
-
|
1656 |
-
|
1657 |
-
|
1658 |
-
|
1659 |
-
|
1660 |
-
|
1661 |
-
|
1662 |
-
|
1663 |
-
|
1664 |
-
|
1665 |
-
|
1666 |
-
|
1667 |
-
|
1668 |
-
|
1669 |
-
|
1670 |
-
|
1671 |
-
|
1672 |
-
|
1673 |
-
|
1674 |
-
|
1675 |
-
|
1676 |
-
|
1677 |
-
|
1678 |
-
|
1679 |
-
|
1680 |
-
|
1681 |
-
|
1682 |
-
|
1683 |
-
|
1684 |
-
|
1685 |
-
|
1686 |
-
|
1687 |
-
|
1688 |
-
|
1689 |
-
|
1690 |
-
{
|
1691 |
-
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
|
1696 |
-
|
1697 |
-
|
1698 |
-
|
1699 |
-
|
1700 |
-
|
1701 |
-
|
1702 |
-
|
1703 |
-
|
1704 |
-
|
1705 |
-
|
1706 |
-
|
1707 |
-
|
1708 |
-
|
1709 |
-
|
1710 |
-
|
1711 |
-
|
1712 |
-
|
1713 |
-
}
|
1714 |
-
|
1715 |
-
|
1716 |
-
|
1717 |
-
|
1718 |
-
|
1719 |
-
|
1720 |
-
|
1721 |
-
|
1722 |
-
|
1723 |
-
|
1724 |
-
|
1725 |
-
|
1726 |
-
|
1727 |
-
|
1728 |
-
|
1729 |
-
|
1730 |
-
|
1731 |
-
|
1732 |
-
|
1733 |
-
|
1734 |
-
|
1735 |
-
|
1736 |
-
|
1737 |
-
//
|
1738 |
-
|
1739 |
-
|
1740 |
-
|
1741 |
-
|
1742 |
-
|
1743 |
-
|
1744 |
-
|
1745 |
-
|
1746 |
-
|
1747 |
-
|
1748 |
-
|
1749 |
-
|
1750 |
-
|
1751 |
-
|
1752 |
-
|
1753 |
-
|
1754 |
-
|
1755 |
-
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
1759 |
-
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
1765 |
-
|
1766 |
-
|
1767 |
-
|
1768 |
-
|
1769 |
-
|
1770 |
-
|
1771 |
-
|
1772 |
-
|
1773 |
-
|
1774 |
-
|
1775 |
-
|
1776 |
-
|
1777 |
-
|
1778 |
-
|
1779 |
-
|
1780 |
-
|
1781 |
-
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
|
1787 |
-
|
1788 |
-
|
1789 |
-
|
1790 |
-
|
1791 |
-
|
1792 |
-
|
1793 |
-
|
1794 |
-
|
1795 |
-
|
1796 |
-
|
1797 |
-
|
1798 |
-
|
1799 |
-
|
1800 |
-
|
1801 |
-
|
1802 |
-
|
1803 |
-
|
1804 |
-
|
1805 |
-
|
1806 |
-
|
1807 |
-
|
1808 |
-
|
1809 |
-
|
1810 |
-
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
|
1816 |
-
|
1817 |
-
|
1818 |
-
|
1819 |
-
|
1820 |
-
|
1821 |
-
|
1822 |
-
|
1823 |
-
|
1824 |
-
|
1825 |
-
|
1826 |
-
|
1827 |
-
|
1828 |
-
|
1829 |
-
|
1830 |
-
|
1831 |
-
|
1832 |
-
|
1833 |
-
|
1834 |
-
|
1835 |
-
|
1836 |
-
|
1837 |
-
|
1838 |
-
|
1839 |
-
|
1840 |
-
|
1841 |
-
|
1842 |
-
|
1843 |
-
|
1844 |
-
|
1845 |
-
|
1846 |
-
|
1847 |
-
|
1848 |
-
|
1849 |
-
|
1850 |
-
|
1851 |
-
|
1852 |
-
|
1853 |
-
|
1854 |
-
|
1855 |
-
|
1856 |
-
|
1857 |
-
|
1858 |
-
|
1859 |
-
|
1860 |
-
|
1861 |
-
|
1862 |
-
|
1863 |
-
|
1864 |
-
|
1865 |
-
|
1866 |
-
|
1867 |
-
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
-
|
1872 |
-
|
1873 |
-
|
1874 |
-
|
1875 |
-
|
1876 |
-
|
1877 |
-
'fw'
|
1878 |
-
|
1879 |
-
|
1880 |
-
|
1881 |
-
|
1882 |
-
|
1883 |
-
'',
|
1884 |
-
|
1885 |
-
|
1886 |
-
|
1887 |
-
|
1888 |
-
|
1889 |
-
)
|
1890 |
-
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
1895 |
-
|
1896 |
-
|
1897 |
-
|
1898 |
-
|
1899 |
-
|
1900 |
-
$error =
|
1901 |
-
|
1902 |
-
|
1903 |
-
|
1904 |
-
|
1905 |
-
|
1906 |
-
|
1907 |
-
|
1908 |
-
|
1909 |
-
}
|
1910 |
-
|
1911 |
-
|
1912 |
-
|
1913 |
-
|
1914 |
-
|
1915 |
-
|
1916 |
-
|
1917 |
-
|
1918 |
-
);
|
1919 |
-
|
1920 |
-
|
1921 |
-
|
1922 |
-
|
1923 |
-
|
1924 |
-
|
1925 |
-
|
1926 |
-
|
1927 |
-
|
1928 |
-
|
1929 |
-
|
1930 |
-
|
1931 |
-
|
1932 |
-
|
1933 |
-
|
1934 |
-
|
1935 |
-
|
1936 |
-
|
1937 |
-
|
1938 |
-
|
1939 |
-
|
1940 |
-
|
1941 |
-
|
1942 |
-
|
1943 |
-
}
|
1944 |
-
|
1945 |
-
$
|
1946 |
-
|
1947 |
-
|
1948 |
-
|
1949 |
-
|
1950 |
-
|
1951 |
-
|
1952 |
-
|
1953 |
-
|
1954 |
-
|
1955 |
-
|
1956 |
-
|
1957 |
-
|
1958 |
-
|
1959 |
-
|
1960 |
-
|
1961 |
-
|
1962 |
-
|
1963 |
-
|
1964 |
-
|
1965 |
-
)
|
1966 |
-
|
1967 |
-
|
1968 |
-
|
1969 |
-
|
1970 |
-
|
1971 |
-
|
1972 |
-
|
1973 |
-
|
1974 |
-
|
1975 |
-
|
1976 |
-
|
1977 |
-
|
1978 |
-
|
1979 |
-
|
1980 |
-
|
1981 |
-
if (
|
1982 |
-
$result[$extension_name] =
|
1983 |
-
|
1984 |
-
|
1985 |
-
)
|
1986 |
-
|
1987 |
-
|
1988 |
-
|
1989 |
-
|
1990 |
-
|
1991 |
-
|
1992 |
-
|
1993 |
-
|
1994 |
-
|
1995 |
-
|
1996 |
-
|
1997 |
-
|
1998 |
-
|
1999 |
-
|
2000 |
-
|
2001 |
-
|
2002 |
-
|
2003 |
-
|
2004 |
-
|
2005 |
-
|
2006 |
-
|
2007 |
-
|
2008 |
-
|
2009 |
-
|
2010 |
-
|
2011 |
-
|
2012 |
-
|
2013 |
-
|
2014 |
-
|
2015 |
-
|
2016 |
-
|
2017 |
-
|
2018 |
-
|
2019 |
-
|
2020 |
-
|
2021 |
-
|
2022 |
-
|
2023 |
-
|
2024 |
-
|
2025 |
-
|
2026 |
-
|
2027 |
-
|
2028 |
-
|
2029 |
-
|
2030 |
-
|
2031 |
-
|
2032 |
-
|
2033 |
-
|
2034 |
-
|
2035 |
-
|
2036 |
-
|
2037 |
-
|
2038 |
-
|
2039 |
-
|
2040 |
-
|
2041 |
-
|
2042 |
-
|
2043 |
-
|
2044 |
-
|
2045 |
-
|
2046 |
-
|
2047 |
-
|
2048 |
-
|
2049 |
-
|
2050 |
-
|
2051 |
-
|
2052 |
-
|
2053 |
-
|
2054 |
-
|
2055 |
-
|
2056 |
-
|
2057 |
-
|
2058 |
-
|
2059 |
-
|
2060 |
-
|
2061 |
-
|
2062 |
-
|
2063 |
-
|
2064 |
-
|
2065 |
-
|
2066 |
-
|
2067 |
-
|
2068 |
-
|
2069 |
-
|
2070 |
-
|
2071 |
-
|
2072 |
-
|
2073 |
-
|
2074 |
-
|
2075 |
-
|
2076 |
-
|
2077 |
-
|
2078 |
-
|
2079 |
-
|
2080 |
-
|
2081 |
-
|
2082 |
-
|
2083 |
-
|
2084 |
-
|
2085 |
-
|
2086 |
-
|
2087 |
-
|
2088 |
-
|
2089 |
-
|
2090 |
-
|
2091 |
-
|
2092 |
-
|
2093 |
-
|
2094 |
-
|
2095 |
-
|
2096 |
-
|
2097 |
-
|
2098 |
-
|
2099 |
-
|
2100 |
-
|
2101 |
-
|
2102 |
-
|
2103 |
-
|
2104 |
-
|
2105 |
-
$this->
|
2106 |
-
|
2107 |
-
|
2108 |
-
|
2109 |
-
|
2110 |
-
|
2111 |
-
|
2112 |
-
|
2113 |
-
|
2114 |
-
|
2115 |
-
|
2116 |
-
|
2117 |
-
|
2118 |
-
|
2119 |
-
|
2120 |
-
|
2121 |
-
|
2122 |
-
|
2123 |
-
|
2124 |
-
$error =
|
2125 |
-
|
2126 |
-
|
2127 |
-
|
2128 |
-
|
2129 |
-
|
2130 |
-
|
2131 |
-
|
2132 |
-
|
2133 |
-
|
2134 |
-
|
2135 |
-
|
2136 |
-
|
2137 |
-
|
2138 |
-
|
2139 |
-
|
2140 |
-
|
2141 |
-
|
2142 |
-
|
2143 |
-
|
2144 |
-
|
2145 |
-
|
2146 |
-
|
2147 |
-
|
2148 |
-
|
2149 |
-
|
2150 |
-
|
2151 |
-
|
2152 |
-
|
2153 |
-
|
2154 |
-
|
2155 |
-
|
2156 |
-
|
2157 |
-
|
2158 |
-
|
2159 |
-
|
2160 |
-
|
2161 |
-
|
2162 |
-
|
2163 |
-
|
2164 |
-
|
2165 |
-
|
2166 |
-
|
2167 |
-
|
2168 |
-
|
2169 |
-
|
2170 |
-
|
2171 |
-
|
2172 |
-
|
2173 |
-
|
2174 |
-
|
2175 |
-
|
2176 |
-
|
2177 |
-
|
2178 |
-
|
2179 |
-
|
2180 |
-
|
2181 |
-
|
2182 |
-
|
2183 |
-
|
2184 |
-
|
2185 |
-
|
2186 |
-
|
2187 |
-
|
2188 |
-
|
2189 |
-
|
2190 |
-
|
2191 |
-
|
2192 |
-
|
2193 |
-
|
2194 |
-
|
2195 |
-
|
2196 |
-
|
2197 |
-
|
2198 |
-
|
2199 |
-
|
2200 |
-
|
2201 |
-
|
2202 |
-
|
2203 |
-
|
2204 |
-
|
2205 |
-
|
2206 |
-
|
2207 |
-
|
2208 |
-
|
2209 |
-
|
2210 |
-
|
2211 |
-
|
2212 |
-
|
2213 |
-
|
2214 |
-
|
2215 |
-
);
|
2216 |
-
|
2217 |
-
|
2218 |
-
|
2219 |
-
$current_deactivating_extensions
|
2220 |
-
|
2221 |
-
|
2222 |
-
|
2223 |
-
|
2224 |
-
|
2225 |
-
|
2226 |
-
|
2227 |
-
|
2228 |
-
|
2229 |
-
|
2230 |
-
|
2231 |
-
|
2232 |
-
|
2233 |
-
|
2234 |
-
|
2235 |
-
|
2236 |
-
|
2237 |
-
|
2238 |
-
|
2239 |
-
|
2240 |
-
|
2241 |
-
|
2242 |
-
|
2243 |
-
|
2244 |
-
|
2245 |
-
|
2246 |
-
|
2247 |
-
|
2248 |
-
|
2249 |
-
|
2250 |
-
|
2251 |
-
|
2252 |
-
|
2253 |
-
|
2254 |
-
|
2255 |
-
|
2256 |
-
|
2257 |
-
|
2258 |
-
|
2259 |
-
|
2260 |
-
|
2261 |
-
|
2262 |
-
|
2263 |
-
),
|
2264 |
-
|
2265 |
-
)
|
2266 |
-
);
|
2267 |
-
|
2268 |
-
|
2269 |
-
|
2270 |
-
|
2271 |
-
|
2272 |
-
|
2273 |
-
|
2274 |
-
|
2275 |
-
|
2276 |
-
|
2277 |
-
|
2278 |
-
|
2279 |
-
|
2280 |
-
|
2281 |
-
|
2282 |
-
|
2283 |
-
|
2284 |
-
|
2285 |
-
|
2286 |
-
|
2287 |
-
|
2288 |
-
|
2289 |
-
|
2290 |
-
|
2291 |
-
|
2292 |
-
|
2293 |
-
|
2294 |
-
|
2295 |
-
|
2296 |
-
|
2297 |
-
|
2298 |
-
|
2299 |
-
|
2300 |
-
|
2301 |
-
|
2302 |
-
|
2303 |
-
|
2304 |
-
|
2305 |
-
}
|
2306 |
-
|
2307 |
-
|
2308 |
-
|
2309 |
-
|
2310 |
-
|
2311 |
-
|
2312 |
-
|
2313 |
-
|
2314 |
-
|
2315 |
-
|
2316 |
-
|
2317 |
-
|
2318 |
-
|
2319 |
-
|
2320 |
-
|
2321 |
-
|
2322 |
-
|
2323 |
-
|
2324 |
-
|
2325 |
-
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
2329 |
-
|
2330 |
-
|
2331 |
-
|
2332 |
-
|
2333 |
-
|
2334 |
-
|
2335 |
-
|
2336 |
-
echo
|
2337 |
-
|
2338 |
-
|
2339 |
-
|
2340 |
-
|
2341 |
-
|
2342 |
-
|
2343 |
-
|
2344 |
-
|
2345 |
-
|
2346 |
-
|
2347 |
-
|
2348 |
-
|
2349 |
-
|
2350 |
-
|
2351 |
-
|
2352 |
-
|
2353 |
-
|
2354 |
-
|
2355 |
-
|
2356 |
-
|
2357 |
-
|
2358 |
-
|
2359 |
-
|
2360 |
-
|
2361 |
-
|
2362 |
-
|
2363 |
-
|
2364 |
-
|
2365 |
-
|
2366 |
-
|
2367 |
-
|
2368 |
-
|
2369 |
-
|
2370 |
-
|
2371 |
-
|
2372 |
-
|
2373 |
-
|
2374 |
-
|
2375 |
-
|
2376 |
-
|
2377 |
-
|
2378 |
-
|
2379 |
-
|
2380 |
-
|
2381 |
-
|
2382 |
-
|
2383 |
-
|
2384 |
-
|
2385 |
-
|
2386 |
-
|
2387 |
-
|
2388 |
-
|
2389 |
-
|
2390 |
-
|
2391 |
-
|
2392 |
-
|
2393 |
-
|
2394 |
-
|
2395 |
-
|
2396 |
-
|
2397 |
-
|
2398 |
-
|
2399 |
-
|
2400 |
-
|
2401 |
-
|
2402 |
-
|
2403 |
-
|
2404 |
-
|
2405 |
-
|
2406 |
-
|
2407 |
-
);
|
2408 |
-
|
2409 |
-
|
2410 |
-
|
2411 |
-
|
2412 |
-
|
2413 |
-
|
2414 |
-
|
2415 |
-
|
2416 |
-
|
2417 |
-
|
2418 |
-
|
2419 |
-
|
2420 |
-
|
2421 |
-
|
2422 |
-
|
2423 |
-
|
2424 |
-
|
2425 |
-
|
2426 |
-
|
2427 |
-
|
2428 |
-
|
2429 |
-
|
2430 |
-
|
2431 |
-
|
2432 |
-
|
2433 |
-
|
2434 |
-
|
2435 |
-
|
2436 |
-
|
2437 |
-
|
2438 |
-
|
2439 |
-
|
2440 |
-
|
2441 |
-
|
2442 |
-
|
2443 |
-
|
2444 |
-
|
2445 |
-
|
2446 |
-
|
2447 |
-
|
2448 |
-
|
2449 |
-
|
2450 |
-
|
2451 |
-
|
2452 |
-
|
2453 |
-
|
2454 |
-
|
2455 |
-
|
2456 |
-
|
2457 |
-
|
2458 |
-
|
2459 |
-
|
2460 |
-
|
2461 |
-
|
2462 |
-
|
2463 |
-
|
2464 |
-
|
2465 |
-
|
2466 |
-
|
2467 |
-
|
2468 |
-
|
2469 |
-
|
2470 |
-
|
2471 |
-
|
2472 |
-
|
2473 |
-
|
2474 |
-
|
2475 |
-
|
2476 |
-
|
2477 |
-
|
2478 |
-
|
2479 |
-
|
2480 |
-
|
2481 |
-
$
|
2482 |
-
|
2483 |
-
);
|
2484 |
-
|
2485 |
-
|
2486 |
-
|
2487 |
-
|
2488 |
-
|
2489 |
-
|
2490 |
-
}
|
2491 |
-
|
2492 |
-
|
2493 |
-
|
2494 |
-
|
2495 |
-
|
2496 |
-
|
2497 |
-
|
2498 |
-
|
2499 |
-
)
|
2500 |
-
|
2501 |
-
|
2502 |
-
|
2503 |
-
|
2504 |
-
$
|
2505 |
-
|
2506 |
-
|
2507 |
-
|
2508 |
-
|
2509 |
-
|
2510 |
-
|
2511 |
-
$
|
2512 |
-
|
2513 |
-
|
2514 |
-
|
2515 |
-
|
2516 |
-
|
2517 |
-
|
2518 |
-
}
|
2519 |
-
|
2520 |
-
|
2521 |
-
|
2522 |
-
|
2523 |
-
|
2524 |
-
|
2525 |
-
|
2526 |
-
|
2527 |
-
|
2528 |
-
|
2529 |
-
|
2530 |
-
|
2531 |
-
|
2532 |
-
|
2533 |
-
|
2534 |
-
|
2535 |
-
|
2536 |
-
|
2537 |
-
|
2538 |
-
|
2539 |
-
|
2540 |
-
|
2541 |
-
|
2542 |
-
|
2543 |
-
|
2544 |
-
|
2545 |
-
|
2546 |
-
|
2547 |
-
|
2548 |
-
|
2549 |
-
*
|
2550 |
-
*
|
2551 |
-
|
2552 |
-
|
2553 |
-
|
2554 |
-
|
2555 |
-
|
2556 |
-
|
2557 |
-
|
2558 |
-
|
2559 |
-
|
2560 |
-
|
2561 |
-
|
2562 |
-
}
|
2563 |
-
|
2564 |
-
/**
|
2565 |
-
* Merge the downloaded extension directory with the existing directory
|
2566 |
-
*
|
2567 |
-
* @param string $source_wp_fs_dir Downloaded extension directory
|
2568 |
-
* @param string $destination_wp_fs_dir
|
2569 |
-
*
|
2570 |
-
* @return null|WP_Error
|
2571 |
-
*/
|
2572 |
-
private function merge_extension($source_wp_fs_dir, $destination_wp_fs_dir)
|
2573 |
-
|
2574 |
-
|
2575 |
-
|
2576 |
-
|
2577 |
-
|
2578 |
-
|
2579 |
-
|
2580 |
-
|
2581 |
-
|
2582 |
-
|
2583 |
-
|
2584 |
-
|
2585 |
-
$
|
2586 |
-
|
2587 |
-
|
2588 |
-
|
2589 |
-
|
2590 |
-
|
2591 |
-
|
2592 |
-
|
2593 |
-
|
2594 |
-
|
2595 |
-
|
2596 |
-
*
|
2597 |
-
|
2598 |
-
|
2599 |
-
|
2600 |
-
|
2601 |
-
|
2602 |
-
|
2603 |
-
|
2604 |
-
$
|
2605 |
-
|
2606 |
-
|
2607 |
-
|
2608 |
-
|
2609 |
-
|
2610 |
-
|
2611 |
-
|
2612 |
-
|
2613 |
-
|
2614 |
-
|
2615 |
-
|
2616 |
-
|
2617 |
-
|
2618 |
-
|
2619 |
-
|
2620 |
-
*
|
2621 |
-
*
|
2622 |
-
*
|
2623 |
-
|
2624 |
-
|
2625 |
-
|
2626 |
-
|
2627 |
-
|
2628 |
-
|
2629 |
-
|
2630 |
-
|
2631 |
-
|
2632 |
-
|
2633 |
-
|
2634 |
-
|
2635 |
-
|
2636 |
-
|
2637 |
-
|
2638 |
-
|
2639 |
-
|
2640 |
-
|
2641 |
-
|
2642 |
-
|
2643 |
-
|
2644 |
-
|
2645 |
-
|
2646 |
-
|
2647 |
-
|
2648 |
-
|
2649 |
-
|
2650 |
-
|
2651 |
-
|
2652 |
-
|
2653 |
-
|
2654 |
-
$
|
2655 |
-
|
2656 |
-
|
2657 |
-
|
2658 |
-
|
2659 |
-
|
2660 |
-
|
2661 |
-
|
2662 |
-
|
2663 |
-
|
2664 |
-
|
2665 |
-
|
2666 |
-
|
2667 |
-
|
2668 |
-
|
2669 |
-
|
2670 |
-
|
2671 |
-
|
2672 |
-
|
2673 |
-
|
2674 |
-
|
2675 |
-
$
|
2676 |
-
|
2677 |
-
|
2678 |
-
|
2679 |
-
|
2680 |
-
|
2681 |
-
|
2682 |
-
|
2683 |
-
|
2684 |
-
|
2685 |
-
|
2686 |
-
|
2687 |
-
|
2688 |
-
|
2689 |
-
|
2690 |
-
|
2691 |
-
|
2692 |
-
|
2693 |
-
$
|
2694 |
-
|
2695 |
-
|
2696 |
-
|
2697 |
-
|
2698 |
-
|
2699 |
-
|
2700 |
-
|
2701 |
-
|
2702 |
-
|
2703 |
-
|
2704 |
-
|
2705 |
-
|
2706 |
-
|
2707 |
-
|
2708 |
-
|
2709 |
-
|
2710 |
-
$
|
2711 |
-
|
2712 |
-
|
2713 |
-
|
2714 |
-
|
2715 |
-
|
2716 |
-
|
2717 |
-
|
2718 |
-
|
2719 |
-
|
2720 |
-
|
2721 |
-
|
2722 |
-
|
2723 |
-
|
2724 |
-
|
2725 |
-
|
2726 |
-
|
2727 |
-
|
2728 |
-
|
2729 |
-
|
2730 |
-
|
2731 |
-
|
2732 |
-
|
2733 |
-
|
2734 |
-
|
2735 |
-
|
2736 |
-
|
2737 |
-
|
2738 |
-
|
2739 |
-
|
2740 |
-
|
2741 |
-
|
2742 |
-
|
2743 |
-
|
2744 |
-
|
2745 |
-
|
2746 |
-
|
2747 |
-
|
2748 |
-
|
2749 |
-
|
2750 |
-
|
2751 |
-
|
2752 |
-
|
2753 |
-
|
2754 |
-
|
2755 |
-
|
2756 |
-
|
2757 |
-
|
2758 |
-
|
2759 |
-
$this->
|
2760 |
-
|
2761 |
-
|
2762 |
-
|
2763 |
-
|
2764 |
-
|
2765 |
-
* @
|
2766 |
-
* @
|
2767 |
-
|
2768 |
-
|
2769 |
-
|
2770 |
-
|
2771 |
-
|
2772 |
-
|
2773 |
-
|
2774 |
-
|
2775 |
-
|
2776 |
-
|
2777 |
-
|
2778 |
-
|
2779 |
-
|
2780 |
-
|
2781 |
-
|
2782 |
-
|
2783 |
-
|
2784 |
-
|
2785 |
-
|
2786 |
-
|
2787 |
-
|
2788 |
-
|
2789 |
-
|
2790 |
-
|
2791 |
-
|
2792 |
-
|
2793 |
-
|
2794 |
-
|
2795 |
-
|
2796 |
-
|
2797 |
-
|
2798 |
-
|
2799 |
-
|
2800 |
-
|
2801 |
-
|
2802 |
-
|
2803 |
-
|
2804 |
-
* @param array $
|
2805 |
-
*
|
2806 |
-
*
|
2807 |
-
|
2808 |
-
|
2809 |
-
|
2810 |
-
|
2811 |
-
|
2812 |
-
|
2813 |
-
|
2814 |
-
|
2815 |
-
|
2816 |
-
|
2817 |
-
|
2818 |
-
|
2819 |
-
|
2820 |
-
|
2821 |
-
|
2822 |
-
|
2823 |
-
|
2824 |
-
|
2825 |
-
|
2826 |
-
|
2827 |
-
|
2828 |
-
|
2829 |
-
|
2830 |
-
|
2831 |
-
|
2832 |
-
'
|
2833 |
-
|
2834 |
-
|
2835 |
-
|
2836 |
-
|
2837 |
-
|
2838 |
-
|
2839 |
-
|
2840 |
-
|
2841 |
-
|
2842 |
-
'
|
2843 |
-
$
|
2844 |
-
|
2845 |
-
|
2846 |
-
|
2847 |
-
|
2848 |
-
|
2849 |
-
|
2850 |
-
|
2851 |
-
|
2852 |
-
|
2853 |
-
|
2854 |
-
|
2855 |
-
|
2856 |
-
|
2857 |
-
|
2858 |
-
|
2859 |
-
|
2860 |
-
|
2861 |
-
|
2862 |
-
|
2863 |
-
|
2864 |
-
|
2865 |
-
|
2866 |
-
|
2867 |
-
$current_parent = $
|
2868 |
-
|
2869 |
-
|
2870 |
-
|
2871 |
-
|
2872 |
-
|
2873 |
-
|
2874 |
-
|
2875 |
-
|
2876 |
-
|
2877 |
-
|
2878 |
-
|
2879 |
-
|
2880 |
-
|
2881 |
-
|
2882 |
-
|
2883 |
-
|
2884 |
-
|
2885 |
-
|
2886 |
-
|
2887 |
-
|
2888 |
-
|
2889 |
-
|
2890 |
-
|
2891 |
-
|
2892 |
-
|
2893 |
-
|
2894 |
-
|
2895 |
-
|
2896 |
-
|
2897 |
-
|
2898 |
-
|
2899 |
-
|
2900 |
-
|
2901 |
-
|
2902 |
-
|
2903 |
-
|
2904 |
-
|
2905 |
-
|
2906 |
-
|
2907 |
-
|
2908 |
-
|
2909 |
-
|
2910 |
-
|
2911 |
-
|
2912 |
-
|
2913 |
-
|
2914 |
-
|
2915 |
-
|
2916 |
-
|
2917 |
-
|
2918 |
-
|
2919 |
-
|
2920 |
-
|
2921 |
-
|
2922 |
-
|
2923 |
-
|
2924 |
-
|
2925 |
-
|
2926 |
-
&&
|
2927 |
-
|
2928 |
-
|
2929 |
-
|
2930 |
-
|
2931 |
-
|
2932 |
-
|
2933 |
-
|
2934 |
-
|
2935 |
-
|
2936 |
-
|
2937 |
-
|
2938 |
-
|
2939 |
-
|
2940 |
-
|
2941 |
-
|
2942 |
-
|
2943 |
-
&&
|
2944 |
-
|
2945 |
-
&&
|
2946 |
-
|
2947 |
-
|
2948 |
-
|
2949 |
-
|
2950 |
-
|
2951 |
-
|
2952 |
-
|
2953 |
-
|
2954 |
-
|
2955 |
-
|
2956 |
-
'
|
2957 |
-
|
2958 |
-
|
2959 |
-
|
2960 |
-
|
2961 |
-
|
2962 |
-
|
2963 |
-
|
2964 |
-
|
2965 |
-
|
2966 |
-
|
2967 |
-
'
|
2968 |
-
|
2969 |
-
|
2970 |
-
'fw',
|
2971 |
-
|
2972 |
-
)
|
2973 |
-
|
2974 |
-
|
2975 |
-
|
2976 |
-
'
|
2977 |
-
|
2978 |
-
|
2979 |
-
|
2980 |
-
|
2981 |
-
|
2982 |
-
|
2983 |
-
|
2984 |
-
|
2985 |
-
|
2986 |
-
|
2987 |
-
*
|
2988 |
-
|
2989 |
-
|
2990 |
-
|
2991 |
-
|
2992 |
-
|
2993 |
-
|
2994 |
-
|
2995 |
-
'
|
2996 |
-
|
2997 |
-
|
2998 |
-
|
2999 |
-
|
3000 |
-
|
3001 |
-
'
|
3002 |
-
|
3003 |
-
|
3004 |
-
|
3005 |
-
|
3006 |
-
|
3007 |
-
|
3008 |
-
|
3009 |
-
|
3010 |
-
|
3011 |
-
|
3012 |
-
|
3013 |
-
|
3014 |
-
|
3015 |
-
|
3016 |
-
|
3017 |
-
|
3018 |
-
|
3019 |
-
|
3020 |
-
|
3021 |
-
|
3022 |
-
|
3023 |
-
|
3024 |
-
|
3025 |
-
|
3026 |
-
|
3027 |
-
|
3028 |
-
|
3029 |
-
|
3030 |
-
|
3031 |
-
|
3032 |
-
|
3033 |
-
|
3034 |
-
|
3035 |
-
|
3036 |
-
|
3037 |
-
|
3038 |
-
|
3039 |
-
|
3040 |
-
|
3041 |
-
|
3042 |
-
|
3043 |
-
|
3044 |
-
|
3045 |
-
|
3046 |
-
$this->
|
3047 |
-
|
3048 |
-
|
3049 |
-
|
3050 |
-
|
3051 |
-
|
3052 |
-
|
3053 |
-
|
3054 |
-
|
3055 |
-
|
3056 |
-
* @param array $
|
3057 |
-
* @param
|
3058 |
-
|
3059 |
-
|
3060 |
-
|
3061 |
-
|
3062 |
-
|
3063 |
-
|
3064 |
-
|
3065 |
-
|
3066 |
-
|
3067 |
-
|
3068 |
-
|
3069 |
-
|
3070 |
-
|
3071 |
-
|
3072 |
-
|
3073 |
-
|
3074 |
-
|
3075 |
-
|
3076 |
-
|
3077 |
-
|
3078 |
-
|
3079 |
-
|
3080 |
-
|
3081 |
-
|
3082 |
-
|
3083 |
-
'
|
3084 |
-
|
3085 |
-
|
3086 |
-
|
3087 |
-
|
3088 |
-
|
3089 |
-
|
3090 |
-
|
3091 |
-
|
3092 |
-
|
3093 |
-
|
3094 |
-
|
3095 |
-
|
3096 |
-
|
3097 |
-
*
|
3098 |
-
* @
|
3099 |
-
|
3100 |
-
|
3101 |
-
|
3102 |
-
|
3103 |
-
|
3104 |
-
|
3105 |
-
|
3106 |
-
|
3107 |
-
* @
|
3108 |
-
|
3109 |
-
|
3110 |
-
|
3111 |
-
|
3112 |
-
|
3113 |
-
|
3114 |
-
|
3115 |
-
|
3116 |
-
|
3117 |
-
|
3118 |
-
|
3119 |
-
|
3120 |
-
|
3121 |
-
|
3122 |
-
|
3123 |
-
|
3124 |
-
|
3125 |
-
|
3126 |
-
|
3127 |
-
|
3128 |
-
|
3129 |
-
|
3130 |
-
|
3131 |
-
$current_parent = $
|
3132 |
-
|
3133 |
-
|
3134 |
-
|
3135 |
-
|
3136 |
-
|
3137 |
-
|
3138 |
-
|
3139 |
-
|
3140 |
-
|
3141 |
-
|
3142 |
-
|
3143 |
-
|
3144 |
-
|
3145 |
-
|
3146 |
-
|
3147 |
-
|
3148 |
-
|
3149 |
-
|
3150 |
-
|
3151 |
-
|
3152 |
-
|
3153 |
-
|
3154 |
-
|
3155 |
-
|
3156 |
-
|
3157 |
-
|
3158 |
-
|
3159 |
-
$
|
3160 |
-
|
3161 |
-
|
3162 |
-
|
3163 |
-
|
3164 |
-
|
3165 |
-
|
3166 |
-
|
3167 |
-
|
3168 |
-
|
3169 |
-
|
3170 |
-
|
3171 |
-
|
3172 |
-
|
3173 |
-
|
3174 |
-
|
3175 |
-
|
3176 |
-
|
3177 |
-
|
3178 |
-
|
3179 |
-
|
3180 |
-
|
3181 |
-
|
3182 |
-
|
3183 |
-
|
3184 |
-
|
3185 |
-
|
3186 |
-
|
3187 |
-
|
3188 |
-
|
3189 |
-
|
3190 |
-
|
3191 |
-
|
3192 |
-
|
3193 |
-
|
3194 |
-
|
3195 |
-
|
3196 |
-
|
3197 |
-
|
3198 |
-
|
3199 |
-
|
3200 |
-
|
3201 |
-
|
3202 |
-
|
3203 |
-
|
3204 |
-
|
3205 |
-
*
|
3206 |
-
|
3207 |
-
|
3208 |
-
|
3209 |
-
|
3210 |
-
|
3211 |
-
|
3212 |
-
|
3213 |
-
|
3214 |
-
|
3215 |
-
|
3216 |
-
|
3217 |
-
|
3218 |
-
|
3219 |
-
|
3220 |
-
|
3221 |
-
|
3222 |
-
|
3223 |
-
|
3224 |
-
|
3225 |
-
|
3226 |
-
|
3227 |
-
|
3228 |
-
|
3229 |
-
*
|
3230 |
-
*
|
3231 |
-
* @
|
3232 |
-
|
3233 |
-
|
3234 |
-
|
3235 |
-
|
3236 |
-
|
3237 |
-
|
3238 |
-
|
3239 |
-
|
3240 |
-
'
|
3241 |
-
|
3242 |
-
|
3243 |
-
|
3244 |
-
|
3245 |
-
|
3246 |
-
|
3247 |
-
|
3248 |
-
|
3249 |
-
|
3250 |
-
|
3251 |
-
|
3252 |
-
|
3253 |
-
|
3254 |
-
|
3255 |
-
|
3256 |
-
|
3257 |
-
'
|
3258 |
-
|
3259 |
-
|
3260 |
-
|
3261 |
-
|
3262 |
-
|
3263 |
-
|
3264 |
-
'
|
3265 |
-
|
3266 |
-
|
3267 |
-
|
3268 |
-
|
3269 |
-
|
3270 |
-
$
|
3271 |
-
$
|
3272 |
-
|
3273 |
-
|
3274 |
-
|
3275 |
-
|
3276 |
-
|
3277 |
-
|
3278 |
-
|
3279 |
-
|
3280 |
-
|
3281 |
-
|
3282 |
-
|
3283 |
-
|
3284 |
-
|
3285 |
-
|
3286 |
-
|
3287 |
-
'
|
3288 |
-
|
3289 |
-
|
3290 |
-
|
3291 |
-
|
3292 |
-
|
3293 |
-
|
3294 |
-
'
|
3295 |
-
|
3296 |
-
|
3297 |
-
|
3298 |
-
|
3299 |
-
|
3300 |
-
|
3301 |
-
|
3302 |
-
|
3303 |
-
'
|
3304 |
-
|
3305 |
-
|
3306 |
-
|
3307 |
-
|
3308 |
-
|
3309 |
-
|
3310 |
-
|
3311 |
-
'
|
3312 |
-
|
3313 |
-
|
3314 |
-
|
3315 |
-
|
3316 |
-
|
3317 |
-
|
3318 |
-
|
3319 |
-
*
|
3320 |
-
*
|
3321 |
-
* @
|
3322 |
-
|
3323 |
-
|
3324 |
-
|
3325 |
-
|
3326 |
-
|
3327 |
-
|
3328 |
-
|
3329 |
-
|
3330 |
-
'
|
3331 |
-
|
3332 |
-
|
3333 |
-
|
3334 |
-
|
3335 |
-
|
3336 |
-
|
3337 |
-
|
3338 |
-
|
3339 |
-
|
3340 |
-
|
3341 |
-
'
|
3342 |
-
|
3343 |
-
|
3344 |
-
|
3345 |
-
|
3346 |
-
|
3347 |
-
*
|
3348 |
-
*
|
3349 |
-
*
|
3350 |
-
*
|
3351 |
-
*
|
3352 |
-
*
|
3353 |
-
|
3354 |
-
|
3355 |
-
|
3356 |
-
|
3357 |
-
|
3358 |
-
|
3359 |
-
|
3360 |
-
|
3361 |
-
'
|
3362 |
-
|
3363 |
-
|
3364 |
-
|
3365 |
-
|
3366 |
-
|
3367 |
-
|
3368 |
-
|
3369 |
-
|
3370 |
-
|
3371 |
-
|
3372 |
-
|
3373 |
-
|
3374 |
-
|
3375 |
-
|
3376 |
-
$
|
3377 |
-
|
3378 |
-
|
3379 |
-
|
3380 |
-
|
3381 |
-
|
3382 |
-
|
3383 |
-
|
3384 |
-
|
3385 |
-
|
3386 |
-
|
3387 |
-
*
|
3388 |
-
* @param
|
3389 |
-
*
|
3390 |
-
*
|
3391 |
-
|
3392 |
-
|
3393 |
-
|
3394 |
-
|
3395 |
-
|
3396 |
-
|
3397 |
-
|
3398 |
-
|
3399 |
-
|
3400 |
-
|
3401 |
-
|
3402 |
-
|
3403 |
-
|
3404 |
-
|
3405 |
-
|
3406 |
-
|
3407 |
-
|
3408 |
-
|
3409 |
-
|
3410 |
-
|
3411 |
-
|
3412 |
-
*
|
3413 |
-
* @param
|
3414 |
-
*
|
3415 |
-
*
|
3416 |
-
|
3417 |
-
|
3418 |
-
|
3419 |
-
|
3420 |
-
|
3421 |
-
|
3422 |
-
|
3423 |
-
&&
|
3424 |
-
|
3425 |
-
&&
|
3426 |
-
|
3427 |
-
|
3428 |
-
|
3429 |
-
|
3430 |
-
|
3431 |
-
|
3432 |
-
|
3433 |
-
|
3434 |
-
|
3435 |
-
|
3436 |
-
*
|
3437 |
-
*
|
3438 |
-
*
|
3439 |
-
|
3440 |
-
|
3441 |
-
|
3442 |
-
|
3443 |
-
|
3444 |
-
|
3445 |
-
|
3446 |
-
|
3447 |
-
|
3448 |
-
|
3449 |
-
|
3450 |
-
|
3451 |
-
*
|
3452 |
-
*
|
3453 |
-
*
|
3454 |
-
*
|
3455 |
-
*
|
3456 |
-
|
3457 |
-
|
3458 |
-
|
3459 |
-
|
3460 |
-
|
3461 |
-
|
3462 |
-
|
3463 |
-
|
3464 |
-
|
3465 |
-
|
3466 |
-
|
3467 |
-
|
3468 |
-
|
3469 |
-
|
3470 |
-
|
3471 |
-
|
3472 |
-
|
3473 |
-
|
3474 |
-
|
3475 |
-
|
3476 |
-
|
3477 |
-
|
3478 |
-
|
3479 |
-
|
3480 |
-
|
3481 |
-
|
3482 |
-
|
3483 |
-
|
3484 |
-
|
3485 |
-
|
3486 |
-
|
3487 |
-
|
3488 |
-
|
3489 |
-
|
3490 |
-
|
3491 |
-
|
3492 |
-
|
3493 |
-
|
3494 |
-
|
3495 |
-
|
3496 |
-
|
3497 |
-
|
3498 |
-
|
3499 |
-
|
3500 |
-
|
3501 |
-
|
3502 |
-
|
3503 |
-
|
3504 |
-
|
3505 |
-
|
3506 |
-
|
3507 |
-
|
3508 |
-
|
3509 |
-
|
3510 |
-
|
3511 |
-
|
3512 |
-
|
3513 |
-
|
3514 |
-
|
3515 |
-
|
3516 |
-
|
3517 |
-
|
3518 |
-
|
3519 |
-
|
3520 |
-
|
3521 |
-
|
3522 |
-
|
3523 |
-
|
3524 |
-
|
3525 |
-
|
3526 |
-
|
3527 |
-
|
3528 |
-
|
3529 |
-
|
3530 |
-
|
3531 |
-
|
3532 |
-
|
3533 |
-
|
3534 |
-
|
3535 |
-
|
3536 |
-
|
3537 |
-
|
3538 |
-
|
3539 |
-
|
3540 |
-
|
3541 |
-
|
3542 |
-
|
3543 |
-
|
3544 |
-
|
3545 |
-
|
3546 |
-
|
3547 |
-
|
3548 |
-
|
3549 |
-
|
3550 |
-
|
3551 |
-
|
3552 |
-
|
3553 |
-
|
3554 |
-
|
3555 |
-
|
3556 |
-
|
3557 |
-
|
3558 |
-
|
3559 |
-
|
3560 |
-
|
3561 |
-
|
3562 |
-
|
3563 |
-
|
3564 |
-
|
3565 |
-
|
3566 |
-
|
3567 |
-
|
3568 |
-
|
3569 |
-
|
3570 |
-
|
3571 |
-
|
3572 |
-
|
3573 |
-
|
3574 |
-
|
3575 |
-
|
3576 |
-
|
3577 |
-
|
3578 |
-
|
3579 |
-
|
3580 |
-
|
3581 |
-
|
3582 |
-
|
3583 |
-
|
3584 |
-
|
3585 |
-
|
3586 |
-
|
3587 |
-
|
3588 |
-
|
3589 |
-
|
3590 |
-
|
3591 |
-
|
3592 |
-
|
3593 |
-
|
3594 |
-
|
3595 |
-
|
3596 |
-
|
3597 |
-
|
3598 |
-
|
3599 |
-
|
3600 |
-
|
3601 |
-
$
|
3602 |
-
|
3603 |
-
|
3604 |
-
|
3605 |
-
|
3606 |
-
|
3607 |
-
|
3608 |
-
|
3609 |
-
|
3610 |
-
$
|
3611 |
-
|
3612 |
-
|
3613 |
-
|
3614 |
-
|
3615 |
-
|
3616 |
-
|
3617 |
-
|
3618 |
-
|
3619 |
-
|
3620 |
-
|
3621 |
-
$
|
3622 |
-
|
3623 |
-
|
3624 |
-
|
3625 |
-
|
3626 |
-
|
3627 |
-
|
3628 |
-
|
3629 |
-
|
3630 |
-
|
3631 |
-
|
3632 |
-
|
3633 |
-
|
3634 |
-
<?php
|
3635 |
-
|
3636 |
-
|
3637 |
-
|
3638 |
-
|
3639 |
-
|
3640 |
-
|
3641 |
-
|
3642 |
-
|
3643 |
-
|
3644 |
-
|
3645 |
-
|
3646 |
-
$
|
3647 |
-
|
3648 |
-
|
3649 |
-
|
3650 |
-
|
3651 |
-
|
3652 |
-
|
3653 |
-
|
3654 |
-
|
3655 |
-
|
3656 |
-
|
3657 |
-
|
3658 |
-
|
3659 |
-
|
3660 |
-
|
3661 |
-
|
3662 |
-
|
3663 |
-
|
3664 |
-
|
3665 |
-
|
3666 |
-
|
3667 |
-
|
3668 |
-
|
3669 |
-
|
3670 |
-
|
3671 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Install/Activate/Deactivate/Remove Extensions
|
5 |
+
* @internal
|
6 |
+
*/
|
7 |
+
final class _FW_Extensions_Manager
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @var FW_Form
|
11 |
+
*/
|
12 |
+
private $extension_settings_form;
|
13 |
+
|
14 |
+
private $manifest_default_values = array(
|
15 |
+
'display' => false,
|
16 |
+
'standalone' => false,
|
17 |
+
);
|
18 |
+
|
19 |
+
private $default_thumbnail = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2PUsHf9DwAC8AGtfm5YCAAAAABJRU5ErkJgggAA';
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @var FW_Access_Key
|
23 |
+
*/
|
24 |
+
private static $access_key;
|
25 |
+
|
26 |
+
private static function get_access_key() {
|
27 |
+
if (!self::$access_key) {
|
28 |
+
self::$access_key = new FW_Access_Key('fw_ext_manager');
|
29 |
+
}
|
30 |
+
|
31 |
+
return self::$access_key;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function __construct()
|
35 |
+
{
|
36 |
+
// In any case/permission, make sure to not miss the plugin update actions to prevent extensions delete
|
37 |
+
{
|
38 |
+
add_action('fw_plugin_pre_update', array($this, '_action_plugin_pre_update'));
|
39 |
+
add_action('fw_plugin_post_update', array($this, '_action_plugin_post_update'));
|
40 |
+
}
|
41 |
+
|
42 |
+
// Preserve {theme}/framework-customizations/theme/available-extensions.php
|
43 |
+
{
|
44 |
+
add_filter('upgrader_pre_install', array($this, '_filter_theme_available_extensions_copy'), 999, 2);
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Must be executed after
|
48 |
+
* https://github.com/WordPress/WordPress/blob/4.6/wp-admin/includes/class-theme-upgrader.php#L204-L205
|
49 |
+
*/
|
50 |
+
add_action('upgrader_process_complete', array($this, '_action_theme_available_extensions_restore'), 999, 2);
|
51 |
+
}
|
52 |
+
|
53 |
+
add_action('fw_plugin_activate', array($this, '_action_plugin_activate_install_compatible_extensions'), 100);
|
54 |
+
add_action('fw_after_plugin_activate', array($this, '_action_after_plugin_activate'), 100);
|
55 |
+
add_action('after_switch_theme', array($this, '_action_theme_switch'));
|
56 |
+
|
57 |
+
if (!is_admin()) {
|
58 |
+
return;
|
59 |
+
}
|
60 |
+
|
61 |
+
if (!$this->can_activate() && !$this->can_install()) {
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
/** Actions */
|
66 |
+
{
|
67 |
+
add_action('fw_init', array($this, '_action_fw_init'));
|
68 |
+
add_action('admin_menu', array($this, '_action_admin_menu'));
|
69 |
+
add_action('network_admin_menu', array($this, '_action_admin_menu'));
|
70 |
+
add_action('admin_footer', array($this, '_action_admin_footer'));
|
71 |
+
add_action('admin_enqueue_scripts', array($this, '_action_enqueue_scripts'));
|
72 |
+
add_action('admin_notices', array($this, '_action_admin_notices'));
|
73 |
+
|
74 |
+
if ($this->can_install()) {
|
75 |
+
add_action('wp_ajax_fw_extensions_check_direct_fs_access', array($this, '_action_ajax_check_direct_fs_access'));
|
76 |
+
add_action('wp_ajax_fw_extensions_install', array($this, '_action_ajax_install'));
|
77 |
+
add_action('wp_ajax_fw_extensions_uninstall', array($this, '_action_ajax_uninstall'));
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/** Filters */
|
82 |
+
{
|
83 |
+
add_filter('fw_plugin_action_list', array($this, '_filter_plugin_action_list'));
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* If current user can:
|
89 |
+
* - activate extension
|
90 |
+
* - disable extensions
|
91 |
+
* - save extension settings options
|
92 |
+
* @return bool
|
93 |
+
*/
|
94 |
+
public function can_activate()
|
95 |
+
{
|
96 |
+
if ( fw_is_cli() ) {
|
97 |
+
return true;
|
98 |
+
}
|
99 |
+
|
100 |
+
$can_activate = current_user_can('manage_options');
|
101 |
+
|
102 |
+
if ($can_activate) {
|
103 |
+
// also you can use this method to get the capability
|
104 |
+
$can_activate = 'manage_options';
|
105 |
+
}
|
106 |
+
|
107 |
+
if (!$can_activate) {
|
108 |
+
// make sure if can install, then also can activate. (can install) > (can activate)
|
109 |
+
$can_activate = $this->can_install();
|
110 |
+
}
|
111 |
+
|
112 |
+
return $can_activate;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* If current user can:
|
117 |
+
* - install extensions
|
118 |
+
* - delete extensions
|
119 |
+
* @return bool
|
120 |
+
*/
|
121 |
+
public function can_install()
|
122 |
+
{
|
123 |
+
if ( fw_is_cli() ) {
|
124 |
+
return true;
|
125 |
+
}
|
126 |
+
|
127 |
+
$capability = 'install_plugins';
|
128 |
+
|
129 |
+
if (is_multisite()) {
|
130 |
+
// only network admin can change files that affects the entire network
|
131 |
+
$can_install = current_user_can_for_blog(get_current_blog_id(), $capability);
|
132 |
+
} else {
|
133 |
+
$can_install = current_user_can($capability);
|
134 |
+
}
|
135 |
+
|
136 |
+
if ($can_install) {
|
137 |
+
// also you can use this method to get the capability
|
138 |
+
$can_install = $capability;
|
139 |
+
}
|
140 |
+
|
141 |
+
return $can_install;
|
142 |
+
}
|
143 |
+
|
144 |
+
public function get_page_slug()
|
145 |
+
{
|
146 |
+
return 'fw-extensions';
|
147 |
+
}
|
148 |
+
|
149 |
+
private function get_cache_key($sub_key)
|
150 |
+
{
|
151 |
+
return 'fw_extensions_manager/'. $sub_key;
|
152 |
+
}
|
153 |
+
|
154 |
+
private function get_uri($append = '')
|
155 |
+
{
|
156 |
+
return fw_get_framework_directory_uri('/core/components/extensions/manager'. $append);
|
157 |
+
}
|
158 |
+
|
159 |
+
private function get_nonce($form) {
|
160 |
+
switch ($form) {
|
161 |
+
case 'install':
|
162 |
+
return array(
|
163 |
+
'name' => '_nonce_fw_extensions_install',
|
164 |
+
'action' => 'install',
|
165 |
+
);
|
166 |
+
case 'delete':
|
167 |
+
return array(
|
168 |
+
'name' => '_nonce_fw_extensions_delete',
|
169 |
+
'action' => 'delete',
|
170 |
+
);
|
171 |
+
case 'activate':
|
172 |
+
return array(
|
173 |
+
'name' => '_nonce_fw_extensions_activate',
|
174 |
+
'action' => 'activate',
|
175 |
+
);
|
176 |
+
case 'deactivate':
|
177 |
+
return array(
|
178 |
+
'name' => '_nonce_fw_extensions_deactivate',
|
179 |
+
'action' => 'deactivate',
|
180 |
+
);
|
181 |
+
default:
|
182 |
+
return array(
|
183 |
+
'name' => '_nonce_fw_extensions',
|
184 |
+
'action' => 'default',
|
185 |
+
);
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Extensions available for download
|
191 |
+
* @return array {name => data}
|
192 |
+
*
|
193 |
+
* @since 2.6.9
|
194 |
+
*/
|
195 |
+
public function get_available_extensions() {
|
196 |
+
try {
|
197 |
+
$cache_key = $this->get_cache_key( 'available_extensions' );
|
198 |
+
|
199 |
+
return FW_Cache::get( $cache_key );
|
200 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
201 |
+
$available = fw_get_variables_from_file( dirname( __FILE__ ) . '/available-extensions.php', array( 'extensions' => array() ) );
|
202 |
+
$available = $available['extensions'];
|
203 |
+
|
204 |
+
// Allow theme to register available extensions
|
205 |
+
$theme_available_ext_file = fw_fix_path( get_template_directory() ) . fw_get_framework_customizations_dir_rel_path( '/theme/available-extensions.php' );
|
206 |
+
|
207 |
+
if ( file_exists( $theme_available_ext_file ) ) {
|
208 |
+
|
209 |
+
$register = new _FW_Available_Extensions_Register( self::get_access_key()->get_key() );
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Usage: https://github.com/ThemeFuse/Unyson/issues/2900
|
213 |
+
* Create {theme}/framework-customizations/theme/available-extensions.php with the following contents:
|
214 |
+
* $extension = new FW_Available_Extension();
|
215 |
+
* $extension->set_...();
|
216 |
+
* $register->register($extension);
|
217 |
+
*/
|
218 |
+
$theme_exts = fw_get_variables_from_file( $theme_available_ext_file, array( 'extensions' => array() ), array( 'register' => $register ) );
|
219 |
+
$available = array_merge( $available, $theme_exts['extensions'] );
|
220 |
+
|
221 |
+
foreach ( $register->_get_types( self::$access_key ) as $extension ) {
|
222 |
+
/** @var FW_Available_Extension $extension */
|
223 |
+
if ( isset( $available[ $extension->get_name() ] ) ) {
|
224 |
+
trigger_error(
|
225 |
+
'Overwriting default extension "' . $extension->get_name() . '" is not allowed',
|
226 |
+
E_USER_WARNING
|
227 |
+
);
|
228 |
+
continue;
|
229 |
+
} elseif ( ! $extension->is_valid() ) {
|
230 |
+
trigger_error(
|
231 |
+
'Theme extension "' . $extension->get_name() . '" is not valid',
|
232 |
+
E_USER_WARNING
|
233 |
+
);
|
234 |
+
continue;
|
235 |
+
} else {
|
236 |
+
$available[ $extension->get_name() ] = array(
|
237 |
+
'theme' => true, // Registered by theme
|
238 |
+
'display' => $extension->get_display(),
|
239 |
+
'parent' => $extension->get_parent(),
|
240 |
+
'name' => $extension->get_title(),
|
241 |
+
'description' => $extension->get_description(),
|
242 |
+
'thumbnail' => $extension->get_thumbnail(),
|
243 |
+
'download' => $extension->get_download_source(),
|
244 |
+
);
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
{
|
250 |
+
$installed_extensions = $this->get_installed_extensions();
|
251 |
+
$supported_extensions = fw()->theme->manifest->get( 'supported_extensions', array() );
|
252 |
+
|
253 |
+
if ( isset( $installed_extensions['backup'] ) ) {
|
254 |
+
// make sure only Backup or Backups can be installed
|
255 |
+
unset( $available['backups'] );
|
256 |
+
}
|
257 |
+
|
258 |
+
foreach ( array( 'backup', 'styling', 'learning' ) as $obsolete_extension ) {
|
259 |
+
if (
|
260 |
+
! isset( $supported_extensions[ $obsolete_extension ] )
|
261 |
+
&&
|
262 |
+
! isset( $installed_extensions[ $obsolete_extension ] )
|
263 |
+
) {
|
264 |
+
unset( $available[ $obsolete_extension ] );
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
FW_Cache::set( $cache_key, $available );
|
270 |
+
|
271 |
+
return $available;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* @internal
|
277 |
+
*/
|
278 |
+
public function _action_ajax_check_direct_fs_access()
|
279 |
+
{
|
280 |
+
if (!$this->can_install()) {
|
281 |
+
// if can't install, no need to know if has access or not
|
282 |
+
wp_send_json_error();
|
283 |
+
}
|
284 |
+
|
285 |
+
if (FW_WP_Filesystem::has_direct_access(fw_get_framework_directory('/extensions'))) {
|
286 |
+
wp_send_json_success();
|
287 |
+
} else {
|
288 |
+
wp_send_json_error();
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* @internal
|
294 |
+
*/
|
295 |
+
public function _action_ajax_install()
|
296 |
+
{
|
297 |
+
if ( ! $this->can_install() ) {
|
298 |
+
// if can't install, no need to know if has access or not
|
299 |
+
wp_send_json_error();
|
300 |
+
}
|
301 |
+
|
302 |
+
if ( ! FW_WP_Filesystem::has_direct_access( fw_get_framework_directory( '/extensions' ) ) ) {
|
303 |
+
wp_send_json_error();
|
304 |
+
}
|
305 |
+
|
306 |
+
$extension = (string) FW_Request::POST( 'extension' );
|
307 |
+
|
308 |
+
$install_result = $this->install_extensions( array( $extension => array() ), array( 'cancel_on_error' => true ) );
|
309 |
+
|
310 |
+
if ( $install_result === true ) {
|
311 |
+
wp_send_json_success();
|
312 |
+
} else {
|
313 |
+
wp_send_json_error( $install_result );
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* @internal
|
319 |
+
*/
|
320 |
+
public function _action_ajax_uninstall()
|
321 |
+
{
|
322 |
+
if (!$this->can_install()) {
|
323 |
+
// if can't install, no need to know if has access or not
|
324 |
+
wp_send_json_error();
|
325 |
+
}
|
326 |
+
|
327 |
+
if (!FW_WP_Filesystem::has_direct_access(fw_get_framework_directory('/extensions'))) {
|
328 |
+
wp_send_json_error();
|
329 |
+
}
|
330 |
+
|
331 |
+
$extension = (string)FW_Request::POST('extension');
|
332 |
+
|
333 |
+
$install_result = $this->uninstall_extensions(array(
|
334 |
+
$extension => array()
|
335 |
+
), array(
|
336 |
+
'cancel_on_error' => true
|
337 |
+
));
|
338 |
+
|
339 |
+
if ($install_result === true) {
|
340 |
+
wp_send_json_success();
|
341 |
+
} else {
|
342 |
+
wp_send_json_error($install_result);
|
343 |
+
}
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* @internal
|
348 |
+
*/
|
349 |
+
public function _action_after_plugin_activate()
|
350 |
+
{
|
351 |
+
$this->activate_theme_extensions();
|
352 |
+
$this->activate_extensions(
|
353 |
+
array_fill_keys(
|
354 |
+
array_keys(fw()->theme->manifest->get('supported_extensions', array())),
|
355 |
+
array()
|
356 |
+
)
|
357 |
+
);
|
358 |
+
|
359 |
+
do_action('fw_after_plugin_activate:before_potential_redirect');
|
360 |
+
|
361 |
+
if (is_admin() && $this->can_install() && $this->get_supported_extensions_for_install()) {
|
362 |
+
wp_redirect($this->get_link() . '&sub-page=install&supported');
|
363 |
+
exit;
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Copy all extensions to a temp backup directory
|
369 |
+
* @internal
|
370 |
+
*/
|
371 |
+
public function _action_plugin_pre_update()
|
372 |
+
{
|
373 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
374 |
+
global $wp_filesystem;
|
375 |
+
|
376 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
377 |
+
return;
|
378 |
+
}
|
379 |
+
|
380 |
+
// a directory outside the plugin
|
381 |
+
$tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
382 |
+
fw_fix_path(WP_CONTENT_DIR) .'/tmp/fw-plugin-update-extensions-backup'
|
383 |
+
);
|
384 |
+
$extensions_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
385 |
+
fw_get_framework_directory('/extensions')
|
386 |
+
);
|
387 |
+
|
388 |
+
$error = false;
|
389 |
+
|
390 |
+
do {
|
391 |
+
if ($wp_filesystem->exists($tmp_dir)) {
|
392 |
+
if (!$wp_filesystem->delete($tmp_dir, true, 'd')) {
|
393 |
+
$error = __('Cannot remove the old extensions backup dir', 'fw');
|
394 |
+
break;
|
395 |
+
}
|
396 |
+
}
|
397 |
+
|
398 |
+
if (!FW_WP_Filesystem::mkdir_recursive($tmp_dir)) {
|
399 |
+
$error = __('Cannot create the extensions backup dir', 'fw');
|
400 |
+
break;
|
401 |
+
}
|
402 |
+
|
403 |
+
if (true !== copy_dir($extensions_dir, $tmp_dir)) {
|
404 |
+
$error = __('Cannot backup the extensions', 'fw');
|
405 |
+
break;
|
406 |
+
}
|
407 |
+
} while(false);
|
408 |
+
|
409 |
+
if ($error) {
|
410 |
+
trigger_error($error, E_USER_WARNING);
|
411 |
+
|
412 |
+
$wp_filesystem->delete($tmp_dir, true, 'd');
|
413 |
+
}
|
414 |
+
}
|
415 |
+
|
416 |
+
/**
|
417 |
+
* Copy all extensions from the temp backup directory to the framework extensions directory (recover)
|
418 |
+
* @internal
|
419 |
+
*/
|
420 |
+
public function _action_plugin_post_update()
|
421 |
+
{
|
422 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
423 |
+
global $wp_filesystem;
|
424 |
+
|
425 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
426 |
+
return;
|
427 |
+
}
|
428 |
+
|
429 |
+
// a directory outside the plugin
|
430 |
+
$tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
431 |
+
fw_fix_path( WP_CONTENT_DIR ) .'/tmp/fw-plugin-update-extensions-backup'
|
432 |
+
);
|
433 |
+
$extensions_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
434 |
+
fw_get_framework_directory( '/extensions' )
|
435 |
+
);
|
436 |
+
|
437 |
+
if (!$wp_filesystem->exists($tmp_dir) || !$wp_filesystem->exists($extensions_dir)) {
|
438 |
+
return;
|
439 |
+
}
|
440 |
+
|
441 |
+
$error = false;
|
442 |
+
|
443 |
+
do {
|
444 |
+
if ($wp_filesystem->exists($extensions_dir)) {
|
445 |
+
/**
|
446 |
+
* Make sure to remove framework initial extensions
|
447 |
+
* The user do not need them because he already used the framework and has in backup the extensions he uses
|
448 |
+
*/
|
449 |
+
if (!$wp_filesystem->delete( $extensions_dir, true, 'd' )) {
|
450 |
+
$error = __( 'Cannot clear the extensions directory', 'fw' );
|
451 |
+
break;
|
452 |
+
}
|
453 |
+
|
454 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $extensions_dir ) ) {
|
455 |
+
$error = __( 'Cannot recreate the extensions directory', 'fw' );
|
456 |
+
break;
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
if (true !== copy_dir($tmp_dir, $extensions_dir)) {
|
461 |
+
$error = __('Cannot recover the extensions', 'fw');
|
462 |
+
break;
|
463 |
+
}
|
464 |
+
} while(false);
|
465 |
+
|
466 |
+
if ($error) {
|
467 |
+
trigger_error($error, E_USER_WARNING);
|
468 |
+
} else {
|
469 |
+
// extensions successfully recovered, the backup is not needed anymore
|
470 |
+
$wp_filesystem->delete($tmp_dir, true, 'd');
|
471 |
+
}
|
472 |
+
}
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Scan all directories for extensions
|
476 |
+
*
|
477 |
+
* @param bool $reset_cache
|
478 |
+
* @return array
|
479 |
+
*
|
480 |
+
* @since 2.6.9
|
481 |
+
*/
|
482 |
+
public function get_installed_extensions($reset_cache = false)
|
483 |
+
{
|
484 |
+
$cache_key = $this->get_cache_key('installed_extensions');
|
485 |
+
|
486 |
+
if ($reset_cache) {
|
487 |
+
FW_Cache::del($cache_key);
|
488 |
+
}
|
489 |
+
|
490 |
+
try {
|
491 |
+
return FW_Cache::get($cache_key);
|
492 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
493 |
+
$extensions = array();
|
494 |
+
|
495 |
+
foreach (fw()->extensions->get_locations() as $location) {
|
496 |
+
// leave only used keys
|
497 |
+
$location = array(
|
498 |
+
'path' => $location['path'],
|
499 |
+
'is' => $location['is'],
|
500 |
+
);
|
501 |
+
|
502 |
+
$this->read_extensions($location, $extensions);
|
503 |
+
}
|
504 |
+
|
505 |
+
FW_Cache::set($cache_key, $extensions);
|
506 |
+
|
507 |
+
return $extensions;
|
508 |
+
}
|
509 |
+
}
|
510 |
+
|
511 |
+
/**
|
512 |
+
* used by $this->get_installed_extensions()
|
513 |
+
* @param string $location
|
514 |
+
* @param array $list
|
515 |
+
* @param null|string $parent_extension_name
|
516 |
+
*/
|
517 |
+
private function read_extensions($location, &$list, $parent_extension_name = null)
|
518 |
+
{
|
519 |
+
$paths = glob($location['path'] .'/*', GLOB_ONLYDIR | GLOB_NOSORT);
|
520 |
+
|
521 |
+
if (empty($paths)) {
|
522 |
+
return;
|
523 |
+
}
|
524 |
+
|
525 |
+
foreach ($paths as $extension_path) {
|
526 |
+
$extension_name = basename($extension_path);
|
527 |
+
|
528 |
+
if (isset($list[$extension_name])) {
|
529 |
+
// extension already found
|
530 |
+
} elseif (file_exists($extension_path .'/manifest.php')) {
|
531 |
+
$vars = fw_get_variables_from_file($extension_path .'/manifest.php', array(
|
532 |
+
'manifest' => array(),
|
533 |
+
));
|
534 |
+
|
535 |
+
$list[$extension_name] = array(
|
536 |
+
'path' => $extension_path,
|
537 |
+
'manifest' => $vars['manifest'],
|
538 |
+
'children' => array(),
|
539 |
+
'active' => (bool)fw()->extensions->get($extension_name),
|
540 |
+
'parent' => $parent_extension_name,
|
541 |
+
'is' => $location['is'],
|
542 |
+
);
|
543 |
+
|
544 |
+
if ($parent_extension_name) {
|
545 |
+
$list[ $parent_extension_name ]['children'][$extension_name] = array();
|
546 |
+
}
|
547 |
+
} else {
|
548 |
+
// it's a directory with customizations for an extension
|
549 |
+
continue;
|
550 |
+
}
|
551 |
+
|
552 |
+
$sub_extension_location = $location;
|
553 |
+
$sub_extension_location['path'] .= '/'. $extension_name .'/extensions';
|
554 |
+
|
555 |
+
$this->read_extensions(
|
556 |
+
$sub_extension_location,
|
557 |
+
$list,
|
558 |
+
$extension_name
|
559 |
+
);
|
560 |
+
}
|
561 |
+
}
|
562 |
+
|
563 |
+
private function get_tmp_dir($append = '')
|
564 |
+
{
|
565 |
+
return apply_filters('fw_tmp_dir', fw_fix_path(WP_CONTENT_DIR) .'/tmp') . $append;
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* @internal
|
570 |
+
*/
|
571 |
+
public function _action_fw_init()
|
572 |
+
{
|
573 |
+
$this->extension_settings_form = new FW_Form('fw_extension_settings', array(
|
574 |
+
'render' => array($this, '_extension_settings_form_render'),
|
575 |
+
'validate' => array($this, '_extension_settings_form_validate'),
|
576 |
+
'save' => array($this, '_extension_settings_form_save'),
|
577 |
+
));
|
578 |
+
|
579 |
+
if (is_admin() && $this->can_activate()) {
|
580 |
+
$db_wp_option_name = 'fw_extensions_activation';
|
581 |
+
|
582 |
+
if ($db_wp_option_value = get_option($db_wp_option_name, array())) {
|
583 |
+
$db_wp_option_value = array_merge(array(
|
584 |
+
'activated' => array(),
|
585 |
+
'deactivated' => array(),
|
586 |
+
), $db_wp_option_value);
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Fire the 'fw_extensions_after_activation' action
|
590 |
+
*/
|
591 |
+
if ($db_wp_option_value['activated']) {
|
592 |
+
$succeeded_extensions = $failed_extensions = array();
|
593 |
+
|
594 |
+
foreach ($db_wp_option_value['activated'] as $extension_name => $not_used_var) {
|
595 |
+
if (fw_ext($extension_name)) {
|
596 |
+
$succeeded_extensions[$extension_name] = array();
|
597 |
+
} else {
|
598 |
+
$failed_extensions[$extension_name] = array();
|
599 |
+
}
|
600 |
+
}
|
601 |
+
|
602 |
+
if (!empty($succeeded_extensions)) {
|
603 |
+
do_action('fw_extensions_after_activation', $succeeded_extensions);
|
604 |
+
}
|
605 |
+
if (!empty($failed_extensions)) {
|
606 |
+
do_action('fw_extensions_activation_failed', $failed_extensions);
|
607 |
+
}
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Fire the 'fw_extensions_after_deactivation' action
|
612 |
+
*/
|
613 |
+
if ($db_wp_option_value['deactivated']) {
|
614 |
+
$succeeded_extensions = $failed_extensions = array();
|
615 |
+
|
616 |
+
foreach ($db_wp_option_value['deactivated'] as $extension_name => $not_used_var) {
|
617 |
+
if (!fw_ext($extension_name)) {
|
618 |
+
$succeeded_extensions[$extension_name] = array();
|
619 |
+
} else {
|
620 |
+
$failed_extensions[$extension_name] = array();
|
621 |
+
}
|
622 |
+
}
|
623 |
+
|
624 |
+
if (!empty($succeeded_extensions)) {
|
625 |
+
do_action('fw_extensions_after_deactivation', $succeeded_extensions);
|
626 |
+
}
|
627 |
+
if (!empty($failed_extensions)) {
|
628 |
+
do_action('fw_extensions_deactivation_failed', $failed_extensions);
|
629 |
+
}
|
630 |
+
}
|
631 |
+
|
632 |
+
delete_option($db_wp_option_name);
|
633 |
+
}
|
634 |
+
}
|
635 |
+
}
|
636 |
+
|
637 |
+
/**
|
638 |
+
* Activate extensions with $manifest['display'] = false; $manifest['standalone'] = true;
|
639 |
+
* - First level extensions
|
640 |
+
* - Child extensions of the active extensions
|
641 |
+
*/
|
642 |
+
private function activate_hidden_standalone_extensions()
|
643 |
+
{
|
644 |
+
if (!is_admin()) {
|
645 |
+
return;
|
646 |
+
}
|
647 |
+
|
648 |
+
if (!$this->can_activate()) {
|
649 |
+
return;
|
650 |
+
}
|
651 |
+
|
652 |
+
$activate_extensions = array();
|
653 |
+
|
654 |
+
foreach (
|
655 |
+
// all disabled extensions
|
656 |
+
array_diff_key($this->get_installed_extensions(), fw()->extensions->get_all())
|
657 |
+
as $ext_name => $ext_data
|
658 |
+
) {
|
659 |
+
if ($ext_data['parent'] && !fw_ext($ext_data['parent'])) {
|
660 |
+
// child extensions of an inactive extension
|
661 |
+
continue;
|
662 |
+
}
|
663 |
+
|
664 |
+
if (false !== fw_akg(
|
665 |
+
'display',
|
666 |
+
$ext_data['manifest'],
|
667 |
+
$this->manifest_default_values['display']
|
668 |
+
)) {
|
669 |
+
// is visible
|
670 |
+
continue;
|
671 |
+
}
|
672 |
+
|
673 |
+
if (true !== fw_akg(
|
674 |
+
'standalone',
|
675 |
+
$ext_data['manifest'],
|
676 |
+
$this->manifest_default_values['standalone']
|
677 |
+
)) {
|
678 |
+
// not standalone
|
679 |
+
continue;
|
680 |
+
}
|
681 |
+
|
682 |
+
$collected = $this->get_extensions_for_activation($ext_name);
|
683 |
+
|
684 |
+
if (is_wp_error($collected)) {
|
685 |
+
if (defined('WP_DEBUG') && WP_DEBUG) {
|
686 |
+
if ($this->is_extensions_page()) {
|
687 |
+
// display this warning only on Unyson extensions page
|
688 |
+
FW_Flash_Messages::add('fw_ext_auto_activate_hidden_standalone',
|
689 |
+
sprintf(__('Cannot activate hidden standalone extension %s', 'fw'),
|
690 |
+
fw_akg('name', $ext_data['manifest'], fw_id_to_title($ext_name))
|
691 |
+
),
|
692 |
+
'error'
|
693 |
+
);
|
694 |
+
}
|
695 |
+
}
|
696 |
+
return;
|
697 |
+
}
|
698 |
+
|
699 |
+
$activate_extensions = array_merge($activate_extensions, $collected);
|
700 |
+
}
|
701 |
+
|
702 |
+
if (empty($activate_extensions)) {
|
703 |
+
return;
|
704 |
+
}
|
705 |
+
|
706 |
+
$option_name = fw()->extensions->_get_active_extensions_db_option_name();
|
707 |
+
|
708 |
+
$db_active_extensions = array_merge(get_option($option_name, array()), $activate_extensions);
|
709 |
+
|
710 |
+
update_option($option_name, $db_active_extensions);
|
711 |
+
}
|
712 |
+
|
713 |
+
/**
|
714 |
+
* @internal
|
715 |
+
*/
|
716 |
+
public function _action_admin_menu()
|
717 |
+
{
|
718 |
+
$capability = $this->can_activate();
|
719 |
+
|
720 |
+
if (!$capability) {
|
721 |
+
return;
|
722 |
+
}
|
723 |
+
|
724 |
+
$data = array(
|
725 |
+
'title' => fw()->manifest->get_name(),
|
726 |
+
'capability' => $capability,
|
727 |
+
'slug' => $this->get_page_slug(),
|
728 |
+
'content_callback' => array($this, '_display_page'),
|
729 |
+
);
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Collect $hookname that contains $data['slug'] before the action
|
733 |
+
* and skip them in verification after action
|
734 |
+
*/
|
735 |
+
{
|
736 |
+
global $_registered_pages;
|
737 |
+
|
738 |
+
$found_hooknames = array();
|
739 |
+
|
740 |
+
if (!empty($_registered_pages)) {
|
741 |
+
foreach ( $_registered_pages as $hookname => $b ) {
|
742 |
+
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
743 |
+
$found_hooknames[$hookname] = true;
|
744 |
+
}
|
745 |
+
}
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
/**
|
750 |
+
* Use this action if you what to add the extensions page in a custom place in menu
|
751 |
+
* Usage example http://pastebin.com/2iWVRPAU
|
752 |
+
*/
|
753 |
+
do_action('fw_backend_add_custom_extensions_menu', $data);
|
754 |
+
|
755 |
+
/**
|
756 |
+
* Check if menu was added in the action above
|
757 |
+
*/
|
758 |
+
{
|
759 |
+
$menu_exists = false;
|
760 |
+
|
761 |
+
if (!empty($_registered_pages)) {
|
762 |
+
foreach ( $_registered_pages as $hookname => $b ) {
|
763 |
+
if (isset($found_hooknames[$hookname])) {
|
764 |
+
continue;
|
765 |
+
}
|
766 |
+
|
767 |
+
if ( strpos( $hookname, $data['slug'] ) !== false ) {
|
768 |
+
$menu_exists = true;
|
769 |
+
break;
|
770 |
+
}
|
771 |
+
}
|
772 |
+
}
|
773 |
+
}
|
774 |
+
|
775 |
+
if ($menu_exists) {
|
776 |
+
// do nothing
|
777 |
+
} else {
|
778 |
+
add_menu_page(
|
779 |
+
$data['title'],
|
780 |
+
$data['title'],
|
781 |
+
$data['capability'],
|
782 |
+
$data['slug'],
|
783 |
+
$data['content_callback'],
|
784 |
+
'none',
|
785 |
+
3
|
786 |
+
);
|
787 |
+
}
|
788 |
+
}
|
789 |
+
|
790 |
+
/**
|
791 |
+
* If output already started, we cannot set the redirect header, do redirect from js
|
792 |
+
*/
|
793 |
+
private function js_redirect()
|
794 |
+
{
|
795 |
+
echo
|
796 |
+
'<script type="text/javascript">'.
|
797 |
+
'window.location.replace("'. esc_js($this->get_link()) .'");'.
|
798 |
+
'</script>';
|
799 |
+
}
|
800 |
+
|
801 |
+
/**
|
802 |
+
* @internal
|
803 |
+
*/
|
804 |
+
public function _display_page()
|
805 |
+
{
|
806 |
+
$page = FW_Request::GET('sub-page');
|
807 |
+
|
808 |
+
switch ($page) {
|
809 |
+
case 'install':
|
810 |
+
$this->display_install_page();
|
811 |
+
break;
|
812 |
+
case 'delete':
|
813 |
+
$this->display_delete_page();
|
814 |
+
break;
|
815 |
+
case 'extension':
|
816 |
+
$this->display_extension_page();
|
817 |
+
break;
|
818 |
+
case 'activate':
|
819 |
+
$this->display_activate_page();
|
820 |
+
break;
|
821 |
+
case 'deactivate':
|
822 |
+
$this->display_deactivate_page();
|
823 |
+
break;
|
824 |
+
default:
|
825 |
+
$this->display_list_page();
|
826 |
+
}
|
827 |
+
}
|
828 |
+
|
829 |
+
private function display_list_page()
|
830 |
+
{
|
831 |
+
// note: static is enqueued in 'admin_enqueue_scripts' action
|
832 |
+
|
833 |
+
/** Prepare extensions list for view */
|
834 |
+
{
|
835 |
+
$lists = array(
|
836 |
+
'active' => array(),
|
837 |
+
'disabled' => array(),
|
838 |
+
'installed' => array(),
|
839 |
+
'available' => array(),
|
840 |
+
'supported' => array(),
|
841 |
+
);
|
842 |
+
|
843 |
+
foreach ($this->get_installed_extensions() as $ext_name => $ext_data) {
|
844 |
+
$lists[ $ext_data['active'] ? 'active' : 'disabled' ][$ext_name] = $ext_data;
|
845 |
+
}
|
846 |
+
|
847 |
+
$lists['installed'] = $lists['active'] + $lists['disabled'];
|
848 |
+
|
849 |
+
unset($ext_data); // prevent change by reference
|
850 |
+
|
851 |
+
foreach ($this->get_available_extensions() as $ext_name => $ext_data) {
|
852 |
+
$lists['available'][$ext_name] = array(
|
853 |
+
'name' => $ext_data['name'],
|
854 |
+
'description' => $ext_data['description'],
|
855 |
+
'thumbnail' => isset($ext_data['thumbnail'])
|
856 |
+
? $ext_data['thumbnail']
|
857 |
+
: (isset($lists['installed'][$ext_name])
|
858 |
+
? fw_akg('thumbnail', $lists['installed'][$ext_name]['manifest'], $this->default_thumbnail)
|
859 |
+
: $this->default_thumbnail),
|
860 |
+
'display' => isset($ext_data['display'])
|
861 |
+
? $ext_data['display']
|
862 |
+
: $this->manifest_default_values['display'],
|
863 |
+
'theme' => isset($ext_data['theme']) && $ext_data['theme'],
|
864 |
+
'download' => isset( $ext_data['download'] ) ? $ext_data['download'] : array()
|
865 |
+
);
|
866 |
+
|
867 |
+
if ($lists['available'][$ext_name]['theme']) {
|
868 |
+
$lists['supported'][$ext_name] = array(
|
869 |
+
'name' => $lists['available'][$ext_name]['name'],
|
870 |
+
'description' => $lists['available'][$ext_name]['description'],
|
871 |
+
);
|
872 |
+
}
|
873 |
+
}
|
874 |
+
|
875 |
+
foreach (fw()->theme->manifest->get('supported_extensions', array()) as $required_ext_name => $required_ext_data) {
|
876 |
+
if (isset($lists['installed'][ $required_ext_name ])) {
|
877 |
+
$lists['supported'][ $required_ext_name ] = array(
|
878 |
+
'name' => fw_akg( 'name', $lists['installed'][ $required_ext_name ]['manifest'], fw_id_to_title( $required_ext_name ) ),
|
879 |
+
'description' => fw_akg( 'description', $lists['installed'][ $required_ext_name ]['manifest'], '' ),
|
880 |
+
);
|
881 |
+
} elseif (isset($lists['available'][$required_ext_name])) {
|
882 |
+
$lists['supported'][ $required_ext_name ] = array(
|
883 |
+
'name' => $lists['available'][ $required_ext_name ]['name'],
|
884 |
+
'description' => $lists['available'][ $required_ext_name ]['description'],
|
885 |
+
);
|
886 |
+
} else {
|
887 |
+
$lists['supported'][ $required_ext_name ] = array(
|
888 |
+
'name' => fw_id_to_title( $required_ext_name ),
|
889 |
+
'description' => '',
|
890 |
+
);
|
891 |
+
}
|
892 |
+
}
|
893 |
+
}
|
894 |
+
|
895 |
+
echo '<div class="wrap">';
|
896 |
+
|
897 |
+
echo '<h2>'. sprintf(__('%s Extensions', 'fw'), fw()->manifest->get_name()) .'</h2><br/>';
|
898 |
+
|
899 |
+
echo '<div id="fw-extensions-list-wrapper">';
|
900 |
+
|
901 |
+
fw_render_view(dirname(__FILE__) .'/views/extensions-page.php', array(
|
902 |
+
'lists' => &$lists,
|
903 |
+
'link' => $this->get_link(),
|
904 |
+
'display_default_value' => $this->manifest_default_values['display'],
|
905 |
+
'default_thumbnail' => $this->default_thumbnail,
|
906 |
+
'nonces' => array(
|
907 |
+
'delete' => $this->get_nonce('delete'),
|
908 |
+
'install' => $this->get_nonce('install'),
|
909 |
+
'activate' => $this->get_nonce('activate'),
|
910 |
+
'deactivate' => $this->get_nonce('deactivate'),
|
911 |
+
),
|
912 |
+
'can_install' => $this->can_install(),
|
913 |
+
), false);
|
914 |
+
|
915 |
+
echo '</div>';
|
916 |
+
|
917 |
+
echo '</div>';
|
918 |
+
}
|
919 |
+
|
920 |
+
private function display_install_page()
|
921 |
+
{
|
922 |
+
$flash_id = 'fw_extensions_install';
|
923 |
+
|
924 |
+
if (!$this->can_install()) {
|
925 |
+
FW_Flash_Messages::add(
|
926 |
+
$flash_id,
|
927 |
+
__('You are not allowed to install extensions.', 'fw'),
|
928 |
+
'error'
|
929 |
+
);
|
930 |
+
$this->js_redirect();
|
931 |
+
return;
|
932 |
+
}
|
933 |
+
|
934 |
+
if (array_key_exists('supported', $_GET)) {
|
935 |
+
$supported = true;
|
936 |
+
$extensions = array_fill_keys(
|
937 |
+
array_keys($this->get_supported_extensions_for_install()),
|
938 |
+
array()
|
939 |
+
);
|
940 |
+
|
941 |
+
if (empty($extensions)) {
|
942 |
+
FW_Flash_Messages::add(
|
943 |
+
$flash_id,
|
944 |
+
__('All supported extensions are already installed.', 'fw'),
|
945 |
+
'info'
|
946 |
+
);
|
947 |
+
$this->js_redirect();
|
948 |
+
return;
|
949 |
+
}
|
950 |
+
} else {
|
951 |
+
$supported = false;
|
952 |
+
|
953 |
+
$extensions = array_fill_keys(
|
954 |
+
array_map( 'trim', explode( ',', FW_Request::GET( 'extension', '' ) )),
|
955 |
+
array()
|
956 |
+
);
|
957 |
+
|
958 |
+
// activate already installed extensions
|
959 |
+
$this->activate_extensions($extensions);
|
960 |
+
}
|
961 |
+
|
962 |
+
{
|
963 |
+
$skin = new _FW_Extensions_Install_Upgrader_Skin(array(
|
964 |
+
'title' => $supported
|
965 |
+
? _n('Install Compatible Extension', 'Install Compatible Extensions', count($extensions), 'fw')
|
966 |
+
: _n('Install Extension', 'Install Extensions', count($extensions), 'fw'),
|
967 |
+
));
|
968 |
+
}
|
969 |
+
|
970 |
+
$skin->header();
|
971 |
+
|
972 |
+
do {
|
973 |
+
$nonce = $this->get_nonce('install');
|
974 |
+
|
975 |
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
976 |
+
if (!isset($_POST[$nonce['name']]) || !wp_verify_nonce($_POST[$nonce['name']], $nonce['action'])) {
|
977 |
+
$skin->error(__('Invalid nonce.', 'fw'));
|
978 |
+
break;
|
979 |
+
}
|
980 |
+
|
981 |
+
if (!FW_WP_Filesystem::request_access(
|
982 |
+
fw_get_framework_directory('/extensions'), fw_current_url(), array($nonce['name'])
|
983 |
+
)) {
|
984 |
+
break;
|
985 |
+
}
|
986 |
+
|
987 |
+
$install_result = $this->install_extensions($extensions, array('verbose' => $skin));
|
988 |
+
|
989 |
+
if (is_wp_error($install_result)) {
|
990 |
+
$skin->error($install_result);
|
991 |
+
} elseif (is_array($install_result)) {
|
992 |
+
$error = array();
|
993 |
+
|
994 |
+
foreach ($install_result as $extension_name => $extension_result) {
|
995 |
+
if (is_wp_error($extension_result)) {
|
996 |
+
$error[] = $extension_result->get_error_message();
|
997 |
+
}
|
998 |
+
}
|
999 |
+
|
1000 |
+
$error = '<ul><li>'. implode('</li><li>', $error) .'</li></ul>';
|
1001 |
+
|
1002 |
+
$skin->error($error);
|
1003 |
+
} elseif ($install_result === true) {
|
1004 |
+
$skin->set_result(true);
|
1005 |
+
}
|
1006 |
+
|
1007 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
1008 |
+
global $wp_filesystem;
|
1009 |
+
|
1010 |
+
$wp_fs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path($this->get_tmp_dir());
|
1011 |
+
|
1012 |
+
if ($wp_filesystem->exists($wp_fs_tmp_dir)) {
|
1013 |
+
if ( ! $wp_filesystem->rmdir( $wp_fs_tmp_dir, true ) ) {
|
1014 |
+
$skin->error(
|
1015 |
+
sprintf( __( 'Cannot remove temporary directory: %s', 'fw' ), $wp_fs_tmp_dir )
|
1016 |
+
);
|
1017 |
+
}
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
$skin->after(array(
|
1021 |
+
'extensions_page_link' => $this->get_link()
|
1022 |
+
));
|
1023 |
+
|
1024 |
+
if ($supported && $install_result === true) {
|
1025 |
+
/**
|
1026 |
+
* @since 2.6.14
|
1027 |
+
* Fixes https://github.com/ThemeFuse/Unyson/issues/2330
|
1028 |
+
*/
|
1029 |
+
do_action( 'fw_after_supported_extensions_install_success' );
|
1030 |
+
}
|
1031 |
+
} else {
|
1032 |
+
echo '<form method="post">';
|
1033 |
+
|
1034 |
+
wp_nonce_field($nonce['action'], $nonce['name']);
|
1035 |
+
|
1036 |
+
$extension_titles = array();
|
1037 |
+
foreach ($extensions as $extension_name => $not_used_var) {
|
1038 |
+
$extension_titles[$extension_name] = $this->get_extension_title($extension_name);
|
1039 |
+
}
|
1040 |
+
|
1041 |
+
fw_render_view(dirname(__FILE__) .'/views/install-form.php', array(
|
1042 |
+
'extension_titles' => $extension_titles,
|
1043 |
+
'list_page_link' => $this->get_link(),
|
1044 |
+
'supported' => $supported
|
1045 |
+
), false);
|
1046 |
+
|
1047 |
+
echo '</form>';
|
1048 |
+
}
|
1049 |
+
} while(false);
|
1050 |
+
|
1051 |
+
$skin->footer();
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* Download (and activate) extensions
|
1056 |
+
* After refresh they should be active, if all dependencies will be met and if parent-extension::_init() will not return false
|
1057 |
+
* @param array $extensions {'ext_1' => array(), 'ext_2' => array(), ...}
|
1058 |
+
* @param array $opts
|
1059 |
+
* @return WP_Error|bool|array
|
1060 |
+
* true: when all extensions succeeded
|
1061 |
+
* array: when some/all failed
|
1062 |
+
*/
|
1063 |
+
public function install_extensions( array $extensions, $opts = array() ) {
|
1064 |
+
{
|
1065 |
+
$opts = array_merge( array(
|
1066 |
+
/**
|
1067 |
+
* @type bool
|
1068 |
+
* false: return {'ext_1' => true|WP_Error, 'ext_2' => true|WP_Error, ...}
|
1069 |
+
* true: return first WP_Error or true on success
|
1070 |
+
*/
|
1071 |
+
'cancel_on_error' => false,
|
1072 |
+
/**
|
1073 |
+
* @type bool Activate installed extensions
|
1074 |
+
*/
|
1075 |
+
'activate' => true,
|
1076 |
+
/**
|
1077 |
+
* @type bool|WP_Upgrader_Skin
|
1078 |
+
*/
|
1079 |
+
'verbose' => false,
|
1080 |
+
), $opts );
|
1081 |
+
|
1082 |
+
$cancel_on_error = $opts['cancel_on_error']; // fixme: remove successfully installed extensions before error?
|
1083 |
+
$activate = $opts['activate'];
|
1084 |
+
$verbose = $opts['verbose'];
|
1085 |
+
|
1086 |
+
unset( $opts );
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
if ( ! $this->can_install() ) {
|
1090 |
+
return new WP_Error(
|
1091 |
+
'access_denied',
|
1092 |
+
__( 'You have no permissions to install extensions', 'fw' )
|
1093 |
+
);
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
if ( empty( $extensions ) ) {
|
1097 |
+
return new WP_Error(
|
1098 |
+
'no_extensions',
|
1099 |
+
__( 'No extensions provided', 'fw' )
|
1100 |
+
);
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
if ( ! FW_WP_Filesystem::is_ready() ) {
|
1104 |
+
return new WP_Error( 'fs_not_initialized', esc_html__( 'WP Filesystem is not initialized', 'fw' ) );
|
1105 |
+
}
|
1106 |
+
|
1107 |
+
$timeout = function_exists( 'ini_get' ) ? intval( ini_get( 'max_execution_time' ) ) : false;
|
1108 |
+
$available_extensions = $this->get_available_extensions();
|
1109 |
+
$installed_extensions = $this->get_installed_extensions();
|
1110 |
+
$result = $downloaded_extensions = array();
|
1111 |
+
$has_errors = false;
|
1112 |
+
|
1113 |
+
while ( ! empty( $extensions ) ) {
|
1114 |
+
reset( $extensions );
|
1115 |
+
$extension_name = key( $extensions );
|
1116 |
+
unset( $extensions[ $extension_name ] );
|
1117 |
+
|
1118 |
+
$extensions_before_install = array_keys( $installed_extensions );
|
1119 |
+
|
1120 |
+
if ( isset( $installed_extensions[ $extension_name ] ) ) {
|
1121 |
+
$result[ $extension_name ] = new WP_Error(
|
1122 |
+
'extension_installed',
|
1123 |
+
sprintf( __( 'Extension "%s" is already installed.', 'fw' ), $this->get_extension_title( $extension_name ) )
|
1124 |
+
);
|
1125 |
+
$has_errors = true;
|
1126 |
+
|
1127 |
+
if ( $cancel_on_error ) {
|
1128 |
+
break;
|
1129 |
+
}
|
1130 |
+
}
|
1131 |
+
|
1132 |
+
if ( ! isset( $available_extensions[ $extension_name ] ) ) {
|
1133 |
+
$result[ $extension_name ] = new WP_Error(
|
1134 |
+
'extension_not_available',
|
1135 |
+
sprintf(
|
1136 |
+
__( 'Extension "%s" is not available for install.', 'fw' ),
|
1137 |
+
$this->get_extension_title( $extension_name )
|
1138 |
+
)
|
1139 |
+
);
|
1140 |
+
$has_errors = true;
|
1141 |
+
|
1142 |
+
if ( $cancel_on_error ) {
|
1143 |
+
break;
|
1144 |
+
}
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
/**
|
1148 |
+
* Find parent extensions
|
1149 |
+
* they will be installed if does not exist
|
1150 |
+
*/
|
1151 |
+
{
|
1152 |
+
$parents = array( $extension_name );
|
1153 |
+
|
1154 |
+
$current_parent = $extension_name;
|
1155 |
+
while ( ! empty( $available_extensions[ $current_parent ]['parent'] ) ) {
|
1156 |
+
$current_parent = $available_extensions[ $current_parent ]['parent'];
|
1157 |
+
|
1158 |
+
if ( ! isset( $available_extensions[ $current_parent ] ) ) {
|
1159 |
+
$result[ $extension_name ] = new WP_Error(
|
1160 |
+
'parent_extension_not_available',
|
1161 |
+
sprintf(
|
1162 |
+
__( 'Parent extension "%s" not available.', 'fw' ),
|
1163 |
+
$this->get_extension_title( $current_parent )
|
1164 |
+
)
|
1165 |
+
);
|
1166 |
+
$has_errors = true;
|
1167 |
+
|
1168 |
+
if ( $cancel_on_error ) {
|
1169 |
+
break 2;
|
1170 |
+
} else {
|
1171 |
+
continue 2;
|
1172 |
+
}
|
1173 |
+
}
|
1174 |
+
|
1175 |
+
$parents[] = $current_parent;
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
$parents = array_reverse( $parents );
|
1179 |
+
}
|
1180 |
+
|
1181 |
+
/**
|
1182 |
+
* Install parent extensions and the extension
|
1183 |
+
*/
|
1184 |
+
{
|
1185 |
+
$destination_path = array(
|
1186 |
+
'framework' => fw_get_framework_directory(),
|
1187 |
+
'theme' => fw_fix_path( get_template_directory() ) . fw_get_framework_customizations_dir_rel_path(),
|
1188 |
+
);
|
1189 |
+
$current_extension_path = '';
|
1190 |
+
|
1191 |
+
foreach ( $parents as $parent_extension_name ) {
|
1192 |
+
$current_extension_path .= '/extensions/' . $parent_extension_name;
|
1193 |
+
$set = $available_extensions[ $parent_extension_name ];
|
1194 |
+
$destination = isset( $set['theme'] ) && $set['theme'] ? 'theme' : 'framework';
|
1195 |
+
|
1196 |
+
if ( isset( $installed_extensions[ $parent_extension_name ] ) ) {
|
1197 |
+
continue; // skip already installed extensions
|
1198 |
+
}
|
1199 |
+
|
1200 |
+
if ( $verbose ) {
|
1201 |
+
$verbose_message = sprintf( esc_html__( 'Downloading the "%s" extension...', 'fw' ), $this->get_extension_title( $parent_extension_name ) );
|
1202 |
+
|
1203 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1204 |
+
$verbose->feedback( $verbose_message );
|
1205 |
+
} else {
|
1206 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1207 |
+
}
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
// increase timeout
|
1211 |
+
if ( $timeout !== false && function_exists( 'set_time_limit' ) ) {
|
1212 |
+
$timeout += 30;
|
1213 |
+
set_time_limit( $timeout );
|
1214 |
+
}
|
1215 |
+
|
1216 |
+
// If is plugin will returned downloadable link zip.
|
1217 |
+
$wp_fw_downloaded_dir = $this->download( $parent_extension_name, $set );
|
1218 |
+
|
1219 |
+
if ( is_wp_error( $wp_fw_downloaded_dir ) ) {
|
1220 |
+
if ( $verbose ) {
|
1221 |
+
$verbose_message = $wp_fw_downloaded_dir->get_error_message();
|
1222 |
+
|
1223 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1224 |
+
$verbose->error( $verbose_message );
|
1225 |
+
} else {
|
1226 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1227 |
+
}
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
$result[ $extension_name ] = $wp_fw_downloaded_dir;
|
1231 |
+
$has_errors = true;
|
1232 |
+
|
1233 |
+
if ( $cancel_on_error ) {
|
1234 |
+
break 2;
|
1235 |
+
} else {
|
1236 |
+
continue 2;
|
1237 |
+
}
|
1238 |
+
}
|
1239 |
+
|
1240 |
+
if ( $verbose ) {
|
1241 |
+
$verbose_message = sprintf( esc_html__( 'Installing the "%s" extension...', 'fw' ), $this->get_extension_title( $parent_extension_name ) );
|
1242 |
+
|
1243 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1244 |
+
$verbose->feedback( $verbose_message );
|
1245 |
+
} else {
|
1246 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1247 |
+
}
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
// Merge directories only for extensions. If we have plugin it will installed via Plugin_Upgrader.
|
1251 |
+
if ( empty( $set['download']['opts']['plugin'] ) ) {
|
1252 |
+
$merge_result = $this->merge_extension(
|
1253 |
+
$wp_fw_downloaded_dir,
|
1254 |
+
FW_WP_Filesystem::real_path_to_filesystem_path( $destination_path[ $destination ] . $current_extension_path )
|
1255 |
+
);
|
1256 |
+
|
1257 |
+
if ( is_wp_error( $merge_result ) ) {
|
1258 |
+
if ( $verbose ) {
|
1259 |
+
$verbose_message = $merge_result->get_error_message();
|
1260 |
+
|
1261 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1262 |
+
$verbose->error( $verbose_message );
|
1263 |
+
} else {
|
1264 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1265 |
+
}
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
$result[ $extension_name ] = $merge_result;
|
1269 |
+
$has_errors = true;
|
1270 |
+
|
1271 |
+
if ( $cancel_on_error ) {
|
1272 |
+
break 2;
|
1273 |
+
} else {
|
1274 |
+
continue 2;
|
1275 |
+
}
|
1276 |
+
}
|
1277 |
+
}
|
1278 |
+
|
1279 |
+
if ( $verbose ) {
|
1280 |
+
$verbose_message = sprintf( __( 'The %s extension has been successfully installed.', 'fw' ),
|
1281 |
+
$this->get_extension_title( $parent_extension_name )
|
1282 |
+
);
|
1283 |
+
|
1284 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1285 |
+
$verbose->feedback( $verbose_message );
|
1286 |
+
} else {
|
1287 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1288 |
+
}
|
1289 |
+
}
|
1290 |
+
|
1291 |
+
$downloaded_extensions[ $parent_extension_name ] = array();
|
1292 |
+
|
1293 |
+
/**
|
1294 |
+
* Read again all extensions
|
1295 |
+
* The downloaded extension may contain more sub extensions
|
1296 |
+
*/
|
1297 |
+
{
|
1298 |
+
unset( $installed_extensions );
|
1299 |
+
$installed_extensions = $this->get_installed_extensions( true );
|
1300 |
+
}
|
1301 |
+
}
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
$result[ $extension_name ] = true;
|
1305 |
+
|
1306 |
+
/**
|
1307 |
+
* Collect required extensions of the newly installed extensions
|
1308 |
+
*/
|
1309 |
+
foreach (
|
1310 |
+
// new extensions
|
1311 |
+
array_diff(
|
1312 |
+
array_keys( $installed_extensions ),
|
1313 |
+
$extensions_before_install
|
1314 |
+
)
|
1315 |
+
as $new_extension_name
|
1316 |
+
) {
|
1317 |
+
foreach (
|
1318 |
+
array_keys(
|
1319 |
+
fw_akg(
|
1320 |
+
'requirements/extensions',
|
1321 |
+
$installed_extensions[ $new_extension_name ]['manifest'],
|
1322 |
+
array()
|
1323 |
+
)
|
1324 |
+
)
|
1325 |
+
as $required_extension_name
|
1326 |
+
) {
|
1327 |
+
if ( isset( $installed_extensions[ $required_extension_name ] ) ) {
|
1328 |
+
// already installed
|
1329 |
+
continue;
|
1330 |
+
}
|
1331 |
+
|
1332 |
+
$extensions[ $required_extension_name ] = array();
|
1333 |
+
}
|
1334 |
+
}
|
1335 |
+
}
|
1336 |
+
|
1337 |
+
if ( $activate ) {
|
1338 |
+
$activate_extensions = array();
|
1339 |
+
|
1340 |
+
foreach ( $result as $extension_name => $extension_result ) {
|
1341 |
+
if ( ! is_wp_error( $extension_result ) ) {
|
1342 |
+
$activate_extensions[ $extension_name ] = array();
|
1343 |
+
}
|
1344 |
+
}
|
1345 |
+
|
1346 |
+
if ( ! empty( $activate_extensions ) ) {
|
1347 |
+
if ( $verbose ) {
|
1348 |
+
$verbose_message = _n(
|
1349 |
+
'Activating extension...',
|
1350 |
+
'Activating extensions...',
|
1351 |
+
count( $activate_extensions ),
|
1352 |
+
'fw'
|
1353 |
+
);
|
1354 |
+
|
1355 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1356 |
+
$verbose->feedback( $verbose_message );
|
1357 |
+
} else {
|
1358 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1359 |
+
}
|
1360 |
+
}
|
1361 |
+
|
1362 |
+
$activation_result = $this->activate_extensions( $activate_extensions );
|
1363 |
+
|
1364 |
+
if ( $verbose ) {
|
1365 |
+
if ( is_wp_error( $activation_result ) ) {
|
1366 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1367 |
+
$verbose->error( $activation_result->get_error_message() );
|
1368 |
+
} else {
|
1369 |
+
echo fw_html_tag( 'p', array(), $activation_result->get_error_message() );
|
1370 |
+
}
|
1371 |
+
} elseif ( is_array( $activation_result ) ) {
|
1372 |
+
$verbose_message = array();
|
1373 |
+
|
1374 |
+
foreach ( $activation_result as $extension_name => $extension_result ) {
|
1375 |
+
if ( is_wp_error( $extension_result ) ) {
|
1376 |
+
$verbose_message[] = $extension_result->get_error_message();
|
1377 |
+
}
|
1378 |
+
}
|
1379 |
+
|
1380 |
+
$verbose_message = '<ul><li>' . implode( '</li><li>', $verbose_message ) . '</li></ul>';
|
1381 |
+
|
1382 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1383 |
+
$verbose->error( $verbose_message );
|
1384 |
+
} else {
|
1385 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1386 |
+
}
|
1387 |
+
} elseif ( $activation_result === true ) {
|
1388 |
+
$verbose_message = _n(
|
1389 |
+
'Extension has been successfully activated.',
|
1390 |
+
'Extensions has been successfully activated.',
|
1391 |
+
count( $activate_extensions ),
|
1392 |
+
'fw'
|
1393 |
+
);
|
1394 |
+
|
1395 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1396 |
+
$verbose->feedback( $verbose_message );
|
1397 |
+
} else {
|
1398 |
+
echo fw_html_tag( 'p', array(), $verbose_message );
|
1399 |
+
}
|
1400 |
+
}
|
1401 |
+
}
|
1402 |
+
}
|
1403 |
+
}
|
1404 |
+
|
1405 |
+
do_action( 'fw_extensions_install', $result );
|
1406 |
+
|
1407 |
+
if ( $cancel_on_error && $has_errors ) {
|
1408 |
+
if ( ( $last_result = end( $result ) ) && is_wp_error( $last_result ) ) {
|
1409 |
+
return $last_result;
|
1410 |
+
} else {
|
1411 |
+
// this should not happen, but just to be sure (for the future, if the code above will be changed)
|
1412 |
+
return new WP_Error(
|
1413 |
+
'installation_failed',
|
1414 |
+
_n( 'Cannot install extension', 'Cannot install extensions', count( $extensions ), 'fw' )
|
1415 |
+
);
|
1416 |
+
}
|
1417 |
+
}
|
1418 |
+
|
1419 |
+
return $has_errors ? $result : true;
|
1420 |
+
}
|
1421 |
+
|
1422 |
+
private function display_delete_page()
|
1423 |
+
{
|
1424 |
+
$flash_id = 'fw_extensions_delete';
|
1425 |
+
|
1426 |
+
if (!$this->can_install()) {
|
1427 |
+
FW_Flash_Messages::add(
|
1428 |
+
$flash_id,
|
1429 |
+
__('You are not allowed to delete extensions.', 'fw'),
|
1430 |
+
'error'
|
1431 |
+
);
|
1432 |
+
$this->js_redirect();
|
1433 |
+
return;
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
$extensions = array_fill_keys(array_map('trim', explode(',', FW_Request::GET('extension', ''))), array());
|
1437 |
+
|
1438 |
+
{
|
1439 |
+
$skin = new _FW_Extensions_Delete_Upgrader_Skin(array(
|
1440 |
+
'title' => _n('Delete Extension', 'Delete Extensions', count($extensions), 'fw'),
|
1441 |
+
));
|
1442 |
+
}
|
1443 |
+
|
1444 |
+
$skin->header();
|
1445 |
+
|
1446 |
+
do {
|
1447 |
+
$nonce = $this->get_nonce('delete');
|
1448 |
+
|
1449 |
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
1450 |
+
if (!isset($_POST[$nonce['name']]) || !wp_verify_nonce($_POST[$nonce['name']], $nonce['action'])) {
|
1451 |
+
$skin->error(__('Invalid nonce.', 'fw'));
|
1452 |
+
break;
|
1453 |
+
}
|
1454 |
+
|
1455 |
+
if (!FW_WP_Filesystem::request_access(
|
1456 |
+
fw_get_framework_directory('/extensions'), fw_current_url(), array($nonce['name'])
|
1457 |
+
)) {
|
1458 |
+
break;
|
1459 |
+
}
|
1460 |
+
|
1461 |
+
$uninstall_result = $this->uninstall_extensions($extensions, array('verbose' => $skin));
|
1462 |
+
|
1463 |
+
if (is_wp_error($uninstall_result)) {
|
1464 |
+
$skin->error($uninstall_result);
|
1465 |
+
} elseif (is_array($uninstall_result)) {
|
1466 |
+
$error = array();
|
1467 |
+
|
1468 |
+
foreach ($uninstall_result as $extension_name => $extension_result) {
|
1469 |
+
if (is_wp_error($extension_result)) {
|
1470 |
+
$error[] = $extension_result->get_error_message();
|
1471 |
+
}
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
$error = '<ul><li>'. implode('</li><li>', $error) .'</li></ul>';
|
1475 |
+
|
1476 |
+
$skin->error($error);
|
1477 |
+
} elseif ($uninstall_result === true) {
|
1478 |
+
$skin->set_result(true);
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
$skin->after(array(
|
1482 |
+
'extensions_page_link' => $this->get_link()
|
1483 |
+
));
|
1484 |
+
} else {
|
1485 |
+
echo '<form method="post">';
|
1486 |
+
|
1487 |
+
wp_nonce_field($nonce['action'], $nonce['name']);
|
1488 |
+
|
1489 |
+
fw_render_view(dirname(__FILE__) .'/views/delete-form.php', array(
|
1490 |
+
'extension_names' => array_keys($extensions),
|
1491 |
+
'installed_extensions' => $this->get_installed_extensions(),
|
1492 |
+
'list_page_link' => $this->get_link(),
|
1493 |
+
), false);
|
1494 |
+
|
1495 |
+
echo '</form>';
|
1496 |
+
}
|
1497 |
+
} while(false);
|
1498 |
+
|
1499 |
+
$skin->footer();
|
1500 |
+
}
|
1501 |
+
|
1502 |
+
/**
|
1503 |
+
* Remove extensions
|
1504 |
+
* @param array $extensions {'ext_1' => array(), 'ext_2' => array(), ...}
|
1505 |
+
* @param array $opts
|
1506 |
+
* @return WP_Error|bool|array
|
1507 |
+
* true: when all extensions succeeded
|
1508 |
+
* array: when some/all failed
|
1509 |
+
*/
|
1510 |
+
public function uninstall_extensions(array $extensions, $opts = array())
|
1511 |
+
{
|
1512 |
+
{
|
1513 |
+
$opts = array_merge(array(
|
1514 |
+
/**
|
1515 |
+
* @type bool
|
1516 |
+
* false: return {'ext_1' => true|WP_Error, 'ext_2' => true|WP_Error, ...}
|
1517 |
+
* true: return first WP_Error or true on success
|
1518 |
+
*/
|
1519 |
+
'cancel_on_error' => false,
|
1520 |
+
/**
|
1521 |
+
* @type bool|WP_Upgrader_Skin
|
1522 |
+
*/
|
1523 |
+
'verbose' => false,
|
1524 |
+
), $opts);
|
1525 |
+
|
1526 |
+
$cancel_on_error = $opts['cancel_on_error']; // fixme: install back successfully removed extensions before error?
|
1527 |
+
$verbose = $opts['verbose'];
|
1528 |
+
|
1529 |
+
unset($opts);
|
1530 |
+
}
|
1531 |
+
|
1532 |
+
if (!$this->can_install()) {
|
1533 |
+
return new WP_Error(
|
1534 |
+
'access_denied',
|
1535 |
+
__('You have no permissions to uninstall extensions', 'fw')
|
1536 |
+
);
|
1537 |
+
}
|
1538 |
+
|
1539 |
+
if (empty($extensions)) {
|
1540 |
+
return new WP_Error(
|
1541 |
+
'no_extensions',
|
1542 |
+
__('No extensions provided', 'fw')
|
1543 |
+
);
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
1547 |
+
global $wp_filesystem;
|
1548 |
+
|
1549 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
1550 |
+
return new WP_Error(
|
1551 |
+
'fs_not_initialized',
|
1552 |
+
__('WP Filesystem is not initialized', 'fw')
|
1553 |
+
);
|
1554 |
+
}
|
1555 |
+
|
1556 |
+
$installed_extensions = $this->get_installed_extensions();
|
1557 |
+
$available_extensions = $this->get_available_extensions();
|
1558 |
+
$extensions_before_uninstall = array_fill_keys( array_keys( $installed_extensions ), array() );
|
1559 |
+
|
1560 |
+
$result = $uninstalled_extensions = array();
|
1561 |
+
$has_errors = false;
|
1562 |
+
|
1563 |
+
while ( ! empty( $extensions ) ) {
|
1564 |
+
|
1565 |
+
reset( $extensions );
|
1566 |
+
$extension_name = key( $extensions );
|
1567 |
+
unset( $extensions[ $extension_name ] );
|
1568 |
+
|
1569 |
+
if ( ! empty( $available_extensions[ $extension_name ]['download']['opts']['plugin'] ) ) {
|
1570 |
+
$unistall = delete_plugins( (array) $available_extensions[ $extension_name ]['download']['opts']['plugin'] );
|
1571 |
+
$plugin_title = $available_extensions[ $extension_name ]['name'];
|
1572 |
+
|
1573 |
+
if ( $unistall ) {
|
1574 |
+
$this->verbose( sprintf( esc_html__( 'Extension "%s" has been deleted.', 'fw' ), $plugin_title ), $verbose );
|
1575 |
+
$result[ $extension_name ] = true;
|
1576 |
+
} else {
|
1577 |
+
if ( is_wp_error( $unistall ) ) {
|
1578 |
+
$msg_error = $unistall->get_error_message() . ' - ' . $plugin_title;
|
1579 |
+
} else {
|
1580 |
+
$msg_error = sprintf( esc_html__( 'Plugin %s is empty.' ), $plugin_title );
|
1581 |
+
}
|
1582 |
+
|
1583 |
+
$result[ $extension_name ] = new WP_Error( 'fw_delete_plugins', $msg_error, $plugin_title );
|
1584 |
+
$has_errors = true;
|
1585 |
+
|
1586 |
+
if ( $cancel_on_error ) {
|
1587 |
+
break;
|
1588 |
+
} else {
|
1589 |
+
continue;
|
1590 |
+
}
|
1591 |
+
}
|
1592 |
+
|
1593 |
+
continue;
|
1594 |
+
}
|
1595 |
+
|
1596 |
+
$extension_title = $this->get_extension_title($extension_name);
|
1597 |
+
|
1598 |
+
if (!isset($installed_extensions[ $extension_name ])) {
|
1599 |
+
// already deleted
|
1600 |
+
$result[$extension_name] = true;
|
1601 |
+
continue;
|
1602 |
+
}
|
1603 |
+
|
1604 |
+
if (
|
1605 |
+
!isset($installed_extensions[ $extension_name ]['path'])
|
1606 |
+
||
|
1607 |
+
empty($installed_extensions[ $extension_name ]['path'])
|
1608 |
+
) {
|
1609 |
+
/**
|
1610 |
+
* This happens sometimes, but I don't know why
|
1611 |
+
* If the script will continue, it will delete the root folder
|
1612 |
+
*/
|
1613 |
+
fw_print(
|
1614 |
+
'Please report this to https://github.com/ThemeFuse/Unyson/issues',
|
1615 |
+
$extension_name,
|
1616 |
+
$installed_extensions
|
1617 |
+
);
|
1618 |
+
die;
|
1619 |
+
}
|
1620 |
+
|
1621 |
+
$wp_fs_extension_path = FW_WP_Filesystem::real_path_to_filesystem_path(
|
1622 |
+
$installed_extensions[ $extension_name ]['path']
|
1623 |
+
);
|
1624 |
+
|
1625 |
+
if (!$wp_filesystem->exists($wp_fs_extension_path)) {
|
1626 |
+
// already deleted, maybe because it was a sub-extension of an deleted extension
|
1627 |
+
$result[$extension_name] = true;
|
1628 |
+
continue;
|
1629 |
+
}
|
1630 |
+
|
1631 |
+
$this->verbose( sprintf( esc_html__( 'Deleting the "%s" extension...', 'fw' ), $extension_title ), $verbose );
|
1632 |
+
|
1633 |
+
if (!$wp_filesystem->delete($wp_fs_extension_path, true, 'd')) {
|
1634 |
+
$result[$extension_name] = new WP_Error(
|
1635 |
+
'cannot_delete_directory',
|
1636 |
+
sprintf(__('Cannot delete the "%s" extension.', 'fw'), $extension_title)
|
1637 |
+
);
|
1638 |
+
$has_errors = true;
|
1639 |
+
|
1640 |
+
if ($cancel_on_error) {
|
1641 |
+
break;
|
1642 |
+
} else {
|
1643 |
+
continue;
|
1644 |
+
}
|
1645 |
+
} else {
|
1646 |
+
$this->verbose( sprintf( esc_html__( 'The %s extension has been successfully deleted.', 'fw' ), $extension_title ), $verbose );
|
1647 |
+
$result[$extension_name] = true;
|
1648 |
+
}
|
1649 |
+
|
1650 |
+
/**
|
1651 |
+
* Read again all extensions
|
1652 |
+
* The delete extension may contain more sub extensions
|
1653 |
+
*/
|
1654 |
+
{
|
1655 |
+
unset($installed_extensions);
|
1656 |
+
$installed_extensions = $this->get_installed_extensions(true);
|
1657 |
+
}
|
1658 |
+
|
1659 |
+
/**
|
1660 |
+
* Add for deletion not used extensions
|
1661 |
+
* For e.g. standalone=false extension that were required by the deleted extension
|
1662 |
+
* and now are not required by any other extension
|
1663 |
+
*/
|
1664 |
+
{
|
1665 |
+
$not_used_extensions = array_fill_keys(
|
1666 |
+
array_keys(
|
1667 |
+
array_diff_key(
|
1668 |
+
$installed_extensions,
|
1669 |
+
$this->get_used_extensions($extensions, array_keys($installed_extensions))
|
1670 |
+
)
|
1671 |
+
),
|
1672 |
+
array()
|
1673 |
+
);
|
1674 |
+
|
1675 |
+
$extensions = array_merge($extensions, $not_used_extensions);
|
1676 |
+
}
|
1677 |
+
}
|
1678 |
+
|
1679 |
+
do_action('fw_extensions_uninstall', $result);
|
1680 |
+
|
1681 |
+
if (
|
1682 |
+
$cancel_on_error
|
1683 |
+
&&
|
1684 |
+
$has_errors
|
1685 |
+
) {
|
1686 |
+
if (
|
1687 |
+
($last_result = end($result))
|
1688 |
+
&&
|
1689 |
+
is_wp_error($last_result)
|
1690 |
+
) {
|
1691 |
+
return $last_result;
|
1692 |
+
} else {
|
1693 |
+
// this should not happen, but just to be sure (for the future, if the code above will be changed)
|
1694 |
+
return new WP_Error(
|
1695 |
+
'uninstall_failed',
|
1696 |
+
_n('Cannot uninstall extension', 'Cannot uninstall extensions', count($extensions), 'fw')
|
1697 |
+
);
|
1698 |
+
}
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
// remove from active list the deleted extensions
|
1702 |
+
{
|
1703 |
+
update_option(
|
1704 |
+
fw()->extensions->_get_active_extensions_db_option_name(),
|
1705 |
+
array_diff_key(
|
1706 |
+
fw()->extensions->_get_db_active_extensions(),
|
1707 |
+
array_diff_key(
|
1708 |
+
$extensions_before_uninstall,
|
1709 |
+
$installed_extensions
|
1710 |
+
)
|
1711 |
+
)
|
1712 |
+
);
|
1713 |
+
}
|
1714 |
+
|
1715 |
+
if ($has_errors) {
|
1716 |
+
return $result;
|
1717 |
+
} else {
|
1718 |
+
return true;
|
1719 |
+
}
|
1720 |
+
}
|
1721 |
+
|
1722 |
+
public function verbose( $msg, &$verbose ) {
|
1723 |
+
|
1724 |
+
if ( ! $verbose ) {
|
1725 |
+
return;
|
1726 |
+
}
|
1727 |
+
|
1728 |
+
if ( is_subclass_of( $verbose, 'WP_Upgrader_Skin' ) ) {
|
1729 |
+
$verbose->feedback( $msg );
|
1730 |
+
} else {
|
1731 |
+
echo fw_html_tag( 'p', array(), $msg );
|
1732 |
+
}
|
1733 |
+
}
|
1734 |
+
|
1735 |
+
private function display_extension_page()
|
1736 |
+
{
|
1737 |
+
// note: static is enqueued in 'admin_enqueue_scripts' action
|
1738 |
+
|
1739 |
+
$extension_name = trim(FW_Request::GET('extension', ''));
|
1740 |
+
|
1741 |
+
$installed_extensions = $this->get_installed_extensions();
|
1742 |
+
|
1743 |
+
$flash_id = 'fw_extension_page';
|
1744 |
+
|
1745 |
+
{
|
1746 |
+
$error = '';
|
1747 |
+
|
1748 |
+
do {
|
1749 |
+
if (empty($extension_name)) {
|
1750 |
+
$error = __('Extension not specified.', 'fw');
|
1751 |
+
break;
|
1752 |
+
}
|
1753 |
+
|
1754 |
+
if (!isset($installed_extensions[$extension_name])) {
|
1755 |
+
$error = sprintf(__('Extension "%s" is not installed.', 'fw'), $this->get_extension_title($extension_name));
|
1756 |
+
break;
|
1757 |
+
}
|
1758 |
+
} while(false);
|
1759 |
+
|
1760 |
+
if ($error) {
|
1761 |
+
FW_Flash_Messages::add($flash_id, $error, 'error');
|
1762 |
+
$this->js_redirect();
|
1763 |
+
return;
|
1764 |
+
}
|
1765 |
+
}
|
1766 |
+
|
1767 |
+
{
|
1768 |
+
$tab = fw_akg('tab', $_GET, 'settings');
|
1769 |
+
|
1770 |
+
if (!in_array($tab, array('settings', 'docs'))) {
|
1771 |
+
$tab = 'settings';
|
1772 |
+
}
|
1773 |
+
}
|
1774 |
+
|
1775 |
+
$extension_title = $this->get_extension_title($extension_name);
|
1776 |
+
$link = $this->get_link();
|
1777 |
+
|
1778 |
+
echo '<div class="wrap" id="fw-extension-page">';
|
1779 |
+
|
1780 |
+
fw_render_view(dirname(__FILE__) .'/views/extension-page-header.php', array(
|
1781 |
+
'extension_name' => $extension_name,
|
1782 |
+
'extension_data' => $installed_extensions[$extension_name],
|
1783 |
+
'link_delete' => $link .'&sub-page=delete',
|
1784 |
+
'link_extension' => $link .'&sub-page=extension',
|
1785 |
+
'extension_title' => $extension_title,
|
1786 |
+
'tab' => $tab,
|
1787 |
+
'is_supported' =>
|
1788 |
+
fw()->theme->manifest->get('supported_extensions/'. $extension_name, false) !== false
|
1789 |
+
||
|
1790 |
+
$installed_extensions[$extension_name]['is']['theme']
|
1791 |
+
), false);
|
1792 |
+
|
1793 |
+
unset($installed_extensions);
|
1794 |
+
|
1795 |
+
echo '<div id="fw-extension-tab-content">';
|
1796 |
+
{
|
1797 |
+
$method_data = array();
|
1798 |
+
|
1799 |
+
switch ($tab) {
|
1800 |
+
case 'settings':
|
1801 |
+
$error = $this->display_extension_settings_page($extension_name, $method_data);
|
1802 |
+
break;
|
1803 |
+
case 'docs':
|
1804 |
+
$error = $this->display_extension_docs_page($extension_name, $method_data);
|
1805 |
+
break;
|
1806 |
+
}
|
1807 |
+
}
|
1808 |
+
echo '</div>';
|
1809 |
+
|
1810 |
+
echo '</div>';
|
1811 |
+
|
1812 |
+
if ($error) {
|
1813 |
+
FW_Flash_Messages::add($flash_id, $error, 'error');
|
1814 |
+
$this->js_redirect();
|
1815 |
+
return;
|
1816 |
+
}
|
1817 |
+
}
|
1818 |
+
|
1819 |
+
private function display_extension_settings_page($extension_name, $data)
|
1820 |
+
{
|
1821 |
+
if (!fw()->extensions->get($extension_name)) {
|
1822 |
+
return sprintf(
|
1823 |
+
__('Extension "%s" does not exist or is not active.', 'fw'),
|
1824 |
+
fw_htmlspecialchars($extension_name)
|
1825 |
+
);
|
1826 |
+
}
|
1827 |
+
|
1828 |
+
$extension = fw()->extensions->get($extension_name);
|
1829 |
+
|
1830 |
+
if (!$extension->get_settings_options()) {
|
1831 |
+
return sprintf(
|
1832 |
+
__('%s extension does not have settings.', 'fw'),
|
1833 |
+
$extension->manifest->get_name()
|
1834 |
+
);
|
1835 |
+
}
|
1836 |
+
|
1837 |
+
echo '<div id="fw-extension-settings">';
|
1838 |
+
|
1839 |
+
echo $this->extension_settings_form->render(array(
|
1840 |
+
'extension' => $extension,
|
1841 |
+
));
|
1842 |
+
|
1843 |
+
echo '</div>';
|
1844 |
+
}
|
1845 |
+
|
1846 |
+
private function display_extension_docs_page($extension_name, $data)
|
1847 |
+
{
|
1848 |
+
$ext = fw_ext($extension_name);
|
1849 |
+
$docs = $ext->get_rendered_docs();
|
1850 |
+
|
1851 |
+
if (! $docs) {
|
1852 |
+
return __(
|
1853 |
+
'Extension has no documentation. Maybe ask its developer to write some?',
|
1854 |
+
'fw'
|
1855 |
+
);
|
1856 |
+
}
|
1857 |
+
|
1858 |
+
echo fw()->backend->render_box(
|
1859 |
+
'fw-extension-docs',
|
1860 |
+
'',
|
1861 |
+
fw()->backend->render_options(array(
|
1862 |
+
'docs' => array(
|
1863 |
+
'label' => false,
|
1864 |
+
'type' => 'html-full',
|
1865 |
+
'html' => $docs
|
1866 |
+
),
|
1867 |
+
))
|
1868 |
+
);
|
1869 |
+
}
|
1870 |
+
|
1871 |
+
private function display_activate_page()
|
1872 |
+
{
|
1873 |
+
$error = '';
|
1874 |
+
|
1875 |
+
do {
|
1876 |
+
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
1877 |
+
$error = __('Invalid request method.', 'fw');
|
1878 |
+
break;
|
1879 |
+
}
|
1880 |
+
|
1881 |
+
$nonce = $this->get_nonce('activate');
|
1882 |
+
|
1883 |
+
if (!wp_verify_nonce(FW_Request::POST($nonce['name']), $nonce['action'])) {
|
1884 |
+
$error = __('Invalid nonce.', 'fw');
|
1885 |
+
break;
|
1886 |
+
}
|
1887 |
+
|
1888 |
+
if (!isset($_GET['extension'])) {
|
1889 |
+
$error = __('No extension specified.', 'fw');
|
1890 |
+
break;
|
1891 |
+
}
|
1892 |
+
|
1893 |
+
$activation_result = $this->activate_extensions(
|
1894 |
+
array_fill_keys(explode(',', $_GET['extension']), array())
|
1895 |
+
);
|
1896 |
+
|
1897 |
+
if (is_wp_error($activation_result)) {
|
1898 |
+
$error = $activation_result->get_error_message();
|
1899 |
+
} elseif (is_array($activation_result)) {
|
1900 |
+
$error = array();
|
1901 |
+
|
1902 |
+
foreach ($activation_result as $extension_name => $extension_result) {
|
1903 |
+
if (is_wp_error($extension_result)) {
|
1904 |
+
$error[] = $extension_result->get_error_message();
|
1905 |
+
}
|
1906 |
+
}
|
1907 |
+
|
1908 |
+
$error = '<ul><li>'. implode('</li><li>', $error) .'</li></ul>';
|
1909 |
+
}
|
1910 |
+
} while(false);
|
1911 |
+
|
1912 |
+
if ($error) {
|
1913 |
+
FW_Flash_Messages::add(
|
1914 |
+
'fw_extensions_activate_page',
|
1915 |
+
$error,
|
1916 |
+
'error'
|
1917 |
+
);
|
1918 |
+
$this->js_redirect();
|
1919 |
+
return;
|
1920 |
+
}
|
1921 |
+
|
1922 |
+
$this->js_redirect();
|
1923 |
+
}
|
1924 |
+
|
1925 |
+
/**
|
1926 |
+
* Add extensions to active extensions list in database
|
1927 |
+
* After refresh they should be active, if all dependencies will be met and if parent-extension::_init() will not return false
|
1928 |
+
* @param array $extensions {'ext_1' => array(), 'ext_2' => array(), ...}
|
1929 |
+
* @param bool $cancel_on_error
|
1930 |
+
* false: return {'ext_1' => true|WP_Error, 'ext_2' => true|WP_Error, ...}
|
1931 |
+
* true: return first WP_Error or true on success
|
1932 |
+
* @return WP_Error|bool|array
|
1933 |
+
* true: when all extensions succeeded
|
1934 |
+
* array: when some/all failed
|
1935 |
+
*/
|
1936 |
+
public function activate_extensions(array $extensions, $cancel_on_error = false)
|
1937 |
+
{
|
1938 |
+
if (!$this->can_activate()) {
|
1939 |
+
return new WP_Error(
|
1940 |
+
'access_denied',
|
1941 |
+
__('You have no permissions to activate extensions', 'fw')
|
1942 |
+
);
|
1943 |
+
}
|
1944 |
+
|
1945 |
+
if (empty($extensions)) {
|
1946 |
+
return new WP_Error(
|
1947 |
+
'no_extensions',
|
1948 |
+
__('No extensions provided', 'fw')
|
1949 |
+
);
|
1950 |
+
}
|
1951 |
+
|
1952 |
+
$installed_extensions = $this->get_installed_extensions();
|
1953 |
+
$available_extensions = $this->get_available_extensions();
|
1954 |
+
|
1955 |
+
$result = $extensions_for_activation = array();
|
1956 |
+
$has_errors = false;
|
1957 |
+
|
1958 |
+
foreach ($extensions as $extension_name => $not_used_var) {
|
1959 |
+
|
1960 |
+
if ( ! empty( $available_extensions[ $extension_name ]['download']['opts']['plugin'] ) ) {
|
1961 |
+
activate_plugin( $available_extensions[ $extension_name ]['download']['opts']['plugin'] );
|
1962 |
+
continue;
|
1963 |
+
}
|
1964 |
+
|
1965 |
+
if (!isset($installed_extensions[$extension_name])) {
|
1966 |
+
$result[$extension_name] = new WP_Error(
|
1967 |
+
'extension_not_installed',
|
1968 |
+
sprintf(__('Extension "%s" does not exist.', 'fw'), $this->get_extension_title($extension_name))
|
1969 |
+
);
|
1970 |
+
$has_errors = true;
|
1971 |
+
|
1972 |
+
if ($cancel_on_error) {
|
1973 |
+
break;
|
1974 |
+
} else {
|
1975 |
+
continue;
|
1976 |
+
}
|
1977 |
+
}
|
1978 |
+
|
1979 |
+
$collected = $this->get_extensions_for_activation($extension_name);
|
1980 |
+
|
1981 |
+
if (is_wp_error($collected)) {
|
1982 |
+
$result[$extension_name] = $collected;
|
1983 |
+
$has_errors = true;
|
1984 |
+
|
1985 |
+
if ($cancel_on_error) {
|
1986 |
+
break;
|
1987 |
+
} else {
|
1988 |
+
continue;
|
1989 |
+
}
|
1990 |
+
}
|
1991 |
+
|
1992 |
+
$extensions_for_activation = array_merge($extensions_for_activation, $collected);
|
1993 |
+
|
1994 |
+
$result[$extension_name] = true;
|
1995 |
+
}
|
1996 |
+
|
1997 |
+
if (
|
1998 |
+
$cancel_on_error
|
1999 |
+
&&
|
2000 |
+
$has_errors
|
2001 |
+
) {
|
2002 |
+
if (
|
2003 |
+
($last_result = end($result))
|
2004 |
+
&&
|
2005 |
+
is_wp_error($last_result)
|
2006 |
+
) {
|
2007 |
+
return $last_result;
|
2008 |
+
} else {
|
2009 |
+
// this should not happen, but just to be sure (for the future, if the code above will be changed)
|
2010 |
+
return new WP_Error(
|
2011 |
+
'activation_failed',
|
2012 |
+
_n('Cannot activate extension', 'Cannot activate extensions', count($extensions), 'fw')
|
2013 |
+
);
|
2014 |
+
}
|
2015 |
+
}
|
2016 |
+
|
2017 |
+
update_option(
|
2018 |
+
fw()->extensions->_get_active_extensions_db_option_name(),
|
2019 |
+
array_merge(fw()->extensions->_get_db_active_extensions(), $extensions_for_activation)
|
2020 |
+
);
|
2021 |
+
|
2022 |
+
// remove already active extensions
|
2023 |
+
foreach ($extensions_for_activation as $extension_name => $not_used_var) {
|
2024 |
+
if (fw_ext($extension_name)) {
|
2025 |
+
unset($extensions_for_activation[$extension_name]);
|
2026 |
+
}
|
2027 |
+
}
|
2028 |
+
|
2029 |
+
/**
|
2030 |
+
* Prepare db wp option used to fire the 'fw_extensions_after_activation' action on next refresh
|
2031 |
+
*/
|
2032 |
+
{
|
2033 |
+
$db_wp_option_name = 'fw_extensions_activation';
|
2034 |
+
$db_wp_option_value = get_option($db_wp_option_name, array(
|
2035 |
+
'activated' => array(),
|
2036 |
+
'deactivated' => array(),
|
2037 |
+
));
|
2038 |
+
|
2039 |
+
/**
|
2040 |
+
* Keep adding to the existing value instead of resetting it on each method call
|
2041 |
+
* in case the method will be called multiple times
|
2042 |
+
*/
|
2043 |
+
$db_wp_option_value['activated'] = array_merge($db_wp_option_value['activated'], $extensions_for_activation);
|
2044 |
+
|
2045 |
+
/**
|
2046 |
+
* Remove activated extensions from deactivated
|
2047 |
+
*/
|
2048 |
+
$db_wp_option_value['deactivated'] = array_diff_key($db_wp_option_value['deactivated'], $db_wp_option_value['activated']);
|
2049 |
+
|
2050 |
+
update_option($db_wp_option_name, $db_wp_option_value, false);
|
2051 |
+
}
|
2052 |
+
|
2053 |
+
do_action('fw_extensions_before_activation', $extensions_for_activation);
|
2054 |
+
|
2055 |
+
if ($has_errors) {
|
2056 |
+
return $result;
|
2057 |
+
} else {
|
2058 |
+
return true;
|
2059 |
+
}
|
2060 |
+
}
|
2061 |
+
|
2062 |
+
private function collect_sub_extensions($ext_name, &$installed_extensions)
|
2063 |
+
{
|
2064 |
+
$result = array();
|
2065 |
+
|
2066 |
+
foreach ($installed_extensions[$ext_name]['children'] as $child_ext_name => $child_ext_data) {
|
2067 |
+
$result[$child_ext_name] = array();
|
2068 |
+
|
2069 |
+
$result += $this->collect_sub_extensions($child_ext_name, $installed_extensions);
|
2070 |
+
}
|
2071 |
+
|
2072 |
+
return $result;
|
2073 |
+
}
|
2074 |
+
|
2075 |
+
private function collect_required_extensions($ext_name, &$installed_extensions, &$collected)
|
2076 |
+
{
|
2077 |
+
if (!isset($installed_extensions[$ext_name])) {
|
2078 |
+
return;
|
2079 |
+
}
|
2080 |
+
|
2081 |
+
foreach (fw_akg('requirements/extensions', $installed_extensions[$ext_name]['manifest'], array()) as $req_ext_name => $req_ext_data) {
|
2082 |
+
if (isset($collected[$req_ext_name])) {
|
2083 |
+
// prevent requirements recursion
|
2084 |
+
continue;
|
2085 |
+
}
|
2086 |
+
|
2087 |
+
$collected[$req_ext_name] = array();
|
2088 |
+
|
2089 |
+
$this->collect_required_extensions($req_ext_name, $installed_extensions, $collected);
|
2090 |
+
}
|
2091 |
+
}
|
2092 |
+
|
2093 |
+
private function display_deactivate_page()
|
2094 |
+
{
|
2095 |
+
$installed_extensions = $this->get_installed_extensions();
|
2096 |
+
|
2097 |
+
$error = '';
|
2098 |
+
|
2099 |
+
do {
|
2100 |
+
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
2101 |
+
$error = __('Invalid request method.', 'fw');
|
2102 |
+
break;
|
2103 |
+
}
|
2104 |
+
|
2105 |
+
$nonce = $this->get_nonce('deactivate');
|
2106 |
+
|
2107 |
+
if (!wp_verify_nonce(FW_Request::POST($nonce['name']), $nonce['action'])) {
|
2108 |
+
$error = __('Invalid nonce.', 'fw');
|
2109 |
+
break;
|
2110 |
+
}
|
2111 |
+
|
2112 |
+
if (!isset($_GET['extension'])) {
|
2113 |
+
$error = __('No extension specified.', 'fw');
|
2114 |
+
break;
|
2115 |
+
}
|
2116 |
+
|
2117 |
+
$deactivation_result = $this->deactivate_extensions(
|
2118 |
+
array_fill_keys(explode(',', $_GET['extension']), array())
|
2119 |
+
);
|
2120 |
+
|
2121 |
+
if (is_wp_error($deactivation_result)) {
|
2122 |
+
$error = $deactivation_result->get_error_message();
|
2123 |
+
} elseif (is_array($deactivation_result)) {
|
2124 |
+
$error = array();
|
2125 |
+
|
2126 |
+
foreach ($deactivation_result as $extension_name => $extension_result) {
|
2127 |
+
if (is_wp_error($extension_result)) {
|
2128 |
+
$error[] = $extension_result->get_error_message();
|
2129 |
+
}
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
$error = '<ul><li>'. implode('</li><li>', $error) .'</li></ul>';
|
2133 |
+
}
|
2134 |
+
} while(false);
|
2135 |
+
|
2136 |
+
if ($error) {
|
2137 |
+
FW_Flash_Messages::add(
|
2138 |
+
'fw_extensions_activate_page',
|
2139 |
+
$error,
|
2140 |
+
'error'
|
2141 |
+
);
|
2142 |
+
}
|
2143 |
+
|
2144 |
+
$this->js_redirect();
|
2145 |
+
}
|
2146 |
+
|
2147 |
+
/**
|
2148 |
+
* Remove extensions from active extensions list in database
|
2149 |
+
* After refresh they will be inactive
|
2150 |
+
* @param array $extensions {'ext_1' => array(), 'ext_2' => array(), ...}
|
2151 |
+
* @param bool $cancel_on_error
|
2152 |
+
* false: return {'ext_1' => true|WP_Error, 'ext_2' => true|WP_Error, ...}
|
2153 |
+
* true: return first WP_Error or true on success
|
2154 |
+
* @return WP_Error|bool|array
|
2155 |
+
* true: when all extensions succeeded
|
2156 |
+
* array: when some/all failed
|
2157 |
+
*/
|
2158 |
+
public function deactivate_extensions(array $extensions, $cancel_on_error = false)
|
2159 |
+
{
|
2160 |
+
if (!$this->can_activate()) {
|
2161 |
+
return new WP_Error(
|
2162 |
+
'access_denied',
|
2163 |
+
__('You have no permissions to deactivate extensions', 'fw')
|
2164 |
+
);
|
2165 |
+
}
|
2166 |
+
|
2167 |
+
if (empty($extensions)) {
|
2168 |
+
return new WP_Error(
|
2169 |
+
'no_extensions',
|
2170 |
+
__('No extensions provided', 'fw')
|
2171 |
+
);
|
2172 |
+
}
|
2173 |
+
|
2174 |
+
$available_extensions = $this->get_available_extensions();
|
2175 |
+
$installed_extensions = $this->get_installed_extensions();
|
2176 |
+
|
2177 |
+
$result = $extensions_for_deactivation = array();
|
2178 |
+
$has_errors = false;
|
2179 |
+
|
2180 |
+
foreach ($extensions as $extension_name => $not_used_var) {
|
2181 |
+
|
2182 |
+
if ( ! empty( $available_extensions[ $extension_name ]['download']['opts']['plugin'] ) ) {
|
2183 |
+
deactivate_plugins( plugin_basename( $available_extensions[ $extension_name ]['download']['opts']['plugin'] ) );
|
2184 |
+
continue;
|
2185 |
+
}
|
2186 |
+
|
2187 |
+
|
2188 |
+
if (!isset($installed_extensions[$extension_name])) {
|
2189 |
+
// anyway remove from the active list
|
2190 |
+
$extensions_for_deactivation[$extension_name] = array();
|
2191 |
+
|
2192 |
+
$result[$extension_name] = new WP_Error(
|
2193 |
+
'extension_not_installed',
|
2194 |
+
sprintf(__( 'Extension "%s" does not exist.' , 'fw' ), $this->get_extension_title($extension_name))
|
2195 |
+
);
|
2196 |
+
$has_errors = true;
|
2197 |
+
|
2198 |
+
if ($cancel_on_error) {
|
2199 |
+
break;
|
2200 |
+
} else {
|
2201 |
+
continue;
|
2202 |
+
}
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
$current_deactivating_extensions = array(
|
2206 |
+
$extension_name => array()
|
2207 |
+
);
|
2208 |
+
|
2209 |
+
// add sub-extensions for deactivation
|
2210 |
+
foreach ($this->collect_sub_extensions($extension_name, $installed_extensions) as $sub_extension_name => $sub_extension_data) {
|
2211 |
+
$current_deactivating_extensions[ $sub_extension_name ] = array();
|
2212 |
+
}
|
2213 |
+
|
2214 |
+
// add extensions that requires deactivated extensions
|
2215 |
+
$this->collect_extensions_that_requires($current_deactivating_extensions, $current_deactivating_extensions);
|
2216 |
+
|
2217 |
+
$extensions_for_deactivation = array_merge(
|
2218 |
+
$extensions_for_deactivation,
|
2219 |
+
$current_deactivating_extensions
|
2220 |
+
);
|
2221 |
+
|
2222 |
+
unset($current_deactivating_extensions);
|
2223 |
+
|
2224 |
+
$result[$extension_name] = true;
|
2225 |
+
}
|
2226 |
+
|
2227 |
+
if (
|
2228 |
+
$cancel_on_error
|
2229 |
+
&&
|
2230 |
+
$has_errors
|
2231 |
+
) {
|
2232 |
+
if (
|
2233 |
+
($last_result = end($result))
|
2234 |
+
&&
|
2235 |
+
is_wp_error($last_result)
|
2236 |
+
) {
|
2237 |
+
return $last_result;
|
2238 |
+
} else {
|
2239 |
+
// this should not happen, but just to be sure (for the future, if the code above will be changed)
|
2240 |
+
return new WP_Error(
|
2241 |
+
'deactivation_failed',
|
2242 |
+
_n('Cannot deactivate extension', 'Cannot activate extensions', count($extensions), 'fw')
|
2243 |
+
);
|
2244 |
+
}
|
2245 |
+
}
|
2246 |
+
|
2247 |
+
// add not used extensions for deactivation
|
2248 |
+
$extensions_for_deactivation = array_merge($extensions_for_deactivation,
|
2249 |
+
array_fill_keys(
|
2250 |
+
array_keys(
|
2251 |
+
array_diff_key(
|
2252 |
+
$installed_extensions,
|
2253 |
+
$this->get_used_extensions($extensions_for_deactivation, array_keys(fw()->extensions->get_all()))
|
2254 |
+
)
|
2255 |
+
),
|
2256 |
+
array()
|
2257 |
+
)
|
2258 |
+
);
|
2259 |
+
|
2260 |
+
update_option(
|
2261 |
+
fw()->extensions->_get_active_extensions_db_option_name(),
|
2262 |
+
array_diff_key(
|
2263 |
+
fw()->extensions->_get_db_active_extensions(),
|
2264 |
+
$extensions_for_deactivation
|
2265 |
+
)
|
2266 |
+
);
|
2267 |
+
|
2268 |
+
// remove already inactive extensions
|
2269 |
+
foreach ($extensions_for_deactivation as $extension_name => $not_used_var) {
|
2270 |
+
if (!fw_ext($extension_name)) {
|
2271 |
+
unset($extensions_for_deactivation[$extension_name]);
|
2272 |
+
}
|
2273 |
+
}
|
2274 |
+
|
2275 |
+
/**
|
2276 |
+
* Prepare db wp option used to fire the 'fw_extensions_after_deactivation' action on next refresh
|
2277 |
+
*/
|
2278 |
+
{
|
2279 |
+
$db_wp_option_name = 'fw_extensions_activation';
|
2280 |
+
$db_wp_option_value = get_option($db_wp_option_name, array(
|
2281 |
+
'activated' => array(),
|
2282 |
+
'deactivated' => array(),
|
2283 |
+
));
|
2284 |
+
|
2285 |
+
/**
|
2286 |
+
* Keep adding to the existing value instead of resetting it on each method call
|
2287 |
+
* in case the method will be called multiple times
|
2288 |
+
*/
|
2289 |
+
$db_wp_option_value['deactivated'] = array_merge($db_wp_option_value['deactivated'], $extensions_for_deactivation);
|
2290 |
+
|
2291 |
+
/**
|
2292 |
+
* Remove deactivated extensions from activated
|
2293 |
+
*/
|
2294 |
+
$db_wp_option_value['activated'] = array_diff_key($db_wp_option_value['activated'], $db_wp_option_value['deactivated']);
|
2295 |
+
|
2296 |
+
update_option($db_wp_option_name, $db_wp_option_value, false);
|
2297 |
+
}
|
2298 |
+
|
2299 |
+
do_action('fw_extensions_before_deactivation', $extensions_for_deactivation);
|
2300 |
+
|
2301 |
+
if ($has_errors) {
|
2302 |
+
return $result;
|
2303 |
+
} else {
|
2304 |
+
return true;
|
2305 |
+
}
|
2306 |
+
}
|
2307 |
+
|
2308 |
+
/**
|
2309 |
+
* @param array $data
|
2310 |
+
* @return array
|
2311 |
+
* @internal
|
2312 |
+
*/
|
2313 |
+
public function _extension_settings_form_render($data)
|
2314 |
+
{
|
2315 |
+
/**
|
2316 |
+
* @var FW_Extension $extension
|
2317 |
+
*/
|
2318 |
+
$extension = $data['data']['extension'];
|
2319 |
+
|
2320 |
+
do_action('fw_extension_settings_form_render:'. $extension->get_name());
|
2321 |
+
|
2322 |
+
echo fw_html_tag('input', array(
|
2323 |
+
'type' => 'hidden',
|
2324 |
+
'name' => 'fw_extension_name',
|
2325 |
+
'value' => $extension->get_name(),
|
2326 |
+
), true);
|
2327 |
+
|
2328 |
+
echo fw()->backend->render_options(
|
2329 |
+
$extension->get_settings_options(),
|
2330 |
+
fw_get_db_ext_settings_option($extension->get_name())
|
2331 |
+
);
|
2332 |
+
|
2333 |
+
$data['submit']['html'] = '';
|
2334 |
+
|
2335 |
+
echo '<p>';
|
2336 |
+
echo fw_html_tag('input', array(
|
2337 |
+
'type' => 'submit',
|
2338 |
+
'class' => 'button-primary',
|
2339 |
+
'value' => __('Save', 'fw'),
|
2340 |
+
));
|
2341 |
+
echo ' ';
|
2342 |
+
echo fw_html_tag('a', array(
|
2343 |
+
'href' => $this->get_link(),
|
2344 |
+
), __('Cancel', 'fw'));
|
2345 |
+
echo '</p>';
|
2346 |
+
|
2347 |
+
return $data;
|
2348 |
+
}
|
2349 |
+
|
2350 |
+
/**
|
2351 |
+
* @param array $errors
|
2352 |
+
* @return array
|
2353 |
+
* @internal
|
2354 |
+
*/
|
2355 |
+
public function _extension_settings_form_validate($errors)
|
2356 |
+
{
|
2357 |
+
do {
|
2358 |
+
if (!current_user_can($this->can_activate())) {
|
2359 |
+
$errors[] = __('You are not allowed to save extensions settings.', 'fw');
|
2360 |
+
break;
|
2361 |
+
}
|
2362 |
+
|
2363 |
+
$extension = fw()->extensions->get(FW_Request::POST('fw_extension_name'));
|
2364 |
+
|
2365 |
+
if (!$extension) {
|
2366 |
+
$errors[] = __('Invalid extension.', 'fw');
|
2367 |
+
break;
|
2368 |
+
}
|
2369 |
+
|
2370 |
+
if (!$extension->get_settings_options()) {
|
2371 |
+
$errors[] = __('Extension does not have settings options.', 'fw');
|
2372 |
+
break;
|
2373 |
+
}
|
2374 |
+
} while(false);
|
2375 |
+
|
2376 |
+
return $errors;
|
2377 |
+
}
|
2378 |
+
|
2379 |
+
/**
|
2380 |
+
* @param array $data
|
2381 |
+
* @return array
|
2382 |
+
* @internal
|
2383 |
+
*/
|
2384 |
+
public function _extension_settings_form_save($data)
|
2385 |
+
{
|
2386 |
+
$extension = fw()->extensions->get(FW_Request::POST('fw_extension_name'));
|
2387 |
+
|
2388 |
+
$options_before_save = (array)fw_get_db_ext_settings_option($extension->get_name());
|
2389 |
+
|
2390 |
+
fw_set_db_ext_settings_option(
|
2391 |
+
$extension->get_name(),
|
2392 |
+
null,
|
2393 |
+
array_merge(
|
2394 |
+
$options_before_save,
|
2395 |
+
fw_get_options_values_from_input(
|
2396 |
+
$extension->get_settings_options()
|
2397 |
+
)
|
2398 |
+
)
|
2399 |
+
);
|
2400 |
+
|
2401 |
+
FW_Flash_Messages::add(
|
2402 |
+
'fw_extension_settings_saved',
|
2403 |
+
__('Extensions settings successfully saved.', 'fw'),
|
2404 |
+
'success'
|
2405 |
+
);
|
2406 |
+
|
2407 |
+
$data['redirect'] = fw_current_url();
|
2408 |
+
|
2409 |
+
do_action('fw_extension_settings_form_saved:'. $extension->get_name(), $options_before_save);
|
2410 |
+
|
2411 |
+
return $data;
|
2412 |
+
}
|
2413 |
+
|
2414 |
+
/**
|
2415 |
+
* Download an extension
|
2416 |
+
*
|
2417 |
+
* global $wp_filesystem; must be initialized
|
2418 |
+
*
|
2419 |
+
* @param string $extension_name
|
2420 |
+
* @param array $data Extension data from the "available extensions" array
|
2421 |
+
* @return string|WP_Error WP Filesystem path to the downloaded directory
|
2422 |
+
*/
|
2423 |
+
private function download( $extension_name, $data ) {
|
2424 |
+
global $wp_filesystem;
|
2425 |
+
$wp_error_id = 'fw_extension_download';
|
2426 |
+
|
2427 |
+
if ( empty( $data['download'] ) ) {
|
2428 |
+
return new WP_Error(
|
2429 |
+
$wp_error_id,
|
2430 |
+
sprintf( __( 'Extension "%s" has no download sources.', 'fw' ), $this->get_extension_title( $extension_name ) )
|
2431 |
+
);
|
2432 |
+
}
|
2433 |
+
|
2434 |
+
$opts = array_merge( array(
|
2435 |
+
'item' => $extension_name,
|
2436 |
+
'extension_name' => $extension_name,
|
2437 |
+
'extension_title' => $this->get_extension_title( $extension_name )
|
2438 |
+
), $data['download']['opts'] );
|
2439 |
+
|
2440 |
+
if ( isset( $opts['plugin'] ) && is_plugin_active( $opts['plugin'] ) ) {
|
2441 |
+
return '';
|
2442 |
+
}
|
2443 |
+
|
2444 |
+
if ( ( $download_source = $this->get_download_source( $data ) ) && is_wp_error( $download_source ) ) {
|
2445 |
+
return $download_source;
|
2446 |
+
}
|
2447 |
+
|
2448 |
+
if ( isset( $opts['plugin'] ) ) {
|
2449 |
+
return $download_source->download( $opts, '' );
|
2450 |
+
}
|
2451 |
+
|
2452 |
+
// create temporary directory
|
2453 |
+
$wp_fs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path( $this->get_tmp_dir() );
|
2454 |
+
|
2455 |
+
if ( $wp_filesystem->exists( $wp_fs_tmp_dir ) ) {
|
2456 |
+
// just in case it already exists, clear everything, it may contain old files
|
2457 |
+
if ( ! $wp_filesystem->rmdir( $wp_fs_tmp_dir, true ) ) {
|
2458 |
+
return new WP_Error(
|
2459 |
+
$wp_error_id,
|
2460 |
+
sprintf( __( 'Cannot remove temporary directory: %s', 'fw' ), $wp_fs_tmp_dir )
|
2461 |
+
);
|
2462 |
+
}
|
2463 |
+
}
|
2464 |
+
|
2465 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $wp_fs_tmp_dir ) ) {
|
2466 |
+
return new WP_Error(
|
2467 |
+
$wp_error_id,
|
2468 |
+
sprintf( __( 'Cannot create temporary directory: %s', 'fw' ), $wp_fs_tmp_dir )
|
2469 |
+
);
|
2470 |
+
}
|
2471 |
+
|
2472 |
+
return $this->perform_zip_download( $download_source, $opts, $wp_fs_tmp_dir );
|
2473 |
+
}
|
2474 |
+
|
2475 |
+
private function perform_zip_download( FW_Ext_Download_Source $download_source, array $opts, $wp_fs_tmp_dir ) {
|
2476 |
+
$wp_error_id = 'fw_extension_download';
|
2477 |
+
|
2478 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
2479 |
+
global $wp_filesystem;
|
2480 |
+
|
2481 |
+
$zip_path = $wp_fs_tmp_dir . '/temp.zip';
|
2482 |
+
|
2483 |
+
$download_result = $download_source->download( $opts, $zip_path );
|
2484 |
+
|
2485 |
+
/**
|
2486 |
+
* Pass further the error, if the service returned one.
|
2487 |
+
*/
|
2488 |
+
if ( is_wp_error( $download_result ) ) {
|
2489 |
+
return $download_result;
|
2490 |
+
}
|
2491 |
+
|
2492 |
+
$extension_name = $opts['extension_name'];
|
2493 |
+
|
2494 |
+
$unzip_result = unzip_file(
|
2495 |
+
FW_WP_Filesystem::filesystem_path_to_real_path( $zip_path ),
|
2496 |
+
$wp_fs_tmp_dir
|
2497 |
+
);
|
2498 |
+
|
2499 |
+
if ( is_wp_error( $unzip_result ) ) {
|
2500 |
+
return $unzip_result;
|
2501 |
+
}
|
2502 |
+
|
2503 |
+
// remove zip file
|
2504 |
+
if ( ! $wp_filesystem->delete( $zip_path, false, 'f' ) ) {
|
2505 |
+
return new WP_Error(
|
2506 |
+
$wp_error_id,
|
2507 |
+
sprintf( __( 'Cannot remove the "%s" extension downloaded zip.', 'fw' ), $this->get_extension_title( $extension_name ) )
|
2508 |
+
);
|
2509 |
+
}
|
2510 |
+
|
2511 |
+
$unzipped_dir_files = $wp_filesystem->dirlist( $wp_fs_tmp_dir );
|
2512 |
+
|
2513 |
+
if ( ! $unzipped_dir_files ) {
|
2514 |
+
return new WP_Error(
|
2515 |
+
$wp_error_id,
|
2516 |
+
__( 'Cannot access the unzipped directory files.', 'fw' )
|
2517 |
+
);
|
2518 |
+
}
|
2519 |
+
|
2520 |
+
/**
|
2521 |
+
* get first found directory
|
2522 |
+
* (if everything worked well, there should be only one directory)
|
2523 |
+
*/
|
2524 |
+
foreach ( $unzipped_dir_files as $file ) {
|
2525 |
+
if ( $file['type'] == 'd' ) {
|
2526 |
+
return $wp_fs_tmp_dir . '/' . $file['name'];
|
2527 |
+
}
|
2528 |
+
}
|
2529 |
+
|
2530 |
+
return new WP_Error(
|
2531 |
+
$wp_error_id,
|
2532 |
+
sprintf( __( 'The unzipped "%s" extension directory not found.', 'fw' ), $this->get_extension_title( $extension_name ) )
|
2533 |
+
);
|
2534 |
+
}
|
2535 |
+
|
2536 |
+
/**
|
2537 |
+
* @param $set
|
2538 |
+
*
|
2539 |
+
* @return FW_Ext_Download_Source|WP_Error
|
2540 |
+
*/
|
2541 |
+
private function get_download_source( $set ) {
|
2542 |
+
require_once dirname( __FILE__ ) . '/includes/download-source/types/init.php';
|
2543 |
+
|
2544 |
+
$register = new _FW_Ext_Download_Source_Register( self::get_access_key()->get_key() );
|
2545 |
+
|
2546 |
+
/**
|
2547 |
+
* Register download sources for extensions.
|
2548 |
+
*
|
2549 |
+
* Usage:
|
2550 |
+
* $download_source = new FW_Ext_Download_Source();
|
2551 |
+
* $register->register($download_source);
|
2552 |
+
*/
|
2553 |
+
do_action( 'fw_register_ext_download_sources', $register );
|
2554 |
+
|
2555 |
+
$download_source = $register->_get_type( self::get_access_key(), $set['download']['source'] );
|
2556 |
+
|
2557 |
+
if ( ! $download_source ) {
|
2558 |
+
$download_source = new WP_Error( 'invalid_dl_source', sprintf( esc_html__( 'Invalid download source: %s', 'fw' ), $set['download']['source'] ) );
|
2559 |
+
}
|
2560 |
+
|
2561 |
+
return $download_source;
|
2562 |
+
}
|
2563 |
+
|
2564 |
+
/**
|
2565 |
+
* Merge the downloaded extension directory with the existing directory
|
2566 |
+
*
|
2567 |
+
* @param string $source_wp_fs_dir Downloaded extension directory
|
2568 |
+
* @param string $destination_wp_fs_dir
|
2569 |
+
*
|
2570 |
+
* @return null|WP_Error
|
2571 |
+
*/
|
2572 |
+
private function merge_extension( $source_wp_fs_dir, $destination_wp_fs_dir ) {
|
2573 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
2574 |
+
global $wp_filesystem;
|
2575 |
+
|
2576 |
+
$wp_error_id = 'fw_extensions_merge';
|
2577 |
+
|
2578 |
+
// check source
|
2579 |
+
{
|
2580 |
+
$source_files = $wp_filesystem->dirlist( $source_wp_fs_dir );
|
2581 |
+
|
2582 |
+
if ( $source_files === false ) {
|
2583 |
+
return new WP_Error(
|
2584 |
+
$wp_error_id,
|
2585 |
+
sprintf( __( 'Cannot read directory "%s".', 'fw' ), $source_wp_fs_dir )
|
2586 |
+
);
|
2587 |
+
}
|
2588 |
+
|
2589 |
+
if ( empty( $source_files ) ) {
|
2590 |
+
return; // directory is empty, nothing to move
|
2591 |
+
}
|
2592 |
+
}
|
2593 |
+
|
2594 |
+
/**
|
2595 |
+
* Prepare destination directory
|
2596 |
+
* Remove everything except the extensions/ directory
|
2597 |
+
*/
|
2598 |
+
if ( $wp_filesystem->exists( $destination_wp_fs_dir ) ) {
|
2599 |
+
$destination_files = $wp_filesystem->dirlist( $destination_wp_fs_dir );
|
2600 |
+
|
2601 |
+
if ( $destination_files === false ) {
|
2602 |
+
return new WP_Error(
|
2603 |
+
$wp_error_id,
|
2604 |
+
sprintf( __( 'Cannot read directory "%s".', 'fw' ), $destination_wp_fs_dir )
|
2605 |
+
);
|
2606 |
+
}
|
2607 |
+
|
2608 |
+
if ( ! empty( $destination_files ) ) {
|
2609 |
+
if (
|
2610 |
+
count( $source_files ) == 1
|
2611 |
+
&&
|
2612 |
+
( $file = reset( $source_files ) )
|
2613 |
+
&&
|
2614 |
+
$file['name'] === 'extensions'
|
2615 |
+
&&
|
2616 |
+
$file['type'] === 'd'
|
2617 |
+
) {
|
2618 |
+
/**
|
2619 |
+
* Source extension is empty
|
2620 |
+
* It happens when you merge a directory which contains child extensions
|
2621 |
+
* Do not delete current destination files, just go in the next child extensions level
|
2622 |
+
* Used by https://github.com/ThemeFuse/Unyson/issues/1874
|
2623 |
+
*/
|
2624 |
+
} else {
|
2625 |
+
// the directory contains some files, delete everything
|
2626 |
+
foreach ( $destination_files as $file ) {
|
2627 |
+
if ( $file['name'] === 'extensions' && $file['type'] === 'd' ) {
|
2628 |
+
// do not touch the extensions/ directory
|
2629 |
+
continue;
|
2630 |
+
}
|
2631 |
+
|
2632 |
+
if ( ! $wp_filesystem->delete(
|
2633 |
+
$destination_wp_fs_dir . '/' . $file['name'],
|
2634 |
+
true,
|
2635 |
+
$file['type']
|
2636 |
+
) ) {
|
2637 |
+
return new WP_Error(
|
2638 |
+
$wp_error_id,
|
2639 |
+
sprintf(
|
2640 |
+
__( 'Cannot delete "%s".', 'fw' ),
|
2641 |
+
$destination_wp_fs_dir . '/' . $file['name']
|
2642 |
+
)
|
2643 |
+
);
|
2644 |
+
}
|
2645 |
+
}
|
2646 |
+
}
|
2647 |
+
|
2648 |
+
unset( $destination_files );
|
2649 |
+
}
|
2650 |
+
} else {
|
2651 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $destination_wp_fs_dir ) ) {
|
2652 |
+
return new WP_Error(
|
2653 |
+
$wp_error_id,
|
2654 |
+
sprintf( __( 'Cannot create the "%s" directory.', 'fw' ), $destination_wp_fs_dir )
|
2655 |
+
);
|
2656 |
+
}
|
2657 |
+
}
|
2658 |
+
|
2659 |
+
// Move files from source to destination
|
2660 |
+
{
|
2661 |
+
$has_sub_extensions = false;
|
2662 |
+
|
2663 |
+
foreach ( $source_files as $file ) {
|
2664 |
+
if ( $file['name'] === 'extensions' && $file['type'] === 'd' ) {
|
2665 |
+
$has_sub_extensions = true; // do not touch the extensions/ directory
|
2666 |
+
continue;
|
2667 |
+
}
|
2668 |
+
|
2669 |
+
if ( ! $wp_filesystem->move( $source_wp_fs_dir . '/' . $file['name'], $destination_wp_fs_dir . '/' . $file['name'] ) ) {
|
2670 |
+
return new WP_Error(
|
2671 |
+
$wp_error_id,
|
2672 |
+
sprintf(
|
2673 |
+
__( 'Cannot move "%s" to "%s".', 'fw' ),
|
2674 |
+
$source_wp_fs_dir . '/' . $file['name'],
|
2675 |
+
$destination_wp_fs_dir . '/' . $file['name']
|
2676 |
+
)
|
2677 |
+
);
|
2678 |
+
}
|
2679 |
+
}
|
2680 |
+
|
2681 |
+
unset( $source_files );
|
2682 |
+
}
|
2683 |
+
|
2684 |
+
if ( ! $has_sub_extensions ) {
|
2685 |
+
return;
|
2686 |
+
}
|
2687 |
+
|
2688 |
+
$sub_extensions = $wp_filesystem->dirlist( $source_wp_fs_dir . '/extensions' );
|
2689 |
+
|
2690 |
+
if ( $sub_extensions === false ) {
|
2691 |
+
return new WP_Error(
|
2692 |
+
$wp_error_id,
|
2693 |
+
sprintf( __( 'Cannot read directory "%s".', 'fw' ), $source_wp_fs_dir . '/extensions' )
|
2694 |
+
);
|
2695 |
+
}
|
2696 |
+
|
2697 |
+
if ( empty( $sub_extensions ) ) {
|
2698 |
+
// directory is empty, nothing to remove
|
2699 |
+
return;
|
2700 |
+
}
|
2701 |
+
|
2702 |
+
foreach ( $sub_extensions as $file ) {
|
2703 |
+
if ( $file['type'] !== 'd' ) {
|
2704 |
+
// wrong, only directories must exist in the extensions/ directory
|
2705 |
+
continue;
|
2706 |
+
}
|
2707 |
+
|
2708 |
+
$merge_result = $this->merge_extension(
|
2709 |
+
$source_wp_fs_dir . '/extensions/' . $file['name'],
|
2710 |
+
$destination_wp_fs_dir . '/extensions/' . $file['name']
|
2711 |
+
);
|
2712 |
+
|
2713 |
+
if ( is_wp_error( $merge_result ) ) {
|
2714 |
+
return $merge_result;
|
2715 |
+
}
|
2716 |
+
}
|
2717 |
+
}
|
2718 |
+
|
2719 |
+
/**
|
2720 |
+
* @since 2.6.9
|
2721 |
+
*/
|
2722 |
+
public function get_supported_extensions()
|
2723 |
+
{
|
2724 |
+
$supported_extensions = fw()->theme->manifest->get('supported_extensions', array());
|
2725 |
+
|
2726 |
+
// Add Available Extensions registered by the theme
|
2727 |
+
foreach ($this->get_available_extensions() as $name => $extension) {
|
2728 |
+
if (isset($extension['theme']) && $extension['theme']) {
|
2729 |
+
$supported_extensions[$name] = array();
|
2730 |
+
}
|
2731 |
+
}
|
2732 |
+
|
2733 |
+
if (empty($supported_extensions)) {
|
2734 |
+
return array();
|
2735 |
+
}
|
2736 |
+
|
2737 |
+
// remove not available extensions
|
2738 |
+
$supported_extensions = array_intersect_key($supported_extensions, $this->get_available_extensions());
|
2739 |
+
|
2740 |
+
if (empty($supported_extensions)) {
|
2741 |
+
return array();
|
2742 |
+
}
|
2743 |
+
|
2744 |
+
if (empty($supported_extensions)) {
|
2745 |
+
return array();
|
2746 |
+
}
|
2747 |
+
|
2748 |
+
return $supported_extensions;
|
2749 |
+
}
|
2750 |
+
|
2751 |
+
/**
|
2752 |
+
* @since 2.6.9
|
2753 |
+
*/
|
2754 |
+
public function get_supported_extensions_for_install()
|
2755 |
+
{
|
2756 |
+
// remove already installed extensions
|
2757 |
+
return array_diff_key(
|
2758 |
+
$this->get_supported_extensions(),
|
2759 |
+
$this->get_installed_extensions()
|
2760 |
+
);
|
2761 |
+
}
|
2762 |
+
|
2763 |
+
/**
|
2764 |
+
* @param $actions
|
2765 |
+
* @return array
|
2766 |
+
* @internal
|
2767 |
+
*/
|
2768 |
+
public function _filter_plugin_action_list($actions)
|
2769 |
+
{
|
2770 |
+
return array_merge(
|
2771 |
+
array(
|
2772 |
+
'fw-extensions' => fw_html_tag('a', array(
|
2773 |
+
'href' => $this->get_link(),
|
2774 |
+
), fw()->manifest->get_name()),
|
2775 |
+
),
|
2776 |
+
$actions
|
2777 |
+
);
|
2778 |
+
}
|
2779 |
+
|
2780 |
+
/**
|
2781 |
+
* @return string Extensions page link
|
2782 |
+
*/
|
2783 |
+
private function get_link()
|
2784 |
+
{
|
2785 |
+
static $cache_link = null;
|
2786 |
+
|
2787 |
+
if ($cache_link === null) {
|
2788 |
+
$cache_link = menu_page_url( $this->get_page_slug(), false );
|
2789 |
+
|
2790 |
+
// https://core.trac.wordpress.org/ticket/28226
|
2791 |
+
if (is_multisite() && is_network_admin()) {
|
2792 |
+
$cache_link = self_admin_url(
|
2793 |
+
// extract relative link
|
2794 |
+
preg_replace('/^'. preg_quote(admin_url(), '/') .'/', '', $cache_link)
|
2795 |
+
);
|
2796 |
+
}
|
2797 |
+
}
|
2798 |
+
|
2799 |
+
return $cache_link;
|
2800 |
+
}
|
2801 |
+
|
2802 |
+
/**
|
2803 |
+
* @param array $skip_extensions {'ext' => mixed}
|
2804 |
+
* @param array $check_for_deps ['ext', 'ext', ...] Extensions to check if has in dependencies the used extensions
|
2805 |
+
*
|
2806 |
+
* @return array
|
2807 |
+
*/
|
2808 |
+
private function get_used_extensions($skip_extensions, $check_for_deps)
|
2809 |
+
{
|
2810 |
+
$used_extensions = array();
|
2811 |
+
|
2812 |
+
$installed_extensions = $this->get_installed_extensions();
|
2813 |
+
|
2814 |
+
foreach ($installed_extensions as $inst_ext_name => &$inst_ext_data) {
|
2815 |
+
if (isset($skip_extensions[ $inst_ext_name ])) {
|
2816 |
+
continue;
|
2817 |
+
}
|
2818 |
+
|
2819 |
+
if (isset($used_extensions[$inst_ext_name])) {
|
2820 |
+
// already marked as used
|
2821 |
+
continue;
|
2822 |
+
}
|
2823 |
+
|
2824 |
+
do {
|
2825 |
+
foreach ($check_for_deps as $deps_ext) {
|
2826 |
+
if (isset($skip_extensions[$deps_ext])) {
|
2827 |
+
continue;
|
2828 |
+
}
|
2829 |
+
|
2830 |
+
if (false !== fw_akg(
|
2831 |
+
'requirements/extensions/'. $inst_ext_name,
|
2832 |
+
$installed_extensions[$deps_ext]['manifest'],
|
2833 |
+
false
|
2834 |
+
)) {
|
2835 |
+
// is required by an active extension
|
2836 |
+
break 2;
|
2837 |
+
}
|
2838 |
+
}
|
2839 |
+
|
2840 |
+
if ( true === fw_akg(
|
2841 |
+
'standalone',
|
2842 |
+
$inst_ext_data['manifest'],
|
2843 |
+
$this->manifest_default_values['standalone']
|
2844 |
+
) ) {
|
2845 |
+
// can exist alone
|
2846 |
+
break;
|
2847 |
+
}
|
2848 |
+
|
2849 |
+
// not used
|
2850 |
+
continue 2;
|
2851 |
+
} while(false);
|
2852 |
+
|
2853 |
+
$used_extensions[$inst_ext_name] = array();
|
2854 |
+
|
2855 |
+
// Set all sub-extensions as used
|
2856 |
+
foreach ($this->collect_sub_extensions($inst_ext_name, $installed_extensions) as $sub_extension_name => $sub_extension_data) {
|
2857 |
+
if (isset($skip_extensions[$sub_extension_name])) {
|
2858 |
+
continue;
|
2859 |
+
}
|
2860 |
+
|
2861 |
+
$used_extensions[ $sub_extension_name ] = array();
|
2862 |
+
}
|
2863 |
+
|
2864 |
+
// Set all parents as used
|
2865 |
+
{
|
2866 |
+
$current_parent = $inst_ext_name;
|
2867 |
+
while ($current_parent = $installed_extensions[$current_parent]['parent']) {
|
2868 |
+
$used_extensions[$current_parent] = array();
|
2869 |
+
}
|
2870 |
+
}
|
2871 |
+
}
|
2872 |
+
unset($inst_ext_data);
|
2873 |
+
|
2874 |
+
// remove all skipped extensions and sub-extension from used extensions
|
2875 |
+
foreach (array_keys($skip_extensions) as $skip_extension_name) {
|
2876 |
+
unset($used_extensions[$skip_extension_name]);
|
2877 |
+
|
2878 |
+
if (isset($installed_extensions[$skip_extension_name])) {
|
2879 |
+
foreach ($this->collect_sub_extensions($skip_extension_name, $installed_extensions) as $sub_extension_name => $sub_extension_data) {
|
2880 |
+
unset($used_extensions[$sub_extension_name]);
|
2881 |
+
}
|
2882 |
+
}
|
2883 |
+
}
|
2884 |
+
|
2885 |
+
return $used_extensions;
|
2886 |
+
}
|
2887 |
+
|
2888 |
+
/**
|
2889 |
+
* @internal
|
2890 |
+
*/
|
2891 |
+
public function _action_admin_footer()
|
2892 |
+
{
|
2893 |
+
$this->activate_hidden_standalone_extensions();
|
2894 |
+
}
|
2895 |
+
|
2896 |
+
public function get_extension_title($extension_name)
|
2897 |
+
{
|
2898 |
+
$installed_extensions = $this->get_installed_extensions();
|
2899 |
+
|
2900 |
+
if (isset($installed_extensions[$extension_name])) {
|
2901 |
+
return fw_akg('name', $installed_extensions[$extension_name]['manifest'], fw_id_to_title($extension_name));
|
2902 |
+
}
|
2903 |
+
|
2904 |
+
unset($installed_extensions);
|
2905 |
+
|
2906 |
+
$available_extensions = $this->get_available_extensions();
|
2907 |
+
|
2908 |
+
if (isset($available_extensions[$extension_name])) {
|
2909 |
+
return $available_extensions[$extension_name]['name'];
|
2910 |
+
}
|
2911 |
+
|
2912 |
+
return fw_id_to_title($extension_name);
|
2913 |
+
}
|
2914 |
+
|
2915 |
+
public function is_extensions_page()
|
2916 |
+
{
|
2917 |
+
$current_screen = get_current_screen();
|
2918 |
+
|
2919 |
+
if (empty($current_screen)) {
|
2920 |
+
return false;
|
2921 |
+
}
|
2922 |
+
|
2923 |
+
return (
|
2924 |
+
property_exists($current_screen, 'base') && strpos($current_screen->base, $this->get_page_slug()) !== false
|
2925 |
+
&&
|
2926 |
+
property_exists($current_screen, 'id') && strpos($current_screen->id, $this->get_page_slug()) !== false
|
2927 |
+
&&
|
2928 |
+
!isset($_GET['sub-page'])
|
2929 |
+
);
|
2930 |
+
}
|
2931 |
+
|
2932 |
+
public function is_extension_page()
|
2933 |
+
{
|
2934 |
+
$current_screen = get_current_screen();
|
2935 |
+
|
2936 |
+
if (empty($current_screen)) {
|
2937 |
+
return false;
|
2938 |
+
}
|
2939 |
+
|
2940 |
+
return (
|
2941 |
+
property_exists($current_screen, 'base') && strpos($current_screen->base, $this->get_page_slug()) !== false
|
2942 |
+
&&
|
2943 |
+
property_exists($current_screen, 'id') && strpos($current_screen->id, $this->get_page_slug()) !== false
|
2944 |
+
&&
|
2945 |
+
isset($_GET['sub-page']) && $_GET['sub-page'] === 'extension'
|
2946 |
+
);
|
2947 |
+
}
|
2948 |
+
|
2949 |
+
/**
|
2950 |
+
* @internal
|
2951 |
+
*/
|
2952 |
+
public function _action_enqueue_scripts()
|
2953 |
+
{
|
2954 |
+
wp_enqueue_style(
|
2955 |
+
'fw-extensions-menu-icon',
|
2956 |
+
$this->get_uri('/static/unyson-font-icon/style.css'),
|
2957 |
+
array(),
|
2958 |
+
fw()->manifest->get_version()
|
2959 |
+
);
|
2960 |
+
|
2961 |
+
/**
|
2962 |
+
* Enqueue only on Extensions List page
|
2963 |
+
*/
|
2964 |
+
if ($this->is_extensions_page()) {
|
2965 |
+
wp_enqueue_style(
|
2966 |
+
'fw-extensions-page',
|
2967 |
+
$this->get_uri('/static/extensions-page.css'),
|
2968 |
+
array(
|
2969 |
+
'fw',
|
2970 |
+
'fw-unycon', 'font-awesome', // in case some extension has font-icon thumbnail
|
2971 |
+
),
|
2972 |
+
fw()->manifest->get_version()
|
2973 |
+
);
|
2974 |
+
wp_enqueue_script(
|
2975 |
+
'fw-extensions-page',
|
2976 |
+
$this->get_uri('/static/extensions-page.js'),
|
2977 |
+
array('fw'),
|
2978 |
+
fw()->manifest->get_version(),
|
2979 |
+
true
|
2980 |
+
);
|
2981 |
+
wp_localize_script('fw-extensions-page', '_fw_extensions_script_data', array(
|
2982 |
+
'link' => $this->get_link(),
|
2983 |
+
));
|
2984 |
+
|
2985 |
+
/**
|
2986 |
+
* this is needed for fw.soleModal design
|
2987 |
+
* it is displayed when extension ajax install returns an error
|
2988 |
+
*/
|
2989 |
+
wp_enqueue_media();
|
2990 |
+
}
|
2991 |
+
|
2992 |
+
if ($this->is_extension_page()) {
|
2993 |
+
wp_enqueue_style(
|
2994 |
+
'fw-extension-page',
|
2995 |
+
$this->get_uri('/static/extension-page.css'),
|
2996 |
+
array('fw'),
|
2997 |
+
fw()->manifest->get_version()
|
2998 |
+
);
|
2999 |
+
wp_enqueue_script(
|
3000 |
+
'fw-extension-page',
|
3001 |
+
$this->get_uri('/static/extension-page.js'),
|
3002 |
+
array('fw'),
|
3003 |
+
fw()->manifest->get_version(),
|
3004 |
+
true
|
3005 |
+
);
|
3006 |
+
|
3007 |
+
/**
|
3008 |
+
* Enqueue extension settings options static
|
3009 |
+
*/
|
3010 |
+
if (
|
3011 |
+
isset($_GET['extension'])
|
3012 |
+
&&
|
3013 |
+
is_string($extension_name = $_GET['extension'])
|
3014 |
+
&&
|
3015 |
+
fw()->extensions->get($extension_name)
|
3016 |
+
&&
|
3017 |
+
($extension_settings_options = fw()->extensions->get($extension_name)->get_settings_options())
|
3018 |
+
) {
|
3019 |
+
fw()->backend->enqueue_options_static($extension_settings_options);
|
3020 |
+
}
|
3021 |
+
}
|
3022 |
+
}
|
3023 |
+
|
3024 |
+
private function activate_theme_extensions()
|
3025 |
+
{
|
3026 |
+
$db_active_extensions = fw()->extensions->_get_db_active_extensions();
|
3027 |
+
|
3028 |
+
foreach ($this->get_installed_extensions() as $extension_name => $extension) {
|
3029 |
+
if ($extension['is']['theme']) {
|
3030 |
+
$db_active_extensions[ $extension_name ] = array();
|
3031 |
+
}
|
3032 |
+
}
|
3033 |
+
|
3034 |
+
update_option(
|
3035 |
+
fw()->extensions->_get_active_extensions_db_option_name(),
|
3036 |
+
$db_active_extensions
|
3037 |
+
);
|
3038 |
+
}
|
3039 |
+
|
3040 |
+
/**
|
3041 |
+
* @internal
|
3042 |
+
*/
|
3043 |
+
public function _action_theme_switch()
|
3044 |
+
{
|
3045 |
+
$this->activate_theme_extensions();
|
3046 |
+
$this->activate_extensions(
|
3047 |
+
array_fill_keys(
|
3048 |
+
array_keys(fw()->theme->manifest->get('supported_extensions', array())),
|
3049 |
+
array()
|
3050 |
+
)
|
3051 |
+
);
|
3052 |
+
}
|
3053 |
+
|
3054 |
+
/**
|
3055 |
+
* @param array $collected The found extensions {'extension_name' => array()}
|
3056 |
+
* @param array $extensions {'extension_name' => array()}
|
3057 |
+
* @param bool $check_all Check all extensions or only active extensions
|
3058 |
+
*/
|
3059 |
+
private function collect_extensions_that_requires(&$collected, $extensions, $check_all = false)
|
3060 |
+
{
|
3061 |
+
if (empty($extensions)) {
|
3062 |
+
return;
|
3063 |
+
}
|
3064 |
+
|
3065 |
+
$found_extensions = array();
|
3066 |
+
|
3067 |
+
foreach ($this->get_installed_extensions() as $extension_name => $extension_data) {
|
3068 |
+
if (isset($collected[$extension_name])) {
|
3069 |
+
continue;
|
3070 |
+
}
|
3071 |
+
|
3072 |
+
if (!$check_all) {
|
3073 |
+
if (!fw_ext($extension_name)) {
|
3074 |
+
continue;
|
3075 |
+
}
|
3076 |
+
}
|
3077 |
+
|
3078 |
+
if (
|
3079 |
+
array_intersect_key(
|
3080 |
+
$extensions,
|
3081 |
+
fw_akg(
|
3082 |
+
'requirements/extensions',
|
3083 |
+
$extension_data['manifest'],
|
3084 |
+
array()
|
3085 |
+
)
|
3086 |
+
)
|
3087 |
+
) {
|
3088 |
+
$found_extensions[$extension_name] = $collected[$extension_name] = array();
|
3089 |
+
}
|
3090 |
+
}
|
3091 |
+
|
3092 |
+
$this->collect_extensions_that_requires($collected, $found_extensions, $check_all);
|
3093 |
+
}
|
3094 |
+
|
3095 |
+
/**
|
3096 |
+
* Get extension settings page link
|
3097 |
+
* @param string $extension_name
|
3098 |
+
* @return string
|
3099 |
+
*/
|
3100 |
+
public function get_extension_link($extension_name)
|
3101 |
+
{
|
3102 |
+
return $this->get_link() .'&sub-page=extension&extension='. $extension_name;
|
3103 |
+
}
|
3104 |
+
|
3105 |
+
/**
|
3106 |
+
* @param string $extension_name
|
3107 |
+
* @return array|WP_Error Extensions to merge with db active extensions list
|
3108 |
+
*/
|
3109 |
+
private function get_extensions_for_activation($extension_name)
|
3110 |
+
{
|
3111 |
+
$installed_extensions = $this->get_installed_extensions();
|
3112 |
+
|
3113 |
+
$wp_error_id = 'fw_ext_activation';
|
3114 |
+
|
3115 |
+
if (!isset($installed_extensions[$extension_name])) {
|
3116 |
+
return new WP_Error($wp_error_id,
|
3117 |
+
sprintf(
|
3118 |
+
__('Cannot activate the %s extension because it is not installed. %s', 'fw'),
|
3119 |
+
$this->get_extension_title($extension_name),
|
3120 |
+
fw_html_tag('a', array(
|
3121 |
+
'href' => $this->get_link() .'&sub-page=install&extension='. $extension_name
|
3122 |
+
), __('Install', 'fw'))
|
3123 |
+
)
|
3124 |
+
);
|
3125 |
+
}
|
3126 |
+
|
3127 |
+
{
|
3128 |
+
$extension_parents = array($extension_name);
|
3129 |
+
|
3130 |
+
$current_parent = $extension_name;
|
3131 |
+
while ($current_parent = $installed_extensions[$current_parent]['parent']) {
|
3132 |
+
$extension_parents[] = $current_parent;
|
3133 |
+
}
|
3134 |
+
|
3135 |
+
$extension_parents = array_reverse($extension_parents);
|
3136 |
+
}
|
3137 |
+
|
3138 |
+
$extensions = array();
|
3139 |
+
|
3140 |
+
foreach ($extension_parents as $parent_extension_name) {
|
3141 |
+
$extensions[ $parent_extension_name ] = array();
|
3142 |
+
}
|
3143 |
+
|
3144 |
+
// search sub-extensions
|
3145 |
+
foreach ($this->collect_sub_extensions($extension_name, $installed_extensions) as $sub_extension_name => $sub_extension_data) {
|
3146 |
+
$extensions[ $sub_extension_name ] = array();
|
3147 |
+
}
|
3148 |
+
|
3149 |
+
// search required extensions
|
3150 |
+
{
|
3151 |
+
$pending_required_search = $extensions;
|
3152 |
+
|
3153 |
+
while ($pending_required_search) {
|
3154 |
+
foreach (array_keys($pending_required_search) as $pend_req_extension_name) {
|
3155 |
+
unset($pending_required_search[$pend_req_extension_name]);
|
3156 |
+
|
3157 |
+
unset($required_extensions); // reset reference
|
3158 |
+
$required_extensions = array();
|
3159 |
+
$this->collect_required_extensions($pend_req_extension_name, $installed_extensions, $required_extensions);
|
3160 |
+
|
3161 |
+
foreach ($required_extensions as $required_extension_name => $required_extension_data) {
|
3162 |
+
if (!isset($installed_extensions[$required_extension_name])) {
|
3163 |
+
return new WP_Error($wp_error_id,
|
3164 |
+
sprintf(
|
3165 |
+
__('Cannot activate the %s extension because it is not installed. %s', 'fw'),
|
3166 |
+
$this->get_extension_title($required_extension_name),
|
3167 |
+
fw_html_tag('a', array(
|
3168 |
+
'href' => $this->get_link() .'&sub-page=install&extension='. $required_extension_name
|
3169 |
+
), __('Install', 'fw'))
|
3170 |
+
)
|
3171 |
+
);
|
3172 |
+
}
|
3173 |
+
|
3174 |
+
$extensions[$required_extension_name] = array();
|
3175 |
+
|
3176 |
+
// search sub-extensions
|
3177 |
+
foreach ($this->collect_sub_extensions($required_extension_name, $installed_extensions) as $sub_extension_name => $sub_extension_data) {
|
3178 |
+
if (isset($extensions[$sub_extension_name])) {
|
3179 |
+
continue;
|
3180 |
+
}
|
3181 |
+
|
3182 |
+
$extensions[$sub_extension_name] = array();
|
3183 |
+
|
3184 |
+
$pending_required_search[$sub_extension_name] = array();
|
3185 |
+
}
|
3186 |
+
}
|
3187 |
+
}
|
3188 |
+
}
|
3189 |
+
}
|
3190 |
+
|
3191 |
+
return $extensions;
|
3192 |
+
}
|
3193 |
+
|
3194 |
+
/**
|
3195 |
+
* @internal
|
3196 |
+
*/
|
3197 |
+
public function _action_admin_notices() {
|
3198 |
+
$should_notify = apply_filters(
|
3199 |
+
'fw_notify_about_missing_extensions',
|
3200 |
+
true
|
3201 |
+
);
|
3202 |
+
|
3203 |
+
/**
|
3204 |
+
* In v2.4.12 was done a terrible mistake https://github.com/ThemeFuse/Unyson-Extensions-Approval/issues/160
|
3205 |
+
* Show a warning with link to install theme supported extensions
|
3206 |
+
*/
|
3207 |
+
if (
|
3208 |
+
$should_notify
|
3209 |
+
&&
|
3210 |
+
!isset($_GET['supported']) // already on 'Install Supported Extensions' page
|
3211 |
+
&&
|
3212 |
+
$this->can_install()
|
3213 |
+
&&
|
3214 |
+
(($installed_extensions = $this->get_installed_extensions()) || true)
|
3215 |
+
&&
|
3216 |
+
!isset($installed_extensions['page-builder'])
|
3217 |
+
&&
|
3218 |
+
$this->get_supported_extensions_for_install()
|
3219 |
+
) {
|
3220 |
+
echo '<div class="error"> <p>'
|
3221 |
+
, fw_html_tag('a', array('href' => $this->get_link() .'&sub-page=install&supported'),
|
3222 |
+
__('Install theme compatible extensions', 'fw'))
|
3223 |
+
, '</p></div>';
|
3224 |
+
}
|
3225 |
+
}
|
3226 |
+
|
3227 |
+
/**
|
3228 |
+
* Copy Theme Available Extensions to a tmp directory
|
3229 |
+
* Used before theme update
|
3230 |
+
* @since 2.6.0
|
3231 |
+
* @return null|WP_Error
|
3232 |
+
*/
|
3233 |
+
public function theme_available_extensions_copy() {
|
3234 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
3235 |
+
global $wp_filesystem;
|
3236 |
+
|
3237 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
3238 |
+
return new WP_Error(
|
3239 |
+
'fs_not_initialized',
|
3240 |
+
__('WP Filesystem is not initialized', 'fw')
|
3241 |
+
);
|
3242 |
+
}
|
3243 |
+
|
3244 |
+
// Prepare temporary directory
|
3245 |
+
{
|
3246 |
+
$wpfs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
3247 |
+
$this->get_tmp_dir('/theme-ext')
|
3248 |
+
);
|
3249 |
+
|
3250 |
+
if (
|
3251 |
+
$wp_filesystem->exists( $wpfs_tmp_dir )
|
3252 |
+
&&
|
3253 |
+
! $wp_filesystem->rmdir( $wpfs_tmp_dir, true )
|
3254 |
+
) {
|
3255 |
+
return new WP_Error(
|
3256 |
+
'tmp_dir_rm_fail',
|
3257 |
+
sprintf(__('Temporary directory cannot be removed: %s', 'fw'), $wpfs_tmp_dir)
|
3258 |
+
);
|
3259 |
+
}
|
3260 |
+
|
3261 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $wpfs_tmp_dir ) ) {
|
3262 |
+
return new WP_Error(
|
3263 |
+
'tmp_dir_rm_fail',
|
3264 |
+
sprintf(__('Temporary directory cannot be created: %s', 'fw'), $wpfs_tmp_dir)
|
3265 |
+
);
|
3266 |
+
}
|
3267 |
+
}
|
3268 |
+
|
3269 |
+
$available_extensions = $this->get_available_extensions();
|
3270 |
+
$installed_extensions = $this->get_installed_extensions(true);
|
3271 |
+
$base_dir = fw_get_template_customizations_directory('/extensions');
|
3272 |
+
|
3273 |
+
foreach ($installed_extensions as $name => $ext) {
|
3274 |
+
if ( ! (
|
3275 |
+
isset($available_extensions[$name])
|
3276 |
+
&&
|
3277 |
+
isset($available_extensions[$name]['theme'])
|
3278 |
+
&&
|
3279 |
+
$available_extensions[$name]['theme']
|
3280 |
+
) ) {
|
3281 |
+
continue;
|
3282 |
+
}
|
3283 |
+
|
3284 |
+
if ( ($rel_path = preg_replace('/^'. preg_quote($base_dir, '/') .'/', '', $ext['path'])) === $base_dir ) {
|
3285 |
+
return new WP_Error(
|
3286 |
+
'rel_path_failed',
|
3287 |
+
sprintf(__('Failed to extract relative directory from: %s', 'fw'), $ext['path'])
|
3288 |
+
);
|
3289 |
+
}
|
3290 |
+
|
3291 |
+
if ( ($wpfs_path = FW_WP_Filesystem::real_path_to_filesystem_path($ext['path'])) === false) {
|
3292 |
+
return new WP_Error(
|
3293 |
+
'real_to_wpfs_filed',
|
3294 |
+
sprintf(__('Failed to extract relative directory from: %s', 'fw'), $ext['path'])
|
3295 |
+
);
|
3296 |
+
}
|
3297 |
+
|
3298 |
+
$wpfs_dest_dir = $wpfs_tmp_dir . $rel_path;
|
3299 |
+
|
3300 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive($wpfs_dest_dir) ) {
|
3301 |
+
return new WP_Error(
|
3302 |
+
'dest_dir_mk_fail',
|
3303 |
+
sprintf(__('Failed to create directory %s', 'fw'), $wpfs_dest_dir)
|
3304 |
+
);
|
3305 |
+
}
|
3306 |
+
|
3307 |
+
if ( is_wp_error( $copy_result = copy_dir($wpfs_path, $wpfs_dest_dir) ) ) {
|
3308 |
+
/** @var WP_Error $copy_result */
|
3309 |
+
return new WP_Error(
|
3310 |
+
'ext_copy_failed',
|
3311 |
+
sprintf( __('Failed to copy extension to %s', 'fw'), $wpfs_dest_dir )
|
3312 |
+
);
|
3313 |
+
}
|
3314 |
+
}
|
3315 |
+
}
|
3316 |
+
|
3317 |
+
/**
|
3318 |
+
* Copy Theme Available Extensions from tmp directory to theme
|
3319 |
+
* Used after theme update
|
3320 |
+
* @since 2.6.0
|
3321 |
+
* @return null|WP_Error
|
3322 |
+
*/
|
3323 |
+
public function theme_available_extensions_restore() {
|
3324 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
3325 |
+
global $wp_filesystem;
|
3326 |
+
|
3327 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
3328 |
+
return new WP_Error(
|
3329 |
+
'fs_not_initialized',
|
3330 |
+
__('WP Filesystem is not initialized', 'fw')
|
3331 |
+
);
|
3332 |
+
}
|
3333 |
+
|
3334 |
+
if ( ! $wp_filesystem->exists(
|
3335 |
+
$wpfs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
3336 |
+
$this->get_tmp_dir('/theme-ext')
|
3337 |
+
)
|
3338 |
+
) ) {
|
3339 |
+
return new WP_Error(
|
3340 |
+
'no_tmp_dir',
|
3341 |
+
sprintf(__('Temporary directory does not exist: %s', 'fw'), $wpfs_tmp_dir)
|
3342 |
+
);
|
3343 |
+
}
|
3344 |
+
|
3345 |
+
/**
|
3346 |
+
* Fixes the case when the theme path before update was
|
3347 |
+
* wp-content/themes/theme-name/theme-name-parent
|
3348 |
+
* but after update it became
|
3349 |
+
* wp-content/themes/theme-name-parent
|
3350 |
+
*
|
3351 |
+
* and at this point get_template_directory() returns old theme directory
|
3352 |
+
* so fw_get_template_customizations_directory() also returns old path
|
3353 |
+
*/
|
3354 |
+
$theme_dir = wp_get_theme()->get_theme_root() .'/'. wp_get_theme()->get_template();
|
3355 |
+
|
3356 |
+
if ( ! ($wpfs_base_dir = FW_WP_Filesystem::real_path_to_filesystem_path(
|
3357 |
+
$base_dir = $theme_dir . fw_get_framework_customizations_dir_rel_path('/extensions')
|
3358 |
+
) ) ) {
|
3359 |
+
return new WP_Error(
|
3360 |
+
'base_dir_to_wpfs_fail',
|
3361 |
+
sprintf( __('Cannot obtain WP Filesystem dir for %s', 'fw'), $base_dir )
|
3362 |
+
);
|
3363 |
+
}
|
3364 |
+
|
3365 |
+
if ( ! ( $dirlist = $wp_filesystem->dirlist($wpfs_tmp_dir) ) ) {
|
3366 |
+
return;
|
3367 |
+
}
|
3368 |
+
|
3369 |
+
foreach ( $dirlist as $filename => $fileinfo ) {
|
3370 |
+
if ( 'd' !== $fileinfo['type'] ) {
|
3371 |
+
continue;
|
3372 |
+
}
|
3373 |
+
|
3374 |
+
if ( is_wp_error($merge_result = $this->merge_extension(
|
3375 |
+
$wpfs_tmp_dir .'/'. $filename,
|
3376 |
+
$wpfs_base_dir .'/'. $filename
|
3377 |
+
)) ) {
|
3378 |
+
return $merge_result;
|
3379 |
+
}
|
3380 |
+
}
|
3381 |
+
|
3382 |
+
$wp_filesystem->rmdir( $wpfs_tmp_dir, true );
|
3383 |
+
}
|
3384 |
+
|
3385 |
+
/**
|
3386 |
+
* Copy Theme Available Extensions to tmp dir
|
3387 |
+
* @param bool|WP_Error $result
|
3388 |
+
* @param array $data
|
3389 |
+
*
|
3390 |
+
* @return bool|WP_Error
|
3391 |
+
*/
|
3392 |
+
public function _filter_theme_available_extensions_copy($result, $data) {
|
3393 |
+
if (
|
3394 |
+
!is_wp_error($result)
|
3395 |
+
&&
|
3396 |
+
is_array($data)
|
3397 |
+
&&
|
3398 |
+
isset($data['theme'])
|
3399 |
+
&&
|
3400 |
+
$data['theme'] === wp_get_theme()->get_template()
|
3401 |
+
) {
|
3402 |
+
if ( is_wp_error( $copy_result = fw()->extensions->manager->theme_available_extensions_copy() ) ) {
|
3403 |
+
return $copy_result;
|
3404 |
+
}
|
3405 |
+
}
|
3406 |
+
|
3407 |
+
return $result;
|
3408 |
+
}
|
3409 |
+
|
3410 |
+
/**
|
3411 |
+
* Restore Theme Available Extensions from tmp dir
|
3412 |
+
* @param Theme_Upgrader $instance
|
3413 |
+
* @param array $data
|
3414 |
+
*
|
3415 |
+
* @return bool|WP_Error
|
3416 |
+
*/
|
3417 |
+
public function _action_theme_available_extensions_restore($instance, $data) {
|
3418 |
+
if (
|
3419 |
+
!is_wp_error($instance->skin->result)
|
3420 |
+
&&
|
3421 |
+
is_array($data)
|
3422 |
+
&&
|
3423 |
+
isset($data['action']) && $data['action'] === 'update'
|
3424 |
+
&&
|
3425 |
+
isset($data['type']) && $data['type'] === 'theme'
|
3426 |
+
&&
|
3427 |
+
isset($data['themes'])
|
3428 |
+
&&
|
3429 |
+
($template = wp_get_theme()->get_template())
|
3430 |
+
&&
|
3431 |
+
(
|
3432 |
+
in_array($template, $data['themes'])
|
3433 |
+
||
|
3434 |
+
/**
|
3435 |
+
* Fixes the case when the theme path before update was
|
3436 |
+
* wp-content/themes/theme-name/theme-name-parent
|
3437 |
+
* but after update it became
|
3438 |
+
* wp-content/themes/theme-name-parent
|
3439 |
+
*/
|
3440 |
+
( preg_match($regex = '/\-parent$/', $template)
|
3441 |
+
? in_array( preg_replace($regex, '', $template) .'/'. $template, $data['themes'] )
|
3442 |
+
: false )
|
3443 |
+
)
|
3444 |
+
) {
|
3445 |
+
fw()->extensions->manager->theme_available_extensions_restore();
|
3446 |
+
}
|
3447 |
+
}
|
3448 |
+
|
3449 |
+
/**
|
3450 |
+
* Install compatible extensions on plugin install -> activate
|
3451 |
+
*
|
3452 |
+
* In order for this to work, int TGM config must be set: 'is_automatic' => true
|
3453 |
+
* http://tgmpluginactivation.com/configuration/
|
3454 |
+
*
|
3455 |
+
* @internal
|
3456 |
+
*/
|
3457 |
+
public function _action_plugin_activate_install_compatible_extensions() {
|
3458 |
+
if (!FW_WP_Filesystem::is_ready()) {
|
3459 |
+
return;
|
3460 |
+
}
|
3461 |
+
|
3462 |
+
if ($compatible_extensions = $this->get_supported_extensions_for_install()) {
|
3463 |
+
$this->install_extensions($compatible_extensions);
|
3464 |
+
// the result is not used because we don't know here if we can print the errors or not
|
3465 |
+
}
|
3466 |
+
}
|
3467 |
+
|
3468 |
+
/**
|
3469 |
+
* @since 2.6.9
|
3470 |
+
*/
|
3471 |
+
public function collect_extension_requirements($extension_name, $can_install = null) {
|
3472 |
+
$installed_extensions = $this->get_installed_extensions();
|
3473 |
+
|
3474 |
+
if (is_null($can_install)) {
|
3475 |
+
$can_install = $this->can_install();
|
3476 |
+
}
|
3477 |
+
|
3478 |
+
if (! isset($installed_extensions[$extension_name])) {
|
3479 |
+
return array();
|
3480 |
+
} else {
|
3481 |
+
$data = $installed_extensions[$extension_name];
|
3482 |
+
}
|
3483 |
+
|
3484 |
+
$result = array();
|
3485 |
+
|
3486 |
+
$manifest_requirements = fw_akg('requirements', $data['manifest'], array());
|
3487 |
+
|
3488 |
+
foreach ($manifest_requirements as $req_name => $req_data) {
|
3489 |
+
switch ($req_name) {
|
3490 |
+
case 'php':
|
3491 |
+
if (empty($req_data['min_version']) && empty($req_data['max_version'])) {
|
3492 |
+
break;
|
3493 |
+
}
|
3494 |
+
|
3495 |
+
if ( ! empty( $req_data['min_version'] ) ) {
|
3496 |
+
if (!version_compare($req_data['min_version'], phpversion(), '<=')) {
|
3497 |
+
$result[] = sprintf(
|
3498 |
+
__( 'PHP needs to be updated to %s', 'fw' ),
|
3499 |
+
$req_data['min_version']
|
3500 |
+
);
|
3501 |
+
}
|
3502 |
+
}
|
3503 |
+
|
3504 |
+
if ( ! empty( $req_data['max_version'] ) ) {
|
3505 |
+
if (!version_compare($req_data['max_version'], phpversion(), '>=')) {
|
3506 |
+
$result[] = sprintf(
|
3507 |
+
__('Maximum supported PHP version is %s', 'fw'),
|
3508 |
+
$req_data['max_version']
|
3509 |
+
);
|
3510 |
+
}
|
3511 |
+
}
|
3512 |
+
|
3513 |
+
break;
|
3514 |
+
|
3515 |
+
case 'wordpress':
|
3516 |
+
if (empty($req_data['min_version']) && empty($req_data['max_version'])) {
|
3517 |
+
break;
|
3518 |
+
}
|
3519 |
+
|
3520 |
+
global $wp_version;
|
3521 |
+
|
3522 |
+
if ( ! empty( $req_data['min_version'] ) ) {
|
3523 |
+
if (!version_compare($req_data['min_version'], $wp_version, '<=')) {
|
3524 |
+
if ($can_install) {
|
3525 |
+
$result[] = sprintf(
|
3526 |
+
__( 'You need to update WordPress to %s: %s', 'fw' ),
|
3527 |
+
$req_data['min_version'],
|
3528 |
+
fw_html_tag( 'a', array( 'href' => self_admin_url( 'update-core.php' ) ), __( 'Update WordPress', 'fw' ) )
|
3529 |
+
);
|
3530 |
+
} else {
|
3531 |
+
$result[] = sprintf(
|
3532 |
+
__( 'WordPress needs to be updated to %s', 'fw' ),
|
3533 |
+
$req_data['min_version']
|
3534 |
+
);
|
3535 |
+
}
|
3536 |
+
}
|
3537 |
+
}
|
3538 |
+
|
3539 |
+
if ( ! empty( $req_data['max_version'] ) ) {
|
3540 |
+
if (!version_compare($req_data['max_version'], $wp_version, '>=')) {
|
3541 |
+
$result[] = sprintf(
|
3542 |
+
__('Maximum supported WordPress version is %s', 'fw'),
|
3543 |
+
$req_data['max_version']
|
3544 |
+
);
|
3545 |
+
}
|
3546 |
+
}
|
3547 |
+
|
3548 |
+
break;
|
3549 |
+
|
3550 |
+
case 'framework':
|
3551 |
+
if (empty($req_data['min_version']) && empty($req_data['max_version'])) {
|
3552 |
+
break;
|
3553 |
+
}
|
3554 |
+
|
3555 |
+
if ( ! empty( $req_data['min_version'] ) ) {
|
3556 |
+
if (!version_compare($req_data['min_version'], fw()->manifest->get_version(), '<=')) {
|
3557 |
+
if ($can_install) {
|
3558 |
+
$result[] = sprintf(
|
3559 |
+
__( 'You need to update %s to %s: %s', 'fw' ),
|
3560 |
+
fw()->manifest->get_name(),
|
3561 |
+
$req_data['min_version'],
|
3562 |
+
fw_html_tag( 'a', array( 'href' => self_admin_url( 'update-core.php' ) ),
|
3563 |
+
sprintf( __( 'Update %s', 'fw' ), fw()->manifest->get_name() )
|
3564 |
+
)
|
3565 |
+
);
|
3566 |
+
} else {
|
3567 |
+
$result[] = sprintf(
|
3568 |
+
__( '%s needs to be updated to %s', 'fw' ),
|
3569 |
+
fw()->manifest->get_name(),
|
3570 |
+
$req_data['min_version']
|
3571 |
+
);
|
3572 |
+
}
|
3573 |
+
}
|
3574 |
+
}
|
3575 |
+
|
3576 |
+
if ( ! empty( $req_data['max_version'] ) ) {
|
3577 |
+
if (!version_compare($req_data['max_version'], fw()->manifest->get_version(), '>=')) {
|
3578 |
+
$result[] = sprintf(
|
3579 |
+
__( 'Maximum supported %s version is %s', 'fw' ),
|
3580 |
+
fw()->manifest->get_name(),
|
3581 |
+
$req_data['max_version']
|
3582 |
+
);
|
3583 |
+
}
|
3584 |
+
}
|
3585 |
+
|
3586 |
+
break;
|
3587 |
+
|
3588 |
+
case 'extensions':
|
3589 |
+
foreach ($req_data as $req_ext => $req_ext_data) {
|
3590 |
+
if ($ext = fw()->extensions->get($req_ext)) {
|
3591 |
+
if (empty($req_ext_data['min_version']) && empty($req_ext_data['max_version'])) {
|
3592 |
+
continue;
|
3593 |
+
}
|
3594 |
+
|
3595 |
+
if ( ! empty( $req_ext_data['min_version'] ) ) {
|
3596 |
+
if (!version_compare($req_ext_data['min_version'], $ext->manifest->get_version(), '<=')) {
|
3597 |
+
if ($can_install) {
|
3598 |
+
$result[] = sprintf(
|
3599 |
+
__('You need to update the %s extension to %s: %s', 'fw'),
|
3600 |
+
$ext->manifest->get_name(),
|
3601 |
+
$req_ext_data['min_version'],
|
3602 |
+
fw_html_tag('a', array('href' => self_admin_url('update-core.php')),
|
3603 |
+
sprintf(__('Update %s', 'fw'), $ext->manifest->get_name())
|
3604 |
+
)
|
3605 |
+
);
|
3606 |
+
} else {
|
3607 |
+
$result[] = sprintf(
|
3608 |
+
__('The %s extension needs to be updated to %s', 'fw'),
|
3609 |
+
$ext->manifest->get_name(),
|
3610 |
+
$req_ext_data['min_version']
|
3611 |
+
);
|
3612 |
+
}
|
3613 |
+
}
|
3614 |
+
}
|
3615 |
+
|
3616 |
+
if ( ! empty( $req_ext_data['max_version'] ) ) {
|
3617 |
+
if (!version_compare($req_ext_data['max_version'], $ext->manifest->get_version(), '>=')) {
|
3618 |
+
$result[] = sprintf(
|
3619 |
+
__( 'Maximum supported %s extension version is %s', 'fw' ),
|
3620 |
+
$ext->manifest->get_name(),
|
3621 |
+
$req_ext_data['max_version']
|
3622 |
+
);
|
3623 |
+
}
|
3624 |
+
}
|
3625 |
+
} else {
|
3626 |
+
$ext_title = fw_id_to_title($req_ext);
|
3627 |
+
|
3628 |
+
if (isset($lists['installed'][$req_ext])) {
|
3629 |
+
$ext_title = fw_akg('name', $lists['installed'][$req_ext]['manifest'], $ext_title);
|
3630 |
+
|
3631 |
+
ob_start(); ?>
|
3632 |
+
<form action="<?php echo esc_attr($link) ?>&sub-page=activate&extension=<?php echo esc_attr($req_ext) ?>" method="post" style="display: inline;">
|
3633 |
+
<?php wp_nonce_field($nonces['activate']['action'], $nonces['activate']['name']); ?>
|
3634 |
+
<?php echo sprintf(__( 'The %s extension is disabled', 'fw' ), $ext_title); ?>:
|
3635 |
+
<a href="#" onclick="jQuery(this).closest('form').submit(); return false;"><?php echo sprintf(__('Activate %s', 'fw'), $ext_title); ?></a>
|
3636 |
+
</form>
|
3637 |
+
<?php
|
3638 |
+
$result[] = ob_get_clean();
|
3639 |
+
} else {
|
3640 |
+
if ($can_install && isset($lists['available'][$req_ext])) {
|
3641 |
+
$ext_title = $lists['available'][ $req_ext ]['name'];
|
3642 |
+
|
3643 |
+
$result[] = sprintf(
|
3644 |
+
__( 'The %s extension is not installed: %s', 'fw' ),
|
3645 |
+
$ext_title,
|
3646 |
+
fw_html_tag( 'a', array( 'href' => $link . '&sub-page=install&extension=' . $req_ext ),
|
3647 |
+
sprintf( __( 'Install %s', 'fw' ), $ext_title )
|
3648 |
+
)
|
3649 |
+
);
|
3650 |
+
} else {
|
3651 |
+
$result[] = sprintf(
|
3652 |
+
__( 'The %s extension is not installed', 'fw' ),
|
3653 |
+
$ext_title
|
3654 |
+
);
|
3655 |
+
}
|
3656 |
+
}
|
3657 |
+
}
|
3658 |
+
}
|
3659 |
+
|
3660 |
+
break;
|
3661 |
+
|
3662 |
+
default:
|
3663 |
+
trigger_error('Invalid requirement: '. $req_name, E_USER_WARNING);
|
3664 |
+
continue;
|
3665 |
+
}
|
3666 |
+
}
|
3667 |
+
|
3668 |
+
return $result;
|
3669 |
+
}
|
3670 |
+
}
|
|
framework/core/components/extensions/manager/includes/available-ext/class--fw-available-extensions-register.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
class _FW_Available_Extensions_Register extends FW_Type_Register {
|
4 |
-
protected function validate_type( FW_Type $type ) {
|
5 |
-
return $type instanceof FW_Available_Extension;
|
6 |
-
}
|
7 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
class _FW_Available_Extensions_Register extends FW_Type_Register {
|
4 |
+
protected function validate_type( FW_Type $type ) {
|
5 |
+
return $type instanceof FW_Available_Extension;
|
6 |
+
}
|
7 |
+
}
|
framework/core/components/extensions/manager/includes/available-ext/class-fw-available-extension.php
CHANGED
@@ -1,131 +1,131 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Used to define extension in framework Available Extensions list
|
5 |
-
* @since 2.5.12
|
6 |
-
*/
|
7 |
-
class FW_Available_Extension extends FW_Type {
|
8 |
-
/**
|
9 |
-
* Extension (directory) name
|
10 |
-
*/
|
11 |
-
private $name;
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var null|string Parent extension name
|
15 |
-
*/
|
16 |
-
private $parent = null;
|
17 |
-
|
18 |
-
/**
|
19 |
-
* @var bool If visible in extensions list
|
20 |
-
*/
|
21 |
-
private $display = true;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* @var string
|
25 |
-
*/
|
26 |
-
private $title;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var string
|
30 |
-
*/
|
31 |
-
private $description;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @var string Image url
|
35 |
-
*/
|
36 |
-
private $thumbnail = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2PUsHf9DwAC8AGtfm5YCAAAAABJRU5ErkJgggAA';
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @var array {source: id, opts: {...}}
|
40 |
-
* @see FW_Ext_Download_Source::get_type() is id
|
41 |
-
* @see FW_Ext_Download_Source
|
42 |
-
*/
|
43 |
-
private $download_source = array();
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @return bool
|
47 |
-
* @since 2.6.0
|
48 |
-
*/
|
49 |
-
public function is_valid() {
|
50 |
-
return (
|
51 |
-
!empty($this->name) && is_string($this->name)
|
52 |
-
&&
|
53 |
-
!empty($this->title) && is_string($this->title)
|
54 |
-
&&
|
55 |
-
!empty($this->description) && is_string($this->description)
|
56 |
-
&&
|
57 |
-
!empty($this->download_source)
|
58 |
-
&&
|
59 |
-
is_bool($this->display)
|
60 |
-
&&
|
61 |
-
(is_null($this->parent) || is_string($this->parent))
|
62 |
-
);
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* @return string
|
67 |
-
* @internal
|
68 |
-
*/
|
69 |
-
final public function get_type() {
|
70 |
-
return $this->get_name();
|
71 |
-
}
|
72 |
-
|
73 |
-
public function get_name() {
|
74 |
-
return $this->name;
|
75 |
-
}
|
76 |
-
|
77 |
-
public function set_name($name) {
|
78 |
-
$this->name = $name;
|
79 |
-
}
|
80 |
-
|
81 |
-
public function get_parent() {
|
82 |
-
return $this->parent;
|
83 |
-
}
|
84 |
-
|
85 |
-
public function set_parent($parent) {
|
86 |
-
$this->parent = $parent;
|
87 |
-
}
|
88 |
-
|
89 |
-
public function get_display() {
|
90 |
-
return $this->display;
|
91 |
-
}
|
92 |
-
|
93 |
-
public function set_display($display) {
|
94 |
-
$this->display = $display;
|
95 |
-
}
|
96 |
-
|
97 |
-
public function get_title() {
|
98 |
-
return $this->title;
|
99 |
-
}
|
100 |
-
|
101 |
-
public function set_title($title) {
|
102 |
-
$this->title = $title;
|
103 |
-
}
|
104 |
-
|
105 |
-
public function get_description() {
|
106 |
-
return $this->description;
|
107 |
-
}
|
108 |
-
|
109 |
-
public function set_description($description) {
|
110 |
-
$this->description = $description;
|
111 |
-
}
|
112 |
-
|
113 |
-
public function get_thumbnail() {
|
114 |
-
return $this->thumbnail;
|
115 |
-
}
|
116 |
-
|
117 |
-
public function set_thumbnail($thumbnail) {
|
118 |
-
$this->thumbnail = $thumbnail;
|
119 |
-
}
|
120 |
-
|
121 |
-
public function get_download_source() {
|
122 |
-
return $this->download_source;
|
123 |
-
}
|
124 |
-
|
125 |
-
public function set_download_source($id, $data) {
|
126 |
-
$this->download_source = array(
|
127 |
-
'source' => $id,
|
128 |
-
'opts' => $data
|
129 |
-
);
|
130 |
-
}
|
131 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Used to define extension in framework Available Extensions list
|
5 |
+
* @since 2.5.12
|
6 |
+
*/
|
7 |
+
class FW_Available_Extension extends FW_Type {
|
8 |
+
/**
|
9 |
+
* Extension (directory) name
|
10 |
+
*/
|
11 |
+
private $name;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var null|string Parent extension name
|
15 |
+
*/
|
16 |
+
private $parent = null;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var bool If visible in extensions list
|
20 |
+
*/
|
21 |
+
private $display = true;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
private $title;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
private $description;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var string Image url
|
35 |
+
*/
|
36 |
+
private $thumbnail = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2PUsHf9DwAC8AGtfm5YCAAAAABJRU5ErkJgggAA';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var array {source: id, opts: {...}}
|
40 |
+
* @see FW_Ext_Download_Source::get_type() is id
|
41 |
+
* @see FW_Ext_Download_Source
|
42 |
+
*/
|
43 |
+
private $download_source = array();
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @return bool
|
47 |
+
* @since 2.6.0
|
48 |
+
*/
|
49 |
+
public function is_valid() {
|
50 |
+
return (
|
51 |
+
!empty($this->name) && is_string($this->name)
|
52 |
+
&&
|
53 |
+
!empty($this->title) && is_string($this->title)
|
54 |
+
&&
|
55 |
+
!empty($this->description) && is_string($this->description)
|
56 |
+
&&
|
57 |
+
!empty($this->download_source)
|
58 |
+
&&
|
59 |
+
is_bool($this->display)
|
60 |
+
&&
|
61 |
+
(is_null($this->parent) || is_string($this->parent))
|
62 |
+
);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return string
|
67 |
+
* @internal
|
68 |
+
*/
|
69 |
+
final public function get_type() {
|
70 |
+
return $this->get_name();
|
71 |
+
}
|
72 |
+
|
73 |
+
public function get_name() {
|
74 |
+
return $this->name;
|
75 |
+
}
|
76 |
+
|
77 |
+
public function set_name($name) {
|
78 |
+
$this->name = $name;
|
79 |
+
}
|
80 |
+
|
81 |
+
public function get_parent() {
|
82 |
+
return $this->parent;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function set_parent($parent) {
|
86 |
+
$this->parent = $parent;
|
87 |
+
}
|
88 |
+
|
89 |
+
public function get_display() {
|
90 |
+
return $this->display;
|
91 |
+
}
|
92 |
+
|
93 |
+
public function set_display($display) {
|
94 |
+
$this->display = $display;
|
95 |
+
}
|
96 |
+
|
97 |
+
public function get_title() {
|
98 |
+
return $this->title;
|
99 |
+
}
|
100 |
+
|
101 |
+
public function set_title($title) {
|
102 |
+
$this->title = $title;
|
103 |
+
}
|
104 |
+
|
105 |
+
public function get_description() {
|
106 |
+
return $this->description;
|
107 |
+
}
|
108 |
+
|
109 |
+
public function set_description($description) {
|
110 |
+
$this->description = $description;
|
111 |
+
}
|
112 |
+
|
113 |
+
public function get_thumbnail() {
|
114 |
+
return $this->thumbnail;
|
115 |
+
}
|
116 |
+
|
117 |
+
public function set_thumbnail($thumbnail) {
|
118 |
+
$this->thumbnail = $thumbnail;
|
119 |
+
}
|
120 |
+
|
121 |
+
public function get_download_source() {
|
122 |
+
return $this->download_source;
|
123 |
+
}
|
124 |
+
|
125 |
+
public function set_download_source($id, $data) {
|
126 |
+
$this->download_source = array(
|
127 |
+
'source' => $id,
|
128 |
+
'opts' => $data
|
129 |
+
);
|
130 |
+
}
|
131 |
+
}
|
framework/core/components/extensions/manager/includes/class--fw-extensions-delete-upgrader-skin.php
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
-
|
5 |
-
class _FW_Extensions_Delete_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
-
{
|
7 |
-
public function after($data = array())
|
8 |
-
{
|
9 |
-
$update_actions = array(
|
10 |
-
'extensions_page' => fw_html_tag(
|
11 |
-
'a',
|
12 |
-
array(
|
13 |
-
'href' => fw_akg('extensions_page_link', $data, '#'),
|
14 |
-
'title' => __('Go to extensions page', 'fw'),
|
15 |
-
'target' => '_parent',
|
16 |
-
),
|
17 |
-
__('Return to Extensions page', 'fw')
|
18 |
-
)
|
19 |
-
);
|
20 |
-
|
21 |
-
$this->feedback(implode(' | ', (array)$update_actions));
|
22 |
-
|
23 |
-
if ($this->result) {
|
24 |
-
// used for popup ajax form submit result
|
25 |
-
$this->feedback('<span success></span>');
|
26 |
-
}
|
27 |
-
}
|
28 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
+
|
5 |
+
class _FW_Extensions_Delete_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
+
{
|
7 |
+
public function after($data = array())
|
8 |
+
{
|
9 |
+
$update_actions = array(
|
10 |
+
'extensions_page' => fw_html_tag(
|
11 |
+
'a',
|
12 |
+
array(
|
13 |
+
'href' => fw_akg('extensions_page_link', $data, '#'),
|
14 |
+
'title' => __('Go to extensions page', 'fw'),
|
15 |
+
'target' => '_parent',
|
16 |
+
),
|
17 |
+
__('Return to Extensions page', 'fw')
|
18 |
+
)
|
19 |
+
);
|
20 |
+
|
21 |
+
$this->feedback(implode(' | ', (array)$update_actions));
|
22 |
+
|
23 |
+
if ($this->result) {
|
24 |
+
// used for popup ajax form submit result
|
25 |
+
$this->feedback('<span success></span>');
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
framework/core/components/extensions/manager/includes/class--fw-extensions-install-upgrader-skin.php
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
-
|
5 |
-
class _FW_Extensions_Install_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
-
{
|
7 |
-
public function after($data = array())
|
8 |
-
{
|
9 |
-
$update_actions = array(
|
10 |
-
'extensions_page' => fw_html_tag(
|
11 |
-
'a',
|
12 |
-
array(
|
13 |
-
'href' => fw_akg('extensions_page_link', $data, '#'),
|
14 |
-
'title' => __('Go to extensions page', 'fw'),
|
15 |
-
'target' => '_parent',
|
16 |
-
),
|
17 |
-
__('Return to Extensions page', 'fw')
|
18 |
-
)
|
19 |
-
);
|
20 |
-
|
21 |
-
$this->feedback(implode(' | ', (array)$update_actions));
|
22 |
-
|
23 |
-
if ($this->result) {
|
24 |
-
// used for popup ajax form submit result
|
25 |
-
$this->feedback('<span success></span>');
|
26 |
-
}
|
27 |
-
}
|
28 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
+
|
5 |
+
class _FW_Extensions_Install_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
+
{
|
7 |
+
public function after($data = array())
|
8 |
+
{
|
9 |
+
$update_actions = array(
|
10 |
+
'extensions_page' => fw_html_tag(
|
11 |
+
'a',
|
12 |
+
array(
|
13 |
+
'href' => fw_akg('extensions_page_link', $data, '#'),
|
14 |
+
'title' => __('Go to extensions page', 'fw'),
|
15 |
+
'target' => '_parent',
|
16 |
+
),
|
17 |
+
__('Return to Extensions page', 'fw')
|
18 |
+
)
|
19 |
+
);
|
20 |
+
|
21 |
+
$this->feedback(implode(' | ', (array)$update_actions));
|
22 |
+
|
23 |
+
if ($this->result) {
|
24 |
+
// used for popup ajax form submit result
|
25 |
+
$this->feedback('<span success></span>');
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
framework/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source-register.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
<?php if (! defined('FW')) { die('Forbidden'); }
|
2 |
-
|
3 |
-
class _FW_Ext_Download_Source_Register extends FW_Type_Register
|
4 |
-
{
|
5 |
-
protected function validate_type( FW_Type $type ) {
|
6 |
-
return $type instanceof FW_Ext_Download_Source;
|
7 |
-
}
|
8 |
-
}
|
9 |
-
|
1 |
+
<?php if (! defined('FW')) { die('Forbidden'); }
|
2 |
+
|
3 |
+
class _FW_Ext_Download_Source_Register extends FW_Type_Register
|
4 |
+
{
|
5 |
+
protected function validate_type( FW_Type $type ) {
|
6 |
+
return $type instanceof FW_Ext_Download_Source;
|
7 |
+
}
|
8 |
+
}
|
9 |
+
|
framework/core/components/extensions/manager/includes/download-source/class--fw-ext-download-source.php
CHANGED
@@ -1,20 +1,21 @@
|
|
1 |
-
<?php if (! defined('FW')) { die('Forbidden'); }
|
2 |
-
|
3 |
-
/**
|
4 |
-
* User to specify multiple download sources for an extension.
|
5 |
-
* @since 2.5.12
|
6 |
-
*/
|
7 |
-
abstract class FW_Ext_Download_Source extends FW_Type
|
8 |
-
{
|
9 |
-
/**
|
10 |
-
* Perform the actual download.
|
11 |
-
* It should download, by convention, a zip file which absolute path
|
12 |
-
* is $path.
|
13 |
-
*
|
14 |
-
* @param array $
|
15 |
-
* @param string $zip_path Absolute file of the future ZIP file
|
16 |
-
*
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
1 |
+
<?php if (! defined('FW')) { die('Forbidden'); }
|
2 |
+
|
3 |
+
/**
|
4 |
+
* User to specify multiple download sources for an extension.
|
5 |
+
* @since 2.5.12
|
6 |
+
*/
|
7 |
+
abstract class FW_Ext_Download_Source extends FW_Type
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* Perform the actual download.
|
11 |
+
* It should download, by convention, a zip file which absolute path
|
12 |
+
* is $path.
|
13 |
+
*
|
14 |
+
* @param array $set {extension_name: '...', extension_title: '...', ...}
|
15 |
+
* @param string $zip_path Absolute file of the future ZIP file
|
16 |
+
*
|
17 |
+
* @return null|WP_Error
|
18 |
+
*/
|
19 |
+
abstract public function download(array $set, $zip_path);
|
20 |
+
}
|
21 |
+
|
framework/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-custom.php
ADDED
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php defined( 'FW' ) or die();
|
2 |
+
|
3 |
+
class FW_Ext_Download_Source_Custom extends FW_Ext_Download_Source {
|
4 |
+
private $download_timeout = 300;
|
5 |
+
// Used in filter http_request_args when extension is as plugin we use api worpdress Plugin_Upgrader.
|
6 |
+
private $set = array();
|
7 |
+
|
8 |
+
public function get_type() {
|
9 |
+
return 'custom';
|
10 |
+
}
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param array $set
|
14 |
+
* @param string $zip_path
|
15 |
+
*
|
16 |
+
* @return WP_Error|bool
|
17 |
+
*/
|
18 |
+
public function download( array $set, $zip_path ) {
|
19 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
20 |
+
global $wp_filesystem;
|
21 |
+
|
22 |
+
$wp_error_id = 'fw_ext_custom_download_source';
|
23 |
+
$transient_name = 'fw_ext_mngr_gh_dl';
|
24 |
+
$requirements = fw()->theme->manifest->get( 'requirements/extensions' );
|
25 |
+
$set['type'] = 'extension';
|
26 |
+
|
27 |
+
if ( isset( $requirements[ $set['extension_name'] ] ) && isset( $requirements[ $set['extension_name'] ]['max_version'] ) ) {
|
28 |
+
$set['tag'] = $requirements[ $set['extension_name'] ]['max_version'];
|
29 |
+
} else {
|
30 |
+
$set['tag'] = $this->get_version( $set );
|
31 |
+
|
32 |
+
if ( is_wp_error( $set['tag'] ) ) {
|
33 |
+
return $set['tag'];
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
$cache = ( $c = get_site_transient( $transient_name ) ) && $c !== false ? $c : array();
|
38 |
+
$cache[ $set['item'] ] = array( 'tag_name' => $set['tag'] );
|
39 |
+
set_site_transient( $transient_name, $cache, HOUR_IN_SECONDS );
|
40 |
+
|
41 |
+
if ( $set['plugin'] ) {
|
42 |
+
return $this->install_plugin( $set, $set['remote'] );
|
43 |
+
}
|
44 |
+
|
45 |
+
$request = wp_remote_post(
|
46 |
+
$set['remote'],
|
47 |
+
array(
|
48 |
+
'timeout' => $this->download_timeout,
|
49 |
+
'body' => json_encode( array_merge( $set, array( 'pull' => 'zip' ) ) )
|
50 |
+
)
|
51 |
+
);
|
52 |
+
|
53 |
+
if ( is_wp_error( $request ) ) {
|
54 |
+
return $request;
|
55 |
+
}
|
56 |
+
|
57 |
+
if ( ! ( $body = wp_remote_retrieve_body( $request ) ) || is_wp_error( $body ) ) {
|
58 |
+
return ! $body ? new WP_Error( $wp_error_id, sprintf( esc_html__( 'Empty zip body for extension: %s', 'fw' ), $set['extension_title'] ) ) : $body;
|
59 |
+
}
|
60 |
+
|
61 |
+
// Try to extract error if server returned json with key error, if not then is an archive zip.
|
62 |
+
if ( ( $error = json_decode( $body, true ) ) && isset( $error['error'] ) ) {
|
63 |
+
return new WP_Error( $wp_error_id, $error['error'] );
|
64 |
+
}
|
65 |
+
|
66 |
+
// save zip to file
|
67 |
+
if ( ! $wp_filesystem->put_contents( $zip_path, $body ) ) {
|
68 |
+
return new WP_Error( $wp_error_id, sprintf( __( 'Cannot save the "%s" extension zip.', 'fw' ), $set['name'] ) );
|
69 |
+
}
|
70 |
+
|
71 |
+
return '';
|
72 |
+
}
|
73 |
+
|
74 |
+
public function get_version( $set ) {
|
75 |
+
|
76 |
+
if ( $this->is_wp_org( $set['remote'] ) ) {
|
77 |
+
|
78 |
+
include ABSPATH . 'wp-admin/includes/plugin-install.php';
|
79 |
+
|
80 |
+
$wp_org = plugins_api(
|
81 |
+
'plugin_information',
|
82 |
+
array(
|
83 |
+
'slug' => 'translatepress-multilingual',
|
84 |
+
'fields' => array(
|
85 |
+
'downloaded' => false,
|
86 |
+
'versions' => false,
|
87 |
+
'reviews' => false,
|
88 |
+
'banners' => false,
|
89 |
+
'icons' => false,
|
90 |
+
'rating' => false,
|
91 |
+
'active_installs' => false,
|
92 |
+
'group' => false,
|
93 |
+
'contributors' => false,
|
94 |
+
'description' => false,
|
95 |
+
'short_description' => false,
|
96 |
+
'donate_link' => false,
|
97 |
+
'tags' => false,
|
98 |
+
'sections' => false,
|
99 |
+
'homepage' => false,
|
100 |
+
'added' => false,
|
101 |
+
'last_updated' => false,
|
102 |
+
'compatibility' => false,
|
103 |
+
'tested' => false,
|
104 |
+
'requires' => false,
|
105 |
+
'downloadlink' => true,
|
106 |
+
)
|
107 |
+
)
|
108 |
+
);
|
109 |
+
|
110 |
+
if ( is_wp_error( $wp_org ) ) {
|
111 |
+
return new WP_Error( sprintf( __( 'Cannot get latest versions for extension: %s', 'fw' ), $set['extension_title'] ) );
|
112 |
+
}
|
113 |
+
|
114 |
+
return $wp_org->version;
|
115 |
+
}
|
116 |
+
|
117 |
+
$request = wp_remote_post(
|
118 |
+
$set['remote'],
|
119 |
+
array(
|
120 |
+
'timeout' => $this->download_timeout,
|
121 |
+
'body' => json_encode( array_merge( $set, array( 'pull' => 'version' ) ) )
|
122 |
+
)
|
123 |
+
);
|
124 |
+
|
125 |
+
if ( is_wp_error( $request ) ) {
|
126 |
+
return $request;
|
127 |
+
}
|
128 |
+
|
129 |
+
if ( ! ( $version = wp_remote_retrieve_body( $request ) ) || is_wp_error( $version ) ) {
|
130 |
+
return ! $version ? new WP_Error( sprintf( esc_html__( 'Empty version for extension: %s', 'fw' ), $set['extension_title'] ) ) : $version;
|
131 |
+
}
|
132 |
+
|
133 |
+
return $version;
|
134 |
+
}
|
135 |
+
|
136 |
+
public function install_plugin( $set, $source ) {
|
137 |
+
|
138 |
+
if ( ! function_exists( 'is_plugin_active' ) ) {
|
139 |
+
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
140 |
+
}
|
141 |
+
|
142 |
+
if ( is_plugin_active( $set['plugin'] ) ) {
|
143 |
+
return '';
|
144 |
+
}
|
145 |
+
|
146 |
+
if ( ! ( $installed = get_plugins() ) || ! isset( $installed[ $set['plugin'] ] ) ) {
|
147 |
+
if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
|
148 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
149 |
+
}
|
150 |
+
|
151 |
+
if ( $this->is_wp_org( $set['remote'] ) ) {
|
152 |
+
$source = esc_url( "{$source}.{$set['tag']}.zip" );
|
153 |
+
}
|
154 |
+
|
155 |
+
$upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
|
156 |
+
// To easy access download settings in function http_request_args.
|
157 |
+
$this->set = $set;
|
158 |
+
add_filter( 'http_request_args', array( $this, 'http_request_args' ) );
|
159 |
+
|
160 |
+
$install = $upgrader->install( $source );
|
161 |
+
|
162 |
+
remove_filter( 'http_request_args', array( $this, 'http_request_args' ) );
|
163 |
+
|
164 |
+
if ( ! $install || is_wp_error( $install ) ) {
|
165 |
+
return new WP_Error( sprintf( __( 'Cannot install plugin: %s', 'fw' ), $set['extension_title'] ) );
|
166 |
+
}
|
167 |
+
|
168 |
+
if ( ! ( $installed = get_plugins() ) || ! isset( $installed[ $set['plugin'] ] ) ) {
|
169 |
+
return new WP_Error( sprintf( __( 'Cannot find plugin: %s', 'fw' ), $set['extension_title'] ) );
|
170 |
+
}
|
171 |
+
|
172 |
+
$cache_plugins = ( $c = wp_cache_get( 'plugins', 'plugins' ) ) && ! empty( $c ) ? $c : array();
|
173 |
+
$cache_plugins[''][ $set['plugin'] ] = $installed[ $set['plugin'] ];
|
174 |
+
wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
|
175 |
+
}
|
176 |
+
|
177 |
+
return activate_plugin( $set['plugin'] );
|
178 |
+
}
|
179 |
+
|
180 |
+
public function http_request_args( $r ) {
|
181 |
+
$r['body'] = json_encode( array_merge( $this->set, array( 'type' => 'extension' ) ) );
|
182 |
+
return $r;
|
183 |
+
}
|
184 |
+
|
185 |
+
public function is_wp_org( $url ) {
|
186 |
+
return strpos( $url, 'downloads.wordpress.org' ) !== false;
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
|
191 |
+
|
192 |
+
|
193 |
+
|
194 |
+
|
195 |
+
|
196 |
+
|
197 |
+
|
198 |
+
|
199 |
+
|
200 |
+
|
201 |
+
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
|
206 |
+
|
207 |
+
|
208 |
+
|
209 |
+
|
framework/core/components/extensions/manager/includes/download-source/types/class-fw-download-source-github.php
CHANGED
@@ -1,187 +1,188 @@
|
|
1 |
-
<?php if (! defined('FW')) {
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
* @param
|
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 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
'
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
$
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
}
|
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
class FW_Ext_Download_Source_Github extends FW_Ext_Download_Source {
|
6 |
+
private $download_timeout = 300;
|
7 |
+
|
8 |
+
public function get_type() {
|
9 |
+
return 'github';
|
10 |
+
}
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param array $set {user_repo: 'ThemeFuse/Unyson'}
|
14 |
+
* @param string $zip_path
|
15 |
+
*
|
16 |
+
* @return WP_Error
|
17 |
+
*/
|
18 |
+
public function download( array $set, $zip_path ) {
|
19 |
+
$wp_error_id = 'fw_ext_github_download_source';
|
20 |
+
$theme_ext_requirements = fw()->theme->manifest->get( 'requirements/extensions' );
|
21 |
+
|
22 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
23 |
+
global $wp_filesystem;
|
24 |
+
|
25 |
+
$extension_name = $set['extension_name'];
|
26 |
+
$extension_title = $set['extension_title'];
|
27 |
+
|
28 |
+
if ( empty( $set['user_repo'] ) ) {
|
29 |
+
return new WP_Error(
|
30 |
+
$wp_error_id,
|
31 |
+
sprintf( __( '"%s" extension github source "user_repo" parameter is required', 'fw' ), $extension_title )
|
32 |
+
);
|
33 |
+
}
|
34 |
+
|
35 |
+
{
|
36 |
+
$transient_name = 'fw_ext_mngr_gh_dl';
|
37 |
+
$transient_ttl = HOUR_IN_SECONDS;
|
38 |
+
|
39 |
+
$cache = get_site_transient( $transient_name );
|
40 |
+
|
41 |
+
if ( $cache === false ) {
|
42 |
+
$cache = array();
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
if ( isset( $cache[ $set['user_repo'] ] ) ) {
|
47 |
+
$download_link = $cache[ $set['user_repo'] ]['zipball_url'];
|
48 |
+
} else {
|
49 |
+
$http = new WP_Http();
|
50 |
+
|
51 |
+
if (
|
52 |
+
isset( $theme_ext_requirements[ $extension_name ] )
|
53 |
+
&&
|
54 |
+
isset( $theme_ext_requirements[ $extension_name ]['max_version'] )
|
55 |
+
) {
|
56 |
+
$tag = 'tags/v' . $theme_ext_requirements[ $extension_name ]['max_version'];
|
57 |
+
} else {
|
58 |
+
$tag = 'latest';
|
59 |
+
}
|
60 |
+
|
61 |
+
$response = $http->get(
|
62 |
+
apply_filters( 'fw_github_api_url', 'https://api.github.com' )
|
63 |
+
. '/repos/' . $set['user_repo'] . '/releases/' . $tag
|
64 |
+
);
|
65 |
+
|
66 |
+
unset( $http );
|
67 |
+
|
68 |
+
$response_code = intval( wp_remote_retrieve_response_code( $response ) );
|
69 |
+
|
70 |
+
if ( $response_code !== 200 ) {
|
71 |
+
if ( $response_code === 403 ) {
|
72 |
+
if ( $json_response = json_decode( $response['body'], true ) ) {
|
73 |
+
return new WP_Error(
|
74 |
+
$wp_error_id,
|
75 |
+
__( 'Github error:', 'fw' ) . ' ' . $json_response['message']
|
76 |
+
);
|
77 |
+
} else {
|
78 |
+
return new WP_Error(
|
79 |
+
$wp_error_id,
|
80 |
+
sprintf(
|
81 |
+
__( 'Failed to access Github repository "%s" releases. (Response code: %d)', 'fw' ),
|
82 |
+
$set['user_repo'], $response_code
|
83 |
+
)
|
84 |
+
);
|
85 |
+
}
|
86 |
+
} elseif ( $response_code ) {
|
87 |
+
return new WP_Error(
|
88 |
+
$wp_error_id,
|
89 |
+
sprintf(
|
90 |
+
__( 'Failed to access Github repository "%s" releases. (Response code: %d)', 'fw' ),
|
91 |
+
$set['user_repo'], $response_code
|
92 |
+
)
|
93 |
+
);
|
94 |
+
} elseif ( is_wp_error( $response ) ) {
|
95 |
+
return new WP_Error(
|
96 |
+
$wp_error_id,
|
97 |
+
sprintf(
|
98 |
+
__( 'Failed to access Github repository "%s" releases. (%s)', 'fw' ),
|
99 |
+
$set['user_repo'], $response->get_error_message()
|
100 |
+
)
|
101 |
+
);
|
102 |
+
} else {
|
103 |
+
return new WP_Error(
|
104 |
+
$wp_error_id,
|
105 |
+
sprintf(
|
106 |
+
__( 'Failed to access Github repository "%s" releases.', 'fw' ),
|
107 |
+
$set['user_repo']
|
108 |
+
)
|
109 |
+
);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
$release = json_decode( $response['body'], true );
|
114 |
+
|
115 |
+
unset( $response );
|
116 |
+
|
117 |
+
if ( empty( $release ) ) {
|
118 |
+
return new WP_Error(
|
119 |
+
$wp_error_id,
|
120 |
+
sprintf(
|
121 |
+
__( '"%s" extension github repository "%s" has no releases.', 'fw' ),
|
122 |
+
$extension_title, $set['user_repo']
|
123 |
+
)
|
124 |
+
);
|
125 |
+
}
|
126 |
+
|
127 |
+
{
|
128 |
+
$cache[ $set['user_repo'] ] = array(
|
129 |
+
'zipball_url' => 'https://github.com/' . $set['user_repo'] . '/archive/' . $release['tag_name'] . '.zip',
|
130 |
+
'tag_name' => $release['tag_name']
|
131 |
+
);
|
132 |
+
|
133 |
+
set_site_transient( $transient_name, $cache, $transient_ttl );
|
134 |
+
}
|
135 |
+
|
136 |
+
$download_link = $cache[ $set['user_repo'] ]['zipball_url'];
|
137 |
+
|
138 |
+
|
139 |
+
unset( $release );
|
140 |
+
}
|
141 |
+
|
142 |
+
{
|
143 |
+
$http = new WP_Http();
|
144 |
+
|
145 |
+
$response = $http->request( $download_link, array(
|
146 |
+
'timeout' => $this->download_timeout,
|
147 |
+
) );
|
148 |
+
|
149 |
+
unset( $http );
|
150 |
+
|
151 |
+
if ( ( $response_code = intval( wp_remote_retrieve_response_code( $response ) ) ) !== 200 ) {
|
152 |
+
if ( $response_code ) {
|
153 |
+
return new WP_Error(
|
154 |
+
$wp_error_id,
|
155 |
+
sprintf( __( 'Cannot download the "%s" extension zip. (Response code: %d)', 'fw' ),
|
156 |
+
$extension_title, $response_code
|
157 |
+
)
|
158 |
+
);
|
159 |
+
} elseif ( is_wp_error( $response ) ) {
|
160 |
+
return new WP_Error(
|
161 |
+
$wp_error_id,
|
162 |
+
sprintf( __( 'Cannot download the "%s" extension zip. %s', 'fw' ),
|
163 |
+
$extension_title,
|
164 |
+
$response->get_error_message()
|
165 |
+
)
|
166 |
+
);
|
167 |
+
} else {
|
168 |
+
return new WP_Error(
|
169 |
+
$wp_error_id,
|
170 |
+
sprintf( __( 'Cannot download the "%s" extension zip.', 'fw' ),
|
171 |
+
$extension_title
|
172 |
+
)
|
173 |
+
);
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
// save zip to file
|
178 |
+
if ( ! $wp_filesystem->put_contents( $zip_path, $response['body'] ) ) {
|
179 |
+
return new WP_Error(
|
180 |
+
$wp_error_id,
|
181 |
+
sprintf( __( 'Cannot save the "%s" extension zip.', 'fw' ), $extension_title )
|
182 |
+
);
|
183 |
+
}
|
184 |
+
|
185 |
+
unset( $response );
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
framework/core/components/extensions/manager/includes/download-source/types/init.php
CHANGED
@@ -1,12 +1,10 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! function_exists( '_action_fw_register_ext_download_sources' ) ) {
|
4 |
-
function _action_fw_register_ext_download_sources(_FW_Ext_Download_Source_Register $download_sources) {
|
5 |
-
$download_sources->register(new FW_Ext_Download_Source_Github());
|
6 |
-
|
7 |
-
}
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
'_action_fw_register_ext_download_sources'
|
12 |
-
);
|
1 |
+
<?php defined( 'FW' ) or die();
|
2 |
+
|
3 |
+
if ( ! function_exists( '_action_fw_register_ext_download_sources' ) ) {
|
4 |
+
function _action_fw_register_ext_download_sources( _FW_Ext_Download_Source_Register $download_sources ) {
|
5 |
+
$download_sources->register( new FW_Ext_Download_Source_Github() );
|
6 |
+
$download_sources->register( new FW_Ext_Download_Source_Custom() );
|
7 |
+
}
|
8 |
+
}
|
9 |
+
|
10 |
+
add_action( 'fw_register_ext_download_sources', '_action_fw_register_ext_download_sources' );
|
|
|
|
framework/core/components/extensions/manager/includes/parsedown/LICENSE.txt
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
-
The MIT License (MIT)
|
2 |
-
|
3 |
-
Copyright (c) 2013 Emanuil Rusev, erusev.com
|
4 |
-
|
5 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6 |
-
this software and associated documentation files (the "Software"), to deal in
|
7 |
-
the Software without restriction, including without limitation the rights to
|
8 |
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9 |
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
10 |
-
subject to the following conditions:
|
11 |
-
|
12 |
-
The above copyright notice and this permission notice shall be included in all
|
13 |
-
copies or substantial portions of the Software.
|
14 |
-
|
15 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17 |
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18 |
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19 |
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20 |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1 |
+
The MIT License (MIT)
|
2 |
+
|
3 |
+
Copyright (c) 2013 Emanuil Rusev, erusev.com
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6 |
+
this software and associated documentation files (the "Software"), to deal in
|
7 |
+
the Software without restriction, including without limitation the rights to
|
8 |
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9 |
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10 |
+
subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17 |
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18 |
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19 |
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20 |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
framework/core/components/extensions/manager/includes/parsedown/Parsedown.php
CHANGED
@@ -1,1528 +1,1528 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
#
|
4 |
-
#
|
5 |
-
# Parsedown
|
6 |
-
# http://parsedown.org
|
7 |
-
#
|
8 |
-
# (c) Emanuil Rusev
|
9 |
-
# http://erusev.com
|
10 |
-
#
|
11 |
-
# For the full license information, view the LICENSE file that was distributed
|
12 |
-
# with this source code.
|
13 |
-
#
|
14 |
-
#
|
15 |
-
|
16 |
-
class Parsedown
|
17 |
-
{
|
18 |
-
# ~
|
19 |
-
|
20 |
-
const version = '1.5.4';
|
21 |
-
|
22 |
-
# ~
|
23 |
-
|
24 |
-
function text($text)
|
25 |
-
{
|
26 |
-
# make sure no definitions are set
|
27 |
-
$this->DefinitionData = array();
|
28 |
-
|
29 |
-
# standardize line breaks
|
30 |
-
$text = str_replace(array("\r\n", "\r"), "\n", $text);
|
31 |
-
|
32 |
-
# remove surrounding line breaks
|
33 |
-
$text = trim($text, "\n");
|
34 |
-
|
35 |
-
# split text into lines
|
36 |
-
$lines = explode("\n", $text);
|
37 |
-
|
38 |
-
# iterate through lines to identify blocks
|
39 |
-
$markup = $this->lines($lines);
|
40 |
-
|
41 |
-
# trim line breaks
|
42 |
-
$markup = trim($markup, "\n");
|
43 |
-
|
44 |
-
return $markup;
|
45 |
-
}
|
46 |
-
|
47 |
-
#
|
48 |
-
# Setters
|
49 |
-
#
|
50 |
-
|
51 |
-
function setBreaksEnabled($breaksEnabled)
|
52 |
-
{
|
53 |
-
$this->breaksEnabled = $breaksEnabled;
|
54 |
-
|
55 |
-
return $this;
|
56 |
-
}
|
57 |
-
|
58 |
-
protected $breaksEnabled;
|
59 |
-
|
60 |
-
function setMarkupEscaped($markupEscaped)
|
61 |
-
{
|
62 |
-
$this->markupEscaped = $markupEscaped;
|
63 |
-
|
64 |
-
return $this;
|
65 |
-
}
|
66 |
-
|
67 |
-
protected $markupEscaped;
|
68 |
-
|
69 |
-
function setUrlsLinked($urlsLinked)
|
70 |
-
{
|
71 |
-
$this->urlsLinked = $urlsLinked;
|
72 |
-
|
73 |
-
return $this;
|
74 |
-
}
|
75 |
-
|
76 |
-
protected $urlsLinked = true;
|
77 |
-
|
78 |
-
#
|
79 |
-
# Lines
|
80 |
-
#
|
81 |
-
|
82 |
-
protected $BlockTypes = array(
|
83 |
-
'#' => array('Header'),
|
84 |
-
'*' => array('Rule', 'List'),
|
85 |
-
'+' => array('List'),
|
86 |
-
'-' => array('SetextHeader', 'Table', 'Rule', 'List'),
|
87 |
-
'0' => array('List'),
|
88 |
-
'1' => array('List'),
|
89 |
-
'2' => array('List'),
|
90 |
-
'3' => array('List'),
|
91 |
-
'4' => array('List'),
|
92 |
-
'5' => array('List'),
|
93 |
-
'6' => array('List'),
|
94 |
-
'7' => array('List'),
|
95 |
-
'8' => array('List'),
|
96 |
-
'9' => array('List'),
|
97 |
-
':' => array('Table'),
|
98 |
-
'<' => array('Comment', 'Markup'),
|
99 |
-
'=' => array('SetextHeader'),
|
100 |
-
'>' => array('Quote'),
|
101 |
-
'[' => array('Reference'),
|
102 |
-
'_' => array('Rule'),
|
103 |
-
'`' => array('FencedCode'),
|
104 |
-
'|' => array('Table'),
|
105 |
-
'~' => array('FencedCode'),
|
106 |
-
);
|
107 |
-
|
108 |
-
# ~
|
109 |
-
|
110 |
-
protected $unmarkedBlockTypes = array(
|
111 |
-
'Code',
|
112 |
-
);
|
113 |
-
|
114 |
-
#
|
115 |
-
# Blocks
|
116 |
-
#
|
117 |
-
|
118 |
-
private function lines(array $lines)
|
119 |
-
{
|
120 |
-
$CurrentBlock = null;
|
121 |
-
|
122 |
-
foreach ($lines as $line)
|
123 |
-
{
|
124 |
-
if (chop($line) === '')
|
125 |
-
{
|
126 |
-
if (isset($CurrentBlock))
|
127 |
-
{
|
128 |
-
$CurrentBlock['interrupted'] = true;
|
129 |
-
}
|
130 |
-
|
131 |
-
continue;
|
132 |
-
}
|
133 |
-
|
134 |
-
if (strpos($line, "\t") !== false)
|
135 |
-
{
|
136 |
-
$parts = explode("\t", $line);
|
137 |
-
|
138 |
-
$line = $parts[0];
|
139 |
-
|
140 |
-
unset($parts[0]);
|
141 |
-
|
142 |
-
foreach ($parts as $part)
|
143 |
-
{
|
144 |
-
$shortage = 4 - mb_strlen($line, 'utf-8') % 4;
|
145 |
-
|
146 |
-
$line .= str_repeat(' ', $shortage);
|
147 |
-
$line .= $part;
|
148 |
-
}
|
149 |
-
}
|
150 |
-
|
151 |
-
$indent = 0;
|
152 |
-
|
153 |
-
while (isset($line[$indent]) and $line[$indent] === ' ')
|
154 |
-
{
|
155 |
-
$indent ++;
|
156 |
-
}
|
157 |
-
|
158 |
-
$text = $indent > 0 ? substr($line, $indent) : $line;
|
159 |
-
|
160 |
-
# ~
|
161 |
-
|
162 |
-
$Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
|
163 |
-
|
164 |
-
# ~
|
165 |
-
|
166 |
-
if (isset($CurrentBlock['continuable']))
|
167 |
-
{
|
168 |
-
$Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock);
|
169 |
-
|
170 |
-
if (isset($Block))
|
171 |
-
{
|
172 |
-
$CurrentBlock = $Block;
|
173 |
-
|
174 |
-
continue;
|
175 |
-
}
|
176 |
-
else
|
177 |
-
{
|
178 |
-
if (method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
179 |
-
{
|
180 |
-
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
181 |
-
}
|
182 |
-
}
|
183 |
-
}
|
184 |
-
|
185 |
-
# ~
|
186 |
-
|
187 |
-
$marker = $text[0];
|
188 |
-
|
189 |
-
# ~
|
190 |
-
|
191 |
-
$blockTypes = $this->unmarkedBlockTypes;
|
192 |
-
|
193 |
-
if (isset($this->BlockTypes[$marker]))
|
194 |
-
{
|
195 |
-
foreach ($this->BlockTypes[$marker] as $blockType)
|
196 |
-
{
|
197 |
-
$blockTypes []= $blockType;
|
198 |
-
}
|
199 |
-
}
|
200 |
-
|
201 |
-
#
|
202 |
-
# ~
|
203 |
-
|
204 |
-
foreach ($blockTypes as $blockType)
|
205 |
-
{
|
206 |
-
$Block = $this->{'block'.$blockType}($Line, $CurrentBlock);
|
207 |
-
|
208 |
-
if (isset($Block))
|
209 |
-
{
|
210 |
-
$Block['type'] = $blockType;
|
211 |
-
|
212 |
-
if ( ! isset($Block['identified']))
|
213 |
-
{
|
214 |
-
$Blocks []= $CurrentBlock;
|
215 |
-
|
216 |
-
$Block['identified'] = true;
|
217 |
-
}
|
218 |
-
|
219 |
-
if (method_exists($this, 'block'.$blockType.'Continue'))
|
220 |
-
{
|
221 |
-
$Block['continuable'] = true;
|
222 |
-
}
|
223 |
-
|
224 |
-
$CurrentBlock = $Block;
|
225 |
-
|
226 |
-
continue 2;
|
227 |
-
}
|
228 |
-
}
|
229 |
-
|
230 |
-
# ~
|
231 |
-
|
232 |
-
if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted']))
|
233 |
-
{
|
234 |
-
$CurrentBlock['element']['text'] .= "\n".$text;
|
235 |
-
}
|
236 |
-
else
|
237 |
-
{
|
238 |
-
$Blocks []= $CurrentBlock;
|
239 |
-
|
240 |
-
$CurrentBlock = $this->paragraph($Line);
|
241 |
-
|
242 |
-
$CurrentBlock['identified'] = true;
|
243 |
-
}
|
244 |
-
}
|
245 |
-
|
246 |
-
# ~
|
247 |
-
|
248 |
-
if (isset($CurrentBlock['continuable']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
249 |
-
{
|
250 |
-
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
251 |
-
}
|
252 |
-
|
253 |
-
# ~
|
254 |
-
|
255 |
-
$Blocks []= $CurrentBlock;
|
256 |
-
|
257 |
-
unset($Blocks[0]);
|
258 |
-
|
259 |
-
# ~
|
260 |
-
|
261 |
-
$markup = '';
|
262 |
-
|
263 |
-
foreach ($Blocks as $Block)
|
264 |
-
{
|
265 |
-
if (isset($Block['hidden']))
|
266 |
-
{
|
267 |
-
continue;
|
268 |
-
}
|
269 |
-
|
270 |
-
$markup .= "\n";
|
271 |
-
$markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']);
|
272 |
-
}
|
273 |
-
|
274 |
-
$markup .= "\n";
|
275 |
-
|
276 |
-
# ~
|
277 |
-
|
278 |
-
return $markup;
|
279 |
-
}
|
280 |
-
|
281 |
-
#
|
282 |
-
# Code
|
283 |
-
|
284 |
-
protected function blockCode($Line, $Block = null)
|
285 |
-
{
|
286 |
-
if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted']))
|
287 |
-
{
|
288 |
-
return;
|
289 |
-
}
|
290 |
-
|
291 |
-
if ($Line['indent'] >= 4)
|
292 |
-
{
|
293 |
-
$text = substr($Line['body'], 4);
|
294 |
-
|
295 |
-
$Block = array(
|
296 |
-
'element' => array(
|
297 |
-
'name' => 'pre',
|
298 |
-
'handler' => 'element',
|
299 |
-
'text' => array(
|
300 |
-
'name' => 'code',
|
301 |
-
'text' => $text,
|
302 |
-
),
|
303 |
-
),
|
304 |
-
);
|
305 |
-
|
306 |
-
return $Block;
|
307 |
-
}
|
308 |
-
}
|
309 |
-
|
310 |
-
protected function blockCodeContinue($Line, $Block)
|
311 |
-
{
|
312 |
-
if ($Line['indent'] >= 4)
|
313 |
-
{
|
314 |
-
if (isset($Block['interrupted']))
|
315 |
-
{
|
316 |
-
$Block['element']['text']['text'] .= "\n";
|
317 |
-
|
318 |
-
unset($Block['interrupted']);
|
319 |
-
}
|
320 |
-
|
321 |
-
$Block['element']['text']['text'] .= "\n";
|
322 |
-
|
323 |
-
$text = substr($Line['body'], 4);
|
324 |
-
|
325 |
-
$Block['element']['text']['text'] .= $text;
|
326 |
-
|
327 |
-
return $Block;
|
328 |
-
}
|
329 |
-
}
|
330 |
-
|
331 |
-
protected function blockCodeComplete($Block)
|
332 |
-
{
|
333 |
-
$text = $Block['element']['text']['text'];
|
334 |
-
|
335 |
-
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
336 |
-
|
337 |
-
$Block['element']['text']['text'] = $text;
|
338 |
-
|
339 |
-
return $Block;
|
340 |
-
}
|
341 |
-
|
342 |
-
#
|
343 |
-
# Comment
|
344 |
-
|
345 |
-
protected function blockComment($Line)
|
346 |
-
{
|
347 |
-
if ($this->markupEscaped)
|
348 |
-
{
|
349 |
-
return;
|
350 |
-
}
|
351 |
-
|
352 |
-
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')
|
353 |
-
{
|
354 |
-
$Block = array(
|
355 |
-
'markup' => $Line['body'],
|
356 |
-
);
|
357 |
-
|
358 |
-
if (preg_match('/-->$/', $Line['text']))
|
359 |
-
{
|
360 |
-
$Block['closed'] = true;
|
361 |
-
}
|
362 |
-
|
363 |
-
return $Block;
|
364 |
-
}
|
365 |
-
}
|
366 |
-
|
367 |
-
protected function blockCommentContinue($Line, array $Block)
|
368 |
-
{
|
369 |
-
if (isset($Block['closed']))
|
370 |
-
{
|
371 |
-
return;
|
372 |
-
}
|
373 |
-
|
374 |
-
$Block['markup'] .= "\n" . $Line['body'];
|
375 |
-
|
376 |
-
if (preg_match('/-->$/', $Line['text']))
|
377 |
-
{
|
378 |
-
$Block['closed'] = true;
|
379 |
-
}
|
380 |
-
|
381 |
-
return $Block;
|
382 |
-
}
|
383 |
-
|
384 |
-
#
|
385 |
-
# Fenced Code
|
386 |
-
|
387 |
-
protected function blockFencedCode($Line)
|
388 |
-
{
|
389 |
-
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
390 |
-
{
|
391 |
-
$Element = array(
|
392 |
-
'name' => 'code',
|
393 |
-
'text' => '',
|
394 |
-
);
|
395 |
-
|
396 |
-
if (isset($matches[1]))
|
397 |
-
{
|
398 |
-
$class = 'language-'.$matches[1];
|
399 |
-
|
400 |
-
$Element['attributes'] = array(
|
401 |
-
'class' => $class,
|
402 |
-
);
|
403 |
-
}
|
404 |
-
|
405 |
-
$Block = array(
|
406 |
-
'char' => $Line['text'][0],
|
407 |
-
'element' => array(
|
408 |
-
'name' => 'pre',
|
409 |
-
'handler' => 'element',
|
410 |
-
'text' => $Element,
|
411 |
-
),
|
412 |
-
);
|
413 |
-
|
414 |
-
return $Block;
|
415 |
-
}
|
416 |
-
}
|
417 |
-
|
418 |
-
protected function blockFencedCodeContinue($Line, $Block)
|
419 |
-
{
|
420 |
-
if (isset($Block['complete']))
|
421 |
-
{
|
422 |
-
return;
|
423 |
-
}
|
424 |
-
|
425 |
-
if (isset($Block['interrupted']))
|
426 |
-
{
|
427 |
-
$Block['element']['text']['text'] .= "\n";
|
428 |
-
|
429 |
-
unset($Block['interrupted']);
|
430 |
-
}
|
431 |
-
|
432 |
-
if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text']))
|
433 |
-
{
|
434 |
-
$Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1);
|
435 |
-
|
436 |
-
$Block['complete'] = true;
|
437 |
-
|
438 |
-
return $Block;
|
439 |
-
}
|
440 |
-
|
441 |
-
$Block['element']['text']['text'] .= "\n".$Line['body'];;
|
442 |
-
|
443 |
-
return $Block;
|
444 |
-
}
|
445 |
-
|
446 |
-
protected function blockFencedCodeComplete($Block)
|
447 |
-
{
|
448 |
-
$text = $Block['element']['text']['text'];
|
449 |
-
|
450 |
-
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
451 |
-
|
452 |
-
$Block['element']['text']['text'] = $text;
|
453 |
-
|
454 |
-
return $Block;
|
455 |
-
}
|
456 |
-
|
457 |
-
#
|
458 |
-
# Header
|
459 |
-
|
460 |
-
protected function blockHeader($Line)
|
461 |
-
{
|
462 |
-
if (isset($Line['text'][1]))
|
463 |
-
{
|
464 |
-
$level = 1;
|
465 |
-
|
466 |
-
while (isset($Line['text'][$level]) and $Line['text'][$level] === '#')
|
467 |
-
{
|
468 |
-
$level ++;
|
469 |
-
}
|
470 |
-
|
471 |
-
if ($level > 6)
|
472 |
-
{
|
473 |
-
return;
|
474 |
-
}
|
475 |
-
|
476 |
-
$text = trim($Line['text'], '# ');
|
477 |
-
|
478 |
-
$Block = array(
|
479 |
-
'element' => array(
|
480 |
-
'name' => 'h' . min(6, $level),
|
481 |
-
'text' => $text,
|
482 |
-
'handler' => 'line',
|
483 |
-
),
|
484 |
-
);
|
485 |
-
|
486 |
-
return $Block;
|
487 |
-
}
|
488 |
-
}
|
489 |
-
|
490 |
-
#
|
491 |
-
# List
|
492 |
-
|
493 |
-
protected function blockList($Line)
|
494 |
-
{
|
495 |
-
list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]');
|
496 |
-
|
497 |
-
if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches))
|
498 |
-
{
|
499 |
-
$Block = array(
|
500 |
-
'indent' => $Line['indent'],
|
501 |
-
'pattern' => $pattern,
|
502 |
-
'element' => array(
|
503 |
-
'name' => $name,
|
504 |
-
'handler' => 'elements',
|
505 |
-
),
|
506 |
-
);
|
507 |
-
|
508 |
-
$Block['li'] = array(
|
509 |
-
'name' => 'li',
|
510 |
-
'handler' => 'li',
|
511 |
-
'text' => array(
|
512 |
-
$matches[2],
|
513 |
-
),
|
514 |
-
);
|
515 |
-
|
516 |
-
$Block['element']['text'] []= & $Block['li'];
|
517 |
-
|
518 |
-
return $Block;
|
519 |
-
}
|
520 |
-
}
|
521 |
-
|
522 |
-
protected function blockListContinue($Line, array $Block)
|
523 |
-
{
|
524 |
-
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches))
|
525 |
-
{
|
526 |
-
if (isset($Block['interrupted']))
|
527 |
-
{
|
528 |
-
$Block['li']['text'] []= '';
|
529 |
-
|
530 |
-
unset($Block['interrupted']);
|
531 |
-
}
|
532 |
-
|
533 |
-
unset($Block['li']);
|
534 |
-
|
535 |
-
$text = isset($matches[1]) ? $matches[1] : '';
|
536 |
-
|
537 |
-
$Block['li'] = array(
|
538 |
-
'name' => 'li',
|
539 |
-
'handler' => 'li',
|
540 |
-
'text' => array(
|
541 |
-
$text,
|
542 |
-
),
|
543 |
-
);
|
544 |
-
|
545 |
-
$Block['element']['text'] []= & $Block['li'];
|
546 |
-
|
547 |
-
return $Block;
|
548 |
-
}
|
549 |
-
|
550 |
-
if ($Line['text'][0] === '[' and $this->blockReference($Line))
|
551 |
-
{
|
552 |
-
return $Block;
|
553 |
-
}
|
554 |
-
|
555 |
-
if ( ! isset($Block['interrupted']))
|
556 |
-
{
|
557 |
-
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
|
558 |
-
|
559 |
-
$Block['li']['text'] []= $text;
|
560 |
-
|
561 |
-
return $Block;
|
562 |
-
}
|
563 |
-
|
564 |
-
if ($Line['indent'] > 0)
|
565 |
-
{
|
566 |
-
$Block['li']['text'] []= '';
|
567 |
-
|
568 |
-
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
|
569 |
-
|
570 |
-
$Block['li']['text'] []= $text;
|
571 |
-
|
572 |
-
unset($Block['interrupted']);
|
573 |
-
|
574 |
-
return $Block;
|
575 |
-
}
|
576 |
-
}
|
577 |
-
|
578 |
-
#
|
579 |
-
# Quote
|
580 |
-
|
581 |
-
protected function blockQuote($Line)
|
582 |
-
{
|
583 |
-
if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
|
584 |
-
{
|
585 |
-
$Block = array(
|
586 |
-
'element' => array(
|
587 |
-
'name' => 'blockquote',
|
588 |
-
'handler' => 'lines',
|
589 |
-
'text' => (array) $matches[1],
|
590 |
-
),
|
591 |
-
);
|
592 |
-
|
593 |
-
return $Block;
|
594 |
-
}
|
595 |
-
}
|
596 |
-
|
597 |
-
protected function blockQuoteContinue($Line, array $Block)
|
598 |
-
{
|
599 |
-
if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
|
600 |
-
{
|
601 |
-
if (isset($Block['interrupted']))
|
602 |
-
{
|
603 |
-
$Block['element']['text'] []= '';
|
604 |
-
|
605 |
-
unset($Block['interrupted']);
|
606 |
-
}
|
607 |
-
|
608 |
-
$Block['element']['text'] []= $matches[1];
|
609 |
-
|
610 |
-
return $Block;
|
611 |
-
}
|
612 |
-
|
613 |
-
if ( ! isset($Block['interrupted']))
|
614 |
-
{
|
615 |
-
$Block['element']['text'] []= $Line['text'];
|
616 |
-
|
617 |
-
return $Block;
|
618 |
-
}
|
619 |
-
}
|
620 |
-
|
621 |
-
#
|
622 |
-
# Rule
|
623 |
-
|
624 |
-
protected function blockRule($Line)
|
625 |
-
{
|
626 |
-
if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text']))
|
627 |
-
{
|
628 |
-
$Block = array(
|
629 |
-
'element' => array(
|
630 |
-
'name' => 'hr'
|
631 |
-
),
|
632 |
-
);
|
633 |
-
|
634 |
-
return $Block;
|
635 |
-
}
|
636 |
-
}
|
637 |
-
|
638 |
-
#
|
639 |
-
# Setext
|
640 |
-
|
641 |
-
protected function blockSetextHeader($Line, array $Block = null)
|
642 |
-
{
|
643 |
-
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
644 |
-
{
|
645 |
-
return;
|
646 |
-
}
|
647 |
-
|
648 |
-
if (chop($Line['text'], $Line['text'][0]) === '')
|
649 |
-
{
|
650 |
-
$Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';
|
651 |
-
|
652 |
-
return $Block;
|
653 |
-
}
|
654 |
-
}
|
655 |
-
|
656 |
-
#
|
657 |
-
# Markup
|
658 |
-
|
659 |
-
protected function blockMarkup($Line)
|
660 |
-
{
|
661 |
-
if ($this->markupEscaped)
|
662 |
-
{
|
663 |
-
return;
|
664 |
-
}
|
665 |
-
|
666 |
-
if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
667 |
-
{
|
668 |
-
$element = strtolower($matches[1]);
|
669 |
-
|
670 |
-
if (in_array($element, $this->textLevelElements))
|
671 |
-
{
|
672 |
-
return;
|
673 |
-
}
|
674 |
-
|
675 |
-
$Block = array(
|
676 |
-
'name' => $matches[1],
|
677 |
-
'depth' => 0,
|
678 |
-
'markup' => $Line['text'],
|
679 |
-
);
|
680 |
-
|
681 |
-
$length = strlen($matches[0]);
|
682 |
-
|
683 |
-
$remainder = substr($Line['text'], $length);
|
684 |
-
|
685 |
-
if (trim($remainder) === '')
|
686 |
-
{
|
687 |
-
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
688 |
-
{
|
689 |
-
$Block['closed'] = true;
|
690 |
-
|
691 |
-
$Block['void'] = true;
|
692 |
-
}
|
693 |
-
}
|
694 |
-
else
|
695 |
-
{
|
696 |
-
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
697 |
-
{
|
698 |
-
return;
|
699 |
-
}
|
700 |
-
|
701 |
-
if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder))
|
702 |
-
{
|
703 |
-
$Block['closed'] = true;
|
704 |
-
}
|
705 |
-
}
|
706 |
-
|
707 |
-
return $Block;
|
708 |
-
}
|
709 |
-
}
|
710 |
-
|
711 |
-
protected function blockMarkupContinue($Line, array $Block)
|
712 |
-
{
|
713 |
-
if (isset($Block['closed']))
|
714 |
-
{
|
715 |
-
return;
|
716 |
-
}
|
717 |
-
|
718 |
-
if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open
|
719 |
-
{
|
720 |
-
$Block['depth'] ++;
|
721 |
-
}
|
722 |
-
|
723 |
-
if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close
|
724 |
-
{
|
725 |
-
if ($Block['depth'] > 0)
|
726 |
-
{
|
727 |
-
$Block['depth'] --;
|
728 |
-
}
|
729 |
-
else
|
730 |
-
{
|
731 |
-
$Block['closed'] = true;
|
732 |
-
}
|
733 |
-
}
|
734 |
-
|
735 |
-
if (isset($Block['interrupted']))
|
736 |
-
{
|
737 |
-
$Block['markup'] .= "\n";
|
738 |
-
|
739 |
-
unset($Block['interrupted']);
|
740 |
-
}
|
741 |
-
|
742 |
-
$Block['markup'] .= "\n".$Line['body'];
|
743 |
-
|
744 |
-
return $Block;
|
745 |
-
}
|
746 |
-
|
747 |
-
#
|
748 |
-
# Reference
|
749 |
-
|
750 |
-
protected function blockReference($Line)
|
751 |
-
{
|
752 |
-
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches))
|
753 |
-
{
|
754 |
-
$id = strtolower($matches[1]);
|
755 |
-
|
756 |
-
$Data = array(
|
757 |
-
'url' => $matches[2],
|
758 |
-
'title' => null,
|
759 |
-
);
|
760 |
-
|
761 |
-
if (isset($matches[3]))
|
762 |
-
{
|
763 |
-
$Data['title'] = $matches[3];
|
764 |
-
}
|
765 |
-
|
766 |
-
$this->DefinitionData['Reference'][$id] = $Data;
|
767 |
-
|
768 |
-
$Block = array(
|
769 |
-
'hidden' => true,
|
770 |
-
);
|
771 |
-
|
772 |
-
return $Block;
|
773 |
-
}
|
774 |
-
}
|
775 |
-
|
776 |
-
#
|
777 |
-
# Table
|
778 |
-
|
779 |
-
protected function blockTable($Line, array $Block = null)
|
780 |
-
{
|
781 |
-
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
782 |
-
{
|
783 |
-
return;
|
784 |
-
}
|
785 |
-
|
786 |
-
if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '')
|
787 |
-
{
|
788 |
-
$alignments = array();
|
789 |
-
|
790 |
-
$divider = $Line['text'];
|
791 |
-
|
792 |
-
$divider = trim($divider);
|
793 |
-
$divider = trim($divider, '|');
|
794 |
-
|
795 |
-
$dividerCells = explode('|', $divider);
|
796 |
-
|
797 |
-
foreach ($dividerCells as $dividerCell)
|
798 |
-
{
|
799 |
-
$dividerCell = trim($dividerCell);
|
800 |
-
|
801 |
-
if ($dividerCell === '')
|
802 |
-
{
|
803 |
-
continue;
|
804 |
-
}
|
805 |
-
|
806 |
-
$alignment = null;
|
807 |
-
|
808 |
-
if ($dividerCell[0] === ':')
|
809 |
-
{
|
810 |
-
$alignment = 'left';
|
811 |
-
}
|
812 |
-
|
813 |
-
if (substr($dividerCell, - 1) === ':')
|
814 |
-
{
|
815 |
-
$alignment = $alignment === 'left' ? 'center' : 'right';
|
816 |
-
}
|
817 |
-
|
818 |
-
$alignments []= $alignment;
|
819 |
-
}
|
820 |
-
|
821 |
-
# ~
|
822 |
-
|
823 |
-
$HeaderElements = array();
|
824 |
-
|
825 |
-
$header = $Block['element']['text'];
|
826 |
-
|
827 |
-
$header = trim($header);
|
828 |
-
$header = trim($header, '|');
|
829 |
-
|
830 |
-
$headerCells = explode('|', $header);
|
831 |
-
|
832 |
-
foreach ($headerCells as $index => $headerCell)
|
833 |
-
{
|
834 |
-
$headerCell = trim($headerCell);
|
835 |
-
|
836 |
-
$HeaderElement = array(
|
837 |
-
'name' => 'th',
|
838 |
-
'text' => $headerCell,
|
839 |
-
'handler' => 'line',
|
840 |
-
);
|
841 |
-
|
842 |
-
if (isset($alignments[$index]))
|
843 |
-
{
|
844 |
-
$alignment = $alignments[$index];
|
845 |
-
|
846 |
-
$HeaderElement['attributes'] = array(
|
847 |
-
'style' => 'text-align: '.$alignment.';',
|
848 |
-
);
|
849 |
-
}
|
850 |
-
|
851 |
-
$HeaderElements []= $HeaderElement;
|
852 |
-
}
|
853 |
-
|
854 |
-
# ~
|
855 |
-
|
856 |
-
$Block = array(
|
857 |
-
'alignments' => $alignments,
|
858 |
-
'identified' => true,
|
859 |
-
'element' => array(
|
860 |
-
'name' => 'table',
|
861 |
-
'handler' => 'elements',
|
862 |
-
),
|
863 |
-
);
|
864 |
-
|
865 |
-
$Block['element']['text'] []= array(
|
866 |
-
'name' => 'thead',
|
867 |
-
'handler' => 'elements',
|
868 |
-
);
|
869 |
-
|
870 |
-
$Block['element']['text'] []= array(
|
871 |
-
'name' => 'tbody',
|
872 |
-
'handler' => 'elements',
|
873 |
-
'text' => array(),
|
874 |
-
);
|
875 |
-
|
876 |
-
$Block['element']['text'][0]['text'] []= array(
|
877 |
-
'name' => 'tr',
|
878 |
-
'handler' => 'elements',
|
879 |
-
'text' => $HeaderElements,
|
880 |
-
);
|
881 |
-
|
882 |
-
return $Block;
|
883 |
-
}
|
884 |
-
}
|
885 |
-
|
886 |
-
protected function blockTableContinue($Line, array $Block)
|
887 |
-
{
|
888 |
-
if (isset($Block['interrupted']))
|
889 |
-
{
|
890 |
-
return;
|
891 |
-
}
|
892 |
-
|
893 |
-
if ($Line['text'][0] === '|' or strpos($Line['text'], '|'))
|
894 |
-
{
|
895 |
-
$Elements = array();
|
896 |
-
|
897 |
-
$row = $Line['text'];
|
898 |
-
|
899 |
-
$row = trim($row);
|
900 |
-
$row = trim($row, '|');
|
901 |
-
|
902 |
-
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);
|
903 |
-
|
904 |
-
foreach ($matches[0] as $index => $cell)
|
905 |
-
{
|
906 |
-
$cell = trim($cell);
|
907 |
-
|
908 |
-
$Element = array(
|
909 |
-
'name' => 'td',
|
910 |
-
'handler' => 'line',
|
911 |
-
'text' => $cell,
|
912 |
-
);
|
913 |
-
|
914 |
-
if (isset($Block['alignments'][$index]))
|
915 |
-
{
|
916 |
-
$Element['attributes'] = array(
|
917 |
-
'style' => 'text-align: '.$Block['alignments'][$index].';',
|
918 |
-
);
|
919 |
-
}
|
920 |
-
|
921 |
-
$Elements []= $Element;
|
922 |
-
}
|
923 |
-
|
924 |
-
$Element = array(
|
925 |
-
'name' => 'tr',
|
926 |
-
'handler' => 'elements',
|
927 |
-
'text' => $Elements,
|
928 |
-
);
|
929 |
-
|
930 |
-
$Block['element']['text'][1]['text'] []= $Element;
|
931 |
-
|
932 |
-
return $Block;
|
933 |
-
}
|
934 |
-
}
|
935 |
-
|
936 |
-
#
|
937 |
-
# ~
|
938 |
-
#
|
939 |
-
|
940 |
-
protected function paragraph($Line)
|
941 |
-
{
|
942 |
-
$Block = array(
|
943 |
-
'element' => array(
|
944 |
-
'name' => 'p',
|
945 |
-
'text' => $Line['text'],
|
946 |
-
'handler' => 'line',
|
947 |
-
),
|
948 |
-
);
|
949 |
-
|
950 |
-
return $Block;
|
951 |
-
}
|
952 |
-
|
953 |
-
#
|
954 |
-
# Inline Elements
|
955 |
-
#
|
956 |
-
|
957 |
-
protected $InlineTypes = array(
|
958 |
-
'"' => array('SpecialCharacter'),
|
959 |
-
'!' => array('Image'),
|
960 |
-
'&' => array('SpecialCharacter'),
|
961 |
-
'*' => array('Emphasis'),
|
962 |
-
':' => array('Url'),
|
963 |
-
'<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),
|
964 |
-
'>' => array('SpecialCharacter'),
|
965 |
-
'[' => array('Link'),
|
966 |
-
'_' => array('Emphasis'),
|
967 |
-
'`' => array('Code'),
|
968 |
-
'~' => array('Strikethrough'),
|
969 |
-
'\\' => array('EscapeSequence'),
|
970 |
-
);
|
971 |
-
|
972 |
-
# ~
|
973 |
-
|
974 |
-
protected $inlineMarkerList = '!"*_&[:<>`~\\';
|
975 |
-
|
976 |
-
#
|
977 |
-
# ~
|
978 |
-
#
|
979 |
-
|
980 |
-
public function line($text)
|
981 |
-
{
|
982 |
-
$markup = '';
|
983 |
-
|
984 |
-
# $excerpt is based on the first occurrence of a marker
|
985 |
-
|
986 |
-
while ($excerpt = strpbrk($text, $this->inlineMarkerList))
|
987 |
-
{
|
988 |
-
$marker = $excerpt[0];
|
989 |
-
|
990 |
-
$markerPosition = strpos($text, $marker);
|
991 |
-
|
992 |
-
$Excerpt = array('text' => $excerpt, 'context' => $text);
|
993 |
-
|
994 |
-
foreach ($this->InlineTypes[$marker] as $inlineType)
|
995 |
-
{
|
996 |
-
$Inline = $this->{'inline'.$inlineType}($Excerpt);
|
997 |
-
|
998 |
-
if ( ! isset($Inline))
|
999 |
-
{
|
1000 |
-
continue;
|
1001 |
-
}
|
1002 |
-
|
1003 |
-
# makes sure that the inline belongs to "our" marker
|
1004 |
-
|
1005 |
-
if (isset($Inline['position']) and $Inline['position'] > $markerPosition)
|
1006 |
-
{
|
1007 |
-
continue;
|
1008 |
-
}
|
1009 |
-
|
1010 |
-
# sets a default inline position
|
1011 |
-
|
1012 |
-
if ( ! isset($Inline['position']))
|
1013 |
-
{
|
1014 |
-
$Inline['position'] = $markerPosition;
|
1015 |
-
}
|
1016 |
-
|
1017 |
-
# the text that comes before the inline
|
1018 |
-
$unmarkedText = substr($text, 0, $Inline['position']);
|
1019 |
-
|
1020 |
-
# compile the unmarked text
|
1021 |
-
$markup .= $this->unmarkedText($unmarkedText);
|
1022 |
-
|
1023 |
-
# compile the inline
|
1024 |
-
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);
|
1025 |
-
|
1026 |
-
# remove the examined text
|
1027 |
-
$text = substr($text, $Inline['position'] + $Inline['extent']);
|
1028 |
-
|
1029 |
-
continue 2;
|
1030 |
-
}
|
1031 |
-
|
1032 |
-
# the marker does not belong to an inline
|
1033 |
-
|
1034 |
-
$unmarkedText = substr($text, 0, $markerPosition + 1);
|
1035 |
-
|
1036 |
-
$markup .= $this->unmarkedText($unmarkedText);
|
1037 |
-
|
1038 |
-
$text = substr($text, $markerPosition + 1);
|
1039 |
-
}
|
1040 |
-
|
1041 |
-
$markup .= $this->unmarkedText($text);
|
1042 |
-
|
1043 |
-
return $markup;
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
#
|
1047 |
-
# ~
|
1048 |
-
#
|
1049 |
-
|
1050 |
-
protected function inlineCode($Excerpt)
|
1051 |
-
{
|
1052 |
-
$marker = $Excerpt['text'][0];
|
1053 |
-
|
1054 |
-
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
|
1055 |
-
{
|
1056 |
-
$text = $matches[2];
|
1057 |
-
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
1058 |
-
$text = preg_replace("/[ ]*\n/", ' ', $text);
|
1059 |
-
|
1060 |
-
return array(
|
1061 |
-
'extent' => strlen($matches[0]),
|
1062 |
-
'element' => array(
|
1063 |
-
'name' => 'code',
|
1064 |
-
'text' => $text,
|
1065 |
-
),
|
1066 |
-
);
|
1067 |
-
}
|
1068 |
-
}
|
1069 |
-
|
1070 |
-
protected function inlineEmailTag($Excerpt)
|
1071 |
-
{
|
1072 |
-
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches))
|
1073 |
-
{
|
1074 |
-
$url = $matches[1];
|
1075 |
-
|
1076 |
-
if ( ! isset($matches[2]))
|
1077 |
-
{
|
1078 |
-
$url = 'mailto:' . $url;
|
1079 |
-
}
|
1080 |
-
|
1081 |
-
return array(
|
1082 |
-
'extent' => strlen($matches[0]),
|
1083 |
-
'element' => array(
|
1084 |
-
'name' => 'a',
|
1085 |
-
'text' => $matches[1],
|
1086 |
-
'attributes' => array(
|
1087 |
-
'href' => $url,
|
1088 |
-
),
|
1089 |
-
),
|
1090 |
-
);
|
1091 |
-
}
|
1092 |
-
}
|
1093 |
-
|
1094 |
-
protected function inlineEmphasis($Excerpt)
|
1095 |
-
{
|
1096 |
-
if ( ! isset($Excerpt['text'][1]))
|
1097 |
-
{
|
1098 |
-
return;
|
1099 |
-
}
|
1100 |
-
|
1101 |
-
$marker = $Excerpt['text'][0];
|
1102 |
-
|
1103 |
-
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
|
1104 |
-
{
|
1105 |
-
$emphasis = 'strong';
|
1106 |
-
}
|
1107 |
-
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
|
1108 |
-
{
|
1109 |
-
$emphasis = 'em';
|
1110 |
-
}
|
1111 |
-
else
|
1112 |
-
{
|
1113 |
-
return;
|
1114 |
-
}
|
1115 |
-
|
1116 |
-
return array(
|
1117 |
-
'extent' => strlen($matches[0]),
|
1118 |
-
'element' => array(
|
1119 |
-
'name' => $emphasis,
|
1120 |
-
'handler' => 'line',
|
1121 |
-
'text' => $matches[1],
|
1122 |
-
),
|
1123 |
-
);
|
1124 |
-
}
|
1125 |
-
|
1126 |
-
protected function inlineEscapeSequence($Excerpt)
|
1127 |
-
{
|
1128 |
-
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
|
1129 |
-
{
|
1130 |
-
return array(
|
1131 |
-
'markup' => $Excerpt['text'][1],
|
1132 |
-
'extent' => 2,
|
1133 |
-
);
|
1134 |
-
}
|
1135 |
-
}
|
1136 |
-
|
1137 |
-
protected function inlineImage($Excerpt)
|
1138 |
-
{
|
1139 |
-
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
|
1140 |
-
{
|
1141 |
-
return;
|
1142 |
-
}
|
1143 |
-
|
1144 |
-
$Excerpt['text']= substr($Excerpt['text'], 1);
|
1145 |
-
|
1146 |
-
$Link = $this->inlineLink($Excerpt);
|
1147 |
-
|
1148 |
-
if ($Link === null)
|
1149 |
-
{
|
1150 |
-
return;
|
1151 |
-
}
|
1152 |
-
|
1153 |
-
$Inline = array(
|
1154 |
-
'extent' => $Link['extent'] + 1,
|
1155 |
-
'element' => array(
|
1156 |
-
'name' => 'img',
|
1157 |
-
'attributes' => array(
|
1158 |
-
'src' => $Link['element']['attributes']['href'],
|
1159 |
-
'alt' => $Link['element']['text'],
|
1160 |
-
),
|
1161 |
-
),
|
1162 |
-
);
|
1163 |
-
|
1164 |
-
$Inline['element']['attributes'] += $Link['element']['attributes'];
|
1165 |
-
|
1166 |
-
unset($Inline['element']['attributes']['href']);
|
1167 |
-
|
1168 |
-
return $Inline;
|
1169 |
-
}
|
1170 |
-
|
1171 |
-
protected function inlineLink($Excerpt)
|
1172 |
-
{
|
1173 |
-
$Element = array(
|
1174 |
-
'name' => 'a',
|
1175 |
-
'handler' => 'line',
|
1176 |
-
'text' => null,
|
1177 |
-
'attributes' => array(
|
1178 |
-
'href' => null,
|
1179 |
-
'title' => null,
|
1180 |
-
),
|
1181 |
-
);
|
1182 |
-
|
1183 |
-
$extent = 0;
|
1184 |
-
|
1185 |
-
$remainder = $Excerpt['text'];
|
1186 |
-
|
1187 |
-
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
|
1188 |
-
{
|
1189 |
-
$Element['text'] = $matches[1];
|
1190 |
-
|
1191 |
-
$extent += strlen($matches[0]);
|
1192 |
-
|
1193 |
-
$remainder = substr($remainder, $extent);
|
1194 |
-
}
|
1195 |
-
else
|
1196 |
-
{
|
1197 |
-
return;
|
1198 |
-
}
|
1199 |
-
|
1200 |
-
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))
|
1201 |
-
{
|
1202 |
-
$Element['attributes']['href'] = $matches[1];
|
1203 |
-
|
1204 |
-
if (isset($matches[2]))
|
1205 |
-
{
|
1206 |
-
$Element['attributes']['title'] = substr($matches[2], 1, - 1);
|
1207 |
-
}
|
1208 |
-
|
1209 |
-
$extent += strlen($matches[0]);
|
1210 |
-
}
|
1211 |
-
else
|
1212 |
-
{
|
1213 |
-
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
|
1214 |
-
{
|
1215 |
-
$definition = strlen($matches[1]) ? $matches[1] : $Element['text'];
|
1216 |
-
$definition = strtolower($definition);
|
1217 |
-
|
1218 |
-
$extent += strlen($matches[0]);
|
1219 |
-
}
|
1220 |
-
else
|
1221 |
-
{
|
1222 |
-
$definition = strtolower($Element['text']);
|
1223 |
-
}
|
1224 |
-
|
1225 |
-
if ( ! isset($this->DefinitionData['Reference'][$definition]))
|
1226 |
-
{
|
1227 |
-
return;
|
1228 |
-
}
|
1229 |
-
|
1230 |
-
$Definition = $this->DefinitionData['Reference'][$definition];
|
1231 |
-
|
1232 |
-
$Element['attributes']['href'] = $Definition['url'];
|
1233 |
-
$Element['attributes']['title'] = $Definition['title'];
|
1234 |
-
}
|
1235 |
-
|
1236 |
-
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
|
1237 |
-
|
1238 |
-
return array(
|
1239 |
-
'extent' => $extent,
|
1240 |
-
'element' => $Element,
|
1241 |
-
);
|
1242 |
-
}
|
1243 |
-
|
1244 |
-
protected function inlineMarkup($Excerpt)
|
1245 |
-
{
|
1246 |
-
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)
|
1247 |
-
{
|
1248 |
-
return;
|
1249 |
-
}
|
1250 |
-
|
1251 |
-
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches))
|
1252 |
-
{
|
1253 |
-
return array(
|
1254 |
-
'markup' => $matches[0],
|
1255 |
-
'extent' => strlen($matches[0]),
|
1256 |
-
);
|
1257 |
-
}
|
1258 |
-
|
1259 |
-
if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches))
|
1260 |
-
{
|
1261 |
-
return array(
|
1262 |
-
'markup' => $matches[0],
|
1263 |
-
'extent' => strlen($matches[0]),
|
1264 |
-
);
|
1265 |
-
}
|
1266 |
-
|
1267 |
-
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
|
1268 |
-
{
|
1269 |
-
return array(
|
1270 |
-
'markup' => $matches[0],
|
1271 |
-
'extent' => strlen($matches[0]),
|
1272 |
-
);
|
1273 |
-
}
|
1274 |
-
}
|
1275 |
-
|
1276 |
-
protected function inlineSpecialCharacter($Excerpt)
|
1277 |
-
{
|
1278 |
-
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text']))
|
1279 |
-
{
|
1280 |
-
return array(
|
1281 |
-
'markup' => '&',
|
1282 |
-
'extent' => 1,
|
1283 |
-
);
|
1284 |
-
}
|
1285 |
-
|
1286 |
-
$SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
|
1287 |
-
|
1288 |
-
if (isset($SpecialCharacter[$Excerpt['text'][0]]))
|
1289 |
-
{
|
1290 |
-
return array(
|
1291 |
-
'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';',
|
1292 |
-
'extent' => 1,
|
1293 |
-
);
|
1294 |
-
}
|
1295 |
-
}
|
1296 |
-
|
1297 |
-
protected function inlineStrikethrough($Excerpt)
|
1298 |
-
{
|
1299 |
-
if ( ! isset($Excerpt['text'][1]))
|
1300 |
-
{
|
1301 |
-
return;
|
1302 |
-
}
|
1303 |
-
|
1304 |
-
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
|
1305 |
-
{
|
1306 |
-
return array(
|
1307 |
-
'extent' => strlen($matches[0]),
|
1308 |
-
'element' => array(
|
1309 |
-
'name' => 'del',
|
1310 |
-
'text' => $matches[1],
|
1311 |
-
'handler' => 'line',
|
1312 |
-
),
|
1313 |
-
);
|
1314 |
-
}
|
1315 |
-
}
|
1316 |
-
|
1317 |
-
protected function inlineUrl($Excerpt)
|
1318 |
-
{
|
1319 |
-
if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')
|
1320 |
-
{
|
1321 |
-
return;
|
1322 |
-
}
|
1323 |
-
|
1324 |
-
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
|
1325 |
-
{
|
1326 |
-
$Inline = array(
|
1327 |
-
'extent' => strlen($matches[0][0]),
|
1328 |
-
'position' => $matches[0][1],
|
1329 |
-
'element' => array(
|
1330 |
-
'name' => 'a',
|
1331 |
-
'text' => $matches[0][0],
|
1332 |
-
'attributes' => array(
|
1333 |
-
'href' => $matches[0][0],
|
1334 |
-
),
|
1335 |
-
),
|
1336 |
-
);
|
1337 |
-
|
1338 |
-
return $Inline;
|
1339 |
-
}
|
1340 |
-
}
|
1341 |
-
|
1342 |
-
protected function inlineUrlTag($Excerpt)
|
1343 |
-
{
|
1344 |
-
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))
|
1345 |
-
{
|
1346 |
-
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
1347 |
-
|
1348 |
-
return array(
|
1349 |
-
'extent' => strlen($matches[0]),
|
1350 |
-
'element' => array(
|
1351 |
-
'name' => 'a',
|
1352 |
-
'text' => $url,
|
1353 |
-
'attributes' => array(
|
1354 |
-
'href' => $url,
|
1355 |
-
),
|
1356 |
-
),
|
1357 |
-
);
|
1358 |
-
}
|
1359 |
-
}
|
1360 |
-
|
1361 |
-
# ~
|
1362 |
-
|
1363 |
-
protected function unmarkedText($text)
|
1364 |
-
{
|
1365 |
-
if ($this->breaksEnabled)
|
1366 |
-
{
|
1367 |
-
$text = preg_replace('/[ ]*\n/', "<br />\n", $text);
|
1368 |
-
}
|
1369 |
-
else
|
1370 |
-
{
|
1371 |
-
$text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "<br />\n", $text);
|
1372 |
-
$text = str_replace(" \n", "\n", $text);
|
1373 |
-
}
|
1374 |
-
|
1375 |
-
return $text;
|
1376 |
-
}
|
1377 |
-
|
1378 |
-
#
|
1379 |
-
# Handlers
|
1380 |
-
#
|
1381 |
-
|
1382 |
-
protected function element(array $Element)
|
1383 |
-
{
|
1384 |
-
$markup = '<'.$Element['name'];
|
1385 |
-
|
1386 |
-
if (isset($Element['attributes']))
|
1387 |
-
{
|
1388 |
-
foreach ($Element['attributes'] as $name => $value)
|
1389 |
-
{
|
1390 |
-
if ($value === null)
|
1391 |
-
{
|
1392 |
-
continue;
|
1393 |
-
}
|
1394 |
-
|
1395 |
-
$markup .= ' '.$name.'="'.$value.'"';
|
1396 |
-
}
|
1397 |
-
}
|
1398 |
-
|
1399 |
-
if (isset($Element['text']))
|
1400 |
-
{
|
1401 |
-
$markup .= '>';
|
1402 |
-
|
1403 |
-
if (isset($Element['handler']))
|
1404 |
-
{
|
1405 |
-
$markup .= $this->{$Element['handler']}($Element['text']);
|
1406 |
-
}
|
1407 |
-
else
|
1408 |
-
{
|
1409 |
-
$markup .= $Element['text'];
|
1410 |
-
}
|
1411 |
-
|
1412 |
-
$markup .= '</'.$Element['name'].'>';
|
1413 |
-
}
|
1414 |
-
else
|
1415 |
-
{
|
1416 |
-
$markup .= ' />';
|
1417 |
-
}
|
1418 |
-
|
1419 |
-
return $markup;
|
1420 |
-
}
|
1421 |
-
|
1422 |
-
protected function elements(array $Elements)
|
1423 |
-
{
|
1424 |
-
$markup = '';
|
1425 |
-
|
1426 |
-
foreach ($Elements as $Element)
|
1427 |
-
{
|
1428 |
-
$markup .= "\n" . $this->element($Element);
|
1429 |
-
}
|
1430 |
-
|
1431 |
-
$markup .= "\n";
|
1432 |
-
|
1433 |
-
return $markup;
|
1434 |
-
}
|
1435 |
-
|
1436 |
-
# ~
|
1437 |
-
|
1438 |
-
protected function li($lines)
|
1439 |
-
{
|
1440 |
-
$markup = $this->lines($lines);
|
1441 |
-
|
1442 |
-
$trimmedMarkup = trim($markup);
|
1443 |
-
|
1444 |
-
if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>')
|
1445 |
-
{
|
1446 |
-
$markup = $trimmedMarkup;
|
1447 |
-
$markup = substr($markup, 3);
|
1448 |
-
|
1449 |
-
$position = strpos($markup, "</p>");
|
1450 |
-
|
1451 |
-
$markup = substr_replace($markup, '', $position, 4);
|
1452 |
-
}
|
1453 |
-
|
1454 |
-
return $markup;
|
1455 |
-
}
|
1456 |
-
|
1457 |
-
#
|
1458 |
-
# Deprecated Methods
|
1459 |
-
#
|
1460 |
-
|
1461 |
-
function parse($text)
|
1462 |
-
{
|
1463 |
-
$markup = $this->text($text);
|
1464 |
-
|
1465 |
-
return $markup;
|
1466 |
-
}
|
1467 |
-
|
1468 |
-
#
|
1469 |
-
# Static Methods
|
1470 |
-
#
|
1471 |
-
|
1472 |
-
static function instance($name = 'default')
|
1473 |
-
{
|
1474 |
-
if (isset(self::$instances[$name]))
|
1475 |
-
{
|
1476 |
-
return self::$instances[$name];
|
1477 |
-
}
|
1478 |
-
|
1479 |
-
$instance = new self(); // static doesn't work in php 5.2
|
1480 |
-
|
1481 |
-
self::$instances[$name] = $instance;
|
1482 |
-
|
1483 |
-
return $instance;
|
1484 |
-
}
|
1485 |
-
|
1486 |
-
private static $instances = array();
|
1487 |
-
|
1488 |
-
#
|
1489 |
-
# Fields
|
1490 |
-
#
|
1491 |
-
|
1492 |
-
protected $DefinitionData;
|
1493 |
-
|
1494 |
-
#
|
1495 |
-
# Read-Only
|
1496 |
-
|
1497 |
-
protected $specialCharacters = array(
|
1498 |
-
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|',
|
1499 |
-
);
|
1500 |
-
|
1501 |
-
protected $StrongRegex = array(
|
1502 |
-
'*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
|
1503 |
-
'_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',
|
1504 |
-
);
|
1505 |
-
|
1506 |
-
protected $EmRegex = array(
|
1507 |
-
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
1508 |
-
'_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
|
1509 |
-
);
|
1510 |
-
|
1511 |
-
protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?';
|
1512 |
-
|
1513 |
-
protected $voidElements = array(
|
1514 |
-
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',
|
1515 |
-
);
|
1516 |
-
|
1517 |
-
protected $textLevelElements = array(
|
1518 |
-
'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',
|
1519 |
-
'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',
|
1520 |
-
'i', 'rp', 'del', 'code', 'strike', 'marquee',
|
1521 |
-
'q', 'rt', 'ins', 'font', 'strong',
|
1522 |
-
's', 'tt', 'sub', 'mark',
|
1523 |
-
'u', 'xm', 'sup', 'nobr',
|
1524 |
-
'var', 'ruby',
|
1525 |
-
'wbr', 'span',
|
1526 |
-
'time',
|
1527 |
-
);
|
1528 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
#
|
4 |
+
#
|
5 |
+
# Parsedown
|
6 |
+
# http://parsedown.org
|
7 |
+
#
|
8 |
+
# (c) Emanuil Rusev
|
9 |
+
# http://erusev.com
|
10 |
+
#
|
11 |
+
# For the full license information, view the LICENSE file that was distributed
|
12 |
+
# with this source code.
|
13 |
+
#
|
14 |
+
#
|
15 |
+
|
16 |
+
class Parsedown
|
17 |
+
{
|
18 |
+
# ~
|
19 |
+
|
20 |
+
const version = '1.5.4';
|
21 |
+
|
22 |
+
# ~
|
23 |
+
|
24 |
+
function text($text)
|
25 |
+
{
|
26 |
+
# make sure no definitions are set
|
27 |
+
$this->DefinitionData = array();
|
28 |
+
|
29 |
+
# standardize line breaks
|
30 |
+
$text = str_replace(array("\r\n", "\r"), "\n", $text);
|
31 |
+
|
32 |
+
# remove surrounding line breaks
|
33 |
+
$text = trim($text, "\n");
|
34 |
+
|
35 |
+
# split text into lines
|
36 |
+
$lines = explode("\n", $text);
|
37 |
+
|
38 |
+
# iterate through lines to identify blocks
|
39 |
+
$markup = $this->lines($lines);
|
40 |
+
|
41 |
+
# trim line breaks
|
42 |
+
$markup = trim($markup, "\n");
|
43 |
+
|
44 |
+
return $markup;
|
45 |
+
}
|
46 |
+
|
47 |
+
#
|
48 |
+
# Setters
|
49 |
+
#
|
50 |
+
|
51 |
+
function setBreaksEnabled($breaksEnabled)
|
52 |
+
{
|
53 |
+
$this->breaksEnabled = $breaksEnabled;
|
54 |
+
|
55 |
+
return $this;
|
56 |
+
}
|
57 |
+
|
58 |
+
protected $breaksEnabled;
|
59 |
+
|
60 |
+
function setMarkupEscaped($markupEscaped)
|
61 |
+
{
|
62 |
+
$this->markupEscaped = $markupEscaped;
|
63 |
+
|
64 |
+
return $this;
|
65 |
+
}
|
66 |
+
|
67 |
+
protected $markupEscaped;
|
68 |
+
|
69 |
+
function setUrlsLinked($urlsLinked)
|
70 |
+
{
|
71 |
+
$this->urlsLinked = $urlsLinked;
|
72 |
+
|
73 |
+
return $this;
|
74 |
+
}
|
75 |
+
|
76 |
+
protected $urlsLinked = true;
|
77 |
+
|
78 |
+
#
|
79 |
+
# Lines
|
80 |
+
#
|
81 |
+
|
82 |
+
protected $BlockTypes = array(
|
83 |
+
'#' => array('Header'),
|
84 |
+
'*' => array('Rule', 'List'),
|
85 |
+
'+' => array('List'),
|
86 |
+
'-' => array('SetextHeader', 'Table', 'Rule', 'List'),
|
87 |
+
'0' => array('List'),
|
88 |
+
'1' => array('List'),
|
89 |
+
'2' => array('List'),
|
90 |
+
'3' => array('List'),
|
91 |
+
'4' => array('List'),
|
92 |
+
'5' => array('List'),
|
93 |
+
'6' => array('List'),
|
94 |
+
'7' => array('List'),
|
95 |
+
'8' => array('List'),
|
96 |
+
'9' => array('List'),
|
97 |
+
':' => array('Table'),
|
98 |
+
'<' => array('Comment', 'Markup'),
|
99 |
+
'=' => array('SetextHeader'),
|
100 |
+
'>' => array('Quote'),
|
101 |
+
'[' => array('Reference'),
|
102 |
+
'_' => array('Rule'),
|
103 |
+
'`' => array('FencedCode'),
|
104 |
+
'|' => array('Table'),
|
105 |
+
'~' => array('FencedCode'),
|
106 |
+
);
|
107 |
+
|
108 |
+
# ~
|
109 |
+
|
110 |
+
protected $unmarkedBlockTypes = array(
|
111 |
+
'Code',
|
112 |
+
);
|
113 |
+
|
114 |
+
#
|
115 |
+
# Blocks
|
116 |
+
#
|
117 |
+
|
118 |
+
private function lines(array $lines)
|
119 |
+
{
|
120 |
+
$CurrentBlock = null;
|
121 |
+
|
122 |
+
foreach ($lines as $line)
|
123 |
+
{
|
124 |
+
if (chop($line) === '')
|
125 |
+
{
|
126 |
+
if (isset($CurrentBlock))
|
127 |
+
{
|
128 |
+
$CurrentBlock['interrupted'] = true;
|
129 |
+
}
|
130 |
+
|
131 |
+
continue;
|
132 |
+
}
|
133 |
+
|
134 |
+
if (strpos($line, "\t") !== false)
|
135 |
+
{
|
136 |
+
$parts = explode("\t", $line);
|
137 |
+
|
138 |
+
$line = $parts[0];
|
139 |
+
|
140 |
+
unset($parts[0]);
|
141 |
+
|
142 |
+
foreach ($parts as $part)
|
143 |
+
{
|
144 |
+
$shortage = 4 - mb_strlen($line, 'utf-8') % 4;
|
145 |
+
|
146 |
+
$line .= str_repeat(' ', $shortage);
|
147 |
+
$line .= $part;
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
$indent = 0;
|
152 |
+
|
153 |
+
while (isset($line[$indent]) and $line[$indent] === ' ')
|
154 |
+
{
|
155 |
+
$indent ++;
|
156 |
+
}
|
157 |
+
|
158 |
+
$text = $indent > 0 ? substr($line, $indent) : $line;
|
159 |
+
|
160 |
+
# ~
|
161 |
+
|
162 |
+
$Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
|
163 |
+
|
164 |
+
# ~
|
165 |
+
|
166 |
+
if (isset($CurrentBlock['continuable']))
|
167 |
+
{
|
168 |
+
$Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock);
|
169 |
+
|
170 |
+
if (isset($Block))
|
171 |
+
{
|
172 |
+
$CurrentBlock = $Block;
|
173 |
+
|
174 |
+
continue;
|
175 |
+
}
|
176 |
+
else
|
177 |
+
{
|
178 |
+
if (method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
179 |
+
{
|
180 |
+
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
}
|
184 |
+
|
185 |
+
# ~
|
186 |
+
|
187 |
+
$marker = $text[0];
|
188 |
+
|
189 |
+
# ~
|
190 |
+
|
191 |
+
$blockTypes = $this->unmarkedBlockTypes;
|
192 |
+
|
193 |
+
if (isset($this->BlockTypes[$marker]))
|
194 |
+
{
|
195 |
+
foreach ($this->BlockTypes[$marker] as $blockType)
|
196 |
+
{
|
197 |
+
$blockTypes []= $blockType;
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
#
|
202 |
+
# ~
|
203 |
+
|
204 |
+
foreach ($blockTypes as $blockType)
|
205 |
+
{
|
206 |
+
$Block = $this->{'block'.$blockType}($Line, $CurrentBlock);
|
207 |
+
|
208 |
+
if (isset($Block))
|
209 |
+
{
|
210 |
+
$Block['type'] = $blockType;
|
211 |
+
|
212 |
+
if ( ! isset($Block['identified']))
|
213 |
+
{
|
214 |
+
$Blocks []= $CurrentBlock;
|
215 |
+
|
216 |
+
$Block['identified'] = true;
|
217 |
+
}
|
218 |
+
|
219 |
+
if (method_exists($this, 'block'.$blockType.'Continue'))
|
220 |
+
{
|
221 |
+
$Block['continuable'] = true;
|
222 |
+
}
|
223 |
+
|
224 |
+
$CurrentBlock = $Block;
|
225 |
+
|
226 |
+
continue 2;
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
# ~
|
231 |
+
|
232 |
+
if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted']))
|
233 |
+
{
|
234 |
+
$CurrentBlock['element']['text'] .= "\n".$text;
|
235 |
+
}
|
236 |
+
else
|
237 |
+
{
|
238 |
+
$Blocks []= $CurrentBlock;
|
239 |
+
|
240 |
+
$CurrentBlock = $this->paragraph($Line);
|
241 |
+
|
242 |
+
$CurrentBlock['identified'] = true;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
# ~
|
247 |
+
|
248 |
+
if (isset($CurrentBlock['continuable']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
249 |
+
{
|
250 |
+
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
251 |
+
}
|
252 |
+
|
253 |
+
# ~
|
254 |
+
|
255 |
+
$Blocks []= $CurrentBlock;
|
256 |
+
|
257 |
+
unset($Blocks[0]);
|
258 |
+
|
259 |
+
# ~
|
260 |
+
|
261 |
+
$markup = '';
|
262 |
+
|
263 |
+
foreach ($Blocks as $Block)
|
264 |
+
{
|
265 |
+
if (isset($Block['hidden']))
|
266 |
+
{
|
267 |
+
continue;
|
268 |
+
}
|
269 |
+
|
270 |
+
$markup .= "\n";
|
271 |
+
$markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']);
|
272 |
+
}
|
273 |
+
|
274 |
+
$markup .= "\n";
|
275 |
+
|
276 |
+
# ~
|
277 |
+
|
278 |
+
return $markup;
|
279 |
+
}
|
280 |
+
|
281 |
+
#
|
282 |
+
# Code
|
283 |
+
|
284 |
+
protected function blockCode($Line, $Block = null)
|
285 |
+
{
|
286 |
+
if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted']))
|
287 |
+
{
|
288 |
+
return;
|
289 |
+
}
|
290 |
+
|
291 |
+
if ($Line['indent'] >= 4)
|
292 |
+
{
|
293 |
+
$text = substr($Line['body'], 4);
|
294 |
+
|
295 |
+
$Block = array(
|
296 |
+
'element' => array(
|
297 |
+
'name' => 'pre',
|
298 |
+
'handler' => 'element',
|
299 |
+
'text' => array(
|
300 |
+
'name' => 'code',
|
301 |
+
'text' => $text,
|
302 |
+
),
|
303 |
+
),
|
304 |
+
);
|
305 |
+
|
306 |
+
return $Block;
|
307 |
+
}
|
308 |
+
}
|
309 |
+
|
310 |
+
protected function blockCodeContinue($Line, $Block)
|
311 |
+
{
|
312 |
+
if ($Line['indent'] >= 4)
|
313 |
+
{
|
314 |
+
if (isset($Block['interrupted']))
|
315 |
+
{
|
316 |
+
$Block['element']['text']['text'] .= "\n";
|
317 |
+
|
318 |
+
unset($Block['interrupted']);
|
319 |
+
}
|
320 |
+
|
321 |
+
$Block['element']['text']['text'] .= "\n";
|
322 |
+
|
323 |
+
$text = substr($Line['body'], 4);
|
324 |
+
|
325 |
+
$Block['element']['text']['text'] .= $text;
|
326 |
+
|
327 |
+
return $Block;
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
protected function blockCodeComplete($Block)
|
332 |
+
{
|
333 |
+
$text = $Block['element']['text']['text'];
|
334 |
+
|
335 |
+
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
336 |
+
|
337 |
+
$Block['element']['text']['text'] = $text;
|
338 |
+
|
339 |
+
return $Block;
|
340 |
+
}
|
341 |
+
|
342 |
+
#
|
343 |
+
# Comment
|
344 |
+
|
345 |
+
protected function blockComment($Line)
|
346 |
+
{
|
347 |
+
if ($this->markupEscaped)
|
348 |
+
{
|
349 |
+
return;
|
350 |
+
}
|
351 |
+
|
352 |
+
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')
|
353 |
+
{
|
354 |
+
$Block = array(
|
355 |
+
'markup' => $Line['body'],
|
356 |
+
);
|
357 |
+
|
358 |
+
if (preg_match('/-->$/', $Line['text']))
|
359 |
+
{
|
360 |
+
$Block['closed'] = true;
|
361 |
+
}
|
362 |
+
|
363 |
+
return $Block;
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
protected function blockCommentContinue($Line, array $Block)
|
368 |
+
{
|
369 |
+
if (isset($Block['closed']))
|
370 |
+
{
|
371 |
+
return;
|
372 |
+
}
|
373 |
+
|
374 |
+
$Block['markup'] .= "\n" . $Line['body'];
|
375 |
+
|
376 |
+
if (preg_match('/-->$/', $Line['text']))
|
377 |
+
{
|
378 |
+
$Block['closed'] = true;
|
379 |
+
}
|
380 |
+
|
381 |
+
return $Block;
|
382 |
+
}
|
383 |
+
|
384 |
+
#
|
385 |
+
# Fenced Code
|
386 |
+
|
387 |
+
protected function blockFencedCode($Line)
|
388 |
+
{
|
389 |
+
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
390 |
+
{
|
391 |
+
$Element = array(
|
392 |
+
'name' => 'code',
|
393 |
+
'text' => '',
|
394 |
+
);
|
395 |
+
|
396 |
+
if (isset($matches[1]))
|
397 |
+
{
|
398 |
+
$class = 'language-'.$matches[1];
|
399 |
+
|
400 |
+
$Element['attributes'] = array(
|
401 |
+
'class' => $class,
|
402 |
+
);
|
403 |
+
}
|
404 |
+
|
405 |
+
$Block = array(
|
406 |
+
'char' => $Line['text'][0],
|
407 |
+
'element' => array(
|
408 |
+
'name' => 'pre',
|
409 |
+
'handler' => 'element',
|
410 |
+
'text' => $Element,
|
411 |
+
),
|
412 |
+
);
|
413 |
+
|
414 |
+
return $Block;
|
415 |
+
}
|
416 |
+
}
|
417 |
+
|
418 |
+
protected function blockFencedCodeContinue($Line, $Block)
|
419 |
+
{
|
420 |
+
if (isset($Block['complete']))
|
421 |
+
{
|
422 |
+
return;
|
423 |
+
}
|
424 |
+
|
425 |
+
if (isset($Block['interrupted']))
|
426 |
+
{
|
427 |
+
$Block['element']['text']['text'] .= "\n";
|
428 |
+
|
429 |
+
unset($Block['interrupted']);
|
430 |
+
}
|
431 |
+
|
432 |
+
if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text']))
|
433 |
+
{
|
434 |
+
$Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1);
|
435 |
+
|
436 |
+
$Block['complete'] = true;
|
437 |
+
|
438 |
+
return $Block;
|
439 |
+
}
|
440 |
+
|
441 |
+
$Block['element']['text']['text'] .= "\n".$Line['body'];;
|
442 |
+
|
443 |
+
return $Block;
|
444 |
+
}
|
445 |
+
|
446 |
+
protected function blockFencedCodeComplete($Block)
|
447 |
+
{
|
448 |
+
$text = $Block['element']['text']['text'];
|
449 |
+
|
450 |
+
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
451 |
+
|
452 |
+
$Block['element']['text']['text'] = $text;
|
453 |
+
|
454 |
+
return $Block;
|
455 |
+
}
|
456 |
+
|
457 |
+
#
|
458 |
+
# Header
|
459 |
+
|
460 |
+
protected function blockHeader($Line)
|
461 |
+
{
|
462 |
+
if (isset($Line['text'][1]))
|
463 |
+
{
|
464 |
+
$level = 1;
|
465 |
+
|
466 |
+
while (isset($Line['text'][$level]) and $Line['text'][$level] === '#')
|
467 |
+
{
|
468 |
+
$level ++;
|
469 |
+
}
|
470 |
+
|
471 |
+
if ($level > 6)
|
472 |
+
{
|
473 |
+
return;
|
474 |
+
}
|
475 |
+
|
476 |
+
$text = trim($Line['text'], '# ');
|
477 |
+
|
478 |
+
$Block = array(
|
479 |
+
'element' => array(
|
480 |
+
'name' => 'h' . min(6, $level),
|
481 |
+
'text' => $text,
|
482 |
+
'handler' => 'line',
|
483 |
+
),
|
484 |
+
);
|
485 |
+
|
486 |
+
return $Block;
|
487 |
+
}
|
488 |
+
}
|
489 |
+
|
490 |
+
#
|
491 |
+
# List
|
492 |
+
|
493 |
+
protected function blockList($Line)
|
494 |
+
{
|
495 |
+
list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]');
|
496 |
+
|
497 |
+
if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches))
|
498 |
+
{
|
499 |
+
$Block = array(
|
500 |
+
'indent' => $Line['indent'],
|
501 |
+
'pattern' => $pattern,
|
502 |
+
'element' => array(
|
503 |
+
'name' => $name,
|
504 |
+
'handler' => 'elements',
|
505 |
+
),
|
506 |
+
);
|
507 |
+
|
508 |
+
$Block['li'] = array(
|
509 |
+
'name' => 'li',
|
510 |
+
'handler' => 'li',
|
511 |
+
'text' => array(
|
512 |
+
$matches[2],
|
513 |
+
),
|
514 |
+
);
|
515 |
+
|
516 |
+
$Block['element']['text'] []= & $Block['li'];
|
517 |
+
|
518 |
+
return $Block;
|
519 |
+
}
|
520 |
+
}
|
521 |
+
|
522 |
+
protected function blockListContinue($Line, array $Block)
|
523 |
+
{
|
524 |
+
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches))
|
525 |
+
{
|
526 |
+
if (isset($Block['interrupted']))
|
527 |
+
{
|
528 |
+
$Block['li']['text'] []= '';
|
529 |
+
|
530 |
+
unset($Block['interrupted']);
|
531 |
+
}
|
532 |
+
|
533 |
+
unset($Block['li']);
|
534 |
+
|
535 |
+
$text = isset($matches[1]) ? $matches[1] : '';
|
536 |
+
|
537 |
+
$Block['li'] = array(
|
538 |
+
'name' => 'li',
|
539 |
+
'handler' => 'li',
|
540 |
+
'text' => array(
|
541 |
+
$text,
|
542 |
+
),
|
543 |
+
);
|
544 |
+
|
545 |
+
$Block['element']['text'] []= & $Block['li'];
|
546 |
+
|
547 |
+
return $Block;
|
548 |
+
}
|
549 |
+
|
550 |
+
if ($Line['text'][0] === '[' and $this->blockReference($Line))
|
551 |
+
{
|
552 |
+
return $Block;
|
553 |
+
}
|
554 |
+
|
555 |
+
if ( ! isset($Block['interrupted']))
|
556 |
+
{
|
557 |
+
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
|
558 |
+
|
559 |
+
$Block['li']['text'] []= $text;
|
560 |
+
|
561 |
+
return $Block;
|
562 |
+
}
|
563 |
+
|
564 |
+
if ($Line['indent'] > 0)
|
565 |
+
{
|
566 |
+
$Block['li']['text'] []= '';
|
567 |
+
|
568 |
+
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
|
569 |
+
|
570 |
+
$Block['li']['text'] []= $text;
|
571 |
+
|
572 |
+
unset($Block['interrupted']);
|
573 |
+
|
574 |
+
return $Block;
|
575 |
+
}
|
576 |
+
}
|
577 |
+
|
578 |
+
#
|
579 |
+
# Quote
|
580 |
+
|
581 |
+
protected function blockQuote($Line)
|
582 |
+
{
|
583 |
+
if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
|
584 |
+
{
|
585 |
+
$Block = array(
|
586 |
+
'element' => array(
|
587 |
+
'name' => 'blockquote',
|
588 |
+
'handler' => 'lines',
|
589 |
+
'text' => (array) $matches[1],
|
590 |
+
),
|
591 |
+
);
|
592 |
+
|
593 |
+
return $Block;
|
594 |
+
}
|
595 |
+
}
|
596 |
+
|
597 |
+
protected function blockQuoteContinue($Line, array $Block)
|
598 |
+
{
|
599 |
+
if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
|
600 |
+
{
|
601 |
+
if (isset($Block['interrupted']))
|
602 |
+
{
|
603 |
+
$Block['element']['text'] []= '';
|
604 |
+
|
605 |
+
unset($Block['interrupted']);
|
606 |
+
}
|
607 |
+
|
608 |
+
$Block['element']['text'] []= $matches[1];
|
609 |
+
|
610 |
+
return $Block;
|
611 |
+
}
|
612 |
+
|
613 |
+
if ( ! isset($Block['interrupted']))
|
614 |
+
{
|
615 |
+
$Block['element']['text'] []= $Line['text'];
|
616 |
+
|
617 |
+
return $Block;
|
618 |
+
}
|
619 |
+
}
|
620 |
+
|
621 |
+
#
|
622 |
+
# Rule
|
623 |
+
|
624 |
+
protected function blockRule($Line)
|
625 |
+
{
|
626 |
+
if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text']))
|
627 |
+
{
|
628 |
+
$Block = array(
|
629 |
+
'element' => array(
|
630 |
+
'name' => 'hr'
|
631 |
+
),
|
632 |
+
);
|
633 |
+
|
634 |
+
return $Block;
|
635 |
+
}
|
636 |
+
}
|
637 |
+
|
638 |
+
#
|
639 |
+
# Setext
|
640 |
+
|
641 |
+
protected function blockSetextHeader($Line, array $Block = null)
|
642 |
+
{
|
643 |
+
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
644 |
+
{
|
645 |
+
return;
|
646 |
+
}
|
647 |
+
|
648 |
+
if (chop($Line['text'], $Line['text'][0]) === '')
|
649 |
+
{
|
650 |
+
$Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';
|
651 |
+
|
652 |
+
return $Block;
|
653 |
+
}
|
654 |
+
}
|
655 |
+
|
656 |
+
#
|
657 |
+
# Markup
|
658 |
+
|
659 |
+
protected function blockMarkup($Line)
|
660 |
+
{
|
661 |
+
if ($this->markupEscaped)
|
662 |
+
{
|
663 |
+
return;
|
664 |
+
}
|
665 |
+
|
666 |
+
if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
667 |
+
{
|
668 |
+
$element = strtolower($matches[1]);
|
669 |
+
|
670 |
+
if (in_array($element, $this->textLevelElements))
|
671 |
+
{
|
672 |
+
return;
|
673 |
+
}
|
674 |
+
|
675 |
+
$Block = array(
|
676 |
+
'name' => $matches[1],
|
677 |
+
'depth' => 0,
|
678 |
+
'markup' => $Line['text'],
|
679 |
+
);
|
680 |
+
|
681 |
+
$length = strlen($matches[0]);
|
682 |
+
|
683 |
+
$remainder = substr($Line['text'], $length);
|
684 |
+
|
685 |
+
if (trim($remainder) === '')
|
686 |
+
{
|
687 |
+
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
688 |
+
{
|
689 |
+
$Block['closed'] = true;
|
690 |
+
|
691 |
+
$Block['void'] = true;
|
692 |
+
}
|
693 |
+
}
|
694 |
+
else
|
695 |
+
{
|
696 |
+
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
697 |
+
{
|
698 |
+
return;
|
699 |
+
}
|
700 |
+
|
701 |
+
if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder))
|
702 |
+
{
|
703 |
+
$Block['closed'] = true;
|
704 |
+
}
|
705 |
+
}
|
706 |
+
|
707 |
+
return $Block;
|
708 |
+
}
|
709 |
+
}
|
710 |
+
|
711 |
+
protected function blockMarkupContinue($Line, array $Block)
|
712 |
+
{
|
713 |
+
if (isset($Block['closed']))
|
714 |
+
{
|
715 |
+
return;
|
716 |
+
}
|
717 |
+
|
718 |
+
if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open
|
719 |
+
{
|
720 |
+
$Block['depth'] ++;
|
721 |
+
}
|
722 |
+
|
723 |
+
if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close
|
724 |
+
{
|
725 |
+
if ($Block['depth'] > 0)
|
726 |
+
{
|
727 |
+
$Block['depth'] --;
|
728 |
+
}
|
729 |
+
else
|
730 |
+
{
|
731 |
+
$Block['closed'] = true;
|
732 |
+
}
|
733 |
+
}
|
734 |
+
|
735 |
+
if (isset($Block['interrupted']))
|
736 |
+
{
|
737 |
+
$Block['markup'] .= "\n";
|
738 |
+
|
739 |
+
unset($Block['interrupted']);
|
740 |
+
}
|
741 |
+
|
742 |
+
$Block['markup'] .= "\n".$Line['body'];
|
743 |
+
|
744 |
+
return $Block;
|
745 |
+
}
|
746 |
+
|
747 |
+
#
|
748 |
+
# Reference
|
749 |
+
|
750 |
+
protected function blockReference($Line)
|
751 |
+
{
|
752 |
+
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches))
|
753 |
+
{
|
754 |
+
$id = strtolower($matches[1]);
|
755 |
+
|
756 |
+
$Data = array(
|
757 |
+
'url' => $matches[2],
|
758 |
+
'title' => null,
|
759 |
+
);
|
760 |
+
|
761 |
+
if (isset($matches[3]))
|
762 |
+
{
|
763 |
+
$Data['title'] = $matches[3];
|
764 |
+
}
|
765 |
+
|
766 |
+
$this->DefinitionData['Reference'][$id] = $Data;
|
767 |
+
|
768 |
+
$Block = array(
|
769 |
+
'hidden' => true,
|
770 |
+
);
|
771 |
+
|
772 |
+
return $Block;
|
773 |
+
}
|
774 |
+
}
|
775 |
+
|
776 |
+
#
|
777 |
+
# Table
|
778 |
+
|
779 |
+
protected function blockTable($Line, array $Block = null)
|
780 |
+
{
|
781 |
+
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
782 |
+
{
|
783 |
+
return;
|
784 |
+
}
|
785 |
+
|
786 |
+
if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '')
|
787 |
+
{
|
788 |
+
$alignments = array();
|
789 |
+
|
790 |
+
$divider = $Line['text'];
|
791 |
+
|
792 |
+
$divider = trim($divider);
|
793 |
+
$divider = trim($divider, '|');
|
794 |
+
|
795 |
+
$dividerCells = explode('|', $divider);
|
796 |
+
|
797 |
+
foreach ($dividerCells as $dividerCell)
|
798 |
+
{
|
799 |
+
$dividerCell = trim($dividerCell);
|
800 |
+
|
801 |
+
if ($dividerCell === '')
|
802 |
+
{
|
803 |
+
continue;
|
804 |
+
}
|
805 |
+
|
806 |
+
$alignment = null;
|
807 |
+
|
808 |
+
if ($dividerCell[0] === ':')
|
809 |
+
{
|
810 |
+
$alignment = 'left';
|
811 |
+
}
|
812 |
+
|
813 |
+
if (substr($dividerCell, - 1) === ':')
|
814 |
+
{
|
815 |
+
$alignment = $alignment === 'left' ? 'center' : 'right';
|
816 |
+
}
|
817 |
+
|
818 |
+
$alignments []= $alignment;
|
819 |
+
}
|
820 |
+
|
821 |
+
# ~
|
822 |
+
|
823 |
+
$HeaderElements = array();
|
824 |
+
|
825 |
+
$header = $Block['element']['text'];
|
826 |
+
|
827 |
+
$header = trim($header);
|
828 |
+
$header = trim($header, '|');
|
829 |
+
|
830 |
+
$headerCells = explode('|', $header);
|
831 |
+
|
832 |
+
foreach ($headerCells as $index => $headerCell)
|
833 |
+
{
|
834 |
+
$headerCell = trim($headerCell);
|
835 |
+
|
836 |
+
$HeaderElement = array(
|
837 |
+
'name' => 'th',
|
838 |
+
'text' => $headerCell,
|
839 |
+
'handler' => 'line',
|
840 |
+
);
|
841 |
+
|
842 |
+
if (isset($alignments[$index]))
|
843 |
+
{
|
844 |
+
$alignment = $alignments[$index];
|
845 |
+
|
846 |
+
$HeaderElement['attributes'] = array(
|
847 |
+
'style' => 'text-align: '.$alignment.';',
|
848 |
+
);
|
849 |
+
}
|
850 |
+
|
851 |
+
$HeaderElements []= $HeaderElement;
|
852 |
+
}
|
853 |
+
|
854 |
+
# ~
|
855 |
+
|
856 |
+
$Block = array(
|
857 |
+
'alignments' => $alignments,
|
858 |
+
'identified' => true,
|
859 |
+
'element' => array(
|
860 |
+
'name' => 'table',
|
861 |
+
'handler' => 'elements',
|
862 |
+
),
|
863 |
+
);
|
864 |
+
|
865 |
+
$Block['element']['text'] []= array(
|
866 |
+
'name' => 'thead',
|
867 |
+
'handler' => 'elements',
|
868 |
+
);
|
869 |
+
|
870 |
+
$Block['element']['text'] []= array(
|
871 |
+
'name' => 'tbody',
|
872 |
+
'handler' => 'elements',
|
873 |
+
'text' => array(),
|
874 |
+
);
|
875 |
+
|
876 |
+
$Block['element']['text'][0]['text'] []= array(
|
877 |
+
'name' => 'tr',
|
878 |
+
'handler' => 'elements',
|
879 |
+
'text' => $HeaderElements,
|
880 |
+
);
|
881 |
+
|
882 |
+
return $Block;
|
883 |
+
}
|
884 |
+
}
|
885 |
+
|
886 |
+
protected function blockTableContinue($Line, array $Block)
|
887 |
+
{
|
888 |
+
if (isset($Block['interrupted']))
|
889 |
+
{
|
890 |
+
return;
|
891 |
+
}
|
892 |
+
|
893 |
+
if ($Line['text'][0] === '|' or strpos($Line['text'], '|'))
|
894 |
+
{
|
895 |
+
$Elements = array();
|
896 |
+
|
897 |
+
$row = $Line['text'];
|
898 |
+
|
899 |
+
$row = trim($row);
|
900 |
+
$row = trim($row, '|');
|
901 |
+
|
902 |
+
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);
|
903 |
+
|
904 |
+
foreach ($matches[0] as $index => $cell)
|
905 |
+
{
|
906 |
+
$cell = trim($cell);
|
907 |
+
|
908 |
+
$Element = array(
|
909 |
+
'name' => 'td',
|
910 |
+
'handler' => 'line',
|
911 |
+
'text' => $cell,
|
912 |
+
);
|
913 |
+
|
914 |
+
if (isset($Block['alignments'][$index]))
|
915 |
+
{
|
916 |
+
$Element['attributes'] = array(
|
917 |
+
'style' => 'text-align: '.$Block['alignments'][$index].';',
|
918 |
+
);
|
919 |
+
}
|
920 |
+
|
921 |
+
$Elements []= $Element;
|
922 |
+
}
|
923 |
+
|
924 |
+
$Element = array(
|
925 |
+
'name' => 'tr',
|
926 |
+
'handler' => 'elements',
|
927 |
+
'text' => $Elements,
|
928 |
+
);
|
929 |
+
|
930 |
+
$Block['element']['text'][1]['text'] []= $Element;
|
931 |
+
|
932 |
+
return $Block;
|
933 |
+
}
|
934 |
+
}
|
935 |
+
|
936 |
+
#
|
937 |
+
# ~
|
938 |
+
#
|
939 |
+
|
940 |
+
protected function paragraph($Line)
|
941 |
+
{
|
942 |
+
$Block = array(
|
943 |
+
'element' => array(
|
944 |
+
'name' => 'p',
|
945 |
+
'text' => $Line['text'],
|
946 |
+
'handler' => 'line',
|
947 |
+
),
|
948 |
+
);
|
949 |
+
|
950 |
+
return $Block;
|
951 |
+
}
|
952 |
+
|
953 |
+
#
|
954 |
+
# Inline Elements
|
955 |
+
#
|
956 |
+
|
957 |
+
protected $InlineTypes = array(
|
958 |
+
'"' => array('SpecialCharacter'),
|
959 |
+
'!' => array('Image'),
|
960 |
+
'&' => array('SpecialCharacter'),
|
961 |
+
'*' => array('Emphasis'),
|
962 |
+
':' => array('Url'),
|
963 |
+
'<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),
|
964 |
+
'>' => array('SpecialCharacter'),
|
965 |
+
'[' => array('Link'),
|
966 |
+
'_' => array('Emphasis'),
|
967 |
+
'`' => array('Code'),
|
968 |
+
'~' => array('Strikethrough'),
|
969 |
+
'\\' => array('EscapeSequence'),
|
970 |
+
);
|
971 |
+
|
972 |
+
# ~
|
973 |
+
|
974 |
+
protected $inlineMarkerList = '!"*_&[:<>`~\\';
|
975 |
+
|
976 |
+
#
|
977 |
+
# ~
|
978 |
+
#
|
979 |
+
|
980 |
+
public function line($text)
|
981 |
+
{
|
982 |
+
$markup = '';
|
983 |
+
|
984 |
+
# $excerpt is based on the first occurrence of a marker
|
985 |
+
|
986 |
+
while ($excerpt = strpbrk($text, $this->inlineMarkerList))
|
987 |
+
{
|
988 |
+
$marker = $excerpt[0];
|
989 |
+
|
990 |
+
$markerPosition = strpos($text, $marker);
|
991 |
+
|
992 |
+
$Excerpt = array('text' => $excerpt, 'context' => $text);
|
993 |
+
|
994 |
+
foreach ($this->InlineTypes[$marker] as $inlineType)
|
995 |
+
{
|
996 |
+
$Inline = $this->{'inline'.$inlineType}($Excerpt);
|
997 |
+
|
998 |
+
if ( ! isset($Inline))
|
999 |
+
{
|
1000 |
+
continue;
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
# makes sure that the inline belongs to "our" marker
|
1004 |
+
|
1005 |
+
if (isset($Inline['position']) and $Inline['position'] > $markerPosition)
|
1006 |
+
{
|
1007 |
+
continue;
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
# sets a default inline position
|
1011 |
+
|
1012 |
+
if ( ! isset($Inline['position']))
|
1013 |
+
{
|
1014 |
+
$Inline['position'] = $markerPosition;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
# the text that comes before the inline
|
1018 |
+
$unmarkedText = substr($text, 0, $Inline['position']);
|
1019 |
+
|
1020 |
+
# compile the unmarked text
|
1021 |
+
$markup .= $this->unmarkedText($unmarkedText);
|
1022 |
+
|
1023 |
+
# compile the inline
|
1024 |
+
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);
|
1025 |
+
|
1026 |
+
# remove the examined text
|
1027 |
+
$text = substr($text, $Inline['position'] + $Inline['extent']);
|
1028 |
+
|
1029 |
+
continue 2;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
# the marker does not belong to an inline
|
1033 |
+
|
1034 |
+
$unmarkedText = substr($text, 0, $markerPosition + 1);
|
1035 |
+
|
1036 |
+
$markup .= $this->unmarkedText($unmarkedText);
|
1037 |
+
|
1038 |
+
$text = substr($text, $markerPosition + 1);
|
1039 |
+
}
|
1040 |
+
|
1041 |
+
$markup .= $this->unmarkedText($text);
|
1042 |
+
|
1043 |
+
return $markup;
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
#
|
1047 |
+
# ~
|
1048 |
+
#
|
1049 |
+
|
1050 |
+
protected function inlineCode($Excerpt)
|
1051 |
+
{
|
1052 |
+
$marker = $Excerpt['text'][0];
|
1053 |
+
|
1054 |
+
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
|
1055 |
+
{
|
1056 |
+
$text = $matches[2];
|
1057 |
+
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
1058 |
+
$text = preg_replace("/[ ]*\n/", ' ', $text);
|
1059 |
+
|
1060 |
+
return array(
|
1061 |
+
'extent' => strlen($matches[0]),
|
1062 |
+
'element' => array(
|
1063 |
+
'name' => 'code',
|
1064 |
+
'text' => $text,
|
1065 |
+
),
|
1066 |
+
);
|
1067 |
+
}
|
1068 |
+
}
|
1069 |
+
|
1070 |
+
protected function inlineEmailTag($Excerpt)
|
1071 |
+
{
|
1072 |
+
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches))
|
1073 |
+
{
|
1074 |
+
$url = $matches[1];
|
1075 |
+
|
1076 |
+
if ( ! isset($matches[2]))
|
1077 |
+
{
|
1078 |
+
$url = 'mailto:' . $url;
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
return array(
|
1082 |
+
'extent' => strlen($matches[0]),
|
1083 |
+
'element' => array(
|
1084 |
+
'name' => 'a',
|
1085 |
+
'text' => $matches[1],
|
1086 |
+
'attributes' => array(
|
1087 |
+
'href' => $url,
|
1088 |
+
),
|
1089 |
+
),
|
1090 |
+
);
|
1091 |
+
}
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
protected function inlineEmphasis($Excerpt)
|
1095 |
+
{
|
1096 |
+
if ( ! isset($Excerpt['text'][1]))
|
1097 |
+
{
|
1098 |
+
return;
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
$marker = $Excerpt['text'][0];
|
1102 |
+
|
1103 |
+
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
|
1104 |
+
{
|
1105 |
+
$emphasis = 'strong';
|
1106 |
+
}
|
1107 |
+
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
|
1108 |
+
{
|
1109 |
+
$emphasis = 'em';
|
1110 |
+
}
|
1111 |
+
else
|
1112 |
+
{
|
1113 |
+
return;
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
return array(
|
1117 |
+
'extent' => strlen($matches[0]),
|
1118 |
+
'element' => array(
|
1119 |
+
'name' => $emphasis,
|
1120 |
+
'handler' => 'line',
|
1121 |
+
'text' => $matches[1],
|
1122 |
+
),
|
1123 |
+
);
|
1124 |
+
}
|
1125 |
+
|
1126 |
+
protected function inlineEscapeSequence($Excerpt)
|
1127 |
+
{
|
1128 |
+
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
|
1129 |
+
{
|
1130 |
+
return array(
|
1131 |
+
'markup' => $Excerpt['text'][1],
|
1132 |
+
'extent' => 2,
|
1133 |
+
);
|
1134 |
+
}
|
1135 |
+
}
|
1136 |
+
|
1137 |
+
protected function inlineImage($Excerpt)
|
1138 |
+
{
|
1139 |
+
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
|
1140 |
+
{
|
1141 |
+
return;
|
1142 |
+
}
|
1143 |
+
|
1144 |
+
$Excerpt['text']= substr($Excerpt['text'], 1);
|
1145 |
+
|
1146 |
+
$Link = $this->inlineLink($Excerpt);
|
1147 |
+
|
1148 |
+
if ($Link === null)
|
1149 |
+
{
|
1150 |
+
return;
|
1151 |
+
}
|
1152 |
+
|
1153 |
+
$Inline = array(
|
1154 |
+
'extent' => $Link['extent'] + 1,
|
1155 |
+
'element' => array(
|
1156 |
+
'name' => 'img',
|
1157 |
+
'attributes' => array(
|
1158 |
+
'src' => $Link['element']['attributes']['href'],
|
1159 |
+
'alt' => $Link['element']['text'],
|
1160 |
+
),
|
1161 |
+
),
|
1162 |
+
);
|
1163 |
+
|
1164 |
+
$Inline['element']['attributes'] += $Link['element']['attributes'];
|
1165 |
+
|
1166 |
+
unset($Inline['element']['attributes']['href']);
|
1167 |
+
|
1168 |
+
return $Inline;
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
protected function inlineLink($Excerpt)
|
1172 |
+
{
|
1173 |
+
$Element = array(
|
1174 |
+
'name' => 'a',
|
1175 |
+
'handler' => 'line',
|
1176 |
+
'text' => null,
|
1177 |
+
'attributes' => array(
|
1178 |
+
'href' => null,
|
1179 |
+
'title' => null,
|
1180 |
+
),
|
1181 |
+
);
|
1182 |
+
|
1183 |
+
$extent = 0;
|
1184 |
+
|
1185 |
+
$remainder = $Excerpt['text'];
|
1186 |
+
|
1187 |
+
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
|
1188 |
+
{
|
1189 |
+
$Element['text'] = $matches[1];
|
1190 |
+
|
1191 |
+
$extent += strlen($matches[0]);
|
1192 |
+
|
1193 |
+
$remainder = substr($remainder, $extent);
|
1194 |
+
}
|
1195 |
+
else
|
1196 |
+
{
|
1197 |
+
return;
|
1198 |
+
}
|
1199 |
+
|
1200 |
+
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))
|
1201 |
+
{
|
1202 |
+
$Element['attributes']['href'] = $matches[1];
|
1203 |
+
|
1204 |
+
if (isset($matches[2]))
|
1205 |
+
{
|
1206 |
+
$Element['attributes']['title'] = substr($matches[2], 1, - 1);
|
1207 |
+
}
|
1208 |
+
|
1209 |
+
$extent += strlen($matches[0]);
|
1210 |
+
}
|
1211 |
+
else
|
1212 |
+
{
|
1213 |
+
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
|
1214 |
+
{
|
1215 |
+
$definition = strlen($matches[1]) ? $matches[1] : $Element['text'];
|
1216 |
+
$definition = strtolower($definition);
|
1217 |
+
|
1218 |
+
$extent += strlen($matches[0]);
|
1219 |
+
}
|
1220 |
+
else
|
1221 |
+
{
|
1222 |
+
$definition = strtolower($Element['text']);
|
1223 |
+
}
|
1224 |
+
|
1225 |
+
if ( ! isset($this->DefinitionData['Reference'][$definition]))
|
1226 |
+
{
|
1227 |
+
return;
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
$Definition = $this->DefinitionData['Reference'][$definition];
|
1231 |
+
|
1232 |
+
$Element['attributes']['href'] = $Definition['url'];
|
1233 |
+
$Element['attributes']['title'] = $Definition['title'];
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
|
1237 |
+
|
1238 |
+
return array(
|
1239 |
+
'extent' => $extent,
|
1240 |
+
'element' => $Element,
|
1241 |
+
);
|
1242 |
+
}
|
1243 |
+
|
1244 |
+
protected function inlineMarkup($Excerpt)
|
1245 |
+
{
|
1246 |
+
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)
|
1247 |
+
{
|
1248 |
+
return;
|
1249 |
+
}
|
1250 |
+
|
1251 |
+
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches))
|
1252 |
+
{
|
1253 |
+
return array(
|
1254 |
+
'markup' => $matches[0],
|
1255 |
+
'extent' => strlen($matches[0]),
|
1256 |
+
);
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches))
|
1260 |
+
{
|
1261 |
+
return array(
|
1262 |
+
'markup' => $matches[0],
|
1263 |
+
'extent' => strlen($matches[0]),
|
1264 |
+
);
|
1265 |
+
}
|
1266 |
+
|
1267 |
+
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
|
1268 |
+
{
|
1269 |
+
return array(
|
1270 |
+
'markup' => $matches[0],
|
1271 |
+
'extent' => strlen($matches[0]),
|
1272 |
+
);
|
1273 |
+
}
|
1274 |
+
}
|
1275 |
+
|
1276 |
+
protected function inlineSpecialCharacter($Excerpt)
|
1277 |
+
{
|
1278 |
+
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text']))
|
1279 |
+
{
|
1280 |
+
return array(
|
1281 |
+
'markup' => '&',
|
1282 |
+
'extent' => 1,
|
1283 |
+
);
|
1284 |
+
}
|
1285 |
+
|
1286 |
+
$SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
|
1287 |
+
|
1288 |
+
if (isset($SpecialCharacter[$Excerpt['text'][0]]))
|
1289 |
+
{
|
1290 |
+
return array(
|
1291 |
+
'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';',
|
1292 |
+
'extent' => 1,
|
1293 |
+
);
|
1294 |
+
}
|
1295 |
+
}
|
1296 |
+
|
1297 |
+
protected function inlineStrikethrough($Excerpt)
|
1298 |
+
{
|
1299 |
+
if ( ! isset($Excerpt['text'][1]))
|
1300 |
+
{
|
1301 |
+
return;
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
|
1305 |
+
{
|
1306 |
+
return array(
|
1307 |
+
'extent' => strlen($matches[0]),
|
1308 |
+
'element' => array(
|
1309 |
+
'name' => 'del',
|
1310 |
+
'text' => $matches[1],
|
1311 |
+
'handler' => 'line',
|
1312 |
+
),
|
1313 |
+
);
|
1314 |
+
}
|
1315 |
+
}
|
1316 |
+
|
1317 |
+
protected function inlineUrl($Excerpt)
|
1318 |
+
{
|
1319 |
+
if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')
|
1320 |
+
{
|
1321 |
+
return;
|
1322 |
+
}
|
1323 |
+
|
1324 |
+
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
|
1325 |
+
{
|
1326 |
+
$Inline = array(
|
1327 |
+
'extent' => strlen($matches[0][0]),
|
1328 |
+
'position' => $matches[0][1],
|
1329 |
+
'element' => array(
|
1330 |
+
'name' => 'a',
|
1331 |
+
'text' => $matches[0][0],
|
1332 |
+
'attributes' => array(
|
1333 |
+
'href' => $matches[0][0],
|
1334 |
+
),
|
1335 |
+
),
|
1336 |
+
);
|
1337 |
+
|
1338 |
+
return $Inline;
|
1339 |
+
}
|
1340 |
+
}
|
1341 |
+
|
1342 |
+
protected function inlineUrlTag($Excerpt)
|
1343 |
+
{
|
1344 |
+
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))
|
1345 |
+
{
|
1346 |
+
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
1347 |
+
|
1348 |
+
return array(
|
1349 |
+
'extent' => strlen($matches[0]),
|
1350 |
+
'element' => array(
|
1351 |
+
'name' => 'a',
|
1352 |
+
'text' => $url,
|
1353 |
+
'attributes' => array(
|
1354 |
+
'href' => $url,
|
1355 |
+
),
|
1356 |
+
),
|
1357 |
+
);
|
1358 |
+
}
|
1359 |
+
}
|
1360 |
+
|
1361 |
+
# ~
|
1362 |
+
|
1363 |
+
protected function unmarkedText($text)
|
1364 |
+
{
|
1365 |
+
if ($this->breaksEnabled)
|
1366 |
+
{
|
1367 |
+
$text = preg_replace('/[ ]*\n/', "<br />\n", $text);
|
1368 |
+
}
|
1369 |
+
else
|
1370 |
+
{
|
1371 |
+
$text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "<br />\n", $text);
|
1372 |
+
$text = str_replace(" \n", "\n", $text);
|
1373 |
+
}
|
1374 |
+
|
1375 |
+
return $text;
|
1376 |
+
}
|
1377 |
+
|
1378 |
+
#
|
1379 |
+
# Handlers
|
1380 |
+
#
|
1381 |
+
|
1382 |
+
protected function element(array $Element)
|
1383 |
+
{
|
1384 |
+
$markup = '<'.$Element['name'];
|
1385 |
+
|
1386 |
+
if (isset($Element['attributes']))
|
1387 |
+
{
|
1388 |
+
foreach ($Element['attributes'] as $name => $value)
|
1389 |
+
{
|
1390 |
+
if ($value === null)
|
1391 |
+
{
|
1392 |
+
continue;
|
1393 |
+
}
|
1394 |
+
|
1395 |
+
$markup .= ' '.$name.'="'.$value.'"';
|
1396 |
+
}
|
1397 |
+
}
|
1398 |
+
|
1399 |
+
if (isset($Element['text']))
|
1400 |
+
{
|
1401 |
+
$markup .= '>';
|
1402 |
+
|
1403 |
+
if (isset($Element['handler']))
|
1404 |
+
{
|
1405 |
+
$markup .= $this->{$Element['handler']}($Element['text']);
|
1406 |
+
}
|
1407 |
+
else
|
1408 |
+
{
|
1409 |
+
$markup .= $Element['text'];
|
1410 |
+
}
|
1411 |
+
|
1412 |
+
$markup .= '</'.$Element['name'].'>';
|
1413 |
+
}
|
1414 |
+
else
|
1415 |
+
{
|
1416 |
+
$markup .= ' />';
|
1417 |
+
}
|
1418 |
+
|
1419 |
+
return $markup;
|
1420 |
+
}
|
1421 |
+
|
1422 |
+
protected function elements(array $Elements)
|
1423 |
+
{
|
1424 |
+
$markup = '';
|
1425 |
+
|
1426 |
+
foreach ($Elements as $Element)
|
1427 |
+
{
|
1428 |
+
$markup .= "\n" . $this->element($Element);
|
1429 |
+
}
|
1430 |
+
|
1431 |
+
$markup .= "\n";
|
1432 |
+
|
1433 |
+
return $markup;
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
# ~
|
1437 |
+
|
1438 |
+
protected function li($lines)
|
1439 |
+
{
|
1440 |
+
$markup = $this->lines($lines);
|
1441 |
+
|
1442 |
+
$trimmedMarkup = trim($markup);
|
1443 |
+
|
1444 |
+
if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>')
|
1445 |
+
{
|
1446 |
+
$markup = $trimmedMarkup;
|
1447 |
+
$markup = substr($markup, 3);
|
1448 |
+
|
1449 |
+
$position = strpos($markup, "</p>");
|
1450 |
+
|
1451 |
+
$markup = substr_replace($markup, '', $position, 4);
|
1452 |
+
}
|
1453 |
+
|
1454 |
+
return $markup;
|
1455 |
+
}
|
1456 |
+
|
1457 |
+
#
|
1458 |
+
# Deprecated Methods
|
1459 |
+
#
|
1460 |
+
|
1461 |
+
function parse($text)
|
1462 |
+
{
|
1463 |
+
$markup = $this->text($text);
|
1464 |
+
|
1465 |
+
return $markup;
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
#
|
1469 |
+
# Static Methods
|
1470 |
+
#
|
1471 |
+
|
1472 |
+
static function instance($name = 'default')
|
1473 |
+
{
|
1474 |
+
if (isset(self::$instances[$name]))
|
1475 |
+
{
|
1476 |
+
return self::$instances[$name];
|
1477 |
+
}
|
1478 |
+
|
1479 |
+
$instance = new self(); // static doesn't work in php 5.2
|
1480 |
+
|
1481 |
+
self::$instances[$name] = $instance;
|
1482 |
+
|
1483 |
+
return $instance;
|
1484 |
+
}
|
1485 |
+
|
1486 |
+
private static $instances = array();
|
1487 |
+
|
1488 |
+
#
|
1489 |
+
# Fields
|
1490 |
+
#
|
1491 |
+
|
1492 |
+
protected $DefinitionData;
|
1493 |
+
|
1494 |
+
#
|
1495 |
+
# Read-Only
|
1496 |
+
|
1497 |
+
protected $specialCharacters = array(
|
1498 |
+
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|',
|
1499 |
+
);
|
1500 |
+
|
1501 |
+
protected $StrongRegex = array(
|
1502 |
+
'*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
|
1503 |
+
'_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',
|
1504 |
+
);
|
1505 |
+
|
1506 |
+
protected $EmRegex = array(
|
1507 |
+
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
1508 |
+
'_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
|
1509 |
+
);
|
1510 |
+
|
1511 |
+
protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?';
|
1512 |
+
|
1513 |
+
protected $voidElements = array(
|
1514 |
+
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',
|
1515 |
+
);
|
1516 |
+
|
1517 |
+
protected $textLevelElements = array(
|
1518 |
+
'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',
|
1519 |
+
'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',
|
1520 |
+
'i', 'rp', 'del', 'code', 'strike', 'marquee',
|
1521 |
+
'q', 'rt', 'ins', 'font', 'strong',
|
1522 |
+
's', 'tt', 'sub', 'mark',
|
1523 |
+
'u', 'xm', 'sup', 'nobr',
|
1524 |
+
'var', 'ruby',
|
1525 |
+
'wbr', 'span',
|
1526 |
+
'time',
|
1527 |
+
);
|
1528 |
}
|
framework/core/components/extensions/manager/static/extension-page.css
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
#fw-extension-page .fw-extension-page-title {
|
2 |
-
padding-right: 0;
|
3 |
-
}
|
4 |
-
|
5 |
-
#fw-extension-page .fw-extension-page-title .button,
|
6 |
-
#fw-extension-page .fw-extension-page-title .button-primary,
|
7 |
-
#fw-extension-page .fw-extension-page-title .button-primary:active {
|
8 |
-
vertical-align: middle;
|
9 |
-
}
|
10 |
-
|
11 |
-
#fw-extension-page .fw-flash-message + br {
|
12 |
-
display: none;
|
13 |
-
}
|
14 |
-
|
15 |
-
|
16 |
-
#fw-extension-docs.fw-postbox > .insider {
|
17 |
-
margin-top: 0 !important;
|
18 |
-
}
|
19 |
-
|
20 |
-
#fw-extension-docs hr {
|
21 |
-
margin-left: -27px;
|
22 |
-
margin-right: -27px;
|
23 |
}
|
1 |
+
#fw-extension-page .fw-extension-page-title {
|
2 |
+
padding-right: 0;
|
3 |
+
}
|
4 |
+
|
5 |
+
#fw-extension-page .fw-extension-page-title .button,
|
6 |
+
#fw-extension-page .fw-extension-page-title .button-primary,
|
7 |
+
#fw-extension-page .fw-extension-page-title .button-primary:active {
|
8 |
+
vertical-align: middle;
|
9 |
+
}
|
10 |
+
|
11 |
+
#fw-extension-page .fw-flash-message + br {
|
12 |
+
display: none;
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
#fw-extension-docs.fw-postbox > .insider {
|
17 |
+
margin-top: 0 !important;
|
18 |
+
}
|
19 |
+
|
20 |
+
#fw-extension-docs hr {
|
21 |
+
margin-left: -27px;
|
22 |
+
margin-right: -27px;
|
23 |
}
|
framework/core/components/extensions/manager/static/extension-page.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
-
jQuery(function($){
|
2 |
-
$('#fw-extension-docs a:fw-external').attr('target', '_blank');
|
3 |
});
|
1 |
+
jQuery(function($){
|
2 |
+
$('#fw-extension-docs a:fw-external').attr('target', '_blank');
|
3 |
});
|
framework/core/components/extensions/manager/static/extensions-page.css
CHANGED
@@ -1,261 +1,261 @@
|
|
1 |
-
.fw-extensions-list a {
|
2 |
-
text-decoration: none;
|
3 |
-
}
|
4 |
-
|
5 |
-
.fw-extensions-no-active {
|
6 |
-
margin: 75px 0;
|
7 |
-
}
|
8 |
-
|
9 |
-
.fw-extensions-no-active .fw-text-muted {
|
10 |
-
color: #9d9d9d;
|
11 |
-
}
|
12 |
-
|
13 |
-
.fw-extensions-no-active .fw-extensions-title-icon .dashicons {
|
14 |
-
color: #d3d3d3;
|
15 |
-
font-size: 46px;
|
16 |
-
width: auto;
|
17 |
-
height: auto;
|
18 |
-
line-height: 35px;
|
19 |
-
}
|
20 |
-
|
21 |
-
.fw-extensions-list .fw-extensions-list-item {
|
22 |
-
padding: 0 15px 15px 0;
|
23 |
-
vertical-align: top;
|
24 |
-
display: inline-block;
|
25 |
-
float: none;
|
26 |
-
margin: 0 -1px;
|
27 |
-
}
|
28 |
-
|
29 |
-
.fw-extensions-list .fw-extensions-list-item > .inner {
|
30 |
-
padding: 20px;
|
31 |
-
background-color: #ffffff;
|
32 |
-
border: 1px solid #dedede;
|
33 |
-
position: relative;
|
34 |
-
}
|
35 |
-
|
36 |
-
.fw-extensions-list .fw-extensions-list-item > .inner > p:last-child {
|
37 |
-
margin-bottom: 0;
|
38 |
-
}
|
39 |
-
|
40 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper {
|
41 |
-
height: 128px;
|
42 |
-
width: 128px;
|
43 |
-
text-align: center;
|
44 |
-
background: url('img/thumbnail-bg.jpg');
|
45 |
-
background-size: 128px;
|
46 |
-
}
|
47 |
-
|
48 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper img.fw-extensions-list-item-thumbnail {
|
49 |
-
display: block;
|
50 |
-
height: 100%;
|
51 |
-
}
|
52 |
-
|
53 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper span.fw-extensions-list-item-thumbnail {
|
54 |
-
display: inline;
|
55 |
-
vertical-align: middle;
|
56 |
-
color: #fff;
|
57 |
-
line-height: 128px;
|
58 |
-
font-size: 42px;
|
59 |
-
}
|
60 |
-
|
61 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper span.fw-extensions-list-item-thumbnail.dashicons {
|
62 |
-
font-size: 48px;
|
63 |
-
}
|
64 |
-
|
65 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
66 |
-
margin-top: 0;
|
67 |
-
}
|
68 |
-
|
69 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title:last-child {
|
70 |
-
margin-bottom: 0;
|
71 |
-
}
|
72 |
-
|
73 |
-
|
74 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table {
|
75 |
-
display: table;
|
76 |
-
width: 100%;
|
77 |
-
}
|
78 |
-
|
79 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row {
|
80 |
-
display: table-row;
|
81 |
-
}
|
82 |
-
|
83 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell {
|
84 |
-
display: table-cell;
|
85 |
-
vertical-align: top;
|
86 |
-
}
|
87 |
-
|
88 |
-
/*.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-2,
|
89 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
90 |
-
vertical-align: middle;
|
91 |
-
}*/
|
92 |
-
|
93 |
-
@media (max-width: 782px) {
|
94 |
-
.fw-extensions-list .fw-extensions-list-item {
|
95 |
-
padding-right: 0;
|
96 |
-
}
|
97 |
-
|
98 |
-
.fw-extensions-list .fw-extensions-list-item .fw-text-center {
|
99 |
-
text-align: left;
|
100 |
-
}
|
101 |
-
|
102 |
-
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-text-center {
|
103 |
-
text-align: right;
|
104 |
-
}
|
105 |
-
|
106 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
107 |
-
margin-top: 20px;
|
108 |
-
}
|
109 |
-
|
110 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table,
|
111 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row,
|
112 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell {
|
113 |
-
display: block;
|
114 |
-
}
|
115 |
-
|
116 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form,
|
117 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form .button {
|
118 |
-
margin-bottom: 0;
|
119 |
-
}
|
120 |
-
}
|
121 |
-
|
122 |
-
@media (min-width: 783px) {
|
123 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
124 |
-
margin-top: 5px;
|
125 |
-
}
|
126 |
-
|
127 |
-
hr.fw-extensions-lists-separator {
|
128 |
-
margin: 22px 0 30px;
|
129 |
-
margin-right: 15px; /* same as .fw-extensions-list .fw-extensions-list-item padding-right */
|
130 |
-
}
|
131 |
-
|
132 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:first-child,
|
133 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:last-child {
|
134 |
-
width: 10px;
|
135 |
-
}
|
136 |
-
|
137 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:not(:first-child):not(:last-child) {
|
138 |
-
padding-left: 20px;
|
139 |
-
}
|
140 |
-
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:not(:first-child):not(:last-child) {
|
141 |
-
padding-left: 0;
|
142 |
-
padding-right: 20px;
|
143 |
-
}
|
144 |
-
|
145 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell > p:last-child {
|
146 |
-
margin-bottom: 0;
|
147 |
-
}
|
148 |
-
|
149 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
150 |
-
display: block;
|
151 |
-
position: absolute;
|
152 |
-
top: 20px;
|
153 |
-
right: 20px;
|
154 |
-
width: auto;
|
155 |
-
}
|
156 |
-
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
157 |
-
right: auto;
|
158 |
-
left: 20px;
|
159 |
-
}
|
160 |
-
|
161 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form {
|
162 |
-
display: inline-block;
|
163 |
-
}
|
164 |
-
|
165 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form {
|
166 |
-
padding: 0 0 4px 15px;
|
167 |
-
vertical-align: bottom;
|
168 |
-
}
|
169 |
-
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form {
|
170 |
-
padding: 0 13px 4px 0;
|
171 |
-
}
|
172 |
-
|
173 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form .btn-icon {
|
174 |
-
font-size: 16px;
|
175 |
-
}
|
176 |
-
}
|
177 |
-
|
178 |
-
|
179 |
-
/* disabled style */
|
180 |
-
|
181 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-disabled {
|
182 |
-
display: none;
|
183 |
-
background: rgba(255, 255, 255, 0.5) url("img/disabled-bg.png");
|
184 |
-
border: 1px solid #ffffff;
|
185 |
-
position: absolute;
|
186 |
-
top: 0;
|
187 |
-
left: 0;
|
188 |
-
width: 100%;
|
189 |
-
height: 100%;
|
190 |
-
}
|
191 |
-
|
192 |
-
.fw-extensions-list .fw-extensions-list-item.disabled .fw-extension-disabled {
|
193 |
-
display: block;
|
194 |
-
}
|
195 |
-
|
196 |
-
.fw-extensions-list .fw-extensions-list-item .fw-extension-disabled .fw-extension-disabled-panel {
|
197 |
-
position: absolute;
|
198 |
-
left: 0;
|
199 |
-
bottom: 0;
|
200 |
-
width: 100%;
|
201 |
-
background: #ffffff;
|
202 |
-
padding: 20px;
|
203 |
-
line-height: 28px;
|
204 |
-
}
|
205 |
-
|
206 |
-
@media (max-width: 782px) {
|
207 |
-
.fw-extensions-list .fw-extensions-list-item.disabled > .inner {
|
208 |
-
min-height: 320px;
|
209 |
-
}
|
210 |
-
}
|
211 |
-
|
212 |
-
/* end: disabled style */
|
213 |
-
|
214 |
-
|
215 |
-
/* tip content */
|
216 |
-
|
217 |
-
.fw-extension-tip-content {
|
218 |
-
padding: 15px;
|
219 |
-
max-width: 380px;
|
220 |
-
}
|
221 |
-
|
222 |
-
.fw-extension-tip-content ul.fw-extension-requirements {
|
223 |
-
margin: 0;
|
224 |
-
}
|
225 |
-
|
226 |
-
.fw-extension-tip-content ul.fw-extension-requirements li:last-child {
|
227 |
-
margin-bottom: 0;
|
228 |
-
}
|
229 |
-
|
230 |
-
/* end: tip content */
|
231 |
-
|
232 |
-
|
233 |
-
/* form ajax loading */
|
234 |
-
|
235 |
-
.fw-extensions-list .fw-extensions-list-item .ajax-form-loading {
|
236 |
-
display: inline-block;
|
237 |
-
margin: -2px 0;
|
238 |
-
padding-left: 7px;
|
239 |
-
}
|
240 |
-
|
241 |
-
.fw-extensions-list .fw-extensions-list-item .ajax-form-loading img {
|
242 |
-
vertical-align: middle;
|
243 |
-
display: inline-block;
|
244 |
-
margin-top: -2px;
|
245 |
-
}
|
246 |
-
|
247 |
-
/* end: form ajax loading */
|
248 |
-
|
249 |
-
|
250 |
-
/* anchor */
|
251 |
-
|
252 |
-
.fw-extensions-list .fw-extensions-list-item a.fw-ext-anchor {
|
253 |
-
position: absolute;
|
254 |
-
top: -15px;
|
255 |
-
}
|
256 |
-
|
257 |
-
body.admin-bar .fw-extensions-list .fw-extensions-list-item a.fw-ext-anchor {
|
258 |
-
top: -50px;
|
259 |
-
}
|
260 |
-
|
261 |
/* end: anchor */
|
1 |
+
.fw-extensions-list a {
|
2 |
+
text-decoration: none;
|
3 |
+
}
|
4 |
+
|
5 |
+
.fw-extensions-no-active {
|
6 |
+
margin: 75px 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.fw-extensions-no-active .fw-text-muted {
|
10 |
+
color: #9d9d9d;
|
11 |
+
}
|
12 |
+
|
13 |
+
.fw-extensions-no-active .fw-extensions-title-icon .dashicons {
|
14 |
+
color: #d3d3d3;
|
15 |
+
font-size: 46px;
|
16 |
+
width: auto;
|
17 |
+
height: auto;
|
18 |
+
line-height: 35px;
|
19 |
+
}
|
20 |
+
|
21 |
+
.fw-extensions-list .fw-extensions-list-item {
|
22 |
+
padding: 0 15px 15px 0;
|
23 |
+
vertical-align: top;
|
24 |
+
display: inline-block;
|
25 |
+
float: none;
|
26 |
+
margin: 0 -1px;
|
27 |
+
}
|
28 |
+
|
29 |
+
.fw-extensions-list .fw-extensions-list-item > .inner {
|
30 |
+
padding: 20px;
|
31 |
+
background-color: #ffffff;
|
32 |
+
border: 1px solid #dedede;
|
33 |
+
position: relative;
|
34 |
+
}
|
35 |
+
|
36 |
+
.fw-extensions-list .fw-extensions-list-item > .inner > p:last-child {
|
37 |
+
margin-bottom: 0;
|
38 |
+
}
|
39 |
+
|
40 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper {
|
41 |
+
height: 128px;
|
42 |
+
width: 128px;
|
43 |
+
text-align: center;
|
44 |
+
background: url('img/thumbnail-bg.jpg');
|
45 |
+
background-size: 128px;
|
46 |
+
}
|
47 |
+
|
48 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper img.fw-extensions-list-item-thumbnail {
|
49 |
+
display: block;
|
50 |
+
height: 100%;
|
51 |
+
}
|
52 |
+
|
53 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper span.fw-extensions-list-item-thumbnail {
|
54 |
+
display: inline;
|
55 |
+
vertical-align: middle;
|
56 |
+
color: #fff;
|
57 |
+
line-height: 128px;
|
58 |
+
font-size: 42px;
|
59 |
+
}
|
60 |
+
|
61 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-thumbnail-wrapper span.fw-extensions-list-item-thumbnail.dashicons {
|
62 |
+
font-size: 48px;
|
63 |
+
}
|
64 |
+
|
65 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
66 |
+
margin-top: 0;
|
67 |
+
}
|
68 |
+
|
69 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title:last-child {
|
70 |
+
margin-bottom: 0;
|
71 |
+
}
|
72 |
+
|
73 |
+
|
74 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table {
|
75 |
+
display: table;
|
76 |
+
width: 100%;
|
77 |
+
}
|
78 |
+
|
79 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row {
|
80 |
+
display: table-row;
|
81 |
+
}
|
82 |
+
|
83 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell {
|
84 |
+
display: table-cell;
|
85 |
+
vertical-align: top;
|
86 |
+
}
|
87 |
+
|
88 |
+
/*.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-2,
|
89 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
90 |
+
vertical-align: middle;
|
91 |
+
}*/
|
92 |
+
|
93 |
+
@media (max-width: 782px) {
|
94 |
+
.fw-extensions-list .fw-extensions-list-item {
|
95 |
+
padding-right: 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
.fw-extensions-list .fw-extensions-list-item .fw-text-center {
|
99 |
+
text-align: left;
|
100 |
+
}
|
101 |
+
|
102 |
+
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-text-center {
|
103 |
+
text-align: right;
|
104 |
+
}
|
105 |
+
|
106 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
107 |
+
margin-top: 20px;
|
108 |
+
}
|
109 |
+
|
110 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table,
|
111 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row,
|
112 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell {
|
113 |
+
display: block;
|
114 |
+
}
|
115 |
+
|
116 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form,
|
117 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form .button {
|
118 |
+
margin-bottom: 0;
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
@media (min-width: 783px) {
|
123 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extensions-list-item-title {
|
124 |
+
margin-top: 5px;
|
125 |
+
}
|
126 |
+
|
127 |
+
hr.fw-extensions-lists-separator {
|
128 |
+
margin: 22px 0 30px;
|
129 |
+
margin-right: 15px; /* same as .fw-extensions-list .fw-extensions-list-item padding-right */
|
130 |
+
}
|
131 |
+
|
132 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:first-child,
|
133 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:last-child {
|
134 |
+
width: 10px;
|
135 |
+
}
|
136 |
+
|
137 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:not(:first-child):not(:last-child) {
|
138 |
+
padding-left: 20px;
|
139 |
+
}
|
140 |
+
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell:not(:first-child):not(:last-child) {
|
141 |
+
padding-left: 0;
|
142 |
+
padding-right: 20px;
|
143 |
+
}
|
144 |
+
|
145 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell > p:last-child {
|
146 |
+
margin-bottom: 0;
|
147 |
+
}
|
148 |
+
|
149 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
150 |
+
display: block;
|
151 |
+
position: absolute;
|
152 |
+
top: 20px;
|
153 |
+
right: 20px;
|
154 |
+
width: auto;
|
155 |
+
}
|
156 |
+
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 {
|
157 |
+
right: auto;
|
158 |
+
left: 20px;
|
159 |
+
}
|
160 |
+
|
161 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form {
|
162 |
+
display: inline-block;
|
163 |
+
}
|
164 |
+
|
165 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form {
|
166 |
+
padding: 0 0 4px 15px;
|
167 |
+
vertical-align: bottom;
|
168 |
+
}
|
169 |
+
body.rtl .fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form {
|
170 |
+
padding: 0 13px 4px 0;
|
171 |
+
}
|
172 |
+
|
173 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-list-item-table > .fw-extension-list-item-table-row > .fw-extension-list-item-table-cell.cell-3 form.extension-delete-form .btn-icon {
|
174 |
+
font-size: 16px;
|
175 |
+
}
|
176 |
+
}
|
177 |
+
|
178 |
+
|
179 |
+
/* disabled style */
|
180 |
+
|
181 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-disabled {
|
182 |
+
display: none;
|
183 |
+
background: rgba(255, 255, 255, 0.5) url("img/disabled-bg.png");
|
184 |
+
border: 1px solid #ffffff;
|
185 |
+
position: absolute;
|
186 |
+
top: 0;
|
187 |
+
left: 0;
|
188 |
+
width: 100%;
|
189 |
+
height: 100%;
|
190 |
+
}
|
191 |
+
|
192 |
+
.fw-extensions-list .fw-extensions-list-item.disabled .fw-extension-disabled {
|
193 |
+
display: block;
|
194 |
+
}
|
195 |
+
|
196 |
+
.fw-extensions-list .fw-extensions-list-item .fw-extension-disabled .fw-extension-disabled-panel {
|
197 |
+
position: absolute;
|
198 |
+
left: 0;
|
199 |
+
bottom: 0;
|
200 |
+
width: 100%;
|
201 |
+
background: #ffffff;
|
202 |
+
padding: 20px;
|
203 |
+
line-height: 28px;
|
204 |
+
}
|
205 |
+
|
206 |
+
@media (max-width: 782px) {
|
207 |
+
.fw-extensions-list .fw-extensions-list-item.disabled > .inner {
|
208 |
+
min-height: 320px;
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
/* end: disabled style */
|
213 |
+
|
214 |
+
|
215 |
+
/* tip content */
|
216 |
+
|
217 |
+
.fw-extension-tip-content {
|
218 |
+
padding: 15px;
|
219 |
+
max-width: 380px;
|
220 |
+
}
|
221 |
+
|
222 |
+
.fw-extension-tip-content ul.fw-extension-requirements {
|
223 |
+
margin: 0;
|
224 |
+
}
|
225 |
+
|
226 |
+
.fw-extension-tip-content ul.fw-extension-requirements li:last-child {
|
227 |
+
margin-bottom: 0;
|
228 |
+
}
|
229 |
+
|
230 |
+
/* end: tip content */
|
231 |
+
|
232 |
+
|
233 |
+
/* form ajax loading */
|
234 |
+
|
235 |
+
.fw-extensions-list .fw-extensions-list-item .ajax-form-loading {
|
236 |
+
display: inline-block;
|
237 |
+
margin: -2px 0;
|
238 |
+
padding-left: 7px;
|
239 |
+
}
|
240 |
+
|
241 |
+
.fw-extensions-list .fw-extensions-list-item .ajax-form-loading img {
|
242 |
+
vertical-align: middle;
|
243 |
+
display: inline-block;
|
244 |
+
margin-top: -2px;
|
245 |
+
}
|
246 |
+
|
247 |
+
/* end: form ajax loading */
|
248 |
+
|
249 |
+
|
250 |
+
/* anchor */
|
251 |
+
|
252 |
+
.fw-extensions-list .fw-extensions-list-item a.fw-ext-anchor {
|
253 |
+
position: absolute;
|
254 |
+
top: -15px;
|
255 |
+
}
|
256 |
+
|
257 |
+
body.admin-bar .fw-extensions-list .fw-extensions-list-item a.fw-ext-anchor {
|
258 |
+
top: -50px;
|
259 |
+
}
|
260 |
+
|
261 |
/* end: anchor */
|
framework/core/components/extensions/manager/static/extensions-page.js
CHANGED
@@ -1,108 +1,108 @@
|
|
1 |
-
jQuery(function ($) {
|
2 |
-
fw.qtip( $('.fw-extensions-list .fw-extensions-list-item .fw-extension-tip') );
|
3 |
-
});
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Install/Remove/... via popup if has direct filesystem access (no ftp credentials required)
|
7 |
-
*/
|
8 |
-
jQuery(function($){
|
9 |
-
var inst = {
|
10 |
-
isBusy: false,
|
11 |
-
eventNamespace: '.fw-extension',
|
12 |
-
$wrapper: $('.wrap'),
|
13 |
-
listenSubmit: function() {
|
14 |
-
this.$wrapper.on('submit'+ this.eventNamespace, 'form.fw-extension-ajax-form', this.onSubmit);
|
15 |
-
},
|
16 |
-
stopListeningSubmit: function() {
|
17 |
-
this.$wrapper.off('submit'+ this.eventNamespace, 'form.fw-extension-ajax-form');
|
18 |
-
},
|
19 |
-
onSubmit: function(e) {
|
20 |
-
e.preventDefault();
|
21 |
-
|
22 |
-
if (inst.isBusy) {
|
23 |
-
alert('Working... Please try again later');
|
24 |
-
return;
|
25 |
-
}
|
26 |
-
|
27 |
-
var $form = $(this);
|
28 |
-
|
29 |
-
var confirmMessage = $form.attr('data-confirm-message');
|
30 |
-
|
31 |
-
inst.isBusy = true;
|
32 |
-
inst.loading($form, true);
|
33 |
-
|
34 |
-
$.ajax({
|
35 |
-
url: ajaxurl,
|
36 |
-
type: 'POST',
|
37 |
-
data: {
|
38 |
-
action: 'fw_extensions_check_direct_fs_access'
|
39 |
-
},
|
40 |
-
dataType: 'json'
|
41 |
-
}).done(function(data){
|
42 |
-
if (data.success) {
|
43 |
-
if (confirmMessage) {
|
44 |
-
if (!confirm(confirmMessage)) {
|
45 |
-
inst.isBusy = false;
|
46 |
-
inst.loading($form, false);
|
47 |
-
}
|
48 |
-
}
|
49 |
-
|
50 |
-
$.ajax({
|
51 |
-
url: ajaxurl,
|
52 |
-
type: 'POST',
|
53 |
-
data: {
|
54 |
-
action: 'fw_extensions_'+ $form.attr('data-extension-action'),
|
55 |
-
extension: $form.attr('data-extension-name')
|
56 |
-
},
|
57 |
-
dataType: 'json'
|
58 |
-
}).done(function(r) {
|
59 |
-
if (r.success) {
|
60 |
-
window.location.reload();
|
61 |
-
} else {
|
62 |
-
var error = r.data ? r.data.pop().message : 'Error';
|
63 |
-
|
64 |
-
fw.soleModal.show(
|
65 |
-
'fw-extension-install-error',
|
66 |
-
'<p class="fw-text-danger">'+ error +'</p>'
|
67 |
-
);
|
68 |
-
}
|
69 |
-
}).fail(function(jqXHR, textStatus, errorThrown){
|
70 |
-
fw.soleModal.show(
|
71 |
-
'fw-extension-install-error',
|
72 |
-
'<p class="fw-text-danger">'+ String(errorThrown) +'</p>'
|
73 |
-
);
|
74 |
-
inst.isBusy = false;
|
75 |
-
inst.loading($form, false);
|
76 |
-
});
|
77 |
-
} else {
|
78 |
-
inst.stopListeningSubmit();
|
79 |
-
$form.submit();
|
80 |
-
}
|
81 |
-
}).fail(function(jqXHR, textStatus, errorThrown){
|
82 |
-
inst.stopListeningSubmit();
|
83 |
-
$form.submit();
|
84 |
-
});
|
85 |
-
},
|
86 |
-
loading: function($form, show) {
|
87 |
-
var $loadingContainer = $form.closest('.fw-extensions-list-item').find('.fw-extensions-list-item-title').first();
|
88 |
-
var $loading = $loadingContainer.find('.ajax-form-loading');
|
89 |
-
|
90 |
-
if (!$loading.length) {
|
91 |
-
$loadingContainer.append(
|
92 |
-
'<span class="ajax-form-loading fw-text-center fw-hidden">'+
|
93 |
-
'<img src="'+ fw.img.loadingSpinner +'" />'+
|
94 |
-
'</span>'
|
95 |
-
);
|
96 |
-
$loading = $loadingContainer.find('.ajax-form-loading');
|
97 |
-
}
|
98 |
-
|
99 |
-
if (show) {
|
100 |
-
$loading.removeClass('fw-hidden');
|
101 |
-
} else {
|
102 |
-
$loading.addClass('fw-hidden');
|
103 |
-
}
|
104 |
-
}
|
105 |
-
};
|
106 |
-
|
107 |
-
inst.listenSubmit();
|
108 |
});
|
1 |
+
jQuery(function ($) {
|
2 |
+
fw.qtip( $('.fw-extensions-list .fw-extensions-list-item .fw-extension-tip') );
|
3 |
+
});
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Install/Remove/... via popup if has direct filesystem access (no ftp credentials required)
|
7 |
+
*/
|
8 |
+
jQuery(function($){
|
9 |
+
var inst = {
|
10 |
+
isBusy: false,
|
11 |
+
eventNamespace: '.fw-extension',
|
12 |
+
$wrapper: $('.wrap'),
|
13 |
+
listenSubmit: function() {
|
14 |
+
this.$wrapper.on('submit'+ this.eventNamespace, 'form.fw-extension-ajax-form', this.onSubmit);
|
15 |
+
},
|
16 |
+
stopListeningSubmit: function() {
|
17 |
+
this.$wrapper.off('submit'+ this.eventNamespace, 'form.fw-extension-ajax-form');
|
18 |
+
},
|
19 |
+
onSubmit: function(e) {
|
20 |
+
e.preventDefault();
|
21 |
+
|
22 |
+
if (inst.isBusy) {
|
23 |
+
alert('Working... Please try again later');
|
24 |
+
return;
|
25 |
+
}
|
26 |
+
|
27 |
+
var $form = $(this);
|
28 |
+
|
29 |
+
var confirmMessage = $form.attr('data-confirm-message');
|
30 |
+
|
31 |
+
inst.isBusy = true;
|
32 |
+
inst.loading($form, true);
|
33 |
+
|
34 |
+
$.ajax({
|
35 |
+
url: ajaxurl,
|
36 |
+
type: 'POST',
|
37 |
+
data: {
|
38 |
+
action: 'fw_extensions_check_direct_fs_access'
|
39 |
+
},
|
40 |
+
dataType: 'json'
|
41 |
+
}).done(function(data){
|
42 |
+
if (data.success) {
|
43 |
+
if (confirmMessage) {
|
44 |
+
if (!confirm(confirmMessage)) {
|
45 |
+
inst.isBusy = false;
|
46 |
+
inst.loading($form, false);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
$.ajax({
|
51 |
+
url: ajaxurl,
|
52 |
+
type: 'POST',
|
53 |
+
data: {
|
54 |
+
action: 'fw_extensions_'+ $form.attr('data-extension-action'),
|
55 |
+
extension: $form.attr('data-extension-name')
|
56 |
+
},
|
57 |
+
dataType: 'json'
|
58 |
+
}).done(function(r) {
|
59 |
+
if (r.success) {
|
60 |
+
window.location.reload();
|
61 |
+
} else {
|
62 |
+
var error = r.data ? r.data.pop().message : 'Error';
|
63 |
+
|
64 |
+
fw.soleModal.show(
|
65 |
+
'fw-extension-install-error',
|
66 |
+
'<p class="fw-text-danger">'+ error +'</p>'
|
67 |
+
);
|
68 |
+
}
|
69 |
+
}).fail(function(jqXHR, textStatus, errorThrown){
|
70 |
+
fw.soleModal.show(
|
71 |
+
'fw-extension-install-error',
|
72 |
+
'<p class="fw-text-danger">'+ String(errorThrown) +'</p>'
|
73 |
+
);
|
74 |
+
inst.isBusy = false;
|
75 |
+
inst.loading($form, false);
|
76 |
+
});
|
77 |
+
} else {
|
78 |
+
inst.stopListeningSubmit();
|
79 |
+
$form.submit();
|
80 |
+
}
|
81 |
+
}).fail(function(jqXHR, textStatus, errorThrown){
|
82 |
+
inst.stopListeningSubmit();
|
83 |
+
$form.submit();
|
84 |
+
});
|
85 |
+
},
|
86 |
+
loading: function($form, show) {
|
87 |
+
var $loadingContainer = $form.closest('.fw-extensions-list-item').find('.fw-extensions-list-item-title').first();
|
88 |
+
var $loading = $loadingContainer.find('.ajax-form-loading');
|
89 |
+
|
90 |
+
if (!$loading.length) {
|
91 |
+
$loadingContainer.append(
|
92 |
+
'<span class="ajax-form-loading fw-text-center fw-hidden">'+
|
93 |
+
'<img src="'+ fw.img.loadingSpinner +'" />'+
|
94 |
+
'</span>'
|
95 |
+
);
|
96 |
+
$loading = $loadingContainer.find('.ajax-form-loading');
|
97 |
+
}
|
98 |
+
|
99 |
+
if (show) {
|
100 |
+
$loading.removeClass('fw-hidden');
|
101 |
+
} else {
|
102 |
+
$loading.addClass('fw-hidden');
|
103 |
+
}
|
104 |
+
}
|
105 |
+
};
|
106 |
+
|
107 |
+
inst.listenSubmit();
|
108 |
});
|
framework/core/components/extensions/manager/static/unyson-font-icon/fonts/icomoon.svg
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
-
<?xml version="1.0" standalone="no"?>
|
2 |
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
3 |
-
<svg xmlns="http://www.w3.org/2000/svg">
|
4 |
-
<metadata>Generated by IcoMoon</metadata>
|
5 |
-
<defs>
|
6 |
-
<font id="icomoon" horiz-adv-x="1024">
|
7 |
-
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
8 |
-
<missing-glyph horiz-adv-x="1024" />
|
9 |
-
<glyph unicode=" " d="" horiz-adv-x="512" />
|
10 |
-
<glyph unicode="" d="M402.322 641.307c8.195 177.384 154.668 318.693 334.198 318.693 184.794 0 334.597-149.702 334.597-334.367 0-5.258-0.166-10.476-0.408-15.674 0 0 0.408 0 0.408 0s0-611.265 0-611.265c0 0-156.842-62.693-156.842-62.693s-146.385 62.693-146.385 62.693c0 0 0 568.788 0 568.788s0 115.621 0 115.621c0 0-0.132 0-0.132 0-0.87 37.687-20.304 70.747-49.501 90.476-27.849-18.815-46.846-49.73-49.306-85.253 0 0-0.396 0-0.396 0s0-433.633 0-433.633zM668.399 254.693c-8.192-177.384-154.577-318.693-334-318.693-184.684 0-334.399 149.702-334.399 334.367 0 5.268 0.295 10.463 0.537 15.674 0 0-0.537 0-0.537 0s0 611.265 0 611.265c0 0 156.747 62.693 156.747 62.693s146.3-62.693 146.3-62.693c0 0 0-568.788 0-568.788s0-115.621 0-115.621c0 0 0.132 0 0.132 0 0.87-37.687 20.292-70.747 49.472-90.476 27.83 18.815 47.867 50.192 50.327 85.714 0 0-0.656-0.462-0.656-0.462s0 433.633 0 433.633z" horiz-adv-x="1071" />
|
11 |
</font></defs></svg>
|
1 |
+
<?xml version="1.0" standalone="no"?>
|
2 |
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
3 |
+
<svg xmlns="http://www.w3.org/2000/svg">
|
4 |
+
<metadata>Generated by IcoMoon</metadata>
|
5 |
+
<defs>
|
6 |
+
<font id="icomoon" horiz-adv-x="1024">
|
7 |
+
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
8 |
+
<missing-glyph horiz-adv-x="1024" />
|
9 |
+
<glyph unicode=" " d="" horiz-adv-x="512" />
|
10 |
+
<glyph unicode="" d="M402.322 641.307c8.195 177.384 154.668 318.693 334.198 318.693 184.794 0 334.597-149.702 334.597-334.367 0-5.258-0.166-10.476-0.408-15.674 0 0 0.408 0 0.408 0s0-611.265 0-611.265c0 0-156.842-62.693-156.842-62.693s-146.385 62.693-146.385 62.693c0 0 0 568.788 0 568.788s0 115.621 0 115.621c0 0-0.132 0-0.132 0-0.87 37.687-20.304 70.747-49.501 90.476-27.849-18.815-46.846-49.73-49.306-85.253 0 0-0.396 0-0.396 0s0-433.633 0-433.633zM668.399 254.693c-8.192-177.384-154.577-318.693-334-318.693-184.684 0-334.399 149.702-334.399 334.367 0 5.268 0.295 10.463 0.537 15.674 0 0-0.537 0-0.537 0s0 611.265 0 611.265c0 0 156.747 62.693 156.747 62.693s146.3-62.693 146.3-62.693c0 0 0-568.788 0-568.788s0-115.621 0-115.621c0 0 0.132 0 0.132 0 0.87-37.687 20.292-70.747 49.472-90.476 27.83 18.815 47.867 50.192 50.327 85.714 0 0-0.656-0.462-0.656-0.462s0 433.633 0 433.633z" horiz-adv-x="1071" />
|
11 |
</font></defs></svg>
|
framework/core/components/extensions/manager/static/unyson-font-icon/style.css
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
@font-face {
|
2 |
-
font-family: 'unyson-font-icon';
|
3 |
-
src:url('fonts/icomoon.eot?iganyx');
|
4 |
-
src:url('fonts/icomoon.eot?#iefixiganyx') format('embedded-opentype'),
|
5 |
-
url('fonts/icomoon.woff?iganyx') format('woff'),
|
6 |
-
url('fonts/icomoon.ttf?iganyx') format('truetype'),
|
7 |
-
url('fonts/icomoon.svg?iganyx#icomoon') format('svg');
|
8 |
-
font-weight: normal;
|
9 |
-
font-style: normal;
|
10 |
-
}
|
11 |
-
|
12 |
-
.toplevel_page_fw-extensions > .wp-menu-image:before {
|
13 |
-
font-family: 'unyson-font-icon';
|
14 |
-
speak: none;
|
15 |
-
font-style: normal;
|
16 |
-
font-weight: normal;
|
17 |
-
font-variant: normal;
|
18 |
-
text-transform: none;
|
19 |
-
line-height: 1;
|
20 |
-
|
21 |
-
/* Better Font Rendering =========== */
|
22 |
-
-webkit-font-smoothing: antialiased;
|
23 |
-
-moz-osx-font-smoothing: grayscale;
|
24 |
-
|
25 |
-
content: "\e600";
|
26 |
-
font-size: 14px;
|
27 |
-
line-height: 20px;
|
28 |
-
}
|
1 |
+
@font-face {
|
2 |
+
font-family: 'unyson-font-icon';
|
3 |
+
src:url('fonts/icomoon.eot?iganyx');
|
4 |
+
src:url('fonts/icomoon.eot?#iefixiganyx') format('embedded-opentype'),
|
5 |
+
url('fonts/icomoon.woff?iganyx') format('woff'),
|
6 |
+
url('fonts/icomoon.ttf?iganyx') format('truetype'),
|
7 |
+
url('fonts/icomoon.svg?iganyx#icomoon') format('svg');
|
8 |
+
font-weight: normal;
|
9 |
+
font-style: normal;
|
10 |
+
}
|
11 |
+
|
12 |
+
.toplevel_page_fw-extensions > .wp-menu-image:before {
|
13 |
+
font-family: 'unyson-font-icon';
|
14 |
+
speak: none;
|
15 |
+
font-style: normal;
|
16 |
+
font-weight: normal;
|
17 |
+
font-variant: normal;
|
18 |
+
text-transform: none;
|
19 |
+
line-height: 1;
|
20 |
+
|
21 |
+
/* Better Font Rendering =========== */
|
22 |
+
-webkit-font-smoothing: antialiased;
|
23 |
+
-moz-osx-font-smoothing: grayscale;
|
24 |
+
|
25 |
+
content: "\e600";
|
26 |
+
font-size: 14px;
|
27 |
+
line-height: 20px;
|
28 |
+
}
|
framework/core/components/extensions/manager/views/delete-form.php
CHANGED
@@ -1,55 +1,55 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
/**
|
3 |
-
* @var array $extension_names
|
4 |
-
* @var array $installed_extensions
|
5 |
-
* @var array $list_page_link
|
6 |
-
*/
|
7 |
-
|
8 |
-
$count = count($extension_names);
|
9 |
-
?>
|
10 |
-
|
11 |
-
<p><?php echo _n(
|
12 |
-
'You are about to remove the following extension:',
|
13 |
-
'You are about to remove the following extensions:',
|
14 |
-
$count,
|
15 |
-
'fw'
|
16 |
-
) ?></p>
|
17 |
-
|
18 |
-
<ul class="ul-disc">
|
19 |
-
<?php foreach ($extension_names as $extension_name): ?>
|
20 |
-
<li><strong><?php echo fw()->extensions->manager->get_extension_title($extension_name); ?></strong></li>
|
21 |
-
<?php endforeach; ?>
|
22 |
-
</ul>
|
23 |
-
|
24 |
-
<p><?php
|
25 |
-
echo _n(
|
26 |
-
'Are you sure you wish to delete this extension?',
|
27 |
-
'Are you sure you wish to delete these extensions?',
|
28 |
-
$count,
|
29 |
-
'fw'
|
30 |
-
)
|
31 |
-
?></p>
|
32 |
-
|
33 |
-
<input type="submit" name="submit" id="submit" class="button" value="<?php
|
34 |
-
echo esc_attr( _n(
|
35 |
-
'Yes, Delete this extension',
|
36 |
-
'Yes, Delete these extensions',
|
37 |
-
$count,
|
38 |
-
'fw'
|
39 |
-
) )
|
40 |
-
?>">
|
41 |
-
|
42 |
-
<a class="button" href="<?php echo esc_attr($list_page_link) ?>" ><?php _e('No, Return me to the extension list', 'fw') ?></a>
|
43 |
-
|
44 |
-
<p>
|
45 |
-
<a href="#" onclick="jQuery('#files-list').toggle(); return false;"><?php _e('Click to view entire list of directories which will be deleted', 'fw') ?></a>
|
46 |
-
</p>
|
47 |
-
<div id="files-list" style="display: none;">
|
48 |
-
<ul class="code">
|
49 |
-
<?php $replace_regex = '/^'. preg_quote(fw_get_framework_directory('/extensions'), '/') .'/'; ?>
|
50 |
-
<?php foreach ($extension_names as $extension_name): ?>
|
51 |
-
<?php if (!isset($installed_extensions[$extension_name])) continue; ?>
|
52 |
-
<li><?php echo preg_replace($replace_regex, '', $installed_extensions[$extension_name]['path']) ?>/</li>
|
53 |
-
<?php endforeach; ?>
|
54 |
-
</ul>
|
55 |
</div>
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
/**
|
3 |
+
* @var array $extension_names
|
4 |
+
* @var array $installed_extensions
|
5 |
+
* @var array $list_page_link
|
6 |
+
*/
|
7 |
+
|
8 |
+
$count = count($extension_names);
|
9 |
+
?>
|
10 |
+
|
11 |
+
<p><?php echo _n(
|
12 |
+
'You are about to remove the following extension:',
|
13 |
+
'You are about to remove the following extensions:',
|
14 |
+
$count,
|
15 |
+
'fw'
|
16 |
+
) ?></p>
|
17 |
+
|
18 |
+
<ul class="ul-disc">
|
19 |
+
<?php foreach ($extension_names as $extension_name): ?>
|
20 |
+
<li><strong><?php echo fw()->extensions->manager->get_extension_title($extension_name); ?></strong></li>
|
21 |
+
<?php endforeach; ?>
|
22 |
+
</ul>
|
23 |
+
|
24 |
+
<p><?php
|
25 |
+
echo _n(
|
26 |
+
'Are you sure you wish to delete this extension?',
|
27 |
+
'Are you sure you wish to delete these extensions?',
|
28 |
+
$count,
|
29 |
+
'fw'
|
30 |
+
)
|
31 |
+
?></p>
|
32 |
+
|
33 |
+
<input type="submit" name="submit" id="submit" class="button" value="<?php
|
34 |
+
echo esc_attr( _n(
|
35 |
+
'Yes, Delete this extension',
|
36 |
+
'Yes, Delete these extensions',
|
37 |
+
$count,
|
38 |
+
'fw'
|
39 |
+
) )
|
40 |
+
?>">
|
41 |
+
|
42 |
+
<a class="button" href="<?php echo esc_attr($list_page_link) ?>" ><?php _e('No, Return me to the extension list', 'fw') ?></a>
|
43 |
+
|
44 |
+
<p>
|
45 |
+
<a href="#" onclick="jQuery('#files-list').toggle(); return false;"><?php _e('Click to view entire list of directories which will be deleted', 'fw') ?></a>
|
46 |
+
</p>
|
47 |
+
<div id="files-list" style="display: none;">
|
48 |
+
<ul class="code">
|
49 |
+
<?php $replace_regex = '/^'. preg_quote(fw_get_framework_directory('/extensions'), '/') .'/'; ?>
|
50 |
+
<?php foreach ($extension_names as $extension_name): ?>
|
51 |
+
<?php if (!isset($installed_extensions[$extension_name])) continue; ?>
|
52 |
+
<li><?php echo preg_replace($replace_regex, '', $installed_extensions[$extension_name]['path']) ?>/</li>
|
53 |
+
<?php endforeach; ?>
|
54 |
+
</ul>
|
55 |
</div>
|
framework/core/components/extensions/manager/views/extension-page-header.php
CHANGED
@@ -1,50 +1,50 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
/**
|
3 |
-
* @var string $extension_name
|
4 |
-
* @var array $extension_data
|
5 |
-
* @var string $extension_title
|
6 |
-
* @var string $link_delete
|
7 |
-
* @var string $link_extension
|
8 |
-
* @var string $tab
|
9 |
-
* @var bool $is_supported
|
10 |
-
*/
|
11 |
-
|
12 |
-
?>
|
13 |
-
<h2 class="fw-extension-page-title">
|
14 |
-
<span class="fw-pull-right">
|
15 |
-
<?php
|
16 |
-
switch ($tab) {
|
17 |
-
case 'settings':
|
18 |
-
if (!file_exists($extension_data['path'] .'/readme.md.php')) {
|
19 |
-
break;
|
20 |
-
}
|
21 |
-
if ($is_supported) {
|
22 |
-
// do not show install instructions for supported extensions
|
23 |
-
break;
|
24 |
-
}
|
25 |
-
?><a href="<?php echo esc_attr($link_extension) ?>&extension=<?php echo esc_attr($extension_name) ?>&tab=docs" class="button-primary"><?php _e('Install Instructions', 'fw') ?></a><?php
|
26 |
-
break;
|
27 |
-
case 'docs':
|
28 |
-
if (!fw()->extensions->get($extension_name) || !fw()->extensions->get($extension_name)->get_settings_options()) {
|
29 |
-
break;
|
30 |
-
}
|
31 |
-
?><a href="<?php echo esc_attr($link_extension) ?>&extension=<?php echo esc_attr($extension_name) ?>" class="button-primary"><?php _e('Settings', 'fw') ?></a><?php
|
32 |
-
break;
|
33 |
-
}
|
34 |
-
?>
|
35 |
-
</span>
|
36 |
-
|
37 |
-
<?php
|
38 |
-
switch ($tab) {
|
39 |
-
case 'settings':
|
40 |
-
echo sprintf(__('%s Settings', 'fw'), $extension_title);
|
41 |
-
break;
|
42 |
-
case 'docs':
|
43 |
-
echo sprintf(__('%s Install Instructions', 'fw'), $extension_title);
|
44 |
-
break;
|
45 |
-
default:
|
46 |
-
echo __('Unknown tab:', 'fw') . ' ' . fw_htmlspecialchars($tab);
|
47 |
-
}
|
48 |
-
?>
|
49 |
-
</h2>
|
50 |
-
<br/>
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
/**
|
3 |
+
* @var string $extension_name
|
4 |
+
* @var array $extension_data
|
5 |
+
* @var string $extension_title
|
6 |
+
* @var string $link_delete
|
7 |
+
* @var string $link_extension
|
8 |
+
* @var string $tab
|
9 |
+
* @var bool $is_supported
|
10 |
+
*/
|
11 |
+
|
12 |
+
?>
|
13 |
+
<h2 class="fw-extension-page-title">
|
14 |
+
<span class="fw-pull-right">
|
15 |
+
<?php
|
16 |
+
switch ($tab) {
|
17 |
+
case 'settings':
|
18 |
+
if (!file_exists($extension_data['path'] .'/readme.md.php')) {
|
19 |
+
break;
|
20 |
+
}
|
21 |
+
if ($is_supported) {
|
22 |
+
// do not show install instructions for supported extensions
|
23 |
+
break;
|
24 |
+
}
|
25 |
+
?><a href="<?php echo esc_attr($link_extension) ?>&extension=<?php echo esc_attr($extension_name) ?>&tab=docs" class="button-primary"><?php _e('Install Instructions', 'fw') ?></a><?php
|
26 |
+
break;
|
27 |
+
case 'docs':
|
28 |
+
if (!fw()->extensions->get($extension_name) || !fw()->extensions->get($extension_name)->get_settings_options()) {
|
29 |
+
break;
|
30 |
+
}
|
31 |
+
?><a href="<?php echo esc_attr($link_extension) ?>&extension=<?php echo esc_attr($extension_name) ?>" class="button-primary"><?php _e('Settings', 'fw') ?></a><?php
|
32 |
+
break;
|
33 |
+
}
|
34 |
+
?>
|
35 |
+
</span>
|
36 |
+
|
37 |
+
<?php
|
38 |
+
switch ($tab) {
|
39 |
+
case 'settings':
|
40 |
+
echo sprintf(__('%s Settings', 'fw'), $extension_title);
|
41 |
+
break;
|
42 |
+
case 'docs':
|
43 |
+
echo sprintf(__('%s Install Instructions', 'fw'), $extension_title);
|
44 |
+
break;
|
45 |
+
default:
|
46 |
+
echo __('Unknown tab:', 'fw') . ' ' . fw_htmlspecialchars($tab);
|
47 |
+
}
|
48 |
+
?>
|
49 |
+
</h2>
|
50 |
+
<br/>
|
framework/core/components/extensions/manager/views/extension.php
CHANGED
@@ -1,229 +1,246 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
/**
|
3 |
-
* Display extension in list on the extensions page
|
4 |
-
* @var string $name
|
5 |
-
* @var string $title
|
6 |
-
* @var string $description
|
7 |
-
* @var string $link
|
8 |
-
* @var array $lists
|
9 |
-
* @var array $nonces
|
10 |
-
* @var string $default_thumbnail
|
11 |
-
* @var bool $can_install
|
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 |
-
}
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
<?php
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
);
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
/**
|
3 |
+
* Display extension in list on the extensions page
|
4 |
+
* @var string $name
|
5 |
+
* @var string $title
|
6 |
+
* @var string $description
|
7 |
+
* @var string $link
|
8 |
+
* @var array $lists
|
9 |
+
* @var array $nonces
|
10 |
+
* @var string $default_thumbnail
|
11 |
+
* @var bool $can_install
|
12 |
+
* @var bool $is_active
|
13 |
+
*/
|
14 |
+
|
15 |
+
$ext = fw_ext( $name );
|
16 |
+
$is_active = isset( $lists['active'][ $name ] ) ? true : false;
|
17 |
+
$version = $ext ? $ext->manifest->get_version() : '';
|
18 |
+
$ext_page = $ext ? $ext->_get_link() : '';
|
19 |
+
$url_set = '';
|
20 |
+
|
21 |
+
if ( $ext && $ext->get_settings_options() ) {
|
22 |
+
$url_set = "{$link}&sub-page=extension&extension={$name}";
|
23 |
+
} else {
|
24 |
+
if ( ! empty( $lists['available'][ $name ]['download']['url_set'] ) ) {
|
25 |
+
$url_set = admin_url( $lists['available'][ $name ]['download']['url_set'] );
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
if (isset($lists['installed'][$name])) {
|
30 |
+
$installed_data = &$lists['installed'][$name];
|
31 |
+
} else {
|
32 |
+
$installed_data = false;
|
33 |
+
}
|
34 |
+
|
35 |
+
if (isset($lists['available'][$name])) {
|
36 |
+
$available_data = &$lists['available'][$name];
|
37 |
+
} else {
|
38 |
+
$available_data = false;
|
39 |
+
}
|
40 |
+
|
41 |
+
{
|
42 |
+
if (isset($lists['available'][$name])) {
|
43 |
+
$thumbnail = $lists['available'][$name]['thumbnail'];
|
44 |
+
} else {
|
45 |
+
$thumbnail = $default_thumbnail;
|
46 |
+
}
|
47 |
+
|
48 |
+
if ( isset( $lists['installed'][ $name ] ) ) {
|
49 |
+
|
50 |
+
$manifest = ! empty( $lists['installed'][ $name ]['thumbnail'] ) ? $lists['installed'][ $name ]['thumbnail'] : $lists['installed'][ $name ]['manifest'];
|
51 |
+
$thumbnail = fw_akg( 'thumbnail', $manifest, $thumbnail );
|
52 |
+
|
53 |
+
// local image
|
54 |
+
if (
|
55 |
+
substr( $thumbnail, 0, 11 ) !== 'data:image/'
|
56 |
+
&&
|
57 |
+
! filter_var( $thumbnail, FILTER_VALIDATE_URL )
|
58 |
+
&&
|
59 |
+
file_exists( $thumbnail_path = $lists['installed'][ $name ]['path'] . '/' . $thumbnail )
|
60 |
+
) {
|
61 |
+
$thumbnail = fw_get_path_url( $thumbnail_path );
|
62 |
+
}
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
$is_compatible =
|
67 |
+
isset($lists['supported'][$name]) // is listed in the supported extensions list in theme manifest
|
68 |
+
||
|
69 |
+
($installed_data && ! empty( $installed_data['is']['theme'] ) ); // is located in the theme
|
70 |
+
|
71 |
+
$wrapper_class = 'fw-col-xs-12 fw-col-lg-6 fw-extensions-list-item';
|
72 |
+
|
73 |
+
if ($installed_data && !$is_active) {
|
74 |
+
$wrapper_class .= ' disabled';
|
75 |
+
}
|
76 |
+
|
77 |
+
if (!$installed_data && !$is_compatible) {
|
78 |
+
$wrapper_class .= ' not-compatible';
|
79 |
+
}
|
80 |
+
?>
|
81 |
+
<div class="<?php echo esc_attr($wrapper_class) ?>" id="fw-ext-<?php echo esc_attr($name) ?>">
|
82 |
+
<a class="fw-ext-anchor" name="ext-<?php echo esc_attr($name) ?>"></a>
|
83 |
+
<div class="inner">
|
84 |
+
<div class="fw-extension-list-item-table">
|
85 |
+
<div class="fw-extension-list-item-table-row">
|
86 |
+
<div class="fw-extension-list-item-table-cell cell-1">
|
87 |
+
<div class="fw-extensions-list-item-thumbnail-wrapper">
|
88 |
+
<?php echo fw_string_to_icon_html($thumbnail, array('class' => 'fw-extensions-list-item-thumbnail')); ?>
|
89 |
+
</div>
|
90 |
+
</div>
|
91 |
+
<div class="fw-extension-list-item-table-cell cell-2">
|
92 |
+
|
93 |
+
<h3 class="fw-extensions-list-item-title"<?php echo( $is_active && $version ? ' title="v' . esc_attr( $version ) . '"' : '' ); ?>>
|
94 |
+
<?php
|
95 |
+
if ( $is_active && $ext_page ) {
|
96 |
+
echo fw_html_tag( 'a', array( 'href' => $ext_page ), $title );
|
97 |
+
} else {
|
98 |
+
echo $title;
|
99 |
+
}
|
100 |
+
?>
|
101 |
+
</h3>
|
102 |
+
|
103 |
+
<?php if ($description): ?>
|
104 |
+
<p class="fw-extensions-list-item-desc"><?php echo esc_html($description); ?></p>
|
105 |
+
<?php endif; ?>
|
106 |
+
|
107 |
+
<?php
|
108 |
+
if ( $installed_data ) {
|
109 |
+
$_links = array();
|
110 |
+
|
111 |
+
if ( $is_active && $url_set ) {
|
112 |
+
$_links[] = '<a href="' . esc_url( $url_set ) . '">' . __( 'Settings', 'fw' ) . '</a>';
|
113 |
+
}
|
114 |
+
|
115 |
+
if ( $is_active && isset( $installed_data['path'] ) && file_exists( $installed_data['path'] . '/readme.md.php' ) ) {
|
116 |
+
if ( isset($lists['supported'][$name]) ) {
|
117 |
+
// no sense to teach how to install the extension if theme is already configured and the is extension marked as compatible
|
118 |
+
} else {
|
119 |
+
$_links[] = '<a href="' . esc_attr( $link ) . '&sub-page=extension&extension=' . esc_attr( $name ) . '&tab=docs">' . __( 'Install Instructions', 'fw' ) . '</a>';
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
if ( ! empty( $_links ) ):
|
124 |
+
?><p class="fw-extensions-list-item-links"><?php echo implode( ' <span class="fw-text-muted">|</span> ', $_links ); ?></p><?php
|
125 |
+
endif;
|
126 |
+
|
127 |
+
unset( $_links );
|
128 |
+
}
|
129 |
+
?>
|
130 |
+
<?php if ($is_compatible): ?>
|
131 |
+
<p><em><strong><span class="dashicons dashicons-yes"></span> <?php _e('Compatible', 'fw') ?></strong> <?php _e('with your current theme', 'fw') ?></em></p>
|
132 |
+
<?php endif; ?>
|
133 |
+
</div>
|
134 |
+
<div class="fw-extension-list-item-table-cell cell-3">
|
135 |
+
<?php if ($is_active): ?>
|
136 |
+
<form action="<?php echo esc_attr($link) ?>&sub-page=deactivate&extension=<?php echo esc_attr( $name ) ?>" method="post">
|
137 |
+
<?php wp_nonce_field($nonces['deactivate']['action'], $nonces['deactivate']['name']); ?>
|
138 |
+
<input class="button" type="submit" value="<?php esc_attr_e('Deactivate', 'fw'); ?>"/>
|
139 |
+
</form>
|
140 |
+
<?php elseif ($installed_data): ?>
|
141 |
+
<div class="fw-text-center">
|
142 |
+
<form action="<?php echo esc_attr($link) ?>&sub-page=activate&extension=<?php echo esc_attr($name) ?>"
|
143 |
+
method="post"
|
144 |
+
class="extension-activate-form"
|
145 |
+
>
|
146 |
+
<?php wp_nonce_field($nonces['activate']['action'], $nonces['activate']['name']); ?>
|
147 |
+
<input class="button" type="submit" value="<?php esc_attr_e('Activate', 'fw'); ?>"/>
|
148 |
+
</form>
|
149 |
+
<?php
|
150 |
+
/**
|
151 |
+
* Do not show the "Delete extension" button if the extension is not in the available list.
|
152 |
+
* If you delete such extension you will not be able to install it back.
|
153 |
+
* Most often these will be extensions located in the theme.
|
154 |
+
*/
|
155 |
+
if ($can_install && $available_data):
|
156 |
+
?>
|
157 |
+
<form action="<?php echo esc_attr($link) ?>&sub-page=delete&extension=<?php echo esc_attr($name) ?>"
|
158 |
+
method="post"
|
159 |
+
class="fw-extension-ajax-form extension-delete-form"
|
160 |
+
data-confirm-message="<?php esc_attr_e('Are you sure you want to remove this extension?', 'fw') ?>"
|
161 |
+
data-extension-name="<?php echo esc_attr($name) ?>"
|
162 |
+
data-extension-action="uninstall"
|
163 |
+
>
|
164 |
+
<?php wp_nonce_field($nonces['delete']['action'], $nonces['delete']['name']); ?>
|
165 |
+
<p class="fw-visible-xs-block"></p>
|
166 |
+
<a href="#"
|
167 |
+
onclick="jQuery(this).closest('form').submit(); return false;"
|
168 |
+
data-remove-extension="<?php echo esc_attr($name) ?>"
|
169 |
+
title="<?php esc_attr_e('Remove', 'fw'); ?>"
|
170 |
+
><span class="btn-text fw-visible-xs-inline"><?php _e('Remove', 'fw'); ?></span><span class="btn-icon unycon unycon-trash fw-hidden-xs"></span></a>
|
171 |
+
</form>
|
172 |
+
<?php endif; ?>
|
173 |
+
</div>
|
174 |
+
<?php elseif ($can_install && $available_data): ?>
|
175 |
+
<form action="<?php echo esc_attr($link) ?>&sub-page=install&extension=<?php echo esc_attr($name) ?>"
|
176 |
+
method="post"
|
177 |
+
class="fw-extension-ajax-form"
|
178 |
+
data-extension-name="<?php echo esc_attr($name) ?>"
|
179 |
+
data-extension-action="install"
|
180 |
+
>
|
181 |
+
<?php wp_nonce_field($nonces['install']['action'], $nonces['install']['name']); ?>
|
182 |
+
<input type="submit" class="button" value="<?php esc_attr_e('Download', 'fw') ?>">
|
183 |
+
</form>
|
184 |
+
<?php endif; ?>
|
185 |
+
</div>
|
186 |
+
</div>
|
187 |
+
</div>
|
188 |
+
<?php if ($installed_data): ?>
|
189 |
+
<?php if (!$is_active): ?>
|
190 |
+
<?php if (!fw()->extensions->_get_db_active_extensions($name)): ?>
|
191 |
+
<span><!-- Is not set as active in db --></span>
|
192 |
+
<?php elseif ($installed_data['parent'] && !fw()->extensions->get($installed_data['parent'])): ?>
|
193 |
+
<?php
|
194 |
+
$parent_extension_name = $installed_data['parent'];
|
195 |
+
$parent_extension_title = fw_id_to_title($parent_extension_name);
|
196 |
+
|
197 |
+
if (isset($lists['installed'][$parent_extension_name])) {
|
198 |
+
$parent_extension_title = fw_akg('name', $lists['installed'][$parent_extension_name]['manifest'], $parent_extension_title);
|
199 |
+
} elseif (isset($lists['available'][$parent_extension_name])) {
|
200 |
+
$parent_extension_title = $lists['available'][$parent_extension_name]['name'];
|
201 |
+
}
|
202 |
+
?>
|
203 |
+
<p class="fw-text-muted"><?php echo sprintf(__('Parent extension "%s" is disabled', 'fw'), $parent_extension_title); ?></p>
|
204 |
+
<?php else: ?>
|
205 |
+
<div class="fw-extension-disabled fw-border-box-sizing">
|
206 |
+
<div class="fw-extension-disabled-panel fw-border-box-sizing">
|
207 |
+
<div class="fw-row">
|
208 |
+
<div class="fw-col-xs-12 fw-col-sm-3">
|
209 |
+
<span class="fw-text-danger">! <?php _e('Disabled', 'fw'); ?></span>
|
210 |
+
</div>
|
211 |
+
<div class="fw-col-xs-12 fw-col-sm-9 fw-text-right">
|
212 |
+
<?php
|
213 |
+
|
214 |
+
$requirements = fw()
|
215 |
+
->extensions
|
216 |
+
->manager->collect_extension_requirements(
|
217 |
+
$name
|
218 |
+
);
|
219 |
+
|
220 |
+
?>
|
221 |
+
<a onclick="return false;" href="#" class="fw-extension-tip" title="<?php
|
222 |
+
echo fw_htmlspecialchars(
|
223 |
+
'<div class="fw-extension-tip-content">'.
|
224 |
+
'<ul class="fw-extension-requirements"><li>- '. implode('</li><li>- ', $requirements) .'</li></ul>'.
|
225 |
+
'</div>'
|
226 |
+
);
|
227 |
+
unset($requirements);
|
228 |
+
?>"><?php _e('View Requirements', 'fw') ?></a>
|
229 |
+
<p class="fw-visible-xs-block"></p><?php
|
230 |
+
if ($can_install):
|
231 |
+
?><a href="<?php echo esc_attr($link) ?>&sub-page=delete&extension=<?php echo esc_attr($name) ?>" class="button" ><?php _e('Remove', 'fw'); ?></a><?php
|
232 |
+
endif;
|
233 |
+
?>
|
234 |
+
</div>
|
235 |
+
</div>
|
236 |
+
</div>
|
237 |
+
</div>
|
238 |
+
<?php endif; ?>
|
239 |
+
<?php endif; ?>
|
240 |
+
<?php elseif ($available_data): ?>
|
241 |
+
<!-- -->
|
242 |
+
<?php else: ?>
|
243 |
+
<!-- -->
|
244 |
+
<?php endif; ?>
|
245 |
+
</div>
|
246 |
+
</div>
|
framework/core/components/extensions/manager/views/extensions-page.php
CHANGED
@@ -1,242 +1,267 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
/**
|
3 |
-
* @var array $lists
|
4 |
-
* @var string $link
|
5 |
-
* @var array $nonces
|
6 |
-
* @var mixed $display_default_value
|
7 |
-
* @var string $default_thumbnail
|
8 |
-
* @var bool $can_install
|
9 |
-
*/
|
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 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
</div>
|
79 |
-
<?php
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
)
|
189 |
-
|
190 |
-
$
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
'
|
206 |
-
'
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
/**
|
3 |
+
* @var array $lists
|
4 |
+
* @var string $link
|
5 |
+
* @var array $nonces
|
6 |
+
* @var mixed $display_default_value
|
7 |
+
* @var string $default_thumbnail
|
8 |
+
* @var bool $can_install
|
9 |
+
*/
|
10 |
+
|
11 |
+
$installed_plugins = get_plugins();
|
12 |
+
|
13 |
+
foreach ( $lists['available'] as $name => &$_ext ) {
|
14 |
+
if ( empty( $_ext['download']['opts']['plugin'] ) ) {
|
15 |
+
continue;
|
16 |
+
}
|
17 |
+
|
18 |
+
$slug = $_ext['download']['opts']['plugin'];
|
19 |
+
|
20 |
+
if ( is_plugin_active( $slug ) ) {
|
21 |
+
$lists['active'][ $name ] = $_ext;
|
22 |
+
$lists['installed'][ $name ] = $_ext;
|
23 |
+
} else {
|
24 |
+
if ( isset( $installed_plugins[ $slug ] ) ) {
|
25 |
+
$lists['installed'][ $name ] = $_ext;
|
26 |
+
$lists['disabled'][ $name ] = $_ext;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
$lists['supported'][ $name ] = $_ext;
|
31 |
+
}
|
32 |
+
|
33 |
+
// Set extensions order same as in available extensions list
|
34 |
+
{
|
35 |
+
$ordered = array(
|
36 |
+
'active' => array(),
|
37 |
+
'installed' => array(),
|
38 |
+
);
|
39 |
+
|
40 |
+
foreach ( $lists['available'] as $name => &$_ext ) {
|
41 |
+
foreach ( $ordered as $type => &$_exts ) {
|
42 |
+
if ( isset( $lists[ $type ][ $name ] ) ) {
|
43 |
+
$ordered[ $type ][ $name ] = $lists[ $type ][ $name ];
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
foreach ( $ordered as $type => &$_exts ) {
|
49 |
+
if ( ! empty( $ordered[ $type ] ) ) {
|
50 |
+
$lists[ $type ] = array_merge( $ordered[ $type ], $lists[ $type ] );
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
unset( $ordered, $name, $_ext, $_exts, $type );
|
55 |
+
}
|
56 |
+
|
57 |
+
$extension_view_path = dirname( __FILE__ ) . '/extension.php';
|
58 |
+
|
59 |
+
$displayed = array();
|
60 |
+
?>
|
61 |
+
|
62 |
+
<h3><?php _e('Active Extensions', 'fw') ?></h3>
|
63 |
+
<?php
|
64 |
+
$display_active_extensions = array();
|
65 |
+
|
66 |
+
foreach ( $lists['active'] as $name => &$data ) {
|
67 |
+
if ( ! empty( $data['display'] ) || true === fw_akg( 'display', $data['manifest'], $display_default_value ) ) {
|
68 |
+
$display_active_extensions[ $name ] = &$data;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
unset($data);
|
73 |
+
?>
|
74 |
+
<?php if (empty($display_active_extensions)): ?>
|
75 |
+
<div class="fw-extensions-no-active">
|
76 |
+
<div class="fw-text-center fw-extensions-title-icon"><span class="dashicons dashicons-screenoptions"></span></div>
|
77 |
+
<p class="fw-text-center fw-text-muted"><em><?php _e('No extensions activated yet', 'fw'); ?><br/><?php _e('Check the available extensions below', 'fw'); ?></em></p>
|
78 |
+
</div>
|
79 |
+
<?php else: ?>
|
80 |
+
<div class="fw-row fw-extensions-list">
|
81 |
+
<?php
|
82 |
+
foreach ( $display_active_extensions as $name => &$data ) {
|
83 |
+
|
84 |
+
$ext = fw_ext( $name );
|
85 |
+
|
86 |
+
fw_render_view( $extension_view_path, array(
|
87 |
+
'name' => $name,
|
88 |
+
'title' => $ext ? $ext->manifest->get_name() : $data['name'],
|
89 |
+
'description' => $ext ? $ext->manifest->get( 'description' ) : ( isset( $data['description'] ) ? $data['description'] : '' ),
|
90 |
+
'link' => $link,
|
91 |
+
'lists' => &$lists,
|
92 |
+
'nonces' => $nonces,
|
93 |
+
'default_thumbnail' => $default_thumbnail,
|
94 |
+
'can_install' => $can_install,
|
95 |
+
), false );
|
96 |
+
|
97 |
+
$displayed[ $name ] = true;
|
98 |
+
}
|
99 |
+
unset($data);
|
100 |
+
?>
|
101 |
+
</div>
|
102 |
+
<?php endif; ?>
|
103 |
+
|
104 |
+
<div id="fw-extensions-list-available">
|
105 |
+
<hr class="fw-extensions-lists-separator"/>
|
106 |
+
<h3><?php _e('Available Extensions', 'fw') ?></h3><!-- This "available" differs from technical "available" -->
|
107 |
+
<div class="fw-row fw-extensions-list">
|
108 |
+
<?php $something_displayed = false; ?>
|
109 |
+
<?php
|
110 |
+
{
|
111 |
+
$theme_extensions = array();
|
112 |
+
|
113 |
+
foreach ( $lists['disabled'] as $name => &$data ) {
|
114 |
+
if ( empty( $data['is']['theme'] ) ) {
|
115 |
+
continue;
|
116 |
+
}
|
117 |
+
|
118 |
+
$theme_extensions[ $name ] = array(
|
119 |
+
'name' => fw_akg( 'name', $data['manifest'], fw_id_to_title( $name ) ),
|
120 |
+
'description' => fw_akg( 'description', $data['manifest'], '' )
|
121 |
+
);
|
122 |
+
}
|
123 |
+
unset($data);
|
124 |
+
|
125 |
+
foreach ($theme_extensions + $lists['supported'] as $name => $data) {
|
126 |
+
if (isset($displayed[$name])) {
|
127 |
+
continue;
|
128 |
+
} elseif ( isset( $lists['installed'][ $name ] ) && ! empty( $lists['installed'][$name]['manifest'] ) ) {
|
129 |
+
if (true !== fw_akg('display', $lists['installed'][$name]['manifest'], $display_default_value)) {
|
130 |
+
continue;
|
131 |
+
}
|
132 |
+
} else {
|
133 |
+
if (isset($lists['available'][$name])) {
|
134 |
+
if (!$can_install) {
|
135 |
+
continue;
|
136 |
+
}
|
137 |
+
} else {
|
138 |
+
//trigger_error(sprintf(__('Supported extension "%s" is not available.', 'fw'), $name));
|
139 |
+
continue;
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
fw_render_view($extension_view_path, array(
|
144 |
+
'name' => $name,
|
145 |
+
'title' => $data['name'],
|
146 |
+
'description' => $data['description'],
|
147 |
+
'link' => $link,
|
148 |
+
'lists' => &$lists,
|
149 |
+
'nonces' => $nonces,
|
150 |
+
'default_thumbnail' => $default_thumbnail,
|
151 |
+
'can_install' => $can_install,
|
152 |
+
), false);
|
153 |
+
|
154 |
+
$displayed[$name] = $something_displayed = true;
|
155 |
+
}
|
156 |
+
|
157 |
+
unset($theme_extensions);
|
158 |
+
}
|
159 |
+
|
160 |
+
foreach ( $lists['disabled'] as $name => &$data ) {
|
161 |
+
if ( isset( $displayed[ $name ] ) ) {
|
162 |
+
continue;
|
163 |
+
} elseif ( isset( $data['display'] ) && true !== $data['display'] ) {
|
164 |
+
continue;
|
165 |
+
} elseif ( isset( $data['manifest'] ) && true !== fw_akg( 'display', $data['manifest'], $display_default_value ) ) {
|
166 |
+
continue;
|
167 |
+
}
|
168 |
+
|
169 |
+
fw_render_view( $extension_view_path, array(
|
170 |
+
'name' => $name,
|
171 |
+
'title' => ! empty( $data['manifest']['name'] ) ? $data['manifest']['name'] : ( ! empty( $data['name'] ) ? $data['name'] : 'No name' ),
|
172 |
+
'description' => ! empty( $data['manifest']['description'] ) ? $data['manifest']['description'] : ( ! empty( $data['description'] ) ? $data['description'] : '' ),
|
173 |
+
'link' => $link,
|
174 |
+
'lists' => &$lists,
|
175 |
+
'nonces' => $nonces,
|
176 |
+
'default_thumbnail' => $default_thumbnail,
|
177 |
+
'can_install' => $can_install,
|
178 |
+
), false );
|
179 |
+
|
180 |
+
$displayed[$name] = $something_displayed = true;
|
181 |
+
}
|
182 |
+
unset($data);
|
183 |
+
|
184 |
+
if ($can_install) {
|
185 |
+
foreach ( $lists['available'] as $name => &$data ) {
|
186 |
+
if ( isset( $displayed[ $name ] ) ) {
|
187 |
+
continue;
|
188 |
+
} elseif ( isset( $lists['installed'][ $name ] ) ) {
|
189 |
+
continue;
|
190 |
+
} elseif ( $data['display'] !== true ) {
|
191 |
+
continue;
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* fixme: remove this in the future when this extensions will look good on any theme
|
196 |
+
*/
|
197 |
+
if ( in_array( $name, array( 'styling', 'megamenu' ) ) ) {
|
198 |
+
if ( isset( $lists['supported'][ $name ] ) || ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
|
199 |
+
} else {
|
200 |
+
continue;
|
201 |
+
}
|
202 |
+
}
|
203 |
+
|
204 |
+
fw_render_view( $extension_view_path, array(
|
205 |
+
'name' => $name,
|
206 |
+
'title' => $data['name'],
|
207 |
+
'description' => $data['description'],
|
208 |
+
'link' => $link,
|
209 |
+
'lists' => &$lists,
|
210 |
+
'nonces' => $nonces,
|
211 |
+
'default_thumbnail' => $default_thumbnail,
|
212 |
+
'can_install' => $can_install,
|
213 |
+
), false );
|
214 |
+
|
215 |
+
$something_displayed = true;
|
216 |
+
}
|
217 |
+
unset($data);
|
218 |
+
}
|
219 |
+
?>
|
220 |
+
</div>
|
221 |
+
|
222 |
+
<?php if ($something_displayed && apply_filters('fw_extensions_page_show_other_extensions', true)): ?>
|
223 |
+
<!-- show/hide not compatible extensions -->
|
224 |
+
<p class="fw-text-center toggle-not-compat-ext-btn-wrapper"><?php
|
225 |
+
echo fw_html_tag(
|
226 |
+
'a',
|
227 |
+
array(
|
228 |
+
'href' => '#',
|
229 |
+
'onclick' => 'return false;',
|
230 |
+
'class' => 'button toggle-not-compat-ext-btn',
|
231 |
+
'style' => 'box-shadow:none;'
|
232 |
+
),
|
233 |
+
'<span class="the-show-text">'. __('Show other extensions', 'fw') .'</span>'.
|
234 |
+
'<span class="the-hide-text fw-hidden">'. __('Hide other extensions', 'fw') .'</span>'
|
235 |
+
);
|
236 |
+
?></p>
|
237 |
+
<script type="text/javascript">
|
238 |
+
jQuery(function($){
|
239 |
+
if (
|
240 |
+
!$('.fw-extensions-list .fw-extensions-list-item.not-compatible').length
|
241 |
+
||
|
242 |
+
<?php echo empty($lists['supported']) ? 'true' : 'false' ?>
|
243 |
+
) {
|
244 |
+
// disable the show/hide feature
|
245 |
+
$('#fw-extensions-list-wrapper .toggle-not-compat-ext-btn-wrapper').addClass('fw-hidden');
|
246 |
+
} else {
|
247 |
+
$('#fw-extensions-list-wrapper .fw-extensions-list .fw-extensions-list-item.not-compatible').fadeOut('fast');
|
248 |
+
|
249 |
+
$('#fw-extensions-list-wrapper .toggle-not-compat-ext-btn-wrapper').on('click', function(){
|
250 |
+
$('#fw-extensions-list-wrapper .fw-extensions-list .fw-extensions-list-item.not-compatible')[
|
251 |
+
$(this).find('.the-hide-text').hasClass('fw-hidden') ? 'fadeIn' : 'fadeOut'
|
252 |
+
]();
|
253 |
+
|
254 |
+
$(this).find('.the-show-text, .the-hide-text').toggleClass('fw-hidden');
|
255 |
+
});
|
256 |
+
}
|
257 |
+
});
|
258 |
+
</script>
|
259 |
+
<!-- end: show/hide not compatible extensions -->
|
260 |
+
<?php else: ?>
|
261 |
+
<script type="text/javascript">
|
262 |
+
jQuery(function($){
|
263 |
+
$('#fw-extensions-list-available').remove();
|
264 |
+
});
|
265 |
+
</script>
|
266 |
+
<?php endif; ?>
|
267 |
+
</div>
|
framework/core/components/extensions/manager/views/install-form.php
CHANGED
@@ -1,51 +1,51 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
/**
|
3 |
-
* @var array $extension_titles
|
4 |
-
* @var array $list_page_link
|
5 |
-
* @var bool $supported
|
6 |
-
*/
|
7 |
-
|
8 |
-
$count = count($extension_titles);
|
9 |
-
?>
|
10 |
-
|
11 |
-
<?php if ($supported): ?>
|
12 |
-
<p><?php echo _n(
|
13 |
-
'We\'ve detected that your current theme is compatible with the following extension and it is recommended that you install it to fully benefit from your theme.',
|
14 |
-
'We\'ve detected that your current theme is compatible with the following extensions and it is recommended that you install them to fully benefit from your theme.',
|
15 |
-
$count,
|
16 |
-
'fw'
|
17 |
-
) ?></p>
|
18 |
-
<?php else: ?>
|
19 |
-
<p><?php echo _n(
|
20 |
-
'You are about to install the following extension:',
|
21 |
-
'You are about to install the following extensions:',
|
22 |
-
$count,
|
23 |
-
'fw'
|
24 |
-
) ?></p>
|
25 |
-
<?php endif; ?>
|
26 |
-
|
27 |
-
<ul class="ul-disc">
|
28 |
-
<?php foreach ($extension_titles as $extension_title): ?>
|
29 |
-
<li><strong><?php echo $extension_title; ?></strong></li>
|
30 |
-
<?php endforeach; ?>
|
31 |
-
</ul>
|
32 |
-
|
33 |
-
<p><?php
|
34 |
-
echo _n(
|
35 |
-
'Are you sure you wish to install this extension?',
|
36 |
-
'Are you sure you wish to install these extensions?',
|
37 |
-
$count,
|
38 |
-
'fw'
|
39 |
-
)
|
40 |
-
?></p>
|
41 |
-
|
42 |
-
<input type="submit" name="submit" id="submit" class="button" value="<?php
|
43 |
-
echo esc_attr( _n(
|
44 |
-
'Yes, Install this extension',
|
45 |
-
'Yes, Install these extensions',
|
46 |
-
$count,
|
47 |
-
'fw'
|
48 |
-
) )
|
49 |
-
?>">
|
50 |
-
|
51 |
-
<a class="button" href="<?php echo esc_attr($list_page_link) ?>" ><?php _e('No, Return me to the extension list', 'fw') ?></a>
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
/**
|
3 |
+
* @var array $extension_titles
|
4 |
+
* @var array $list_page_link
|
5 |
+
* @var bool $supported
|
6 |
+
*/
|
7 |
+
|
8 |
+
$count = count($extension_titles);
|
9 |
+
?>
|
10 |
+
|
11 |
+
<?php if ($supported): ?>
|
12 |
+
<p><?php echo _n(
|
13 |
+
'We\'ve detected that your current theme is compatible with the following extension and it is recommended that you install it to fully benefit from your theme.',
|
14 |
+
'We\'ve detected that your current theme is compatible with the following extensions and it is recommended that you install them to fully benefit from your theme.',
|
15 |
+
$count,
|
16 |
+
'fw'
|
17 |
+
) ?></p>
|
18 |
+
<?php else: ?>
|
19 |
+
<p><?php echo _n(
|
20 |
+
'You are about to install the following extension:',
|
21 |
+
'You are about to install the following extensions:',
|
22 |
+
$count,
|
23 |
+
'fw'
|
24 |
+
) ?></p>
|
25 |
+
<?php endif; ?>
|
26 |
+
|
27 |
+
<ul class="ul-disc">
|
28 |
+
<?php foreach ($extension_titles as $extension_title): ?>
|
29 |
+
<li><strong><?php echo $extension_title; ?></strong></li>
|
30 |
+
<?php endforeach; ?>
|
31 |
+
</ul>
|
32 |
+
|
33 |
+
<p><?php
|
34 |
+
echo _n(
|
35 |
+
'Are you sure you wish to install this extension?',
|
36 |
+
'Are you sure you wish to install these extensions?',
|
37 |
+
$count,
|
38 |
+
'fw'
|
39 |
+
)
|
40 |
+
?></p>
|
41 |
+
|
42 |
+
<input type="submit" name="submit" id="submit" class="button" value="<?php
|
43 |
+
echo esc_attr( _n(
|
44 |
+
'Yes, Install this extension',
|
45 |
+
'Yes, Install these extensions',
|
46 |
+
$count,
|
47 |
+
'fw'
|
48 |
+
) )
|
49 |
+
?>">
|
50 |
+
|
51 |
+
<a class="button" href="<?php echo esc_attr($list_page_link) ?>" ><?php _e('No, Return me to the extension list', 'fw') ?></a>
|
framework/core/components/theme.php
CHANGED
@@ -1,203 +1,203 @@
|
|
1 |
-
<?php defined( 'FW' ) or die();
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Theme Component
|
5 |
-
* Works with framework customizations / theme directory
|
6 |
-
*/
|
7 |
-
final class _FW_Component_Theme {
|
8 |
-
private static $cache_key = 'fw_theme';
|
9 |
-
|
10 |
-
/**
|
11 |
-
* @var FW_Theme_Manifest
|
12 |
-
*/
|
13 |
-
public $manifest;
|
14 |
-
|
15 |
-
public function __construct() {
|
16 |
-
$manifest = array();
|
17 |
-
|
18 |
-
if ( ( $manifest_file = fw_get_template_customizations_directory( '/theme/manifest.php' ) ) && is_file( $manifest_file ) ) {
|
19 |
-
@include $manifest_file;
|
20 |
-
}
|
21 |
-
|
22 |
-
$this->manifest = new FW_Theme_Manifest( $manifest );
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @internal
|
27 |
-
*/
|
28 |
-
public function _init() {
|
29 |
-
add_action( 'admin_notices', array( $this, '_action_admin_notices' ) );
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* @internal
|
34 |
-
*/
|
35 |
-
public function _after_components_init() {
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Search relative path in: child theme -> parent "theme" directory and return full path
|
40 |
-
*
|
41 |
-
* @param string $rel_path
|
42 |
-
*
|
43 |
-
* @return false|string
|
44 |
-
*/
|
45 |
-
public function locate_path( $rel_path ) {
|
46 |
-
if ( is_child_theme() && file_exists( fw_get_stylesheet_customizations_directory( '/theme' . $rel_path ) ) ) {
|
47 |
-
return fw_get_stylesheet_customizations_directory( '/theme' . $rel_path );
|
48 |
-
} elseif ( file_exists( fw_get_template_customizations_directory( '/theme' . $rel_path ) ) ) {
|
49 |
-
return fw_get_template_customizations_directory( '/theme' . $rel_path );
|
50 |
-
} else {
|
51 |
-
return false;
|
52 |
-
}
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Return array with options from specified name/path
|
57 |
-
*
|
58 |
-
* @param string $name '{theme}/framework-customizations/theme/options/{$name}.php'
|
59 |
-
* @param array $variables These will be available in options file (like variables for view)
|
60 |
-
*
|
61 |
-
* @return array
|
62 |
-
*/
|
63 |
-
public function get_options( $name, array $variables = array() ) {
|
64 |
-
$path = $this->locate_path( '/options/' . $name . '.php' );
|
65 |
-
|
66 |
-
if ( ! $path ) {
|
67 |
-
return array();
|
68 |
-
}
|
69 |
-
|
70 |
-
$variables = fw_get_variables_from_file( $path, array( 'options' => array() ), $variables );
|
71 |
-
|
72 |
-
return $variables['options'];
|
73 |
-
}
|
74 |
-
|
75 |
-
public function get_settings_options() {
|
76 |
-
$cache_key = self::$cache_key . '/options/settings';
|
77 |
-
|
78 |
-
try {
|
79 |
-
return FW_Cache::get( $cache_key );
|
80 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
81 |
-
$options = apply_filters( 'fw_settings_options', $this->get_options( 'settings' ) );
|
82 |
-
|
83 |
-
FW_Cache::set( $cache_key, $options );
|
84 |
-
|
85 |
-
return $options;
|
86 |
-
}
|
87 |
-
}
|
88 |
-
|
89 |
-
public function get_customizer_options() {
|
90 |
-
$cache_key = self::$cache_key . '/options/customizer';
|
91 |
-
|
92 |
-
try {
|
93 |
-
return FW_Cache::get( $cache_key );
|
94 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
95 |
-
$options = apply_filters( 'fw_customizer_options', $this->get_options( 'customizer' ) );
|
96 |
-
|
97 |
-
FW_Cache::set( $cache_key, $options );
|
98 |
-
|
99 |
-
return $options;
|
100 |
-
}
|
101 |
-
}
|
102 |
-
|
103 |
-
public function get_post_options( $post_type ) {
|
104 |
-
$cache_key = self::$cache_key . '/options/posts/' . $post_type;
|
105 |
-
|
106 |
-
try {
|
107 |
-
return FW_Cache::get( $cache_key );
|
108 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
109 |
-
$options = apply_filters(
|
110 |
-
'fw_post_options',
|
111 |
-
apply_filters( "fw_post_options:$post_type", $this->get_options( 'posts/' . $post_type ) ),
|
112 |
-
$post_type
|
113 |
-
);
|
114 |
-
|
115 |
-
FW_Cache::set( $cache_key, $options );
|
116 |
-
|
117 |
-
return $options;
|
118 |
-
}
|
119 |
-
}
|
120 |
-
|
121 |
-
public function get_taxonomy_options( $taxonomy ) {
|
122 |
-
$cache_key = self::$cache_key . '/options/taxonomies/' . $taxonomy;
|
123 |
-
|
124 |
-
try {
|
125 |
-
return FW_Cache::get( $cache_key );
|
126 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
127 |
-
$options = apply_filters(
|
128 |
-
'fw_taxonomy_options',
|
129 |
-
apply_filters( "fw_taxonomy_options:$taxonomy", $this->get_options( 'taxonomies/' . $taxonomy ) ),
|
130 |
-
$taxonomy
|
131 |
-
);
|
132 |
-
|
133 |
-
FW_Cache::set( $cache_key, $options );
|
134 |
-
|
135 |
-
return $options;
|
136 |
-
}
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Return config key value, or entire config array
|
141 |
-
* Config array is merged from child configs
|
142 |
-
*
|
143 |
-
* @param string|null $key Multi key format accepted: 'a/b/c'
|
144 |
-
* @param mixed $default_value
|
145 |
-
*
|
146 |
-
* @return mixed|null
|
147 |
-
*/
|
148 |
-
final public function get_config( $key = null, $default_value = null ) {
|
149 |
-
$cache_key = self::$cache_key . '/config';
|
150 |
-
|
151 |
-
try {
|
152 |
-
$config = FW_Cache::get( $cache_key );
|
153 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
154 |
-
// default values
|
155 |
-
$config = array(
|
156 |
-
/** Toggle Theme Settings form ajax submit */
|
157 |
-
'settings_form_ajax_submit' => true,
|
158 |
-
/** Toggle Theme Settings side tabs */
|
159 |
-
'settings_form_side_tabs' => false,
|
160 |
-
/** Toggle Tabs rendered all at once, or initialized only on open/display */
|
161 |
-
'lazy_tabs' => true,
|
162 |
-
);
|
163 |
-
|
164 |
-
if ( file_exists( fw_get_template_customizations_directory( '/theme/config.php' ) ) ) {
|
165 |
-
$variables = fw_get_variables_from_file( fw_get_template_customizations_directory( '/theme/config.php' ), array( 'cfg' => null ) );
|
166 |
-
|
167 |
-
if ( ! empty( $variables['cfg'] ) ) {
|
168 |
-
$config = array_merge( $config, $variables['cfg'] );
|
169 |
-
unset( $variables );
|
170 |
-
}
|
171 |
-
}
|
172 |
-
|
173 |
-
if ( is_child_theme() && file_exists( fw_get_stylesheet_customizations_directory( '/theme/config.php' ) ) ) {
|
174 |
-
$variables = fw_get_variables_from_file( fw_get_stylesheet_customizations_directory( '/theme/config.php' ), array( 'cfg' => null ) );
|
175 |
-
|
176 |
-
if ( ! empty( $variables['cfg'] ) ) {
|
177 |
-
$config = array_merge( $config, $variables['cfg'] );
|
178 |
-
unset( $variables );
|
179 |
-
}
|
180 |
-
}
|
181 |
-
|
182 |
-
unset( $path );
|
183 |
-
|
184 |
-
FW_Cache::set( $cache_key, $config );
|
185 |
-
}
|
186 |
-
|
187 |
-
return $key === null ? $config : fw_akg( $key, $config, $default_value );
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* @internal
|
192 |
-
*/
|
193 |
-
public function _action_admin_notices() {
|
194 |
-
if ( is_admin() && ! fw()->theme->manifest->check_requirements() && current_user_can( 'manage_options' ) ) {
|
195 |
-
echo
|
196 |
-
'<div class="notice notice-warning">
|
197 |
-
<p>' .
|
198 |
-
__( 'Theme requirements not met:', 'fw' ) . ' ' . fw()->theme->manifest->get_not_met_requirement_text() .
|
199 |
-
'</p>
|
200 |
-
</div>';
|
201 |
-
}
|
202 |
-
}
|
203 |
-
}
|
1 |
+
<?php defined( 'FW' ) or die();
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Theme Component
|
5 |
+
* Works with framework customizations / theme directory
|
6 |
+
*/
|
7 |
+
final class _FW_Component_Theme {
|
8 |
+
private static $cache_key = 'fw_theme';
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var FW_Theme_Manifest
|
12 |
+
*/
|
13 |
+
public $manifest;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
$manifest = array();
|
17 |
+
|
18 |
+
if ( ( $manifest_file = fw_get_template_customizations_directory( '/theme/manifest.php' ) ) && is_file( $manifest_file ) ) {
|
19 |
+
@include $manifest_file;
|
20 |
+
}
|
21 |
+
|
22 |
+
$this->manifest = new FW_Theme_Manifest( $manifest );
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @internal
|
27 |
+
*/
|
28 |
+
public function _init() {
|
29 |
+
add_action( 'admin_notices', array( $this, '_action_admin_notices' ) );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @internal
|
34 |
+
*/
|
35 |
+
public function _after_components_init() {
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Search relative path in: child theme -> parent "theme" directory and return full path
|
40 |
+
*
|
41 |
+
* @param string $rel_path
|
42 |
+
*
|
43 |
+
* @return false|string
|
44 |
+
*/
|
45 |
+
public function locate_path( $rel_path ) {
|
46 |
+
if ( is_child_theme() && file_exists( fw_get_stylesheet_customizations_directory( '/theme' . $rel_path ) ) ) {
|
47 |
+
return fw_get_stylesheet_customizations_directory( '/theme' . $rel_path );
|
48 |
+
} elseif ( file_exists( fw_get_template_customizations_directory( '/theme' . $rel_path ) ) ) {
|
49 |
+
return fw_get_template_customizations_directory( '/theme' . $rel_path );
|
50 |
+
} else {
|
51 |
+
return false;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Return array with options from specified name/path
|
57 |
+
*
|
58 |
+
* @param string $name '{theme}/framework-customizations/theme/options/{$name}.php'
|
59 |
+
* @param array $variables These will be available in options file (like variables for view)
|
60 |
+
*
|
61 |
+
* @return array
|
62 |
+
*/
|
63 |
+
public function get_options( $name, array $variables = array() ) {
|
64 |
+
$path = $this->locate_path( '/options/' . $name . '.php' );
|
65 |
+
|
66 |
+
if ( ! $path ) {
|
67 |
+
return array();
|
68 |
+
}
|
69 |
+
|
70 |
+
$variables = fw_get_variables_from_file( $path, array( 'options' => array() ), $variables );
|
71 |
+
|
72 |
+
return $variables['options'];
|
73 |
+
}
|
74 |
+
|
75 |
+
public function get_settings_options() {
|
76 |
+
$cache_key = self::$cache_key . '/options/settings';
|
77 |
+
|
78 |
+
try {
|
79 |
+
return FW_Cache::get( $cache_key );
|
80 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
81 |
+
$options = apply_filters( 'fw_settings_options', $this->get_options( 'settings' ) );
|
82 |
+
|
83 |
+
FW_Cache::set( $cache_key, $options );
|
84 |
+
|
85 |
+
return $options;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
public function get_customizer_options() {
|
90 |
+
$cache_key = self::$cache_key . '/options/customizer';
|
91 |
+
|
92 |
+
try {
|
93 |
+
return FW_Cache::get( $cache_key );
|
94 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
95 |
+
$options = apply_filters( 'fw_customizer_options', $this->get_options( 'customizer' ) );
|
96 |
+
|
97 |
+
FW_Cache::set( $cache_key, $options );
|
98 |
+
|
99 |
+
return $options;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
public function get_post_options( $post_type ) {
|
104 |
+
$cache_key = self::$cache_key . '/options/posts/' . $post_type;
|
105 |
+
|
106 |
+
try {
|
107 |
+
return FW_Cache::get( $cache_key );
|
108 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
109 |
+
$options = apply_filters(
|
110 |
+
'fw_post_options',
|
111 |
+
apply_filters( "fw_post_options:$post_type", $this->get_options( 'posts/' . $post_type ) ),
|
112 |
+
$post_type
|
113 |
+
);
|
114 |
+
|
115 |
+
FW_Cache::set( $cache_key, $options );
|
116 |
+
|
117 |
+
return $options;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
public function get_taxonomy_options( $taxonomy ) {
|
122 |
+
$cache_key = self::$cache_key . '/options/taxonomies/' . $taxonomy;
|
123 |
+
|
124 |
+
try {
|
125 |
+
return FW_Cache::get( $cache_key );
|
126 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
127 |
+
$options = apply_filters(
|
128 |
+
'fw_taxonomy_options',
|
129 |
+
apply_filters( "fw_taxonomy_options:$taxonomy", $this->get_options( 'taxonomies/' . $taxonomy ) ),
|
130 |
+
$taxonomy
|
131 |
+
);
|
132 |
+
|
133 |
+
FW_Cache::set( $cache_key, $options );
|
134 |
+
|
135 |
+
return $options;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Return config key value, or entire config array
|
141 |
+
* Config array is merged from child configs
|
142 |
+
*
|
143 |
+
* @param string|null $key Multi key format accepted: 'a/b/c'
|
144 |
+
* @param mixed $default_value
|
145 |
+
*
|
146 |
+
* @return mixed|null
|
147 |
+
*/
|
148 |
+
final public function get_config( $key = null, $default_value = null ) {
|
149 |
+
$cache_key = self::$cache_key . '/config';
|
150 |
+
|
151 |
+
try {
|
152 |
+
$config = FW_Cache::get( $cache_key );
|
153 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
154 |
+
// default values
|
155 |
+
$config = array(
|
156 |
+
/** Toggle Theme Settings form ajax submit */
|
157 |
+
'settings_form_ajax_submit' => true,
|
158 |
+
/** Toggle Theme Settings side tabs */
|
159 |
+
'settings_form_side_tabs' => false,
|
160 |
+
/** Toggle Tabs rendered all at once, or initialized only on open/display */
|
161 |
+
'lazy_tabs' => true,
|
162 |
+
);
|
163 |
+
|
164 |
+
if ( file_exists( fw_get_template_customizations_directory( '/theme/config.php' ) ) ) {
|
165 |
+
$variables = fw_get_variables_from_file( fw_get_template_customizations_directory( '/theme/config.php' ), array( 'cfg' => null ) );
|
166 |
+
|
167 |
+
if ( ! empty( $variables['cfg'] ) ) {
|
168 |
+
$config = array_merge( $config, $variables['cfg'] );
|
169 |
+
unset( $variables );
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
if ( is_child_theme() && file_exists( fw_get_stylesheet_customizations_directory( '/theme/config.php' ) ) ) {
|
174 |
+
$variables = fw_get_variables_from_file( fw_get_stylesheet_customizations_directory( '/theme/config.php' ), array( 'cfg' => null ) );
|
175 |
+
|
176 |
+
if ( ! empty( $variables['cfg'] ) ) {
|
177 |
+
$config = array_merge( $config, $variables['cfg'] );
|
178 |
+
unset( $variables );
|
179 |
+
}
|
180 |
+
}
|
181 |
+
|
182 |
+
unset( $path );
|
183 |
+
|
184 |
+
FW_Cache::set( $cache_key, $config );
|
185 |
+
}
|
186 |
+
|
187 |
+
return $key === null ? $config : fw_akg( $key, $config, $default_value );
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* @internal
|
192 |
+
*/
|
193 |
+
public function _action_admin_notices() {
|
194 |
+
if ( is_admin() && ! fw()->theme->manifest->check_requirements() && current_user_can( 'manage_options' ) ) {
|
195 |
+
echo
|
196 |
+
'<div class="notice notice-warning">
|
197 |
+
<p>' .
|
198 |
+
__( 'Theme requirements not met:', 'fw' ) . ' ' . fw()->theme->manifest->get_not_met_requirement_text() .
|
199 |
+
'</p>
|
200 |
+
</div>';
|
201 |
+
}
|
202 |
+
}
|
203 |
+
}
|
framework/core/exceptions/class-fw-option-type-exception.php
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Class FW_Option_Type_Exception
|
8 |
-
*
|
9 |
-
* @since 2.6.11
|
10 |
-
*/
|
11 |
-
class FW_Option_Type_Exception extends Exception {
|
12 |
-
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Class FW_Option_Type_Exception_Not_Found
|
17 |
-
*
|
18 |
-
* @since 2.6.11
|
19 |
-
*/
|
20 |
-
class FW_Option_Type_Exception_Not_Found extends FW_Option_Type_Exception {
|
21 |
-
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Class FW_Option_Type_Exception_Invalid_Class
|
26 |
-
*
|
27 |
-
* @since 2.6.11
|
28 |
-
*/
|
29 |
-
class FW_Option_Type_Exception_Invalid_Class extends FW_Option_Type_Exception {
|
30 |
-
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Class FW_Option_Type_Exception_Already_Registered
|
35 |
-
*
|
36 |
-
* @since 2.6.11
|
37 |
-
*/
|
38 |
-
class FW_Option_Type_Exception_Already_Registered extends FW_Option_Type_Exception {
|
39 |
-
|
40 |
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class FW_Option_Type_Exception
|
8 |
+
*
|
9 |
+
* @since 2.6.11
|
10 |
+
*/
|
11 |
+
class FW_Option_Type_Exception extends Exception {
|
12 |
+
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Class FW_Option_Type_Exception_Not_Found
|
17 |
+
*
|
18 |
+
* @since 2.6.11
|
19 |
+
*/
|
20 |
+
class FW_Option_Type_Exception_Not_Found extends FW_Option_Type_Exception {
|
21 |
+
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Class FW_Option_Type_Exception_Invalid_Class
|
26 |
+
*
|
27 |
+
* @since 2.6.11
|
28 |
+
*/
|
29 |
+
class FW_Option_Type_Exception_Invalid_Class extends FW_Option_Type_Exception {
|
30 |
+
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Class FW_Option_Type_Exception_Already_Registered
|
35 |
+
*
|
36 |
+
* @since 2.6.11
|
37 |
+
*/
|
38 |
+
class FW_Option_Type_Exception_Already_Registered extends FW_Option_Type_Exception {
|
39 |
+
|
40 |
}
|
framework/core/extends/class-fw-container-type.php
CHANGED
@@ -1,233 +1,233 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Backend option container
|
5 |
-
*/
|
6 |
-
abstract class FW_Container_Type
|
7 |
-
{
|
8 |
-
/**
|
9 |
-
* Container's unique type, used in option array in 'type' key
|
10 |
-
* @return string
|
11 |
-
*/
|
12 |
-
abstract public function get_type();
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Overwrite this method to enqueue scripts and styles
|
16 |
-
*
|
17 |
-
* @param string $id
|
18 |
-
* @param array $option
|
19 |
-
* @param array $values Options values (in db format, returned from get_value_from_input())
|
20 |
-
* @param array $data
|
21 |
-
* @param bool Return true to call this method again on the next enqueue,
|
22 |
-
* if you have some functionality in it that depends on option parameters.
|
23 |
-
* By default this method is called only once for performance reasons.
|
24 |
-
*/
|
25 |
-
abstract protected function _enqueue_static($id, $option, $values, $data);
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Generate html
|
29 |
-
* @param array $containers array('option_id' => array(), ...)
|
30 |
-
* - Options arrays are merged with _get_defaults()
|
31 |
-
* - All options are 100% only current container type, no need to check if ($option['type'] === $this->get_type())
|
32 |
-
* - Are sent multiple options instead of one, because tabs (and maybe other feature containers)
|
33 |
-
* can't be rendered separately (only as a collection).
|
34 |
-
* Instead of having render_option() for those that can be rendered separately,
|
35 |
-
* and render_options() for those like tabs, was decided to make a compromise,
|
36 |
-
* only one method that always will receive an array of options,
|
37 |
-
* instead of two methods when things may become confuse and complicated.
|
38 |
-
* @param array $values Options values (in db format, returned from get_value_from_input())
|
39 |
-
* @param array $data {id_prefix => '...', name_prefix => '...'}
|
40 |
-
* @return string HTML
|
41 |
-
* @internal
|
42 |
-
*/
|
43 |
-
abstract protected function _render($containers, $values, $data);
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Default option array
|
47 |
-
*
|
48 |
-
* This makes possible a container option array to have required only two parameters:
|
49 |
-
* array('type' => '...', 'options' => array(...))
|
50 |
-
* Other parameters are merged with the array returned by this method.
|
51 |
-
*
|
52 |
-
* @return array
|
53 |
-
*
|
54 |
-
* array(
|
55 |
-
* 'type' => '...',
|
56 |
-
* ...
|
57 |
-
* 'options' => array(...),
|
58 |
-
* )
|
59 |
-
* @internal
|
60 |
-
*/
|
61 |
-
abstract protected function _get_defaults();
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Prevent execute enqueue multiple times
|
65 |
-
* @var bool
|
66 |
-
*/
|
67 |
-
private $static_enqueued = false;
|
68 |
-
|
69 |
-
final public function __construct()
|
70 |
-
{
|
71 |
-
// does nothing at the moment, but maybe in the future will do something
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* @param FW_Access_Key $access_key
|
76 |
-
* @internal
|
77 |
-
* This must be called right after an instance of container type has been created
|
78 |
-
* and was added to the registered array
|
79 |
-
*/
|
80 |
-
final public function _call_init($access_key)
|
81 |
-
{
|
82 |
-
if ($access_key->get_key() !== 'fw_backend') {
|
83 |
-
trigger_error('Method call not allowed', E_USER_ERROR);
|
84 |
-
}
|
85 |
-
|
86 |
-
if (method_exists($this, '_init')) {
|
87 |
-
$this->_init();
|
88 |
-
}
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* Fixes and prepare defaults
|
93 |
-
*
|
94 |
-
* @param string $id
|
95 |
-
* @param array $option
|
96 |
-
* @param array $data
|
97 |
-
* @return array
|
98 |
-
*/
|
99 |
-
private function prepare($id, &$option, &$data)
|
100 |
-
{
|
101 |
-
$data = array_merge(
|
102 |
-
array(
|
103 |
-
'id_prefix' => fw()->backend->get_options_id_attr_prefix(), // attribute id prefix
|
104 |
-
'name_prefix' => fw()->backend->get_options_name_attr_prefix(), // attribute name prefix
|
105 |
-
),
|
106 |
-
$data
|
107 |
-
);
|
108 |
-
|
109 |
-
$option = array_merge(
|
110 |
-
$this->get_defaults(),
|
111 |
-
$option,
|
112 |
-
array(
|
113 |
-
'type' => $this->get_type(),
|
114 |
-
)
|
115 |
-
);
|
116 |
-
|
117 |
-
if (!isset($option['attr'])) {
|
118 |
-
$option['attr'] = array();
|
119 |
-
}
|
120 |
-
|
121 |
-
if (!isset($option['title'])) {
|
122 |
-
$option['title'] = fw_id_to_title($id);
|
123 |
-
}
|
124 |
-
|
125 |
-
$option['attr']['class'] = 'fw-container fw-container-type-'. $option['type'] .(
|
126 |
-
isset($option['attr']['class'])
|
127 |
-
? ' '. $option['attr']['class']
|
128 |
-
: ''
|
129 |
-
);
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Generate html
|
134 |
-
* @param array $options array('container_id' => array(...container option...))
|
135 |
-
* @param array $values Options values (in db format, returned from get_value_from_input())
|
136 |
-
* @param array $data {'id_prefix' => '...', 'name_prefix' => '...'}
|
137 |
-
* @return string HTML
|
138 |
-
*/
|
139 |
-
final public function render($options, $values = array(), $data = array())
|
140 |
-
{
|
141 |
-
$containers = array();
|
142 |
-
|
143 |
-
foreach ($options as $id => &$option) {
|
144 |
-
if (
|
145 |
-
!isset($option['options'])
|
146 |
-
||
|
147 |
-
!isset($option['type'])
|
148 |
-
||
|
149 |
-
$option['type'] !== $this->get_type()
|
150 |
-
) {
|
151 |
-
continue;
|
152 |
-
}
|
153 |
-
|
154 |
-
$this->prepare($id, $option, $data);
|
155 |
-
|
156 |
-
$this->enqueue_static($id, $option, $data);
|
157 |
-
|
158 |
-
$containers[$id] = &$option;
|
159 |
-
}
|
160 |
-
|
161 |
-
return $this->_render($containers, $values, $data);
|
162 |
-
}
|
163 |
-
|
164 |
-
/**
|
165 |
-
* Enqueue container type scripts and styles
|
166 |
-
*
|
167 |
-
* All parameters are optional and will be populated with defaults
|
168 |
-
*
|
169 |
-
* @param string $id
|
170 |
-
* @param array $option
|
171 |
-
* @param array $values Options values (in db format, returned from get_value_from_input())
|
172 |
-
* @param array $data
|
173 |
-
* @return bool
|
174 |
-
*/
|
175 |
-
final public function enqueue_static($id = '', $option = array(), $values = array(), $data = array())
|
176 |
-
{
|
177 |
-
if (
|
178 |
-
!doing_action('admin_enqueue_scripts')
|
179 |
-
&&
|
180 |
-
!did_action('admin_enqueue_scripts')
|
181 |
-
) {
|
182 |
-
/**
|
183 |
-
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
184 |
-
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
185 |
-
* So as a result some handles will not be equeued because of not registered dependecies.
|
186 |
-
*/
|
187 |
-
return;
|
188 |
-
}
|
189 |
-
|
190 |
-
if ($this->static_enqueued) {
|
191 |
-
return false;
|
192 |
-
}
|
193 |
-
|
194 |
-
$this->prepare($id, $option, $data);
|
195 |
-
|
196 |
-
$call_next_time = $this->_enqueue_static($id, $option, $values, $data);
|
197 |
-
|
198 |
-
$this->static_enqueued = !$call_next_time;
|
199 |
-
|
200 |
-
return $call_next_time;
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* Default option array
|
205 |
-
*
|
206 |
-
* @return array
|
207 |
-
* 'type' => '...'
|
208 |
-
* 'title' => '...'
|
209 |
-
* 'attr' => array(...)
|
210 |
-
*/
|
211 |
-
final public function get_defaults()
|
212 |
-
{
|
213 |
-
$option = $this->_get_defaults();
|
214 |
-
|
215 |
-
$option['type'] = $this->get_type();
|
216 |
-
|
217 |
-
return $option;
|
218 |
-
}
|
219 |
-
|
220 |
-
/**
|
221 |
-
* Use this method to register a new container type
|
222 |
-
* @param string|FW_Container_Type $container_type_class
|
223 |
-
*/
|
224 |
-
final public static function register($container_type_class) {
|
225 |
-
static $registration_access_key = null;
|
226 |
-
|
227 |
-
if ($registration_access_key === null) {
|
228 |
-
$registration_access_key = new FW_Access_Key('fw_container_type');
|
229 |
-
}
|
230 |
-
|
231 |
-
fw()->backend->_register_container_type($registration_access_key, $container_type_class);
|
232 |
-
}
|
233 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Backend option container
|
5 |
+
*/
|
6 |
+
abstract class FW_Container_Type
|
7 |
+
{
|
8 |
+
/**
|
9 |
+
* Container's unique type, used in option array in 'type' key
|
10 |
+
* @return string
|
11 |
+
*/
|
12 |
+
abstract public function get_type();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Overwrite this method to enqueue scripts and styles
|
16 |
+
*
|
17 |
+
* @param string $id
|
18 |
+
* @param array $option
|
19 |
+
* @param array $values Options values (in db format, returned from get_value_from_input())
|
20 |
+
* @param array $data
|
21 |
+
* @param bool Return true to call this method again on the next enqueue,
|
22 |
+
* if you have some functionality in it that depends on option parameters.
|
23 |
+
* By default this method is called only once for performance reasons.
|
24 |
+
*/
|
25 |
+
abstract protected function _enqueue_static($id, $option, $values, $data);
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Generate html
|
29 |
+
* @param array $containers array('option_id' => array(), ...)
|
30 |
+
* - Options arrays are merged with _get_defaults()
|
31 |
+
* - All options are 100% only current container type, no need to check if ($option['type'] === $this->get_type())
|
32 |
+
* - Are sent multiple options instead of one, because tabs (and maybe other feature containers)
|
33 |
+
* can't be rendered separately (only as a collection).
|
34 |
+
* Instead of having render_option() for those that can be rendered separately,
|
35 |
+
* and render_options() for those like tabs, was decided to make a compromise,
|
36 |
+
* only one method that always will receive an array of options,
|
37 |
+
* instead of two methods when things may become confuse and complicated.
|
38 |
+
* @param array $values Options values (in db format, returned from get_value_from_input())
|
39 |
+
* @param array $data {id_prefix => '...', name_prefix => '...'}
|
40 |
+
* @return string HTML
|
41 |
+
* @internal
|
42 |
+
*/
|
43 |
+
abstract protected function _render($containers, $values, $data);
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Default option array
|
47 |
+
*
|
48 |
+
* This makes possible a container option array to have required only two parameters:
|
49 |
+
* array('type' => '...', 'options' => array(...))
|
50 |
+
* Other parameters are merged with the array returned by this method.
|
51 |
+
*
|
52 |
+
* @return array
|
53 |
+
*
|
54 |
+
* array(
|
55 |
+
* 'type' => '...',
|
56 |
+
* ...
|
57 |
+
* 'options' => array(...),
|
58 |
+
* )
|
59 |
+
* @internal
|
60 |
+
*/
|
61 |
+
abstract protected function _get_defaults();
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Prevent execute enqueue multiple times
|
65 |
+
* @var bool
|
66 |
+
*/
|
67 |
+
private $static_enqueued = false;
|
68 |
+
|
69 |
+
final public function __construct()
|
70 |
+
{
|
71 |
+
// does nothing at the moment, but maybe in the future will do something
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @param FW_Access_Key $access_key
|
76 |
+
* @internal
|
77 |
+
* This must be called right after an instance of container type has been created
|
78 |
+
* and was added to the registered array
|
79 |
+
*/
|
80 |
+
final public function _call_init($access_key)
|
81 |
+
{
|
82 |
+
if ($access_key->get_key() !== 'fw_backend') {
|
83 |
+
trigger_error('Method call not allowed', E_USER_ERROR);
|
84 |
+
}
|
85 |
+
|
86 |
+
if (method_exists($this, '_init')) {
|
87 |
+
$this->_init();
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Fixes and prepare defaults
|
93 |
+
*
|
94 |
+
* @param string $id
|
95 |
+
* @param array $option
|
96 |
+
* @param array $data
|
97 |
+
* @return array
|
98 |
+
*/
|
99 |
+
private function prepare($id, &$option, &$data)
|
100 |
+
{
|
101 |
+
$data = array_merge(
|
102 |
+
array(
|
103 |
+
'id_prefix' => fw()->backend->get_options_id_attr_prefix(), // attribute id prefix
|
104 |
+
'name_prefix' => fw()->backend->get_options_name_attr_prefix(), // attribute name prefix
|
105 |
+
),
|
106 |
+
$data
|
107 |
+
);
|
108 |
+
|
109 |
+
$option = array_merge(
|
110 |
+
$this->get_defaults(),
|
111 |
+
$option,
|
112 |
+
array(
|
113 |
+
'type' => $this->get_type(),
|
114 |
+
)
|
115 |
+
);
|
116 |
+
|
117 |
+
if (!isset($option['attr'])) {
|
118 |
+
$option['attr'] = array();
|
119 |
+
}
|
120 |
+
|
121 |
+
if (!isset($option['title'])) {
|
122 |
+
$option['title'] = fw_id_to_title($id);
|
123 |
+
}
|
124 |
+
|
125 |
+
$option['attr']['class'] = 'fw-container fw-container-type-'. $option['type'] .(
|
126 |
+
isset($option['attr']['class'])
|
127 |
+
? ' '. $option['attr']['class']
|
128 |
+
: ''
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Generate html
|
134 |
+
* @param array $options array('container_id' => array(...container option...))
|
135 |
+
* @param array $values Options values (in db format, returned from get_value_from_input())
|
136 |
+
* @param array $data {'id_prefix' => '...', 'name_prefix' => '...'}
|
137 |
+
* @return string HTML
|
138 |
+
*/
|
139 |
+
final public function render($options, $values = array(), $data = array())
|
140 |
+
{
|
141 |
+
$containers = array();
|
142 |
+
|
143 |
+
foreach ($options as $id => &$option) {
|
144 |
+
if (
|
145 |
+
!isset($option['options'])
|
146 |
+
||
|
147 |
+
!isset($option['type'])
|
148 |
+
||
|
149 |
+
$option['type'] !== $this->get_type()
|
150 |
+
) {
|
151 |
+
continue;
|
152 |
+
}
|
153 |
+
|
154 |
+
$this->prepare($id, $option, $data);
|
155 |
+
|
156 |
+
$this->enqueue_static($id, $option, $data);
|
157 |
+
|
158 |
+
$containers[$id] = &$option;
|
159 |
+
}
|
160 |
+
|
161 |
+
return $this->_render($containers, $values, $data);
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Enqueue container type scripts and styles
|
166 |
+
*
|
167 |
+
* All parameters are optional and will be populated with defaults
|
168 |
+
*
|
169 |
+
* @param string $id
|
170 |
+
* @param array $option
|
171 |
+
* @param array $values Options values (in db format, returned from get_value_from_input())
|
172 |
+
* @param array $data
|
173 |
+
* @return bool
|
174 |
+
*/
|
175 |
+
final public function enqueue_static($id = '', $option = array(), $values = array(), $data = array())
|
176 |
+
{
|
177 |
+
if (
|
178 |
+
!doing_action('admin_enqueue_scripts')
|
179 |
+
&&
|
180 |
+
!did_action('admin_enqueue_scripts')
|
181 |
+
) {
|
182 |
+
/**
|
183 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
184 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
185 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
186 |
+
*/
|
187 |
+
return;
|
188 |
+
}
|
189 |
+
|
190 |
+
if ($this->static_enqueued) {
|
191 |
+
return false;
|
192 |
+
}
|
193 |
+
|
194 |
+
$this->prepare($id, $option, $data);
|
195 |
+
|
196 |
+
$call_next_time = $this->_enqueue_static($id, $option, $values, $data);
|
197 |
+
|
198 |
+
$this->static_enqueued = !$call_next_time;
|
199 |
+
|
200 |
+
return $call_next_time;
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Default option array
|
205 |
+
*
|
206 |
+
* @return array
|
207 |
+
* 'type' => '...'
|
208 |
+
* 'title' => '...'
|
209 |
+
* 'attr' => array(...)
|
210 |
+
*/
|
211 |
+
final public function get_defaults()
|
212 |
+
{
|
213 |
+
$option = $this->_get_defaults();
|
214 |
+
|
215 |
+
$option['type'] = $this->get_type();
|
216 |
+
|
217 |
+
return $option;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Use this method to register a new container type
|
222 |
+
* @param string|FW_Container_Type $container_type_class
|
223 |
+
*/
|
224 |
+
final public static function register($container_type_class) {
|
225 |
+
static $registration_access_key = null;
|
226 |
+
|
227 |
+
if ($registration_access_key === null) {
|
228 |
+
$registration_access_key = new FW_Access_Key('fw_container_type');
|
229 |
+
}
|
230 |
+
|
231 |
+
fw()->backend->_register_container_type($registration_access_key, $container_type_class);
|
232 |
+
}
|
233 |
+
}
|
framework/core/extends/class-fw-extension.php
CHANGED
@@ -1,514 +1,514 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* All framework extensions should extend this
|
5 |
-
*/
|
6 |
-
abstract class FW_Extension
|
7 |
-
{
|
8 |
-
/**
|
9 |
-
* Called after all extensions instances was created
|
10 |
-
* @internal
|
11 |
-
*/
|
12 |
-
abstract protected function _init();
|
13 |
-
|
14 |
-
/** @var FW_Extension_Manifest */
|
15 |
-
public $manifest;
|
16 |
-
|
17 |
-
/** @var string Key used in FW_Cache to store data about extensions */
|
18 |
-
private static $cache_key = 'fw_ext';
|
19 |
-
|
20 |
-
/** @var FW_Access_Key */
|
21 |
-
private static $access_key;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Extension name, equal to directory name
|
25 |
-
* @var string
|
26 |
-
*/
|
27 |
-
private $name;
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Parent extension instance
|
31 |
-
* @var FW_Extension|null
|
32 |
-
*/
|
33 |
-
private $parent;
|
34 |
-
|
35 |
-
/**
|
36 |
-
* @var string
|
37 |
-
*/
|
38 |
-
private $rel_path;
|
39 |
-
|
40 |
-
/**
|
41 |
-
* @var string
|
42 |
-
*/
|
43 |
-
private $path;
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @var string
|
47 |
-
*/
|
48 |
-
private $uri;
|
49 |
-
|
50 |
-
/**
|
51 |
-
* On what directory depth is the extension
|
52 |
-
*
|
53 |
-
* 1 - Root extension
|
54 |
-
* 2 - Their children
|
55 |
-
* 3 - Sub children
|
56 |
-
* ...
|
57 |
-
*
|
58 |
-
* @var int
|
59 |
-
*/
|
60 |
-
private $depth;
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Locations where the extension can look for customizations (overwrite views, options; extend config)
|
64 |
-
* @var array {'/path' => 'https://uri.to/path'}
|
65 |
-
*/
|
66 |
-
private $customizations_locations;
|
67 |
-
|
68 |
-
final public function __construct($data)
|
69 |
-
{
|
70 |
-
if (!self::$access_key) {
|
71 |
-
self::$access_key = new FW_Access_Key('extension');
|
72 |
-
}
|
73 |
-
|
74 |
-
$this->rel_path = $data['rel_path'];
|
75 |
-
$this->path = $data['path'];
|
76 |
-
$this->uri = $data['uri'];
|
77 |
-
$this->parent = $data['parent'];
|
78 |
-
$this->depth = $data['depth'];
|
79 |
-
$this->customizations_locations = $data['customizations_locations'];
|
80 |
-
$this->manifest = _FW_Component_Extensions::_get_manifest($this->get_name(), self::$access_key);
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* Cache key for this extension
|
85 |
-
*
|
86 |
-
* Usage:
|
87 |
-
* FW_Cache::get( $this->get_cache_key('/some/key') )
|
88 |
-
*
|
89 |
-
* @param string $sub_key
|
90 |
-
* @return string
|
91 |
-
*/
|
92 |
-
final public function get_cache_key($sub_key = '')
|
93 |
-
{
|
94 |
-
return self::$cache_key .'/'. $this->get_name() . $sub_key;
|
95 |
-
}
|
96 |
-
|
97 |
-
/**
|
98 |
-
* @param string $name View file name (without .php) from <extension>/views directory
|
99 |
-
* @param array $view_variables Keys will be variables names within view
|
100 |
-
* @param bool $return In some cases, for memory saving reasons, you can disable the use of output buffering
|
101 |
-
* @return string HTML
|
102 |
-
*/
|
103 |
-
final protected function render_view($name, $view_variables = array(), $return = true)
|
104 |
-
{
|
105 |
-
$full_path = $this->locate_path('/views/'. $name .'.php');
|
106 |
-
|
107 |
-
if (!$full_path) {
|
108 |
-
trigger_error('Extension view not found: '. $name, E_USER_WARNING);
|
109 |
-
return;
|
110 |
-
}
|
111 |
-
|
112 |
-
return fw_render_view($full_path, $view_variables, $return);
|
113 |
-
}
|
114 |
-
|
115 |
-
/**
|
116 |
-
* @internal
|
117 |
-
* @param FW_Access_Key $access_key
|
118 |
-
* @return mixed
|
119 |
-
*/
|
120 |
-
final public function _call_init($access_key)
|
121 |
-
{
|
122 |
-
if ($access_key->get_key() !== 'fw_extensions') {
|
123 |
-
trigger_error(__METHOD__ .' denied', E_USER_ERROR);
|
124 |
-
}
|
125 |
-
|
126 |
-
return $this->_init();
|
127 |
-
}
|
128 |
-
|
129 |
-
/**
|
130 |
-
* Tree array with all sub extensions
|
131 |
-
* @return array
|
132 |
-
*/
|
133 |
-
final public function get_tree()
|
134 |
-
{
|
135 |
-
return fw()->extensions->_get_extension_tree(self::$access_key, $this->get_name());
|
136 |
-
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* @param string $rel_path '/views/test.php'
|
140 |
-
* @return false|string '/var/www/.../extensions/<extension>/views/test.php'
|
141 |
-
*/
|
142 |
-
final public function locate_path($rel_path)
|
143 |
-
{
|
144 |
-
$locations = $this->customizations_locations;
|
145 |
-
$locations[$this->get_path()] = $this->get_uri();
|
146 |
-
|
147 |
-
foreach ($locations as $path => $uri) {
|
148 |
-
if (file_exists($path . $rel_path)) {
|
149 |
-
return $path . $rel_path;
|
150 |
-
}
|
151 |
-
}
|
152 |
-
|
153 |
-
return false;
|
154 |
-
}
|
155 |
-
|
156 |
-
/**
|
157 |
-
* @param string $rel_path E.g. '/static/js/scripts.js'
|
158 |
-
* @return string URI E.g. 'http: //wordpress.com/.../extensions/<extension>/static/js/scripts.js'
|
159 |
-
*/
|
160 |
-
final public function locate_URI($rel_path)
|
161 |
-
{
|
162 |
-
$locations = $this->customizations_locations;
|
163 |
-
$locations[$this->get_path()] = $this->get_uri();
|
164 |
-
|
165 |
-
foreach ($locations as $path => $uri) {
|
166 |
-
if (file_exists($path . $rel_path)) {
|
167 |
-
return $uri . $rel_path;
|
168 |
-
}
|
169 |
-
}
|
170 |
-
|
171 |
-
return false;
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* @return FW_Extension|null if has no parent extension
|
176 |
-
*/
|
177 |
-
final public function get_parent()
|
178 |
-
{
|
179 |
-
return $this->parent;
|
180 |
-
}
|
181 |
-
|
182 |
-
/**
|
183 |
-
* @return string
|
184 |
-
*/
|
185 |
-
final public function get_name()
|
186 |
-
{
|
187 |
-
if ($this->name === null) {
|
188 |
-
$this->name = basename($this->path);
|
189 |
-
}
|
190 |
-
|
191 |
-
return $this->name;
|
192 |
-
}
|
193 |
-
|
194 |
-
/**
|
195 |
-
* @return string
|
196 |
-
* @deprecated
|
197 |
-
*/
|
198 |
-
final public function get_declared_source()
|
199 |
-
{
|
200 |
-
return 'deprecated';
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* @param string $append_rel_path E.g. '/includes/something.php'
|
205 |
-
* @return string
|
206 |
-
* @deprecated
|
207 |
-
*/
|
208 |
-
final public function get_declared_path($append_rel_path = '')
|
209 |
-
{
|
210 |
-
return $this->get_path($append_rel_path);
|
211 |
-
}
|
212 |
-
|
213 |
-
final public function get_path($append_rel_path = '')
|
214 |
-
{
|
215 |
-
return $this->path . $append_rel_path;
|
216 |
-
}
|
217 |
-
|
218 |
-
/**
|
219 |
-
* @param string $append_rel_path E.g. '/includes/foo/bar/script.js'
|
220 |
-
* @return string
|
221 |
-
* @deprecated
|
222 |
-
*/
|
223 |
-
final public function get_declared_URI($append_rel_path = '')
|
224 |
-
{
|
225 |
-
return $this->get_uri($append_rel_path);
|
226 |
-
}
|
227 |
-
|
228 |
-
/**
|
229 |
-
* @param string $append_rel_path E.g. '/includes/foo/bar/script.js'
|
230 |
-
* @return string
|
231 |
-
*/
|
232 |
-
final public function get_uri($append_rel_path = '')
|
233 |
-
{
|
234 |
-
return $this->uri . $append_rel_path;
|
235 |
-
}
|
236 |
-
|
237 |
-
/**
|
238 |
-
* @param string $child_extension_name
|
239 |
-
* @return FW_Extension|null
|
240 |
-
*/
|
241 |
-
final public function get_child($child_extension_name)
|
242 |
-
{
|
243 |
-
$active_tree = $this->get_tree();
|
244 |
-
|
245 |
-
if (isset($active_tree[$child_extension_name])) {
|
246 |
-
return fw()->extensions->get($child_extension_name);
|
247 |
-
} else {
|
248 |
-
return null;
|
249 |
-
}
|
250 |
-
}
|
251 |
-
|
252 |
-
/**
|
253 |
-
* Return all child extensions
|
254 |
-
* Only one level, not all sub levels
|
255 |
-
* @return FW_Extension[]
|
256 |
-
*/
|
257 |
-
final public function get_children()
|
258 |
-
{
|
259 |
-
$active_tree = $this->get_tree();
|
260 |
-
|
261 |
-
$result = array();
|
262 |
-
|
263 |
-
foreach ($active_tree as $extension_name => &$sub_extensions) {
|
264 |
-
$result[$extension_name] = fw()->extensions->get($extension_name);
|
265 |
-
}
|
266 |
-
unset($sub_extensions);
|
267 |
-
|
268 |
-
return $result;
|
269 |
-
}
|
270 |
-
|
271 |
-
/**
|
272 |
-
* Return config key value, or entire config array
|
273 |
-
* Config array is merged from child configs
|
274 |
-
* @param string|null $key Multi key format accepted: 'a/b/c'
|
275 |
-
* @return mixed|null
|
276 |
-
*/
|
277 |
-
final public function get_config($key = null)
|
278 |
-
{
|
279 |
-
$cache_key = $this->get_cache_key() .'/config';
|
280 |
-
|
281 |
-
try {
|
282 |
-
$config = FW_Cache::get($cache_key);
|
283 |
-
} catch (FW_Cache_Not_Found_Exception $e) {
|
284 |
-
$config = array();
|
285 |
-
|
286 |
-
$locations = $this->customizations_locations;
|
287 |
-
$locations[$this->get_path()] = $this->get_uri();
|
288 |
-
|
289 |
-
foreach (array_reverse($locations) as $path => $uri) {
|
290 |
-
$config_path = $path .'/config.php';
|
291 |
-
|
292 |
-
if (file_exists($config_path)) {
|
293 |
-
$variables = fw_get_variables_from_file($config_path, array('cfg' => null));
|
294 |
-
|
295 |
-
if (!empty($variables['cfg'])) {
|
296 |
-
$config = array_merge($config, $variables['cfg']);
|
297 |
-
unset($variables);
|
298 |
-
}
|
299 |
-
}
|
300 |
-
}
|
301 |
-
|
302 |
-
FW_Cache::set($cache_key, $config);
|
303 |
-
}
|
304 |
-
|
305 |
-
return $key === null ? $config : fw_call( fw_akg( $key, $config ) );
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* Return array with options from specified name/path
|
310 |
-
* @param string $name Examples: 'framework', 'posts/portfolio'
|
311 |
-
* @param array $variables These will be available in options file (like variables for view)
|
312 |
-
* @return array
|
313 |
-
*/
|
314 |
-
final public function get_options($name, array $variables = array())
|
315 |
-
{
|
316 |
-
try {
|
317 |
-
return FW_Cache::get($cache_key = $this->get_cache_key('/options/'. $name));
|
318 |
-
} catch (FW_Cache_Not_Found_Exception $e) {
|
319 |
-
if ($path = $this->locate_path('/options/'. $name .'.php')) {
|
320 |
-
$variables = fw_get_variables_from_file($path, array('options' => array()), $variables);
|
321 |
-
} else {
|
322 |
-
$variables = array('options' => array());
|
323 |
-
}
|
324 |
-
|
325 |
-
FW_Cache::set($cache_key, $variables['options']);
|
326 |
-
|
327 |
-
return $variables['options'];
|
328 |
-
}
|
329 |
-
}
|
330 |
-
|
331 |
-
final public function get_settings_options()
|
332 |
-
{
|
333 |
-
try {
|
334 |
-
return FW_Cache::get($cache_key = $this->get_cache_key('/settings_options'));
|
335 |
-
} catch (FW_Cache_Not_Found_Exception $e) {
|
336 |
-
if (file_exists($path = $this->get_path('/settings-options.php'))) {
|
337 |
-
$variables = fw_get_variables_from_file($path, array('options' => array()));
|
338 |
-
} else {
|
339 |
-
$variables = array('options' => array());
|
340 |
-
}
|
341 |
-
|
342 |
-
FW_Cache::set($cache_key, $variables['options']);
|
343 |
-
|
344 |
-
return $variables['options'];
|
345 |
-
}
|
346 |
-
}
|
347 |
-
|
348 |
-
/**
|
349 |
-
* @since 2.6.9
|
350 |
-
*/
|
351 |
-
final public function get_rendered_docs() {
|
352 |
-
$docs_path = $this->get_path('/readme.md.php');
|
353 |
-
|
354 |
-
if (! file_exists($docs_path)) {
|
355 |
-
return false;
|
356 |
-
}
|
357 |
-
|
358 |
-
return fw()->backend->get_markdown_parser()->text(
|
359 |
-
/**
|
360 |
-
* TODO: Perhaps send here some values in order to make extension docs
|
361 |
-
* more dynamic???
|
362 |
-
*/
|
363 |
-
fw_render_view($docs_path, array())
|
364 |
-
);
|
365 |
-
}
|
366 |
-
|
367 |
-
/**
|
368 |
-
* Get extension's settings option value from the database
|
369 |
-
*
|
370 |
-
* @param string|null $option_id
|
371 |
-
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
372 |
-
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
373 |
-
*
|
374 |
-
* @return mixed|null
|
375 |
-
*/
|
376 |
-
final public function get_db_settings_option( $option_id = null, $default_value = null, $get_original_value = null ) {
|
377 |
-
return fw_get_db_ext_settings_option( $this->get_name(), $option_id, $default_value, $get_original_value );
|
378 |
-
}
|
379 |
-
|
380 |
-
/**
|
381 |
-
* Set extension's setting option value in database
|
382 |
-
*
|
383 |
-
* @param string|null $option_id
|
384 |
-
* @param mixed $value
|
385 |
-
*/
|
386 |
-
final public function set_db_settings_option( $option_id = null, $value ) {
|
387 |
-
fw_set_db_ext_settings_option( $this->get_name(), $option_id, $value );
|
388 |
-
}
|
389 |
-
|
390 |
-
/**
|
391 |
-
* Get extension's data from the database
|
392 |
-
*
|
393 |
-
* @param string|null $multi_key The key of the data you want to get. null - all data
|
394 |
-
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
395 |
-
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
396 |
-
*
|
397 |
-
* @return mixed|null
|
398 |
-
*/
|
399 |
-
final public function get_db_data( $multi_key = null, $default_value = null, $get_original_value = null ) {
|
400 |
-
return fw_get_db_extension_data( $this->get_name(), $multi_key, $default_value, $get_original_value );
|
401 |
-
}
|
402 |
-
|
403 |
-
/**
|
404 |
-
* Set some extension's data in database
|
405 |
-
*
|
406 |
-
* @param string|null $multi_key The key of the data you want to set. null - all data
|
407 |
-
* @param mixed $value
|
408 |
-
*/
|
409 |
-
final public function set_db_data( $multi_key = null, $value ) {
|
410 |
-
fw_set_db_extension_data( $this->get_name(), $multi_key, $value );
|
411 |
-
}
|
412 |
-
|
413 |
-
/**
|
414 |
-
* Get extension's data from user meta
|
415 |
-
*
|
416 |
-
* @param int $user_id
|
417 |
-
* @param string|null $keys
|
418 |
-
*
|
419 |
-
* @return mixed|null
|
420 |
-
*/
|
421 |
-
final public function get_user_data( $user_id, $keys = null ) {
|
422 |
-
return fw_get_db_extension_user_data($user_id, $this->get_name(), $keys);
|
423 |
-
}
|
424 |
-
|
425 |
-
/**
|
426 |
-
* et some extension's data in user meta
|
427 |
-
*
|
428 |
-
* @param int $user_id
|
429 |
-
* @param mixed $value
|
430 |
-
* @param string|null $keys
|
431 |
-
*
|
432 |
-
* @return bool|int
|
433 |
-
*/
|
434 |
-
final public function set_user_data( $user_id, $value, $keys = null ) {
|
435 |
-
return fw_set_db_extension_user_data($user_id, $this->get_name(), $value, $keys);
|
436 |
-
}
|
437 |
-
|
438 |
-
final public function get_post_options($post_type)
|
439 |
-
{
|
440 |
-
return $this->get_options('posts/'. $post_type);
|
441 |
-
}
|
442 |
-
|
443 |
-
final public function get_taxonomy_options($taxonomy)
|
444 |
-
{
|
445 |
-
return $this->get_options('taxonomies/'. $taxonomy);
|
446 |
-
}
|
447 |
-
|
448 |
-
/**
|
449 |
-
* @param string $name File name without extension, located in <extension>/static/js/$name.js
|
450 |
-
* @return string URI
|
451 |
-
*/
|
452 |
-
final public function locate_js_URI($name)
|
453 |
-
{
|
454 |
-
return $this->locate_URI('/static/js/'. $name .'.js');
|
455 |
-
}
|
456 |
-
|
457 |
-
/**
|
458 |
-
* @param string $name File name without extension, located in <extension>/static/js/$name.js
|
459 |
-
* @return string URI
|
460 |
-
*/
|
461 |
-
final public function locate_css_URI($name)
|
462 |
-
{
|
463 |
-
return $this->locate_URI('/static/css/'. $name .'.css');
|
464 |
-
}
|
465 |
-
|
466 |
-
/**
|
467 |
-
* @param string $name File name without extension, located in <extension>/views/$name.php
|
468 |
-
* @return false|string
|
469 |
-
*/
|
470 |
-
final public function locate_view_path($name)
|
471 |
-
{
|
472 |
-
return $this->locate_path('/views/'. $name .'.php');
|
473 |
-
}
|
474 |
-
|
475 |
-
final public function get_depth()
|
476 |
-
{
|
477 |
-
return $this->depth;
|
478 |
-
}
|
479 |
-
|
480 |
-
final public function get_customizations_locations()
|
481 |
-
{
|
482 |
-
return $this->customizations_locations;
|
483 |
-
}
|
484 |
-
|
485 |
-
final public function get_rel_path()
|
486 |
-
{
|
487 |
-
return $this->rel_path;
|
488 |
-
}
|
489 |
-
|
490 |
-
/**
|
491 |
-
* Check if child extension is valid
|
492 |
-
*
|
493 |
-
* Used for special cases when an extension requires its child extensions to extend some special class
|
494 |
-
*
|
495 |
-
* @param FW_Extension $child_extension_instance
|
496 |
-
* @return bool
|
497 |
-
* @internal
|
498 |
-
*/
|
499 |
-
public function _child_extension_is_valid($child_extension_instance)
|
500 |
-
{
|
501 |
-
return is_subclass_of($child_extension_instance, 'FW_Extension');
|
502 |
-
}
|
503 |
-
|
504 |
-
/**
|
505 |
-
* Get link to the page created by this extension in dashboard
|
506 |
-
* (Used on the extensions page)
|
507 |
-
* @internal
|
508 |
-
* @return string
|
509 |
-
*/
|
510 |
-
public function _get_link()
|
511 |
-
{
|
512 |
-
return false;
|
513 |
-
}
|
514 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* All framework extensions should extend this
|
5 |
+
*/
|
6 |
+
abstract class FW_Extension
|
7 |
+
{
|
8 |
+
/**
|
9 |
+
* Called after all extensions instances was created
|
10 |
+
* @internal
|
11 |
+
*/
|
12 |
+
abstract protected function _init();
|
13 |
+
|
14 |
+
/** @var FW_Extension_Manifest */
|
15 |
+
public $manifest;
|
16 |
+
|
17 |
+
/** @var string Key used in FW_Cache to store data about extensions */
|
18 |
+
private static $cache_key = 'fw_ext';
|
19 |
+
|
20 |
+
/** @var FW_Access_Key */
|
21 |
+
private static $access_key;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Extension name, equal to directory name
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
+
private $name;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Parent extension instance
|
31 |
+
* @var FW_Extension|null
|
32 |
+
*/
|
33 |
+
private $parent;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var string
|
37 |
+
*/
|
38 |
+
private $rel_path;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @var string
|
42 |
+
*/
|
43 |
+
private $path;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @var string
|
47 |
+
*/
|
48 |
+
private $uri;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* On what directory depth is the extension
|
52 |
+
*
|
53 |
+
* 1 - Root extension
|
54 |
+
* 2 - Their children
|
55 |
+
* 3 - Sub children
|
56 |
+
* ...
|
57 |
+
*
|
58 |
+
* @var int
|
59 |
+
*/
|
60 |
+
private $depth;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Locations where the extension can look for customizations (overwrite views, options; extend config)
|
64 |
+
* @var array {'/path' => 'https://uri.to/path'}
|
65 |
+
*/
|
66 |
+
private $customizations_locations;
|
67 |
+
|
68 |
+
final public function __construct($data)
|
69 |
+
{
|
70 |
+
if (!self::$access_key) {
|
71 |
+
self::$access_key = new FW_Access_Key('extension');
|
72 |
+
}
|
73 |
+
|
74 |
+
$this->rel_path = $data['rel_path'];
|
75 |
+
$this->path = $data['path'];
|
76 |
+
$this->uri = $data['uri'];
|
77 |
+
$this->parent = $data['parent'];
|
78 |
+
$this->depth = $data['depth'];
|
79 |
+
$this->customizations_locations = $data['customizations_locations'];
|
80 |
+
$this->manifest = _FW_Component_Extensions::_get_manifest($this->get_name(), self::$access_key);
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Cache key for this extension
|
85 |
+
*
|
86 |
+
* Usage:
|
87 |
+
* FW_Cache::get( $this->get_cache_key('/some/key') )
|
88 |
+
*
|
89 |
+
* @param string $sub_key
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
final public function get_cache_key($sub_key = '')
|
93 |
+
{
|
94 |
+
return self::$cache_key .'/'. $this->get_name() . $sub_key;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* @param string $name View file name (without .php) from <extension>/views directory
|
99 |
+
* @param array $view_variables Keys will be variables names within view
|
100 |
+
* @param bool $return In some cases, for memory saving reasons, you can disable the use of output buffering
|
101 |
+
* @return string HTML
|
102 |
+
*/
|
103 |
+
final protected function render_view($name, $view_variables = array(), $return = true)
|
104 |
+
{
|
105 |
+
$full_path = $this->locate_path('/views/'. $name .'.php');
|
106 |
+
|
107 |
+
if (!$full_path) {
|
108 |
+
trigger_error('Extension view not found: '. $name, E_USER_WARNING);
|
109 |
+
return;
|
110 |
+
}
|
111 |
+
|
112 |
+
return fw_render_view($full_path, $view_variables, $return);
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @internal
|
117 |
+
* @param FW_Access_Key $access_key
|
118 |
+
* @return mixed
|
119 |
+
*/
|
120 |
+
final public function _call_init($access_key)
|
121 |
+
{
|
122 |
+
if ($access_key->get_key() !== 'fw_extensions') {
|
123 |
+
trigger_error(__METHOD__ .' denied', E_USER_ERROR);
|
124 |
+
}
|
125 |
+
|
126 |
+
return $this->_init();
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Tree array with all sub extensions
|
131 |
+
* @return array
|
132 |
+
*/
|
133 |
+
final public function get_tree()
|
134 |
+
{
|
135 |
+
return fw()->extensions->_get_extension_tree(self::$access_key, $this->get_name());
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* @param string $rel_path '/views/test.php'
|
140 |
+
* @return false|string '/var/www/.../extensions/<extension>/views/test.php'
|
141 |
+
*/
|
142 |
+
final public function locate_path($rel_path)
|
143 |
+
{
|
144 |
+
$locations = $this->customizations_locations;
|
145 |
+
$locations[$this->get_path()] = $this->get_uri();
|
146 |
+
|
147 |
+
foreach ($locations as $path => $uri) {
|
148 |
+
if (file_exists($path . $rel_path)) {
|
149 |
+
return $path . $rel_path;
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
return false;
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* @param string $rel_path E.g. '/static/js/scripts.js'
|
158 |
+
* @return string URI E.g. 'http: //wordpress.com/.../extensions/<extension>/static/js/scripts.js'
|
159 |
+
*/
|
160 |
+
final public function locate_URI($rel_path)
|
161 |
+
{
|
162 |
+
$locations = $this->customizations_locations;
|
163 |
+
$locations[$this->get_path()] = $this->get_uri();
|
164 |
+
|
165 |
+
foreach ($locations as $path => $uri) {
|
166 |
+
if (file_exists($path . $rel_path)) {
|
167 |
+
return $uri . $rel_path;
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
return false;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* @return FW_Extension|null if has no parent extension
|
176 |
+
*/
|
177 |
+
final public function get_parent()
|
178 |
+
{
|
179 |
+
return $this->parent;
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* @return string
|
184 |
+
*/
|
185 |
+
final public function get_name()
|
186 |
+
{
|
187 |
+
if ($this->name === null) {
|
188 |
+
$this->name = basename($this->path);
|
189 |
+
}
|
190 |
+
|
191 |
+
return $this->name;
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* @return string
|
196 |
+
* @deprecated
|
197 |
+
*/
|
198 |
+
final public function get_declared_source()
|
199 |
+
{
|
200 |
+
return 'deprecated';
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* @param string $append_rel_path E.g. '/includes/something.php'
|
205 |
+
* @return string
|
206 |
+
* @deprecated
|
207 |
+
*/
|
208 |
+
final public function get_declared_path($append_rel_path = '')
|
209 |
+
{
|
210 |
+
return $this->get_path($append_rel_path);
|
211 |
+
}
|
212 |
+
|
213 |
+
final public function get_path($append_rel_path = '')
|
214 |
+
{
|
215 |
+
return $this->path . $append_rel_path;
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* @param string $append_rel_path E.g. '/includes/foo/bar/script.js'
|
220 |
+
* @return string
|
221 |
+
* @deprecated
|
222 |
+
*/
|
223 |
+
final public function get_declared_URI($append_rel_path = '')
|
224 |
+
{
|
225 |
+
return $this->get_uri($append_rel_path);
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* @param string $append_rel_path E.g. '/includes/foo/bar/script.js'
|
230 |
+
* @return string
|
231 |
+
*/
|
232 |
+
final public function get_uri($append_rel_path = '')
|
233 |
+
{
|
234 |
+
return $this->uri . $append_rel_path;
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* @param string $child_extension_name
|
239 |
+
* @return FW_Extension|null
|
240 |
+
*/
|
241 |
+
final public function get_child($child_extension_name)
|
242 |
+
{
|
243 |
+
$active_tree = $this->get_tree();
|
244 |
+
|
245 |
+
if (isset($active_tree[$child_extension_name])) {
|
246 |
+
return fw()->extensions->get($child_extension_name);
|
247 |
+
} else {
|
248 |
+
return null;
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Return all child extensions
|
254 |
+
* Only one level, not all sub levels
|
255 |
+
* @return FW_Extension[]
|
256 |
+
*/
|
257 |
+
final public function get_children()
|
258 |
+
{
|
259 |
+
$active_tree = $this->get_tree();
|
260 |
+
|
261 |
+
$result = array();
|
262 |
+
|
263 |
+
foreach ($active_tree as $extension_name => &$sub_extensions) {
|
264 |
+
$result[$extension_name] = fw()->extensions->get($extension_name);
|
265 |
+
}
|
266 |
+
unset($sub_extensions);
|
267 |
+
|
268 |
+
return $result;
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Return config key value, or entire config array
|
273 |
+
* Config array is merged from child configs
|
274 |
+
* @param string|null $key Multi key format accepted: 'a/b/c'
|
275 |
+
* @return mixed|null
|
276 |
+
*/
|
277 |
+
final public function get_config($key = null)
|
278 |
+
{
|
279 |
+
$cache_key = $this->get_cache_key() .'/config';
|
280 |
+
|
281 |
+
try {
|
282 |
+
$config = FW_Cache::get($cache_key);
|
283 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
284 |
+
$config = array();
|
285 |
+
|
286 |
+
$locations = $this->customizations_locations;
|
287 |
+
$locations[$this->get_path()] = $this->get_uri();
|
288 |
+
|
289 |
+
foreach (array_reverse($locations) as $path => $uri) {
|
290 |
+
$config_path = $path .'/config.php';
|
291 |
+
|
292 |
+
if (file_exists($config_path)) {
|
293 |
+
$variables = fw_get_variables_from_file($config_path, array('cfg' => null));
|
294 |
+
|
295 |
+
if (!empty($variables['cfg'])) {
|
296 |
+
$config = array_merge($config, $variables['cfg']);
|
297 |
+
unset($variables);
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
FW_Cache::set($cache_key, $config);
|
303 |
+
}
|
304 |
+
|
305 |
+
return $key === null ? $config : fw_call( fw_akg( $key, $config ) );
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Return array with options from specified name/path
|
310 |
+
* @param string $name Examples: 'framework', 'posts/portfolio'
|
311 |
+
* @param array $variables These will be available in options file (like variables for view)
|
312 |
+
* @return array
|
313 |
+
*/
|
314 |
+
final public function get_options($name, array $variables = array())
|
315 |
+
{
|
316 |
+
try {
|
317 |
+
return FW_Cache::get($cache_key = $this->get_cache_key('/options/'. $name));
|
318 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
319 |
+
if ($path = $this->locate_path('/options/'. $name .'.php')) {
|
320 |
+
$variables = fw_get_variables_from_file($path, array('options' => array()), $variables);
|
321 |
+
} else {
|
322 |
+
$variables = array('options' => array());
|
323 |
+
}
|
324 |
+
|
325 |
+
FW_Cache::set($cache_key, $variables['options']);
|
326 |
+
|
327 |
+
return $variables['options'];
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
final public function get_settings_options()
|
332 |
+
{
|
333 |
+
try {
|
334 |
+
return FW_Cache::get($cache_key = $this->get_cache_key('/settings_options'));
|
335 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
336 |
+
if (file_exists($path = $this->get_path('/settings-options.php'))) {
|
337 |
+
$variables = fw_get_variables_from_file($path, array('options' => array()));
|
338 |
+
} else {
|
339 |
+
$variables = array('options' => array());
|
340 |
+
}
|
341 |
+
|
342 |
+
FW_Cache::set($cache_key, $variables['options']);
|
343 |
+
|
344 |
+
return $variables['options'];
|
345 |
+
}
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* @since 2.6.9
|
350 |
+
*/
|
351 |
+
final public function get_rendered_docs() {
|
352 |
+
$docs_path = $this->get_path('/readme.md.php');
|
353 |
+
|
354 |
+
if (! file_exists($docs_path)) {
|
355 |
+
return false;
|
356 |
+
}
|
357 |
+
|
358 |
+
return fw()->backend->get_markdown_parser()->text(
|
359 |
+
/**
|
360 |
+
* TODO: Perhaps send here some values in order to make extension docs
|
361 |
+
* more dynamic???
|
362 |
+
*/
|
363 |
+
fw_render_view($docs_path, array())
|
364 |
+
);
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Get extension's settings option value from the database
|
369 |
+
*
|
370 |
+
* @param string|null $option_id
|
371 |
+
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
372 |
+
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
373 |
+
*
|
374 |
+
* @return mixed|null
|
375 |
+
*/
|
376 |
+
final public function get_db_settings_option( $option_id = null, $default_value = null, $get_original_value = null ) {
|
377 |
+
return fw_get_db_ext_settings_option( $this->get_name(), $option_id, $default_value, $get_original_value );
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* Set extension's setting option value in database
|
382 |
+
*
|
383 |
+
* @param string|null $option_id
|
384 |
+
* @param mixed $value
|
385 |
+
*/
|
386 |
+
final public function set_db_settings_option( $option_id = null, $value ) {
|
387 |
+
fw_set_db_ext_settings_option( $this->get_name(), $option_id, $value );
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* Get extension's data from the database
|
392 |
+
*
|
393 |
+
* @param string|null $multi_key The key of the data you want to get. null - all data
|
394 |
+
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
395 |
+
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
396 |
+
*
|
397 |
+
* @return mixed|null
|
398 |
+
*/
|
399 |
+
final public function get_db_data( $multi_key = null, $default_value = null, $get_original_value = null ) {
|
400 |
+
return fw_get_db_extension_data( $this->get_name(), $multi_key, $default_value, $get_original_value );
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Set some extension's data in database
|
405 |
+
*
|
406 |
+
* @param string|null $multi_key The key of the data you want to set. null - all data
|
407 |
+
* @param mixed $value
|
408 |
+
*/
|
409 |
+
final public function set_db_data( $multi_key = null, $value ) {
|
410 |
+
fw_set_db_extension_data( $this->get_name(), $multi_key, $value );
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Get extension's data from user meta
|
415 |
+
*
|
416 |
+
* @param int $user_id
|
417 |
+
* @param string|null $keys
|
418 |
+
*
|
419 |
+
* @return mixed|null
|
420 |
+
*/
|
421 |
+
final public function get_user_data( $user_id, $keys = null ) {
|
422 |
+
return fw_get_db_extension_user_data($user_id, $this->get_name(), $keys);
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* et some extension's data in user meta
|
427 |
+
*
|
428 |
+
* @param int $user_id
|
429 |
+
* @param mixed $value
|
430 |
+
* @param string|null $keys
|
431 |
+
*
|
432 |
+
* @return bool|int
|
433 |
+
*/
|
434 |
+
final public function set_user_data( $user_id, $value, $keys = null ) {
|
435 |
+
return fw_set_db_extension_user_data($user_id, $this->get_name(), $value, $keys);
|
436 |
+
}
|
437 |
+
|
438 |
+
final public function get_post_options($post_type)
|
439 |
+
{
|
440 |
+
return $this->get_options('posts/'. $post_type);
|
441 |
+
}
|
442 |
+
|
443 |
+
final public function get_taxonomy_options($taxonomy)
|
444 |
+
{
|
445 |
+
return $this->get_options('taxonomies/'. $taxonomy);
|
446 |
+
}
|
447 |
+
|
448 |
+
/**
|
449 |
+
* @param string $name File name without extension, located in <extension>/static/js/$name.js
|
450 |
+
* @return string URI
|
451 |
+
*/
|
452 |
+
final public function locate_js_URI($name)
|
453 |
+
{
|
454 |
+
return $this->locate_URI('/static/js/'. $name .'.js');
|
455 |
+
}
|
456 |
+
|
457 |
+
/**
|
458 |
+
* @param string $name File name without extension, located in <extension>/static/js/$name.js
|
459 |
+
* @return string URI
|
460 |
+
*/
|
461 |
+
final public function locate_css_URI($name)
|
462 |
+
{
|
463 |
+
return $this->locate_URI('/static/css/'. $name .'.css');
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* @param string $name File name without extension, located in <extension>/views/$name.php
|
468 |
+
* @return false|string
|
469 |
+
*/
|
470 |
+
final public function locate_view_path($name)
|
471 |
+
{
|
472 |
+
return $this->locate_path('/views/'. $name .'.php');
|
473 |
+
}
|
474 |
+
|
475 |
+
final public function get_depth()
|
476 |
+
{
|
477 |
+
return $this->depth;
|
478 |
+
}
|
479 |
+
|
480 |
+
final public function get_customizations_locations()
|
481 |
+
{
|
482 |
+
return $this->customizations_locations;
|
483 |
+
}
|
484 |
+
|
485 |
+
final public function get_rel_path()
|
486 |
+
{
|
487 |
+
return $this->rel_path;
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Check if child extension is valid
|
492 |
+
*
|
493 |
+
* Used for special cases when an extension requires its child extensions to extend some special class
|
494 |
+
*
|
495 |
+
* @param FW_Extension $child_extension_instance
|
496 |
+
* @return bool
|
497 |
+
* @internal
|
498 |
+
*/
|
499 |
+
public function _child_extension_is_valid($child_extension_instance)
|
500 |
+
{
|
501 |
+
return is_subclass_of($child_extension_instance, 'FW_Extension');
|
502 |
+
}
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Get link to the page created by this extension in dashboard
|
506 |
+
* (Used on the extensions page)
|
507 |
+
* @internal
|
508 |
+
* @return string
|
509 |
+
*/
|
510 |
+
public function _get_link()
|
511 |
+
{
|
512 |
+
return false;
|
513 |
+
}
|
514 |
+
}
|
framework/core/extends/class-fw-option-type.php
CHANGED
@@ -1,453 +1,465 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Backend option
|
5 |
-
*/
|
6 |
-
abstract class FW_Option_Type
|
7 |
-
{
|
8 |
-
/**
|
9 |
-
* @var FW_Access_Key
|
10 |
-
*/
|
11 |
-
private static $access_key;
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Option's unique type, used in option array in 'type' key
|
15 |
-
* @return string
|
16 |
-
*/
|
17 |
-
abstract public function get_type();
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Overwrite this method to enqueue scripts and styles
|
21 |
-
*
|
22 |
-
* This method would be abstract but was added after the framework release,
|
23 |
-
* and to prevent fatal errors from new option types created by users we can't make it abstract.
|
24 |
-
*
|
25 |
-
* @param string $id
|
26 |
-
* @param array $option
|
27 |
-
* @param array $data
|
28 |
-
* @param bool Return true to call this method again on the next enqueue,
|
29 |
-
* if you have some functionality in it that depends on option parameters.
|
30 |
-
* By default this method is called only once for performance reasons.
|
31 |
-
*/
|
32 |
-
protected function _enqueue_static($id, $option, $data) {}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Generate html
|
36 |
-
* @param string $id
|
37 |
-
* @param array $option Option array merged with _get_defaults()
|
38 |
-
* @param array $data {value => _get_value_from_input(), id_prefix => ..., name_prefix => ...}
|
39 |
-
* @return string HTML
|
40 |
-
* @internal
|
41 |
-
*/
|
42 |
-
abstract protected function _render($id, $option, $data);
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Extract correct value that will be stored in db or $option['value'] from raw form input value
|
46 |
-
* If input value is empty, will be returned $option['value']
|
47 |
-
* This method should be named get_db_value($form_input_value, $option)
|
48 |
-
* @param array $option Option array merged with _get_defaults()
|
49 |
-
* @param array|string|null $input_value
|
50 |
-
* @return string|array|int|bool Correct value
|
51 |
-
* @internal
|
52 |
-
*/
|
53 |
-
abstract protected function _get_value_from_input($option, $input_value);
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Default option array
|
57 |
-
*
|
58 |
-
* This makes possible an option array to have required only one parameter: array('type' => '...')
|
59 |
-
* Other parameters are merged with the array returned by this method.
|
60 |
-
*
|
61 |
-
* @return array
|
62 |
-
*
|
63 |
-
* array(
|
64 |
-
* 'value' => '',
|
65 |
-
* ...
|
66 |
-
* )
|
67 |
-
* @internal
|
68 |
-
*/
|
69 |
-
abstract protected function _get_defaults();
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Put data for to be accessed in JavaScript for each option type instance
|
73 |
-
*/
|
74 |
-
protected function _get_data_for_js($id, $option, $data = array()) {
|
75 |
-
return array(
|
76 |
-
'option' => $option
|
77 |
-
);
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
*
|
82 |
-
*
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
*
|
109 |
-
*
|
110 |
-
*
|
111 |
-
*/
|
112 |
-
final public function
|
113 |
-
{
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
'
|
214 |
-
$
|
215 |
-
|
216 |
-
);
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
*
|
343 |
-
*
|
344 |
-
*
|
345 |
-
* @
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
*
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
*
|
365 |
-
*
|
366 |
-
* @param
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
*
|
403 |
-
*
|
404 |
-
*
|
405 |
-
* @
|
406 |
-
* @
|
407 |
-
* @
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
protected function
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Backend option
|
5 |
+
*/
|
6 |
+
abstract class FW_Option_Type
|
7 |
+
{
|
8 |
+
/**
|
9 |
+
* @var FW_Access_Key
|
10 |
+
*/
|
11 |
+
private static $access_key;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Option's unique type, used in option array in 'type' key
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
abstract public function get_type();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Overwrite this method to enqueue scripts and styles
|
21 |
+
*
|
22 |
+
* This method would be abstract but was added after the framework release,
|
23 |
+
* and to prevent fatal errors from new option types created by users we can't make it abstract.
|
24 |
+
*
|
25 |
+
* @param string $id
|
26 |
+
* @param array $option
|
27 |
+
* @param array $data
|
28 |
+
* @param bool Return true to call this method again on the next enqueue,
|
29 |
+
* if you have some functionality in it that depends on option parameters.
|
30 |
+
* By default this method is called only once for performance reasons.
|
31 |
+
*/
|
32 |
+
protected function _enqueue_static($id, $option, $data) {}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Generate html
|
36 |
+
* @param string $id
|
37 |
+
* @param array $option Option array merged with _get_defaults()
|
38 |
+
* @param array $data {value => _get_value_from_input(), id_prefix => ..., name_prefix => ...}
|
39 |
+
* @return string HTML
|
40 |
+
* @internal
|
41 |
+
*/
|
42 |
+
abstract protected function _render($id, $option, $data);
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Extract correct value that will be stored in db or $option['value'] from raw form input value
|
46 |
+
* If input value is empty, will be returned $option['value']
|
47 |
+
* This method should be named get_db_value($form_input_value, $option)
|
48 |
+
* @param array $option Option array merged with _get_defaults()
|
49 |
+
* @param array|string|null $input_value
|
50 |
+
* @return string|array|int|bool Correct value
|
51 |
+
* @internal
|
52 |
+
*/
|
53 |
+
abstract protected function _get_value_from_input($option, $input_value);
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Default option array
|
57 |
+
*
|
58 |
+
* This makes possible an option array to have required only one parameter: array('type' => '...')
|
59 |
+
* Other parameters are merged with the array returned by this method.
|
60 |
+
*
|
61 |
+
* @return array
|
62 |
+
*
|
63 |
+
* array(
|
64 |
+
* 'value' => '',
|
65 |
+
* ...
|
66 |
+
* )
|
67 |
+
* @internal
|
68 |
+
*/
|
69 |
+
abstract protected function _get_defaults();
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Put data for to be accessed in JavaScript for each option type instance
|
73 |
+
*/
|
74 |
+
protected function _get_data_for_js($id, $option, $data = array()) {
|
75 |
+
return array(
|
76 |
+
'option' => $option
|
77 |
+
);
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* An option type can decide which design to use by default when rendering
|
82 |
+
* itself.
|
83 |
+
*
|
84 |
+
* @return
|
85 |
+
* null - will use whatever is passed based on the context
|
86 |
+
* string - will use that particular design
|
87 |
+
*/
|
88 |
+
public function get_forced_render_design() {
|
89 |
+
return null;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Prevent execute enqueue multiple times
|
94 |
+
* @var bool
|
95 |
+
*/
|
96 |
+
private $static_enqueued = false;
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Used as prefix for attribute id="{prefix}{option-id}"
|
100 |
+
* @return string
|
101 |
+
*/
|
102 |
+
final public static function get_default_id_prefix()
|
103 |
+
{
|
104 |
+
return fw()->backend->get_options_id_attr_prefix();
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Used as default prefix for attribute name="prefix[name]"
|
109 |
+
* Cannot contain [], it is used for $_POST[ self::get_default_name_prefix() ]
|
110 |
+
* @return string
|
111 |
+
*/
|
112 |
+
final public static function get_default_name_prefix()
|
113 |
+
{
|
114 |
+
return fw()->backend->get_options_name_attr_prefix();
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* @param FW_Access_Key $access_key
|
119 |
+
* @internal
|
120 |
+
* This must be called right after an instance of option type has been created
|
121 |
+
* and was added to the registered array, so it is available through
|
122 |
+
* fw()->backend->option_type($this->get_type())
|
123 |
+
*/
|
124 |
+
final public function _call_init($access_key)
|
125 |
+
{
|
126 |
+
if ($access_key->get_key() !== 'fw_backend') {
|
127 |
+
trigger_error('Method call not allowed', E_USER_ERROR);
|
128 |
+
}
|
129 |
+
|
130 |
+
if (method_exists($this, '_init')) {
|
131 |
+
$this->_init();
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
public function __construct() {
|
136 |
+
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Fixes and prepare defaults
|
141 |
+
*
|
142 |
+
* @param string $id
|
143 |
+
* @param array $option
|
144 |
+
* @param array $data
|
145 |
+
* @return array
|
146 |
+
*
|
147 |
+
* @since 2.5.10
|
148 |
+
*/
|
149 |
+
public function prepare(&$id, &$option, &$data)
|
150 |
+
{
|
151 |
+
$data = array_merge(
|
152 |
+
array(
|
153 |
+
'id_prefix' => self::get_default_id_prefix(), // attribute id prefix
|
154 |
+
'name_prefix' => self::get_default_name_prefix(), // attribute name prefix
|
155 |
+
),
|
156 |
+
$data
|
157 |
+
);
|
158 |
+
|
159 |
+
$defaults = $this->get_defaults();
|
160 |
+
$merge_attr = !empty($option['attr']) && !empty($defaults['attr']);
|
161 |
+
|
162 |
+
$option = array_merge($defaults, $option, array(
|
163 |
+
'type' => $this->get_type()
|
164 |
+
));
|
165 |
+
|
166 |
+
if ($merge_attr) {
|
167 |
+
$option['attr'] = array_merge($defaults['attr'], $option['attr']);
|
168 |
+
}
|
169 |
+
|
170 |
+
if (!isset($data['value'])) {
|
171 |
+
// if no input value, use default
|
172 |
+
$data['value'] = $option['value'];
|
173 |
+
}
|
174 |
+
|
175 |
+
if (!isset($option['attr'])) {
|
176 |
+
$option['attr'] = array();
|
177 |
+
}
|
178 |
+
|
179 |
+
$option['attr']['name'] = $data['name_prefix'] .'['. $id .']';
|
180 |
+
$option['attr']['id'] = $data['id_prefix'] . $id;
|
181 |
+
$option['attr']['class'] = 'fw-option fw-option-type-'. $option['type'] .(
|
182 |
+
isset($option['attr']['class'])
|
183 |
+
? ' '. $option['attr']['class']
|
184 |
+
: ''
|
185 |
+
);
|
186 |
+
$option['attr']['value'] = is_array($option['value']) ? '' : $option['value'];
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Remove some blacklisted attributes
|
190 |
+
* They should be added only by the render method
|
191 |
+
*/
|
192 |
+
{
|
193 |
+
unset($option['attr']['type']);
|
194 |
+
unset($option['attr']['checked']);
|
195 |
+
unset($option['attr']['selected']);
|
196 |
+
}
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Generate option's html from option array
|
201 |
+
* @param string $id
|
202 |
+
* @param array $option
|
203 |
+
* @param array $data {value => $this->get_value_from_input()}
|
204 |
+
* @return string HTML
|
205 |
+
*/
|
206 |
+
final public function render($id, $option, $data = array())
|
207 |
+
{
|
208 |
+
$this->prepare($id, $option, $data);
|
209 |
+
|
210 |
+
$this->enqueue_static($id, $option, $data);
|
211 |
+
|
212 |
+
$html_attributes = array(
|
213 |
+
'class' => 'fw-backend-option-descriptor',
|
214 |
+
'data-fw-option-id' => $id,
|
215 |
+
'data-fw-option-type' => $option['type']
|
216 |
+
);
|
217 |
+
|
218 |
+
$data_for_js = $this->_get_data_for_js($id, $option, $data);
|
219 |
+
|
220 |
+
if ($data_for_js) {
|
221 |
+
$html_attributes['data-fw-for-js'] = json_encode($data_for_js);
|
222 |
+
}
|
223 |
+
|
224 |
+
return fw_html_tag(
|
225 |
+
'div',
|
226 |
+
$html_attributes,
|
227 |
+
$this->_render( $id, $this->load_callbacks( $option ), $data )
|
228 |
+
);
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Enqueue option type scripts and styles
|
233 |
+
*
|
234 |
+
* All parameters are optional and will be populated with defaults
|
235 |
+
* @param string $id
|
236 |
+
* @param array $option
|
237 |
+
* @param array $data
|
238 |
+
* @return bool
|
239 |
+
*/
|
240 |
+
final public function enqueue_static($id = '', $option = array(), $data = array())
|
241 |
+
{
|
242 |
+
if ($this->static_enqueued) {
|
243 |
+
return false;
|
244 |
+
}
|
245 |
+
|
246 |
+
if (
|
247 |
+
!doing_action('admin_enqueue_scripts')
|
248 |
+
&&
|
249 |
+
!did_action('admin_enqueue_scripts')
|
250 |
+
) {
|
251 |
+
/**
|
252 |
+
* Do not wp_enqueue/register_...() because at this point not all handles has been registered
|
253 |
+
* and maybe they are used in dependencies in handles that are going to be enqueued.
|
254 |
+
* So as a result some handles will not be equeued because of not registered dependecies.
|
255 |
+
*/
|
256 |
+
return;
|
257 |
+
}
|
258 |
+
|
259 |
+
{
|
260 |
+
static $option_types_static_enqueued = false;
|
261 |
+
|
262 |
+
if (!$option_types_static_enqueued) {
|
263 |
+
wp_enqueue_style(
|
264 |
+
'fw-option-types',
|
265 |
+
fw_get_framework_directory_uri('/static/css/option-types.css'),
|
266 |
+
array('fw', 'qtip'),
|
267 |
+
fw()->manifest->get_version()
|
268 |
+
);
|
269 |
+
wp_enqueue_script(
|
270 |
+
'fw-option-types',
|
271 |
+
fw_get_framework_directory_uri('/static/js/option-types.js'),
|
272 |
+
array('fw-events', 'qtip', 'fw-reactive-options'),
|
273 |
+
fw()->manifest->get_version(),
|
274 |
+
true
|
275 |
+
);
|
276 |
+
|
277 |
+
$option_types_static_enqueued = true;
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
$this->prepare($id, $option, $data);
|
282 |
+
|
283 |
+
$call_next_time = $this->_enqueue_static($id, $option, $data);
|
284 |
+
|
285 |
+
$this->static_enqueued = !$call_next_time;
|
286 |
+
|
287 |
+
return $call_next_time;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Extract correct value that will be stored in db or $option['value'] from raw form input value
|
292 |
+
* If input value is empty, will be returned $option['value']
|
293 |
+
* This method should be named get_db_value($form_input_value, $option)
|
294 |
+
* @param array $option
|
295 |
+
* @param mixed|null $input_value Option's value from $_POST or elsewhere. If is null, it means it does not exists
|
296 |
+
* @return array|string
|
297 |
+
*/
|
298 |
+
final public function get_value_from_input($option, $input_value)
|
299 |
+
{
|
300 |
+
$option = array_merge(
|
301 |
+
$this->get_defaults(),
|
302 |
+
$option,
|
303 |
+
array(
|
304 |
+
'type' => $this->get_type()
|
305 |
+
)
|
306 |
+
);
|
307 |
+
|
308 |
+
return $this->_get_value_from_input( $this->load_callbacks( $option ), $input_value);
|
309 |
+
}
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Default option array
|
313 |
+
*
|
314 |
+
* This makes possible an option array to have required only one parameter: array('type' => '...')
|
315 |
+
* Other parameters are merged with array returned from this method
|
316 |
+
*
|
317 |
+
* @param string Multikey. Since 2.6.9
|
318 |
+
* @return array
|
319 |
+
*/
|
320 |
+
final public function get_defaults($key = null)
|
321 |
+
{
|
322 |
+
$option = $this->_get_defaults();
|
323 |
+
|
324 |
+
$option['type'] = $this->get_type();
|
325 |
+
|
326 |
+
if (!array_key_exists('value', $option)) {
|
327 |
+
FW_Flash_Messages::add(
|
328 |
+
'fw-option-type-no-default-value',
|
329 |
+
sprintf(__('Option type %s has no default value', 'fw'), $this->get_type()),
|
330 |
+
'warning'
|
331 |
+
);
|
332 |
+
|
333 |
+
$option['value'] = array();
|
334 |
+
}
|
335 |
+
|
336 |
+
return is_string($key) ? fw_akg($key, $option) : $option;
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Exist 3 types of options widths:
|
341 |
+
* - auto (float left real width of the option (minimal) )
|
342 |
+
* - fixed (inputs, select, textarea, and others - they have same width)
|
343 |
+
* - full (100% . eg. html option should expand to maximum width)
|
344 |
+
* Options can override this method to return another value
|
345 |
+
* @return bool
|
346 |
+
* @internal
|
347 |
+
*/
|
348 |
+
public function _get_backend_width_type()
|
349 |
+
{
|
350 |
+
return 'fixed';
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
* a general purpose 'label' => false | true from options.php
|
355 |
+
* @return bool | string
|
356 |
+
*
|
357 |
+
* @since 2.7.1
|
358 |
+
*/
|
359 |
+
public function _default_label($id, $option) {
|
360 |
+
return fw_id_to_title($id);
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* Use this method to register a new option type
|
365 |
+
*
|
366 |
+
* @param string|FW_Option_Type $option_type_class
|
367 |
+
*/
|
368 |
+
final public static function register( $option_type_class, $type = null ) {
|
369 |
+
fw()->backend->_register_option_type( self::get_access_key(), $option_type_class, $type );
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* If the option is composed of more options (added by user) which values are stored in database
|
374 |
+
* the option must call fw_db_option_storage_load() for each sub-option
|
375 |
+
* because some of them may have configured the save to be done in separate place (post meta, wp option, etc.)
|
376 |
+
* @param string $id
|
377 |
+
* @param array $option
|
378 |
+
* @param mixed $value
|
379 |
+
* @param array $params
|
380 |
+
* @return mixed
|
381 |
+
* @since 2.5.0
|
382 |
+
*/
|
383 |
+
final public function storage_load($id, array $option, $value, array $params = array()) {
|
384 |
+
if ( // do not check !empty($option['fw-storage']) because this param can be set in option defaults
|
385 |
+
$this->get_type() === $option['type']
|
386 |
+
&&
|
387 |
+
($option = array_merge($this->get_defaults(), $option))
|
388 |
+
) {
|
389 |
+
if (is_null($value)) {
|
390 |
+
$value = fw()->backend->option_type($option['type'])->get_value_from_input($option, $value);
|
391 |
+
}
|
392 |
+
|
393 |
+
return $this->_storage_load($id, $option, $value, $params);
|
394 |
+
} else {
|
395 |
+
return $value;
|
396 |
+
}
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* @see storage_load()
|
401 |
+
* @param string $id
|
402 |
+
* @param array $option
|
403 |
+
* @param mixed $value
|
404 |
+
* @param array $params
|
405 |
+
* @return mixed
|
406 |
+
* @since 2.5.0
|
407 |
+
* @internal
|
408 |
+
*/
|
409 |
+
protected function _storage_load($id, array $option, $value, array $params) {
|
410 |
+
return fw_db_option_storage_load($id, $option, $value, $params);
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* If the option is composed of more options (added by user) which values are stored in database
|
415 |
+
* the option must call fw_db_option_storage_save() for each sub-option
|
416 |
+
* because some of them may have configured the save to be done in separate place (post meta, wp option, etc.)
|
417 |
+
* @param string $id
|
418 |
+
* @param array $option
|
419 |
+
* @param mixed $value
|
420 |
+
* @param array $params
|
421 |
+
* @return mixed
|
422 |
+
* @since 2.5.0
|
423 |
+
*/
|
424 |
+
final public function storage_save($id, array $option, $value, array $params = array()) {
|
425 |
+
if ( // do not check !empty($option['fw-storage']) because this param can be set in option defaults
|
426 |
+
$this->get_type() === $option['type']
|
427 |
+
&&
|
428 |
+
($option = array_merge($this->get_defaults(), $option))
|
429 |
+
) {
|
430 |
+
return $this->_storage_save($id, $option, $value, $params);
|
431 |
+
} else {
|
432 |
+
return $value;
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* @see storage_save()
|
438 |
+
* @param string $id
|
439 |
+
* @param array $option
|
440 |
+
* @param mixed $value
|
441 |
+
* @param array $params
|
442 |
+
* @return mixed
|
443 |
+
* @since 2.5.0
|
444 |
+
* @internal
|
445 |
+
*/
|
446 |
+
protected function _storage_save($id, array $option, $value, array $params) {
|
447 |
+
return fw_db_option_storage_save($id, $option, $value, $params);
|
448 |
+
}
|
449 |
+
|
450 |
+
private static function get_access_key() {
|
451 |
+
if ( self::$access_key === null ) {
|
452 |
+
self::$access_key = new FW_Access_Key( 'fw_option_type' );
|
453 |
+
}
|
454 |
+
|
455 |
+
return self::$access_key;
|
456 |
+
}
|
457 |
+
|
458 |
+
protected function load_callbacks( $data ) {
|
459 |
+
if ( ! is_array( $data ) ) {
|
460 |
+
return $data;
|
461 |
+
}
|
462 |
+
|
463 |
+
return array_map( 'fw_call', $data );
|
464 |
+
}
|
465 |
+
}
|
framework/core/extends/interface-fw-option-handler.php
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @deprecated since 2.5.0
|
5 |
-
* Will be removed soon https://github.com/ThemeFuse/Unyson/issues/1937
|
6 |
-
*/
|
7 |
-
interface FW_Option_Handler
|
8 |
-
{
|
9 |
-
function get_option_value($option_id, $option, $data = array());
|
10 |
-
|
11 |
-
function save_option_value($option_id, $option, $value, $data = array());
|
12 |
-
}
|
13 |
-
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @deprecated since 2.5.0
|
5 |
+
* Will be removed soon https://github.com/ThemeFuse/Unyson/issues/1937
|
6 |
+
*/
|
7 |
+
interface FW_Option_Handler
|
8 |
+
{
|
9 |
+
function get_option_value($option_id, $option, $data = array());
|
10 |
+
|
11 |
+
function save_option_value($option_id, $option, $value, $data = array());
|
12 |
+
}
|
13 |
+
|
framework/extensions/blog/class-fw-extension-blog.php
CHANGED
@@ -1,90 +1,90 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
class FW_Extension_Blog extends FW_Extension {
|
6 |
-
private $post_type = 'post';
|
7 |
-
|
8 |
-
/**
|
9 |
-
* @internal
|
10 |
-
*/
|
11 |
-
public function _init() {
|
12 |
-
if ( is_admin() ) {
|
13 |
-
add_action( 'admin_menu', array( $this, '_admin_action_rename_post_menu' ) );
|
14 |
-
add_action( 'init', array( $this, '_admin_action_change_post_labels' ), 999 );
|
15 |
-
} else {
|
16 |
-
add_action( 'init', array( $this, '_theme_action_change_post_labels' ), 999 );
|
17 |
-
}
|
18 |
-
}
|
19 |
-
|
20 |
-
/**
|
21 |
-
* Changes the labels value od the posts type: post from Post to Blog Post
|
22 |
-
* @internal
|
23 |
-
*/
|
24 |
-
public function _theme_action_change_post_labels() {
|
25 |
-
global $wp_post_types;
|
26 |
-
$p = $this->post_type;
|
27 |
-
|
28 |
-
// Someone has changed this post type, always check for that!
|
29 |
-
if ( empty ( $wp_post_types[ $p ] )
|
30 |
-
or ! is_object( $wp_post_types[ $p ] )
|
31 |
-
or empty ( $wp_post_types[ $p ]->labels )
|
32 |
-
) {
|
33 |
-
return;
|
34 |
-
}
|
35 |
-
|
36 |
-
$wp_post_types[ $p ]->labels->name = __( 'Blog', 'fw' );
|
37 |
-
$wp_post_types[ $p ]->labels->singular_name = __( 'Blog', 'fw' );
|
38 |
-
$wp_post_types[ $p ]->labels->add_new = __( 'Add blog post', 'fw' );
|
39 |
-
$wp_post_types[ $p ]->labels->add_new_item = __( 'Add new blog post', 'fw' );
|
40 |
-
$wp_post_types[ $p ]->labels->all_items = __( 'All blog posts', 'fw' );
|
41 |
-
$wp_post_types[ $p ]->labels->edit_item = __( 'Edit blog post', 'fw' );
|
42 |
-
$wp_post_types[ $p ]->labels->name_admin_bar = __( 'Blog Post', 'fw' );
|
43 |
-
$wp_post_types[ $p ]->labels->menu_name = __( 'Blog Post', 'fw' );
|
44 |
-
$wp_post_types[ $p ]->labels->new_item = __( 'New blog post', 'fw' );
|
45 |
-
$wp_post_types[ $p ]->labels->not_found = __( 'No blog posts found', 'fw' );
|
46 |
-
$wp_post_types[ $p ]->labels->not_found_in_trash = __( 'No blog posts found in trash', 'fw' );
|
47 |
-
$wp_post_types[ $p ]->labels->search_items = __( 'Search blog posts', 'fw' );
|
48 |
-
$wp_post_types[ $p ]->labels->view_item = __( 'View blog post', 'fw' );
|
49 |
-
}
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Changes the labels value od the posts type: post from Post to Blog Post
|
53 |
-
* @internal
|
54 |
-
*/
|
55 |
-
public function _admin_action_change_post_labels() {
|
56 |
-
global $wp_post_types, $wp_taxonomies;
|
57 |
-
$p = $this->post_type;
|
58 |
-
|
59 |
-
// Someone has changed this post type, always check for that!
|
60 |
-
if ( empty ( $wp_post_types[ $p ] )
|
61 |
-
or ! is_object( $wp_post_types[ $p ] )
|
62 |
-
or empty ( $wp_post_types[ $p ]->labels )
|
63 |
-
) {
|
64 |
-
return;
|
65 |
-
}
|
66 |
-
|
67 |
-
$wp_post_types[ $p ]->labels->name = __( 'Blog Posts', 'fw' );
|
68 |
-
|
69 |
-
if ( empty ( $wp_taxonomies['category'] )
|
70 |
-
or ! is_object( $wp_taxonomies['category'] )
|
71 |
-
or empty ( $wp_taxonomies['category']->labels )
|
72 |
-
) {
|
73 |
-
return;
|
74 |
-
}
|
75 |
-
|
76 |
-
$wp_taxonomies['category']->labels->name = __( 'Blog Categories', 'fw' );
|
77 |
-
}
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Changes the name in admin menu from Post to Blog Post
|
81 |
-
* @internal
|
82 |
-
*/
|
83 |
-
public function _admin_action_rename_post_menu() {
|
84 |
-
global $menu;
|
85 |
-
|
86 |
-
if ( isset( $menu[5] ) ) {
|
87 |
-
$menu[5][0] = __( 'Blog Posts', 'fw' );
|
88 |
-
}
|
89 |
-
}
|
90 |
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
class FW_Extension_Blog extends FW_Extension {
|
6 |
+
private $post_type = 'post';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @internal
|
10 |
+
*/
|
11 |
+
public function _init() {
|
12 |
+
if ( is_admin() ) {
|
13 |
+
add_action( 'admin_menu', array( $this, '_admin_action_rename_post_menu' ) );
|
14 |
+
add_action( 'init', array( $this, '_admin_action_change_post_labels' ), 999 );
|
15 |
+
} else {
|
16 |
+
add_action( 'init', array( $this, '_theme_action_change_post_labels' ), 999 );
|
17 |
+
}
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Changes the labels value od the posts type: post from Post to Blog Post
|
22 |
+
* @internal
|
23 |
+
*/
|
24 |
+
public function _theme_action_change_post_labels() {
|
25 |
+
global $wp_post_types;
|
26 |
+
$p = $this->post_type;
|
27 |
+
|
28 |
+
// Someone has changed this post type, always check for that!
|
29 |
+
if ( empty ( $wp_post_types[ $p ] )
|
30 |
+
or ! is_object( $wp_post_types[ $p ] )
|
31 |
+
or empty ( $wp_post_types[ $p ]->labels )
|
32 |
+
) {
|
33 |
+
return;
|
34 |
+
}
|
35 |
+
|
36 |
+
$wp_post_types[ $p ]->labels->name = __( 'Blog', 'fw' );
|
37 |
+
$wp_post_types[ $p ]->labels->singular_name = __( 'Blog', 'fw' );
|
38 |
+
$wp_post_types[ $p ]->labels->add_new = __( 'Add blog post', 'fw' );
|
39 |
+
$wp_post_types[ $p ]->labels->add_new_item = __( 'Add new blog post', 'fw' );
|
40 |
+
$wp_post_types[ $p ]->labels->all_items = __( 'All blog posts', 'fw' );
|
41 |
+
$wp_post_types[ $p ]->labels->edit_item = __( 'Edit blog post', 'fw' );
|
42 |
+
$wp_post_types[ $p ]->labels->name_admin_bar = __( 'Blog Post', 'fw' );
|
43 |
+
$wp_post_types[ $p ]->labels->menu_name = __( 'Blog Post', 'fw' );
|
44 |
+
$wp_post_types[ $p ]->labels->new_item = __( 'New blog post', 'fw' );
|
45 |
+
$wp_post_types[ $p ]->labels->not_found = __( 'No blog posts found', 'fw' );
|
46 |
+
$wp_post_types[ $p ]->labels->not_found_in_trash = __( 'No blog posts found in trash', 'fw' );
|
47 |
+
$wp_post_types[ $p ]->labels->search_items = __( 'Search blog posts', 'fw' );
|
48 |
+
$wp_post_types[ $p ]->labels->view_item = __( 'View blog post', 'fw' );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Changes the labels value od the posts type: post from Post to Blog Post
|
53 |
+
* @internal
|
54 |
+
*/
|
55 |
+
public function _admin_action_change_post_labels() {
|
56 |
+
global $wp_post_types, $wp_taxonomies;
|
57 |
+
$p = $this->post_type;
|
58 |
+
|
59 |
+
// Someone has changed this post type, always check for that!
|
60 |
+
if ( empty ( $wp_post_types[ $p ] )
|
61 |
+
or ! is_object( $wp_post_types[ $p ] )
|
62 |
+
or empty ( $wp_post_types[ $p ]->labels )
|
63 |
+
) {
|
64 |
+
return;
|
65 |
+
}
|
66 |
+
|
67 |
+
$wp_post_types[ $p ]->labels->name = __( 'Blog Posts', 'fw' );
|
68 |
+
|
69 |
+
if ( empty ( $wp_taxonomies['category'] )
|
70 |
+
or ! is_object( $wp_taxonomies['category'] )
|
71 |
+
or empty ( $wp_taxonomies['category']->labels )
|
72 |
+
) {
|
73 |
+
return;
|
74 |
+
}
|
75 |
+
|
76 |
+
$wp_taxonomies['category']->labels->name = __( 'Blog Categories', 'fw' );
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Changes the name in admin menu from Post to Blog Post
|
81 |
+
* @internal
|
82 |
+
*/
|
83 |
+
public function _admin_action_rename_post_menu() {
|
84 |
+
global $menu;
|
85 |
+
|
86 |
+
if ( isset( $menu[5] ) ) {
|
87 |
+
$menu[5][0] = __( 'Blog Posts', 'fw' );
|
88 |
+
}
|
89 |
+
}
|
90 |
}
|
framework/extensions/blog/manifest.php
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
$manifest = array();
|
6 |
-
|
7 |
-
$manifest['name'] = __( 'Blog Posts', 'fw' );
|
8 |
-
$manifest['description'] = __( 'Blog Posts', 'fw' );
|
9 |
-
$manifest['version'] = '1.0.2';
|
10 |
-
$manifest['display'] = false;
|
11 |
-
$manifest['standalone'] = true;
|
12 |
-
|
13 |
-
$manifest['github_update'] = 'ThemeFuse/Unyson-Blog-Extension';
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
$manifest = array();
|
6 |
+
|
7 |
+
$manifest['name'] = __( 'Blog Posts', 'fw' );
|
8 |
+
$manifest['description'] = __( 'Blog Posts', 'fw' );
|
9 |
+
$manifest['version'] = '1.0.2';
|
10 |
+
$manifest['display'] = false;
|
11 |
+
$manifest['standalone'] = true;
|
12 |
+
|
13 |
+
$manifest['github_update'] = 'ThemeFuse/Unyson-Blog-Extension';
|
framework/extensions/update/class-fw-extension-update.php
CHANGED
@@ -1,963 +1,1005 @@
|
|
1 |
-
<?php defined( 'FW' ) or die( 'Forbidden' );
|
2 |
-
|
3 |
-
require dirname( __FILE__ ) . '/includes/extends/class-fw-ext-update-service.php';
|
4 |
-
|
5 |
-
class FW_Extension_Update extends FW_Extension {
|
6 |
-
/**
|
7 |
-
* {@inheritdoc}
|
8 |
-
*/
|
9 |
-
public function _child_extension_is_valid( $child_extension_instance ) {
|
10 |
-
return is_subclass_of( $child_extension_instance, 'FW_Ext_Update_Service' );
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* File names to skip (do not delete or change) during the update process
|
15 |
-
* @var array
|
16 |
-
*/
|
17 |
-
private $skip_file_names = array( '.git' );
|
18 |
-
|
19 |
-
/**
|
20 |
-
* @internal
|
21 |
-
*/
|
22 |
-
protected function _init() {
|
23 |
-
|
24 |
-
if ( ! current_user_can( 'update_plugins' ) ) {
|
25 |
-
return false;
|
26 |
-
}
|
27 |
-
|
28 |
-
$this->add_actions();
|
29 |
-
$this->add_filters();
|
30 |
-
|
31 |
-
return true;
|
32 |
-
}
|
33 |
-
|
34 |
-
private function add_actions() {
|
35 |
-
|
36 |
-
add_action( '
|
37 |
-
add_action( '
|
38 |
-
|
39 |
-
|
40 |
-
add_action( '
|
41 |
-
add_action( 'update-core-custom_' . 'fw-update-
|
42 |
-
add_action( 'update-core-custom_' . 'fw-update-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
}
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
'
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
private function
|
132 |
-
$
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
)
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
$
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
)
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
if ( $
|
470 |
-
|
471 |
-
|
472 |
-
$downloaded_file_path,
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
);
|
524 |
-
}
|
525 |
-
|
526 |
-
return
|
527 |
-
}
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
$
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
}
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
$
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
);
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
)
|
752 |
-
}
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
);
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
{
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
$
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php defined( 'FW' ) or die( 'Forbidden' );
|
2 |
+
|
3 |
+
require dirname( __FILE__ ) . '/includes/extends/class-fw-ext-update-service.php';
|
4 |
+
|
5 |
+
class FW_Extension_Update extends FW_Extension {
|
6 |
+
/**
|
7 |
+
* {@inheritdoc}
|
8 |
+
*/
|
9 |
+
public function _child_extension_is_valid( $child_extension_instance ) {
|
10 |
+
return is_subclass_of( $child_extension_instance, 'FW_Ext_Update_Service' );
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* File names to skip (do not delete or change) during the update process
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
private $skip_file_names = array( '.git' );
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @internal
|
21 |
+
*/
|
22 |
+
protected function _init() {
|
23 |
+
|
24 |
+
if ( ! current_user_can( 'update_plugins' ) ) {
|
25 |
+
return false;
|
26 |
+
}
|
27 |
+
|
28 |
+
$this->add_actions();
|
29 |
+
$this->add_filters();
|
30 |
+
|
31 |
+
return true;
|
32 |
+
}
|
33 |
+
|
34 |
+
private function add_actions() {
|
35 |
+
|
36 |
+
add_action( 'admin_menu', array( $this, '_action_admin_menu' ) );
|
37 |
+
add_action( 'admin_notices', array( $this, '_action_admin_notices' ) );
|
38 |
+
add_action( 'network_admin_notices', array( $this, '_action_admin_notices' ) );
|
39 |
+
|
40 |
+
add_action( 'core_upgrade_preamble', array( $this, '_action_updates_page_footer' ) );
|
41 |
+
add_action( 'update-core-custom_' . 'fw-update-framework', array( $this, '_action_update_framework' ) );
|
42 |
+
add_action( 'update-core-custom_' . 'fw-update-theme', array( $this, '_action_update_theme' ) );
|
43 |
+
add_action( 'update-core-custom_' . 'fw-update-extensions', array( $this, '_action_update_extensions' ) );
|
44 |
+
}
|
45 |
+
|
46 |
+
private function add_filters() {
|
47 |
+
add_filter( 'wp_get_update_data', array( $this, '_filter_update_data' ), 10, 2 );
|
48 |
+
}
|
49 |
+
|
50 |
+
private function get_fixed_version( $version ) {
|
51 |
+
// remove from the beginning everything that is not a number: 'v1.2.3' -> '1.2.3', 'ver1.0.0' -> '1.0.0'
|
52 |
+
return preg_replace( '/^[^0-9]+/i', '', $version );
|
53 |
+
}
|
54 |
+
|
55 |
+
private function get_wp_fs_tmp_dir() {
|
56 |
+
return FW_WP_Filesystem::real_path_to_filesystem_path(
|
57 |
+
apply_filters( 'fw_tmp_dir', fw_fix_path( WP_CONTENT_DIR ) . '/tmp' )
|
58 |
+
);
|
59 |
+
}
|
60 |
+
|
61 |
+
public function _action_admin_menu() {
|
62 |
+
|
63 |
+
if ( ! is_multisite() || is_plugin_active_for_network( 'unyson/unyson.php' ) ) {
|
64 |
+
return;
|
65 |
+
}
|
66 |
+
|
67 |
+
add_submenu_page( 'admin.php', esc_html__( 'Unyson updates', 'fw' ), '', 'update_plugins', 'fw-update', array( $this, '_multisite_updates_page' ) );
|
68 |
+
}
|
69 |
+
|
70 |
+
public function _multisite_updates_page() {
|
71 |
+
if ( isset( $_GET['action'] ) && ! empty( $_POST ) ) {
|
72 |
+
if ( $_GET['action'] === 'fw-update-extensions' ) {
|
73 |
+
$this->_action_update_extensions();
|
74 |
+
} else {
|
75 |
+
$this->_action_update_theme();
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
$this->_action_updates_page_footer();
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @internal
|
84 |
+
*/
|
85 |
+
public function _action_updates_page_footer() {
|
86 |
+
|
87 |
+
$url = current_filter() == 'core_upgrade_preamble' ? 'update-core.php' : '?page=fw-update';
|
88 |
+
|
89 |
+
echo $this->render_view( 'updates-list', array(
|
90 |
+
'updates' => $this->get_updates( ! empty( $_GET['force-check'] ) ),
|
91 |
+
'form_action' => self_admin_url( $url )
|
92 |
+
) );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @internal
|
97 |
+
*/
|
98 |
+
public function _filter_update_data( $data, $titles ) {
|
99 |
+
$updates = $this->get_updates( ! empty( $_GET['force-check'] ) );
|
100 |
+
|
101 |
+
if ( $updates['framework'] && ! is_wp_error( $updates['framework'] ) ) {
|
102 |
+
++ $data['counts']['total'];
|
103 |
+
}
|
104 |
+
|
105 |
+
if ( $updates['theme'] && ! is_wp_error( $updates['theme'] ) ) {
|
106 |
+
++ $data['counts']['total'];
|
107 |
+
}
|
108 |
+
|
109 |
+
if ( ! empty( $updates['extensions'] ) ) {
|
110 |
+
foreach ( $updates['extensions'] as $ext_name => $ext_update ) {
|
111 |
+
if ( is_wp_error( $ext_update ) ) {
|
112 |
+
continue;
|
113 |
+
}
|
114 |
+
|
115 |
+
++ $data['counts']['total'];
|
116 |
+
|
117 |
+
if ( $this->get_config( 'extensions_as_one_update' ) ) {
|
118 |
+
// no matter how many extensions, display as one update
|
119 |
+
break;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
$title = esc_html__( 'Available extensions updates.', 'fw' );
|
124 |
+
|
125 |
+
$data['title'] = empty( $data['title'] ) ? $title : $data['title'] . ', ' . $title;
|
126 |
+
}
|
127 |
+
|
128 |
+
return $data;
|
129 |
+
}
|
130 |
+
|
131 |
+
private function get_updates( $force_check = false ) {
|
132 |
+
$cache_key = 'fw_ext_update/updates';
|
133 |
+
|
134 |
+
// use cache because this method may be called multiple times (to prevent useless requests to update servers)
|
135 |
+
try {
|
136 |
+
return FW_Cache::get( $cache_key );
|
137 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
138 |
+
$updates = array(
|
139 |
+
'framework' => $this->get_framework_update( $force_check ),
|
140 |
+
'theme' => $this->get_theme_update( $force_check ),
|
141 |
+
'extensions' => $this->get_extensions_with_updates( $force_check )
|
142 |
+
);
|
143 |
+
|
144 |
+
FW_Cache::set( $cache_key, $updates );
|
145 |
+
|
146 |
+
return $updates;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Collect extensions that has new versions available
|
152 |
+
*
|
153 |
+
* @param bool $force_check
|
154 |
+
*
|
155 |
+
* @return array {ext_name => update_data}
|
156 |
+
*/
|
157 |
+
private function get_extensions_with_updates( $force_check = false ) {
|
158 |
+
$updates = array();
|
159 |
+
$services = $this->get_children();
|
160 |
+
$theme_ext_requirements = fw()->theme->manifest->get( 'requirements/extensions' );
|
161 |
+
|
162 |
+
foreach ( fw()->extensions->get_all() as $ext_name => $extension ) {
|
163 |
+
/** @var FW_Extension $extension */
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Ask each service if it knows how to update the extension
|
167 |
+
*/
|
168 |
+
foreach ( $services as $service_name => $service ) {
|
169 |
+
/** @var $service FW_Ext_Update_Service */
|
170 |
+
|
171 |
+
$latest_version = $service->_get_extension_latest_version( $extension, $force_check );
|
172 |
+
|
173 |
+
if ( $latest_version === false ) {
|
174 |
+
// It said that it doesn't know how to update it
|
175 |
+
continue;
|
176 |
+
}
|
177 |
+
|
178 |
+
if ( is_wp_error( $latest_version ) ) {
|
179 |
+
$updates[ $ext_name ] = $latest_version;
|
180 |
+
break;
|
181 |
+
}
|
182 |
+
|
183 |
+
$fixed_latest_version = $this->get_fixed_version( $latest_version );
|
184 |
+
|
185 |
+
if ( ! version_compare( $fixed_latest_version, $extension->manifest->get_version(), '>' ) ) {
|
186 |
+
// we already have latest version
|
187 |
+
continue;
|
188 |
+
}
|
189 |
+
|
190 |
+
if (
|
191 |
+
isset( $theme_ext_requirements[ $ext_name ] )
|
192 |
+
&&
|
193 |
+
isset( $theme_ext_requirements[ $ext_name ]['max_version'] )
|
194 |
+
&&
|
195 |
+
version_compare( $fixed_latest_version, $theme_ext_requirements[ $ext_name ]['max_version'], '>' )
|
196 |
+
) {
|
197 |
+
continue; // do not allow update if it exceeds max_version
|
198 |
+
}
|
199 |
+
|
200 |
+
$updates[ $ext_name ] = array(
|
201 |
+
'service' => $service_name,
|
202 |
+
'latest_version' => $latest_version,
|
203 |
+
'fixed_latest_version' => $fixed_latest_version
|
204 |
+
);
|
205 |
+
|
206 |
+
break;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
return $updates;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* @param bool $force_check
|
215 |
+
*
|
216 |
+
* @return array|false|WP_Error
|
217 |
+
*/
|
218 |
+
private function get_framework_update( $force_check = false ) {
|
219 |
+
/**
|
220 |
+
* Ask each service if it knows how to update the framework
|
221 |
+
*/
|
222 |
+
foreach ( $this->get_children() as $service_name => $service ) {
|
223 |
+
/** @var $service FW_Ext_Update_Service */
|
224 |
+
|
225 |
+
$latest_version = $service->_get_framework_latest_version( $force_check );
|
226 |
+
|
227 |
+
if ( $latest_version === false ) {
|
228 |
+
// It said that it doesn't know how to update it
|
229 |
+
continue;
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( is_wp_error( $latest_version ) ) {
|
233 |
+
return $latest_version;
|
234 |
+
}
|
235 |
+
|
236 |
+
$fixed_latest_version = $this->get_fixed_version( $latest_version );
|
237 |
+
|
238 |
+
if ( ! version_compare( $fixed_latest_version, fw()->manifest->get_version(), '>' ) ) {
|
239 |
+
// we already have latest version
|
240 |
+
continue;
|
241 |
+
}
|
242 |
+
|
243 |
+
return array(
|
244 |
+
'service' => $service_name,
|
245 |
+
'latest_version' => $latest_version,
|
246 |
+
'fixed_latest_version' => $fixed_latest_version
|
247 |
+
);
|
248 |
+
}
|
249 |
+
|
250 |
+
return false;
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* @param bool $force_check
|
255 |
+
*
|
256 |
+
* @return array|false|WP_Error
|
257 |
+
*/
|
258 |
+
private function get_theme_update( $force_check = false ) {
|
259 |
+
/**
|
260 |
+
* Ask each service if it knows how to update the theme
|
261 |
+
*/
|
262 |
+
foreach ( $this->get_children() as $service_name => $service ) {
|
263 |
+
/** @var $service FW_Ext_Update_Service */
|
264 |
+
|
265 |
+
$latest_version = $service->_get_theme_latest_version( $force_check );
|
266 |
+
|
267 |
+
if ( $latest_version === false ) {
|
268 |
+
// It said that it doesn't know how to update it
|
269 |
+
continue;
|
270 |
+
}
|
271 |
+
|
272 |
+
if ( is_wp_error( $latest_version ) ) {
|
273 |
+
return $latest_version;
|
274 |
+
}
|
275 |
+
|
276 |
+
$fixed_latest_version = $this->get_fixed_version( $latest_version );
|
277 |
+
|
278 |
+
if ( ! version_compare( $fixed_latest_version, fw()->theme->manifest->get_version(), '>' ) ) {
|
279 |
+
// we already have latest version
|
280 |
+
continue;
|
281 |
+
}
|
282 |
+
|
283 |
+
return array(
|
284 |
+
'service' => $service_name,
|
285 |
+
'latest_version' => $latest_version,
|
286 |
+
'fixed_latest_version' => $fixed_latest_version
|
287 |
+
);
|
288 |
+
}
|
289 |
+
|
290 |
+
return false;
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Turn on/off the maintenance mode
|
295 |
+
*
|
296 |
+
* @param bool $enable
|
297 |
+
*/
|
298 |
+
private function maintenance_mode( $enable = false ) {
|
299 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
300 |
+
global $wp_filesystem;
|
301 |
+
|
302 |
+
if ( ! $wp_filesystem || ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) ) {
|
303 |
+
return;
|
304 |
+
}
|
305 |
+
|
306 |
+
$file_path = $wp_filesystem->abspath() . '.maintenance';
|
307 |
+
|
308 |
+
if ( $wp_filesystem->exists( $file_path ) ) {
|
309 |
+
if ( ! $wp_filesystem->delete( $file_path ) ) {
|
310 |
+
trigger_error( __( 'Cannot delete: ', 'fw' ) . $file_path, E_USER_WARNING );
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
if ( $enable ) {
|
315 |
+
// Create maintenance file to signal that we are upgrading
|
316 |
+
if ( ! $wp_filesystem->put_contents( $file_path, '<?php $upgrading = ' . time() . '; ?>', FS_CHMOD_FILE ) ) {
|
317 |
+
trigger_error( __( 'Cannot create: ', 'fw' ) . $file_path, E_USER_WARNING );
|
318 |
+
}
|
319 |
+
}
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Download and install new version files
|
324 |
+
*
|
325 |
+
* global $wp_filesystem; must be initialized before calling this method
|
326 |
+
*
|
327 |
+
* @param array $data
|
328 |
+
* @param bool $merge_extensions The extensions/ directory will not be replaced entirely,
|
329 |
+
* only extensions that comes with the update will be replaced
|
330 |
+
*
|
331 |
+
* @return null|WP_Error
|
332 |
+
*/
|
333 |
+
private function update( $data, $merge_extensions = false ) {
|
334 |
+
$required_data_keys = array(
|
335 |
+
'wp_fs_destination_dir' => true,
|
336 |
+
'download_callback' => true,
|
337 |
+
'download_callback_args' => true,
|
338 |
+
'skin' => true,
|
339 |
+
'title' => true,
|
340 |
+
);
|
341 |
+
|
342 |
+
if ( count( $required_data_keys ) > count( array_intersect_key( $required_data_keys, $data ) ) ) {
|
343 |
+
trigger_error( 'Some required keys are not present', E_USER_ERROR );
|
344 |
+
}
|
345 |
+
|
346 |
+
// move manually every key to variable, so IDE will understand better them
|
347 |
+
{
|
348 |
+
/**
|
349 |
+
* Replace all files in this directory with downloaded
|
350 |
+
* @var string $wp_fs_destination_dir
|
351 |
+
*/
|
352 |
+
$wp_fs_destination_dir = $data['wp_fs_destination_dir'];
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Called to download new version files to $this->get_wp_fs_tmp_dir()
|
356 |
+
* @var callable $download_callback
|
357 |
+
*/
|
358 |
+
$download_callback = $data['download_callback'];
|
359 |
+
|
360 |
+
/**
|
361 |
+
* @var array
|
362 |
+
*/
|
363 |
+
$download_callback_args = $data['download_callback_args'];
|
364 |
+
|
365 |
+
/**
|
366 |
+
* @var WP_Upgrader_Skin $skin
|
367 |
+
*/
|
368 |
+
$skin = $data['skin'];
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Used in text messages
|
372 |
+
* @var string $title
|
373 |
+
*/
|
374 |
+
$title = $data['title'];
|
375 |
+
|
376 |
+
unset( $data );
|
377 |
+
}
|
378 |
+
|
379 |
+
/**
|
380 |
+
* @var string|WP_Error
|
381 |
+
*/
|
382 |
+
$error = false;
|
383 |
+
|
384 |
+
$tmp_download_dir = $this->get_wp_fs_tmp_dir();
|
385 |
+
|
386 |
+
do {
|
387 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
388 |
+
global $wp_filesystem;
|
389 |
+
|
390 |
+
// create temporary directory
|
391 |
+
{
|
392 |
+
if ( $wp_filesystem->exists( $tmp_download_dir ) ) {
|
393 |
+
// just in case it already exists, clear everything, it may contain old files
|
394 |
+
if ( ! $wp_filesystem->rmdir( $tmp_download_dir, true ) ) {
|
395 |
+
$error = __( 'Cannot remove old temporary directory: ', 'fw' ) . $tmp_download_dir;
|
396 |
+
break;
|
397 |
+
}
|
398 |
+
}
|
399 |
+
|
400 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $tmp_download_dir ) ) {
|
401 |
+
$error = __( 'Cannot create directory: ', 'fw' ) . $tmp_download_dir;
|
402 |
+
break;
|
403 |
+
}
|
404 |
+
}
|
405 |
+
|
406 |
+
$skin->feedback( sprintf( __( 'Downloading the %s...', 'fw' ), $title ) );
|
407 |
+
{
|
408 |
+
$downloaded_dir = call_user_func_array( $download_callback, $download_callback_args );
|
409 |
+
|
410 |
+
if ( ! $downloaded_dir ) {
|
411 |
+
$error = sprintf( __( 'Cannot download the %s.', 'fw' ), $title );
|
412 |
+
break;
|
413 |
+
} elseif ( is_wp_error( $downloaded_dir ) ) {
|
414 |
+
$error = $downloaded_dir;
|
415 |
+
break;
|
416 |
+
}
|
417 |
+
}
|
418 |
+
|
419 |
+
$this->maintenance_mode( true );
|
420 |
+
|
421 |
+
$skin->feedback( sprintf( __( 'Installing the %s...', 'fw' ), $title ) );
|
422 |
+
{
|
423 |
+
// remove all files from destination directory
|
424 |
+
{
|
425 |
+
$dir_files = $wp_filesystem->dirlist( $wp_fs_destination_dir, true );
|
426 |
+
if ( $dir_files === false ) {
|
427 |
+
$error = __( 'Cannot access directory: ', 'fw' ) . $wp_fs_destination_dir;
|
428 |
+
break;
|
429 |
+
}
|
430 |
+
|
431 |
+
foreach ( $dir_files as $file ) {
|
432 |
+
if ( in_array( $file['name'], $this->skip_file_names ) ) {
|
433 |
+
continue;
|
434 |
+
}
|
435 |
+
|
436 |
+
if ( $merge_extensions ) {
|
437 |
+
if ( $file['name'] === 'extensions' && $file['type'] === 'd' ) {
|
438 |
+
// do not remove extensions, will be merged later
|
439 |
+
continue;
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
$file_path = $wp_fs_destination_dir . '/' . $file['name'];
|
444 |
+
|
445 |
+
if ( ! $wp_filesystem->delete( $file_path, true, $file['type'] ) ) {
|
446 |
+
$error = __( 'Cannot remove: ', 'fw' ) . $file_path;
|
447 |
+
break 2;
|
448 |
+
}
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
// move all files from the temporary directory to the destination directory
|
453 |
+
{
|
454 |
+
$dir_files = $wp_filesystem->dirlist( $downloaded_dir, true );
|
455 |
+
if ( $dir_files === false ) {
|
456 |
+
$error = __( 'Cannot access directory: ', 'fw' ) . $downloaded_dir;
|
457 |
+
break;
|
458 |
+
}
|
459 |
+
|
460 |
+
foreach ( $dir_files as $file ) {
|
461 |
+
if ( in_array( $file['name'], $this->skip_file_names ) ) {
|
462 |
+
continue;
|
463 |
+
}
|
464 |
+
|
465 |
+
$downloaded_file_path = $downloaded_dir . '/' . $file['name'];
|
466 |
+
$destination_file_path = $wp_fs_destination_dir . '/' . $file['name'];
|
467 |
+
|
468 |
+
if ( $merge_extensions ) {
|
469 |
+
if ( $file['name'] === 'extensions' && $file['type'] === 'd' ) {
|
470 |
+
// merge extensions/ after all other files was moved
|
471 |
+
$merge_extensions_data = array(
|
472 |
+
'source' => $downloaded_file_path,
|
473 |
+
'destination' => $destination_file_path,
|
474 |
+
);
|
475 |
+
continue;
|
476 |
+
}
|
477 |
+
}
|
478 |
+
|
479 |
+
if ( ! $wp_filesystem->move( $downloaded_file_path, $destination_file_path ) ) {
|
480 |
+
$error = sprintf(
|
481 |
+
__( 'Cannot move "%s" to "%s"', 'fw' ),
|
482 |
+
$downloaded_file_path, $destination_file_path
|
483 |
+
);
|
484 |
+
break 2;
|
485 |
+
}
|
486 |
+
}
|
487 |
+
|
488 |
+
if ( $merge_extensions ) {
|
489 |
+
if ( ! empty( $merge_extensions_data ) ) {
|
490 |
+
$merge_result = $this->merge_extensions(
|
491 |
+
$merge_extensions_data['source'],
|
492 |
+
$merge_extensions_data['destination']
|
493 |
+
);
|
494 |
+
|
495 |
+
if ( $merge_result === false ) {
|
496 |
+
$error = sprintf(
|
497 |
+
__( 'Cannot merge "%s" with "%s"', 'fw' ),
|
498 |
+
$downloaded_file_path, $destination_file_path
|
499 |
+
);
|
500 |
+
break;
|
501 |
+
} elseif ( is_wp_error( $merge_result ) ) {
|
502 |
+
$error = $merge_result;
|
503 |
+
break;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
}
|
507 |
+
}
|
508 |
+
}
|
509 |
+
|
510 |
+
$skin->feedback( sprintf( __( 'The %s has been successfully updated.', 'fw' ), $title ) );
|
511 |
+
} while ( false );
|
512 |
+
|
513 |
+
$this->maintenance_mode( false );
|
514 |
+
|
515 |
+
if ( $wp_filesystem->exists( $tmp_download_dir ) ) {
|
516 |
+
if ( ! $wp_filesystem->delete( $tmp_download_dir, true, 'd' ) ) {
|
517 |
+
$error = sprintf( __( 'Cannot remove temporary directory "%s".', 'fw' ), $tmp_download_dir );
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
if ( $error ) {
|
522 |
+
if ( ! is_wp_error( $error ) ) {
|
523 |
+
$error = new WP_Error( 'fw_ext_update_failed', (string) $error );
|
524 |
+
}
|
525 |
+
|
526 |
+
return $error;
|
527 |
+
}
|
528 |
+
}
|
529 |
+
|
530 |
+
/**
|
531 |
+
* Merge two extensions/ directories
|
532 |
+
*
|
533 |
+
* @param string $source_dir WP_Filesystem dir '/a/b/c/extensions'
|
534 |
+
* @param string $destination_dir WP_Filesystem dir '/a/b/d/extensions'
|
535 |
+
*
|
536 |
+
* @return bool|WP_Error
|
537 |
+
*/
|
538 |
+
private function merge_extensions( $source_dir, $destination_dir ) {
|
539 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
540 |
+
global $wp_filesystem;
|
541 |
+
|
542 |
+
$wp_error_id = 'fw_ext_update_merge_extensions';
|
543 |
+
|
544 |
+
if ( ! $wp_filesystem->exists( $destination_dir ) ) {
|
545 |
+
// do a simple move if destination does not exist
|
546 |
+
if ( ! $wp_filesystem->move( $source_dir, $destination_dir ) ) {
|
547 |
+
return new WP_Error( $wp_error_id,
|
548 |
+
sprintf( __( 'Cannot move "%s" to "%s"', 'fw' ), $source_dir, $destination_dir )
|
549 |
+
);
|
550 |
+
}
|
551 |
+
|
552 |
+
return true;
|
553 |
+
}
|
554 |
+
|
555 |
+
$source_ext_dirs = $wp_filesystem->dirlist( $source_dir, true );
|
556 |
+
if ( $source_ext_dirs === false ) {
|
557 |
+
return new WP_Error( $wp_error_id,
|
558 |
+
__( 'Cannot access directory: ', 'fw' ) . $source_dir
|
559 |
+
);
|
560 |
+
}
|
561 |
+
|
562 |
+
foreach ( $source_ext_dirs as $ext_dir ) {
|
563 |
+
if ( in_array( $ext_dir['name'], $this->skip_file_names ) ) {
|
564 |
+
continue;
|
565 |
+
}
|
566 |
+
|
567 |
+
if ( $ext_dir['type'] !== 'd' ) {
|
568 |
+
// process only directories from the extensions/ directory
|
569 |
+
continue;
|
570 |
+
}
|
571 |
+
|
572 |
+
$source_extension_dir = $source_dir . '/' . $ext_dir['name'];
|
573 |
+
$destination_extension_dir = $destination_dir . '/' . $ext_dir['name'];
|
574 |
+
|
575 |
+
{
|
576 |
+
$source_ext_files = $wp_filesystem->dirlist( $source_extension_dir, true );
|
577 |
+
if ( $source_ext_files === false ) {
|
578 |
+
return new WP_Error( $wp_error_id,
|
579 |
+
__( 'Cannot access directory: ', 'fw' ) . $source_extension_dir
|
580 |
+
);
|
581 |
+
}
|
582 |
+
|
583 |
+
if ( empty( $source_ext_files ) ) {
|
584 |
+
/**
|
585 |
+
* Source extension directory is empty, do nothing.
|
586 |
+
* This happens when the extension is a git submodule in repository
|
587 |
+
* but in zip it comes as an empty directory.
|
588 |
+
*/
|
589 |
+
continue;
|
590 |
+
}
|
591 |
+
}
|
592 |
+
|
593 |
+
// prepare destination
|
594 |
+
{
|
595 |
+
// create if not exists
|
596 |
+
if ( ! $wp_filesystem->exists( $destination_extension_dir ) ) {
|
597 |
+
if ( ! FW_WP_Filesystem::mkdir_recursive( $destination_extension_dir ) ) {
|
598 |
+
return new WP_Error( $wp_error_id,
|
599 |
+
__( 'Cannot create directory: ', 'fw' ) . $destination_extension_dir
|
600 |
+
);
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
// remove everything except the extensions/ dir
|
605 |
+
{
|
606 |
+
$dest_ext_files = $wp_filesystem->dirlist( $destination_extension_dir, true );
|
607 |
+
if ( $dest_ext_files === false ) {
|
608 |
+
return new WP_Error( $wp_error_id,
|
609 |
+
__( 'Cannot access directory: ', 'fw' ) . $destination_extension_dir
|
610 |
+
);
|
611 |
+
}
|
612 |
+
|
613 |
+
$destination_has_extensions_dir = false;
|
614 |
+
|
615 |
+
foreach ( $dest_ext_files as $dest_ext_file ) {
|
616 |
+
if ( in_array( $dest_ext_file['name'], $this->skip_file_names ) ) {
|
617 |
+
continue;
|
618 |
+
}
|
619 |
+
|
620 |
+
if ( $dest_ext_file['name'] === 'extensions' && $dest_ext_file['type'] === 'd' ) {
|
621 |
+
$destination_has_extensions_dir = true;
|
622 |
+
continue;
|
623 |
+
}
|
624 |
+
|
625 |
+
$dest_ext_file_path = $destination_extension_dir . '/' . $dest_ext_file['name'];
|
626 |
+
|
627 |
+
if ( ! $wp_filesystem->delete( $dest_ext_file_path, true, $dest_ext_file['type'] ) ) {
|
628 |
+
return new WP_Error( $wp_error_id,
|
629 |
+
__( 'Cannot delete: ', 'fw' ) . $dest_ext_file_path
|
630 |
+
);
|
631 |
+
}
|
632 |
+
}
|
633 |
+
}
|
634 |
+
}
|
635 |
+
|
636 |
+
// move files from source to destination extension directory
|
637 |
+
{
|
638 |
+
$source_has_extensions_dir = false;
|
639 |
+
|
640 |
+
foreach ( $source_ext_files as $source_ext_file ) {
|
641 |
+
if ( in_array( $source_ext_file['name'], $this->skip_file_names ) ) {
|
642 |
+
continue;
|
643 |
+
}
|
644 |
+
|
645 |
+
if ( $source_ext_file['name'] === 'extensions' && $source_ext_file['type'] === 'd' ) {
|
646 |
+
$source_has_extensions_dir = true;
|
647 |
+
continue;
|
648 |
+
}
|
649 |
+
|
650 |
+
$source_ext_file_path = $source_extension_dir . '/' . $source_ext_file['name'];
|
651 |
+
$dest_ext_file_path = $destination_extension_dir . '/' . $source_ext_file['name'];
|
652 |
+
|
653 |
+
if ( ! $wp_filesystem->move( $source_ext_file_path, $dest_ext_file_path ) ) {
|
654 |
+
return new WP_Error( $wp_error_id,
|
655 |
+
sprintf( __( 'Cannot move "%s" to "%s"', 'fw' ),
|
656 |
+
$source_ext_file_path, $dest_ext_file_path
|
657 |
+
)
|
658 |
+
);
|
659 |
+
}
|
660 |
+
}
|
661 |
+
}
|
662 |
+
|
663 |
+
if ( $source_has_extensions_dir ) {
|
664 |
+
if ( $destination_has_extensions_dir ) {
|
665 |
+
$merge_result = $this->merge_extensions(
|
666 |
+
$source_extension_dir . '/extensions',
|
667 |
+
$destination_extension_dir . '/extensions'
|
668 |
+
);
|
669 |
+
|
670 |
+
if ( $merge_result !== true ) {
|
671 |
+
return $merge_result;
|
672 |
+
}
|
673 |
+
} else {
|
674 |
+
if ( ! $wp_filesystem->move(
|
675 |
+
$source_extension_dir . '/extensions',
|
676 |
+
$destination_extension_dir . '/extensions'
|
677 |
+
) ) {
|
678 |
+
return new WP_Error( $wp_error_id,
|
679 |
+
sprintf( __( 'Cannot move "%s" to "%s"', 'fw' ),
|
680 |
+
$source_extension_dir . '/extensions',
|
681 |
+
$destination_extension_dir . '/extensions'
|
682 |
+
)
|
683 |
+
);
|
684 |
+
}
|
685 |
+
}
|
686 |
+
}
|
687 |
+
}
|
688 |
+
|
689 |
+
return true;
|
690 |
+
}
|
691 |
+
|
692 |
+
/**
|
693 |
+
* @internal
|
694 |
+
*/
|
695 |
+
public function _action_update_framework() {
|
696 |
+
$nonce_name = '_nonce_fw_ext_update_framework';
|
697 |
+
if ( ! isset( $_POST[ $nonce_name ] ) || ! wp_verify_nonce( $_POST[ $nonce_name ] ) ) {
|
698 |
+
wp_die( __( 'Invalid nonce.', 'fw' ) );
|
699 |
+
}
|
700 |
+
|
701 |
+
{
|
702 |
+
if ( ! class_exists( '_FW_Ext_Update_Framework_Upgrader_Skin' ) ) {
|
703 |
+
fw_include_file_isolated(
|
704 |
+
$this->get_declared_path( '/includes/classes/class--fw-ext-update-framework-upgrader-skin.php' )
|
705 |
+
);
|
706 |
+
}
|
707 |
+
|
708 |
+
$skin = new _FW_Ext_Update_Framework_Upgrader_Skin( array(
|
709 |
+
'title' => __( 'Framework Update', 'fw' ),
|
710 |
+
) );
|
711 |
+
}
|
712 |
+
|
713 |
+
require_once ABSPATH . 'wp-admin/admin-header.php';
|
714 |
+
|
715 |
+
$skin->header();
|
716 |
+
|
717 |
+
do {
|
718 |
+
if ( ! FW_WP_Filesystem::request_access( fw_get_framework_directory(), fw_current_url(), array( $nonce_name ) ) ) {
|
719 |
+
break;
|
720 |
+
}
|
721 |
+
|
722 |
+
$update = $this->get_framework_update();
|
723 |
+
|
724 |
+
if ( $update === false ) {
|
725 |
+
$skin->error( __( 'Failed to get framework latest version.', 'fw' ) );
|
726 |
+
break;
|
727 |
+
} elseif ( is_wp_error( $update ) ) {
|
728 |
+
$skin->error( $update );
|
729 |
+
break;
|
730 |
+
}
|
731 |
+
|
732 |
+
/** @var FW_Ext_Update_Service $service */
|
733 |
+
$service = $this->get_child( $update['service'] );
|
734 |
+
|
735 |
+
$update_result = $this->update( array(
|
736 |
+
'wp_fs_destination_dir' => FW_WP_Filesystem::real_path_to_filesystem_path(
|
737 |
+
fw_get_framework_directory()
|
738 |
+
),
|
739 |
+
'download_callback' => array( $service, '_download_framework' ),
|
740 |
+
'download_callback_args' => array( $update['latest_version'], $this->get_wp_fs_tmp_dir() ),
|
741 |
+
'skin' => $skin,
|
742 |
+
'title' => __( 'Framework', 'fw' ),
|
743 |
+
) );
|
744 |
+
|
745 |
+
if ( is_wp_error( $update_result ) ) {
|
746 |
+
$skin->error( $update_result );
|
747 |
+
break;
|
748 |
+
}
|
749 |
+
|
750 |
+
$skin->set_result( true );
|
751 |
+
$skin->after();
|
752 |
+
} while ( false );
|
753 |
+
|
754 |
+
$skin->footer();
|
755 |
+
|
756 |
+
require_once( ABSPATH . 'wp-admin/admin-footer.php' );
|
757 |
+
}
|
758 |
+
|
759 |
+
/**
|
760 |
+
* @internal
|
761 |
+
*/
|
762 |
+
public function _action_update_theme() {
|
763 |
+
$nonce_name = '_nonce_fw_ext_update_theme';
|
764 |
+
if ( ! isset( $_POST[ $nonce_name ] ) || ! wp_verify_nonce( $_POST[ $nonce_name ] ) ) {
|
765 |
+
wp_die( __( 'Invalid nonce.', 'fw' ) );
|
766 |
+
}
|
767 |
+
|
768 |
+
{
|
769 |
+
if ( ! class_exists( '_FW_Ext_Update_Theme_Upgrader_Skin' ) ) {
|
770 |
+
fw_include_file_isolated(
|
771 |
+
$this->get_declared_path( '/includes/classes/class--fw-ext-update-theme-upgrader-skin.php' )
|
772 |
+
);
|
773 |
+
}
|
774 |
+
|
775 |
+
$skin = new _FW_Ext_Update_Theme_Upgrader_Skin( array(
|
776 |
+
'title' => __( 'Theme Update', 'fw' ),
|
777 |
+
) );
|
778 |
+
}
|
779 |
+
|
780 |
+
require_once( ABSPATH . 'wp-admin/admin-header.php' );
|
781 |
+
|
782 |
+
$skin->header();
|
783 |
+
|
784 |
+
do {
|
785 |
+
if ( ! FW_WP_Filesystem::request_access( get_template_directory(), fw_current_url(), array( $nonce_name ) ) ) {
|
786 |
+
break;
|
787 |
+
}
|
788 |
+
|
789 |
+
$update = $this->get_theme_update();
|
790 |
+
|
791 |
+
if ( $update === false ) {
|
792 |
+
$skin->error( __( 'Failed to get theme latest version.', 'fw' ) );
|
793 |
+
break;
|
794 |
+
} elseif ( is_wp_error( $update ) ) {
|
795 |
+
$skin->error( $update );
|
796 |
+
break;
|
797 |
+
}
|
798 |
+
|
799 |
+
/** @var FW_Ext_Update_Service $service */
|
800 |
+
$service = $this->get_child( $update['service'] );
|
801 |
+
|
802 |
+
$update_result = $this->update( array(
|
803 |
+
'wp_fs_destination_dir' => FW_WP_Filesystem::real_path_to_filesystem_path(
|
804 |
+
get_template_directory()
|
805 |
+
),
|
806 |
+
'download_callback' => array( $service, '_download_theme' ),
|
807 |
+
'download_callback_args' => array( $update['latest_version'], $this->get_wp_fs_tmp_dir() ),
|
808 |
+
'skin' => $skin,
|
809 |
+
'title' => __( 'Theme', 'fw' ),
|
810 |
+
) );
|
811 |
+
|
812 |
+
if ( is_wp_error( $update_result ) ) {
|
813 |
+
$skin->error( $update_result );
|
814 |
+
break;
|
815 |
+
}
|
816 |
+
|
817 |
+
$skin->set_result( true );
|
818 |
+
$skin->after();
|
819 |
+
} while ( false );
|
820 |
+
|
821 |
+
$skin->footer();
|
822 |
+
|
823 |
+
require_once( ABSPATH . 'wp-admin/admin-footer.php' );
|
824 |
+
}
|
825 |
+
|
826 |
+
/**
|
827 |
+
* @internal
|
828 |
+
*/
|
829 |
+
public function _action_update_extensions() {
|
830 |
+
$nonce_name = '_nonce_fw_ext_update_extensions';
|
831 |
+
if ( ! isset( $_POST[ $nonce_name ] ) || ! wp_verify_nonce( $_POST[ $nonce_name ] ) ) {
|
832 |
+
wp_die( __( 'Invalid nonce.', 'fw' ) );
|
833 |
+
}
|
834 |
+
|
835 |
+
$form_input_name = 'extensions';
|
836 |
+
$extensions_list = FW_Request::POST( $form_input_name );
|
837 |
+
|
838 |
+
if ( empty( $extensions_list ) ) {
|
839 |
+
FW_Flash_Messages::add(
|
840 |
+
'fw_ext_update',
|
841 |
+
__( 'Please check the extensions you want to update.', 'fw' ),
|
842 |
+
'warning'
|
843 |
+
);
|
844 |
+
wp_redirect( self_admin_url( 'update-core.php' ) );
|
845 |
+
exit;
|
846 |
+
}
|
847 |
+
|
848 |
+
// handle changes by the hack below
|
849 |
+
{
|
850 |
+
if ( is_string( $extensions_list ) ) {
|
851 |
+
$extensions_list = json_decode( $extensions_list );
|
852 |
+
} else {
|
853 |
+
$extensions_list = array_keys( $extensions_list );
|
854 |
+
}
|
855 |
+
}
|
856 |
+
|
857 |
+
{
|
858 |
+
if ( ! class_exists( '_FW_Ext_Update_Extensions_Upgrader_Skin' ) ) {
|
859 |
+
fw_include_file_isolated(
|
860 |
+
$this->get_declared_path( '/includes/classes/class--fw-ext-update-extensions-upgrader-skin.php' )
|
861 |
+
);
|
862 |
+
}
|
863 |
+
|
864 |
+
$skin = new _FW_Ext_Update_Extensions_Upgrader_Skin( array(
|
865 |
+
'title' => __( 'Extensions Update', 'fw' ),
|
866 |
+
) );
|
867 |
+
}
|
868 |
+
|
869 |
+
require_once( ABSPATH . 'wp-admin/admin-header.php' );
|
870 |
+
|
871 |
+
$skin->header();
|
872 |
+
|
873 |
+
do {
|
874 |
+
/**
|
875 |
+
* Hack for the ftp credentials template that does not support array post values
|
876 |
+
* https://github.com/WordPress/WordPress/blob/3949a8b6cc50a021ed93798287b4ef9ea8a560d9/wp-admin/includes/file.php#L1144
|
877 |
+
*/
|
878 |
+
$original_post_value = $_POST[ $form_input_name ];
|
879 |
+
$_POST[ $form_input_name ] = wp_slash( json_encode( $extensions_list ) );
|
880 |
+
|
881 |
+
if ( ! FW_WP_Filesystem::request_access( fw_get_framework_directory( '/extensions' ), fw_current_url(), array( $nonce_name, $form_input_name ) ) ) {
|
882 |
+
// revert hack changes
|
883 |
+
$_POST[ $form_input_name ] = $original_post_value;
|
884 |
+
unset( $original_post_value );
|
885 |
+
|
886 |
+
break;
|
887 |
+
}
|
888 |
+
|
889 |
+
// revert hack changes
|
890 |
+
$_POST[ $form_input_name ] = $original_post_value;
|
891 |
+
unset( $original_post_value );
|
892 |
+
|
893 |
+
$updates = $this->get_extensions_with_updates();
|
894 |
+
|
895 |
+
if ( empty( $updates ) ) {
|
896 |
+
$skin->error( __( 'No extensions updates found.', 'fw' ) );
|
897 |
+
break;
|
898 |
+
}
|
899 |
+
|
900 |
+
foreach ( $extensions_list as $extension_name ) {
|
901 |
+
if ( ! ( $extension = fw()->extensions->get( $extension_name ) ) ) {
|
902 |
+
$skin->error( sprintf( __( 'Extension "%s" does not exist or is disabled.', 'fw' ), $extension_name ) );
|
903 |
+
continue;
|
904 |
+
}
|
905 |
+
|
906 |
+
if ( ! isset( $updates[ $extension_name ] ) ) {
|
907 |
+
$skin->error( sprintf( __( 'No update found for the "%s" extension.', 'fw' ), $extension->manifest->get_name() ) );
|
908 |
+
continue;
|
909 |
+
}
|
910 |
+
|
911 |
+
$update = $updates[ $extension_name ];
|
912 |
+
|
913 |
+
if ( is_wp_error( $update ) ) {
|
914 |
+
$skin->error( $update );
|
915 |
+
continue;
|
916 |
+
}
|
917 |
+
|
918 |
+
/** @var FW_Ext_Update_Service $service */
|
919 |
+
$service = $this->get_child( $update['service'] );
|
920 |
+
|
921 |
+
$update_result = $this->update( array(
|
922 |
+
'wp_fs_destination_dir' => FW_WP_Filesystem::real_path_to_filesystem_path(
|
923 |
+
$extension->get_declared_path()
|
924 |
+
),
|
925 |
+
'download_callback' => array( $service, '_download_extension' ),
|
926 |
+
'download_callback_args' => array(
|
927 |
+
$extension,
|
928 |
+
$update['latest_version'],
|
929 |
+
$this->get_wp_fs_tmp_dir()
|
930 |
+
),
|
931 |
+
'skin' => $skin,
|
932 |
+
'title' => sprintf( __( '%s extension', 'fw' ), $extension->manifest->get_name() ),
|
933 |
+
), true );
|
934 |
+
|
935 |
+
if ( is_wp_error( $update_result ) ) {
|
936 |
+
$skin->error( $update_result );
|
937 |
+
continue;
|
938 |
+
}
|
939 |
+
|
940 |
+
$skin->set_result( true );
|
941 |
+
|
942 |
+
if ( ! $this->get_config( 'extensions_as_one_update' ) ) {
|
943 |
+
$skin->decrement_extension_update_count( $extension_name );
|
944 |
+
}
|
945 |
+
}
|
946 |
+
|
947 |
+
if ( $this->get_config( 'extensions_as_one_update' ) ) {
|
948 |
+
$skin->decrement_extension_update_count( $extension_name );
|
949 |
+
}
|
950 |
+
|
951 |
+
$skin->after();
|
952 |
+
} while ( false );
|
953 |
+
|
954 |
+
$skin->footer();
|
955 |
+
|
956 |
+
require_once( ABSPATH . 'wp-admin/admin-footer.php' );
|
957 |
+
}
|
958 |
+
|
959 |
+
public function _action_admin_notices() {
|
960 |
+
|
961 |
+
$updates = $this->get_updates();
|
962 |
+
|
963 |
+
if ( ( empty( $updates['extensions'] ) && empty( $updates['theme'] ) )
|
964 |
+
||
|
965 |
+
strpos( get_current_screen()->id, 'update-core' ) !== false
|
966 |
+
||
|
967 |
+
( isset( $_GET['page'] ) && $_GET['page'] === 'fw-update' ) ) {
|
968 |
+
|
969 |
+
return;
|
970 |
+
}
|
971 |
+
|
972 |
+
foreach ( $updates['extensions'] as $ext_name => $ext_update ) {
|
973 |
+
if ( is_wp_error( $ext_update ) ) {
|
974 |
+
return;
|
975 |
+
}
|
976 |
+
|
977 |
+
break;
|
978 |
+
}
|
979 |
+
|
980 |
+
$slug = is_multisite() && ! is_plugin_active_for_network( 'unyson/unyson.php' ) ? '?page=fw-update' : 'update-core.php#fw-ext-update-extensions';
|
981 |
+
|
982 |
+
if ( ! empty( $updates['extensions'] ) && empty( $updates['theme'] ) ) {
|
983 |
+
$text = 'extensions updates';
|
984 |
+
} elseif ( empty( $updates['extensions'] ) && ! empty( $updates['theme'] ) ) {
|
985 |
+
$text = 'theme update';
|
986 |
+
} else {
|
987 |
+
$text = 'extensions/theme updates';
|
988 |
+
}
|
989 |
+
|
990 |
+
echo
|
991 |
+
'<div class="notice notice-warning">
|
992 |
+
<p>' .
|
993 |
+
sprintf(
|
994 |
+
esc_html__( 'New %s available. %s', 'fw' ),
|
995 |
+
$text,
|
996 |
+
fw_html_tag(
|
997 |
+
'a',
|
998 |
+
array( 'href' => self_admin_url( $slug ) ),
|
999 |
+
esc_html__( 'Go to Updates page', 'fw' )
|
1000 |
+
)
|
1001 |
+
) .
|
1002 |
+
'</p>
|
1003 |
+
</div>';
|
1004 |
+
}
|
1005 |
+
}
|
framework/extensions/update/config.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
$cfg = array();
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Do not show details about each extension update, but show it as one update
|
7 |
-
* (simplify users life)
|
8 |
-
*/
|
9 |
-
$cfg['extensions_as_one_update'] = true;
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
$cfg = array();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Do not show details about each extension update, but show it as one update
|
7 |
+
* (simplify users life)
|
8 |
+
*/
|
9 |
+
$cfg['extensions_as_one_update'] = true;
|
framework/extensions/update/extensions/custom-update/class-fw-extension-custom-update.php
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php defined( 'FW' ) or die();
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Custom server Update
|
5 |
+
*
|
6 |
+
* Add {'remote' => 'your_url'} to your manifest and this extension will handle it
|
7 |
+
*/
|
8 |
+
class FW_Extension_Custom_Update extends FW_Ext_Update_Service {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* How long to cache server responses
|
12 |
+
* @var int seconds
|
13 |
+
*/
|
14 |
+
private $transient_expiration = DAY_IN_SECONDS;
|
15 |
+
|
16 |
+
private $download_timeout = 300;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Used when there is internet connection problems
|
20 |
+
* To prevent site being blocked on every refresh, this fake version will be cached in the transient
|
21 |
+
* @var string
|
22 |
+
*/
|
23 |
+
private $fake_latest_version = '0.0.0';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @internal
|
27 |
+
*/
|
28 |
+
protected function _init() {}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param $force_check
|
32 |
+
* @param $set - manifest settings.
|
33 |
+
*
|
34 |
+
* @return mixed|string|WP_Error
|
35 |
+
*/
|
36 |
+
private function get_latest_version( $force_check, $set ) {
|
37 |
+
|
38 |
+
$transient_name = 'fw_ext_upd_gh_fw';
|
39 |
+
|
40 |
+
if ( $force_check ) {
|
41 |
+
delete_site_transient( $transient_name );
|
42 |
+
|
43 |
+
$cache = array();
|
44 |
+
} else {
|
45 |
+
$cache = ( $c = get_site_transient( $transient_name ) ) && $c !== false ? $c : array();
|
46 |
+
|
47 |
+
if ( isset( $cache[ $set['item'] ] ) ) {
|
48 |
+
return $cache[ $set['item'] ];
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
$version = $this->fetch_latest_version( $set );
|
53 |
+
|
54 |
+
if ( is_wp_error( $version ) ) {
|
55 |
+
// Cache fake version to prevent requests to yourserver on every refresh.
|
56 |
+
$cache[ $set['item'] ] = $this->fake_latest_version;
|
57 |
+
|
58 |
+
// Show the error to the user because it is not visible elsewhere.
|
59 |
+
FW_Flash_Messages::add( 'fw_ext_custom_update_error', $version->get_error_message(), 'error' );
|
60 |
+
|
61 |
+
} else {
|
62 |
+
$cache[ $set['item'] ] = $version;
|
63 |
+
}
|
64 |
+
|
65 |
+
set_site_transient( $transient_name, $cache, $this->transient_expiration );
|
66 |
+
|
67 |
+
return $version;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param $set
|
72 |
+
*
|
73 |
+
* @return array|string|WP_Error
|
74 |
+
*/
|
75 |
+
private function fetch_latest_version( $set ) {
|
76 |
+
/**
|
77 |
+
* If at least one request failed, do not do any other requests, to prevent site being blocked on every refresh.
|
78 |
+
* This may happen on localhost when develop your theme and you have no internet connection.
|
79 |
+
* Then this method will return a fake '0.0.0' version, it will be cached by the transient
|
80 |
+
* and will not bother you until the transient will expire, then a new request will be made.
|
81 |
+
* @var bool
|
82 |
+
*/
|
83 |
+
static $no_internet_connection = false;
|
84 |
+
|
85 |
+
if ( $no_internet_connection ) {
|
86 |
+
return $this->fake_latest_version;
|
87 |
+
}
|
88 |
+
|
89 |
+
$request = wp_remote_post(
|
90 |
+
apply_filters( 'fw_custom_url_version', $set['remote'], $set ),
|
91 |
+
array(
|
92 |
+
'timeout' => $this->download_timeout,
|
93 |
+
'body' => json_encode( array_merge( $set, array( 'pull' => 'version' ) ) )
|
94 |
+
)
|
95 |
+
);
|
96 |
+
|
97 |
+
if ( is_wp_error( $request ) ) {
|
98 |
+
if ( $request->get_error_code() === 'http_request_failed' ) {
|
99 |
+
$no_internet_connection = true;
|
100 |
+
}
|
101 |
+
|
102 |
+
return $request;
|
103 |
+
}
|
104 |
+
|
105 |
+
if ( ! ( $version = wp_remote_retrieve_body( $request ) ) || is_wp_error( $version ) ) {
|
106 |
+
return ! $version ? new WP_Error( sprintf( __( 'Empty version for item: %s', 'fw' ), $set['item'] ) ) : $version;
|
107 |
+
}
|
108 |
+
|
109 |
+
return $version;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @param array $set - manifest keys.
|
114 |
+
* @param string $version Requested version to download
|
115 |
+
* @param string $wp_filesystem_download_directory Allocated temporary empty directory
|
116 |
+
* @param string $title Used in messages
|
117 |
+
*
|
118 |
+
* @return string|WP_Error Path to the downloaded directory
|
119 |
+
*/
|
120 |
+
private function download( $set, $version, $wp_filesystem_download_directory, $title ) {
|
121 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
122 |
+
global $wp_filesystem;
|
123 |
+
|
124 |
+
$error_id = 'fw_ext_update_custom_download_zip';
|
125 |
+
$request = wp_remote_post(
|
126 |
+
$set['remote'],
|
127 |
+
array(
|
128 |
+
'timeout' => $this->download_timeout,
|
129 |
+
'body' => json_encode( array_merge( $set, array( 'pull' => 'zip' ) ) )
|
130 |
+
)
|
131 |
+
);
|
132 |
+
|
133 |
+
if ( is_wp_error( $request ) ) {
|
134 |
+
return $request;
|
135 |
+
}
|
136 |
+
|
137 |
+
if ( ! ( $body = wp_remote_retrieve_body( $request ) ) || is_wp_error( $body ) ) {
|
138 |
+
return ! $body ? new WP_Error( $error_id, sprintf( esc_html__( 'Empty zip body for item: %s', 'fw' ), $title ) ) : $body;
|
139 |
+
}
|
140 |
+
|
141 |
+
// Try to extract error if server returned json with key error. If not then is an archive zip.
|
142 |
+
if ( ( $error = json_decode( $body, true ) ) && isset( $error['error'] ) ) {
|
143 |
+
return new WP_Error( $error_id, $error['error'] );
|
144 |
+
}
|
145 |
+
|
146 |
+
$zip_path = $wp_filesystem_download_directory . '/temp.zip';
|
147 |
+
|
148 |
+
// save zip to file
|
149 |
+
if ( ! $wp_filesystem->put_contents( $zip_path, $body ) ) {
|
150 |
+
return new WP_Error( $error_id, sprintf( esc_html__( 'Cannot save %s zip.', 'fw' ), $title ) );
|
151 |
+
}
|
152 |
+
|
153 |
+
$unzip_result = unzip_file( FW_WP_Filesystem::filesystem_path_to_real_path( $zip_path ), $wp_filesystem_download_directory );
|
154 |
+
|
155 |
+
if ( is_wp_error( $unzip_result ) ) {
|
156 |
+
return $unzip_result;
|
157 |
+
}
|
158 |
+
|
159 |
+
// remove zip file
|
160 |
+
if ( ! $wp_filesystem->delete( $zip_path, false, 'f' ) ) {
|
161 |
+
return new WP_Error( $error_id, sprintf( esc_html__( 'Cannot remove %s zip.', 'fw' ), $title ) );
|
162 |
+
}
|
163 |
+
|
164 |
+
$unzipped_dir_files = $wp_filesystem->dirlist( $wp_filesystem_download_directory );
|
165 |
+
|
166 |
+
if ( ! $unzipped_dir_files ) {
|
167 |
+
return new WP_Error( $error_id, esc_html__( 'Cannot access the unzipped directory files.', 'fw' ) );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* get first found directory
|
172 |
+
* (if everything worked well, there should be only one directory)
|
173 |
+
*/
|
174 |
+
foreach ( $unzipped_dir_files as $file ) {
|
175 |
+
if ( $file['type'] == 'd' ) {
|
176 |
+
return $wp_filesystem_download_directory . '/' . $file['name'];
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
return new WP_Error( $error_id, sprintf( esc_html__( 'The unzipped %s directory not found.', 'fw' ), $title ) );
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* {@inheritdoc}
|
185 |
+
* @internal
|
186 |
+
*/
|
187 |
+
public function _get_framework_latest_version( $force_check ) {
|
188 |
+
return false;
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* {@inheritdoc}
|
193 |
+
* @internal
|
194 |
+
*/
|
195 |
+
public function _get_theme_latest_version( $force_check ) {
|
196 |
+
|
197 |
+
$manifest = $this->get_clean_theme_manifest();
|
198 |
+
|
199 |
+
if ( empty( $manifest['remote'] ) ) {
|
200 |
+
return false;
|
201 |
+
}
|
202 |
+
|
203 |
+
return $this->get_latest_version( $force_check, $manifest );
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* {@inheritdoc}
|
208 |
+
* @internal
|
209 |
+
*/
|
210 |
+
public function _download_theme( $version, $wp_filesystem_download_directory ) {
|
211 |
+
return $this->download( $this->get_clean_theme_manifest(), $version, $wp_filesystem_download_directory, esc_html__( 'Theme', 'fw' ) );
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* {@inheritdoc}
|
216 |
+
* @internal
|
217 |
+
*/
|
218 |
+
public function _get_extension_latest_version( FW_Extension $extension, $force_check ) {
|
219 |
+
|
220 |
+
if ( ! $extension->manifest->get( 'remote' ) ) {
|
221 |
+
return false;
|
222 |
+
}
|
223 |
+
|
224 |
+
return $this->get_latest_version( $force_check, $this->data_manifest( $extension->manifest->get_manifest(), 'extension', $extension->get_name() ) );
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* {@inheritdoc}
|
229 |
+
* @internal
|
230 |
+
*/
|
231 |
+
public function _download_extension( FW_Extension $extension, $version, $wp_filesystem_download_directory ) {
|
232 |
+
return $this->download(
|
233 |
+
$this->data_manifest( $extension->manifest->get_manifest(), 'extension', $extension->get_name() ),
|
234 |
+
$version,
|
235 |
+
$wp_filesystem_download_directory,
|
236 |
+
sprintf( esc_html__( '%s extension', 'fw' ), $extension->manifest->get_name() )
|
237 |
+
);
|
238 |
+
}
|
239 |
+
|
240 |
+
public function data_manifest( $manifest, $type, $id ) {
|
241 |
+
return array_merge( $manifest, array( 'type' => $type, 'item' => $id ) );
|
242 |
+
}
|
243 |
+
|
244 |
+
public function get_clean_theme_manifest() {
|
245 |
+
|
246 |
+
if ( ! ( $manifest_file = fw_get_template_customizations_directory( '/theme/manifest.php' ) ) || ! is_file( $manifest_file ) ) {
|
247 |
+
return array();
|
248 |
+
}
|
249 |
+
|
250 |
+
include $manifest_file;
|
251 |
+
|
252 |
+
return isset( $manifest ) ? $this->data_manifest( $manifest, 'theme', $manifest['id'] ) : array();
|
253 |
+
}
|
254 |
+
}
|
framework/extensions/update/extensions/custom-update/manifest.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php defined( 'FW' ) or die();
|
2 |
+
|
3 |
+
$manifest = array();
|
4 |
+
|
5 |
+
$manifest['standalone'] = true;
|
framework/extensions/update/extensions/github-update/class-fw-extension-github-update.php
CHANGED
@@ -1,443 +1,433 @@
|
|
1 |
-
<?php if (!defined('FW'))
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
*
|
7 |
-
|
8 |
-
|
9 |
-
|
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 |
-
* @return string
|
47 |
-
*/
|
48 |
-
private function get_github_api_url($append)
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
*
|
57 |
-
*
|
58 |
-
*
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
$
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
);
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
*
|
131 |
-
*
|
132 |
-
* @param string $
|
133 |
-
*
|
134 |
-
* @
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
* @param string $
|
207 |
-
*
|
208 |
-
* @
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
);
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
)
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
$
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
);
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
public function _download_extension(FW_Extension $extension, $version, $wp_filesystem_download_directory)
|
435 |
-
{
|
436 |
-
return $this->download(
|
437 |
-
$extension->manifest->get($this->manifest_key),
|
438 |
-
$version,
|
439 |
-
$wp_filesystem_download_directory,
|
440 |
-
sprintf(__('%s extension', 'fw'), $extension->manifest->get_name())
|
441 |
-
);
|
442 |
-
}
|
443 |
-
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Github Update
|
7 |
+
*
|
8 |
+
* Add {'github_update' => 'user/repo'} to your manifest and this extension will handle it
|
9 |
+
*/
|
10 |
+
class FW_Extension_Github_Update extends FW_Ext_Update_Service {
|
11 |
+
/**
|
12 |
+
* Handle framework, theme and extensions that has this key in manifest
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
private $manifest_key = 'github_update';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Check if manifest key format is correct 'user/repo'
|
19 |
+
* @var string
|
20 |
+
*/
|
21 |
+
private $manifest_key_regex = '/^([^\s\/]+)\/([^\s\/]+)$/';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* How long to cache server responses
|
25 |
+
* @var int seconds
|
26 |
+
*/
|
27 |
+
private $transient_expiration = DAY_IN_SECONDS;
|
28 |
+
|
29 |
+
private $download_timeout = 300;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Used when there is internet connection problems
|
33 |
+
* To prevent site being blocked on every refresh, this fake version will be cached in the transient
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
private $fake_latest_version = '0.0.0';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @internal
|
40 |
+
*/
|
41 |
+
protected function _init() {}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @param string $append '/foo/bar'
|
45 |
+
*
|
46 |
+
* @return string
|
47 |
+
*/
|
48 |
+
private function get_github_api_url( $append ) {
|
49 |
+
return apply_filters( 'fw_github_api_url', 'https://api.github.com' ) . $append;
|
50 |
+
}
|
51 |
+
|
52 |
+
private function fetch_latest_version( $user_slash_repo ) {
|
53 |
+
/**
|
54 |
+
* If at least one request failed, do not do any other requests, to prevent site being blocked on every refresh.
|
55 |
+
* This may happen on localhost when develop your theme and you have no internet connection.
|
56 |
+
* Then this method will return a fake '0.0.0' version, it will be cached by the transient
|
57 |
+
* and will not bother you until the transient will expire, then a new request will be made.
|
58 |
+
* @var bool
|
59 |
+
*/
|
60 |
+
static $no_internet_connection = false;
|
61 |
+
|
62 |
+
if ( $no_internet_connection ) {
|
63 |
+
return $this->fake_latest_version;
|
64 |
+
}
|
65 |
+
|
66 |
+
$http = new WP_Http();
|
67 |
+
|
68 |
+
$response = $http->get(
|
69 |
+
$this->get_github_api_url( '/repos/' . $user_slash_repo . '/releases/latest' )
|
70 |
+
);
|
71 |
+
|
72 |
+
unset( $http );
|
73 |
+
|
74 |
+
if ( is_wp_error( $response ) ) {
|
75 |
+
if ( $response->get_error_code() === 'http_request_failed' ) {
|
76 |
+
$no_internet_connection = true;
|
77 |
+
}
|
78 |
+
|
79 |
+
return $response;
|
80 |
+
}
|
81 |
+
|
82 |
+
if ( ( $response_code = intval( wp_remote_retrieve_response_code( $response ) ) ) !== 200 ) {
|
83 |
+
if ( $response_code === 403 ) {
|
84 |
+
$json_response = json_decode( $response['body'], true );
|
85 |
+
|
86 |
+
if ( $json_response ) {
|
87 |
+
return new WP_Error(
|
88 |
+
'fw_ext_update_github_fetch_releases_failed',
|
89 |
+
__( 'Github error:', 'fw' ) . ' ' . $json_response['message']
|
90 |
+
);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
if ( $response_code ) {
|
95 |
+
return new WP_Error(
|
96 |
+
'fw_ext_update_github_fetch_releases_failed',
|
97 |
+
sprintf(
|
98 |
+
__( 'Failed to access Github repository "%s" releases. (Response code: %d)', 'fw' ),
|
99 |
+
$user_slash_repo, $response_code
|
100 |
+
)
|
101 |
+
);
|
102 |
+
} else {
|
103 |
+
return new WP_Error(
|
104 |
+
'fw_ext_update_github_fetch_releases_failed',
|
105 |
+
sprintf(
|
106 |
+
__( 'Failed to access Github repository "%s" releases.', 'fw' ),
|
107 |
+
$user_slash_repo
|
108 |
+
)
|
109 |
+
);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
$release = json_decode( $response['body'], true );
|
114 |
+
|
115 |
+
unset( $response );
|
116 |
+
|
117 |
+
if ( empty( $release ) ) {
|
118 |
+
return new WP_Error(
|
119 |
+
'fw_ext_update_github_fetch_no_releases',
|
120 |
+
sprintf( __( 'No releases found in repository "%s".', 'fw' ), $user_slash_repo )
|
121 |
+
);
|
122 |
+
}
|
123 |
+
|
124 |
+
return $release['tag_name'];
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Get repository latest release version
|
129 |
+
*
|
130 |
+
* @param string $user_slash_repo Github 'user/repo'
|
131 |
+
* @param bool $force_check Bypass cache
|
132 |
+
* @param string $title Used in messages
|
133 |
+
*
|
134 |
+
* @return string|WP_Error
|
135 |
+
*/
|
136 |
+
private function get_latest_version( $user_slash_repo, $force_check, $title ) {
|
137 |
+
if ( ! preg_match( $this->manifest_key_regex, $user_slash_repo ) ) {
|
138 |
+
return new WP_Error( 'fw_ext_update_github_manifest_invalid',
|
139 |
+
sprintf(
|
140 |
+
__( '%s manifest has invalid "github_update" parameter. Please use "user/repo" format.', 'fw' ),
|
141 |
+
$title
|
142 |
+
)
|
143 |
+
);
|
144 |
+
}
|
145 |
+
|
146 |
+
$transient_id = 'fw_ext_upd_gh_fw'; // the length must be 45 characters or less
|
147 |
+
|
148 |
+
if ( $force_check ) {
|
149 |
+
delete_site_transient( $transient_id );
|
150 |
+
|
151 |
+
$cache = array();
|
152 |
+
} else {
|
153 |
+
$cache = get_site_transient( $transient_id );
|
154 |
+
|
155 |
+
if ( $cache === false ) {
|
156 |
+
$cache = array();
|
157 |
+
} elseif ( isset( $cache[ $user_slash_repo ] ) ) {
|
158 |
+
return $cache[ $user_slash_repo ];
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
$latest_version = $this->fetch_latest_version( $user_slash_repo );
|
163 |
+
|
164 |
+
if ( empty( $latest_version ) ) {
|
165 |
+
return new WP_Error(
|
166 |
+
'fw_ext_update_github_failed_fetch_latest_version',
|
167 |
+
sprintf(
|
168 |
+
__( 'Failed to fetch %s latest version from github "%s".', 'fw' ),
|
169 |
+
$title, $user_slash_repo
|
170 |
+
)
|
171 |
+
);
|
172 |
+
}
|
173 |
+
|
174 |
+
if ( is_wp_error( $latest_version ) ) {
|
175 |
+
/**
|
176 |
+
* Internet connection problems or Github API requests limit reached.
|
177 |
+
* Cache fake version to prevent requests to Github API on every refresh.
|
178 |
+
*/
|
179 |
+
$cache = array_merge( $cache, array( $user_slash_repo => $this->fake_latest_version ) );
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Show the error to the user because it is not visible elsewhere
|
183 |
+
*/
|
184 |
+
FW_Flash_Messages::add(
|
185 |
+
'fw_ext_github_update_error',
|
186 |
+
$latest_version->get_error_message(),
|
187 |
+
'error'
|
188 |
+
);
|
189 |
+
} else {
|
190 |
+
$cache = array_merge( $cache, array( $user_slash_repo => $latest_version ) );
|
191 |
+
}
|
192 |
+
|
193 |
+
set_site_transient(
|
194 |
+
$transient_id,
|
195 |
+
$cache,
|
196 |
+
$this->transient_expiration
|
197 |
+
);
|
198 |
+
|
199 |
+
return $latest_version;
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* @param string $user_slash_repo Github 'user/repo'
|
204 |
+
* @param string $version Requested version to download
|
205 |
+
* @param string $wp_filesystem_download_directory Allocated temporary empty directory
|
206 |
+
* @param string $title Used in messages
|
207 |
+
*
|
208 |
+
* @return string|WP_Error Path to the downloaded directory
|
209 |
+
*/
|
210 |
+
private function download( $user_slash_repo, $version, $wp_filesystem_download_directory, $title ) {
|
211 |
+
$http = new WP_Http();
|
212 |
+
|
213 |
+
$response = $http->get(
|
214 |
+
$this->get_github_api_url( '/repos/' . $user_slash_repo . '/releases/tags/' . $version )
|
215 |
+
);
|
216 |
+
|
217 |
+
unset( $http );
|
218 |
+
|
219 |
+
$response_code = intval( wp_remote_retrieve_response_code( $response ) );
|
220 |
+
|
221 |
+
if ( $response_code !== 200 ) {
|
222 |
+
if ( $response_code === 403 ) {
|
223 |
+
$json_response = json_decode( $response['body'], true );
|
224 |
+
|
225 |
+
if ( $json_response ) {
|
226 |
+
return new WP_Error(
|
227 |
+
'fw_ext_update_github_download_releases_failed',
|
228 |
+
__( 'Github error:', 'fw' ) . ' ' . $json_response['message']
|
229 |
+
);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
if ( $response_code ) {
|
234 |
+
return new WP_Error(
|
235 |
+
'fw_ext_update_github_download_releases_failed',
|
236 |
+
sprintf(
|
237 |
+
__( 'Failed to access Github repository "%s" releases. (Response code: %d)', 'fw' ),
|
238 |
+
$user_slash_repo, $response_code
|
239 |
+
)
|
240 |
+
);
|
241 |
+
} else {
|
242 |
+
return new WP_Error(
|
243 |
+
'fw_ext_update_github_download_releases_failed',
|
244 |
+
sprintf(
|
245 |
+
__( 'Failed to access Github repository "%s" releases.', 'fw' ),
|
246 |
+
$user_slash_repo
|
247 |
+
)
|
248 |
+
);
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
$release = json_decode( $response['body'], true );
|
253 |
+
|
254 |
+
unset( $response );
|
255 |
+
|
256 |
+
if ( empty( $release ) ) {
|
257 |
+
return new WP_Error(
|
258 |
+
'fw_ext_update_github_download_no_release',
|
259 |
+
sprintf(
|
260 |
+
__( '%s github repository "%s" does not have the "%s" release.', 'fw' ),
|
261 |
+
$title, $user_slash_repo, $version
|
262 |
+
)
|
263 |
+
);
|
264 |
+
}
|
265 |
+
|
266 |
+
$http = new WP_Http();
|
267 |
+
|
268 |
+
$response = $http->request(
|
269 |
+
'https://github.com/' . $user_slash_repo . '/archive/' . $release['tag_name'] . '.zip',
|
270 |
+
array(
|
271 |
+
'timeout' => $this->download_timeout,
|
272 |
+
)
|
273 |
+
);
|
274 |
+
|
275 |
+
unset( $http );
|
276 |
+
|
277 |
+
if ( intval( wp_remote_retrieve_response_code( $response ) ) !== 200 ) {
|
278 |
+
return new WP_Error(
|
279 |
+
'fw_ext_update_github_download_failed',
|
280 |
+
sprintf( __( 'Cannot download %s zip.', 'fw' ), $title )
|
281 |
+
);
|
282 |
+
}
|
283 |
+
|
284 |
+
/** @var WP_Filesystem_Base $wp_filesystem */
|
285 |
+
global $wp_filesystem;
|
286 |
+
|
287 |
+
$zip_path = $wp_filesystem_download_directory . '/temp.zip';
|
288 |
+
|
289 |
+
// save zip to file
|
290 |
+
if ( ! $wp_filesystem->put_contents( $zip_path, $response['body'] ) ) {
|
291 |
+
return new WP_Error(
|
292 |
+
'fw_ext_update_github_save_download_failed',
|
293 |
+
sprintf( __( 'Cannot save %s zip.', 'fw' ), $title )
|
294 |
+
);
|
295 |
+
}
|
296 |
+
|
297 |
+
unset( $response );
|
298 |
+
|
299 |
+
$unzip_result = unzip_file(
|
300 |
+
FW_WP_Filesystem::filesystem_path_to_real_path( $zip_path ),
|
301 |
+
$wp_filesystem_download_directory
|
302 |
+
);
|
303 |
+
|
304 |
+
if ( is_wp_error( $unzip_result ) ) {
|
305 |
+
return $unzip_result;
|
306 |
+
}
|
307 |
+
|
308 |
+
// remove zip file
|
309 |
+
if ( ! $wp_filesystem->delete( $zip_path, false, 'f' ) ) {
|
310 |
+
return new WP_Error(
|
311 |
+
'fw_ext_update_github_remove_downloaded_zip_failed',
|
312 |
+
sprintf( __( 'Cannot remove %s zip.', 'fw' ), $title )
|
313 |
+
);
|
314 |
+
}
|
315 |
+
|
316 |
+
$unzipped_dir_files = $wp_filesystem->dirlist( $wp_filesystem_download_directory );
|
317 |
+
|
318 |
+
if ( ! $unzipped_dir_files ) {
|
319 |
+
return new WP_Error(
|
320 |
+
'fw_ext_update_github_unzipped_dir_fail',
|
321 |
+
__( 'Cannot access the unzipped directory files.', 'fw' )
|
322 |
+
);
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* get first found directory
|
327 |
+
* (if everything worked well, there should be only one directory)
|
328 |
+
*/
|
329 |
+
foreach ( $unzipped_dir_files as $file ) {
|
330 |
+
if ( $file['type'] == 'd' ) {
|
331 |
+
return $wp_filesystem_download_directory . '/' . $file['name'];
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
return new WP_Error(
|
336 |
+
'fw_ext_update_github_unzipped_dir_not_found',
|
337 |
+
sprintf( __( 'The unzipped %s directory not found.', 'fw' ), $title )
|
338 |
+
);
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* {@inheritdoc}
|
343 |
+
* @internal
|
344 |
+
*/
|
345 |
+
public function _get_framework_latest_version( $force_check ) {
|
346 |
+
$user_slash_repo = fw()->manifest->get( $this->manifest_key );
|
347 |
+
|
348 |
+
if ( empty( $user_slash_repo ) ) {
|
349 |
+
return false;
|
350 |
+
}
|
351 |
+
|
352 |
+
return $this->get_latest_version(
|
353 |
+
$user_slash_repo,
|
354 |
+
$force_check,
|
355 |
+
__( 'Framework', 'fw' )
|
356 |
+
);
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* {@inheritdoc}
|
361 |
+
* @internal
|
362 |
+
*/
|
363 |
+
public function _download_framework( $version, $wp_filesystem_download_directory ) {
|
364 |
+
return $this->download(
|
365 |
+
fw()->manifest->get( $this->manifest_key ),
|
366 |
+
$version,
|
367 |
+
$wp_filesystem_download_directory,
|
368 |
+
__( 'Framework', 'fw' )
|
369 |
+
);
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* {@inheritdoc}
|
374 |
+
* @internal
|
375 |
+
*/
|
376 |
+
public function _get_theme_latest_version( $force_check ) {
|
377 |
+
$user_slash_repo = fw()->theme->manifest->get( $this->manifest_key );
|
378 |
+
|
379 |
+
if ( empty( $user_slash_repo ) ) {
|
380 |
+
return false;
|
381 |
+
}
|
382 |
+
|
383 |
+
return $this->get_latest_version(
|
384 |
+
$user_slash_repo,
|
385 |
+
$force_check,
|
386 |
+
__( 'Theme', 'fw' )
|
387 |
+
);
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* {@inheritdoc}
|
392 |
+
* @internal
|
393 |
+
*/
|
394 |
+
public function _download_theme( $version, $wp_filesystem_download_directory ) {
|
395 |
+
return $this->download(
|
396 |
+
fw()->theme->manifest->get( $this->manifest_key ),
|
397 |
+
$version,
|
398 |
+
$wp_filesystem_download_directory,
|
399 |
+
__( 'Theme', 'fw' )
|
400 |
+
);
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* {@inheritdoc}
|
405 |
+
* @internal
|
406 |
+
*/
|
407 |
+
public function _get_extension_latest_version( FW_Extension $extension, $force_check ) {
|
408 |
+
$user_slash_repo = $extension->manifest->get( $this->manifest_key );
|
409 |
+
|
410 |
+
if ( empty( $user_slash_repo ) ) {
|
411 |
+
return false;
|
412 |
+
}
|
413 |
+
|
414 |
+
return $this->get_latest_version(
|
415 |
+
$user_slash_repo,
|
416 |
+
$force_check,
|
417 |
+
sprintf( __( '%s extension', 'fw' ), $extension->manifest->get_name() )
|
418 |
+
);
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* {@inheritdoc}
|
423 |
+
* @internal
|
424 |
+
*/
|
425 |
+
public function _download_extension( FW_Extension $extension, $version, $wp_filesystem_download_directory ) {
|
426 |
+
return $this->download(
|
427 |
+
$extension->manifest->get( $this->manifest_key ),
|
428 |
+
$version,
|
429 |
+
$wp_filesystem_download_directory,
|
430 |
+
sprintf( __( '%s extension', 'fw' ), $extension->manifest->get_name() )
|
431 |
+
);
|
432 |
+
}
|
433 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
framework/extensions/update/extensions/github-update/manifest.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
$manifest = array();
|
4 |
-
|
5 |
-
$manifest['standalone'] = true;
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
$manifest = array();
|
4 |
+
|
5 |
+
$manifest['standalone'] = true;
|
framework/extensions/update/includes/classes/class--fw-ext-update-extensions-list-table.php
CHANGED
@@ -1,128 +1,128 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Display extensions with updates on the Update Page
|
5 |
-
*/
|
6 |
-
class _FW_Ext_Update_Extensions_List_Table extends WP_List_Table
|
7 |
-
{
|
8 |
-
private $items_pre_page = 1000;
|
9 |
-
|
10 |
-
private $total_items = null;
|
11 |
-
|
12 |
-
private $_extensions = array();
|
13 |
-
|
14 |
-
private $_table_columns = array();
|
15 |
-
private $_table_columns_count = 0;
|
16 |
-
|
17 |
-
public function __construct($args)
|
18 |
-
{
|
19 |
-
parent::__construct(array(
|
20 |
-
'screen' => 'fw-ext-update-extensions-update'
|
21 |
-
));
|
22 |
-
|
23 |
-
$this->_extensions = $args['extensions'];
|
24 |
-
|
25 |
-
$this->_table_columns = array(
|
26 |
-
'cb' => '<input type="checkbox" />',
|
27 |
-
'details' => fw_html_tag(
|
28 |
-
'a',
|
29 |
-
array(
|
30 |
-
'href' => '#',
|
31 |
-
'onclick' => "jQuery(this).closest('tr').find('input[type=\"checkbox\"]:first').trigger('click'); return false;"
|
32 |
-
),
|
33 |
-
__('Select All', 'fw')
|
34 |
-
),
|
35 |
-
);
|
36 |
-
$this->_table_columns_count = count($this->_table_columns);
|
37 |
-
}
|
38 |
-
|
39 |
-
public function get_columns()
|
40 |
-
{
|
41 |
-
return $this->_table_columns;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function prepare_items()
|
45 |
-
{
|
46 |
-
if ($this->total_items !== null) {
|
47 |
-
return;
|
48 |
-
}
|
49 |
-
|
50 |
-
$this->total_items = count($this->_extensions);
|
51 |
-
|
52 |
-
$this->set_pagination_args(array(
|
53 |
-
'total_items' => $this->total_items,
|
54 |
-
'per_page' => $this->items_pre_page,
|
55 |
-
));
|
56 |
-
|
57 |
-
$page_num = $this->get_pagenum();
|
58 |
-
$offset = ($page_num - 1) * $this->items_pre_page;
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Prepare items for output
|
62 |
-
*/
|
63 |
-
foreach ($this->_extensions as $ext_name => $ext_update) {
|
64 |
-
$extension = fw()->extensions->get($ext_name);
|
65 |
-
|
66 |
-
if (is_wp_error($ext_update)) {
|
67 |
-
$this->items[] = array(
|
68 |
-
'cb' => '<input type="checkbox" disabled />',
|
69 |
-
'details' =>
|
70 |
-
'<p>'.
|
71 |
-
'<strong>'. fw_htmlspecialchars($extension->manifest->get_name()) .'</strong>'.
|
72 |
-
'<br/>'.
|
73 |
-
'<span class="wp-ui-text-notification">'. $ext_update->get_error_message() .'</span>'.
|
74 |
-
'</p>',
|
75 |
-
);
|
76 |
-
} else {
|
77 |
-
$this->items[] = array(
|
78 |
-
'cb' => '<input type="checkbox" name="extensions['. esc_attr($ext_name) .']" />',
|
79 |
-
'details' =>
|
80 |
-
'<p>'.
|
81 |
-
'<strong>'. fw_htmlspecialchars($extension->manifest->get_name()) .'</strong>'.
|
82 |
-
'<br/>'.
|
83 |
-
sprintf(
|
84 |
-
__('You have version %s installed. Update to %s.', 'fw'),
|
85 |
-
$extension->manifest->get_version(), fw_htmlspecialchars($ext_update['fixed_latest_version'])
|
86 |
-
).
|
87 |
-
'</p>',
|
88 |
-
);
|
89 |
-
}
|
90 |
-
}
|
91 |
-
}
|
92 |
-
|
93 |
-
public function has_items()
|
94 |
-
{
|
95 |
-
$this->prepare_items();
|
96 |
-
|
97 |
-
return $this->total_items;
|
98 |
-
}
|
99 |
-
|
100 |
-
/**
|
101 |
-
* (override parent)
|
102 |
-
*/
|
103 |
-
function single_row($item)
|
104 |
-
{
|
105 |
-
static $row_class = '';
|
106 |
-
|
107 |
-
$row_class = ( $row_class == '' ? ' class="alternate"' : '' );
|
108 |
-
|
109 |
-
echo '<tr' . $row_class . '>';
|
110 |
-
echo $this->single_row_columns( $item );
|
111 |
-
echo '</tr>';
|
112 |
-
}
|
113 |
-
|
114 |
-
protected function column_cb($item)
|
115 |
-
{
|
116 |
-
echo $item['cb'];
|
117 |
-
}
|
118 |
-
|
119 |
-
protected function column_default($item, $column_name)
|
120 |
-
{
|
121 |
-
echo $item[$column_name];
|
122 |
-
}
|
123 |
-
|
124 |
-
function no_items()
|
125 |
-
{
|
126 |
-
_e('No Extensions for update.', 'fw');
|
127 |
-
}
|
128 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Display extensions with updates on the Update Page
|
5 |
+
*/
|
6 |
+
class _FW_Ext_Update_Extensions_List_Table extends WP_List_Table
|
7 |
+
{
|
8 |
+
private $items_pre_page = 1000;
|
9 |
+
|
10 |
+
private $total_items = null;
|
11 |
+
|
12 |
+
private $_extensions = array();
|
13 |
+
|
14 |
+
private $_table_columns = array();
|
15 |
+
private $_table_columns_count = 0;
|
16 |
+
|
17 |
+
public function __construct($args)
|
18 |
+
{
|
19 |
+
parent::__construct(array(
|
20 |
+
'screen' => 'fw-ext-update-extensions-update'
|
21 |
+
));
|
22 |
+
|
23 |
+
$this->_extensions = $args['extensions'];
|
24 |
+
|
25 |
+
$this->_table_columns = array(
|
26 |
+
'cb' => '<input type="checkbox" />',
|
27 |
+
'details' => fw_html_tag(
|
28 |
+
'a',
|
29 |
+
array(
|
30 |
+
'href' => '#',
|
31 |
+
'onclick' => "jQuery(this).closest('tr').find('input[type=\"checkbox\"]:first').trigger('click'); return false;"
|
32 |
+
),
|
33 |
+
__('Select All', 'fw')
|
34 |
+
),
|
35 |
+
);
|
36 |
+
$this->_table_columns_count = count($this->_table_columns);
|
37 |
+
}
|
38 |
+
|
39 |
+
public function get_columns()
|
40 |
+
{
|
41 |
+
return $this->_table_columns;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function prepare_items()
|
45 |
+
{
|
46 |
+
if ($this->total_items !== null) {
|
47 |
+
return;
|
48 |
+
}
|
49 |
+
|
50 |
+
$this->total_items = count($this->_extensions);
|
51 |
+
|
52 |
+
$this->set_pagination_args(array(
|
53 |
+
'total_items' => $this->total_items,
|
54 |
+
'per_page' => $this->items_pre_page,
|
55 |
+
));
|
56 |
+
|
57 |
+
$page_num = $this->get_pagenum();
|
58 |
+
$offset = ($page_num - 1) * $this->items_pre_page;
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Prepare items for output
|
62 |
+
*/
|
63 |
+
foreach ($this->_extensions as $ext_name => $ext_update) {
|
64 |
+
$extension = fw()->extensions->get($ext_name);
|
65 |
+
|
66 |
+
if (is_wp_error($ext_update)) {
|
67 |
+
$this->items[] = array(
|
68 |
+
'cb' => '<input type="checkbox" disabled />',
|
69 |
+
'details' =>
|
70 |
+
'<p>'.
|
71 |
+
'<strong>'. fw_htmlspecialchars($extension->manifest->get_name()) .'</strong>'.
|
72 |
+
'<br/>'.
|
73 |
+
'<span class="wp-ui-text-notification">'. $ext_update->get_error_message() .'</span>'.
|
74 |
+
'</p>',
|
75 |
+
);
|
76 |
+
} else {
|
77 |
+
$this->items[] = array(
|
78 |
+
'cb' => '<input type="checkbox" name="extensions['. esc_attr($ext_name) .']" />',
|
79 |
+
'details' =>
|
80 |
+
'<p>'.
|
81 |
+
'<strong>'. fw_htmlspecialchars($extension->manifest->get_name()) .'</strong>'.
|
82 |
+
'<br/>'.
|
83 |
+
sprintf(
|
84 |
+
__('You have version %s installed. Update to %s.', 'fw'),
|
85 |
+
$extension->manifest->get_version(), fw_htmlspecialchars($ext_update['fixed_latest_version'])
|
86 |
+
).
|
87 |
+
'</p>',
|
88 |
+
);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
public function has_items()
|
94 |
+
{
|
95 |
+
$this->prepare_items();
|
96 |
+
|
97 |
+
return $this->total_items;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* (override parent)
|
102 |
+
*/
|
103 |
+
function single_row($item)
|
104 |
+
{
|
105 |
+
static $row_class = '';
|
106 |
+
|
107 |
+
$row_class = ( $row_class == '' ? ' class="alternate"' : '' );
|
108 |
+
|
109 |
+
echo '<tr' . $row_class . '>';
|
110 |
+
echo $this->single_row_columns( $item );
|
111 |
+
echo '</tr>';
|
112 |
+
}
|
113 |
+
|
114 |
+
protected function column_cb($item)
|
115 |
+
{
|
116 |
+
echo $item['cb'];
|
117 |
+
}
|
118 |
+
|
119 |
+
protected function column_default($item, $column_name)
|
120 |
+
{
|
121 |
+
echo $item[$column_name];
|
122 |
+
}
|
123 |
+
|
124 |
+
function no_items()
|
125 |
+
{
|
126 |
+
_e('No Extensions for update.', 'fw');
|
127 |
+
}
|
128 |
+
}
|
framework/extensions/update/includes/classes/class--fw-ext-update-extensions-upgrader-skin.php
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
-
|
5 |
-
class _FW_Ext_Update_Extensions_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
-
{
|
7 |
-
public function after()
|
8 |
-
{
|
9 |
-
$update_actions = array(
|
10 |
-
'updates_page' => fw_html_tag(
|
11 |
-
'a',
|
12 |
-
array(
|
13 |
-
'href' => self_admin_url('update-core.php'),
|
14 |
-
'title' => __('Go to updates page', 'fw'),
|
15 |
-
'target' => '_parent',
|
16 |
-
),
|
17 |
-
__('Return to Updates page', 'fw')
|
18 |
-
)
|
19 |
-
);
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Filter the list of action links available following extensions update.
|
23 |
-
* @param array $update_actions Array of plugin action links.
|
24 |
-
*/
|
25 |
-
$update_actions = apply_filters('fw_ext_update_extensions_complete_actions', $update_actions);
|
26 |
-
|
27 |
-
if (!empty($update_actions)) {
|
28 |
-
$this->feedback(implode(' | ', (array)$update_actions));
|
29 |
-
}
|
30 |
-
}
|
31 |
-
|
32 |
-
public function decrement_extension_update_count($extension_name)
|
33 |
-
{
|
34 |
-
$this->decrement_update_count('fw:extension:'. $extension_name);
|
35 |
-
}
|
36 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
+
|
5 |
+
class _FW_Ext_Update_Extensions_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
+
{
|
7 |
+
public function after()
|
8 |
+
{
|
9 |
+
$update_actions = array(
|
10 |
+
'updates_page' => fw_html_tag(
|
11 |
+
'a',
|
12 |
+
array(
|
13 |
+
'href' => self_admin_url('update-core.php'),
|
14 |
+
'title' => __('Go to updates page', 'fw'),
|
15 |
+
'target' => '_parent',
|
16 |
+
),
|
17 |
+
__('Return to Updates page', 'fw')
|
18 |
+
)
|
19 |
+
);
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Filter the list of action links available following extensions update.
|
23 |
+
* @param array $update_actions Array of plugin action links.
|
24 |
+
*/
|
25 |
+
$update_actions = apply_filters('fw_ext_update_extensions_complete_actions', $update_actions);
|
26 |
+
|
27 |
+
if (!empty($update_actions)) {
|
28 |
+
$this->feedback(implode(' | ', (array)$update_actions));
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
public function decrement_extension_update_count($extension_name)
|
33 |
+
{
|
34 |
+
$this->decrement_update_count('fw:extension:'. $extension_name);
|
35 |
+
}
|
36 |
+
}
|
framework/extensions/update/includes/classes/class--fw-ext-update-framework-upgrader-skin.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
-
|
5 |
-
class _FW_Ext_Update_Framework_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
-
{
|
7 |
-
public function after()
|
8 |
-
{
|
9 |
-
$this->decrement_update_count('fw');
|
10 |
-
|
11 |
-
$update_actions = array(
|
12 |
-
'updates_page' => fw_html_tag(
|
13 |
-
'a',
|
14 |
-
array(
|
15 |
-
'href' => self_admin_url('update-core.php'),
|
16 |
-
'title' => __('Go to updates page', 'fw'),
|
17 |
-
'target' => '_parent',
|
18 |
-
),
|
19 |
-
__('Return to Updates page', 'fw')
|
20 |
-
)
|
21 |
-
);
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Filter the list of action links available following framework update.
|
25 |
-
* @param array $update_actions Array of plugin action links.
|
26 |
-
*/
|
27 |
-
$update_actions = apply_filters('fw_ext_update_framework_complete_actions', $update_actions);
|
28 |
-
|
29 |
-
if (!empty($update_actions)) {
|
30 |
-
$this->feedback(implode(' | ', (array)$update_actions));
|
31 |
-
}
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
+
|
5 |
+
class _FW_Ext_Update_Framework_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
+
{
|
7 |
+
public function after()
|
8 |
+
{
|
9 |
+
$this->decrement_update_count('fw');
|
10 |
+
|
11 |
+
$update_actions = array(
|
12 |
+
'updates_page' => fw_html_tag(
|
13 |
+
'a',
|
14 |
+
array(
|
15 |
+
'href' => self_admin_url('update-core.php'),
|
16 |
+
'title' => __('Go to updates page', 'fw'),
|
17 |
+
'target' => '_parent',
|
18 |
+
),
|
19 |
+
__('Return to Updates page', 'fw')
|
20 |
+
)
|
21 |
+
);
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Filter the list of action links available following framework update.
|
25 |
+
* @param array $update_actions Array of plugin action links.
|
26 |
+
*/
|
27 |
+
$update_actions = apply_filters('fw_ext_update_framework_complete_actions', $update_actions);
|
28 |
+
|
29 |
+
if (!empty($update_actions)) {
|
30 |
+
$this->feedback(implode(' | ', (array)$update_actions));
|
31 |
+
}
|
32 |
+
}
|
33 |
+
}
|
framework/extensions/update/includes/classes/class--fw-ext-update-theme-upgrader-skin.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
-
|
5 |
-
class _FW_Ext_Update_Theme_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
-
{
|
7 |
-
public function after()
|
8 |
-
{
|
9 |
-
$this->decrement_update_count('fw:theme');
|
10 |
-
|
11 |
-
$update_actions = array(
|
12 |
-
'updates_page' => fw_html_tag(
|
13 |
-
'a',
|
14 |
-
array(
|
15 |
-
'href' => self_admin_url('update-core.php'),
|
16 |
-
'title' => __('Go to updates page', 'fw'),
|
17 |
-
'target' => '_parent',
|
18 |
-
),
|
19 |
-
__('Return to Updates page', 'fw')
|
20 |
-
)
|
21 |
-
);
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Filter the list of action links available following theme update.
|
25 |
-
* @param array $update_actions Array of plugin action links.
|
26 |
-
*/
|
27 |
-
$update_actions = apply_filters('fw_ext_update_theme_complete_actions', $update_actions);
|
28 |
-
|
29 |
-
if (!empty($update_actions)) {
|
30 |
-
$this->feedback(implode(' | ', (array)$update_actions));
|
31 |
-
}
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
4 |
+
|
5 |
+
class _FW_Ext_Update_Theme_Upgrader_Skin extends WP_Upgrader_Skin
|
6 |
+
{
|
7 |
+
public function after()
|
8 |
+
{
|
9 |
+
$this->decrement_update_count('fw:theme');
|
10 |
+
|
11 |
+
$update_actions = array(
|
12 |
+
'updates_page' => fw_html_tag(
|
13 |
+
'a',
|
14 |
+
array(
|
15 |
+
'href' => self_admin_url('update-core.php'),
|
16 |
+
'title' => __('Go to updates page', 'fw'),
|
17 |
+
'target' => '_parent',
|
18 |
+
),
|
19 |
+
__('Return to Updates page', 'fw')
|
20 |
+
)
|
21 |
+
);
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Filter the list of action links available following theme update.
|
25 |
+
* @param array $update_actions Array of plugin action links.
|
26 |
+
*/
|
27 |
+
$update_actions = apply_filters('fw_ext_update_theme_complete_actions', $update_actions);
|
28 |
+
|
29 |
+
if (!empty($update_actions)) {
|
30 |
+
$this->feedback(implode(' | ', (array)$update_actions));
|
31 |
+
}
|
32 |
+
}
|
33 |
+
}
|
framework/extensions/update/includes/extends/class-fw-ext-update-service.php
CHANGED
@@ -1,105 +1,105 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Extend this class if you want to create a new update service
|
5 |
-
*/
|
6 |
-
abstract class FW_Ext_Update_Service extends FW_Extension
|
7 |
-
{
|
8 |
-
/**
|
9 |
-
* Return latest version of the framework if this service supports framework update
|
10 |
-
*
|
11 |
-
* @param bool $force_check Check now, do not use cache
|
12 |
-
* @return string|false|WP_Error
|
13 |
-
* false Does not know how to work with extension.
|
14 |
-
* WP_Error Knows how to work with it, but there is an error
|
15 |
-
* string Everything is ok, here is latest version
|
16 |
-
*
|
17 |
-
* @internal
|
18 |
-
*/
|
19 |
-
public function _get_framework_latest_version($force_check)
|
20 |
-
{
|
21 |
-
return false;
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Download (and extract) framework files
|
26 |
-
*
|
27 |
-
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
28 |
-
*
|
29 |
-
* @param $version Version to download
|
30 |
-
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
31 |
-
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
32 |
-
*
|
33 |
-
* @internal
|
34 |
-
*/
|
35 |
-
public function _download_framework($version, $wp_filesystem_download_directory)
|
36 |
-
{
|
37 |
-
return false;
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Return latest version of the theme if this service supports theme update
|
42 |
-
*
|
43 |
-
* @param bool $force_check Check now, do not use cache
|
44 |
-
* @return string|false|WP_Error
|
45 |
-
* false Does not know how to work with extension.
|
46 |
-
* WP_Error Knows how to work with it, but there is an error
|
47 |
-
* string Everything is ok, here is latest version
|
48 |
-
*
|
49 |
-
* @internal
|
50 |
-
*/
|
51 |
-
public function _get_theme_latest_version($force_check)
|
52 |
-
{
|
53 |
-
return false;
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Download (and extract) theme files
|
58 |
-
*
|
59 |
-
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
60 |
-
*
|
61 |
-
* @param $version Version to download
|
62 |
-
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
63 |
-
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
64 |
-
*
|
65 |
-
* @internal
|
66 |
-
*/
|
67 |
-
public function _download_theme($version, $wp_filesystem_download_directory)
|
68 |
-
{
|
69 |
-
return false;
|
70 |
-
}
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Return latest version of the extension if this service supports extension update
|
74 |
-
*
|
75 |
-
* @param FW_Extension $extension
|
76 |
-
* @param bool $force_check Check now, do not use cache
|
77 |
-
* @return string|false|WP_Error
|
78 |
-
* false Does not know how to work with extension.
|
79 |
-
* WP_Error Knows how to work with it, but there is an error
|
80 |
-
* string Everything is ok, here is latest version
|
81 |
-
*
|
82 |
-
* @internal
|
83 |
-
*/
|
84 |
-
public function _get_extension_latest_version(FW_Extension $extension, $force_check)
|
85 |
-
{
|
86 |
-
return false;
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Download (and extract) extension
|
91 |
-
*
|
92 |
-
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
93 |
-
*
|
94 |
-
* @param FW_Extension $extension
|
95 |
-
* @param $version Version to download
|
96 |
-
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
97 |
-
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
98 |
-
*
|
99 |
-
* @internal
|
100 |
-
*/
|
101 |
-
public function _download_extension(FW_Extension $extension, $version, $wp_filesystem_download_directory)
|
102 |
-
{
|
103 |
-
return false;
|
104 |
-
}
|
105 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Extend this class if you want to create a new update service
|
5 |
+
*/
|
6 |
+
abstract class FW_Ext_Update_Service extends FW_Extension
|
7 |
+
{
|
8 |
+
/**
|
9 |
+
* Return latest version of the framework if this service supports framework update
|
10 |
+
*
|
11 |
+
* @param bool $force_check Check now, do not use cache
|
12 |
+
* @return string|false|WP_Error
|
13 |
+
* false Does not know how to work with extension.
|
14 |
+
* WP_Error Knows how to work with it, but there is an error
|
15 |
+
* string Everything is ok, here is latest version
|
16 |
+
*
|
17 |
+
* @internal
|
18 |
+
*/
|
19 |
+
public function _get_framework_latest_version($force_check)
|
20 |
+
{
|
21 |
+
return false;
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Download (and extract) framework files
|
26 |
+
*
|
27 |
+
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
28 |
+
*
|
29 |
+
* @param $version Version to download
|
30 |
+
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
31 |
+
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
32 |
+
*
|
33 |
+
* @internal
|
34 |
+
*/
|
35 |
+
public function _download_framework($version, $wp_filesystem_download_directory)
|
36 |
+
{
|
37 |
+
return false;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Return latest version of the theme if this service supports theme update
|
42 |
+
*
|
43 |
+
* @param bool $force_check Check now, do not use cache
|
44 |
+
* @return string|false|WP_Error
|
45 |
+
* false Does not know how to work with extension.
|
46 |
+
* WP_Error Knows how to work with it, but there is an error
|
47 |
+
* string Everything is ok, here is latest version
|
48 |
+
*
|
49 |
+
* @internal
|
50 |
+
*/
|
51 |
+
public function _get_theme_latest_version($force_check)
|
52 |
+
{
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Download (and extract) theme files
|
58 |
+
*
|
59 |
+
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
60 |
+
*
|
61 |
+
* @param $version Version to download
|
62 |
+
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
63 |
+
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
64 |
+
*
|
65 |
+
* @internal
|
66 |
+
*/
|
67 |
+
public function _download_theme($version, $wp_filesystem_download_directory)
|
68 |
+
{
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Return latest version of the extension if this service supports extension update
|
74 |
+
*
|
75 |
+
* @param FW_Extension $extension
|
76 |
+
* @param bool $force_check Check now, do not use cache
|
77 |
+
* @return string|false|WP_Error
|
78 |
+
* false Does not know how to work with extension.
|
79 |
+
* WP_Error Knows how to work with it, but there is an error
|
80 |
+
* string Everything is ok, here is latest version
|
81 |
+
*
|
82 |
+
* @internal
|
83 |
+
*/
|
84 |
+
public function _get_extension_latest_version(FW_Extension $extension, $force_check)
|
85 |
+
{
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Download (and extract) extension
|
91 |
+
*
|
92 |
+
* ! Work with global $wp_filesystem; Do not use base php filesystem functions
|
93 |
+
*
|
94 |
+
* @param FW_Extension $extension
|
95 |
+
* @param $version Version to download
|
96 |
+
* @param string $wp_filesystem_download_directory Empty directory offered for download files in it
|
97 |
+
* @return string|false|WP_Error Path to WP Filesystem directory with downloaded (and extracted) files
|
98 |
+
*
|
99 |
+
* @internal
|
100 |
+
*/
|
101 |
+
public function _download_extension(FW_Extension $extension, $version, $wp_filesystem_download_directory)
|
102 |
+
{
|
103 |
+
return false;
|
104 |
+
}
|
105 |
+
}
|
framework/extensions/update/manifest.php
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
$manifest = array();
|
4 |
-
|
5 |
-
$manifest['name'] = __('Update', 'fw');
|
6 |
-
$manifest['description'] = __('Keep you framework, extensions and theme up to date.', 'fw');
|
7 |
-
$manifest['standalone'] = true;
|
8 |
-
|
9 |
-
$manifest['version'] = '1.0.12';
|
10 |
-
$manifest['github_update'] = 'ThemeFuse/Unyson-Update-Extension';
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
$manifest = array();
|
4 |
+
|
5 |
+
$manifest['name'] = __('Update', 'fw');
|
6 |
+
$manifest['description'] = __('Keep you framework, extensions and theme up to date.', 'fw');
|
7 |
+
$manifest['standalone'] = true;
|
8 |
+
|
9 |
+
$manifest['version'] = '1.0.12';
|
10 |
+
$manifest['github_update'] = 'ThemeFuse/Unyson-Update-Extension';
|
framework/extensions/update/static.php
CHANGED
@@ -1,14 +1,14 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
$extension = fw()->extensions->get('update');
|
4 |
-
|
5 |
-
if (fw_current_screen_match(array('only' => array(array('id' => 'update-core'))))) {
|
6 |
-
// Include only on update page
|
7 |
-
|
8 |
-
wp_enqueue_style(
|
9 |
-
'fw-ext-'. $extension->get_name() .'-update-page',
|
10 |
-
$extension->get_declared_URI('/static/css/admin-update-page.css'),
|
11 |
-
array(),
|
12 |
-
$extension->manifest->get_version()
|
13 |
-
);
|
14 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
$extension = fw()->extensions->get('update');
|
4 |
+
|
5 |
+
if (fw_current_screen_match(array('only' => array(array('id' => 'update-core'))))) {
|
6 |
+
// Include only on update page
|
7 |
+
|
8 |
+
wp_enqueue_style(
|
9 |
+
'fw-ext-'. $extension->get_name() .'-update-page',
|
10 |
+
$extension->get_declared_URI('/static/css/admin-update-page.css'),
|
11 |
+
array(),
|
12 |
+
$extension->manifest->get_version()
|
13 |
+
);
|
14 |
+
}
|
framework/extensions/update/static/css/admin-update-page.css
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
-
#fw-ext-update-extensions .tablenav {
|
2 |
-
display: none;
|
3 |
}
|
1 |
+
#fw-ext-update-extensions .tablenav {
|
2 |
+
display: none;
|
3 |
}
|
framework/extensions/update/views/updates-list.php
CHANGED
@@ -1,113 +1,118 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
<?php if ($updates['framework']
|
8 |
-
<
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
</div>
|
30 |
-
<?php endif; ?>
|
31 |
-
|
32 |
-
<?php if ($updates['theme'] !== false): ?>
|
33 |
-
<div id="fw-ext-update-theme">
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
<?php
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
<?php
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php defined( 'FW' ) or die(); ?>
|
2 |
+
|
3 |
+
<?php if ( $updates['framework'] !== false ): ?>
|
4 |
+
<div id="fw-ext-update-framework">
|
5 |
+
<a name="fw-framework"></a>
|
6 |
+
<h3><?php _e( 'Framework', 'fw' ) ?></h3>
|
7 |
+
<?php if ( empty( $updates['framework'] ) ): ?>
|
8 |
+
<p><?php echo sprintf( __( 'You have the latest version of %s.', 'fw' ), fw()->manifest->get_name() ) ?></p>
|
9 |
+
<?php else: ?>
|
10 |
+
<?php if ( is_wp_error( $updates['framework'] ) ): ?>
|
11 |
+
<p class="wp-ui-text-notification"><?php echo $updates['framework']->get_error_message() ?></p>
|
12 |
+
<?php else: ?>
|
13 |
+
<form id="fw-ext-update-framework" method="post" action="update-core.php?action=fw-update-framework">
|
14 |
+
<p>
|
15 |
+
<?php
|
16 |
+
_e( sprintf( 'You have version %s installed. Update to %s.',
|
17 |
+
fw()->manifest->get_version(),
|
18 |
+
$updates['framework']['fixed_latest_version']
|
19 |
+
), 'fw' )
|
20 |
+
?>
|
21 |
+
</p>
|
22 |
+
<?php wp_nonce_field( - 1, '_nonce_fw_ext_update_framework' ); ?>
|
23 |
+
<p>
|
24 |
+
<input class="button" type="submit" value="<?php echo esc_attr( __( 'Update Framework', 'fw' ) ); ?>" name="update">
|
25 |
+
</p>
|
26 |
+
</form>
|
27 |
+
<?php endif; ?>
|
28 |
+
<?php endif; ?>
|
29 |
+
</div>
|
30 |
+
<?php endif; ?>
|
31 |
+
|
32 |
+
<?php if ( $updates['theme'] !== false ): ?>
|
33 |
+
<div id="fw-ext-update-theme">
|
34 |
+
<a name="fw-theme"></a>
|
35 |
+
<h3><?php $theme = wp_get_theme();
|
36 |
+
_e( sprintf( '%s Theme', ( is_child_theme() ? $theme->parent()->get( 'Name' ) : $theme->get( 'Name' ) ) ), 'fw' ) ?></h3>
|
37 |
+
<?php if ( empty( $updates['theme'] ) ): ?>
|
38 |
+
<p><?php _e( 'Your theme is up to date.', 'fw' ) ?></p>
|
39 |
+
<?php else: ?>
|
40 |
+
<?php if ( is_wp_error( $updates['theme'] ) ): ?>
|
41 |
+
<p class="wp-ui-text-notification"><?php echo $updates['theme']->get_error_message() ?></p>
|
42 |
+
<?php else: ?>
|
43 |
+
<form id="fw-ext-update-theme" method="post" action="<?php echo esc_url( add_query_arg( 'action', 'fw-update-theme', $form_action ) ); ?>">
|
44 |
+
<p>
|
45 |
+
<?php
|
46 |
+
_e( sprintf( 'You have version %s installed. Update to %s.',
|
47 |
+
fw()->theme->manifest->get_version(),
|
48 |
+
$updates['theme']['fixed_latest_version']
|
49 |
+
), 'fw' )
|
50 |
+
?>
|
51 |
+
</p>
|
52 |
+
<?php wp_nonce_field( - 1, '_nonce_fw_ext_update_theme' ); ?>
|
53 |
+
<p>
|
54 |
+
<input class="button" type="submit" value="<?php echo esc_attr( __( 'Update Theme', 'fw' ) ) ?>" name="update">
|
55 |
+
</p>
|
56 |
+
</form>
|
57 |
+
<?php endif; ?>
|
58 |
+
<?php endif; ?>
|
59 |
+
</div>
|
60 |
+
<?php endif; ?>
|
61 |
+
|
62 |
+
<div id="fw-ext-update-extensions">
|
63 |
+
<a name="fw-extensions"></a>
|
64 |
+
<h3><?php echo sprintf( __( '%s Extensions', 'fw' ), fw()->manifest->get_name() ); ?></h3>
|
65 |
+
<?php if ( empty( $updates['extensions'] ) ): ?>
|
66 |
+
<p><?php echo sprintf( __( 'You have the latest version of %s Extensions.', 'fw' ), fw()->manifest->get_name() ); ?></p>
|
67 |
+
<?php else: ?>
|
68 |
+
<?php
|
69 |
+
$one_update_mode = fw()->extensions->get( 'update' )->get_config( 'extensions_as_one_update' );
|
70 |
+
|
71 |
+
foreach ( $updates['extensions'] as $extension ) {
|
72 |
+
if ( is_wp_error( $extension ) ) {
|
73 |
+
/**
|
74 |
+
* Cancel the "One update mode" and display all extensions list table with details
|
75 |
+
* if at least one extension has an error that needs to be visible
|
76 |
+
*/
|
77 |
+
$one_update_mode = false;
|
78 |
+
break;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
?>
|
82 |
+
<form id="fw-ext-update-extensions" method="post" action="<?php echo esc_url( add_query_arg( 'action', 'fw-update-extensions', $form_action ) ); ?>">
|
83 |
+
<div class="fw-ext-update-extensions-form-detailed"<?php echo( $one_update_mode ? ' style="display: none;"' : '' ); ?>>
|
84 |
+
<p>
|
85 |
+
<input class="button" type="submit" value="<?php echo esc_attr( __( 'Update Extensions', 'fw' ) ) ?>" name="update">
|
86 |
+
</p>
|
87 |
+
<?php
|
88 |
+
if ( ! class_exists( '_FW_Ext_Update_Extensions_List_Table' ) ) {
|
89 |
+
fw_include_file_isolated(
|
90 |
+
fw()->extensions->get( 'update' )->get_declared_path( '/includes/classes/class--fw-ext-update-extensions-list-table.php' )
|
91 |
+
);
|
92 |
+
}
|
93 |
+
|
94 |
+
$list_table = new _FW_Ext_Update_Extensions_List_Table( array( 'extensions' => $updates['extensions'] ) );
|
95 |
+
$list_table->display();
|
96 |
+
?>
|
97 |
+
<?php wp_nonce_field( - 1, '_nonce_fw_ext_update_extensions' ); ?>
|
98 |
+
<p>
|
99 |
+
<input class="button" type="submit" value="<?php echo esc_attr( esc_html__( 'Update Extensions', 'fw' ) ); ?>" name="update">
|
100 |
+
</p>
|
101 |
+
</div>
|
102 |
+
<?php if ( $one_update_mode ) : ?>
|
103 |
+
<div class="fw-ext-update-extensions-form-simple">
|
104 |
+
<p style="color:#d54e21;"><?php _e( 'New extensions updates available.', 'fw' ); ?></p>
|
105 |
+
<p><input class="button" type="submit"
|
106 |
+
value="<?php echo esc_attr( __( 'Update Extensions', 'fw' ) ) ?>" name="update"></p>
|
107 |
+
<script type="text/javascript">
|
108 |
+
jQuery( function ( $ ) {
|
109 |
+
$( 'form#fw-ext-update-extensions' ).on( 'submit', function () {
|
110 |
+
$( this ).find( '.check-column input[type="checkbox"]' ).prop( 'checked', true );
|
111 |
+
} );
|
112 |
+
} );
|
113 |
+
</script>
|
114 |
+
</div>
|
115 |
+
<?php endif; ?>
|
116 |
+
</form>
|
117 |
+
<?php endif; ?>
|
118 |
+
</div>
|
framework/helpers/class-fw-access-key.php
CHANGED
@@ -1,43 +1,43 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Used in public callbacks to allow call only from known caller
|
5 |
-
*
|
6 |
-
* For e.g. Inside some class is created an instance of FW_Access_Key with unique key 'whatever',
|
7 |
-
* so nobody else can create another instance with same key, only that class owns that unique key.
|
8 |
-
* Some public callback (function or method) that wants to allow to be called only by that class,
|
9 |
-
* sets an requirement that some parameter should be an instance on FW_Access_Key and its key should be 'whatever'
|
10 |
-
*
|
11 |
-
* function my_function(FW_Access_Key $key, $another_parameter) {
|
12 |
-
* if ($key->get_key() !== 'whatever') {
|
13 |
-
* trigger_error('Call denied', E_USER_ERROR);
|
14 |
-
* }
|
15 |
-
*
|
16 |
-
* //...
|
17 |
-
* }
|
18 |
-
*/
|
19 |
-
final class FW_Access_Key
|
20 |
-
{
|
21 |
-
private static $created_keys = array();
|
22 |
-
|
23 |
-
private $key;
|
24 |
-
|
25 |
-
final public function get_key()
|
26 |
-
{
|
27 |
-
return $this->key;
|
28 |
-
}
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @param string $unique_key unique
|
32 |
-
*/
|
33 |
-
final public function __construct($unique_key)
|
34 |
-
{
|
35 |
-
if (isset(self::$created_keys[$unique_key])) {
|
36 |
-
trigger_error('Key "'. $unique_key .'" already defined', E_USER_ERROR);
|
37 |
-
}
|
38 |
-
|
39 |
-
self::$created_keys[$unique_key] = true;
|
40 |
-
|
41 |
-
$this->key = $unique_key;
|
42 |
-
}
|
43 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Used in public callbacks to allow call only from known caller
|
5 |
+
*
|
6 |
+
* For e.g. Inside some class is created an instance of FW_Access_Key with unique key 'whatever',
|
7 |
+
* so nobody else can create another instance with same key, only that class owns that unique key.
|
8 |
+
* Some public callback (function or method) that wants to allow to be called only by that class,
|
9 |
+
* sets an requirement that some parameter should be an instance on FW_Access_Key and its key should be 'whatever'
|
10 |
+
*
|
11 |
+
* function my_function(FW_Access_Key $key, $another_parameter) {
|
12 |
+
* if ($key->get_key() !== 'whatever') {
|
13 |
+
* trigger_error('Call denied', E_USER_ERROR);
|
14 |
+
* }
|
15 |
+
*
|
16 |
+
* //...
|
17 |
+
* }
|
18 |
+
*/
|
19 |
+
final class FW_Access_Key
|
20 |
+
{
|
21 |
+
private static $created_keys = array();
|
22 |
+
|
23 |
+
private $key;
|
24 |
+
|
25 |
+
final public function get_key()
|
26 |
+
{
|
27 |
+
return $this->key;
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param string $unique_key unique
|
32 |
+
*/
|
33 |
+
final public function __construct($unique_key)
|
34 |
+
{
|
35 |
+
if (isset(self::$created_keys[$unique_key])) {
|
36 |
+
trigger_error('Key "'. $unique_key .'" already defined', E_USER_ERROR);
|
37 |
+
}
|
38 |
+
|
39 |
+
self::$created_keys[$unique_key] = true;
|
40 |
+
|
41 |
+
$this->key = $unique_key;
|
42 |
+
}
|
43 |
+
}
|
framework/helpers/class-fw-cache.php
CHANGED
@@ -1,309 +1,309 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Memory Cache
|
5 |
-
*
|
6 |
-
* Recommended usage example:
|
7 |
-
* try {
|
8 |
-
* $value = FW_Cache::get('some/key');
|
9 |
-
* } catch(FW_Cache_Not_Found_Exception $e) {
|
10 |
-
* $value = get_value_from_somewhere();
|
11 |
-
*
|
12 |
-
* FW_Cache::set('some/key', $value);
|
13 |
-
*
|
14 |
-
* // (!) after set, do not do this:
|
15 |
-
* $value = FW_Cache::get('some/key');
|
16 |
-
* // because there is no guaranty that FW_Cache::set('some/key', $value); succeeded
|
17 |
-
* // trust only your $value, cache can do clean-up right after set() and remove the value you tried to set
|
18 |
-
* }
|
19 |
-
*
|
20 |
-
* // use $value ...
|
21 |
-
*/
|
22 |
-
class FW_Cache
|
23 |
-
{
|
24 |
-
/**
|
25 |
-
* The actual cache
|
26 |
-
* @var array
|
27 |
-
*/
|
28 |
-
protected static $cache = array();
|
29 |
-
|
30 |
-
/**
|
31 |
-
* If the PHP will have less that this memory, the cache will try to delete parts from its array to free memory
|
32 |
-
*
|
33 |
-
* (1024 * 1024 = 1048576 = 1 Mb) * 10
|
34 |
-
*/
|
35 |
-
protected static $min_free_memory = 10485760;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* A special value that is used to detect if value was found in cache
|
39 |
-
* We can't use null|false because these can be values set by user and we can't treat them as not existing values
|
40 |
-
*/
|
41 |
-
protected static $not_found_value;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* The amount of times the data was already stored in the cache.
|
45 |
-
* @var int
|
46 |
-
* @since 2.4.17
|
47 |
-
*/
|
48 |
-
protected static $hits = 0;
|
49 |
-
|
50 |
-
/**
|
51 |
-
* Amount of times the cache did not have the value in cache.
|
52 |
-
* @var int
|
53 |
-
* @since 2.4.17
|
54 |
-
*/
|
55 |
-
protected static $misses = 0;
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Amount of times the cache free was called.
|
59 |
-
* @var int
|
60 |
-
* @since 2.4.17
|
61 |
-
*/
|
62 |
-
protected static $freed = 0;
|
63 |
-
|
64 |
-
protected static function get_memory_limit()
|
65 |
-
{
|
66 |
-
$memory_limit = ini_get('memory_limit');
|
67 |
-
|
68 |
-
if ($memory_limit === '-1') { // This happens in WP CLI
|
69 |
-
return 256 * 1024 * 1024;
|
70 |
-
}
|
71 |
-
|
72 |
-
switch (substr($memory_limit, -1)) {
|
73 |
-
case 'M': return intval($memory_limit) * 1024 * 1024;
|
74 |
-
case 'K': return intval($memory_limit) * 1024;
|
75 |
-
case 'G': return intval($memory_limit) * 1024 * 1024 * 1024;
|
76 |
-
default: return intval($memory_limit) * 1024 * 1024;
|
77 |
-
}
|
78 |
-
}
|
79 |
-
|
80 |
-
protected static function memory_exceeded()
|
81 |
-
{
|
82 |
-
return memory_get_usage(false) >= self::get_memory_limit() - self::$min_free_memory;
|
83 |
-
|
84 |
-
// about memory_get_usage(false) http://stackoverflow.com/a/16239377/1794248
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* @internal
|
89 |
-
*/
|
90 |
-
public static function _init()
|
91 |
-
{
|
92 |
-
self::$not_found_value = new FW_Cache_Not_Found_Exception();
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Listen often triggered hooks to clear the memory
|
96 |
-
* instead of tick function https://github.com/ThemeFuse/Unyson/issues/1197
|
97 |
-
* @since 2.4.17
|
98 |
-
*/
|
99 |
-
foreach (array(
|
100 |
-
'query' => true,
|
101 |
-
'plugins_loaded' => true,
|
102 |
-
'wp_get_object_terms' => true,
|
103 |
-
'created_term' => true,
|
104 |
-
'wp_upgrade' => true,
|
105 |
-
'added_option' => true,
|
106 |
-
'updated_option' => true,
|
107 |
-
'deleted_option' => true,
|
108 |
-
'wp_after_admin_bar_render' => true,
|
109 |
-
'http_response' => true,
|
110 |
-
'oembed_result' => true,
|
111 |
-
'customize_post_value_set' => true,
|
112 |
-
'customize_save_after' => true,
|
113 |
-
'customize_render_panel' => true,
|
114 |
-
'customize_render_control' => true,
|
115 |
-
'customize_render_section' => true,
|
116 |
-
'role_has_cap' => true,
|
117 |
-
'user_has_cap' => true,
|
118 |
-
'theme_page_templates' => true,
|
119 |
-
'pre_get_users' => true,
|
120 |
-
'request' => true,
|
121 |
-
'send_headers' => true,
|
122 |
-
'updated_usermeta' => true,
|
123 |
-
'added_usermeta' => true,
|
124 |
-
'image_memory_limit' => true,
|
125 |
-
'upload_dir' => true,
|
126 |
-
'wp_head' => true,
|
127 |
-
'wp_footer' => true,
|
128 |
-
'wp' => true,
|
129 |
-
'wp_init' => true,
|
130 |
-
'fw_init' => true,
|
131 |
-
'init' => true,
|
132 |
-
'updated_postmeta' => true,
|
133 |
-
'deleted_postmeta' => true,
|
134 |
-
'setted_transient' => true,
|
135 |
-
'registered_post_type' => true,
|
136 |
-
'wp_count_posts' => true,
|
137 |
-
'wp_count_attachments' => true,
|
138 |
-
'after_delete_post' => true,
|
139 |
-
'post_updated' => true,
|
140 |
-
'wp_insert_post' => true,
|
141 |
-
'deleted_post' => true,
|
142 |
-
'clean_post_cache' => true,
|
143 |
-
'wp_restore_post_revision' => true,
|
144 |
-
'wp_delete_post_revision' => true,
|
145 |
-
'get_term' => true,
|
146 |
-
'edited_term_taxonomies' => true,
|
147 |
-
'deleted_term_taxonomy' => true,
|
148 |
-
'edited_terms' => true,
|
149 |
-
'created_term' => true,
|
150 |
-
'clean_term_cache' => true,
|
151 |
-
'edited_term_taxonomy' => true,
|
152 |
-
'switch_theme' => true,
|
153 |
-
'wp_get_update_data' => true,
|
154 |
-
'clean_user_cache' => true,
|
155 |
-
'process_text_diff_html' => true,
|
156 |
-
) as $hook => $tmp) {
|
157 |
-
add_filter($hook, array(__CLASS__, 'free_memory'), 1);
|
158 |
-
}
|
159 |
-
|
160 |
-
/**
|
161 |
-
* Flush the cache when something major is changed (files or db values)
|
162 |
-
*/
|
163 |
-
foreach (array(
|
164 |
-
'switch_blog' => true,
|
165 |
-
'upgrader_post_install' => true,
|
166 |
-
'upgrader_process_complete' => true,
|
167 |
-
'switch_theme' => true,
|
168 |
-
) as $hook => $tmp) {
|
169 |
-
add_filter($hook, array(__CLASS__, 'clear'), 1);
|
170 |
-
}
|
171 |
-
}
|
172 |
-
|
173 |
-
/**
|
174 |
-
* This method does nothing @since 2.4.17
|
175 |
-
* but we can't delete it because it's public and maybe somebody is calling it
|
176 |
-
* @return bool
|
177 |
-
*/
|
178 |
-
public static function is_enabled()
|
179 |
-
{
|
180 |
-
return true;
|
181 |
-
}
|
182 |
-
|
183 |
-
/**
|
184 |
-
* @param mixed $dummy
|
185 |
-
* @return mixed
|
186 |
-
*/
|
187 |
-
public static function free_memory($dummy = null)
|
188 |
-
{
|
189 |
-
while (self::memory_exceeded() && !empty(self::$cache)) {
|
190 |
-
reset(self::$cache);
|
191 |
-
|
192 |
-
$key = key(self::$cache);
|
193 |
-
|
194 |
-
unset(self::$cache[$key]);
|
195 |
-
}
|
196 |
-
|
197 |
-
++self::$freed;
|
198 |
-
|
199 |
-
/**
|
200 |
-
* This method is used in add_filter() so to not break anything return filter value
|
201 |
-
*/
|
202 |
-
return $dummy;
|
203 |
-
}
|
204 |
-
|
205 |
-
/**
|
206 |
-
* @param $keys
|
207 |
-
* @param $value
|
208 |
-
* @param $keys_delimiter
|
209 |
-
*/
|
210 |
-
public static function set($keys, $value, $keys_delimiter = '/')
|
211 |
-
{
|
212 |
-
if (!self::is_enabled()) {
|
213 |
-
return;
|
214 |
-
}
|
215 |
-
|
216 |
-
self::free_memory();
|
217 |
-
|
218 |
-
fw_aks($keys, $value, self::$cache, $keys_delimiter);
|
219 |
-
|
220 |
-
self::free_memory();
|
221 |
-
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* Unset key from cache
|
225 |
-
* @param $keys
|
226 |
-
* @param $keys_delimiter
|
227 |
-
*/
|
228 |
-
public static function del($keys, $keys_delimiter = '/')
|
229 |
-
{
|
230 |
-
fw_aku($keys, self::$cache, $keys_delimiter);
|
231 |
-
|
232 |
-
self::free_memory();
|
233 |
-
}
|
234 |
-
|
235 |
-
/**
|
236 |
-
* @param $keys
|
237 |
-
* @param $keys_delimiter
|
238 |
-
* @return mixed
|
239 |
-
* @throws FW_Cache_Not_Found_Exception
|
240 |
-
*/
|
241 |
-
public static function get($keys, $keys_delimiter = '/')
|
242 |
-
{
|
243 |
-
$keys = (string)$keys;
|
244 |
-
$keys_arr = explode($keys_delimiter, $keys);
|
245 |
-
|
246 |
-
$key = $keys_arr;
|
247 |
-
$key = array_shift($key);
|
248 |
-
|
249 |
-
if ($key === '' || $key === null) {
|
250 |
-
trigger_error('First key must not be empty', E_USER_ERROR);
|
251 |
-
}
|
252 |
-
|
253 |
-
self::free_memory();
|
254 |
-
|
255 |
-
$value = fw_akg($keys, self::$cache, self::$not_found_value, $keys_delimiter);
|
256 |
-
|
257 |
-
self::free_memory();
|
258 |
-
|
259 |
-
if ($value === self::$not_found_value) {
|
260 |
-
++self::$misses;
|
261 |
-
|
262 |
-
throw new FW_Cache_Not_Found_Exception();
|
263 |
-
} else {
|
264 |
-
++self::$hits;
|
265 |
-
|
266 |
-
return $value;
|
267 |
-
}
|
268 |
-
}
|
269 |
-
|
270 |
-
/**
|
271 |
-
* Empty the cache
|
272 |
-
* @param mixed $dummy When method is used in add_filter()
|
273 |
-
* @return mixed
|
274 |
-
*/
|
275 |
-
public static function clear($dummy = null)
|
276 |
-
{
|
277 |
-
self::$cache = array();
|
278 |
-
|
279 |
-
/**
|
280 |
-
* This method is used in add_filter() so to not break anything return filter value
|
281 |
-
*/
|
282 |
-
return $dummy;
|
283 |
-
}
|
284 |
-
|
285 |
-
/**
|
286 |
-
* Debug information
|
287 |
-
* <?php add_action('admin_footer', function(){ FW_Cache::stats(); });
|
288 |
-
* @since 2.4.17
|
289 |
-
*/
|
290 |
-
public static function stats() {
|
291 |
-
echo '<div style="z-index: 10000; position: relative; background: #fff; padding: 15px;">';
|
292 |
-
echo '<p>';
|
293 |
-
echo '<strong>Cache Hits:</strong> '. self::$hits .'<br />';
|
294 |
-
echo '<strong>Cache Misses:</strong> '. self::$misses .'<br />';
|
295 |
-
echo '<strong>Cache Freed:</strong> '. self::$freed .'<br />';
|
296 |
-
echo '<strong>PHP Memory Peak Usage:</strong> '. fw_human_bytes(memory_get_peak_usage(false)) .'<br />';
|
297 |
-
echo '</p>';
|
298 |
-
echo '<ul>';
|
299 |
-
foreach (self::$cache as $group => $cache) {
|
300 |
-
echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
|
301 |
-
}
|
302 |
-
echo '</ul>';
|
303 |
-
echo '</div>';
|
304 |
-
}
|
305 |
-
}
|
306 |
-
|
307 |
-
class FW_Cache_Not_Found_Exception extends Exception {}
|
308 |
-
|
309 |
FW_Cache::_init();
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Memory Cache
|
5 |
+
*
|
6 |
+
* Recommended usage example:
|
7 |
+
* try {
|
8 |
+
* $value = FW_Cache::get('some/key');
|
9 |
+
* } catch(FW_Cache_Not_Found_Exception $e) {
|
10 |
+
* $value = get_value_from_somewhere();
|
11 |
+
*
|
12 |
+
* FW_Cache::set('some/key', $value);
|
13 |
+
*
|
14 |
+
* // (!) after set, do not do this:
|
15 |
+
* $value = FW_Cache::get('some/key');
|
16 |
+
* // because there is no guaranty that FW_Cache::set('some/key', $value); succeeded
|
17 |
+
* // trust only your $value, cache can do clean-up right after set() and remove the value you tried to set
|
18 |
+
* }
|
19 |
+
*
|
20 |
+
* // use $value ...
|
21 |
+
*/
|
22 |
+
class FW_Cache
|
23 |
+
{
|
24 |
+
/**
|
25 |
+
* The actual cache
|
26 |
+
* @var array
|
27 |
+
*/
|
28 |
+
protected static $cache = array();
|
29 |
+
|
30 |
+
/**
|
31 |
+
* If the PHP will have less that this memory, the cache will try to delete parts from its array to free memory
|
32 |
+
*
|
33 |
+
* (1024 * 1024 = 1048576 = 1 Mb) * 10
|
34 |
+
*/
|
35 |
+
protected static $min_free_memory = 10485760;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* A special value that is used to detect if value was found in cache
|
39 |
+
* We can't use null|false because these can be values set by user and we can't treat them as not existing values
|
40 |
+
*/
|
41 |
+
protected static $not_found_value;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* The amount of times the data was already stored in the cache.
|
45 |
+
* @var int
|
46 |
+
* @since 2.4.17
|
47 |
+
*/
|
48 |
+
protected static $hits = 0;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Amount of times the cache did not have the value in cache.
|
52 |
+
* @var int
|
53 |
+
* @since 2.4.17
|
54 |
+
*/
|
55 |
+
protected static $misses = 0;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Amount of times the cache free was called.
|
59 |
+
* @var int
|
60 |
+
* @since 2.4.17
|
61 |
+
*/
|
62 |
+
protected static $freed = 0;
|
63 |
+
|
64 |
+
protected static function get_memory_limit()
|
65 |
+
{
|
66 |
+
$memory_limit = ini_get('memory_limit');
|
67 |
+
|
68 |
+
if ($memory_limit === '-1') { // This happens in WP CLI
|
69 |
+
return 256 * 1024 * 1024;
|
70 |
+
}
|
71 |
+
|
72 |
+
switch (substr($memory_limit, -1)) {
|
73 |
+
case 'M': return intval($memory_limit) * 1024 * 1024;
|
74 |
+
case 'K': return intval($memory_limit) * 1024;
|
75 |
+
case 'G': return intval($memory_limit) * 1024 * 1024 * 1024;
|
76 |
+
default: return intval($memory_limit) * 1024 * 1024;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
protected static function memory_exceeded()
|
81 |
+
{
|
82 |
+
return memory_get_usage(false) >= self::get_memory_limit() - self::$min_free_memory;
|
83 |
+
|
84 |
+
// about memory_get_usage(false) http://stackoverflow.com/a/16239377/1794248
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @internal
|
89 |
+
*/
|
90 |
+
public static function _init()
|
91 |
+
{
|
92 |
+
self::$not_found_value = new FW_Cache_Not_Found_Exception();
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Listen often triggered hooks to clear the memory
|
96 |
+
* instead of tick function https://github.com/ThemeFuse/Unyson/issues/1197
|
97 |
+
* @since 2.4.17
|
98 |
+
*/
|
99 |
+
foreach (array(
|
100 |
+
'query' => true,
|
101 |
+
'plugins_loaded' => true,
|
102 |
+
'wp_get_object_terms' => true,
|
103 |
+
'created_term' => true,
|
104 |
+
'wp_upgrade' => true,
|
105 |
+
'added_option' => true,
|
106 |
+
'updated_option' => true,
|
107 |
+
'deleted_option' => true,
|
108 |
+
'wp_after_admin_bar_render' => true,
|
109 |
+
'http_response' => true,
|
110 |
+
'oembed_result' => true,
|
111 |
+
'customize_post_value_set' => true,
|
112 |
+
'customize_save_after' => true,
|
113 |
+
'customize_render_panel' => true,
|
114 |
+
'customize_render_control' => true,
|
115 |
+
'customize_render_section' => true,
|
116 |
+
'role_has_cap' => true,
|
117 |
+
'user_has_cap' => true,
|
118 |
+
'theme_page_templates' => true,
|
119 |
+
'pre_get_users' => true,
|
120 |
+
'request' => true,
|
121 |
+
'send_headers' => true,
|
122 |
+
'updated_usermeta' => true,
|
123 |
+
'added_usermeta' => true,
|
124 |
+
'image_memory_limit' => true,
|
125 |
+
'upload_dir' => true,
|
126 |
+
'wp_head' => true,
|
127 |
+
'wp_footer' => true,
|
128 |
+
'wp' => true,
|
129 |
+
'wp_init' => true,
|
130 |
+
'fw_init' => true,
|
131 |
+
'init' => true,
|
132 |
+
'updated_postmeta' => true,
|
133 |
+
'deleted_postmeta' => true,
|
134 |
+
'setted_transient' => true,
|
135 |
+
'registered_post_type' => true,
|
136 |
+
'wp_count_posts' => true,
|
137 |
+
'wp_count_attachments' => true,
|
138 |
+
'after_delete_post' => true,
|
139 |
+
'post_updated' => true,
|
140 |
+
'wp_insert_post' => true,
|
141 |
+
'deleted_post' => true,
|
142 |
+
'clean_post_cache' => true,
|
143 |
+
'wp_restore_post_revision' => true,
|
144 |
+
'wp_delete_post_revision' => true,
|
145 |
+
'get_term' => true,
|
146 |
+
'edited_term_taxonomies' => true,
|
147 |
+
'deleted_term_taxonomy' => true,
|
148 |
+
'edited_terms' => true,
|
149 |
+
'created_term' => true,
|
150 |
+
'clean_term_cache' => true,
|
151 |
+
'edited_term_taxonomy' => true,
|
152 |
+
'switch_theme' => true,
|
153 |
+
'wp_get_update_data' => true,
|
154 |
+
'clean_user_cache' => true,
|
155 |
+
'process_text_diff_html' => true,
|
156 |
+
) as $hook => $tmp) {
|
157 |
+
add_filter($hook, array(__CLASS__, 'free_memory'), 1);
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Flush the cache when something major is changed (files or db values)
|
162 |
+
*/
|
163 |
+
foreach (array(
|
164 |
+
'switch_blog' => true,
|
165 |
+
'upgrader_post_install' => true,
|
166 |
+
'upgrader_process_complete' => true,
|
167 |
+
'switch_theme' => true,
|
168 |
+
) as $hook => $tmp) {
|
169 |
+
add_filter($hook, array(__CLASS__, 'clear'), 1);
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* This method does nothing @since 2.4.17
|
175 |
+
* but we can't delete it because it's public and maybe somebody is calling it
|
176 |
+
* @return bool
|
177 |
+
*/
|
178 |
+
public static function is_enabled()
|
179 |
+
{
|
180 |
+
return true;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* @param mixed $dummy
|
185 |
+
* @return mixed
|
186 |
+
*/
|
187 |
+
public static function free_memory($dummy = null)
|
188 |
+
{
|
189 |
+
while (self::memory_exceeded() && !empty(self::$cache)) {
|
190 |
+
reset(self::$cache);
|
191 |
+
|
192 |
+
$key = key(self::$cache);
|
193 |
+
|
194 |
+
unset(self::$cache[$key]);
|
195 |
+
}
|
196 |
+
|
197 |
+
++self::$freed;
|
198 |
+
|
199 |
+
/**
|
200 |
+
* This method is used in add_filter() so to not break anything return filter value
|
201 |
+
*/
|
202 |
+
return $dummy;
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* @param $keys
|
207 |
+
* @param $value
|
208 |
+
* @param $keys_delimiter
|
209 |
+
*/
|
210 |
+
public static function set($keys, $value, $keys_delimiter = '/')
|
211 |
+
{
|
212 |
+
if (!self::is_enabled()) {
|
213 |
+
return;
|
214 |
+
}
|
215 |
+
|
216 |
+
self::free_memory();
|
217 |
+
|
218 |
+
fw_aks($keys, $value, self::$cache, $keys_delimiter);
|
219 |
+
|
220 |
+
self::free_memory();
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Unset key from cache
|
225 |
+
* @param $keys
|
226 |
+
* @param $keys_delimiter
|
227 |
+
*/
|
228 |
+
public static function del($keys, $keys_delimiter = '/')
|
229 |
+
{
|
230 |
+
fw_aku($keys, self::$cache, $keys_delimiter);
|
231 |
+
|
232 |
+
self::free_memory();
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* @param $keys
|
237 |
+
* @param $keys_delimiter
|
238 |
+
* @return mixed
|
239 |
+
* @throws FW_Cache_Not_Found_Exception
|
240 |
+
*/
|
241 |
+
public static function get($keys, $keys_delimiter = '/')
|
242 |
+
{
|
243 |
+
$keys = (string)$keys;
|
244 |
+
$keys_arr = explode($keys_delimiter, $keys);
|
245 |
+
|
246 |
+
$key = $keys_arr;
|
247 |
+
$key = array_shift($key);
|
248 |
+
|
249 |
+
if ($key === '' || $key === null) {
|
250 |
+
trigger_error('First key must not be empty', E_USER_ERROR);
|
251 |
+
}
|
252 |
+
|
253 |
+
self::free_memory();
|
254 |
+
|
255 |
+
$value = fw_akg($keys, self::$cache, self::$not_found_value, $keys_delimiter);
|
256 |
+
|
257 |
+
self::free_memory();
|
258 |
+
|
259 |
+
if ($value === self::$not_found_value) {
|
260 |
+
++self::$misses;
|
261 |
+
|
262 |
+
throw new FW_Cache_Not_Found_Exception();
|
263 |
+
} else {
|
264 |
+
++self::$hits;
|
265 |
+
|
266 |
+
return $value;
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Empty the cache
|
272 |
+
* @param mixed $dummy When method is used in add_filter()
|
273 |
+
* @return mixed
|
274 |
+
*/
|
275 |
+
public static function clear($dummy = null)
|
276 |
+
{
|
277 |
+
self::$cache = array();
|
278 |
+
|
279 |
+
/**
|
280 |
+
* This method is used in add_filter() so to not break anything return filter value
|
281 |
+
*/
|
282 |
+
return $dummy;
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Debug information
|
287 |
+
* <?php add_action('admin_footer', function(){ FW_Cache::stats(); });
|
288 |
+
* @since 2.4.17
|
289 |
+
*/
|
290 |
+
public static function stats() {
|
291 |
+
echo '<div style="z-index: 10000; position: relative; background: #fff; padding: 15px;">';
|
292 |
+
echo '<p>';
|
293 |
+
echo '<strong>Cache Hits:</strong> '. self::$hits .'<br />';
|
294 |
+
echo '<strong>Cache Misses:</strong> '. self::$misses .'<br />';
|
295 |
+
echo '<strong>Cache Freed:</strong> '. self::$freed .'<br />';
|
296 |
+
echo '<strong>PHP Memory Peak Usage:</strong> '. fw_human_bytes(memory_get_peak_usage(false)) .'<br />';
|
297 |
+
echo '</p>';
|
298 |
+
echo '<ul>';
|
299 |
+
foreach (self::$cache as $group => $cache) {
|
300 |
+
echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
|
301 |
+
}
|
302 |
+
echo '</ul>';
|
303 |
+
echo '</div>';
|
304 |
+
}
|
305 |
+
}
|
306 |
+
|
307 |
+
class FW_Cache_Not_Found_Exception extends Exception {}
|
308 |
+
|
309 |
FW_Cache::_init();
|
framework/helpers/class-fw-callback.php
CHANGED
@@ -1,132 +1,132 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class FW_Callback
|
7 |
-
*
|
8 |
-
* @since 2.6.14
|
9 |
-
*/
|
10 |
-
class FW_Callback {
|
11 |
-
/**
|
12 |
-
* @var $callback string|array
|
13 |
-
*/
|
14 |
-
private $callback;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* @var array $args
|
18 |
-
*/
|
19 |
-
private $args;
|
20 |
-
|
21 |
-
/**
|
22 |
-
* @var bool
|
23 |
-
*/
|
24 |
-
private $cache;
|
25 |
-
|
26 |
-
/**
|
27 |
-
* @var string
|
28 |
-
*/
|
29 |
-
private $id;
|
30 |
-
|
31 |
-
/**
|
32 |
-
* FW_Callback constructor.
|
33 |
-
*
|
34 |
-
* @param string|array|Closure $callback Callback function
|
35 |
-
* @param array $args Callback arguments
|
36 |
-
* @param bool $cache Whenever you want to cache the function value after it's first call or not
|
37 |
-
* Recommend when the function call may require many resources or time (database requests) , or the value is small
|
38 |
-
* Not recommended using on very large values
|
39 |
-
*
|
40 |
-
*/
|
41 |
-
public function __construct( $callback, array $args = array(), $cache = true ) {
|
42 |
-
$this->callback = $callback;
|
43 |
-
$this->args = $args;
|
44 |
-
$this->cache = (bool) $cache;
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Return callback function
|
49 |
-
* @return array|string
|
50 |
-
*/
|
51 |
-
public function get_callback() {
|
52 |
-
return $this->callback;
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Return callback function arguments
|
57 |
-
* @return array
|
58 |
-
*/
|
59 |
-
public function get_args() {
|
60 |
-
return $this->args;
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Execute callback function
|
65 |
-
* @return mixed
|
66 |
-
*/
|
67 |
-
public function execute() {
|
68 |
-
if ( $this->cache ) {
|
69 |
-
try {
|
70 |
-
return FW_Cache::get( $this->get_id() );
|
71 |
-
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
72 |
-
FW_Cache::set(
|
73 |
-
$this->get_id(),
|
74 |
-
$value = $this->get_value()
|
75 |
-
);
|
76 |
-
|
77 |
-
return $value;
|
78 |
-
}
|
79 |
-
} else {
|
80 |
-
return $this->get_value();
|
81 |
-
}
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* Whenever you want to clear the cached value or the function
|
86 |
-
*/
|
87 |
-
public function clear_cache() {
|
88 |
-
FW_Cache::del( $this->get_id() );
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* Get raw callback value, ignoring the cache
|
93 |
-
* @return mixed
|
94 |
-
*/
|
95 |
-
protected function get_value() {
|
96 |
-
return call_user_func_array( $this->callback, $this->args );
|
97 |
-
}
|
98 |
-
|
99 |
-
protected function get_id() {
|
100 |
-
if ( ! is_string( $this->id ) ) {
|
101 |
-
//$this->id = 'fw-callback-' . md5( $this->serialize_callback() . serialize( $this->args ) );
|
102 |
-
//Disabled temporary for optimization reasons
|
103 |
-
//Maybe later will come with a better idea.
|
104 |
-
$this->id = uniqid( 'fw-callback-' );
|
105 |
-
}
|
106 |
-
|
107 |
-
return $this->id;
|
108 |
-
}
|
109 |
-
|
110 |
-
protected function serialize_callback() {
|
111 |
-
|
112 |
-
if ( is_string( $this->callback ) ) {
|
113 |
-
return $this->callback;
|
114 |
-
}
|
115 |
-
|
116 |
-
if ( is_object( $this->callback ) ) {
|
117 |
-
return spl_object_hash( $this->callback );
|
118 |
-
}
|
119 |
-
|
120 |
-
if ( is_array( $this->callback ) ) {
|
121 |
-
$callback = $this->callback;
|
122 |
-
|
123 |
-
if ( is_object( ( $first = array_shift( $callback ) ) ) ) {
|
124 |
-
return spl_object_hash( $first ) . serialize( $callback );
|
125 |
-
}
|
126 |
-
|
127 |
-
return serialize( $this->callback );
|
128 |
-
}
|
129 |
-
|
130 |
-
return uniqid();
|
131 |
-
}
|
132 |
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class FW_Callback
|
7 |
+
*
|
8 |
+
* @since 2.6.14
|
9 |
+
*/
|
10 |
+
class FW_Callback {
|
11 |
+
/**
|
12 |
+
* @var $callback string|array
|
13 |
+
*/
|
14 |
+
private $callback;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var array $args
|
18 |
+
*/
|
19 |
+
private $args;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @var bool
|
23 |
+
*/
|
24 |
+
private $cache;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
private $id;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* FW_Callback constructor.
|
33 |
+
*
|
34 |
+
* @param string|array|Closure $callback Callback function
|
35 |
+
* @param array $args Callback arguments
|
36 |
+
* @param bool $cache Whenever you want to cache the function value after it's first call or not
|
37 |
+
* Recommend when the function call may require many resources or time (database requests) , or the value is small
|
38 |
+
* Not recommended using on very large values
|
39 |
+
*
|
40 |
+
*/
|
41 |
+
public function __construct( $callback, array $args = array(), $cache = true ) {
|
42 |
+
$this->callback = $callback;
|
43 |
+
$this->args = $args;
|
44 |
+
$this->cache = (bool) $cache;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Return callback function
|
49 |
+
* @return array|string
|
50 |
+
*/
|
51 |
+
public function get_callback() {
|
52 |
+
return $this->callback;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Return callback function arguments
|
57 |
+
* @return array
|
58 |
+
*/
|
59 |
+
public function get_args() {
|
60 |
+
return $this->args;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Execute callback function
|
65 |
+
* @return mixed
|
66 |
+
*/
|
67 |
+
public function execute() {
|
68 |
+
if ( $this->cache ) {
|
69 |
+
try {
|
70 |
+
return FW_Cache::get( $this->get_id() );
|
71 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
72 |
+
FW_Cache::set(
|
73 |
+
$this->get_id(),
|
74 |
+
$value = $this->get_value()
|
75 |
+
);
|
76 |
+
|
77 |
+
return $value;
|
78 |
+
}
|
79 |
+
} else {
|
80 |
+
return $this->get_value();
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Whenever you want to clear the cached value or the function
|
86 |
+
*/
|
87 |
+
public function clear_cache() {
|
88 |
+
FW_Cache::del( $this->get_id() );
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get raw callback value, ignoring the cache
|
93 |
+
* @return mixed
|
94 |
+
*/
|
95 |
+
protected function get_value() {
|
96 |
+
return call_user_func_array( $this->callback, $this->args );
|
97 |
+
}
|
98 |
+
|
99 |
+
protected function get_id() {
|
100 |
+
if ( ! is_string( $this->id ) ) {
|
101 |
+
//$this->id = 'fw-callback-' . md5( $this->serialize_callback() . serialize( $this->args ) );
|
102 |
+
//Disabled temporary for optimization reasons
|
103 |
+
//Maybe later will come with a better idea.
|
104 |
+
$this->id = uniqid( 'fw-callback-' );
|
105 |
+
}
|
106 |
+
|
107 |
+
return $this->id;
|
108 |
+
}
|
109 |
+
|
110 |
+
protected function serialize_callback() {
|
111 |
+
|
112 |
+
if ( is_string( $this->callback ) ) {
|
113 |
+
return $this->callback;
|
114 |
+
}
|
115 |
+
|
116 |
+
if ( is_object( $this->callback ) ) {
|
117 |
+
return spl_object_hash( $this->callback );
|
118 |
+
}
|
119 |
+
|
120 |
+
if ( is_array( $this->callback ) ) {
|
121 |
+
$callback = $this->callback;
|
122 |
+
|
123 |
+
if ( is_object( ( $first = array_shift( $callback ) ) ) ) {
|
124 |
+
return spl_object_hash( $first ) . serialize( $callback );
|
125 |
+
}
|
126 |
+
|
127 |
+
return serialize( $this->callback );
|
128 |
+
}
|
129 |
+
|
130 |
+
return uniqid();
|
131 |
+
}
|
132 |
}
|
framework/helpers/class-fw-db-options-model.php
CHANGED
@@ -1,319 +1,330 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Lets you create easy functions for get/set database option values
|
5 |
-
* it will handle all clever logic with default values, multikeys and processing options fw-storage parameter
|
6 |
-
* @since 2.5.9
|
7 |
-
*/
|
8 |
-
abstract class FW_Db_Options_Model {
|
9 |
-
/**
|
10 |
-
* @return string Must not contain '/'
|
11 |
-
*/
|
12 |
-
abstract protected function get_id();
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @param null|int|string $item_id
|
16 |
-
* @param array $extra_data
|
17 |
-
* @return mixed
|
18 |
-
*/
|
19 |
-
abstract protected function get_values($item_id, array $extra_data = array());
|
20 |
-
|
21 |
-
/**
|
22 |
-
* @param null|int|string $item_id
|
23 |
-
* @param mixed $values
|
24 |
-
* @param array $extra_data
|
25 |
-
* @return void
|
26 |
-
*/
|
27 |
-
abstract protected function set_values($item_id, $values, array $extra_data = array());
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @param null|int|string $item_id
|
31 |
-
* @param array $extra_data
|
32 |
-
* @return array
|
33 |
-
*/
|
34 |
-
abstract protected function get_options($item_id, array $extra_data = array());
|
35 |
-
|
36 |
-
/**
|
37 |
-
* @param null|int|string $item_id
|
38 |
-
* @param array $extra_data
|
39 |
-
* @return array E.g. for post options {'post-id': $item_id}
|
40 |
-
* @see fw_db_option_storage_type()
|
41 |
-
*/
|
42 |
-
abstract protected function get_fw_storage_params($item_id, array $extra_data = array());
|
43 |
-
|
44 |
-
abstract protected function _init();
|
45 |
-
|
46 |
-
/**
|
47 |
-
* @param null|int|string $item_id
|
48 |
-
* @param null|string $option_id
|
49 |
-
* @param null|string $sub_keys
|
50 |
-
* @param mixed $old_value
|
51 |
-
* @param array $extra_data
|
52 |
-
*/
|
53 |
-
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Get sub-key. For e.g. if each item must have a separate key or not.
|
57 |
-
* @param string $key
|
58 |
-
* @param null|int|string $item_id
|
59 |
-
* @param array $extra_data
|
60 |
-
* @return null|string
|
61 |
-
*/
|
62 |
-
protected function _get_cache_key($key, $item_id, array $extra_data = array()) {
|
63 |
-
return empty($item_id) ? null : $item_id;
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* @var array {'id': mixed}
|
68 |
-
*/
|
69 |
-
private static $instances = array();
|
70 |
-
|
71 |
-
/**
|
72 |
-
* @param string $id
|
73 |
-
* @return FW_Db_Options_Model
|
74 |
-
* @internal
|
75 |
-
*/
|
76 |
-
final public static function _get_instance($id) {
|
77 |
-
return self::$instances[$id];
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* @return string
|
82 |
-
* @since 2.6.7
|
83 |
-
*/
|
84 |
-
final public function get_main_cache_key() {
|
85 |
-
return 'fw-options-model:'. $this->get_id();
|
86 |
-
}
|
87 |
-
|
88 |
-
final public function __construct() {
|
89 |
-
if (isset(self::$instances[ $this->get_id() ])) {
|
90 |
-
trigger_error(__CLASS__ .' with id "'. $this->get_id() .'" was already defined', E_USER_ERROR);
|
91 |
-
} else {
|
92 |
-
self::$instances[ $this->get_id() ] = $this;
|
93 |
-
}
|
94 |
-
|
95 |
-
$this->_init();
|
96 |
-
}
|
97 |
-
|
98 |
-
private function get_cache_key($key, $item_id, array $extra_data = array()) {
|
99 |
-
$item_key = $this->_get_cache_key($key, $item_id, $extra_data);
|
100 |
-
|
101 |
-
return $this->get_main_cache_key() .'/'. $key . (empty($item_key) ? '' : '/'. $item_key);
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* @param null|int|string $item_id
|
106 |
-
* @param null|string $option_id
|
107 |
-
* @param mixed $default_value
|
108 |
-
* @param array $extra_data
|
109 |
-
* @return mixed
|
110 |
-
*/
|
111 |
-
final public function get( $item_id = null, $option_id = null, $default_value = null, array $extra_data = array() ) {
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
$
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
}
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
);
|
130 |
-
}
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
$
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
);
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
)
|
307 |
-
|
308 |
-
}
|
309 |
-
}
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Lets you create easy functions for get/set database option values
|
5 |
+
* it will handle all clever logic with default values, multikeys and processing options fw-storage parameter
|
6 |
+
* @since 2.5.9
|
7 |
+
*/
|
8 |
+
abstract class FW_Db_Options_Model {
|
9 |
+
/**
|
10 |
+
* @return string Must not contain '/'
|
11 |
+
*/
|
12 |
+
abstract protected function get_id();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param null|int|string $item_id
|
16 |
+
* @param array $extra_data
|
17 |
+
* @return mixed
|
18 |
+
*/
|
19 |
+
abstract protected function get_values($item_id, array $extra_data = array());
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @param null|int|string $item_id
|
23 |
+
* @param mixed $values
|
24 |
+
* @param array $extra_data
|
25 |
+
* @return void
|
26 |
+
*/
|
27 |
+
abstract protected function set_values($item_id, $values, array $extra_data = array());
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param null|int|string $item_id
|
31 |
+
* @param array $extra_data
|
32 |
+
* @return array
|
33 |
+
*/
|
34 |
+
abstract protected function get_options($item_id, array $extra_data = array());
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @param null|int|string $item_id
|
38 |
+
* @param array $extra_data
|
39 |
+
* @return array E.g. for post options {'post-id': $item_id}
|
40 |
+
* @see fw_db_option_storage_type()
|
41 |
+
*/
|
42 |
+
abstract protected function get_fw_storage_params($item_id, array $extra_data = array());
|
43 |
+
|
44 |
+
abstract protected function _init();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @param null|int|string $item_id
|
48 |
+
* @param null|string $option_id
|
49 |
+
* @param null|string $sub_keys
|
50 |
+
* @param mixed $old_value
|
51 |
+
* @param array $extra_data
|
52 |
+
*/
|
53 |
+
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Get sub-key. For e.g. if each item must have a separate key or not.
|
57 |
+
* @param string $key
|
58 |
+
* @param null|int|string $item_id
|
59 |
+
* @param array $extra_data
|
60 |
+
* @return null|string
|
61 |
+
*/
|
62 |
+
protected function _get_cache_key($key, $item_id, array $extra_data = array()) {
|
63 |
+
return empty($item_id) ? null : $item_id;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @var array {'id': mixed}
|
68 |
+
*/
|
69 |
+
private static $instances = array();
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @param string $id
|
73 |
+
* @return FW_Db_Options_Model
|
74 |
+
* @internal
|
75 |
+
*/
|
76 |
+
final public static function _get_instance($id) {
|
77 |
+
return self::$instances[$id];
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @return string
|
82 |
+
* @since 2.6.7
|
83 |
+
*/
|
84 |
+
final public function get_main_cache_key() {
|
85 |
+
return 'fw-options-model:'. $this->get_id();
|
86 |
+
}
|
87 |
+
|
88 |
+
final public function __construct() {
|
89 |
+
if (isset(self::$instances[ $this->get_id() ])) {
|
90 |
+
trigger_error(__CLASS__ .' with id "'. $this->get_id() .'" was already defined', E_USER_ERROR);
|
91 |
+
} else {
|
92 |
+
self::$instances[ $this->get_id() ] = $this;
|
93 |
+
}
|
94 |
+
|
95 |
+
$this->_init();
|
96 |
+
}
|
97 |
+
|
98 |
+
private function get_cache_key($key, $item_id, array $extra_data = array()) {
|
99 |
+
$item_key = $this->_get_cache_key($key, $item_id, $extra_data);
|
100 |
+
|
101 |
+
return $this->get_main_cache_key() .'/'. $key . (empty($item_key) ? '' : '/'. $item_key);
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* @param null|int|string $item_id
|
106 |
+
* @param null|string $option_id
|
107 |
+
* @param mixed $default_value
|
108 |
+
* @param array $extra_data
|
109 |
+
* @return mixed
|
110 |
+
*/
|
111 |
+
final public function get( $item_id = null, $option_id = null, $default_value = null, array $extra_data = array() ) {
|
112 |
+
|
113 |
+
if ( is_preview() ) {
|
114 |
+
global $wp_query;
|
115 |
+
|
116 |
+
if ( $wp_query->queried_object && ( is_single( $item_id ) || is_page( $item_id ) ) ) {
|
117 |
+
$reset_get_rev = wp_get_post_revisions( $item_id );
|
118 |
+
$item_id = ( $rewisions = reset( $reset_get_rev ) ) && isset( $rewisions->ID ) ? $rewisions->ID : $item_id;
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
if ( empty( $option_id ) ) {
|
123 |
+
$sub_keys = null;
|
124 |
+
} else {
|
125 |
+
$option_id = explode( '/', $option_id ); // 'option_id/sub/keys'
|
126 |
+
$_option_id = array_shift( $option_id ); // 'option_id'
|
127 |
+
$sub_keys = empty( $option_id ) ? null : implode( '/', $option_id ); // 'sub/keys'
|
128 |
+
$option_id = $_option_id;
|
129 |
+
unset( $_option_id );
|
130 |
+
}
|
131 |
+
|
132 |
+
try {
|
133 |
+
// Cached because values are merged with extracted default values
|
134 |
+
$values = FW_Cache::get( $cache_key_values = $this->get_cache_key( 'values', $item_id, $extra_data ) );
|
135 |
+
|
136 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
137 |
+
|
138 |
+
FW_Cache::set(
|
139 |
+
$cache_key_values,
|
140 |
+
$values = ( is_array( $values = $this->get_values( $item_id, $extra_data ) ) ? $values : array() )
|
141 |
+
);
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* If db value is not found and default value is provided
|
146 |
+
* return default value before the options file is loaded
|
147 |
+
*/
|
148 |
+
if ( ! is_null( $default_value ) ) {
|
149 |
+
if ( empty( $option_id ) ) {
|
150 |
+
if ( empty( $values )
|
151 |
+
&& (
|
152 |
+
is_array( $default_value )
|
153 |
+
||
|
154 |
+
fw_is_callback( is_array( $default_value ) )
|
155 |
+
)
|
156 |
+
) {
|
157 |
+
return fw_call( $default_value );
|
158 |
+
}
|
159 |
+
} else {
|
160 |
+
if ( is_null( $sub_keys ) ) {
|
161 |
+
if ( ! isset( $values[ $option_id ] ) ) {
|
162 |
+
return fw_call( $default_value );
|
163 |
+
}
|
164 |
+
} else {
|
165 |
+
if ( ! isset( $values[ $option_id ] ) || is_null( fw_akg( $sub_keys, $values[ $option_id ] ) ) ) {
|
166 |
+
return fw_call( $default_value );
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
try {
|
173 |
+
$options = FW_Cache::get( $cache_key = $this->get_cache_key( 'options', $item_id, $extra_data ) );
|
174 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
175 |
+
FW_Cache::set( $cache_key, array() ); // prevent recursion
|
176 |
+
FW_Cache::set( $cache_key, $options = fw_extract_only_options( $this->get_options( $item_id, $extra_data ) ) );
|
177 |
+
}
|
178 |
+
|
179 |
+
if ( $options ) {
|
180 |
+
try {
|
181 |
+
FW_Cache::get(
|
182 |
+
// fixes https://github.com/ThemeFuse/Unyson/issues/2034
|
183 |
+
$cache_key_values_processed = $this->get_cache_key( 'values:processed', $item_id, $extra_data )
|
184 |
+
);
|
185 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
186 |
+
/**
|
187 |
+
* Set cache value before processing options
|
188 |
+
* Fixes https://github.com/ThemeFuse/Unyson/issues/2034#issuecomment-248571149
|
189 |
+
*/
|
190 |
+
FW_Cache::set( $cache_key_values_processed, true );
|
191 |
+
|
192 |
+
// Complete missing db values with default values from options array
|
193 |
+
{
|
194 |
+
try {
|
195 |
+
$skip_types_process = FW_Cache::get( $cache_key = 'fw:options-default-values:skip-types' );
|
196 |
+
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
197 |
+
FW_Cache::set(
|
198 |
+
$cache_key,
|
199 |
+
$skip_types_process = apply_filters( 'fw:options-default-values:skip-types', array(// 'type' => true
|
200 |
+
) )
|
201 |
+
);
|
202 |
+
}
|
203 |
+
|
204 |
+
foreach ( array_diff_key( fw_extract_only_options( $options ), $values ) as $id => $option ) {
|
205 |
+
$values[ $id ] = isset( $skip_types_process[ $option['type'] ] )
|
206 |
+
? (
|
207 |
+
isset( $option['value'] )
|
208 |
+
? $option['value']
|
209 |
+
: fw()->backend->option_type( $option['type'] )->get_defaults( 'value' )
|
210 |
+
)
|
211 |
+
: fw()->backend->option_type( $option['type'] )->get_value_from_input( $option, null );
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
foreach ( $options as $id => $option ) {
|
216 |
+
$values[ $id ] = fw()->backend->option_type( $option['type'] )->storage_load(
|
217 |
+
$id,
|
218 |
+
$option,
|
219 |
+
isset( $values[ $id ] ) ? $values[ $id ] : null,
|
220 |
+
$this->get_fw_storage_params( $item_id, $extra_data )
|
221 |
+
);
|
222 |
+
}
|
223 |
+
|
224 |
+
FW_Cache::set( $cache_key_values, $values );
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
if ( empty( $option_id ) ) {
|
229 |
+
return ( empty( $values ) && ( is_array( $default_value ) || fw_is_callback( $default_value ) ) )
|
230 |
+
? fw_call( $default_value )
|
231 |
+
: $values;
|
232 |
+
} else {
|
233 |
+
if ( is_null( $sub_keys ) ) {
|
234 |
+
return isset( $values[ $option_id ] )
|
235 |
+
? $values[ $option_id ]
|
236 |
+
: fw_call( $default_value );
|
237 |
+
} else {
|
238 |
+
return isset( $values[ $option_id ] )
|
239 |
+
? fw_akg( $sub_keys, $values[ $option_id ], $default_value )
|
240 |
+
: fw_call( $default_value );
|
241 |
+
}
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
+
final public function set( $item_id = null, $option_id = null, $value, array $extra_data = array() ) {
|
246 |
+
FW_Cache::del($cache_key_values = $this->get_cache_key('values', $item_id, $extra_data));
|
247 |
+
FW_Cache::del($cache_key_values_processed = $this->get_cache_key('values:processed', $item_id, $extra_data));
|
248 |
+
|
249 |
+
try {
|
250 |
+
$options = FW_Cache::get($cache_key = $this->get_cache_key('options', $item_id, $extra_data));
|
251 |
+
} catch (FW_Cache_Not_Found_Exception $e) {
|
252 |
+
FW_Cache::set($cache_key, array()); // prevent recursion
|
253 |
+
FW_Cache::set($cache_key, $options = fw_extract_only_options($this->get_options($item_id, $extra_data)));
|
254 |
+
}
|
255 |
+
|
256 |
+
$sub_keys = null;
|
257 |
+
|
258 |
+
if ($option_id) {
|
259 |
+
$option_id = explode('/', $option_id); // 'option_id/sub/keys'
|
260 |
+
$_option_id = array_shift($option_id); // 'option_id'
|
261 |
+
$sub_keys = empty($option_id) ? null : implode('/', $option_id); // 'sub/keys'
|
262 |
+
$option_id = $_option_id;
|
263 |
+
unset($_option_id);
|
264 |
+
|
265 |
+
$old_values = is_array($old_values = $this->get_values($item_id, $extra_data)) ? $old_values : array();
|
266 |
+
$old_value = isset($old_values[$option_id]) ? $old_values[$option_id] : null;
|
267 |
+
|
268 |
+
if ($sub_keys) { // update sub_key in old_value and use the entire value
|
269 |
+
$new_value = $old_value;
|
270 |
+
fw_aks($sub_keys, $value, $new_value);
|
271 |
+
$value = $new_value;
|
272 |
+
unset($new_value);
|
273 |
+
|
274 |
+
$old_value = fw_akg($sub_keys, $old_value);
|
275 |
+
}
|
276 |
+
|
277 |
+
if (isset($options[$option_id])) {
|
278 |
+
$value = fw()->backend->option_type($options[$option_id]['type'])->storage_save(
|
279 |
+
$option_id,
|
280 |
+
$options[$option_id],
|
281 |
+
$value,
|
282 |
+
$this->get_fw_storage_params($item_id, $extra_data)
|
283 |
+
);
|
284 |
+
}
|
285 |
+
|
286 |
+
$old_values[$option_id] = $value;
|
287 |
+
|
288 |
+
$this->set_values($item_id, $old_values, $extra_data);
|
289 |
+
|
290 |
+
unset($old_values);
|
291 |
+
} else {
|
292 |
+
$old_value = is_array($old_values = $this->get_values($item_id, $extra_data)) ? $old_values : array();
|
293 |
+
|
294 |
+
if ( ! is_array($value) ) {
|
295 |
+
$value = array();
|
296 |
+
}
|
297 |
+
|
298 |
+
if (empty($value)) {
|
299 |
+
// All options reset. Reset all fw-storage values too
|
300 |
+
// Fixes https://github.com/ThemeFuse/Unyson/issues/2179
|
301 |
+
foreach ($options as $_option_id => $_option) {
|
302 |
+
fw()->backend->option_type($options[$_option_id]['type'])->storage_save(
|
303 |
+
$_option_id,
|
304 |
+
$_option,
|
305 |
+
fw()->backend->option_type($options[$_option_id]['type'])->get_defaults('value'),
|
306 |
+
$this->get_fw_storage_params($item_id, $extra_data)
|
307 |
+
);
|
308 |
+
}
|
309 |
+
} else {
|
310 |
+
foreach ($value as $_option_id => $_option_value) {
|
311 |
+
if (isset($options[$_option_id])) {
|
312 |
+
$value[$_option_id] = fw()->backend->option_type($options[$_option_id]['type'])->storage_save(
|
313 |
+
$_option_id,
|
314 |
+
$options[$_option_id],
|
315 |
+
$_option_value,
|
316 |
+
$this->get_fw_storage_params($item_id, $extra_data)
|
317 |
+
);
|
318 |
+
}
|
319 |
+
}
|
320 |
+
}
|
321 |
+
|
322 |
+
$this->set_values($item_id, $value, $extra_data);
|
323 |
+
}
|
324 |
+
|
325 |
+
FW_Cache::del($cache_key_values); // fixes https://github.com/ThemeFuse/Unyson/issues/1538
|
326 |
+
FW_Cache::del($cache_key_values_processed);
|
327 |
+
|
328 |
+
$this->_after_set($item_id, $option_id, $sub_keys, $old_value, $extra_data);
|
329 |
+
}
|
330 |
+
}
|
framework/helpers/class-fw-dumper.php
CHANGED
@@ -1,124 +1,124 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// original source: https://code.google.com/p/prado3/source/browse/trunk/framework/Util/TVar_dumper.php
|
4 |
-
|
5 |
-
/**
|
6 |
-
* TVar_dumper class.
|
7 |
-
*
|
8 |
-
* TVar_dumper is intended to replace the buggy PHP function var_dump and print_r.
|
9 |
-
* It can correctly identify the recursively referenced objects in a complex
|
10 |
-
* object structure. It also has a recursive depth control to avoid indefinite
|
11 |
-
* recursive display of some peculiar variables.
|
12 |
-
*
|
13 |
-
* TVar_dumper can be used as follows,
|
14 |
-
* <code>
|
15 |
-
* echo TVar_dumper::dump($var);
|
16 |
-
* </code>
|
17 |
-
*
|
18 |
-
* @author Qiang Xue <qiang.xue@gmail.com>
|
19 |
-
* @version $Id$
|
20 |
-
* @package System.Util
|
21 |
-
* @since 3.0
|
22 |
-
*/
|
23 |
-
class FW_Dumper
|
24 |
-
{
|
25 |
-
private static $_objects;
|
26 |
-
private static $_output;
|
27 |
-
private static $_depth;
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Converts a variable into a string representation.
|
31 |
-
* This method achieves the similar functionality as var_dump and print_r
|
32 |
-
* but is more robust when handling complex objects such as PRADO controls.
|
33 |
-
* @param mixed $var Variable to be dumped
|
34 |
-
* @param integer $depth Maximum depth that the dumper should go into the variable. Defaults to 10.
|
35 |
-
* @return string the string representation of the variable
|
36 |
-
*/
|
37 |
-
public static function dump($var, $depth=10)
|
38 |
-
{
|
39 |
-
self::reset_internals();
|
40 |
-
|
41 |
-
self::$_depth=$depth;
|
42 |
-
self::dump_internal($var,0);
|
43 |
-
|
44 |
-
$output = self::$_output;
|
45 |
-
|
46 |
-
self::reset_internals();
|
47 |
-
|
48 |
-
return $output;
|
49 |
-
}
|
50 |
-
|
51 |
-
private static function reset_internals()
|
52 |
-
{
|
53 |
-
self::$_output='';
|
54 |
-
self::$_objects=array();
|
55 |
-
self::$_depth=10;
|
56 |
-
}
|
57 |
-
|
58 |
-
private static function dump_internal($var,$level)
|
59 |
-
{
|
60 |
-
switch(gettype($var)) {
|
61 |
-
case 'boolean':
|
62 |
-
self::$_output.=$var?'true':'false';
|
63 |
-
break;
|
64 |
-
case 'integer':
|
65 |
-
self::$_output.="$var";
|
66 |
-
break;
|
67 |
-
case 'double':
|
68 |
-
self::$_output.="$var";
|
69 |
-
break;
|
70 |
-
case 'string':
|
71 |
-
self::$_output.="'$var'";
|
72 |
-
break;
|
73 |
-
case 'resource':
|
74 |
-
self::$_output.='{resource}';
|
75 |
-
break;
|
76 |
-
case 'NULL':
|
77 |
-
self::$_output.="null";
|
78 |
-
break;
|
79 |
-
case 'unknown type':
|
80 |
-
self::$_output.='{unknown}';
|
81 |
-
break;
|
82 |
-
case 'array':
|
83 |
-
if(self::$_depth<=$level)
|
84 |
-
self::$_output.='array(...)';
|
85 |
-
else if(empty($var))
|
86 |
-
self::$_output.='array()';
|
87 |
-
else
|
88 |
-
{
|
89 |
-
$keys=array_keys($var);
|
90 |
-
$spaces=str_repeat(' ',$level*4);
|
91 |
-
self::$_output.="array\n".$spaces.'(';
|
92 |
-
foreach($keys as $key)
|
93 |
-
{
|
94 |
-
self::$_output.="\n".$spaces." [$key] => ";
|
95 |
-
self::$_output.=self::dump_internal($var[$key],$level+1);
|
96 |
-
}
|
97 |
-
self::$_output.="\n".$spaces.')';
|
98 |
-
}
|
99 |
-
break;
|
100 |
-
case 'object':
|
101 |
-
if(($id=array_search($var,self::$_objects,true))!==false)
|
102 |
-
self::$_output.=get_class($var).'(...)';
|
103 |
-
else if(self::$_depth<=$level)
|
104 |
-
self::$_output.=get_class($var).'(...)';
|
105 |
-
else
|
106 |
-
{
|
107 |
-
$id=array_push(self::$_objects,$var);
|
108 |
-
$class_name=get_class($var);
|
109 |
-
$members=(array)$var;
|
110 |
-
$keys=array_keys($members);
|
111 |
-
$spaces=str_repeat(' ',$level*4);
|
112 |
-
self::$_output.="$class_name\n".$spaces.'(';
|
113 |
-
foreach($keys as $key)
|
114 |
-
{
|
115 |
-
$key_display=strtr(trim($key),array("\0"=>':'));
|
116 |
-
self::$_output.="\n".$spaces." [$key_display] => ";
|
117 |
-
self::$_output.=self::dump_internal($members[$key],$level+1);
|
118 |
-
}
|
119 |
-
self::$_output.="\n".$spaces.')';
|
120 |
-
}
|
121 |
-
break;
|
122 |
-
}
|
123 |
-
}
|
124 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// original source: https://code.google.com/p/prado3/source/browse/trunk/framework/Util/TVar_dumper.php
|
4 |
+
|
5 |
+
/**
|
6 |
+
* TVar_dumper class.
|
7 |
+
*
|
8 |
+
* TVar_dumper is intended to replace the buggy PHP function var_dump and print_r.
|
9 |
+
* It can correctly identify the recursively referenced objects in a complex
|
10 |
+
* object structure. It also has a recursive depth control to avoid indefinite
|
11 |
+
* recursive display of some peculiar variables.
|
12 |
+
*
|
13 |
+
* TVar_dumper can be used as follows,
|
14 |
+
* <code>
|
15 |
+
* echo TVar_dumper::dump($var);
|
16 |
+
* </code>
|
17 |
+
*
|
18 |
+
* @author Qiang Xue <qiang.xue@gmail.com>
|
19 |
+
* @version $Id$
|
20 |
+
* @package System.Util
|
21 |
+
* @since 3.0
|
22 |
+
*/
|
23 |
+
class FW_Dumper
|
24 |
+
{
|
25 |
+
private static $_objects;
|
26 |
+
private static $_output;
|
27 |
+
private static $_depth;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Converts a variable into a string representation.
|
31 |
+
* This method achieves the similar functionality as var_dump and print_r
|
32 |
+
* but is more robust when handling complex objects such as PRADO controls.
|
33 |
+
* @param mixed $var Variable to be dumped
|
34 |
+
* @param integer $depth Maximum depth that the dumper should go into the variable. Defaults to 10.
|
35 |
+
* @return string the string representation of the variable
|
36 |
+
*/
|
37 |
+
public static function dump($var, $depth=10)
|
38 |
+
{
|
39 |
+
self::reset_internals();
|
40 |
+
|
41 |
+
self::$_depth=$depth;
|
42 |
+
self::dump_internal($var,0);
|
43 |
+
|
44 |
+
$output = self::$_output;
|
45 |
+
|
46 |
+
self::reset_internals();
|
47 |
+
|
48 |
+
return $output;
|
49 |
+
}
|
50 |
+
|
51 |
+
private static function reset_internals()
|
52 |
+
{
|
53 |
+
self::$_output='';
|
54 |
+
self::$_objects=array();
|
55 |
+
self::$_depth=10;
|
56 |
+
}
|
57 |
+
|
58 |
+
private static function dump_internal($var,$level)
|
59 |
+
{
|
60 |
+
switch(gettype($var)) {
|
61 |
+
case 'boolean':
|
62 |
+
self::$_output.=$var?'true':'false';
|
63 |
+
break;
|
64 |
+
case 'integer':
|
65 |
+
self::$_output.="$var";
|
66 |
+
break;
|
67 |
+
case 'double':
|
68 |
+
self::$_output.="$var";
|
69 |
+
break;
|
70 |
+
case 'string':
|
71 |
+
self::$_output.="'$var'";
|
72 |
+
break;
|
73 |
+
case 'resource':
|
74 |
+
self::$_output.='{resource}';
|
75 |
+
break;
|
76 |
+
case 'NULL':
|
77 |
+
self::$_output.="null";
|
78 |
+
break;
|
79 |
+
case 'unknown type':
|
80 |
+
self::$_output.='{unknown}';
|
81 |
+
break;
|
82 |
+
case 'array':
|
83 |
+
if(self::$_depth<=$level)
|
84 |
+
self::$_output.='array(...)';
|
85 |
+
else if(empty($var))
|
86 |
+
self::$_output.='array()';
|
87 |
+
else
|
88 |
+
{
|
89 |
+
$keys=array_keys($var);
|
90 |
+
$spaces=str_repeat(' ',$level*4);
|
91 |
+
self::$_output.="array\n".$spaces.'(';
|
92 |
+
foreach($keys as $key)
|
93 |
+
{
|
94 |
+
self::$_output.="\n".$spaces." [$key] => ";
|
95 |
+
self::$_output.=self::dump_internal($var[$key],$level+1);
|
96 |
+
}
|
97 |
+
self::$_output.="\n".$spaces.')';
|
98 |
+
}
|
99 |
+
break;
|
100 |
+
case 'object':
|
101 |
+
if(($id=array_search($var,self::$_objects,true))!==false)
|
102 |
+
self::$_output.=get_class($var).'(...)';
|
103 |
+
else if(self::$_depth<=$level)
|
104 |
+
self::$_output.=get_class($var).'(...)';
|
105 |
+
else
|
106 |
+
{
|
107 |
+
$id=array_push(self::$_objects,$var);
|
108 |
+
$class_name=get_class($var);
|
109 |
+
$members=(array)$var;
|
110 |
+
$keys=array_keys($members);
|
111 |
+
$spaces=str_repeat(' ',$level*4);
|
112 |
+
self::$_output.="$class_name\n".$spaces.'(';
|
113 |
+
foreach($keys as $key)
|
114 |
+
{
|
115 |
+
$key_display=strtr(trim($key),array("\0"=>':'));
|
116 |
+
self::$_output.="\n".$spaces." [$key_display] => ";
|
117 |
+
self::$_output.=self::dump_internal($members[$key],$level+1);
|
118 |
+
}
|
119 |
+
self::$_output.="\n".$spaces.')';
|
120 |
+
}
|
121 |
+
break;
|
122 |
+
}
|
123 |
+
}
|
124 |
}
|
framework/helpers/class-fw-flash-messages.php
CHANGED
@@ -1,218 +1,218 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Set flash messages
|
5 |
-
**
|
6 |
-
* Store messages in session (to not be lost between redirects) and remove them after they were shown to the user
|
7 |
-
*/
|
8 |
-
class FW_Flash_Messages
|
9 |
-
{
|
10 |
-
private static $available_types = array(
|
11 |
-
// 'type' => 'backend class/type' (only 2 backend types exists: error and updated)
|
12 |
-
'error' => 'error',
|
13 |
-
'warning' => 'update-nag',
|
14 |
-
'info' => 'updated',
|
15 |
-
'success' => 'updated'
|
16 |
-
);
|
17 |
-
|
18 |
-
private static $session_key = 'fw_flash_messages';
|
19 |
-
|
20 |
-
private static $frontend_printed = false;
|
21 |
-
|
22 |
-
private static function get_messages()
|
23 |
-
{
|
24 |
-
$messages = FW_Session::get(self::$session_key);
|
25 |
-
|
26 |
-
if (empty($messages) || !is_array($messages)) {
|
27 |
-
$messages = array_fill_keys(array_keys(self::$available_types), array());
|
28 |
-
}
|
29 |
-
|
30 |
-
return $messages;
|
31 |
-
}
|
32 |
-
|
33 |
-
private static function set_messages(array $messages)
|
34 |
-
{
|
35 |
-
FW_Session::set(self::$session_key, $messages);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Remove messages with ids from pending remove
|
40 |
-
*/
|
41 |
-
private static function process_pending_remove_ids()
|
42 |
-
{
|
43 |
-
$pending_remove = array();
|
44 |
-
|
45 |
-
foreach (self::get_messages() as $messages) {
|
46 |
-
if (empty($messages)) {
|
47 |
-
continue;
|
48 |
-
}
|
49 |
-
|
50 |
-
foreach ($messages as $message) {
|
51 |
-
if (empty($message['remove_ids'])) {
|
52 |
-
continue;
|
53 |
-
}
|
54 |
-
|
55 |
-
foreach ($message['remove_ids'] as $remove_id) {
|
56 |
-
$pending_remove[$remove_id] = true;
|
57 |
-
}
|
58 |
-
}
|
59 |
-
}
|
60 |
-
|
61 |
-
if (empty($pending_remove)) {
|
62 |
-
return;
|
63 |
-
}
|
64 |
-
|
65 |
-
$types = self::get_messages();
|
66 |
-
|
67 |
-
foreach ($types as $type => $messages) {
|
68 |
-
if (empty($messages)) {
|
69 |
-
continue;
|
70 |
-
}
|
71 |
-
|
72 |
-
foreach ($messages as $id => $message) {
|
73 |
-
if (isset($pending_remove[$id])) {
|
74 |
-
unset($types[$type][$id]);
|
75 |
-
}
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
self::set_messages( $types );
|
80 |
-
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Add flash message
|
84 |
-
**
|
85 |
-
* @param string $id Unique id of the message
|
86 |
-
* @param string $message Message (can be html)
|
87 |
-
* @param string $type Type from $available_types
|
88 |
-
* @param array $removed_ids Remove flashes with this id(s)
|
89 |
-
* (For e.g. your message is success and some known error messages ids needs to be removed
|
90 |
-
* because they are not relevant anymore, your success message suppress/cancels them)
|
91 |
-
*/
|
92 |
-
public static function add($id, $message, $type = 'info', array $removed_ids = array())
|
93 |
-
{
|
94 |
-
if (!isset(self::$available_types[$type])) {
|
95 |
-
trigger_error(sprintf(__('Invalid flash message type: %s', 'tfuse'), $type), E_USER_WARNING);
|
96 |
-
$type = 'info';
|
97 |
-
}
|
98 |
-
|
99 |
-
$messages = self::get_messages();
|
100 |
-
|
101 |
-
$messages[$type][$id] = array(
|
102 |
-
'message' => $message,
|
103 |
-
'remove_ids' => $removed_ids,
|
104 |
-
);
|
105 |
-
|
106 |
-
self::set_messages($messages);
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Use this method to print messages html in backend
|
111 |
-
* (used in action at the end of the file)
|
112 |
-
* @internal
|
113 |
-
*/
|
114 |
-
public static function _print_backend()
|
115 |
-
{
|
116 |
-
if (!session_id()) {
|
117 |
-
return; // fixes https://github.com/ThemeFuse/Unyson/issues/2219
|
118 |
-
}
|
119 |
-
|
120 |
-
self::process_pending_remove_ids();
|
121 |
-
|
122 |
-
$html = array_fill_keys(array_keys(self::$available_types), '');
|
123 |
-
|
124 |
-
$all_messages = self::get_messages();
|
125 |
-
|
126 |
-
foreach ($all_messages as $type => $messages) {
|
127 |
-
if (!empty($messages)) {
|
128 |
-
foreach ($messages as $id => $data) {
|
129 |
-
$html[$type] .=
|
130 |
-
'<div class="'. self::$available_types[$type] .' fw-flash-message">'.
|
131 |
-
'<p data-id="'. esc_attr($id) .'">'. $data['message'] .'</p>'.
|
132 |
-
'</div>';
|
133 |
-
|
134 |
-
unset($all_messages[$type][$id]);
|
135 |
-
}
|
136 |
-
|
137 |
-
$html[$type] = '<div class="fw-flash-type-'. $type .'">'. $html[$type] .'</div>';
|
138 |
-
}
|
139 |
-
}
|
140 |
-
|
141 |
-
unset($success, $error, $info);
|
142 |
-
|
143 |
-
self::set_messages($all_messages);
|
144 |
-
|
145 |
-
echo '<div class="fw-flash-messages">'. implode("\n\n", $html) .'</div>';
|
146 |
-
}
|
147 |
-
|
148 |
-
/**
|
149 |
-
* Use this method to print messages html in frontend
|
150 |
-
* @return bool If some html was printed or not
|
151 |
-
*/
|
152 |
-
public static function _print_frontend()
|
153 |
-
{
|
154 |
-
self::process_pending_remove_ids();
|
155 |
-
|
156 |
-
$html = array_fill_keys(array_keys(self::$available_types), '');
|
157 |
-
$all_messages = self::get_messages();
|
158 |
-
|
159 |
-
$messages_exists = false;
|
160 |
-
|
161 |
-
foreach ($all_messages as $type => $messages) {
|
162 |
-
if (empty($messages)) {
|
163 |
-
continue;
|
164 |
-
}
|
165 |
-
|
166 |
-
foreach ($messages as $id => $data) {
|
167 |
-
$html[$type] .= '<li class="fw-flash-message">'. nl2br($data['message']) .'</li>';
|
168 |
-
|
169 |
-
unset($all_messages[$type][$id]);
|
170 |
-
}
|
171 |
-
|
172 |
-
$html[$type] = '<ul class="fw-flash-type-'. $type .'">'. $html[$type] .'</ul>';
|
173 |
-
|
174 |
-
$messages_exists = true;
|
175 |
-
}
|
176 |
-
|
177 |
-
self::set_messages($all_messages);
|
178 |
-
|
179 |
-
self::$frontend_printed = true;
|
180 |
-
|
181 |
-
if ($messages_exists) {
|
182 |
-
echo '<div class="fw-flash-messages">';
|
183 |
-
echo implode("\n\n", $html);
|
184 |
-
echo '</div>';
|
185 |
-
|
186 |
-
return true;
|
187 |
-
} else {
|
188 |
-
return false;
|
189 |
-
}
|
190 |
-
}
|
191 |
-
|
192 |
-
public static function _frontend_printed()
|
193 |
-
{
|
194 |
-
return self::$frontend_printed;
|
195 |
-
}
|
196 |
-
|
197 |
-
public static function _get_messages($clear = false)
|
198 |
-
{
|
199 |
-
self::process_pending_remove_ids();
|
200 |
-
|
201 |
-
$messages = self::get_messages();
|
202 |
-
|
203 |
-
if ($clear) {
|
204 |
-
self::_clear();
|
205 |
-
}
|
206 |
-
|
207 |
-
return $messages;
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Clear the FW_Flash_Messages messages
|
212 |
-
*
|
213 |
-
* @since 2.6.15
|
214 |
-
*/
|
215 |
-
public static function _clear() {
|
216 |
-
self::set_messages(array());
|
217 |
-
}
|
218 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Set flash messages
|
5 |
+
**
|
6 |
+
* Store messages in session (to not be lost between redirects) and remove them after they were shown to the user
|
7 |
+
*/
|
8 |
+
class FW_Flash_Messages
|
9 |
+
{
|
10 |
+
private static $available_types = array(
|
11 |
+
// 'type' => 'backend class/type' (only 2 backend types exists: error and updated)
|
12 |
+
'error' => 'error',
|
13 |
+
'warning' => 'update-nag',
|
14 |
+
'info' => 'updated',
|
15 |
+
'success' => 'updated'
|
16 |
+
);
|
17 |
+
|
18 |
+
private static $session_key = 'fw_flash_messages';
|
19 |
+
|
20 |
+
private static $frontend_printed = false;
|
21 |
+
|
22 |
+
private static function get_messages()
|
23 |
+
{
|
24 |
+
$messages = FW_Session::get(self::$session_key);
|
25 |
+
|
26 |
+
if (empty($messages) || !is_array($messages)) {
|
27 |
+
$messages = array_fill_keys(array_keys(self::$available_types), array());
|
28 |
+
}
|
29 |
+
|
30 |
+
return $messages;
|
31 |
+
}
|
32 |
+
|
33 |
+
private static function set_messages(array $messages)
|
34 |
+
{
|
35 |
+
FW_Session::set(self::$session_key, $messages);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Remove messages with ids from pending remove
|
40 |
+
*/
|
41 |
+
private static function process_pending_remove_ids()
|
42 |
+
{
|
43 |
+
$pending_remove = array();
|
44 |
+
|
45 |
+
foreach (self::get_messages() as $messages) {
|
46 |
+
if (empty($messages)) {
|
47 |
+
continue;
|
48 |
+
}
|
49 |
+
|
50 |
+
foreach ($messages as $message) {
|
51 |
+
if (empty($message['remove_ids'])) {
|
52 |
+
continue;
|
53 |
+
}
|
54 |
+
|
55 |
+
foreach ($message['remove_ids'] as $remove_id) {
|
56 |
+
$pending_remove[$remove_id] = true;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
if (empty($pending_remove)) {
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
$types = self::get_messages();
|
66 |
+
|
67 |
+
foreach ($types as $type => $messages) {
|
68 |
+
if (empty($messages)) {
|
69 |
+
continue;
|
70 |
+
}
|
71 |
+
|
72 |
+
foreach ($messages as $id => $message) {
|
73 |
+
if (isset($pending_remove[$id])) {
|
74 |
+
unset($types[$type][$id]);
|
75 |
+
}
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
self::set_messages( $types );
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Add flash message
|
84 |
+
**
|
85 |
+
* @param string $id Unique id of the message
|
86 |
+
* @param string $message Message (can be html)
|
87 |
+
* @param string $type Type from $available_types
|
88 |
+
* @param array $removed_ids Remove flashes with this id(s)
|
89 |
+
* (For e.g. your message is success and some known error messages ids needs to be removed
|
90 |
+
* because they are not relevant anymore, your success message suppress/cancels them)
|
91 |
+
*/
|
92 |
+
public static function add($id, $message, $type = 'info', array $removed_ids = array())
|
93 |
+
{
|
94 |
+
if (!isset(self::$available_types[$type])) {
|
95 |
+
trigger_error(sprintf(__('Invalid flash message type: %s', 'tfuse'), $type), E_USER_WARNING);
|
96 |
+
$type = 'info';
|
97 |
+
}
|
98 |
+
|
99 |
+
$messages = self::get_messages();
|
100 |
+
|
101 |
+
$messages[$type][$id] = array(
|
102 |
+
'message' => $message,
|
103 |
+
'remove_ids' => $removed_ids,
|
104 |
+
);
|
105 |
+
|
106 |
+
self::set_messages($messages);
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Use this method to print messages html in backend
|
111 |
+
* (used in action at the end of the file)
|
112 |
+
* @internal
|
113 |
+
*/
|
114 |
+
public static function _print_backend()
|
115 |
+
{
|
116 |
+
if (!session_id()) {
|
117 |
+
return; // fixes https://github.com/ThemeFuse/Unyson/issues/2219
|
118 |
+
}
|
119 |
+
|
120 |
+
self::process_pending_remove_ids();
|
121 |
+
|
122 |
+
$html = array_fill_keys(array_keys(self::$available_types), '');
|
123 |
+
|
124 |
+
$all_messages = self::get_messages();
|
125 |
+
|
126 |
+
foreach ($all_messages as $type => $messages) {
|
127 |
+
if (!empty($messages)) {
|
128 |
+
foreach ($messages as $id => $data) {
|
129 |
+
$html[$type] .=
|
130 |
+
'<div class="'. self::$available_types[$type] .' fw-flash-message">'.
|
131 |
+
'<p data-id="'. esc_attr($id) .'">'. $data['message'] .'</p>'.
|
132 |
+
'</div>';
|
133 |
+
|
134 |
+
unset($all_messages[$type][$id]);
|
135 |
+
}
|
136 |
+
|
137 |
+
$html[$type] = '<div class="fw-flash-type-'. $type .'">'. $html[$type] .'</div>';
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
unset($success, $error, $info);
|
142 |
+
|
143 |
+
self::set_messages($all_messages);
|
144 |
+
|
145 |
+
echo '<div class="fw-flash-messages">'. implode("\n\n", $html) .'</div>';
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Use this method to print messages html in frontend
|
150 |
+
* @return bool If some html was printed or not
|
151 |
+
*/
|
152 |
+
public static function _print_frontend()
|
153 |
+
{
|
154 |
+
self::process_pending_remove_ids();
|
155 |
+
|
156 |
+
$html = array_fill_keys(array_keys(self::$available_types), '');
|
157 |
+
$all_messages = self::get_messages();
|
158 |
+
|
159 |
+
$messages_exists = false;
|
160 |
+
|
161 |
+
foreach ($all_messages as $type => $messages) {
|
162 |
+
if (empty($messages)) {
|
163 |
+
continue;
|
164 |
+
}
|
165 |
+
|
166 |
+
foreach ($messages as $id => $data) {
|
167 |
+
$html[$type] .= '<li class="fw-flash-message">'. nl2br($data['message']) .'</li>';
|
168 |
+
|
169 |
+
unset($all_messages[$type][$id]);
|
170 |
+
}
|
171 |
+
|
172 |
+
$html[$type] = '<ul class="fw-flash-type-'. $type .'">'. $html[$type] .'</ul>';
|
173 |
+
|
174 |
+
$messages_exists = true;
|
175 |
+
}
|
176 |
+
|
177 |
+
self::set_messages($all_messages);
|
178 |
+
|
179 |
+
self::$frontend_printed = true;
|
180 |
+
|
181 |
+
if ($messages_exists) {
|
182 |
+
echo '<div class="fw-flash-messages">';
|
183 |
+
echo implode("\n\n", $html);
|
184 |
+
echo '</div>';
|
185 |
+
|
186 |
+
return true;
|
187 |
+
} else {
|
188 |
+
return false;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
public static function _frontend_printed()
|
193 |
+
{
|
194 |
+
return self::$frontend_printed;
|
195 |
+
}
|
196 |
+
|
197 |
+
public static function _get_messages($clear = false)
|
198 |
+
{
|
199 |
+
self::process_pending_remove_ids();
|
200 |
+
|
201 |
+
$messages = self::get_messages();
|
202 |
+
|
203 |
+
if ($clear) {
|
204 |
+
self::_clear();
|
205 |
+
}
|
206 |
+
|
207 |
+
return $messages;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Clear the FW_Flash_Messages messages
|
212 |
+
*
|
213 |
+
* @since 2.6.15
|
214 |
+
*/
|
215 |
+
public static function _clear() {
|
216 |
+
self::set_messages(array());
|
217 |
+
}
|
218 |
+
}
|
framework/helpers/class-fw-form.php
CHANGED
@@ -1,651 +1,651 @@
|
|
1 |
-
<?php if ( ! defined( 'FW' ) ) {
|
2 |
-
die( 'Forbidden' );
|
3 |
-
}
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Dynamic forms
|
7 |
-
*/
|
8 |
-
class FW_Form {
|
9 |
-
/**
|
10 |
-
* Store all form ids created with this class
|
11 |
-
* @var FW_Form[] {'form_id' => instance}
|
12 |
-
*
|
13 |
-
* @deprecated 2.6.15 Use FW_Form::get_forms()
|
14 |
-
*/
|
15 |
-
protected static $forms = array();
|
16 |
-
|
17 |
-
/**
|
18 |
-
* The id of the submitted form id
|
19 |
-
* @var string
|
20 |
-
*
|
21 |
-
* @deprecated 2.6.15
|
22 |
-
*/
|
23 |
-
protected static $submitted_id;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Hidden input name that stores the form id
|
27 |
-
* @var string
|
28 |
-
*
|
29 |
-
* @deprecated 2.6.15 Use self::get_form_id_name()
|
30 |
-
*/
|
31 |
-
protected static $id_input_name = 'fwf';
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Form id
|
35 |
-
* @var string
|
36 |
-
*
|
37 |
-
* @deprecated 2.6.15 Use $this->get_id()
|
38 |
-
*/
|
39 |
-
protected $id;
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Html attributes for <form> tag
|
43 |
-
* @var array
|
44 |
-
*
|
45 |
-
* @deprecated 2.6.15 Use $this->attr()
|
46 |
-
*/
|
47 |
-
protected $attr = array();
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Found validation errors
|
51 |
-
* @var array
|
52 |
-
*/
|
53 |
-
protected $errors;
|
54 |
-
|
55 |
-
/**
|
56 |
-
* If the get_errors() method was called at leas once
|
57 |
-
* @var bool
|
58 |
-
*/
|
59 |
-
protected $errors_accessed = false;
|
60 |
-
|
61 |
-
/**
|
62 |
-
* If current request is the submit of this form
|
63 |
-
* @var bool
|
64 |
-
*
|
65 |
-
* @deprecated 2.6.15 Use $this->is_submitted()
|
66 |
-
*/
|
67 |
-
protected $is_submitted;
|
68 |
-
|
69 |
-
/**
|
70 |
-
* @var bool
|
71 |
-
*
|
72 |
-
* @deprecated 2.6.15
|
73 |
-
*/
|
74 |
-
protected $validate_and_save_called = false;
|
75 |
-
|
76 |
-
/**
|
77 |
-
* @var array
|
78 |
-
*
|
79 |
-
* @deprecated 2.6.15 Use $this->get_callbacks()
|
80 |
-
*/
|
81 |
-
protected $callbacks = array(
|
82 |
-
'render' => false,
|
83 |
-
'validate' => false,
|
84 |
-
'save' => false
|
85 |
-
);
|
86 |
-
|
87 |
-
private $request;
|
88 |
-
|
89 |
-
/**
|
90 |
-
* @param string $id Unique
|
91 |
-
* @param array $data (optional)
|
92 |
-
* array(
|
93 |
-
* 'render' => callback // The callback that will render the form's html
|
94 |
-
* 'validate' => callback // The callback that will validate user input
|
95 |
-
* 'save' => callback // The callback that will save successfully validated user input
|
96 |
-
* 'attr' => array() // Custom <form ...> attributes
|
97 |
-
* )
|
98 |
-
*/
|
99 |
-
public function __construct( $id, $data = array() ) {
|
100 |
-
try {
|
101 |
-
self::get_form( $id );
|
102 |
-
trigger_error( sprintf( __( 'Form with id "%s" was already defined', 'fw' ), $id ), E_USER_ERROR );
|
103 |
-
|
104 |
-
return;
|
105 |
-
} catch ( FW_Form_Not_Found_Exception $e ) {
|
106 |
-
}
|
107 |
-
|
108 |
-
$this
|
109 |
-
// set id
|
110 |
-
->set_id( $id )
|
111 |
-
// prepare callbacks
|
112 |
-
->set_callbacks( array(
|
113 |
-
'render' => fw_akg( 'render', $data, false ),
|
114 |
-
'validate' => fw_akg( 'validate', $data, false ),
|
115 |
-
'save' => fw_akg( 'save', $data, false ),
|
116 |
-
) )
|
117 |
-
// prepare attributes
|
118 |
-
->set_attr( (array) fw_akg( 'attr', $data, array() ) );
|
119 |
-
|
120 |
-
self::$forms[ $this->get_id() ] =& $this;
|
121 |
-
|
122 |
-
if ( did_action( 'wp_loaded' ) ) {
|
123 |
-
// in case if form instance was created after action
|
124 |
-
$this->_validate_and_save();
|
125 |
-
} else {
|
126 |
-
// attach to an action before 'send_headers' action, to be able to do redirects
|
127 |
-
add_action( 'wp_loaded', array( $this, '_validate_and_save' ), 101 );
|
128 |
-
}
|
129 |
-
|
130 |
-
add_action( 'fw_form_display:before_form', array( $this, '_action_fw_form_show_errors' ) );
|
131 |
-
}
|
132 |
-
|
133 |
-
/**
|
134 |
-
* @return string
|
135 |
-
*/
|
136 |
-
public function get_id() {
|
137 |
-
return $this->id;
|
138 |
-
}
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Get validation errors
|
142 |
-
* @return array
|
143 |
-
*/
|
144 |
-
public function get_errors() {
|
145 |
-
if ( ! $this->validate_and_save_called ) {
|
146 |
-
fw_print( debug_backtrace() );
|
147 |
-
trigger_error( __METHOD__ . ' called before validation', E_USER_WARNING );
|
148 |
-
|
149 |
-
return array( '~' => true );
|
150 |
-
}
|
151 |
-
|
152 |
-
$this->errors_accessed = true;
|
153 |
-
|
154 |
-
return $this->_get_errors();
|
155 |
-
}
|
156 |
-
|
157 |
-
public function get_callbacks() {
|
158 |
-
return $this->callbacks;
|
159 |
-
}
|
160 |
-
|
161 |
-
public function errors_accessed() {
|
162 |
-
return $this->errors_accessed;
|
163 |
-
}
|
164 |
-
|
165 |
-
/**
|
166 |
-
* If current form was submitted, validate and save it
|
167 |
-
*
|
168 |
-
* Note: This callback can abort script execution if save does redirect
|
169 |
-
*
|
170 |
-
* @internal
|
171 |
-
*/
|
172 |
-
public function _validate_and_save() {
|
173 |
-
|
174 |
-
if ( ! self::is_form_submitted( $this->get_id() ) || $this->validate_and_save_called ) {
|
175 |
-
return;
|
176 |
-
}
|
177 |
-
|
178 |
-
$this->validate_and_save_called = true;
|
179 |
-
|
180 |
-
try {
|
181 |
-
$data = $this->submit( self::get_form_request( $this->get_id() ) );
|
182 |
-
|
183 |
-
if ( $this->_is_ajax() ) {
|
184 |
-
wp_send_json_success( array(
|
185 |
-
'save_data' => $data,
|
186 |
-
'flash_messages' => self::collect_flash_messages(),
|
187 |
-
) );
|
188 |
-
}
|
189 |
-
|
190 |
-
if ( ( $redirect = fw_akg( 'redirect', $data ) ) ) {
|
191 |
-
wp_redirect( $redirect );
|
192 |
-
exit;
|
193 |
-
}
|
194 |
-
} catch ( FW_Form_Invalid_Submission_Exception $e ) {
|
195 |
-
if ( $this->_is_ajax() ) {
|
196 |
-
wp_send_json_error( array(
|
197 |
-
'errors' => $this->get_errors(),
|
198 |
-
'flash_messages' => self::collect_flash_messages()
|
199 |
-
) );
|
200 |
-
}
|
201 |
-
}
|
202 |
-
}
|
203 |
-
|
204 |
-
/**
|
205 |
-
* @param FW_Form $form
|
206 |
-
*
|
207 |
-
* @internal
|
208 |
-
*
|
209 |
-
* You can overwrite it in case you do not need the errors to be shown for your form
|
210 |
-
*/
|
211 |
-
public function _action_fw_form_show_errors( $form ) {
|
212 |
-
if (
|
213 |
-
$form->get_id() != $this->get_id()
|
214 |
-
// errors in admin side are displayed by a script at the end of this file
|
215 |
-
|| is_admin()
|
216 |
-
|| ! $form->is_submitted()
|
217 |
-
|| $form->is_valid()
|
218 |
-
|| $form->errors_accessed()
|
219 |
-
) {
|
220 |
-
|
221 |
-
return;
|
222 |
-
}
|
223 |
-
|
224 |
-
/**
|
225 |
-
* Use this action to customize errors display in your theme
|
226 |
-
*/
|
227 |
-
do_action( 'fw_form_display_errors_frontend', $form );
|
228 |
-
|
229 |
-
$errors = $form->get_errors();
|
230 |
-
|
231 |
-
if ( empty( $errors ) ) {
|
232 |
-
return;
|
233 |
-
}
|
234 |
-
|
235 |
-
echo '<ul class="fw-form-errors">';
|
236 |
-
|
237 |
-
foreach ( $errors as $input_name => $error_message ) {
|
238 |
-
echo fw_html_tag(
|
239 |
-
'li',
|
240 |
-
array(
|
241 |
-
'data-input-name' => $input_name,
|
242 |
-
),
|
243 |
-
$error_message
|
244 |
-
);
|
245 |
-
}
|
246 |
-
|
247 |
-
echo '</ul>';
|
248 |
-
}
|
249 |
-
|
250 |
-
/**
|
251 |
-
* Get html attribute(s)
|
252 |
-
*
|
253 |
-
* @param null|string $name
|
254 |
-
*
|
255 |
-
* @return array|string
|
256 |
-
*/
|
257 |
-
public function attr( $name = null ) {
|
258 |
-
return $name !== null
|
259 |
-
? fw_akg( $name, $this->attr )
|
260 |
-
: $this->attr;
|
261 |
-
}
|
262 |
-
|
263 |
-
/**
|
264 |
-
* Render form's html
|
265 |
-
*
|
266 |
-
* @param array $data
|
267 |
-
*/
|
268 |
-
public function render( $data = array() ) {
|
269 |
-
$render_data = array(
|
270 |
-
'submit' => array(
|
271 |
-
'value' => __( 'Submit', 'fw' ),
|
272 |
-
/**
|
273 |
-
* you can set here custom submit button html
|
274 |
-
* and the 'value' parameter will not be used
|
275 |
-
*/
|
276 |
-
'html' => null,
|
277 |
-
),
|
278 |
-
'data' => $data,
|
279 |
-
'attr' => $this->attr(),
|
280 |
-
);
|
281 |
-
|
282 |
-
$html = '';
|
283 |
-
|
284 |
-
if ( $render_callback = fw_akg( 'render', $this->get_callbacks() ) ) {
|
285 |
-
ob_start();
|
286 |
-
|
287 |
-
$data = call_user_func_array( $render_callback, array( $render_data, $this ) );
|
288 |
-
|
289 |
-
$html = ob_get_clean();
|
290 |
-
|
291 |
-
if ( empty( $data ) ) {
|
292 |
-
// fix if returned wrong data from callback
|
293 |
-
$data = $render_data;
|
294 |
-
}
|
295 |
-
|
296 |
-
$render_data = $data;
|
297 |
-
}
|
298 |
-
|
299 |
-
do_action( 'fw_form_display:before_form', $this );
|
300 |
-
|
301 |
-
// display form errors in frontend
|
302 |
-
echo '<form ' . fw_attr_to_html( $render_data['attr'] ) . ' >';
|
303 |
-
|
304 |
-
do_action( 'fw_form_display:before', $this );
|
305 |
-
|
306 |
-
echo fw_html_tag( 'input',
|
307 |
-
array(
|
308 |
-
'type' => 'hidden',
|
309 |
-
'name' => self::get_form_id_name(),
|
310 |
-
'value' => $this->get_id(),
|
311 |
-
) );
|
312 |
-
|
313 |
-
wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_name( $render_data ) );
|
314 |
-
|
315 |
-
if ( ! empty( $render_data['attr']['action'] ) && $render_data['attr']['method'] == 'get' ) {
|
316 |
-
/**
|
317 |
-
* Add query vars from the action attribute url to hidden inputs to not loose them
|
318 |
-
*/
|
319 |
-
|
320 |
-
parse_str( parse_url( $render_data['attr']['action'], PHP_URL_QUERY ), $query_vars );
|
321 |
-
|
322 |
-
if ( ! empty( $query_vars ) ) {
|
323 |
-
foreach ( $query_vars as $var_name => $var_value ) {
|
324 |
-
echo fw_html_tag( 'input',
|
325 |
-
array(
|
326 |
-
'type' => 'hidden',
|
327 |
-
'name' => $var_name,
|
328 |
-
'value' => $var_value,
|
329 |
-
) );
|
330 |
-
}
|
331 |
-
}
|
332 |
-
}
|
333 |
-
|
334 |
-
echo $html;
|
335 |
-
|
336 |
-
// In filter can be defined custom html for submit button
|
337 |
-
if ( isset( $render_data['submit']['html'] ) ) {
|
338 |
-
echo $render_data['submit']['html'];
|
339 |
-
} else {
|
340 |
-
echo fw_html_tag( 'input',
|
341 |
-
array(
|
342 |
-
'type' => 'submit',
|
343 |
-
'value' => $render_data['submit']['value']
|
344 |
-
) );
|
345 |
-
}
|
346 |
-
|
347 |
-
do_action( 'fw_form_display:after', $this );
|
348 |
-
|
349 |
-
echo '</form>';
|
350 |
-
|
351 |
-
do_action( 'fw_form_display:after_form', $this );
|
352 |
-
}
|
353 |
-
|
354 |
-
/**
|
355 |
-
* If now is a submit of this form
|
356 |
-
* @return bool
|
357 |
-
*/
|
358 |
-
public function is_submitted() {
|
359 |
-
return $this->request !== null;
|
360 |
-
}
|
361 |
-
|
362 |
-
/**
|
363 |
-
* @return bool
|
364 |
-
*/
|
365 |
-
public function is_valid() {
|
366 |
-
if ( ! $this->is_submitted() ) {
|
367 |
-
return null;
|
368 |
-
}
|
369 |
-
|
370 |
-
return count( $this->_get_errors() ) == 0;
|
371 |
-
}
|
372 |
-
|
373 |
-
/**
|
374 |
-
* @param array $request
|
375 |
-
*
|
376 |
-
* @throws FW_Form_Invalid_Submission_Exception
|
377 |
-
*
|
378 |
-
* @return mixed
|
379 |
-
*/
|
380 |
-
public function submit( array $request = array() ) {
|
381 |
-
$this->request = $request;
|
382 |
-
//Updated the deprecated member for those that extended the class and use it in code
|
383 |
-
$this->is_submitted = true;
|
384 |
-
|
385 |
-
$errors = $this->validate();
|
386 |
-
|
387 |
-
if ( ! empty( $errors ) ) {
|
388 |
-
throw new FW_Form_Invalid_Submission_Exception( $errors );
|
389 |
-
}
|
390 |
-
|
391 |
-
return $this->save();
|
392 |
-
}
|
393 |
-
|
394 |
-
protected function get_default_attr() {
|
395 |
-
return array(
|
396 |
-
'data-fw-form-id' => $this->get_id(),
|
397 |
-
'method' => 'post',
|
398 |
-
'action' => fw_current_url(),
|
399 |
-
'class' => 'fw_form_' . $this->get_id()
|
400 |
-
);
|
401 |
-
}
|
402 |
-
|
403 |
-
/**
|
404 |
-
* @param array $attr
|
405 |
-
*
|
406 |
-
* @return $this
|
407 |
-
*/
|
408 |
-
protected function set_attr( array $attr ) {
|
409 |
-
$this->attr = array_merge( $this->get_default_attr(), $attr );
|
410 |
-
|
411 |
-
return $this;
|
412 |
-
}
|
413 |
-
|
414 |
-
/**
|
415 |
-
* @param null $key
|
416 |
-
*
|
417 |
-
* @return array|mixed|null
|
418 |
-
*
|
419 |
-
* @since 2.6.15
|
420 |
-
*/
|
421 |
-
protected function get_request( $key = null ) {
|
422 |
-
return $key === null ? (array) $this->request : fw_akg( $key, $this->request );
|
423 |
-
}
|
424 |
-
|
425 |
-
/**
|
426 |
-
* @return string|null
|
427 |
-
*
|
428 |
-
* @since 2.6.15
|
429 |
-
*/
|
430 |
-
protected function get_nonce() {
|
431 |
-
return $this->get_request( $this->get_nonce_name() );
|
432 |
-
}
|
433 |
-
|
434 |
-
/**
|
435 |
-
* Returns forms errors without counting them as accessed
|
436 |
-
* @return array
|
437 |
-
*/
|
438 |
-
protected function _get_errors() {
|
439 |
-
return $this->errors;
|
440 |
-
}
|
441 |
-
|
442 |
-
/**
|
443 |
-
* @return string
|
444 |
-
*
|
445 |
-
* @since 2.6.15
|
446 |
-
*/
|
447 |
-
protected function get_nonce_action() {
|
448 |
-
return 'submit_fwf';
|
449 |
-
}
|
450 |
-
|
451 |
-
protected function check_nonce( $nonce ) {
|
452 |
-
return wp_verify_nonce( $nonce, $this->get_nonce_action() );
|
453 |
-
}
|
454 |
-
|
455 |
-
/**
|
456 |
-
* @return array
|
457 |
-
*/
|
458 |
-
protected function validate() {
|
459 |
-
/**
|
460 |
-
* Errors array {'input[name]' => 'Error message'}
|
461 |
-
*/
|
462 |
-
$errors = array();
|
463 |
-
|
464 |
-
if ( ! $this->check_nonce( $this->get_nonce() ) ) {
|
465 |
-
$errors[ $this->get_nonce_name() ] = esc_html__( 'Your session expired. Please refresh page and try again.', 'fw' );
|
466 |
-
}
|
467 |
-
|
468 |
-
/**
|
469 |
-
* Call validate callback
|
470 |
-
*
|
471 |
-
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
472 |
-
*/
|
473 |
-
if ( ( $validate = fw_akg( 'validate', $this->get_callbacks() ) ) ) {
|
474 |
-
$errors = (array) call_user_func( $validate, $errors );
|
475 |
-
}
|
476 |
-
|
477 |
-
return $this->set_errors( $errors )->_get_errors();
|
478 |
-
}
|
479 |
-
|
480 |
-
/**
|
481 |
-
* @return array|mixed
|
482 |
-
*/
|
483 |
-
protected function save() {
|
484 |
-
$save_data = array(
|
485 |
-
// you can set here a url for redirect after save
|
486 |
-
'redirect' => null
|
487 |
-
);
|
488 |
-
|
489 |
-
/**
|
490 |
-
* Call save callback
|
491 |
-
*
|
492 |
-
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
493 |
-
*/
|
494 |
-
if ( ( $save_callback = fw_akg( 'save', $this->get_callbacks() ) ) ) {
|
495 |
-
$data = call_user_func_array( $save_callback, array( $save_data ) );
|
496 |
-
|
497 |
-
if ( ! is_array( $data ) ) {
|
498 |
-
// fix if returned wrong data from callback
|
499 |
-
$data = $save_data;
|
500 |
-
}
|
501 |
-
|
502 |
-
$save_data = $data;
|
503 |
-
|
504 |
-
unset( $data );
|
505 |
-
}
|
506 |
-
|
507 |
-
return $save_data;
|
508 |
-
}
|
509 |
-
|
510 |
-
/**
|
511 |
-
* @return bool
|
512 |
-
*
|
513 |
-
* @deprecated 2.6.15
|
514 |
-
*/
|
515 |
-
protected function is_ajax() {
|
516 |
-
return self::_is_ajax();
|
517 |
-
}
|
518 |
-
|
519 |
-
protected function set_id( $id ) {
|
520 |
-
$this->id = $id;
|
521 |
-
|
522 |
-
return $this;
|
523 |
-
}
|
524 |
-
|
525 |
-
/**
|
526 |
-
* @param array $callbacks
|
527 |
-
*
|
528 |
-
* @return $this
|
529 |
-
*/
|
530 |
-
protected function set_callbacks( array $callbacks ) {
|
531 |
-
$this->callbacks = $callbacks;
|
532 |
-
|
533 |
-
return $this;
|
534 |
-
}
|
535 |
-
|
536 |
-
protected function set_errors( array $errors ) {
|
537 |
-
$this->errors = $errors;
|
538 |
-
|
539 |
-
return $this;
|
540 |
-
}
|
541 |
-
|
542 |
-
/**
|
543 |
-
* Some forms (like Forms extension frontend form) uses the same FW_Form instance for all sub-forms
|
544 |
-
* and they must be differentiated somehow.
|
545 |
-
* Fixes https://github.com/ThemeFuse/Unyson/issues/2033
|
546 |
-
*
|
547 |
-
* @param array $render_data
|
548 |
-
*
|
549 |
-
* @return string
|
550 |
-
* @since 2.6.6
|
551 |
-
*/
|
552 |
-
private function get_nonce_name( $render_data = array() ) {
|
553 |
-
return '_nonce_' . md5( $this->id . apply_filters( 'fw:form:nonce-name-data', '', $this, $render_data ) );
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* @return FW_Form[]
|
558 |
-
*
|
559 |
-
* @since 2.6.15
|
560 |
-
*/
|
561 |
-
public static function get_forms() {
|
562 |
-
return self::$forms;
|
563 |
-
}
|
564 |
-
|
565 |
-
/**
|
566 |
-
* @param $id
|
567 |
-
*
|
568 |
-
* @return FW_Form
|
569 |
-
* @throws FW_Form_Not_Found_Exception
|
570 |
-
*
|
571 |
-
* @since 2.6.15
|
572 |
-
*/
|
573 |
-
public static function get_form( $id ) {
|
574 |
-
if ( ! isset( self::$forms[ $id ] ) ) {
|
575 |
-
throw new FW_Form_Not_Found_Exception( "FW_Form $id was not defined" );
|
576 |
-
}
|
577 |
-
|
578 |
-
return self::$forms[ $id ];
|
579 |
-
}
|
580 |
-
|
581 |
-
/**
|
582 |
-
* Get submitted form instance (or false if no form is currently submitted)
|
583 |
-
* @return FW_Form|false
|
584 |
-
*/
|
585 |
-
public static function get_submitted() {
|
586 |
-
foreach ( self::get_forms() as $id => $form ) {
|
587 |
-
if ( self::is_form_submitted( $id ) ) {
|
588 |
-
return $form;
|
589 |
-
}
|
590 |
-
}
|
591 |
-
|
592 |
-
return false;
|
593 |
-
}
|
594 |
-
|
595 |
-
/**
|
596 |
-
* @return bool
|
597 |
-
*
|
598 |
-
* @since 2.6.15
|
599 |
-
*/
|
600 |
-
public static function _is_ajax() {
|
601 |
-
return ( defined( 'DOING_AJAX' ) && DOING_AJAX )
|
602 |
-
||
|
603 |
-
strtolower( fw_akg( 'HTTP_X_REQUESTED_WITH', $_SERVER ) ) == 'xmlhttprequest';
|
604 |
-
}
|
605 |
-
|
606 |
-
public static function get_form_request( $id ) {
|
607 |
-
if ( FW_Request::POST( self::get_form_id_name() ) == $id ) {
|
608 |
-
return FW_Request::POST();
|
609 |
-
}
|
610 |
-
|
611 |
-
if ( FW_Request::GET( self::get_form_id_name() ) == $id ) {
|
612 |
-
return FW_Request::GET();
|
613 |
-
}
|
614 |
-
|
615 |
-
return null;
|
616 |
-
}
|
617 |
-
|
618 |
-
/**
|
619 |
-
* @return string
|
620 |
-
*
|
621 |
-
* @since 2.6.15
|
622 |
-
*/
|
623 |
-
protected static function get_form_id_name() {
|
624 |
-
return 'fwf';
|
625 |
-
}
|
626 |
-
|
627 |
-
/**
|
628 |
-
* @param $id
|
629 |
-
*
|
630 |
-
* @return bool
|
631 |
-
*
|
632 |
-
* @since 2.6.15
|
633 |
-
*/
|
634 |
-
protected static function is_form_submitted( $id ) {
|
635 |
-
return self::get_form_request( $id ) !== null;
|
636 |
-
}
|
637 |
-
|
638 |
-
private static function collect_flash_messages() {
|
639 |
-
$flash_messages = array();
|
640 |
-
|
641 |
-
foreach ( FW_Flash_Messages::_get_messages( true ) as $type => $messages ) {
|
642 |
-
$flash_messages[ $type ] = array();
|
643 |
-
|
644 |
-
foreach ( $messages as $id => $message_data ) {
|
645 |
-
$flash_messages[ $type ][ $id ] = $message_data['message'];
|
646 |
-
}
|
647 |
-
}
|
648 |
-
|
649 |
-
return $flash_messages;
|
650 |
-
}
|
651 |
}
|
1 |
+
<?php if ( ! defined( 'FW' ) ) {
|
2 |
+
die( 'Forbidden' );
|
3 |
+
}
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Dynamic forms
|
7 |
+
*/
|
8 |
+
class FW_Form {
|
9 |
+
/**
|
10 |
+
* Store all form ids created with this class
|
11 |
+
* @var FW_Form[] {'form_id' => instance}
|
12 |
+
*
|
13 |
+
* @deprecated 2.6.15 Use FW_Form::get_forms()
|
14 |
+
*/
|
15 |
+
protected static $forms = array();
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The id of the submitted form id
|
19 |
+
* @var string
|
20 |
+
*
|
21 |
+
* @deprecated 2.6.15
|
22 |
+
*/
|
23 |
+
protected static $submitted_id;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Hidden input name that stores the form id
|
27 |
+
* @var string
|
28 |
+
*
|
29 |
+
* @deprecated 2.6.15 Use self::get_form_id_name()
|
30 |
+
*/
|
31 |
+
protected static $id_input_name = 'fwf';
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Form id
|
35 |
+
* @var string
|
36 |
+
*
|
37 |
+
* @deprecated 2.6.15 Use $this->get_id()
|
38 |
+
*/
|
39 |
+
protected $id;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Html attributes for <form> tag
|
43 |
+
* @var array
|
44 |
+
*
|
45 |
+
* @deprecated 2.6.15 Use $this->attr()
|
46 |
+
*/
|
47 |
+
protected $attr = array();
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Found validation errors
|
51 |
+
* @var array
|
52 |
+
*/
|
53 |
+
protected $errors;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* If the get_errors() method was called at leas once
|
57 |
+
* @var bool
|
58 |
+
*/
|
59 |
+
protected $errors_accessed = false;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* If current request is the submit of this form
|
63 |
+
* @var bool
|
64 |
+
*
|
65 |
+
* @deprecated 2.6.15 Use $this->is_submitted()
|
66 |
+
*/
|
67 |
+
protected $is_submitted;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @var bool
|
71 |
+
*
|
72 |
+
* @deprecated 2.6.15
|
73 |
+
*/
|
74 |
+
protected $validate_and_save_called = false;
|
75 |
+
|
76 |
+
/**
|
77 |
+
* @var array
|
78 |
+
*
|
79 |
+
* @deprecated 2.6.15 Use $this->get_callbacks()
|
80 |
+
*/
|
81 |
+
protected $callbacks = array(
|
82 |
+
'render' => false,
|
83 |
+
'validate' => false,
|
84 |
+
'save' => false
|
85 |
+
);
|
86 |
+
|
87 |
+
private $request;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param string $id Unique
|
91 |
+
* @param array $data (optional)
|
92 |
+
* array(
|
93 |
+
* 'render' => callback // The callback that will render the form's html
|
94 |
+
* 'validate' => callback // The callback that will validate user input
|
95 |
+
* 'save' => callback // The callback that will save successfully validated user input
|
96 |
+
* 'attr' => array() // Custom <form ...> attributes
|
97 |
+
* )
|
98 |
+
*/
|
99 |
+
public function __construct( $id, $data = array() ) {
|
100 |
+
try {
|
101 |
+
self::get_form( $id );
|
102 |
+
trigger_error( sprintf( __( 'Form with id "%s" was already defined', 'fw' ), $id ), E_USER_ERROR );
|
103 |
+
|
104 |
+
return;
|
105 |
+
} catch ( FW_Form_Not_Found_Exception $e ) {
|
106 |
+
}
|
107 |
+
|
108 |
+
$this
|
109 |
+
// set id
|
110 |
+
->set_id( $id )
|
111 |
+
// prepare callbacks
|
112 |
+
->set_callbacks( array(
|
113 |
+
'render' => fw_akg( 'render', $data, false ),
|
114 |
+
'validate' => fw_akg( 'validate', $data, false ),
|
115 |
+
'save' => fw_akg( 'save', $data, false ),
|
116 |
+
) )
|
117 |
+
// prepare attributes
|
118 |
+
->set_attr( (array) fw_akg( 'attr', $data, array() ) );
|
119 |
+
|
120 |
+
self::$forms[ $this->get_id() ] =& $this;
|
121 |
+
|
122 |
+
if ( did_action( 'wp_loaded' ) ) {
|
123 |
+
// in case if form instance was created after action
|
124 |
+
$this->_validate_and_save();
|
125 |
+
} else {
|
126 |
+
// attach to an action before 'send_headers' action, to be able to do redirects
|
127 |
+
add_action( 'wp_loaded', array( $this, '_validate_and_save' ), 101 );
|
128 |
+
}
|
129 |
+
|
130 |
+
add_action( 'fw_form_display:before_form', array( $this, '_action_fw_form_show_errors' ) );
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @return string
|
135 |
+
*/
|
136 |
+
public function get_id() {
|
137 |
+
return $this->id;
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Get validation errors
|
142 |
+
* @return array
|
143 |
+
*/
|
144 |
+
public function get_errors() {
|
145 |
+
if ( ! $this->validate_and_save_called ) {
|
146 |
+
fw_print( debug_backtrace() );
|
147 |
+
trigger_error( __METHOD__ . ' called before validation', E_USER_WARNING );
|
148 |
+
|
149 |
+
return array( '~' => true );
|
150 |
+
}
|
151 |
+
|
152 |
+
$this->errors_accessed = true;
|
153 |
+
|
154 |
+
return $this->_get_errors();
|
155 |
+
}
|
156 |
+
|
157 |
+
public function get_callbacks() {
|
158 |
+
return $this->callbacks;
|
159 |
+
}
|
160 |
+
|
161 |
+
public function errors_accessed() {
|
162 |
+
return $this->errors_accessed;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* If current form was submitted, validate and save it
|
167 |
+
*
|
168 |
+
* Note: This callback can abort script execution if save does redirect
|
169 |
+
*
|
170 |
+
* @internal
|
171 |
+
*/
|
172 |
+
public function _validate_and_save() {
|
173 |
+
|
174 |
+
if ( ! self::is_form_submitted( $this->get_id() ) || $this->validate_and_save_called ) {
|
175 |
+
return;
|
176 |
+
}
|
177 |
+
|
178 |
+
$this->validate_and_save_called = true;
|
179 |
+
|
180 |
+
try {
|
181 |
+
$data = $this->submit( self::get_form_request( $this->get_id() ) );
|
182 |
+
|
183 |
+
if ( $this->_is_ajax() ) {
|
184 |
+
wp_send_json_success( array(
|
185 |
+
'save_data' => $data,
|
186 |
+
'flash_messages' => self::collect_flash_messages(),
|
187 |
+
) );
|
188 |
+
}
|
189 |
+
|
190 |
+
if ( ( $redirect = fw_akg( 'redirect', $data ) ) ) {
|
191 |
+
wp_redirect( $redirect );
|
192 |
+
exit;
|
193 |
+
}
|
194 |
+
} catch ( FW_Form_Invalid_Submission_Exception $e ) {
|
195 |
+
if ( $this->_is_ajax() ) {
|
196 |
+
wp_send_json_error( array(
|
197 |
+
'errors' => $this->get_errors(),
|
198 |
+
'flash_messages' => self::collect_flash_messages()
|
199 |
+
) );
|
200 |
+
}
|
201 |
+
}
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
* @param FW_Form $form
|
206 |
+
*
|
207 |
+
* @internal
|
208 |
+
*
|
209 |
+
* You can overwrite it in case you do not need the errors to be shown for your form
|
210 |
+
*/
|
211 |
+
public function _action_fw_form_show_errors( $form ) {
|
212 |
+
if (
|
213 |
+
$form->get_id() != $this->get_id()
|
214 |
+
// errors in admin side are displayed by a script at the end of this file
|
215 |
+
|| is_admin()
|
216 |
+
|| ! $form->is_submitted()
|
217 |
+
|| $form->is_valid()
|
218 |
+
|| $form->errors_accessed()
|
219 |
+
) {
|
220 |
+
|
221 |
+
return;
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Use this action to customize errors display in your theme
|
226 |
+
*/
|
227 |
+
do_action( 'fw_form_display_errors_frontend', $form );
|
228 |
+
|
229 |
+
$errors = $form->get_errors();
|
230 |
+
|
231 |
+
if ( empty( $errors ) ) {
|
232 |
+
return;
|
233 |
+
}
|
234 |
+
|
235 |
+
echo '<ul class="fw-form-errors">';
|
236 |
+
|
237 |
+
foreach ( $errors as $input_name => $error_message ) {
|
238 |
+
echo fw_html_tag(
|
239 |
+
'li',
|
240 |
+
array(
|
241 |
+
'data-input-name' => $input_name,
|
242 |
+
),
|
243 |
+
$error_message
|
244 |
+
);
|
245 |
+
}
|
246 |
+
|
247 |
+
echo '</ul>';
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Get html attribute(s)
|
252 |
+
*
|
253 |
+
* @param null|string $name
|
254 |
+
*
|
255 |
+
* @return array|string
|
256 |
+
*/
|
257 |
+
public function attr( $name = null ) {
|
258 |
+
return $name !== null
|
259 |
+
? fw_akg( $name, $this->attr )
|
260 |
+
: $this->attr;
|
261 |
+
}
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Render form's html
|
265 |
+
*
|
266 |
+
* @param array $data
|
267 |
+
*/
|
268 |
+
public function render( $data = array() ) {
|
269 |
+
$render_data = array(
|
270 |
+
'submit' => array(
|
271 |
+
'value' => __( 'Submit', 'fw' ),
|
272 |
+
/**
|
273 |
+
* you can set here custom submit button html
|
274 |
+
* and the 'value' parameter will not be used
|
275 |
+
*/
|
276 |
+
'html' => null,
|
277 |
+
),
|
278 |
+
'data' => $data,
|
279 |
+
'attr' => $this->attr(),
|
280 |
+
);
|
281 |
+
|
282 |
+
$html = '';
|
283 |
+
|
284 |
+
if ( $render_callback = fw_akg( 'render', $this->get_callbacks() ) ) {
|
285 |
+
ob_start();
|
286 |
+
|
287 |
+
$data = call_user_func_array( $render_callback, array( $render_data, $this ) );
|
288 |
+
|
289 |
+
$html = ob_get_clean();
|
290 |
+
|
291 |
+
if ( empty( $data ) ) {
|
292 |
+
// fix if returned wrong data from callback
|
293 |
+
$data = $render_data;
|
294 |
+
}
|
295 |
+
|
296 |
+
$render_data = $data;
|
297 |
+
}
|
298 |
+
|
299 |
+
do_action( 'fw_form_display:before_form', $this );
|
300 |
+
|
301 |
+
// display form errors in frontend
|
302 |
+
echo '<form ' . fw_attr_to_html( $render_data['attr'] ) . ' >';
|
303 |
+
|
304 |
+
do_action( 'fw_form_display:before', $this );
|
305 |
+
|
306 |
+
echo fw_html_tag( 'input',
|
307 |
+
array(
|
308 |
+
'type' => 'hidden',
|
309 |
+
'name' => self::get_form_id_name(),
|
310 |
+
'value' => $this->get_id(),
|
311 |
+
) );
|
312 |
+
|
313 |
+
wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_name( $render_data ) );
|
314 |
+
|
315 |
+
if ( ! empty( $render_data['attr']['action'] ) && $render_data['attr']['method'] == 'get' ) {
|
316 |
+
/**
|
317 |
+
* Add query vars from the action attribute url to hidden inputs to not loose them
|
318 |
+
*/
|
319 |
+
|
320 |
+
parse_str( parse_url( $render_data['attr']['action'], PHP_URL_QUERY ), $query_vars );
|
321 |
+
|
322 |
+
if ( ! empty( $query_vars ) ) {
|
323 |
+
foreach ( $query_vars as $var_name => $var_value ) {
|
324 |
+
echo fw_html_tag( 'input',
|
325 |
+
array(
|
326 |
+
'type' => 'hidden',
|
327 |
+
'name' => $var_name,
|
328 |
+
'value' => $var_value,
|
329 |
+
) );
|
330 |
+
}
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
echo $html;
|
335 |
+
|
336 |
+
// In filter can be defined custom html for submit button
|
337 |
+
if ( isset( $render_data['submit']['html'] ) ) {
|
338 |
+
echo $render_data['submit']['html'];
|
339 |
+
} else {
|
340 |
+
echo fw_html_tag( 'input',
|
341 |
+
array(
|
342 |
+
'type' => 'submit',
|
343 |
+
'value' => $render_data['submit']['value']
|
344 |
+
) );
|
345 |
+
}
|
346 |
+
|
347 |
+
do_action( 'fw_form_display:after', $this );
|
348 |
+
|
349 |
+
echo '</form>';
|
350 |
+
|
351 |
+
do_action( 'fw_form_display:after_form', $this );
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* If now is a submit of this form
|
356 |
+
* @return bool
|
357 |
+
*/
|
358 |
+
public function is_submitted() {
|
359 |
+
return $this->request !== null;
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* @return bool
|
364 |
+
*/
|
365 |
+
public function is_valid() {
|
366 |
+
if ( ! $this->is_submitted() ) {
|
367 |
+
return null;
|
368 |
+
}
|
369 |
+
|
370 |
+
return count( $this->_get_errors() ) == 0;
|
371 |
+
}
|
372 |
+
|
373 |
+
/**
|
374 |
+
* @param array $request
|
375 |
+
*
|
376 |
+
* @throws FW_Form_Invalid_Submission_Exception
|
377 |
+
*
|
378 |
+
* @return mixed
|
379 |
+
*/
|
380 |
+
public function submit( array $request = array() ) {
|
381 |
+
$this->request = $request;
|
382 |
+
//Updated the deprecated member for those that extended the class and use it in code
|
383 |
+
$this->is_submitted = true;
|
384 |
+
|
385 |
+
$errors = $this->validate();
|
386 |
+
|
387 |
+
if ( ! empty( $errors ) ) {
|
388 |
+
throw new FW_Form_Invalid_Submission_Exception( $errors );
|
389 |
+
}
|
390 |
+
|
391 |
+
return $this->save();
|
392 |
+
}
|
393 |
+
|
394 |
+
protected function get_default_attr() {
|
395 |
+
return array(
|
396 |
+
'data-fw-form-id' => $this->get_id(),
|
397 |
+
'method' => 'post',
|
398 |
+
'action' => fw_current_url(),
|
399 |
+
'class' => 'fw_form_' . $this->get_id()
|
400 |
+
);
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* @param array $attr
|
405 |
+
*
|
406 |
+
* @return $this
|
407 |
+
*/
|
408 |
+
protected function set_attr( array $attr ) {
|
409 |
+
$this->attr = array_merge( $this->get_default_attr(), $attr );
|
410 |
+
|
411 |
+
return $this;
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* @param null $key
|
416 |
+
*
|
417 |
+
* @return array|mixed|null
|
418 |
+
*
|
419 |
+
* @since 2.6.15
|
420 |
+
*/
|
421 |
+
protected function get_request( $key = null ) {
|
422 |
+
return $key === null ? (array) $this->request : fw_akg( $key, $this->request );
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* @return string|null
|
427 |
+
*
|
428 |
+
* @since 2.6.15
|
429 |
+
*/
|
430 |
+
protected function get_nonce() {
|
431 |
+
return $this->get_request( $this->get_nonce_name() );
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Returns forms errors without counting them as accessed
|
436 |
+
* @return array
|
437 |
+
*/
|
438 |
+
protected function _get_errors() {
|
439 |
+
return $this->errors;
|
440 |
+
}
|
441 |
+
|
442 |
+
/**
|
443 |
+
* @return string
|
444 |
+
*
|
445 |
+
* @since 2.6.15
|
446 |
+
*/
|
447 |
+
protected function get_nonce_action() {
|
448 |
+
return 'submit_fwf';
|
449 |
+
}
|
450 |
+
|
451 |
+
protected function check_nonce( $nonce ) {
|
452 |
+
return wp_verify_nonce( $nonce, $this->get_nonce_action() );
|
453 |
+
}
|
454 |
+
|
455 |
+
/**
|
456 |
+
* @return array
|
457 |
+
*/
|
458 |
+
protected function validate() {
|
459 |
+
/**
|
460 |
+
* Errors array {'input[name]' => 'Error message'}
|
461 |
+
*/
|
462 |
+
$errors = array();
|
463 |
+
|
464 |
+
if ( ! $this->check_nonce( $this->get_nonce() ) ) {
|
465 |
+
$errors[ $this->get_nonce_name() ] = esc_html__( 'Your session expired. Please refresh page and try again.', 'fw' );
|
466 |
+
}
|
467 |
+
|
468 |
+
/**
|
469 |
+
* Call validate callback
|
470 |
+
*
|
471 |
+
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
472 |
+
*/
|
473 |
+
if ( ( $validate = fw_akg( 'validate', $this->get_callbacks() ) ) ) {
|
474 |
+
$errors = (array) call_user_func( $validate, $errors );
|
475 |
+
}
|
476 |
+
|
477 |
+
return $this->set_errors( $errors )->_get_errors();
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* @return array|mixed
|
482 |
+
*/
|
483 |
+
protected function save() {
|
484 |
+
$save_data = array(
|
485 |
+
// you can set here a url for redirect after save
|
486 |
+
'redirect' => null
|
487 |
+
);
|
488 |
+
|
489 |
+
/**
|
490 |
+
* Call save callback
|
491 |
+
*
|
492 |
+
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
493 |
+
*/
|
494 |
+
if ( ( $save_callback = fw_akg( 'save', $this->get_callbacks() ) ) ) {
|
495 |
+
$data = call_user_func_array( $save_callback, array( $save_data ) );
|
496 |
+
|
497 |
+
if ( ! is_array( $data ) ) {
|
498 |
+
// fix if returned wrong data from callback
|
499 |
+
$data = $save_data;
|
500 |
+
}
|
501 |
+
|
502 |
+
$save_data = $data;
|
503 |
+
|
504 |
+
unset( $data );
|
505 |
+
}
|
506 |
+
|
507 |
+
return $save_data;
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* @return bool
|
512 |
+
*
|
513 |
+
* @deprecated 2.6.15
|
514 |
+
*/
|
515 |
+
protected function is_ajax() {
|
516 |
+
return self::_is_ajax();
|
517 |
+
}
|
518 |
+
|
519 |
+
protected function set_id( $id ) {
|
520 |
+
$this->id = $id;
|
521 |
+
|
522 |
+
return $this;
|
523 |
+
}
|
524 |
+
|
525 |
+
/**
|
526 |
+
* @param array $callbacks
|
527 |
+
*
|
528 |
+
* @return $this
|
529 |
+
*/
|
530 |
+
protected function set_callbacks( array $callbacks ) {
|
531 |
+
$this->callbacks = $callbacks;
|
532 |
+
|
533 |
+
return $this;
|
534 |
+
}
|
535 |
+
|
536 |
+
protected function set_errors( array $errors ) {
|
537 |
+
$this->errors = $errors;
|
538 |
+
|
539 |
+
return $this;
|
540 |
+
}
|
541 |
+
|
542 |
+
/**
|
543 |
+
* Some forms (like Forms extension frontend form) uses the same FW_Form instance for all sub-forms
|
544 |
+
* and they must be differentiated somehow.
|
545 |
+
* Fixes https://github.com/ThemeFuse/Unyson/issues/2033
|
546 |
+
*
|
547 |
+
* @param array $render_data
|
548 |
+
*
|
549 |
+
* @return string
|
550 |
+
* @since 2.6.6
|
551 |
+
*/
|
552 |
+
private function get_nonce_name( $render_data = array() ) {
|
553 |
+
return '_nonce_' . md5( $this->id . apply_filters( 'fw:form:nonce-name-data', '', $this, $render_data ) );
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* @return FW_Form[]
|
558 |
+
*
|
559 |
+
* @since 2.6.15
|
560 |
+
*/
|
561 |
+
public static function get_forms() {
|
562 |
+
return self::$forms;
|
563 |
+
}
|
564 |
+
|
565 |
+
/**
|
566 |
+
* @param $id
|
567 |
+
*
|
568 |
+
* @return FW_Form
|
569 |
+
* @throws FW_Form_Not_Found_Exception
|
570 |
+
*
|
571 |
+
* @since 2.6.15
|
572 |
+
*/
|
573 |
+
public static function get_form( $id ) {
|
574 |
+
if ( ! isset( self::$forms[ $id ] ) ) {
|
575 |
+
throw new FW_Form_Not_Found_Exception( "FW_Form $id was not defined" );
|
576 |
+
}
|
577 |
+
|
578 |
+
return self::$forms[ $id ];
|
579 |
+
}
|
580 |
+
|
581 |
+
/**
|
582 |
+
* Get submitted form instance (or false if no form is currently submitted)
|
583 |
+
* @return FW_Form|false
|
584 |
+
*/
|
585 |
+
public static function get_submitted() {
|
586 |
+
foreach ( self::get_forms() as $id => $form ) {
|
587 |
+
if ( self::is_form_submitted( $id ) ) {
|
588 |
+
return $form;
|
589 |
+
}
|
590 |
+
}
|
591 |
+
|
592 |
+
return false;
|
593 |
+
}
|
594 |
+
|
595 |
+
/**
|
596 |
+
* @return bool
|
597 |
+
*
|
598 |
+
* @since 2.6.15
|
599 |
+
*/
|
600 |
+
public static function _is_ajax() {
|
601 |
+
return ( defined( 'DOING_AJAX' ) && DOING_AJAX )
|
602 |
+
||
|
603 |
+
strtolower( fw_akg( 'HTTP_X_REQUESTED_WITH', $_SERVER ) ) == 'xmlhttprequest';
|
604 |
+
}
|
605 |
+
|
606 |
+
public static function get_form_request( $id ) {
|
607 |
+
if ( FW_Request::POST( self::get_form_id_name() ) == $id ) {
|
608 |
+
return FW_Request::POST();
|
609 |
+
}
|
610 |
+
|
611 |
+
if ( FW_Request::GET( self::get_form_id_name() ) == $id ) {
|
612 |
+
return FW_Request::GET();
|
613 |
+
}
|
614 |
+
|
615 |
+
return null;
|
616 |
+
}
|
617 |
+
|
618 |
+
/**
|
619 |
+
* @return string
|
620 |
+
*
|
621 |
+
* @since 2.6.15
|
622 |
+
*/
|
623 |
+
protected static function get_form_id_name() {
|
624 |
+
return 'fwf';
|
625 |
+
}
|
626 |
+
|
627 |
+
/**
|
628 |
+
* @param $id
|
629 |
+
*
|
630 |
+
* @return bool
|
631 |
+
*
|
632 |
+
* @since 2.6.15
|
633 |
+
*/
|
634 |
+
protected static function is_form_submitted( $id ) {
|
635 |
+
return self::get_form_request( $id ) !== null;
|
636 |
+
}
|
637 |
+
|
638 |
+
private static function collect_flash_messages() {
|
639 |
+
$flash_messages = array();
|
640 |
+
|
641 |
+
foreach ( FW_Flash_Messages::_get_messages( true ) as $type => $messages ) {
|
642 |
+
$flash_messages[ $type ] = array();
|
643 |
+
|
644 |
+
foreach ( $messages as $id => $message_data ) {
|
645 |
+
$flash_messages[ $type ][ $id ] = $message_data['message'];
|
646 |
+
}
|
647 |
+
}
|
648 |
+
|
649 |
+
return $flash_messages;
|
650 |
+
}
|
651 |
}
|
framework/helpers/class-fw-request.php
CHANGED
@@ -1,90 +1,90 @@
|
|
1 |
-
<?php if (!defined('FW')) die('Forbidden');
|
2 |
-
|
3 |
-
/**
|
4 |
-
* WordPress automatically adds slashes to:
|
5 |
-
* $_REQUEST
|
6 |
-
* $_POST
|
7 |
-
* $_GET
|
8 |
-
* $_COOKIE
|
9 |
-
*
|
10 |
-
* For e.g.
|
11 |
-
*
|
12 |
-
* If value is simple, get value directly:
|
13 |
-
* $foo = isset($_GET['bar']) && $_GET['bar'] == 'yes';
|
14 |
-
*
|
15 |
-
* If value can contain some user input and can have quotes or json
|
16 |
-
* $foo = json_decode(FW_Request::POST('bar')); // json_decode($_POST('bar')) will not work if json will contain quotes
|
17 |
-
*
|
18 |
-
* You can test that problem.
|
19 |
-
* Add somewhere this code:
|
20 |
-
fw_print(array(
|
21 |
-
$_GET['test'],
|
22 |
-
json_decode($_GET['test']),
|
23 |
-
FW_Request::GET('test'),
|
24 |
-
json_decode(FW_Request::GET('test'))
|
25 |
-
));
|
26 |
-
* and access: http://your-site.com/?test={'a':1}
|
27 |
-
*/
|
28 |
-
class FW_Request
|
29 |
-
{
|
30 |
-
protected static function prepare_key($key)
|
31 |
-
{
|
32 |
-
return (get_magic_quotes_gpc() && is_string($key) ? addslashes($key) : $key);
|
33 |
-
}
|
34 |
-
|
35 |
-
protected static function get_set_key($multikey = null, $set_value = null, &$value)
|
36 |
-
{
|
37 |
-
$multikey = self::prepare_key($multikey);
|
38 |
-
|
39 |
-
if ($set_value === null) { // get
|
40 |
-
return fw_stripslashes_deep_keys($multikey === null ? $value : fw_akg($multikey, $value));
|
41 |
-
} else { // set
|
42 |
-
fw_aks($multikey, fw_addslashes_deep_keys($set_value), $value);
|
43 |
-
}
|
44 |
-
|
45 |
-
return '';
|
46 |
-
}
|
47 |
-
|
48 |
-
public static function GET($multikey = null, $default_value = null)
|
49 |
-
{
|
50 |
-
return fw_stripslashes_deep_keys(
|
51 |
-
$multikey === null
|
52 |
-
? $_GET
|
53 |
-
: fw_akg($multikey, $_GET, $default_value)
|
54 |
-
);
|
55 |
-
}
|
56 |
-
|
57 |
-
public static function POST($multikey = null, $default_value = null)
|
58 |
-
{
|
59 |
-
return fw_stripslashes_deep_keys(
|
60 |
-
$multikey === null
|
61 |
-
? $_POST
|
62 |
-
: fw_akg($multikey, $_POST, $default_value)
|
63 |
-
);
|
64 |
-
}
|
65 |
-
|
66 |
-
public static function COOKIE($multikey = null, $set_value = null, $expire = 0, $path = null)
|
67 |
-
{
|
68 |
-
if ($set_value !== null) {
|
69 |
-
|
70 |
-
// transforms a string ( key1/key2/key3 => key1][key2][key3] )
|
71 |
-
$multikey = str_replace('/', '][', $multikey) . ']';
|
72 |
-
|
73 |
-
// removes the first closed square bracket ( key1][key2][key3] => key1[key2][key3] )
|
74 |
-
$multikey = preg_replace('/\]/', '', $multikey, 1);
|
75 |
-
|
76 |
-
return setcookie($multikey, $set_value, $expire, $path);
|
77 |
-
} else {
|
78 |
-
return self::get_set_key($multikey, $set_value, $_COOKIE);
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
public static function REQUEST($multikey = null, $default_value = null)
|
83 |
-
{
|
84 |
-
return fw_stripslashes_deep_keys(
|
85 |
-
$multikey === null
|
86 |
-
? $_REQUEST
|
87 |
-
: fw_akg($multikey, $_REQUEST, $default_value)
|
88 |
-
);
|
89 |
-
}
|
90 |
-
}
|
1 |
+
<?php if (!defined('FW')) die('Forbidden');
|
2 |
+
|
3 |
+
/**
|
4 |
+
* WordPress automatically adds slashes to:
|
5 |
+
* $_REQUEST
|
6 |
+
* $_POST
|
7 |
+
* $_GET
|
8 |
+
* $_COOKIE
|
9 |
+
*
|
10 |
+
* For e.g.
|
11 |
+
*
|
12 |
+
* If value is simple, get value directly:
|
13 |
+
* $foo = isset($_GET['bar']) && $_GET['bar'] == 'yes';
|
14 |
+
*
|
15 |
+
* If value can contain some user input and can have quotes or json fr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|