Version Description
- Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
- WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
- Cache-Control header is now added in .htaccess, when redirecting directly to existing webp
For more info, see the closed issues on the 0.10.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/7?closed=1
Download this release
Release Info
Developer | rosell.dk |
Plugin | WebP Express |
Version | 0.10.0 |
Comparing to | |
See all releases |
Code changes from version 0.9.1 to 0.10.0
- BACKERS.md +13 -25
- README.md +168 -10
- README.txt +217 -26
- changelog.txt +12 -5
- lib/admin.php +1 -1
- lib/classes/CacheMover.php +153 -0
- lib/classes/Config.php +186 -69
- lib/classes/FileHelper.php +22 -0
- lib/classes/HTAccess.php +215 -94
- lib/classes/Paths.php +37 -10
- lib/migrate/migrate.php +12 -0
- lib/migrate/migrate4.php +68 -0
- lib/options/css/webp-express-options-page.css +37 -4
- lib/options/enqueue_scripts.php +23 -10
- lib/options/js/converters.js +1 -153
- lib/options/js/page.js +77 -21
- lib/options/options/cache-control.inc +0 -25
- lib/options/options/conversion-options/conversion-options.inc +28 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/cwebp.php +0 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/ewww.php +0 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/gd.php +0 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/imagick.php +0 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/imagickbinary.php +0 -0
- lib/options/options/{converter-options → conversion-options/converter-options}/wpc.php +0 -0
- lib/options/options/{converters.inc → conversion-options/converters.inc} +0 -0
- lib/options/options/conversion-options/destination-extension.inc +15 -0
- lib/options/options/conversion-options/destination-folder.inc +15 -0
- lib/options/options/{metadata.inc → conversion-options/metadata.inc} +0 -0
- lib/options/options/{quality.inc → conversion-options/quality.inc} +0 -0
- lib/options/options/do-not-pass-source-path-in-query-string.inc +0 -6
- lib/options/options/image-types.inc +0 -22
- lib/options/options/operation-mode.inc +73 -0
- lib/options/options/redirect-to-existing.inc +0 -8
- lib/options/options/redirection-rules/add-vary-header-in-htaccess.inc +12 -0
- lib/options/options/redirection-rules/do-not-pass-source-path-in-query-string.inc +6 -0
- lib/options/options/redirection-rules/enable-redirection-to-converter.inc +18 -0
- lib/options/options/redirection-rules/image-types.inc +36 -0
- lib/options/options/redirection-rules/only-redirect-to-converter-for-webp-enabled-browsers.inc +13 -0
- lib/options/options/redirection-rules/only-redirect-to-converter-on-cache-miss.inc +8 -0
- lib/options/options/redirection-rules/redirect-to-existing.inc +11 -0
- lib/options/options/redirection-rules/redirection-rules.inc +33 -0
- lib/options/options/serve-options/cache-control.inc +115 -0
- lib/options/options/{response-on-failure.inc → serve-options/response-on-failure.inc} +0 -0
- lib/options/options/serve-options/response-on-success.inc +12 -0
- lib/options/options/serve-options/serve-options.inc +21 -0
- lib/options/options/web-service-options/web-service-options.inc +16 -0
- lib/options/options/{web-service.inc → web-service-options/web-service.inc} +1 -1
- lib/options/page-messages.php +1 -1
- lib/options/page.php +51 -66
- lib/options/submit.php +163 -160
- test/test.jpg.webp +0 -0
- test/test.webp +0 -0
- webp-express.php +1 -1
- wod/.webp +0 -0
- wod/webp-on-demand.php +87 -23
BACKERS.md
CHANGED
@@ -1,38 +1,26 @@
|
|
1 |
-
There are no backers yet. Become the first, by backing me up financially at patreon.com.
|
2 |
-
Your name will then appear here.
|
3 |
|
4 |
-
|
5 |
|
|
|
6 |
|
7 |
-
|
8 |
|
9 |
-
|
10 |
|
11 |
-
Generous backers will get their names listed here, along with a message - max 100 chars, and it may contain one link (the link url does not count any chars).
|
12 |
|
13 |
-
|
14 |
|
15 |
-
| Name | Date | Message (70 chars
|
16 |
| --------------------- | ---------- | ----------------------------------------------------------------------- |
|
17 |
-
|
|
18 |
-
| John Doe 2 | 2018-11-23 | I do in fact sell shoes - with WebP Express logo! [Check it out!]((https://printed-shoes.com/) |
|
19 |
-
|
20 |
-
<small>
|
21 |
-
I reserve the right to disallow inappropriate messages and links. No xxx sites or anything freaky or fishy, please. You may however advertise non-freaky-or-fishy things, if you wish. Just remember the audience. No point in trying to sell shoes here</small>
|
22 |
-
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
There are no backers yet. [Be the first!](https://www.patreon.com/rosell)
|
27 |
|
28 |
-
|
29 |
|
30 |
-
|
31 |
|
32 |
-
|
33 |
-
| --------------------- | ---------- | ----------------------------------------------------------------------- |
|
34 |
-
| John Doe | 2018-11-23 | Your children shouldn't just eat bananas. Buy some oranges too! |
|
35 |
-
| John Doe 2 | 2018-11-23 | Perhaps you could work on multisite support? |
|
36 |
-
| John Doe 3 | 2018-11-23 | Thank you. Your plugin changed my life! |
|
37 |
|
38 |
-
<
|
|
|
|
|
|
1 |
|
2 |
+
# Backers
|
3 |
|
4 |
+
WebP Express is an MIT-licensed open source project. It is free and always will be. And I, the developer, promise not to try to harvest it later by creating a PRO version.
|
5 |
|
6 |
+
How is it financed then? Well, it isn't exactly. However, some people choose to support the development by buying the developer a cup of coffee, and some go even further, by becoming backers. Backers are nice folks making recurring monthly donations, and by doing this, they give me an excuse to put more work into the plugin than I really should.
|
7 |
|
8 |
+
To become a backer, yourself, [go to my page at patreon.com](https://www.patreon.com/rosell)
|
9 |
|
|
|
10 |
|
11 |
+
## Backers via Patron
|
12 |
|
13 |
+
| Name | Date | Message (max 70 chars, plain text only) |
|
14 |
| --------------------- | ---------- | ----------------------------------------------------------------------- |
|
15 |
+
| Tammy Valgardson | 2018-12-27 | |
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
+
<sub>I reserve the right to disallow inappropriate messages. No Trump hooting or bashing here, please. And don't be aggressive, obscene or anything unpleasant. But I don't have to point that out, do I?</sub>
|
|
|
|
|
18 |
|
19 |
+
## Generous backers via Patron
|
20 |
|
21 |
+
Generous backers will get their names listed here, along with a message - max 100 chars, and it may contain one link (the link url does not count any chars).
|
22 |
|
23 |
+
There are no generous backers yet. [Be the first!](https://www.patreon.com/rosell)
|
|
|
|
|
|
|
|
|
24 |
|
25 |
+
<sub>
|
26 |
+
I reserve the right to disallow inappropriate messages and links. No xxx sites or anything freaky or fishy, please. You may however advertise non-freaky-or-fishy things, if you wish. Just remember the audience. No point in trying to sell shoes here</sub>
|
README.md
CHANGED
@@ -113,33 +113,69 @@ Easy enough. Browsers looks at the *content type* header rather than the URL to
|
|
113 |
I am btw considering making an option to have the plugin redirect to the webp instead of serving immediately. That would remove the apparent mismatch between file extension and content type header. However, the cost of doing that will be an extra request for each image, which means extra time and worse performance. I believe you'd be ill advised to use that option, so I guess I will not implement it. But perhaps you have good reasons to use it? If you do, please let me know!
|
114 |
|
115 |
### I am on NGINX / OpenResty
|
116 |
-
It is possible to make WebP Express work on NGINX, but it requieres manually inserting redirection rules in the NGINX configuration file (nginx.conf).
|
117 |
|
118 |
-
*Note that the rules stated here previously had a bug*: It had ” rather than ". The slightly slanted quotation mark does not work. Also, it used $request_uri, which contains the querystring, which resulted in errors when querystrings were supplied (ie ?debug)
|
119 |
-
|
120 |
-
For 0.8.0:
|
121 |
```
|
122 |
if ($http_accept ~* "webp"){
|
123 |
-
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?
|
124 |
}
|
125 |
```
|
126 |
-
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
127 |
|
128 |
-
|
|
|
129 |
```
|
130 |
if ($http_accept ~* "webp"){
|
131 |
-
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?
|
132 |
}
|
133 |
```
|
|
|
134 |
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
135 |
|
136 |
The `wp-content` argument must point to the wp-content folder (relative to document root). In most installations, it is 'wp-content'.
|
137 |
|
|
|
|
|
138 |
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
|
139 |
|
140 |
### I am on a WAMP stack
|
141 |
It has been reported that WebP Express *almost* works on WAMP stack (Windows, Apache, MySQL, PHP). I'd love to debug this, but do not own a Windows server or access to one... Can you help?
|
142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
### Why do I not see the option to set WebP quality to auto?
|
144 |
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick extension* (PECL >= 2.2.2) or enable exec() calls and install either *Imagick* or *Gmagick*.
|
145 |
|
@@ -152,6 +188,128 @@ Chances are that the default setting of your CDN is not to forward any headers t
|
|
152 |
|
153 |
The plugin takes care of setting the "Vary" HTTP header to "Accept" when routing WebP images. When the CDN sees this, it knows that the response varies, depending on the "Accept" header. The CDN is thus instructed not to cache the response on URL only, but also on the "Accept" header. This means that it will store an image for every accept header it meets. Luckily, there are (not that many variants for images)[https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values#Values_for_an_image], so it is not an issue.
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
### Does it work with lazy loaded images?
|
156 |
No plugins/frameworks has yet been discovered, which does not work with *WebP Express*.
|
157 |
|
@@ -164,7 +322,7 @@ The following lazy load plugins/frameworks has been tested and works with *WebP
|
|
164 |
### When is feature X coming? / Roadmap
|
165 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
166 |
|
167 |
-
Here are my
|
168 |
|
169 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
170 |
|
@@ -180,4 +338,4 @@ For more info, see the closed issues on the 0.9.0 milestone on the github reposi
|
|
180 |
Bread on the table don't come for free, even though this plugin does, and always will. I enjoy developing this, and supporting you guys, but I kind of need the bread too. Please make it possible for me to continue putting effort into this plugin:
|
181 |
|
182 |
- [Buy me a Coffee](https://ko-fi.com/rosell)
|
183 |
-
- [Become a backer
|
113 |
I am btw considering making an option to have the plugin redirect to the webp instead of serving immediately. That would remove the apparent mismatch between file extension and content type header. However, the cost of doing that will be an extra request for each image, which means extra time and worse performance. I believe you'd be ill advised to use that option, so I guess I will not implement it. But perhaps you have good reasons to use it? If you do, please let me know!
|
114 |
|
115 |
### I am on NGINX / OpenResty
|
116 |
+
It is possible to make WebP Express work on NGINX, but it requieres manually inserting redirection rules in the NGINX configuration file (nginx.conf or the configuration file for the site, found in `/etc/nginx/sites-available`). On most setups the following rules should work:
|
117 |
|
|
|
|
|
|
|
118 |
```
|
119 |
if ($http_accept ~* "webp"){
|
120 |
+
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?wp-content=wp-content break;
|
121 |
}
|
122 |
```
|
|
|
123 |
|
124 |
+
If it doesn't work, try this instead:
|
125 |
+
|
126 |
```
|
127 |
if ($http_accept ~* "webp"){
|
128 |
+
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?xsource=x$request_filename&wp-content=wp-content break;
|
129 |
}
|
130 |
```
|
131 |
+
|
132 |
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
133 |
|
134 |
The `wp-content` argument must point to the wp-content folder (relative to document root). In most installations, it is 'wp-content'.
|
135 |
|
136 |
+
Note that the rules above redirects every image request to the PHP script. To get better performance, you can add a rule that redirects jpeg/png requests directly to existing webp images. There are some rules for that [here](https://www.keycdn.com/blog/convert-to-webp-the-successor-of-jpeg#rewriterules-for-nginx-nginx-conf), but they need to be modified because WebP Express stores the webp files in a different location (`wp-content/webp-express/webp-images/doc-root`).
|
137 |
+
|
138 |
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
|
139 |
|
140 |
### I am on a WAMP stack
|
141 |
It has been reported that WebP Express *almost* works on WAMP stack (Windows, Apache, MySQL, PHP). I'd love to debug this, but do not own a Windows server or access to one... Can you help?
|
142 |
|
143 |
+
### I am using Jetpack
|
144 |
+
If you install Jetpack and enable the "Speed up image load times" then Jetpack will alter the HTML such that images are pointed to their CDN.
|
145 |
+
|
146 |
+
Ie:
|
147 |
+
`<img src="https://example.com/wp-content/uploads/2018/09/architecture.jpg">`
|
148 |
+
|
149 |
+
becomes:
|
150 |
+
`<img src="https://i0.wp.com/example.com/wp-content/uploads/2018/09/architecture.jpg">`
|
151 |
+
|
152 |
+
Jetpack automatically serves webp files to browsers that supports it using same mechanism as the standard WebP Express configuration: If the "Accept" header contains "image/webp", a webp is served (keeping original file extension, but setting the "content-type" header to "image/webp"), otherwise a jpg is served.
|
153 |
+
|
154 |
+
As images are no longer pointed to your original server, the .htaccess rules created by WebP Express will not have any effect.
|
155 |
+
|
156 |
+
So if you are using Jetpack you don't really need WebP Express?
|
157 |
+
Well, there is no point in having the "Speed up image load times" enabled together with WebP Express.
|
158 |
+
|
159 |
+
But there is a case for using WebP Express rather than Jetpacks "Speed up image load times" feature:
|
160 |
+
|
161 |
+
Jetpack has the same drawback as the *Standard* WebP Express operation mode: If a user downloads the file, there will be a mismatch between the file extension and the image type (the file is ie called "logo.jpg", but it is really a webp image). I don't think that is a big issue, but for those who do, WebP Express might still be for you, even though you have Jetpack. And that is because WebP Express can be set up just to generate webp's, without doing the internal redirection to webp (will be possible from version 0.10.0). You can then for example use the [Cache Enabler](https://wordpress.org/plugins/cache-enabler/) plugin, which is able to generate and cache two versions of each page. One for browsers that accepts webp and one for those that don't. In the HTML for webp-enabled browsers, the images points directly to the webp files.
|
162 |
+
|
163 |
+
Pro Jetpack:
|
164 |
+
- It is a free CDN which serves webp out of the box.
|
165 |
+
- It optimizes jpegs and pngs as well (but note that only about 1 out of 5 users gets these, as webp is widely supported now)
|
166 |
+
|
167 |
+
Con Jetpack:
|
168 |
+
- It is a big plugin to install if you are only after the CDN
|
169 |
+
- It requires that you create an account on Wordpress.com
|
170 |
+
|
171 |
+
Pro WebP Express:
|
172 |
+
- You have control over quality and metadata
|
173 |
+
- It is a small plugin and care has been taken to add only very little overhead
|
174 |
+
- Plays well together with Cache Enabler. By not redirecting jpg to webp, there is no need to do any special configuration on the CDN and no issue with misleading file extension, if user downloads a file.
|
175 |
+
|
176 |
+
Con WebP Express:
|
177 |
+
- If you are using a CDN and you are redirecting jpg to webp, you must configure the CDN to forward the Accept header. It is not possible on all CDNs.
|
178 |
+
|
179 |
### Why do I not see the option to set WebP quality to auto?
|
180 |
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick extension* (PECL >= 2.2.2) or enable exec() calls and install either *Imagick* or *Gmagick*.
|
181 |
|
188 |
|
189 |
The plugin takes care of setting the "Vary" HTTP header to "Accept" when routing WebP images. When the CDN sees this, it knows that the response varies, depending on the "Accept" header. The CDN is thus instructed not to cache the response on URL only, but also on the "Accept" header. This means that it will store an image for every accept header it meets. Luckily, there are (not that many variants for images)[https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values#Values_for_an_image], so it is not an issue.
|
190 |
|
191 |
+
In the 0.10.0 release, you will have another (and better) option, as [described here](https://github.com/rosell-dk/webp-express/issues/133)
|
192 |
+
|
193 |
+
### I am on Cloudflare
|
194 |
+
Without configuration, Cloudflare will not maintain separate caches for jpegs and webp; all browsers will get jpeg. To make Cloudflare cache not only by URL, but also by header, you need to use the [Custom Cache Key](https://support.cloudflare.com/hc/en-us/articles/115004290387) page rule, and add *Header content* to make separate caches depending on the *Accept* request header.
|
195 |
+
|
196 |
+
However, the *Custom Cache Key* rule currently requires an *Enterprise* account. And if you already have that, you may as well go with the *Polish* feature, which starts at the “Pro” level plan. With the *Polish* feature, you will not need WebP Express.
|
197 |
+
|
198 |
+
To make *WebP Express* work on a free Cloudflare account, you have the following choices:
|
199 |
+
|
200 |
+
1. You can configure the CDN not to cache jpeg images by adding the following page rule: If rule matches: `example.com/*.jpg`, set: *Cache level* to: *Bypass*
|
201 |
+
|
202 |
+
2. You can set up another CDN (on another provider), which you just use for handling the images. You need to configure that CDN to forward the *Accept header*. You also need to install a Wordpress plugin that points images to that CDN.
|
203 |
+
|
204 |
+
3. You can switch operation mode to "Just convert" and use either *Cache Enabler* or *ShortPixel* to modify the HTML. See the following FAQ items
|
205 |
+
|
206 |
+
### WebP Express / ShortPixel setup
|
207 |
+
Here is a recipe for using WebP Express together with ShortPixel, such that WebP Express generates the webp's, and ShortPixel only is used to create `<picture>` tags, when it detects a webp image in the same folder as an original.
|
208 |
+
|
209 |
+
The reason for doing this could be:
|
210 |
+
1. You are using a CDN which cannot be configured to work with the Standard WebP Express setup.
|
211 |
+
2. You think it is problematic that when a user saves an image, it has the jpg extension, even though it is a webp image.
|
212 |
+
|
213 |
+
You need:
|
214 |
+
1 x WebP Express
|
215 |
+
1 x ShortPixel
|
216 |
+
|
217 |
+
#### 1. Setup WebP Express
|
218 |
+
If you are using a CDN which cannot be configured to work in *Standard mode*:
|
219 |
+
- Open WebP Express options
|
220 |
+
- Switch to *Just convert* mode.
|
221 |
+
- Set *File extension* to "Set to .webp"
|
222 |
+
- Make sure the *Auto convert* option is enabled
|
223 |
+
|
224 |
+
If you want to *ShortPixel* to create <picture> tags but still want the magic to work on other images (such as images are referenced from CSS or javascript):
|
225 |
+
- Open WebP Express options
|
226 |
+
- Switch to *Standard* mode.
|
227 |
+
- Set *Destination folder* to "Mingled"
|
228 |
+
- Set *File extension* to "Set to .webp"
|
229 |
+
|
230 |
+
#### 2. Setup ShortPixel
|
231 |
+
- Install [ShortPixel](https://wordpress.org/plugins/shortpixel-image-optimiser/) the usual way
|
232 |
+
- Get an API key and enter it on the options page.
|
233 |
+
- In *Advanced*, enable the following options:
|
234 |
+
- *Also create WebP versions of the images, for free.*
|
235 |
+
- *Deliver the WebP versions of the images in the front-end*
|
236 |
+
- *Altering the page code, using the <PICTURE> tag syntax*
|
237 |
+
- As there is a limit to how many images you can convert freely with *ShortPixel*, you should disable the following options (also on the *Advanced* screen):
|
238 |
+
- *Automatically optimize images added by users in front end.*
|
239 |
+
- *Automatically optimize Media Library items after they are uploaded (recommended).*
|
240 |
+
|
241 |
+
#### 3. Visit a page
|
242 |
+
As there are presumably no webps generated yet, ShortPixel will not generate `<picture>` tags on the first visit. However, the images that are referenced causes the WebP Express *Auto convert* feature to kick in and generate webp images for each image on that page.
|
243 |
+
|
244 |
+
#### 4. Visit the page again
|
245 |
+
As *WebP Express* have generated webps in the same folder as the originals, *ShortPixel* detects these, and you should see `<picture>` tags which references the webp's.
|
246 |
+
|
247 |
+
#### ShortPixel or Cache Enabler ?
|
248 |
+
Cache Enabler has the advantage over ShortPixel that the HTML structure remains the same. With ShortPixel, image tags are wrapped in a `<picture>` tag structure, and by doing that, there is a risk of breaking styles.
|
249 |
+
|
250 |
+
Further, Cache Enabler *caches* the HTML. This is good for performance. However, this also locks you to using that plugin for caching. With ShortPixel, you can keep using your favourite caching plugin.
|
251 |
+
|
252 |
+
Cache Enabler will not work if you are caching HTML on a CDN, because the HTML varies depending on the *Accept* header and it doesn't signal this with a Vary:Accept header. You could however add that manually. ShortPixel does not have that issue, as the HTML is the same for all.
|
253 |
+
|
254 |
+
### WebP Express / Cache Enabler setup
|
255 |
+
The WebP Express / Cache Enabler setup is quite potent and very CDN-friendly. Cache Enabler is used for generating and caching two versions of the HTML (one for webp-enabled browsers and one for webp-disabled browsers)
|
256 |
+
|
257 |
+
The reason for doing this could be:
|
258 |
+
1. You are using a CDN which cannot be configured to work with the Standard WebP Express setup.
|
259 |
+
2. You think it is problematic that when a user saves an image, it has the jpg extension, even though it is a webp image.
|
260 |
+
|
261 |
+
You need:
|
262 |
+
1 x WebP Express
|
263 |
+
1 x Cache Enabler
|
264 |
+
|
265 |
+
#### 1. Setup WebP Express
|
266 |
+
If you are using a CDN which cannot be configured to work in *Standard mode*:
|
267 |
+
- Open WebP Express options
|
268 |
+
- Switch to *Just convert* mode.
|
269 |
+
- Set *File extension* to "Set to .webp"
|
270 |
+
- Make sure the *Auto convert* option is enabled
|
271 |
+
|
272 |
+
If you want to *Cache Enabler* to create <picture> tags but still want the magic to work on other images (such as images are referenced from CSS or javascript):
|
273 |
+
- Open WebP Express options
|
274 |
+
- Switch to *Standard* mode.
|
275 |
+
- Set *Destination folder* to "Mingled"
|
276 |
+
- Set *File extension* to "Set to .webp"
|
277 |
+
|
278 |
+
#### 2. Setup Cache Enabler
|
279 |
+
- Open the options
|
280 |
+
- Enable of the *Create an additional cached version for WebP image support* option
|
281 |
+
|
282 |
+
#### 3. Let rise in a warm place until doubled
|
283 |
+
*WebP Express* creates *webp* images on need basis. It needs page visits in order to do the convertions . Bulk conversion is on the roadmap, but until then, you need to visit all pages of relevance. You can either do it manually, let your visitors do it (that is: wait a bit), or, if you are on linux, you can use `wget` to grab your website:
|
284 |
+
|
285 |
+
```
|
286 |
+
wget -e robots=off -r -np -w 2 http://www.example.com
|
287 |
+
```
|
288 |
+
|
289 |
+
**flags:**
|
290 |
+
`-e robots=off` makes wget ignore rules in robots.txt
|
291 |
+
`-np` (no-parent) makes wget stay within the boundaries (doesn't go into parent folders)
|
292 |
+
`w 2` Waits two seconds between each request, in order not to stress the server
|
293 |
+
|
294 |
+
#### 4. Clear the Cache Enabler cache.
|
295 |
+
Click the "Clear Cache" button in the top right corner in order to clear the Cache Enabler cache.
|
296 |
+
|
297 |
+
#### 5. Inspect the HTML
|
298 |
+
When visiting a page with images on, different HTML will be served to browsers, depending on whether they support webp or not.
|
299 |
+
|
300 |
+
In a webp-enabled browser, the HTML may look like this: `<img src="image.webp">`, while in a non-webp enabled browser, it looks like this: `<img src="image.jpg">`
|
301 |
+
|
302 |
+
|
303 |
+
#### 6. Optionally add Cache Enabler rewrite rules in your .htaccess
|
304 |
+
*Cache Enabler* provides some rewrite rules that redirects to the cached file directly in the `.htaccess`, bypassing PHP entirely. Their plugin doesn't do that for you, so you will have to do it manually in order to get the best performance. The rules are in the "Advanced configuration" section on [this page](https://www.keycdn.com/support/wordpress-cache-enabler-plugin).
|
305 |
+
|
306 |
+
#### ShortPixel or Cache Enabler ?
|
307 |
+
Cache Enabler has the advantage over ShortPixel that the HTML structure remains the same. With ShortPixel, image tags are wrapped in a `<picture>` tag structure, and by doing that, there is a risk of breaking styles.
|
308 |
+
|
309 |
+
Further, Cache Enabler *caches* the HTML. This is good for performance. However, this also locks you to using that plugin for caching. With ShortPixel, you can keep using your favourite caching plugin.
|
310 |
+
|
311 |
+
Cache Enabler will not work if you are caching HTML on a CDN, because the HTML varies depending on the *Accept* header and it doesn't signal this with a Vary:Accept header. You could however add that manually. ShortPixel does not have that issue, as the HTML is the same for all.
|
312 |
+
|
313 |
### Does it work with lazy loaded images?
|
314 |
No plugins/frameworks has yet been discovered, which does not work with *WebP Express*.
|
315 |
|
322 |
### When is feature X coming? / Roadmap
|
323 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
324 |
|
325 |
+
Here are my current plans ahead: The 0.11 release will probably add a some diagnose tool – this should release some time spend in the forum. 0.12 could be focused on PNG. 0.13 might be displaying rules for NGINX. 0.14 might be supporting Save-Data header (send extra compressed images to clients who wants to use as little bandwidth as possible). 0.15 might be multisite support. 0.16 might be a file manager-like interface for inspecting generated webp files. 0.17 might be WAMP support. The current milestones, their subtasks and their progress can be viewed here: https://github.com/rosell-dk/webp-express/milestones
|
326 |
|
327 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
328 |
|
338 |
Bread on the table don't come for free, even though this plugin does, and always will. I enjoy developing this, and supporting you guys, but I kind of need the bread too. Please make it possible for me to continue putting effort into this plugin:
|
339 |
|
340 |
- [Buy me a Coffee](https://ko-fi.com/rosell)
|
341 |
+
- [Become a backer](https://github.com/rosell-dk/webp-express/blob/master/BACKERS.md)
|
README.txt
CHANGED
@@ -4,7 +4,7 @@ Donate link: https://ko-fi.com/rosell
|
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 5.0
|
7 |
-
Stable tag: 0.
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
@@ -124,35 +124,69 @@ Easy enough. Browsers looks at the *content type* header rather than the URL to
|
|
124 |
I am btw considering making an option to have the plugin redirect to the webp instead of serving immediately. That would remove the apparent mismatch between file extension and content type header. However, the cost of doing that will be an extra request for each image, which means extra time and worse performance. I believe you'd be ill advised to use that option, so I guess I will not implement it. But perhaps you have good reasons to use it? If you do, please let me know!
|
125 |
|
126 |
= I am on NGINX / OpenResty =
|
127 |
-
It is possible to make WebP Express work on NGINX, but it requieres manually inserting redirection rules in the NGINX configuration file (nginx.conf).
|
128 |
|
129 |
-
|
130 |
-
|
131 |
-
For 0.8.0:
|
132 |
-
`
|
133 |
if ($http_accept ~* "webp"){
|
134 |
-
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?
|
135 |
}
|
136 |
-
|
137 |
-
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
138 |
|
139 |
-
|
140 |
-
|
|
|
141 |
if ($http_accept ~* "webp"){
|
142 |
-
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?
|
143 |
}
|
144 |
-
|
145 |
-
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
146 |
|
|
|
147 |
|
148 |
The `wp-content` argument must point to the wp-content folder (relative to document root). In most installations, it is 'wp-content'.
|
149 |
|
150 |
-
|
151 |
|
|
|
152 |
|
153 |
= I am on a WAMP stack =
|
154 |
It has been reported that WebP Express *almost* works on WAMP stack. I'd love to debug this, but do not own a Windows server or access to one... Can you help?
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
= Why do I not see the option to set WebP quality to auto? =
|
157 |
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick extension* (PECL >= 2.2.2) or enable exec() calls and install either *Imagick* or *Gmagick*.
|
158 |
|
@@ -160,15 +194,159 @@ If you have the *Imagick*, the *Imagick binary* or the *Remote WebP Express* con
|
|
160 |
|
161 |
Note: If you experience that the general auto option doesn't show, even though the above-mentioned requirements should be in order, check out [this support-thread](https://wordpress.org/support/topic/still-no-auto-option/).
|
162 |
|
163 |
-
= How do I
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
|
166 |
-
|
167 |
-
|
168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
|
170 |
= Does it work with lazy loaded images? =
|
171 |
-
No plugins/frameworks has yet been discovered, which does not work with *WebP Express
|
172 |
|
173 |
The most common way of lazy-loading is by setting a *data-src* attribute on the image and let javascript use that value for setten the *src* attribute. That method works, as the image request, seen from the server side, is indistinguishable from any other image request. It could however be that some obscure lazy load implementation would load the image with an XHR request. In that case, the *Accept* header will not contain 'image/webp', but '*/*', and a jpeg will be served, even though the browser supports webp.
|
174 |
|
@@ -176,14 +354,13 @@ The following lazy load plugins/frameworks has been tested and works with *WebP
|
|
176 |
- [BJ Lazy Load](https://da.wordpress.org/plugins/bj-lazy-load/)
|
177 |
- [Owl Carousel 2](https://owlcarousel2.github.io/OwlCarousel2/)
|
178 |
|
179 |
-
= When is feature X coming? =
|
180 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
181 |
|
182 |
-
Here are my
|
183 |
|
184 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
185 |
|
186 |
-
|
187 |
= How do I buy you a cup of coffee? =
|
188 |
Easy enough! - [Go here!](https://ko-fi.com/rosell). Or [here](https://buymeacoff.ee/rosell).
|
189 |
|
@@ -193,10 +370,21 @@ Easy enough! - [Go here!](https://ko-fi.com/rosell). Or [here](https://buymeacof
|
|
193 |
|
194 |
== Changelog ==
|
195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
= 0.9.0 =
|
197 |
-
*
|
198 |
* Optionally make .htaccess redirect directly to existing webp (improves performance)
|
199 |
-
* Optionally do not send filename from
|
200 |
* Fixed some bugs
|
201 |
|
202 |
For more info, see the closed issues on the 0.9.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.9.0
|
@@ -269,6 +457,9 @@ For older releases, check out changelog.txt
|
|
269 |
|
270 |
== Upgrade Notice ==
|
271 |
|
|
|
|
|
|
|
272 |
= 0.9.1 =
|
273 |
Fixed critical bug causing options page to go blank
|
274 |
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 5.0
|
7 |
+
Stable tag: 0.10.0
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
124 |
I am btw considering making an option to have the plugin redirect to the webp instead of serving immediately. That would remove the apparent mismatch between file extension and content type header. However, the cost of doing that will be an extra request for each image, which means extra time and worse performance. I believe you'd be ill advised to use that option, so I guess I will not implement it. But perhaps you have good reasons to use it? If you do, please let me know!
|
125 |
|
126 |
= I am on NGINX / OpenResty =
|
127 |
+
It is possible to make WebP Express work on NGINX, but it requieres manually inserting redirection rules in the NGINX configuration file (nginx.conf or the configuration file for the site, found in `/etc/nginx/sites-available`). On most setups the following rules should work:
|
128 |
|
129 |
+
```
|
|
|
|
|
|
|
130 |
if ($http_accept ~* "webp"){
|
131 |
+
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?wp-content=wp-content break;
|
132 |
}
|
133 |
+
```
|
|
|
134 |
|
135 |
+
If it doesn't work, try this instead:
|
136 |
+
|
137 |
+
```
|
138 |
if ($http_accept ~* "webp"){
|
139 |
+
rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?xsource=x$request_filename&wp-content=wp-content break;
|
140 |
}
|
141 |
+
```
|
|
|
142 |
|
143 |
+
*Beware:* If you copy the code above, you might get an html-encoded ampersand before "wp-content"
|
144 |
|
145 |
The `wp-content` argument must point to the wp-content folder (relative to document root). In most installations, it is 'wp-content'.
|
146 |
|
147 |
+
Note that the rules above redirects every image request to the PHP script. To get better performance, you can add a rule that redirects jpeg/png requests directly to existing webp images. There are some rules for that [here](https://www.keycdn.com/blog/convert-to-webp-the-successor-of-jpeg#rewriterules-for-nginx-nginx-conf), but they need to be modified because WebP Express stores the webp files in a different location (`wp-content/webp-express/webp-images/doc-root`).
|
148 |
|
149 |
+
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
|
150 |
|
151 |
= I am on a WAMP stack =
|
152 |
It has been reported that WebP Express *almost* works on WAMP stack. I'd love to debug this, but do not own a Windows server or access to one... Can you help?
|
153 |
|
154 |
+
= I am using Jetpack =
|
155 |
+
If you install Jetpack and enable the "Speed up image load times" then Jetpack will alter the HTML such that images are pointed to their CDN.
|
156 |
+
|
157 |
+
Ie:
|
158 |
+
`<img src="https://example.com/wp-content/uploads/2018/09/architecture.jpg">`
|
159 |
+
|
160 |
+
becomes:
|
161 |
+
`<img src="https://i0.wp.com/example.com/wp-content/uploads/2018/09/architecture.jpg">`
|
162 |
+
|
163 |
+
Jetpack automatically serves webp files to browsers that supports it using same mechanism as the standard WebP Express configuration: If the "Accept" header contains "image/webp", a webp is served (keeping original file extension, but setting the "content-type" header to "image/webp"), otherwise a jpg is served.
|
164 |
+
|
165 |
+
As images are no longer pointed to your original server, the .htaccess rules created by WebP Express will not have any effect.
|
166 |
+
|
167 |
+
So if you are using Jetpack you don't really need WebP Express?
|
168 |
+
Well, there is no point in having the "Speed up image load times" enabled together with WebP Express.
|
169 |
+
|
170 |
+
But there is a case for using WebP Express rather than Jetpacks "Speed up image load times" feature:
|
171 |
+
|
172 |
+
Jetpack has the same drawback as the *standard* WebP Express configuration: If a user downloads the file, there will be a mismatch between the file extension and the image type (the file is ie called "logo.jpg", but it is really a webp image). I don't think that is a big issue, but for those who do, WebP Express might still be for you, even though you have Jetpack. And that is because WebP Express can be set up just to generate webp's, without doing the internal redirection to webp (will be possible from version 0.10.0). You can then for example use the [Cache Enabler](https://wordpress.org/plugins/cache-enabler/) plugin, which is able to generate and cache two versions of each page. One for browsers that accepts webp and one for those that don't. In the HTML for webp-enabled browsers, the images points directly to the webp files.
|
173 |
+
|
174 |
+
Pro Jetpack:
|
175 |
+
- It is a free CDN which serves webp out of the box.
|
176 |
+
- It optimizes jpegs and pngs as well (but note that only about 1 out of 5 users gets these, as webp is widely supported now)
|
177 |
+
|
178 |
+
Con Jetpack:
|
179 |
+
- It is a big plugin to install if you are only after the CDN
|
180 |
+
- It requires that you create an account on Wordpress.com
|
181 |
+
|
182 |
+
Pro WebP Express:
|
183 |
+
- You have control over quality and metadata
|
184 |
+
- It is a small plugin and care has been taken to add only very little overhead
|
185 |
+
- Plays well together with Cache Enabler. By not redirecting jpg to webp, there is no need to do any special configuration on the CDN and no issue with misleading file extension, if user downloads a file.
|
186 |
+
|
187 |
+
Con WebP Express:
|
188 |
+
- If you are using a CDN and you are redirecting jpg to webp, you must configure the CDN to forward the Accept header. It is not possible on all CDNs.
|
189 |
+
|
190 |
= Why do I not see the option to set WebP quality to auto? =
|
191 |
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick extension* (PECL >= 2.2.2) or enable exec() calls and install either *Imagick* or *Gmagick*.
|
192 |
|
194 |
|
195 |
Note: If you experience that the general auto option doesn't show, even though the above-mentioned requirements should be in order, check out [this support-thread](https://wordpress.org/support/topic/still-no-auto-option/).
|
196 |
|
197 |
+
= How do I configure my CDN? (Standard mode) =
|
198 |
+
In *Standard* operation mode, the response *varies* depending on whether the browser supports webp or not (which browsers signals in the *Accept* header). Some CDN's support this out of the box, others requires some configuration and others doesn't support it at all.
|
199 |
+
|
200 |
+
For a CDN to cooperate, it needs to
|
201 |
+
1) forward the *Accept* header and
|
202 |
+
2) Honour the Vary:Accept response header.
|
203 |
+
|
204 |
+
You can also make it "work" on some CDN's by bypassing cache for images. But I rather suggest that you try out the *Just convert* mode (see next FAQ item)
|
205 |
+
|
206 |
+
*Status of some CDN's*:
|
207 |
+
|
208 |
+
- *KeyCDN*: Does not support varied responses. I have added a feature request [here](https://community.keycdn.com/t/support-vary-accept-header-for-conditional-webp/1864). You can give it a +1 if you like!
|
209 |
+
- *Cloudflare*: See the "I am on Cloudflare" item
|
210 |
+
- *Cloudfront*: Works, but needs to be configured to forward the accept header. Go to *Distribution settings*, find the *Behavior tab*, select the Behavior and click the Edit button. Choose *Whitelist* from *Forward Headers* and then add the "Accept" header to the whitelist.
|
211 |
+
|
212 |
+
I shall add more to the list. You are welcome to help out [here](https://wordpress.org/support/topic/which-cdns-works-in-standard-mode/).
|
213 |
+
|
214 |
+
= How do I configure my CDN? (Just convert mode) =
|
215 |
+
In *Just convert* mode, there is no trickery with varied responses, so no special attention is required *on the CDN*.
|
216 |
+
|
217 |
+
In *Just-convert* mode, to get things going, you must install a plugin which alters the HTML. Before continuing, read the *WebP Express / ShortPixel setup* and the *WebP Express / Cache Enabler setup* items.
|
218 |
+
|
219 |
+
If you have set up your whole site to be on CDN, things should now work.
|
220 |
+
|
221 |
+
If however you only want the static assets to be on the CDN, you need a plugin to alter the HTML for that (ie w3tc). So now we have two alterations!
|
222 |
+
|
223 |
+
But this should work, as long the alterations that creates `<picture>` tags happens *before* the alterations that points the images to the CDN.
|
224 |
+
|
225 |
+
Tip: In *ShortPixel*, you can select if HTML alterations should happen in hooks or in output buffer. Hooks are executed before they reaches the output buffer.
|
226 |
+
|
227 |
+
= I am on Cloudflare =
|
228 |
+
Without configuration, Cloudflare will not maintain separate caches for jpegs and webp; all browsers will get jpeg. To make Cloudflare cache not only by URL, but also by header, you need to use the [Custom Cache Key](https://support.cloudflare.com/hc/en-us/articles/115004290387) page rule, and add *Header content* to make separate caches depending on the *Accept* request header.
|
229 |
+
|
230 |
+
However, the *Custom Cache Key* rule currently requires an *Enterprise* account. And if you already have that, you may as well go with the *Polish* feature, which starts at the “Pro” level plan. With the *Polish* feature, you will not need WebP Express.
|
231 |
+
|
232 |
+
To make *WebP Express* work on a free Cloudflare account, you have the following choices:
|
233 |
+
|
234 |
+
1. You can configure the CDN not to cache jpeg images by adding the following page rule: If rule matches: `example.com/*.jpg`, set: *Cache level* to: *Bypass*
|
235 |
|
236 |
+
2. You can set up another CDN (on another provider), which you just use for handling the images. You need to configure that CDN to forward the *Accept header*. You also need to install a Wordpress plugin that points images to that CDN.
|
237 |
+
|
238 |
+
3. You can switch operation mode to "Just convert" and use either Cache Enabler or Shortpixel to modify the HTML. See the follwoning FAQ items
|
239 |
+
|
240 |
+
### WebP Express / ShortPixel setup
|
241 |
+
Here is a recipe for using WebP Express together with ShortPixel, such that WebP Express generates the webp's, and ShortPixel only is used to create `<picture>` tags, when it detects a webp image in the same folder as an original.
|
242 |
+
|
243 |
+
The reason for doing this could be:
|
244 |
+
1. You are using a CDN which cannot be configured to work with the Standard WebP Express setup.
|
245 |
+
2. You think it is problematic that when a user saves an image, it has the jpg extension, even though it is a webp image.
|
246 |
+
|
247 |
+
You need:
|
248 |
+
1 x WebP Express
|
249 |
+
1 x ShortPixel
|
250 |
+
|
251 |
+
*1. Setup WebP Express*
|
252 |
+
If you are using a CDN which cannot be configured to work in *Standard mode*:
|
253 |
+
- Open WebP Express options
|
254 |
+
- Switch to *Just convert* mode.
|
255 |
+
- Set *File extension* to "Set to .webp"
|
256 |
+
- Make sure the *Auto convert* option is enabled
|
257 |
+
|
258 |
+
If you want to *ShortPixel* to create <picture> tags but still want the magic to work on other images (such as images are referenced from CSS or javascript):
|
259 |
+
- Open WebP Express options
|
260 |
+
- Switch to *Standard* mode.
|
261 |
+
- Set *Destination folder* to "Mingled"
|
262 |
+
- Set *File extension* to "Set to .webp"
|
263 |
+
|
264 |
+
*2. Setup ShortPixel*
|
265 |
+
- Install [ShortPixel](https://wordpress.org/plugins/shortpixel-image-optimiser/) the usual way
|
266 |
+
- Get an API key and enter it on the options page.
|
267 |
+
- In *Advanced*, enable the following options:
|
268 |
+
- *Also create WebP versions of the images, for free.*
|
269 |
+
- *Deliver the WebP versions of the images in the front-end*
|
270 |
+
- *Altering the page code, using the <PICTURE> tag syntax*
|
271 |
+
- As there is a limit to how many images you can convert freely with *ShortPixel*, you should disable the following options (also on the *Advanced* screen):
|
272 |
+
- *Automatically optimize images added by users in front end.*
|
273 |
+
- *Automatically optimize Media Library items after they are uploaded (recommended).*
|
274 |
+
|
275 |
+
*3. Visit a page*
|
276 |
+
As there are presumably no webps generated yet, ShortPixel will not generate `<picture>` tags on the first visit. However, the images that are referenced causes the WebP Express *Auto convert* feature to kick in and generate webp images for each image on that page.
|
277 |
+
|
278 |
+
*4. Visit the page again*
|
279 |
+
As *WebP Express* have generated webps in the same folder as the originals, *ShortPixel* detects these, and you should see `<picture>` tags which references the webp's.
|
280 |
+
|
281 |
+
*ShortPixel or Cache Enabler ?*
|
282 |
+
Cache Enabler has the advantage over ShortPixel that the HTML structure remains the same. With ShortPixel, image tags are wrapped in a `<picture>` tag structure, and by doing that, there is a risk of breaking styles.
|
283 |
+
|
284 |
+
Further, Cache Enabler *caches* the HTML. This is good for performance. However, this also locks you to using that plugin for caching. With ShortPixel, you can keep using your favourite caching plugin.
|
285 |
+
|
286 |
+
Cache Enabler will not work if you are caching HTML on a CDN, because the HTML varies depending on the *Accept* header and it doesn't signal this with a Vary:Accept header. You could however add that manually. ShortPixel does not have that issue, as the HTML is the same for all.
|
287 |
+
|
288 |
+
### WebP Express / Cache Enabler setup
|
289 |
+
The WebP Express / Cache Enabler setup is quite potent and very CDN-friendly. Cache Enabler is used for generating and caching two versions of the HTML (one for webp-enabled browsers and one for webp-disabled browsers)
|
290 |
+
|
291 |
+
The reason for doing this could be:
|
292 |
+
1. You are using a CDN which cannot be configured to work with the Standard WebP Express setup.
|
293 |
+
2. You think it is problematic that when a user saves an image, it has the jpg extension, even though it is a webp image.
|
294 |
+
|
295 |
+
You need:
|
296 |
+
1 x WebP Express
|
297 |
+
1 x Cache Enabler
|
298 |
+
|
299 |
+
*1. Setup WebP Express*
|
300 |
+
If you are using a CDN which cannot be configured to work in *Standard mode*:
|
301 |
+
- Open WebP Express options
|
302 |
+
- Switch to *Just convert* mode.
|
303 |
+
- Set *File extension* to "Set to .webp"
|
304 |
+
- Make sure the *Auto convert* option is enabled
|
305 |
+
|
306 |
+
If you want to *Cache Enabler* to create <picture> tags but still want the magic to work on other images (such as images are referenced from CSS or javascript):
|
307 |
+
- Open WebP Express options
|
308 |
+
- Switch to *Standard* mode.
|
309 |
+
- Set *Destination folder* to "Mingled"
|
310 |
+
- Set *File extension* to "Set to .webp"
|
311 |
+
|
312 |
+
*2. Setup Cache Enabler*
|
313 |
+
- Open the options
|
314 |
+
- Enable of the *Create an additional cached version for WebP image support* option
|
315 |
+
|
316 |
+
|
317 |
+
*3. Let rise in a warm place until doubled*
|
318 |
+
*WebP Express* creates *webp* images on need basis. It needs page visits in order to do the convertions . Bulk conversion is on the roadmap, but until then, you need to visit all pages of relevance. You can either do it manually, let your visitors do it (that is: wait a bit), or, if you are on linux, you can use `wget` to grab your website:
|
319 |
+
|
320 |
+
```
|
321 |
+
wget -e robots=off -r -np -w 2 http://www.example.com
|
322 |
+
```
|
323 |
+
|
324 |
+
**flags:**
|
325 |
+
`-e robots=off` makes wget ignore rules in robots.txt
|
326 |
+
`-np` (no-parent) makes wget stay within the boundaries (doesn't go into parent folders)
|
327 |
+
`w 2` Waits two seconds between each request, in order not to stress the server
|
328 |
+
|
329 |
+
*4. Clear the Cache Enabler cache.*
|
330 |
+
Click the "Clear Cache" button in the top right corner in order to clear the Cache Enabler cache.
|
331 |
+
|
332 |
+
*5. Inspect the HTML*
|
333 |
+
When visiting a page with images on, different HTML will be served to browsers, depending on whether they support webp or not.
|
334 |
+
|
335 |
+
In a webp-enabled browser, the HTML may look like this: `<img src="image.webp">`, while in a non-webp enabled browser, it looks like this: `<img src="image.jpg">`
|
336 |
+
|
337 |
+
|
338 |
+
*6. Optionally add Cache Enabler rewrite rules in your .htaccess*
|
339 |
+
*Cache Enabler* provides some rewrite rules that redirects to the cached file directly in the `.htaccess`, bypassing PHP entirely. Their plugin doesn't do that for you, so you will have to do it manually in order to get the best performance. The rules are in the "Advanced configuration" section on [this page](https://www.keycdn.com/support/wordpress-cache-enabler-plugin).
|
340 |
+
|
341 |
+
*ShortPixel or Cache Enabler ?*
|
342 |
+
Cache Enabler has the advantage over ShortPixel that the HTML structure remains the same. With ShortPixel, image tags are wrapped in a `<picture>` tag structure, and by doing that, there is a risk of breaking styles.
|
343 |
+
|
344 |
+
Further, Cache Enabler *caches* the HTML. This is good for performance. However, this also locks you to using that plugin for caching. With ShortPixel, you can keep using your favourite caching plugin.
|
345 |
+
|
346 |
+
Cache Enabler will not work if you are caching HTML on a CDN, because the HTML varies depending on the *Accept* header and it doesn't signal this with a Vary:Accept header. You could however add that manually. ShortPixel does not have that issue, as the HTML is the same for all.
|
347 |
|
348 |
= Does it work with lazy loaded images? =
|
349 |
+
No plugins/frameworks has yet been discovered, which does not work with *WebP Express* in standard mode.
|
350 |
|
351 |
The most common way of lazy-loading is by setting a *data-src* attribute on the image and let javascript use that value for setten the *src* attribute. That method works, as the image request, seen from the server side, is indistinguishable from any other image request. It could however be that some obscure lazy load implementation would load the image with an XHR request. In that case, the *Accept* header will not contain 'image/webp', but '*/*', and a jpeg will be served, even though the browser supports webp.
|
352 |
|
354 |
- [BJ Lazy Load](https://da.wordpress.org/plugins/bj-lazy-load/)
|
355 |
- [Owl Carousel 2](https://owlcarousel2.github.io/OwlCarousel2/)
|
356 |
|
357 |
+
= When is feature X coming? / Roadmap =
|
358 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
359 |
|
360 |
+
Here are my current plans ahead: The 0.11 release will add ability to alter HTML (both picture tag syntax, as ShortPixel does and replace image URLs as Cache Enabler does). The 0.12 release will allow webp for all browsers! - using [this wonderful javascript library](https://webpjs.appspot.com/). The 0.13 release will probably add a some diagnose tool – this should release some time spend in the forum. 0.14 could be focused on PNG. 0.15 might be displaying rules for NGINX. 0.16 might be supporting Save-Data header (send extra compressed images to clients who wants to use as little bandwidth as possible). 0.17 might be multisite support. 0.18 might be a file manager-like interface for inspecting generated webp files. 0.19 might be WAMP support. The current milestones, their subtasks and their progress can be viewed here: https://github.com/rosell-dk/webp-express/milestones
|
361 |
|
362 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
363 |
|
|
|
364 |
= How do I buy you a cup of coffee? =
|
365 |
Easy enough! - [Go here!](https://ko-fi.com/rosell). Or [here](https://buymeacoff.ee/rosell).
|
366 |
|
370 |
|
371 |
== Changelog ==
|
372 |
|
373 |
+
= 0.10.0 =
|
374 |
+
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
|
375 |
+
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
|
376 |
+
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
|
377 |
+
|
378 |
+
For more info, see the closed issues on the 0.10.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/7?closed=1
|
379 |
+
|
380 |
+
= 0.9.1 =
|
381 |
+
*(released 28 dec 2018)*
|
382 |
+
* Fixed critical bug causing blank page on options page
|
383 |
+
|
384 |
= 0.9.0 =
|
385 |
+
*(released 27 dec 2018)*
|
386 |
* Optionally make .htaccess redirect directly to existing webp (improves performance)
|
387 |
+
* Optionally do not send filename from *.htaccess* to the PHP in Querystring, but use other means (improves security and reduces risks of problems due to firewall rules)
|
388 |
* Fixed some bugs
|
389 |
|
390 |
For more info, see the closed issues on the 0.9.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.9.0
|
457 |
|
458 |
== Upgrade Notice ==
|
459 |
|
460 |
+
= 0.10.0 =
|
461 |
+
WebP Express can now be used in conjunction with Cache Enabler and ShortPixel. Also introduced "Operation modes" in order to keep setting screens simple but still allow tweaking.
|
462 |
+
|
463 |
= 0.9.1 =
|
464 |
Fixed critical bug causing options page to go blank
|
465 |
|
changelog.txt
CHANGED
@@ -1,21 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
= 0.9.1 =
|
2 |
-
(released 28 dec 2018)
|
3 |
* Fixed critical bug causing blank page on options page
|
4 |
|
5 |
= 0.9.0 =
|
6 |
-
(released 27 dec 2018)
|
7 |
* Optionally make .htaccess redirect directly to existing webp (improves performance)
|
8 |
-
* Optionally do not send filename from
|
9 |
* Fixed some bugs
|
10 |
|
11 |
For more info, see the closed issues on the 0.9.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.9.0
|
12 |
|
13 |
= 0.8.1 =
|
14 |
-
*
|
15 |
* Fixed javascript bug
|
16 |
|
17 |
= 0.8.0 =
|
18 |
-
*
|
19 |
* New conversion method, which calls imagick binary directly. This will make WebP express work out of the box on more systems
|
20 |
* Made sure not to trigger LFI warning i Wordfence (to activate, click the force .htaccess button)
|
21 |
* Imagick can now be configured to set quality to auto on systems where the auto option isn't generally available
|
1 |
+
= 0.10.0 =
|
2 |
+
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
|
3 |
+
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
|
4 |
+
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
|
5 |
+
|
6 |
+
For more info, see the closed issues on the 0.10.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/7?closed=1
|
7 |
+
|
8 |
= 0.9.1 =
|
9 |
+
*(released 28 dec 2018)*
|
10 |
* Fixed critical bug causing blank page on options page
|
11 |
|
12 |
= 0.9.0 =
|
13 |
+
*(released 27 dec 2018)*
|
14 |
* Optionally make .htaccess redirect directly to existing webp (improves performance)
|
15 |
+
* Optionally do not send filename from *.htaccess* to the PHP in Querystring, but use other means (improves security and reduces risks of problems due to firewall rules)
|
16 |
* Fixed some bugs
|
17 |
|
18 |
For more info, see the closed issues on the 0.9.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.9.0
|
19 |
|
20 |
= 0.8.1 =
|
21 |
+
*(released 11 dec 2018)*
|
22 |
* Fixed javascript bug
|
23 |
|
24 |
= 0.8.0 =
|
25 |
+
*(released 11 dec 2018)*
|
26 |
* New conversion method, which calls imagick binary directly. This will make WebP express work out of the box on more systems
|
27 |
* Made sure not to trigger LFI warning i Wordfence (to activate, click the force .htaccess button)
|
28 |
* Imagick can now be configured to set quality to auto on systems where the auto option isn't generally available
|
lib/admin.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
use \WebPExpress\State;
|
3 |
|
4 |
// When an update requires a migration, the number should be increased
|
5 |
-
define('WEBPEXPRESS_MIGRATION_VERSION', '
|
6 |
|
7 |
if (WEBPEXPRESS_MIGRATION_VERSION != get_option('webp-express-migration-version', 0)) {
|
8 |
// run migration logic
|
2 |
use \WebPExpress\State;
|
3 |
|
4 |
// When an update requires a migration, the number should be increased
|
5 |
+
define('WEBPEXPRESS_MIGRATION_VERSION', '4');
|
6 |
|
7 |
if (WEBPEXPRESS_MIGRATION_VERSION != get_option('webp-express-migration-version', 0)) {
|
8 |
// run migration logic
|
lib/classes/CacheMover.php
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
include_once "FileHelper.php";
|
6 |
+
use \WebPExpress\FileHelper;
|
7 |
+
|
8 |
+
include_once "Paths.php";
|
9 |
+
use \WebPExpress\Paths;
|
10 |
+
|
11 |
+
|
12 |
+
class CacheMover
|
13 |
+
{
|
14 |
+
|
15 |
+
public static function getUploadFolder($destinationFolder)
|
16 |
+
{
|
17 |
+
switch ($destinationFolder) {
|
18 |
+
case 'mingled':
|
19 |
+
return Paths::getUploadDirAbs();
|
20 |
+
case 'separate':
|
21 |
+
return Paths::getCacheDirAbs() . '/doc-root/' . Paths::getUploadDirRel();
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Move cache because of change in options.
|
27 |
+
* Only move the upload folder
|
28 |
+
* Only move those that has an original
|
29 |
+
* Only move those that can be moved.
|
30 |
+
* @return [$numFilesMoved, $numFilesFailedMoving]
|
31 |
+
*/
|
32 |
+
public static function move($newConfig, $oldConfig)
|
33 |
+
{
|
34 |
+
$fromDir = self::getUploadFolder($oldConfig['destination-folder']);
|
35 |
+
$fromExt = $oldConfig['destination-extension'];
|
36 |
+
|
37 |
+
$toDir = self::getUploadFolder($newConfig['destination-folder']);
|
38 |
+
$toExt = $newConfig['destination-extension'];
|
39 |
+
|
40 |
+
$srcDir = self::getUploadFolder('mingled');
|
41 |
+
|
42 |
+
// for testing!
|
43 |
+
/*
|
44 |
+
$fromDir = self::getUploadFolder('mingled'); // separate | mingled
|
45 |
+
$toDir = self::getUploadFolder('mingled');
|
46 |
+
$fromExt = 'set'; // set | append
|
47 |
+
$toExt = 'append';
|
48 |
+
|
49 |
+
echo '<pre>';
|
50 |
+
echo 'from: ' . $fromDir . '<br>';
|
51 |
+
echo 'to: ' . $toDir . '<br>';
|
52 |
+
echo 'ext:' . $fromExt . ' => ' . $toExt . '<br>';
|
53 |
+
echo '</pre>';*/
|
54 |
+
|
55 |
+
return self::moveRecursively($fromDir, $toDir, $srcDir, $fromExt, $toExt);
|
56 |
+
//self::moveRecursively($toDir, $fromDir, $srcDir, $fromExt, $toExt);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @return [$numFilesMoved, $numFilesFailedMoving]
|
61 |
+
*/
|
62 |
+
public static function moveRecursively($fromDir, $toDir, $srcDir, $fromExt, $toExt)
|
63 |
+
{
|
64 |
+
if (!@is_dir($fromDir)) {
|
65 |
+
return [0, 0];
|
66 |
+
}
|
67 |
+
if (!@file_exists($toDir)) {
|
68 |
+
if (!@mkdir($toDir)) {
|
69 |
+
return [0, 0];
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
$numFilesMoved = 0;
|
74 |
+
$numFilesFailedMoving = 0;
|
75 |
+
|
76 |
+
//$filenames = @scandir($fromDir);
|
77 |
+
$fileIterator = new \FilesystemIterator($fromDir);
|
78 |
+
|
79 |
+
//foreach ($filenames as $filename) {
|
80 |
+
while ($fileIterator->valid()) {
|
81 |
+
$filename = $fileIterator->getFilename();
|
82 |
+
|
83 |
+
if (($filename != ".") && ($filename != "..")) {
|
84 |
+
//$filePerm = FileHelper::filePermWithFallback($filePerm, 0777);
|
85 |
+
|
86 |
+
if (@is_dir($fromDir . "/" . $filename)) {
|
87 |
+
list($r1, $r2) = self::moveRecursively($fromDir . "/" . $filename, $toDir . "/" . $filename, $srcDir . "/" . $filename, $fromExt, $toExt, 0);
|
88 |
+
$numFilesMoved += $r1;
|
89 |
+
$numFilesFailedMoving += $r2;
|
90 |
+
|
91 |
+
// Remove dir, if its empty. But do not remove dirs in srcDir
|
92 |
+
if ($fromDir != $srcDir) {
|
93 |
+
$fileIterator2 = new \FilesystemIterator($fromDir . "/" . $filename);
|
94 |
+
$dirEmpty = !$fileIterator2->valid();
|
95 |
+
if ($dirEmpty) {
|
96 |
+
@rmdir($fromDir . "/" . $filename);
|
97 |
+
}
|
98 |
+
}
|
99 |
+
} else {
|
100 |
+
// its a file.
|
101 |
+
// check if its a webp
|
102 |
+
if (strpos($filename, '.webp', strlen($filename) - 5) !== false) {
|
103 |
+
|
104 |
+
$filenameWithoutWebp = substr($filename, 0, strlen($filename) - 5);
|
105 |
+
$srcFilePathWithoutWebp = $srcDir . "/" . $filenameWithoutWebp;
|
106 |
+
|
107 |
+
// check if a corresponding source file exists
|
108 |
+
$newFilename = null;
|
109 |
+
if (($fromExt == 'append') && (@file_exists($srcFilePathWithoutWebp))) {
|
110 |
+
if ($toExt == 'append') {
|
111 |
+
$newFilename = $filename;
|
112 |
+
} else {
|
113 |
+
// remove ".jpg" part of filename (or ".png")
|
114 |
+
$newFilename = preg_replace("/\.(jpe?g|png)\.webp$/", '.webp', $filename);
|
115 |
+
}
|
116 |
+
} elseif ($fromExt == 'set') {
|
117 |
+
if ($toExt == 'set') {
|
118 |
+
if (
|
119 |
+
@file_exists($srcFilePathWithoutWebp . ".jpg") ||
|
120 |
+
@file_exists($srcFilePathWithoutWebp . ".jpeg") ||
|
121 |
+
@file_exists($srcFilePathWithoutWebp . ".png")
|
122 |
+
) {
|
123 |
+
$newFilename = $filename;
|
124 |
+
}
|
125 |
+
} else {
|
126 |
+
// append
|
127 |
+
if (@file_exists($srcFilePathWithoutWebp . ".jpg")) {
|
128 |
+
$newFilename = $filenameWithoutWebp . ".jpg.webp";
|
129 |
+
} elseif (@file_exists($srcFilePathWithoutWebp . ".jpeg")) {
|
130 |
+
$newFilename = $filenameWithoutWebp . ".jpeg.webp";
|
131 |
+
} elseif (@file_exists($srcFilePathWithoutWebp . ".png")) {
|
132 |
+
$newFilename = $filenameWithoutWebp . ".png.webp";
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
+
|
137 |
+
if ($newFilename !== null) {
|
138 |
+
//echo 'moving to: ' . $toDir . '/' .$newFilename . "<br>";
|
139 |
+
if (@rename($fromDir . "/" . $filename, $toDir . "/" . $newFilename)) {
|
140 |
+
$numFilesMoved++;
|
141 |
+
} else {
|
142 |
+
$numFilesFailedMoving++;
|
143 |
+
}
|
144 |
+
}
|
145 |
+
}
|
146 |
+
}
|
147 |
+
}
|
148 |
+
$fileIterator->next();
|
149 |
+
}
|
150 |
+
return [$numFilesMoved, $numFilesFailedMoving];
|
151 |
+
}
|
152 |
+
|
153 |
+
}
|
lib/classes/Config.php
CHANGED
@@ -58,34 +58,44 @@ class Config
|
|
58 |
return self::loadJSONOptions(Paths::getConfigFileName());
|
59 |
}
|
60 |
|
61 |
-
public static $
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
}
|
67 |
-
// Test converters
|
68 |
-
$testResult = TestRun::getConverterStatus();
|
69 |
-
$workingConverters = [];
|
70 |
-
if ($testResult) {
|
71 |
-
$workingConverters = $testResult['workingConverters'];
|
72 |
-
//print_r($testResult);
|
73 |
}
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
'
|
78 |
-
|
79 |
-
|
80 |
-
'
|
81 |
-
'forward-query-string' => true,
|
82 |
'image-types' => 1,
|
83 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
'max-quality' => 80,
|
85 |
'quality-specific' => 70,
|
86 |
'metadata' => 'none',
|
87 |
-
'
|
88 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
'web-service' => [
|
90 |
'enabled' => false,
|
91 |
'whitelist' => [
|
@@ -101,20 +111,74 @@ class Config
|
|
101 |
|
102 |
]
|
103 |
];
|
|
|
104 |
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
-
$config
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
}
|
112 |
-
//$config = [];
|
113 |
|
114 |
-
|
115 |
-
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
}
|
|
|
|
|
|
|
118 |
if (!isset($config['web-service'])) {
|
119 |
$config['web-service'] = [];
|
120 |
}
|
@@ -122,25 +186,30 @@ class Config
|
|
122 |
$config['web-service']['whitelist'] = [];
|
123 |
}
|
124 |
|
125 |
-
|
126 |
-
|
127 |
-
unset($whitelistEntry['api-key']);
|
128 |
}
|
129 |
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
unset($converter['options']['api-key']);
|
138 |
-
}
|
139 |
-
}
|
140 |
-
}
|
141 |
|
142 |
-
if (count($config['converters']) == 0) {
|
143 |
// This is first time visit!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
if (count($workingConverters) == 0) {
|
146 |
// No converters are working
|
@@ -172,15 +241,45 @@ class Config
|
|
172 |
}
|
173 |
$config['converters'] = array_merge($resultPart1, $resultPart2);
|
174 |
}
|
|
|
175 |
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
|
185 |
// Set "working" and "error" properties
|
186 |
if ($testResult) {
|
@@ -189,7 +288,12 @@ class Config
|
|
189 |
$hasError = isset($testResult['errors'][$converterId]);
|
190 |
$working = !$hasError;
|
191 |
|
|
|
|
|
|
|
192 |
if (isset($converter['working']) && ($converter['working'] != $working)) {
|
|
|
|
|
193 |
if ($working) {
|
194 |
Messenger::printMessage(
|
195 |
'info',
|
@@ -202,6 +306,7 @@ class Config
|
|
202 |
);
|
203 |
}
|
204 |
}
|
|
|
205 |
$converter['working'] = $working;
|
206 |
if ($hasError) {
|
207 |
$error = $testResult['errors'][$converterId];
|
@@ -260,6 +365,30 @@ class Config
|
|
260 |
return false;
|
261 |
}
|
262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
public static function generateWodOptionsFromConfigObj($config)
|
264 |
{
|
265 |
$options = $config;
|
@@ -291,23 +420,7 @@ class Config
|
|
291 |
}
|
292 |
|
293 |
if (isset($options['cache-control'])) {
|
294 |
-
$
|
295 |
-
$cacheControlOptions = [
|
296 |
-
'no-header' => '',
|
297 |
-
'one-second' => 'public, max-age=1',
|
298 |
-
'one-minute' => 'public, max-age=60',
|
299 |
-
'one-hour' => 'public, max-age=3600',
|
300 |
-
'one-day' => 'public, max-age=86400',
|
301 |
-
'one-week' => 'public, max-age=604800',
|
302 |
-
'one-month' => 'public, max-age=2592000',
|
303 |
-
'one-year' => 'public, max-age=31536000',
|
304 |
-
];
|
305 |
-
|
306 |
-
if (isset($cacheControlOptions[$cacheControl])) {
|
307 |
-
$options['cache-control-header'] = $cacheControlOptions[$cacheControl];
|
308 |
-
} else {
|
309 |
-
$options['cache-control-header'] = $options['cache-control-custom'];
|
310 |
-
}
|
311 |
}
|
312 |
|
313 |
$auto = (isset($options['quality-auto']) && $options['quality-auto']);
|
@@ -324,6 +437,10 @@ class Config
|
|
324 |
unset($options['image-types']);
|
325 |
unset($options['cache-control']);
|
326 |
unset($options['cache-control-custom']);
|
|
|
|
|
|
|
|
|
327 |
//unset($options['forward-query-string']); // It is used in webp-on-demand.php, so do not unset!
|
328 |
unset($options['do-not-pass-source-in-query-string']);
|
329 |
unset($options['redirect-to-existing-in-htaccess']);
|
58 |
return self::loadJSONOptions(Paths::getConfigFileName());
|
59 |
}
|
60 |
|
61 |
+
public static function getDefaultConfig($skipQualityAuto = false) {
|
62 |
+
if ($skipQualityAuto) {
|
63 |
+
$qualityAuto = null;
|
64 |
+
} else {
|
65 |
+
$qualityAuto = TestRun::isLocalQualityDetectionWorking();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
}
|
67 |
|
68 |
+
return [
|
69 |
+
|
70 |
+
'operation-mode' => 'standard',
|
71 |
+
|
72 |
+
// redirection rules
|
73 |
+
'enable-redirection-to-converter' => true,
|
|
|
74 |
'image-types' => 1,
|
75 |
+
'only-redirect-to-converter-on-cache-miss' => false,
|
76 |
+
'only-redirect-to-converter-for-webp-enabled-browsers' => true,
|
77 |
+
'do-not-pass-source-in-query-string' => false,
|
78 |
+
'redirect-to-existing-in-htaccess' => true,
|
79 |
+
'forward-query-string' => false,
|
80 |
+
|
81 |
+
// conversion options
|
82 |
+
'converters' => [],
|
83 |
+
'quality-auto' => $qualityAuto,
|
84 |
'max-quality' => 80,
|
85 |
'quality-specific' => 70,
|
86 |
'metadata' => 'none',
|
87 |
+
'destination-folder' => 'separate',
|
88 |
+
'destination-extension' => 'append',
|
89 |
+
|
90 |
+
// serve options
|
91 |
+
'cache-control' => 'no-header', /* can be "no-header", "set" or "custom" */
|
92 |
+
'cache-control-custom' => 'public, max-age:86400, stale-while-revalidate=604800, stale-if-error=604800',
|
93 |
+
'cache-control-max-age' => 'one-week',
|
94 |
+
'cache-control-public' => false,
|
95 |
+
'fail' => 'original',
|
96 |
+
'success-response' => 'converted',
|
97 |
+
|
98 |
+
// web service
|
99 |
'web-service' => [
|
100 |
'enabled' => false,
|
101 |
'whitelist' => [
|
111 |
|
112 |
]
|
113 |
];
|
114 |
+
}
|
115 |
|
116 |
+
/**
|
117 |
+
* Apply operation mode (set the hidden defaults that comes along with the mode)
|
118 |
+
* @return An altered configuration array
|
119 |
+
*/
|
120 |
+
public static function applyOperationMode($config)
|
121 |
+
{
|
122 |
+
if (!isset($config['operation-mode'])) {
|
123 |
+
$config['operation-mode'] = 'standard';
|
124 |
+
}
|
125 |
|
126 |
+
if ($config['operation-mode'] == 'standard') {
|
127 |
+
$config = array_merge($config, [
|
128 |
+
'enable-redirection-to-converter' => true,
|
129 |
+
'only-redirect-to-converter-for-webp-enabled-browsers' => true,
|
130 |
+
'only-redirect-to-converter-on-cache-miss' => false,
|
131 |
+
'do-not-pass-source-in-query-string' => true,
|
132 |
+
//'redirect-to-existing-in-htaccess' => true,
|
133 |
+
'fail' => 'original',
|
134 |
+
'success-response' => 'converted',
|
135 |
+
]);
|
136 |
+
} elseif ($config['operation-mode'] == 'just-convert') {
|
137 |
+
$config = array_merge($config, [
|
138 |
+
'only-redirect-to-converter-for-webp-enabled-browsers' => false,
|
139 |
+
'only-redirect-to-converter-on-cache-miss' => true,
|
140 |
+
'do-not-pass-source-in-query-string' => true,
|
141 |
+
'redirect-to-existing-in-htaccess' => false,
|
142 |
+
'destination-folder' => 'mingled',
|
143 |
+
'fail' => 'original',
|
144 |
+
'success-response' => 'original',
|
145 |
+
]);
|
146 |
+
} elseif ($config['operation-mode'] == 'just-redirect') {
|
147 |
+
|
148 |
+
// TODO: Go through these...
|
149 |
+
|
150 |
+
$config = array_merge($config, [
|
151 |
+
'enable-redirection-to-converter' => false,
|
152 |
+
'destination-folder' => 'mingled',
|
153 |
+
]);
|
154 |
}
|
|
|
155 |
|
156 |
+
return $config;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Loads Config (if available), fills in the rest with defaults
|
161 |
+
* also applies operation mode.
|
162 |
+
*/
|
163 |
+
public static function loadConfigAndFix($checkQualityDetection = true)
|
164 |
+
{
|
165 |
+
$config = Config::loadConfig();
|
166 |
+
if ($config === false) {
|
167 |
+
$config = self::getDefaultConfig(!$checkQualityDetection);
|
168 |
+
} else {
|
169 |
+
if ($checkQualityDetection) {
|
170 |
+
if (isset($config['quality-auto']) && ($config['quality-auto'])) {
|
171 |
+
$qualityDetectionWorking = TestRun::isLocalQualityDetectionWorking();
|
172 |
+
if (!TestRun::isLocalQualityDetectionWorking()) {
|
173 |
+
$config['quality-auto'] = false;
|
174 |
+
}
|
175 |
+
}
|
176 |
+
}
|
177 |
+
$config = array_merge(self::getDefaultConfig(true), $config);
|
178 |
}
|
179 |
+
|
180 |
+
$config = self::applyOperationMode($config);
|
181 |
+
|
182 |
if (!isset($config['web-service'])) {
|
183 |
$config['web-service'] = [];
|
184 |
}
|
186 |
$config['web-service']['whitelist'] = [];
|
187 |
}
|
188 |
|
189 |
+
if ($config['converters'] == null) {
|
190 |
+
$config['converters'] = [];
|
|
|
191 |
}
|
192 |
|
193 |
+
if (count($config['converters']) > 0) {
|
194 |
+
// merge missing converters in
|
195 |
+
$config['converters'] = ConvertersHelper::mergeConverters(
|
196 |
+
$config['converters'],
|
197 |
+
ConvertersHelper::$defaultConverters
|
198 |
+
);
|
199 |
+
} else {
|
|
|
|
|
|
|
|
|
200 |
|
|
|
201 |
// This is first time visit!
|
202 |
+
// We must add converters.
|
203 |
+
// We want to order them according to which ones that are working,
|
204 |
+
// so we run
|
205 |
+
$testResult = TestRun::getConverterStatus();
|
206 |
+
$workingConverters = [];
|
207 |
+
if ($testResult) {
|
208 |
+
$workingConverters = $testResult['workingConverters'];
|
209 |
+
//print_r($testResult);
|
210 |
+
}
|
211 |
+
|
212 |
+
$defaultConverters = ConvertersHelper::$defaultConverters;
|
213 |
|
214 |
if (count($workingConverters) == 0) {
|
215 |
// No converters are working
|
241 |
}
|
242 |
$config['converters'] = array_merge($resultPart1, $resultPart2);
|
243 |
}
|
244 |
+
}
|
245 |
|
246 |
+
return $config;
|
247 |
+
}
|
248 |
+
|
249 |
+
|
250 |
+
public static $configForOptionsPage = null; // cache the result (called twice, - also in enqueue_scripts)
|
251 |
+
public static function getConfigForOptionsPage()
|
252 |
+
{
|
253 |
+
if (isset(self::$configForOptionsPage)) {
|
254 |
+
return self::$configForOptionsPage;
|
255 |
+
}
|
256 |
+
|
257 |
+
// Test converters
|
258 |
+
$testResult = TestRun::getConverterStatus();
|
259 |
+
$workingConverters = [];
|
260 |
+
if ($testResult) {
|
261 |
+
$workingConverters = $testResult['workingConverters'];
|
262 |
+
//print_r($testResult);
|
263 |
}
|
264 |
|
265 |
+
$config = self::loadConfigAndFix();
|
266 |
+
|
267 |
+
// Remove keys in whitelist (so they cannot easily be picked up by examining the html)
|
268 |
+
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
|
269 |
+
unset($whitelistEntry['api-key']);
|
270 |
+
}
|
271 |
+
|
272 |
+
// Remove keys from WPC converters
|
273 |
+
foreach ($config['converters'] as &$converter) {
|
274 |
+
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
|
275 |
+
if (isset($converter['options']['api-key'])) {
|
276 |
+
if ($converter['options']['api-key'] != '') {
|
277 |
+
$converter['options']['_api-key-non-empty'] = true;
|
278 |
+
}
|
279 |
+
unset($converter['options']['api-key']);
|
280 |
+
}
|
281 |
+
}
|
282 |
+
}
|
283 |
|
284 |
// Set "working" and "error" properties
|
285 |
if ($testResult) {
|
288 |
$hasError = isset($testResult['errors'][$converterId]);
|
289 |
$working = !$hasError;
|
290 |
|
291 |
+
/*
|
292 |
+
Don't print this stuff here. It can end up in the head tag.
|
293 |
+
TODO: Move it somewhere
|
294 |
if (isset($converter['working']) && ($converter['working'] != $working)) {
|
295 |
+
|
296 |
+
// TODO: webpexpress_converterName($converterId)
|
297 |
if ($working) {
|
298 |
Messenger::printMessage(
|
299 |
'info',
|
306 |
);
|
307 |
}
|
308 |
}
|
309 |
+
*/
|
310 |
$converter['working'] = $working;
|
311 |
if ($hasError) {
|
312 |
$error = $testResult['errors'][$converterId];
|
365 |
return false;
|
366 |
}
|
367 |
|
368 |
+
public static function getCacheControlHeader($config) {
|
369 |
+
$cacheControl = $config['cache-control'];
|
370 |
+
switch ($cacheControl) {
|
371 |
+
case 'custom':
|
372 |
+
return $config['cache-control-custom'];
|
373 |
+
case 'no-header':
|
374 |
+
return '';
|
375 |
+
default:
|
376 |
+
$public = (isset($config['cache-control-public']) ? $config['cache-control-public'] : true);
|
377 |
+
$maxAge = (isset($config['cache-control-max-age']) ? $config['cache-control-max-age'] : $cacheControl);
|
378 |
+
$maxAgeOptions = [
|
379 |
+
'one-second' => 'max-age=1',
|
380 |
+
'one-minute' => 'max-age=60',
|
381 |
+
'one-hour' => 'max-age=3600',
|
382 |
+
'one-day' => 'max-age=86400',
|
383 |
+
'one-week' => 'max-age=604800',
|
384 |
+
'one-month' => 'max-age=2592000',
|
385 |
+
'one-year' => 'max-age=31536000',
|
386 |
+
];
|
387 |
+
return ($public ? 'public, ' : 'private, ') . $maxAgeOptions[$maxAge];
|
388 |
+
}
|
389 |
+
|
390 |
+
}
|
391 |
+
|
392 |
public static function generateWodOptionsFromConfigObj($config)
|
393 |
{
|
394 |
$options = $config;
|
420 |
}
|
421 |
|
422 |
if (isset($options['cache-control'])) {
|
423 |
+
$options['cache-control-header'] = self::getCacheControlHeader($config);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
424 |
}
|
425 |
|
426 |
$auto = (isset($options['quality-auto']) && $options['quality-auto']);
|
437 |
unset($options['image-types']);
|
438 |
unset($options['cache-control']);
|
439 |
unset($options['cache-control-custom']);
|
440 |
+
unset($options['cache-control-public']);
|
441 |
+
unset($options['cache-control-max-age']);
|
442 |
+
|
443 |
+
|
444 |
//unset($options['forward-query-string']); // It is used in webp-on-demand.php, so do not unset!
|
445 |
unset($options['do-not-pass-source-in-query-string']);
|
446 |
unset($options['redirect-to-existing-in-htaccess']);
|
lib/classes/FileHelper.php
CHANGED
@@ -27,6 +27,19 @@ class FileHelper
|
|
27 |
return octdec(substr(decoct($perm), -4));
|
28 |
}
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
public static function humanReadableFilePerm($mode) {
|
31 |
return substr(decoct($mode), -4);
|
32 |
}
|
@@ -59,6 +72,15 @@ class FileHelper
|
|
59 |
return false;
|
60 |
}
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
/**
|
63 |
* Get directory part of filename.
|
64 |
* Ie '/var/www/.htaccess' => '/var/www'
|
27 |
return octdec(substr(decoct($perm), -4));
|
28 |
}
|
29 |
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Get file permission of a file (integer). Only get the last part, ie 0644
|
33 |
+
* If failure, it returns $fallback
|
34 |
+
*/
|
35 |
+
public static function filePermWithFallback($filename, $fallback) {
|
36 |
+
$perm = self::filePerm();
|
37 |
+
if ($perm === false) {
|
38 |
+
return $fallback;
|
39 |
+
}
|
40 |
+
return $perm;
|
41 |
+
}
|
42 |
+
|
43 |
public static function humanReadableFilePerm($mode) {
|
44 |
return substr(decoct($mode), -4);
|
45 |
}
|
72 |
return false;
|
73 |
}
|
74 |
|
75 |
+
/**
|
76 |
+
* Create a dir using same permissions as parent.
|
77 |
+
* If
|
78 |
+
*/
|
79 |
+
/*
|
80 |
+
public static function mkdirSamePermissionsAsParent($pathname) {
|
81 |
+
|
82 |
+
}*/
|
83 |
+
|
84 |
/**
|
85 |
* Get directory part of filename.
|
86 |
* Ie '/var/www/.htaccess' => '/var/www'
|
lib/classes/HTAccess.php
CHANGED
@@ -16,9 +16,30 @@ use \WebPExpress\State;
|
|
16 |
|
17 |
class HTAccess
|
18 |
{
|
19 |
-
// (called from this file only)
|
20 |
public static function generateHTAccessRulesFromConfigObj($config, $htaccessDir = 'index')
|
21 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
/* Calculate $fileExt */
|
23 |
$imageTypes = $config['image-types'];
|
24 |
$fileExtensions = [];
|
@@ -31,47 +52,44 @@ class HTAccess
|
|
31 |
$fileExt = implode('|', $fileExtensions);
|
32 |
|
33 |
if ($imageTypes == 0) {
|
34 |
-
return '# WebP Express disabled (no image types have been choosen to be converted)';
|
35 |
}
|
36 |
|
37 |
/* Build rules */
|
38 |
$rules = '';
|
39 |
|
|
|
40 |
// The next line sets an environment variable.
|
41 |
// On the options page, we verify if this is set to diagnose if "AllowOverride None" is presented in 'httpd.conf'
|
42 |
//$rules .= "# The following SetEnv allows to diagnose if .htaccess files are turned off\n";
|
43 |
//$rules .= "SetEnv HTACCESS on\n\n";
|
|
|
44 |
|
45 |
$rules .= "<IfModule mod_rewrite.c>\n" .
|
46 |
" RewriteEngine On\n\n";
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
//$pathToExisting = Paths::getCacheDirRel() . '/doc-root/' . Paths::getPluginDirRel();
|
52 |
-
$pathToExisting = Paths::getCacheDirRel() . '/doc-root/';
|
53 |
switch ($htaccessDir) {
|
54 |
case 'index':
|
55 |
-
$
|
56 |
break;
|
57 |
case 'home':
|
58 |
-
$
|
59 |
break;
|
60 |
case 'plugin':
|
61 |
-
$
|
62 |
break;
|
63 |
case 'uploads':
|
64 |
-
$
|
65 |
break;
|
66 |
case 'wp-content':
|
67 |
-
$
|
68 |
break;
|
69 |
}
|
70 |
|
71 |
-
$
|
72 |
-
$passSourceInQS = !$doNotpassSourceInQS;
|
73 |
-
|
74 |
-
$redirectToExisting = (isset($config['redirect-to-existing-in-htaccess']) && ($config['redirect-to-existing-in-htaccess']));
|
75 |
|
76 |
// TODO: Is it possible to handle when wp-content is outside document root?
|
77 |
|
@@ -81,65 +99,171 @@ class HTAccess
|
|
81 |
// to get: RewriteRule ^\/?(.*)\.(jpe?g)$ /wp-content-moved/webp-express/webp-images/doc-root/plugins-moved/$1.$2.webp [NC,T=image/webp,QSD,E=WEBPACCEPT:1,E=EXISTING:1,L]
|
82 |
|
83 |
// https://stackoverflow.com/questions/34124819/mod-rewrite-set-custom-header-through-htaccess
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
$rules .= " # Redirect to existing converted image in cache-dir (if browser supports webp)\n";
|
86 |
$rules .= " RewriteCond %{HTTP_ACCEPT} image/webp\n";
|
87 |
$rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
|
88 |
-
$rules .= " RewriteCond %{DOCUMENT_ROOT}/" . $
|
89 |
-
$rules .= " RewriteRule ^\/?(.*)\.(" . $fileExt . ")$ /" . $
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
"
|
97 |
-
" <IfModule mod_headers.c>\n"
|
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 |
-
$rules .="</IfModule>\n";
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
|
142 |
-
/*if ($
|
143 |
$rules .=
|
144 |
"<IfModule mod_headers.c>\n" .
|
145 |
" # Append Vary Accept header, when the rules above are redirecting to existing webp\n" .
|
@@ -156,8 +280,9 @@ class HTAccess
|
|
156 |
"</IfModule>\n\n";
|
157 |
}*/
|
158 |
|
159 |
-
$rules .= "
|
160 |
-
|
|
|
161 |
return $rules;
|
162 |
}
|
163 |
|
@@ -208,40 +333,36 @@ class HTAccess
|
|
208 |
}
|
209 |
|
210 |
$propsToCompare = [
|
211 |
-
'forward-query-string',
|
212 |
-
'image-types',
|
213 |
-
'do-not-pass-source-in-query-string',
|
214 |
-
'redirect-to-existing-in-htaccess',
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
];
|
216 |
|
|
|
|
|
|
|
|
|
217 |
|
218 |
-
foreach ($propsToCompare as $prop) {
|
219 |
if (!isset($newConfig[$prop])) {
|
220 |
continue;
|
221 |
}
|
222 |
if (!isset($oldConfig[$prop])) {
|
223 |
-
if
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
// Otherwise DO trigger .htaccess update
|
231 |
-
return true;
|
232 |
-
}
|
233 |
-
}
|
234 |
-
if ($prop == 'redirect-to-existing-in-htaccess') {
|
235 |
-
if ($newConfig[$prop] == false) {
|
236 |
-
continue;
|
237 |
-
} else {
|
238 |
-
return true;
|
239 |
-
}
|
240 |
}
|
241 |
-
|
242 |
-
// The option was not set in the old configuration,
|
243 |
-
// - so lets say that .htaccess needs updating
|
244 |
-
return true;
|
245 |
}
|
246 |
if ($newConfig[$prop] != $oldConfig[$prop]) {
|
247 |
return true;
|
16 |
|
17 |
class HTAccess
|
18 |
{
|
19 |
+
// (called from this file only. BUT our saveRules methods calls it, and it is called from several classes)
|
20 |
public static function generateHTAccessRulesFromConfigObj($config, $htaccessDir = 'index')
|
21 |
{
|
22 |
+
// Any option that is newer than ~v.0.2 may not be set yet.
|
23 |
+
// So, in order to not have to use isset() all over the place, set to values
|
24 |
+
// that results in same behaviour as before the option was introduced.
|
25 |
+
// Beware that this may not be same as the default value in the UI (but it is generally)
|
26 |
+
$defaults = [
|
27 |
+
'enable-redirection-to-converter' => true,
|
28 |
+
'forward-query-string' => true,
|
29 |
+
'image-types' => 1,
|
30 |
+
'do-not-pass-source-in-query-string' => false,
|
31 |
+
'redirect-to-existing-in-htaccess' => false,
|
32 |
+
'only-redirect-to-converter-on-cache-miss' => false,
|
33 |
+
'destination-folder' => 'separate',
|
34 |
+
'destination-extension' => 'append',
|
35 |
+
'success-response' => 'converted',
|
36 |
+
];
|
37 |
+
$config = array_merge($defaults, $config);
|
38 |
+
|
39 |
+
if ((!$config['enable-redirection-to-converter']) && (!$config['redirect-to-existing-in-htaccess'])) {
|
40 |
+
return '# WebP Express does not need to write any rules (it has not been set up to redirect to converter, nor to existing webp)';
|
41 |
+
}
|
42 |
+
|
43 |
/* Calculate $fileExt */
|
44 |
$imageTypes = $config['image-types'];
|
45 |
$fileExtensions = [];
|
52 |
$fileExt = implode('|', $fileExtensions);
|
53 |
|
54 |
if ($imageTypes == 0) {
|
55 |
+
return '# WebP Express disabled (no image types have been choosen to be converted/redirected)';
|
56 |
}
|
57 |
|
58 |
/* Build rules */
|
59 |
$rules = '';
|
60 |
|
61 |
+
/*
|
62 |
// The next line sets an environment variable.
|
63 |
// On the options page, we verify if this is set to diagnose if "AllowOverride None" is presented in 'httpd.conf'
|
64 |
//$rules .= "# The following SetEnv allows to diagnose if .htaccess files are turned off\n";
|
65 |
//$rules .= "SetEnv HTACCESS on\n\n";
|
66 |
+
*/
|
67 |
|
68 |
$rules .= "<IfModule mod_rewrite.c>\n" .
|
69 |
" RewriteEngine On\n\n";
|
70 |
|
71 |
+
$cacheDirRel = Paths::getCacheDirRel() . '/doc-root';
|
72 |
+
|
73 |
+
$htaccessDirRel = '';
|
|
|
|
|
74 |
switch ($htaccessDir) {
|
75 |
case 'index':
|
76 |
+
$htaccessDirRel = Paths::getIndexDirRel();
|
77 |
break;
|
78 |
case 'home':
|
79 |
+
$htaccessDirRel = Paths::getHomeDirRel();
|
80 |
break;
|
81 |
case 'plugin':
|
82 |
+
$htaccessDirRel = Paths::getPluginDirRel();
|
83 |
break;
|
84 |
case 'uploads':
|
85 |
+
$htaccessDirRel = Paths::getUploadDirRel();
|
86 |
break;
|
87 |
case 'wp-content':
|
88 |
+
$htaccessDirRel = Paths::getWPContentDirRel();
|
89 |
break;
|
90 |
}
|
91 |
|
92 |
+
$passSourceInQS = !($config['do-not-pass-source-in-query-string']);
|
|
|
|
|
|
|
93 |
|
94 |
// TODO: Is it possible to handle when wp-content is outside document root?
|
95 |
|
99 |
// to get: RewriteRule ^\/?(.*)\.(jpe?g)$ /wp-content-moved/webp-express/webp-images/doc-root/plugins-moved/$1.$2.webp [NC,T=image/webp,QSD,E=WEBPACCEPT:1,E=EXISTING:1,L]
|
100 |
|
101 |
// https://stackoverflow.com/questions/34124819/mod-rewrite-set-custom-header-through-htaccess
|
102 |
+
$mingled = ($config['destination-folder'] == 'mingled');
|
103 |
+
|
104 |
+
if ($config['redirect-to-existing-in-htaccess']) {
|
105 |
+
if ($mingled) {
|
106 |
+
$rules .= " # Redirect to existing converted image in same dir (if browser supports webp)\n";
|
107 |
+
$rules .= " RewriteCond %{HTTP_ACCEPT} image/webp\n";
|
108 |
+
|
109 |
+
if ($config['destination-extension'] == 'append') {
|
110 |
+
$rules .= " RewriteCond %{DOCUMENT_ROOT}/" . $htaccessDirRel . "/$1.$2.webp -f\n";
|
111 |
+
$rules .= " RewriteRule ^(.+)\.(" . $fileExt . ")$ $1.$2.webp [T=image/webp,QSD,E=EXISTING:1,L]\n\n";
|
112 |
+
} else {
|
113 |
+
$rules .= " RewriteCond %{DOCUMENT_ROOT}/" . $htaccessDirRel . "/$1.webp -f\n";
|
114 |
+
$rules .= " RewriteRule ^(.+)\.(" . $fileExt . ")$ $1.webp [T=image/webp,QSD,E=EXISTING:1,L]\n\n";
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
$rules .= " # Redirect to existing converted image in cache-dir (if browser supports webp)\n";
|
119 |
$rules .= " RewriteCond %{HTTP_ACCEPT} image/webp\n";
|
120 |
$rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
|
121 |
+
$rules .= " RewriteCond %{DOCUMENT_ROOT}/" . $cacheDirRel . "/" . $htaccessDirRel . "/$1.$2.webp -f\n";
|
122 |
+
$rules .= " RewriteRule ^\/?(.*)\.(" . $fileExt . ")$ /" . $cacheDirRel . "/" . $htaccessDirRel . "/$1.$2.webp [NC,T=image/webp,QSD,E=EXISTING:1,L]\n\n";
|
123 |
+
|
124 |
+
$cacheControlHeader = Config::getCacheControlHeader($config);
|
125 |
+
if ($cacheControlHeader != '') {
|
126 |
+
|
127 |
+
// Add Cache-Control header for webp files (this requires mod_headers)
|
128 |
+
// $rules .= "\n";
|
129 |
+
$rules .= " # Set Cache-Control header so these direct redirections also get cached\n";
|
130 |
+
$rules .= " <IfModule mod_headers.c>\n";
|
131 |
+
$rules .= " <FilesMatch \"\.webp$\">\n";
|
132 |
+
$rules .= " Header set Cache-Control \"" . $cacheControlHeader . "\"\n";
|
133 |
+
$rules .= " </FilesMatch>\n";
|
134 |
+
$rules .= " </IfModule>\n\n";
|
135 |
+
|
136 |
+
// Fall back to mod_expires if mod_headers is unavailable
|
137 |
+
$cacheControl = $config['cache-control'];
|
138 |
+
if ($cacheControl == 'custom') {
|
139 |
+
$expires = '';
|
140 |
+
|
141 |
+
// Do not add Expire header if private is set
|
142 |
+
// - because then the user don't want caching in proxies / CDNs.
|
143 |
+
// the Expires header doesn't differentiate between private/public
|
144 |
+
if (!(preg_match('/private/', $config['cache-control-custom']))) {
|
145 |
+
if (preg_match('/max-age=(\d+)/', $config['cache-control-custom'], $matches)) {
|
146 |
+
if (isset($matches[1])) {
|
147 |
+
$expires = $matches[1] . ' seconds';
|
148 |
+
}
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
} elseif ($cacheControl == 'no-header') {
|
153 |
+
$expires = '';
|
154 |
+
} elseif ($cacheControl == 'set') {
|
155 |
+
if ($config['cache-control-public']) {
|
156 |
+
$cacheControlOptions = [
|
157 |
+
'no-header' => '',
|
158 |
+
'one-second' => '1 seconds',
|
159 |
+
'one-minute' => '1 minutes',
|
160 |
+
'one-hour' => '1 hours',
|
161 |
+
'one-day' => '1 days',
|
162 |
+
'one-week' => '1 weeks',
|
163 |
+
'one-month' => '1 months',
|
164 |
+
'one-year' => '1 years',
|
165 |
+
];
|
166 |
+
$expires = $cacheControlOptions[$config['cache-control-max-age']];
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
if ($expires != '') {
|
171 |
+
// in case mod_headers is missing, try mod_expires
|
172 |
+
$rules .= " # Fall back to mod_expires if mod_headers is unavailable\n";
|
173 |
+
$rules .= " <IfModule !mod_headers.c>\n";
|
174 |
+
$rules .= " <IfModule mod_expires.c>\n";
|
175 |
+
$rules .= " ExpiresActive On\n";
|
176 |
+
$rules .= " ExpiresByType image/webp \"access plus " . $expires . "\"\n";
|
177 |
+
$rules .= " </IfModule>\n";
|
178 |
+
$rules .= " </IfModule>\n\n";
|
179 |
+
}
|
180 |
+
}
|
181 |
+
|
182 |
+
}
|
183 |
+
|
184 |
+
if ($config['enable-redirection-to-converter']) {
|
185 |
+
$basicConditions = '';
|
186 |
+
if ($config['only-redirect-to-converter-for-webp-enabled-browsers']) {
|
187 |
+
$basicConditions = " RewriteCond %{HTTP_ACCEPT} image/webp\n";
|
188 |
+
}
|
189 |
+
$basicConditions .= " RewriteCond %{REQUEST_FILENAME} -f\n";
|
190 |
+
if ($config['only-redirect-to-converter-on-cache-miss']) {
|
191 |
+
if ($mingled) {
|
192 |
+
if ($config['destination-extension'] == 'append') {
|
193 |
+
$basicConditions .= " RewriteCond %{DOCUMENT_ROOT}/" . $htaccessDirRel . "/$1.$2.webp !-f\n";
|
194 |
+
} else {
|
195 |
+
$basicConditions .= " RewriteCond %{DOCUMENT_ROOT}/" . $htaccessDirRel . "/$1.webp !-f\n";
|
196 |
+
}
|
197 |
+
} else {
|
198 |
+
$basicConditions .= " RewriteCond %{DOCUMENT_ROOT}/" . $cacheDirRel . "/" . $htaccessDirRel . "/$1.$2.webp !-f\n";
|
199 |
+
}
|
200 |
+
}
|
201 |
|
|
|
202 |
|
203 |
+
if (!$passSourceInQS) {
|
204 |
+
$rules .= " # Pass REQUEST_FILENAME to PHP by in request header\n";
|
205 |
+
$rules .= $basicConditions;
|
206 |
+
$rules .= " RewriteRule ^(.*)\.(" . $fileExt . ")$ - [E=REQFN:%{REQUEST_FILENAME}]\n" .
|
207 |
+
" <IfModule mod_headers.c>\n" .
|
208 |
+
" RequestHeader set REQFN \"%{REQFN}e\" env=REQFN\n" .
|
209 |
+
" </IfModule>\n\n";
|
210 |
+
}
|
211 |
|
212 |
+
$rules .= " # Redirect images to webp-on-demand.php ";
|
213 |
+
if ($config['only-redirect-to-converter-for-webp-enabled-browsers']) {
|
214 |
+
$rules .= "(if browser supports webp)\n";
|
215 |
+
} else {
|
216 |
+
$rules .= "(regardless whether browser supports webp or not!)\n";
|
217 |
+
}
|
218 |
+
if ($config['only-redirect-to-converter-on-cache-miss']) {
|
219 |
+
$rules .= " # - but only, when no existing converted image is found\n";
|
220 |
+
}
|
221 |
+
$rules .= $basicConditions;
|
222 |
|
223 |
+
if ($config['forward-query-string']) {
|
224 |
+
$rules .= " RewriteCond %{QUERY_STRING} (.*)\n";
|
225 |
+
}
|
226 |
+
/*
|
227 |
+
if ($config['forward-query-string']) {
|
228 |
+
}*/
|
229 |
+
|
230 |
+
|
231 |
+
// TODO:
|
232 |
+
// Add "NE" flag?
|
233 |
+
// https://github.com/rosell-dk/webp-convert/issues/95
|
234 |
+
// (and try testing spaces in directory paths)
|
235 |
+
$rules .= " RewriteRule ^(.*)\.(" . $fileExt . ")$ " .
|
236 |
+
"/" . Paths::getWodUrlPath() .
|
237 |
+
($passSourceInQS ? "?xsource=x%{SCRIPT_FILENAME}&" : "?") .
|
238 |
+
"wp-content=" . Paths::getWPContentDirRel() .
|
239 |
+
($config['forward-query-string'] ? '&%1' : '') .
|
240 |
+
" [NC,L]\n"; // E=WOD:1
|
241 |
+
|
242 |
+
|
243 |
+
$rules .= "\n <IfModule mod_headers.c>\n";
|
244 |
+
$rules .= " <IfModule mod_setenvif.c>\n";
|
245 |
+
|
246 |
+
if (($config['success-response'] == 'converted') || ($config['redirect-to-existing-in-htaccess'])) {
|
247 |
+
$rules .= " # Set Vary:Accept header for the image types handled by WebP Express.\n" .
|
248 |
+
" # The purpose is to make CDN aware that the response varies with the Accept header, so it should not just use the URL as cache key, but also the Accept header. \n" .
|
249 |
+
" SetEnvIf Request_URI \"\.(" . $fileExt . ")\" ADDVARY\n" .
|
250 |
+
" Header append \"Vary\" \"Accept\" env=ADDVARY\n\n";
|
251 |
+
}
|
252 |
|
253 |
+
$rules .= " # Set X-WebP-Express header for diagnose purposes\n" .
|
254 |
+
" # Apache appends \"REDIRECT_\" in front of the environment variables defined in mod_rewrite, but LiteSpeed does not.\n" .
|
255 |
+
" # So, the next line is for Apache, in order to set environment variables without \"REDIRECT_\"\n" .
|
256 |
+
" SetEnvIf REDIRECT_EXISTING 1 EXISTING=1\n" .
|
257 |
+
//" SetEnvIf REDIRECT_WOD 1 WOD=1\n\n" .
|
258 |
+
//" # Set the debug header\n" .
|
259 |
+
" Header set \"X-WebP-Express\" \"Redirected directly to existing webp\" env=EXISTING\n" .
|
260 |
+
//" Header set \"X-WebP-Express\" \"Redirected to image converter\" env=WOD\n" .
|
261 |
+
" </IfModule>\n" .
|
262 |
+
" </IfModule>\n\n";
|
263 |
+
}
|
264 |
+
$rules .="</IfModule>\n";
|
265 |
|
266 |
+
/*if ($config['redirect-to-existing-in-htaccess']) {
|
267 |
$rules .=
|
268 |
"<IfModule mod_headers.c>\n" .
|
269 |
" # Append Vary Accept header, when the rules above are redirecting to existing webp\n" .
|
280 |
"</IfModule>\n\n";
|
281 |
}*/
|
282 |
|
283 |
+
$rules .= "<IfModule mod_mime.c>\n";
|
284 |
+
$rules .= " AddType image/webp .webp\n";
|
285 |
+
$rules .= "</IfModule>\n";
|
286 |
return $rules;
|
287 |
}
|
288 |
|
333 |
}
|
334 |
|
335 |
$propsToCompare = [
|
336 |
+
'forward-query-string' => true,
|
337 |
+
'image-types' => 1,
|
338 |
+
'do-not-pass-source-in-query-string' => false,
|
339 |
+
'redirect-to-existing-in-htaccess' => false,
|
340 |
+
'only-redirect-to-converter-on-cache-miss' => false,
|
341 |
+
'success-response' => 'converted',
|
342 |
+
'cache-control' => 'no-header',
|
343 |
+
'cache-control-custom' => 'public, max-age:3600',
|
344 |
+
'cache-control-max-age' => 'one-week',
|
345 |
+
'cache-control-public' => true,
|
346 |
];
|
347 |
|
348 |
+
if (isset($newConfig['redirect-to-existing-in-htaccess']) && $newConfig['redirect-to-existing-in-htaccess']) {
|
349 |
+
$propsToCompare['destination-folder'] = 'separate';
|
350 |
+
$propsToCompare['destination-extension'] = 'append';
|
351 |
+
}
|
352 |
|
353 |
+
foreach ($propsToCompare as $prop => $behaviourBeforeIntroduced) {
|
354 |
if (!isset($newConfig[$prop])) {
|
355 |
continue;
|
356 |
}
|
357 |
if (!isset($oldConfig[$prop])) {
|
358 |
+
// Do not trigger .htaccess update if the new value results
|
359 |
+
// in same old behaviour (before this option was introduced)
|
360 |
+
if ($newConfig[$prop] == $behaviourBeforeIntroduced) {
|
361 |
+
continue;
|
362 |
+
} else {
|
363 |
+
// Otherwise DO trigger .htaccess update
|
364 |
+
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
}
|
|
|
|
|
|
|
|
|
366 |
}
|
367 |
if ($newConfig[$prop] != $oldConfig[$prop]) {
|
368 |
return true;
|
lib/classes/Paths.php
CHANGED
@@ -13,8 +13,10 @@ class Paths
|
|
13 |
|
14 |
public static function createDirIfMissing($dir)
|
15 |
{
|
16 |
-
if (
|
17 |
-
|
|
|
|
|
18 |
}
|
19 |
return file_exists($dir);
|
20 |
}
|
@@ -36,6 +38,34 @@ class Paths
|
|
36 |
return PathHelper::getRelDir(realpath($_SERVER['DOCUMENT_ROOT']), $dir);
|
37 |
}
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
// ------------ Home Dir -------------
|
40 |
|
41 |
public static function getHomeDirAbs()
|
@@ -43,7 +73,7 @@ class Paths
|
|
43 |
if (!function_exists('get_home_path')) {
|
44 |
require_once ABSPATH . 'wp-admin/includes/file.php';
|
45 |
}
|
46 |
-
return
|
47 |
}
|
48 |
|
49 |
public static function getHomeDirRel()
|
@@ -56,7 +86,7 @@ class Paths
|
|
56 |
|
57 |
public static function getIndexDirAbs()
|
58 |
{
|
59 |
-
return
|
60 |
}
|
61 |
|
62 |
public static function getIndexDirRel()
|
@@ -88,7 +118,7 @@ class Paths
|
|
88 |
// ------------ WP Content Dir -------------
|
89 |
public static function getWPContentDirAbs()
|
90 |
{
|
91 |
-
return
|
92 |
}
|
93 |
public static function getWPContentDirRel()
|
94 |
{
|
@@ -111,10 +141,7 @@ class Paths
|
|
111 |
|
112 |
public static function getContentDirAbs()
|
113 |
{
|
114 |
-
|
115 |
-
|
116 |
-
}
|
117 |
-
return rtrim(WP_CONTENT_DIR, '/') . '/webp-express';
|
118 |
}
|
119 |
|
120 |
public static function getContentDirRel()
|
@@ -131,7 +158,7 @@ class Paths
|
|
131 |
public static function getUploadDirAbs()
|
132 |
{
|
133 |
$upload_dir = wp_upload_dir(null, false);
|
134 |
-
return $upload_dir['basedir'];
|
135 |
}
|
136 |
public static function getUploadDirRel()
|
137 |
{
|
13 |
|
14 |
public static function createDirIfMissing($dir)
|
15 |
{
|
16 |
+
if (!@file_exists($dir)) {
|
17 |
+
// We use the wp_mkdir_p, because it takes care of setting folder
|
18 |
+
// permissions to that of parent, and handles creating deep structures too
|
19 |
+
wp_mkdir_p($dir);
|
20 |
}
|
21 |
return file_exists($dir);
|
22 |
}
|
38 |
return PathHelper::getRelDir(realpath($_SERVER['DOCUMENT_ROOT']), $dir);
|
39 |
}
|
40 |
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Return absolute dir.
|
44 |
+
* - realpath() is used to resolve soft links and resolve '../' and './'
|
45 |
+
* - trailing dash is removed - we don't use that around here.
|
46 |
+
*
|
47 |
+
* realpath() only works on existing dirs.
|
48 |
+
* If realpath fails, PathHelper::canonicalize() will be used insead.
|
49 |
+
* (this takes care of resolving '../' and './', but does NOT resolve soft links)
|
50 |
+
*/
|
51 |
+
public static function getAbsDir($dir)
|
52 |
+
{
|
53 |
+
$result = realpath($dir);
|
54 |
+
if ($result === false) {
|
55 |
+
$dir = PathHelper::canonicalize($dir);
|
56 |
+
} else {
|
57 |
+
$dir = $result;
|
58 |
+
}
|
59 |
+
return rtrim($dir, '/');
|
60 |
+
}
|
61 |
+
|
62 |
+
// ------------ Document Root -------------
|
63 |
+
|
64 |
+
public static function getDocumentRootAbs()
|
65 |
+
{
|
66 |
+
return self::getAbsDir($_SERVER["DOCUMENT_ROOT"]);
|
67 |
+
}
|
68 |
+
|
69 |
// ------------ Home Dir -------------
|
70 |
|
71 |
public static function getHomeDirAbs()
|
73 |
if (!function_exists('get_home_path')) {
|
74 |
require_once ABSPATH . 'wp-admin/includes/file.php';
|
75 |
}
|
76 |
+
return self::getAbsDir(get_home_path());
|
77 |
}
|
78 |
|
79 |
public static function getHomeDirRel()
|
86 |
|
87 |
public static function getIndexDirAbs()
|
88 |
{
|
89 |
+
return self::getAbsDir(ABSPATH);
|
90 |
}
|
91 |
|
92 |
public static function getIndexDirRel()
|
118 |
// ------------ WP Content Dir -------------
|
119 |
public static function getWPContentDirAbs()
|
120 |
{
|
121 |
+
return self::getAbsDir(WP_CONTENT_DIR);
|
122 |
}
|
123 |
public static function getWPContentDirRel()
|
124 |
{
|
141 |
|
142 |
public static function getContentDirAbs()
|
143 |
{
|
144 |
+
return self::getWPContentDirAbs() . '/webp-express';
|
|
|
|
|
|
|
145 |
}
|
146 |
|
147 |
public static function getContentDirRel()
|
158 |
public static function getUploadDirAbs()
|
159 |
{
|
160 |
$upload_dir = wp_upload_dir(null, false);
|
161 |
+
return self::getAbsDir($upload_dir['basedir']);
|
162 |
}
|
163 |
public static function getUploadDirRel()
|
164 |
{
|
lib/migrate/migrate.php
CHANGED
@@ -29,6 +29,17 @@ if (!(State::getState('configured', false))) {
|
|
29 |
update_option('webp-express-migration-version', WEBPEXPRESS_MIGRATION_VERSION);
|
30 |
} else {
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
if (intval(get_option('webp-express-migration-version', 0)) == 0) {
|
33 |
// run migration 1
|
34 |
// It must take care of updating migration-version to 1, - if successful.
|
@@ -47,4 +58,5 @@ if (!(State::getState('configured', false))) {
|
|
47 |
// run migration 3
|
48 |
include __DIR__ . '/migrate3.php';
|
49 |
}
|
|
|
50 |
}
|
29 |
update_option('webp-express-migration-version', WEBPEXPRESS_MIGRATION_VERSION);
|
30 |
} else {
|
31 |
|
32 |
+
for ($x = intval(get_option('webp-express-migration-version', 0)); $x < WEBPEXPRESS_MIGRATION_VERSION; $x++) {
|
33 |
+
if (intval(get_option('webp-express-migration-version', 0)) == $x) {
|
34 |
+
// run migration X+1, which upgrades from X to X+1
|
35 |
+
// It must take care of updating the "webp-express-migration-version" option to X+1, - if successful.
|
36 |
+
// If unsuccessful, it must leaves the option unaltered, which will prevent
|
37 |
+
// newer migrations to run, until the problem with that migration is fixed.
|
38 |
+
include __DIR__ . '/migrate' . ($x + 1) . '.php';
|
39 |
+
}
|
40 |
+
|
41 |
+
}
|
42 |
+
/*
|
43 |
if (intval(get_option('webp-express-migration-version', 0)) == 0) {
|
44 |
// run migration 1
|
45 |
// It must take care of updating migration-version to 1, - if successful.
|
58 |
// run migration 3
|
59 |
include __DIR__ . '/migrate3.php';
|
60 |
}
|
61 |
+
*/
|
62 |
}
|
lib/migrate/migrate4.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
|
6 |
+
include_once __DIR__ . '/../classes/Config.php';
|
7 |
+
use \WebPExpress\Config;
|
8 |
+
|
9 |
+
include_once __DIR__ . '/../classes/Messenger.php';
|
10 |
+
use \WebPExpress\Messenger;
|
11 |
+
|
12 |
+
|
13 |
+
function webpexpress_migrate4() {
|
14 |
+
$config = Config::loadConfig();
|
15 |
+
|
16 |
+
if ($config !== false) {
|
17 |
+
if (isset($config['cache-control'])) {
|
18 |
+
switch ($config['cache-control']) {
|
19 |
+
case 'no-header':
|
20 |
+
break;
|
21 |
+
case 'custom':
|
22 |
+
break;
|
23 |
+
default:
|
24 |
+
$config['cache-control-max-age'] = $config['cache-control'];
|
25 |
+
$config['cache-control'] = 'set';
|
26 |
+
$config['cache-control-public'] = true;
|
27 |
+
Config::saveConfigurationFile($config);
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
if (isset($config['fail']) && ($config['fail'] != 'original')) {
|
32 |
+
$config['operation-mode'] = 'tweaked';
|
33 |
+
if (Config::saveConfigurationFile($config)) {
|
34 |
+
Messenger::addMessage(
|
35 |
+
'info',
|
36 |
+
'WebP Express 0.10 introduces <i>operation modes</i>. Your configuration <i>almost</i> fits the mode called ' .
|
37 |
+
'<i>Standard</i>, however as you have set the <i>Response on failure</i> option to something other than ' .
|
38 |
+
'<i>Original</i>, your setup has been put into <i>Tweaked</i> mode. ' .
|
39 |
+
'<a href="' . Paths::getSettingsUrl() . '">You might want to go and change that</a>.'
|
40 |
+
);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
if (isset($config['redirect-to-existing-in-htaccess']) && ($config['redirect-to-existing-in-htaccess'])) {
|
45 |
+
Messenger::addMessage(
|
46 |
+
'info',
|
47 |
+
'In WebP Express 0.10, the <i>.htaccess</i> rules has been altered a bit: The Cache-Control header is now set when ' .
|
48 |
+
'redirecting directly to an existing webp image.<br>' .
|
49 |
+
'You might want to <a href="' . Paths::getSettingsUrl() . '">go to the options page</a> and re-save settings in order to regenerate the <i>.htaccess</i> rules.'
|
50 |
+
);
|
51 |
+
}
|
52 |
+
|
53 |
+
if (!isset($config['redirect-to-existing-in-htaccess'])) {
|
54 |
+
Messenger::addMessage(
|
55 |
+
'info',
|
56 |
+
'In WebP Express 0.10, the "Redirect directly to converted image when available" option is no longer in beta. ' .
|
57 |
+
'You might want to <a href="' . Paths::getSettingsUrl() . '">go and activate it</a>.'
|
58 |
+
);
|
59 |
+
}
|
60 |
+
|
61 |
+
}
|
62 |
+
|
63 |
+
// PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
|
64 |
+
update_option('webp-express-migration-version', '4');
|
65 |
+
|
66 |
+
}
|
67 |
+
|
68 |
+
webpexpress_migrate4();
|
lib/options/css/webp-express-options-page.css
CHANGED
@@ -159,7 +159,36 @@
|
|
159 |
min-width: 150px;
|
160 |
font-weight: normal;
|
161 |
text-align: left;
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
}
|
164 |
#converters li.operational .popup {
|
165 |
background-color: #80ff80;
|
@@ -174,9 +203,6 @@
|
|
174 |
|
175 |
}
|
176 |
|
177 |
-
.help .popup {
|
178 |
-
min-width: 250px;
|
179 |
-
}
|
180 |
|
181 |
/*
|
182 |
#converters li > a.remove-converter {
|
@@ -227,6 +253,13 @@
|
|
227 |
font-family: sans-serif;
|
228 |
position: relative;
|
229 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
|
231 |
/*
|
232 |
.converter-options.wpc #wpc_web_services_div > p {
|
159 |
min-width: 150px;
|
160 |
font-weight: normal;
|
161 |
text-align: left;
|
162 |
+
}
|
163 |
+
|
164 |
+
.help .popup.narrow {
|
165 |
+
width: 200px;
|
166 |
+
}
|
167 |
+
.help .popup {
|
168 |
+
width: 250px;
|
169 |
+
}
|
170 |
+
.help .popup.wide {
|
171 |
+
width: 350px;
|
172 |
+
}
|
173 |
+
.help .popup.wider {
|
174 |
+
width: 450px;
|
175 |
+
}
|
176 |
+
@media (max-width: 500px) {
|
177 |
+
.help .popup {
|
178 |
+
max-width: 380px;
|
179 |
+
}
|
180 |
+
}
|
181 |
+
@media (max-width: 400px) {
|
182 |
+
.help .popup {
|
183 |
+
max-width: 280px;
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
.help .popup > p:first-child {
|
188 |
+
margin-top: 0;
|
189 |
+
}
|
190 |
+
.help .popup > p:last-child {
|
191 |
+
margin-bottom: 0;
|
192 |
}
|
193 |
#converters li.operational .popup {
|
194 |
background-color: #80ff80;
|
203 |
|
204 |
}
|
205 |
|
|
|
|
|
|
|
206 |
|
207 |
/*
|
208 |
#converters li > a.remove-converter {
|
253 |
font-family: sans-serif;
|
254 |
position: relative;
|
255 |
}
|
256 |
+
.help.no-margin-left {
|
257 |
+
margin-left: 0px;
|
258 |
+
}
|
259 |
+
.help.set-margin-right {
|
260 |
+
margin-right: 7px;
|
261 |
+
}
|
262 |
+
|
263 |
|
264 |
/*
|
265 |
.converter-options.wpc #wpc_web_services_div > p {
|
lib/options/enqueue_scripts.php
CHANGED
@@ -6,7 +6,7 @@ use \WebPExpress\Paths;
|
|
6 |
include_once __DIR__ . '/../classes/Config.php';
|
7 |
use \WebPExpress\Config;
|
8 |
|
9 |
-
$version = '0.
|
10 |
|
11 |
function webp_express_add_inline_script($id, $script, $position) {
|
12 |
if (function_exists('wp_add_inline_script')) {
|
@@ -24,17 +24,30 @@ wp_enqueue_script('daspopup');
|
|
24 |
|
25 |
$config = Config::getConfigForOptionsPage();
|
26 |
|
27 |
-
|
28 |
-
wp_register_script('converters', plugins_url('js/converters.js', __FILE__), ['sortable','daspopup'], $version);
|
29 |
-
webp_express_add_inline_script('converters', 'window.webpExpressPaths = ' . json_encode(Paths::getUrlsAndPathsForTheJavascript()) . ';', 'before');
|
30 |
-
webp_express_add_inline_script('converters', 'window.converters = ' . json_encode($config['converters']) . ';', 'before');
|
31 |
-
wp_enqueue_script('converters');
|
32 |
|
|
|
|
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
//wp_register_script('api_keys', plugins_url('js/api-keys.js', __FILE__), ['daspopup'], '0.7.0-dev8');
|
40 |
//wp_enqueue_script('api_keys');
|
6 |
include_once __DIR__ . '/../classes/Config.php';
|
7 |
use \WebPExpress\Config;
|
8 |
|
9 |
+
$version = '0.10.0';
|
10 |
|
11 |
function webp_express_add_inline_script($id, $script, $position) {
|
12 |
if (function_exists('wp_add_inline_script')) {
|
24 |
|
25 |
$config = Config::getConfigForOptionsPage();
|
26 |
|
27 |
+
if (!(isset($config['operation-mode']) && $config['operation-mode'] == 'just-redirect')) {
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
// Remove empty options arrays.
|
30 |
+
// These cause trouble in json because they are encoded as [] rather than {}
|
31 |
|
32 |
+
foreach ($config['converters'] as &$converter) {
|
33 |
+
if (isset($converter['options']) && (count(array_keys($converter['options'])) == 0)) {
|
34 |
+
unset($converter['options']);
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
// Converters
|
39 |
+
wp_register_script('converters', plugins_url('js/converters.js', __FILE__), ['sortable','daspopup'], $version);
|
40 |
+
webp_express_add_inline_script('converters', 'window.webpExpressPaths = ' . json_encode(Paths::getUrlsAndPathsForTheJavascript()) . ';', 'before');
|
41 |
+
webp_express_add_inline_script('converters', 'window.converters = ' . json_encode($config['converters']) . ';', 'before');
|
42 |
+
wp_enqueue_script('converters');
|
43 |
+
|
44 |
+
|
45 |
+
// Whitelist
|
46 |
+
wp_register_script('whitelist', plugins_url('js/whitelist.js', __FILE__), ['daspopup'], $version);
|
47 |
+
webp_express_add_inline_script('whitelist', 'window.whitelist = ' . json_encode($config['web-service']['whitelist']) . ';', 'before');
|
48 |
+
wp_enqueue_script('whitelist');
|
49 |
+
|
50 |
+
}
|
51 |
|
52 |
//wp_register_script('api_keys', plugins_url('js/api-keys.js', __FILE__), ['daspopup'], '0.7.0-dev8');
|
53 |
//wp_enqueue_script('api_keys');
|
lib/options/js/converters.js
CHANGED
@@ -5,50 +5,6 @@ window.convertersMap = {};
|
|
5 |
|
6 |
window.currentlyEditing = '';
|
7 |
|
8 |
-
function resetToDefaultConverters() {
|
9 |
-
window.converters = window.defaultConverters;
|
10 |
-
}
|
11 |
-
|
12 |
-
function addMissingConvertersAndOptions() {
|
13 |
-
// check if all available converters are in the array.
|
14 |
-
// if not - add!
|
15 |
-
// the double loop could be avoided with map. But arrays are so small, so not worth it
|
16 |
-
/*
|
17 |
-
for (var i=0; i<window.defaultConverters.length; i++) {
|
18 |
-
var checkMe = window.defaultConverters[i];
|
19 |
-
var found = false;
|
20 |
-
for (var j=0; j<window.converters.length; j++) {
|
21 |
-
var checkMe2 = window.converters[j]
|
22 |
-
if (checkMe2['converter'] == checkMe['converter']) {
|
23 |
-
found = true;
|
24 |
-
// at a earilier point in time, we accidently added options as an
|
25 |
-
// empty array instead of an empty object. Correcting that!
|
26 |
-
if (checkMe2['options'] && checkMe2['options'].constructor === Array) {
|
27 |
-
checkMe2['options'] = {};
|
28 |
-
}
|
29 |
-
if (checkMe['options']) {
|
30 |
-
for (var optionName in checkMe['options']) {
|
31 |
-
if (checkMe['options'].hasOwnProperty(optionName)) {
|
32 |
-
if (!checkMe2['options']) {
|
33 |
-
checkMe2['options'] = {};
|
34 |
-
}
|
35 |
-
if (!checkMe2['options'].hasOwnProperty(optionName)) {
|
36 |
-
checkMe2['options'][optionName] = checkMe['options'][optionName];
|
37 |
-
}
|
38 |
-
}
|
39 |
-
}
|
40 |
-
}
|
41 |
-
}
|
42 |
-
}
|
43 |
-
if (!found) {
|
44 |
-
window.converters.push(window.defaultConverters[i]);
|
45 |
-
}
|
46 |
-
|
47 |
-
}*/
|
48 |
-
//console.log(window.converters);
|
49 |
-
//console.log(window.defaultConverters);
|
50 |
-
}
|
51 |
-
|
52 |
function getConversionMethodDescription(converterId) {
|
53 |
var descriptions = {
|
54 |
'cwebp': '<i>cwebp</i> binary',
|
@@ -211,8 +167,6 @@ function setConvertersHTML() {
|
|
211 |
}
|
212 |
|
213 |
document.addEventListener('DOMContentLoaded', function() {
|
214 |
-
//resetToDefaultConverters();
|
215 |
-
addMissingConvertersAndOptions();
|
216 |
setConvertersHTML();
|
217 |
});
|
218 |
|
@@ -252,7 +206,6 @@ function deleteConverterOption(converter, optionName) {
|
|
252 |
function configureConverter(id) {
|
253 |
var converter = window.convertersMap[id];
|
254 |
window.currentlyEditing = id;
|
255 |
-
|
256 |
var q = getConverterOption(converter, 'quality', 'auto');
|
257 |
if (document.getElementById(id + '_quality')) {
|
258 |
document.getElementById(id + '_quality').value = q;
|
@@ -417,6 +370,7 @@ function updateConverterOptions() {
|
|
417 |
setConverterOption(converter, 'use-nice', document.getElementById('imagickbinary_use_nice').checked);
|
418 |
break;
|
419 |
}
|
|
|
420 |
updateInputValue();
|
421 |
tb_remove();
|
422 |
}
|
@@ -573,109 +527,3 @@ function wpcApiVersionChanged() {
|
|
573 |
document.getElementById('wpc_api_key_div').style.display = 'block';
|
574 |
}
|
575 |
}
|
576 |
-
/*
|
577 |
-
function wpcClearPropertiesForm() {
|
578 |
-
document.getElementById('wpc_label').value = '';
|
579 |
-
document.getElementById('wpc_url').value = '';
|
580 |
-
document.getElementById('wpc_api_key').value = '';
|
581 |
-
document.getElementById('wpc_crypt_api_key_in_transfer').checked = true;
|
582 |
-
}
|
583 |
-
|
584 |
-
function wpcRemoveEntry(i) {
|
585 |
-
var id = window.currentlyEditing;
|
586 |
-
var converter = window.convertersMap[id];
|
587 |
-
|
588 |
-
converter['options']['web-services'].splice(i, 1);
|
589 |
-
wpcUpdateWebServicesHTML();
|
590 |
-
}
|
591 |
-
function wpcUpdateWebServicesHTML() {
|
592 |
-
var id = window.currentlyEditing;
|
593 |
-
var converter = window.convertersMap[id];
|
594 |
-
|
595 |
-
//setConverterOption(converter, 'web-services', )
|
596 |
-
var s = '';
|
597 |
-
|
598 |
-
var webServices = getConverterOption(converter, 'web-services', []);
|
599 |
-
|
600 |
-
if (webServices.length == 0) {
|
601 |
-
s += '<p>Not connected to any web service yet</p>';
|
602 |
-
} else {
|
603 |
-
s += '<ul>';
|
604 |
-
for (var i=0; i<webServices.length; i++) {
|
605 |
-
s+='<li>';
|
606 |
-
s+=webServices[i].label;
|
607 |
-
s+='<div class="wpc-links">'
|
608 |
-
s+='<a href="javascript:wpcEditEntry(' + i + ')">edit</a>';
|
609 |
-
s+='<a href="javascript:wpcRemoveEntry(' + i + ')">remove</a>';
|
610 |
-
s+='</div>'
|
611 |
-
s+='</li>';
|
612 |
-
}
|
613 |
-
s += '</ul>';
|
614 |
-
}
|
615 |
-
|
616 |
-
document.getElementById('wpc_web_services_div').innerHTML = s;
|
617 |
-
}
|
618 |
-
|
619 |
-
function wpcAddEntry() {
|
620 |
-
var id = window.currentlyEditing;
|
621 |
-
var converter = window.convertersMap[id];
|
622 |
-
|
623 |
-
if (!converter['options']['web-services']) {
|
624 |
-
converter['options']['web-services'] = [];
|
625 |
-
}
|
626 |
-
converter['options']['web-services'].push(
|
627 |
-
{
|
628 |
-
'label' : document.getElementById('wpc_label').value,
|
629 |
-
'url' : document.getElementById('wpc_url').value,
|
630 |
-
'new-api-key': document.getElementById('wpc_api_key').value,
|
631 |
-
'crypt-api-key-in-transfer': document.getElementById('wpc_crypt_api_key_in_transfer').checked
|
632 |
-
}
|
633 |
-
)
|
634 |
-
wpcUpdateWebServicesHTML();
|
635 |
-
closeDasPopup();
|
636 |
-
}
|
637 |
-
|
638 |
-
function wpcUpdateEntry() {
|
639 |
-
var id = window.currentlyEditing;
|
640 |
-
var converter = window.convertersMap[id];
|
641 |
-
var i = parseInt(document.getElementById('wpc_i').value, 10);
|
642 |
-
var settings = converter['options']['web-services'][i];
|
643 |
-
|
644 |
-
// TODO: validate
|
645 |
-
settings['label'] = document.getElementById('wpc_label').value;
|
646 |
-
settings['url'] = document.getElementById('wpc_url').value;
|
647 |
-
settings['crypt-api-key-in-transfer'] = document.getElementById('wpc_crypt_api_key_in_transfer').checked;
|
648 |
-
|
649 |
-
wpcUpdateWebServicesHTML();
|
650 |
-
closeDasPopup();
|
651 |
-
|
652 |
-
}
|
653 |
-
|
654 |
-
function wpcEditEntry(i) {
|
655 |
-
var id = window.currentlyEditing;
|
656 |
-
var converter = window.convertersMap[id];
|
657 |
-
var settings = converter['options']['web-services'][i];
|
658 |
-
|
659 |
-
// todo: uid?
|
660 |
-
// TODO: api keys must be removed in page.php
|
661 |
-
// TODO: api-version
|
662 |
-
document.getElementById('wpc_i').value = i;
|
663 |
-
document.getElementById('wpc_label').value = settings['label'];
|
664 |
-
document.getElementById('wpc_url').value = settings['url'];
|
665 |
-
document.getElementById('wpc_new_api_key').value = '';
|
666 |
-
document.getElementById('wpc_crypt_api_key_in_transfer').checked = settings['crypt-api-key-in-transfer'];
|
667 |
-
|
668 |
-
document.getElementById('wpc_properties_popup').className = 'das-popup mode-edit';
|
669 |
-
openDasPopup('wpc_properties_popup', 500, 350);
|
670 |
-
}
|
671 |
-
|
672 |
-
|
673 |
-
function wpcAddManually() {
|
674 |
-
closeDasPopup();
|
675 |
-
|
676 |
-
wpcClearPropertiesForm();
|
677 |
-
|
678 |
-
document.getElementById('wpc_properties_popup').className = 'das-popup mode-add';
|
679 |
-
openDasPopup('wpc_properties_popup', 500, 350);
|
680 |
-
|
681 |
-
}*/
|
5 |
|
6 |
window.currentlyEditing = '';
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
function getConversionMethodDescription(converterId) {
|
9 |
var descriptions = {
|
10 |
'cwebp': '<i>cwebp</i> binary',
|
167 |
}
|
168 |
|
169 |
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
170 |
setConvertersHTML();
|
171 |
});
|
172 |
|
206 |
function configureConverter(id) {
|
207 |
var converter = window.convertersMap[id];
|
208 |
window.currentlyEditing = id;
|
|
|
209 |
var q = getConverterOption(converter, 'quality', 'auto');
|
210 |
if (document.getElementById(id + '_quality')) {
|
211 |
document.getElementById(id + '_quality').value = q;
|
370 |
setConverterOption(converter, 'use-nice', document.getElementById('imagickbinary_use_nice').checked);
|
371 |
break;
|
372 |
}
|
373 |
+
|
374 |
updateInputValue();
|
375 |
tb_remove();
|
376 |
}
|
527 |
document.getElementById('wpc_api_key_div').style.display = 'block';
|
528 |
}
|
529 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/options/js/page.js
CHANGED
@@ -1,23 +1,44 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
function updateCacheControlCustomVisibility() {
|
3 |
|
4 |
if (document.getElementById('cache_control_select') == null) {
|
5 |
-
//
|
6 |
-
// but it does? https://wordpress.org/support/topic/console-errors-9/#post-11018243
|
7 |
-
alert('document.getElementById("cache_control_select") returns null. Strange! Please report.');
|
8 |
return;
|
9 |
}
|
10 |
if (document.getElementById('cache_control_custom') == null) {
|
11 |
alert('document.getElementById("cache_control_custom") returns null. Strange! Please report.');
|
12 |
return;
|
13 |
}
|
|
|
|
|
|
|
|
|
|
|
14 |
var cacheControlValue = document.getElementById('cache_control_select').value;
|
|
|
15 |
var customEl = document.getElementById('cache_control_custom');
|
16 |
if (cacheControlValue == 'custom') {
|
17 |
customEl.setAttribute('type', 'text');
|
18 |
} else {
|
19 |
customEl.setAttribute('type', 'hidden');
|
20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
|
23 |
function updateQualityVisibility() {
|
@@ -37,6 +58,22 @@ function updateQualityVisibility() {
|
|
37 |
maxQualityRowEl.style['display'] = 'none';
|
38 |
qualitySpecificRowEl.style['display'] = 'table-row';
|
39 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
}
|
42 |
|
@@ -56,10 +93,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
56 |
updateCacheControlCustomVisibility();
|
57 |
updateQualityVisibility();
|
58 |
updateServerSettingsVisibility();
|
|
|
59 |
|
60 |
-
document.getElementById('cache_control_select')
|
61 |
-
|
62 |
-
|
|
|
|
|
63 |
|
64 |
if (document.getElementById('quality_auto_select')) {
|
65 |
document.getElementById('quality_auto_select').addEventListener('change', function() {
|
@@ -67,22 +107,38 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
67 |
});
|
68 |
}
|
69 |
|
70 |
-
document.getElementById('
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
if (
|
80 |
-
|
81 |
} else {
|
82 |
-
|
83 |
}
|
84 |
}
|
85 |
-
}, 500);
|
86 |
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
});
|
1 |
+
function setOptionVisibility(elmId, show) {
|
2 |
+
var elm = document.getElementById(elmId);
|
3 |
+
if (!elm) {
|
4 |
+
return;
|
5 |
+
}
|
6 |
+
if (show) {
|
7 |
+
elm.style['visibility'] = 'visible';
|
8 |
+
elm.style['position'] = 'static';
|
9 |
+
} else {
|
10 |
+
elm.style['visibility'] = 'hidden';
|
11 |
+
elm.style['position'] = 'absolute';
|
12 |
+
}
|
13 |
+
}
|
14 |
function updateCacheControlCustomVisibility() {
|
15 |
|
16 |
if (document.getElementById('cache_control_select') == null) {
|
17 |
+
// Well, it seems that the cache control option isn't available in this operation mode
|
|
|
|
|
18 |
return;
|
19 |
}
|
20 |
if (document.getElementById('cache_control_custom') == null) {
|
21 |
alert('document.getElementById("cache_control_custom") returns null. Strange! Please report.');
|
22 |
return;
|
23 |
}
|
24 |
+
if (document.getElementById('cache_control_public') == null) {
|
25 |
+
alert('document.getElementById("cache_control_public") returns null. Strange! Please report.');
|
26 |
+
return;
|
27 |
+
}
|
28 |
+
|
29 |
var cacheControlValue = document.getElementById('cache_control_select').value;
|
30 |
+
/*
|
31 |
var customEl = document.getElementById('cache_control_custom');
|
32 |
if (cacheControlValue == 'custom') {
|
33 |
customEl.setAttribute('type', 'text');
|
34 |
} else {
|
35 |
customEl.setAttribute('type', 'hidden');
|
36 |
+
}*/
|
37 |
+
|
38 |
+
setOptionVisibility('cache_control_custom_div', (cacheControlValue == 'custom'));
|
39 |
+
|
40 |
+
setOptionVisibility('cache_control_set_div', (cacheControlValue == 'set'));
|
41 |
+
|
42 |
}
|
43 |
|
44 |
function updateQualityVisibility() {
|
58 |
maxQualityRowEl.style['display'] = 'none';
|
59 |
qualitySpecificRowEl.style['display'] = 'table-row';
|
60 |
}
|
61 |
+
}
|
62 |
+
|
63 |
+
function updateDestinationExtensionVisibility() {
|
64 |
+
var destinationFolderEl = document.getElementById('destination_folder');
|
65 |
+
if (!destinationFolderEl) {
|
66 |
+
return;
|
67 |
+
}
|
68 |
+
var destinationFolderValue = destinationFolderEl.value;
|
69 |
+
var destinationExtensionEl = document.getElementById('destination_extension_row');
|
70 |
+
|
71 |
+
//alert(qualityAutoValue);
|
72 |
+
if (destinationFolderValue == 'mingled') {
|
73 |
+
destinationExtensionEl.style['display'] = 'table-row';
|
74 |
+
} else {
|
75 |
+
destinationExtensionEl.style['display'] = 'none';
|
76 |
+
}
|
77 |
|
78 |
}
|
79 |
|
93 |
updateCacheControlCustomVisibility();
|
94 |
updateQualityVisibility();
|
95 |
updateServerSettingsVisibility();
|
96 |
+
updateDestinationExtensionVisibility();
|
97 |
|
98 |
+
if (document.getElementById('cache_control_select')) {
|
99 |
+
document.getElementById('cache_control_select').addEventListener('change', function() {
|
100 |
+
updateCacheControlCustomVisibility();
|
101 |
+
});
|
102 |
+
}
|
103 |
|
104 |
if (document.getElementById('quality_auto_select')) {
|
105 |
document.getElementById('quality_auto_select').addEventListener('change', function() {
|
107 |
});
|
108 |
}
|
109 |
|
110 |
+
if (document.getElementById('destination_folder')) {
|
111 |
+
document.getElementById('destination_folder').addEventListener('change', function() {
|
112 |
+
updateDestinationExtensionVisibility();
|
113 |
+
});
|
114 |
+
}
|
115 |
+
|
116 |
+
if (document.getElementById('web_service_enabled')) {
|
117 |
+
document.getElementById('web_service_enabled').addEventListener('change', function() {
|
118 |
+
updateServerSettingsVisibility();
|
119 |
+
});
|
120 |
+
}
|
121 |
|
122 |
+
document.getElementById('change_operation_mode').addEventListener('change', function() {
|
123 |
+
var msg;
|
124 |
+
if (document.getElementById('operation_mode').value == 'tweaked') {
|
125 |
+
msg = 'Save configuration and change mode? Any tweaks will be lost';
|
126 |
+
} else {
|
127 |
+
if (document.getElementById('change_operation_mode').value == 'tweaked') {
|
128 |
+
msg = 'Save configuration and change to tweaked mode? No options are lost when changing to tweaked mode (it will behave the same way as currently, until you start tweaking)';
|
129 |
} else {
|
130 |
+
msg = 'Save configuration and change mode?';
|
131 |
}
|
132 |
}
|
|
|
133 |
|
134 |
+
if (confirm(msg)) {
|
135 |
+
document.getElementById('webpexpress_settings').submit();
|
136 |
+
} else {
|
137 |
+
// undo select box change
|
138 |
+
document.getElementById('change_operation_mode').value = document.getElementById('operation_mode').value;
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
});
|
143 |
+
|
144 |
});
|
lib/options/options/cache-control.inc
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
//$maxQuality = get_option('webp_express_max_quality');
|
4 |
-
$cacheControl = $config['cache-control'];
|
5 |
-
$cacheControlCustom = $config['cache-control-custom'];
|
6 |
-
|
7 |
-
echo '<tr><th scope="row">Caching';
|
8 |
-
echo helpIcon(
|
9 |
-
'Controls the cache-control header for the converted image. ' .
|
10 |
-
'This header is only sent when a converted image can be successfully delivered (either existing, or new ' .
|
11 |
-
'conversion). In case of failure, headers will be sent to prevent caching.');
|
12 |
-
echo '</th><td>';
|
13 |
-
echo '<select id="cache_control_select" name="cache-control">';
|
14 |
-
echo '<option value="no-header"' . ($cacheControl == 'no-header' ? ' selected' : '') . '>Do not set Cache-Control header</option>';
|
15 |
-
echo '<option value="one-second"' . ($cacheControl == 'one-second' ? ' selected' : '') . '>One second</option>';
|
16 |
-
echo '<option value="one-minute"' . ($cacheControl == 'one-minute' ? ' selected' : '') . '>One minute</option>';
|
17 |
-
echo '<option value="one-hour"' . ($cacheControl == 'one-hour' ? ' selected' : '') . '>One hour</option>';
|
18 |
-
echo '<option value="one-day"' . ($cacheControl == 'one-day' ? ' selected' : '') . '>One day</option>';
|
19 |
-
echo '<option value="one-week"' . ($cacheControl == 'one-week' ? ' selected' : '') . '>One week</option>';
|
20 |
-
echo '<option value="one-month"' . ($cacheControl == 'one-month' ? ' selected' : '') . '>One month</option>';
|
21 |
-
echo '<option value="one-year"' . ($cacheControl == 'one-year' ? ' selected' : '') . '>One year</option>';
|
22 |
-
echo '<option value="custom"' . ($cacheControl == 'custom' ? ' selected' : '') . '>Custom Cache-Control header</option>';
|
23 |
-
echo '</select><br>';
|
24 |
-
echo '<input type="text" id="cache_control_custom" name="cache-control-custom" value="' . $cacheControlCustom . '">';
|
25 |
-
echo '</td></tr>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/options/options/conversion-options/conversion-options.inc
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ($config['operation-mode'] == 'tweaked') : ?>
|
2 |
+
<fieldset class="block">
|
3 |
+
<h3>Conversion options</h3>
|
4 |
+
<p><i>The options here affects the conversion process</i></p>
|
5 |
+
<table class="form-table">
|
6 |
+
<tbody>
|
7 |
+
<?php
|
8 |
+
include_once 'quality.inc';
|
9 |
+
include_once 'metadata.inc';
|
10 |
+
include_once 'converters.inc';
|
11 |
+
include_once 'destination-folder.inc';
|
12 |
+
include_once 'destination-extension.inc';
|
13 |
+
?>
|
14 |
+
</tbody>
|
15 |
+
</table>
|
16 |
+
</fieldset>
|
17 |
+
<?php
|
18 |
+
else:
|
19 |
+
include_once 'quality.inc';
|
20 |
+
include_once 'metadata.inc';
|
21 |
+
include_once 'converters.inc';
|
22 |
+
|
23 |
+
if ($config['operation-mode'] == 'standard') {
|
24 |
+
include_once 'destination-folder.inc';
|
25 |
+
}
|
26 |
+
include_once 'destination-extension.inc';
|
27 |
+
endif;
|
28 |
+
?>
|
lib/options/options/{converter-options → conversion-options/converter-options}/cwebp.php
RENAMED
File without changes
|
lib/options/options/{converter-options → conversion-options/converter-options}/ewww.php
RENAMED
File without changes
|
lib/options/options/{converter-options → conversion-options/converter-options}/gd.php
RENAMED
File without changes
|
lib/options/options/{converter-options → conversion-options/converter-options}/imagick.php
RENAMED
File without changes
|
lib/options/options/{converter-options → conversion-options/converter-options}/imagickbinary.php
RENAMED
File without changes
|
lib/options/options/{converter-options → conversion-options/converter-options}/wpc.php
RENAMED
File without changes
|
lib/options/options/{converters.inc → conversion-options/converters.inc}
RENAMED
File without changes
|
lib/options/options/conversion-options/destination-extension.inc
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Image types
|
3 |
+
// ------------
|
4 |
+
echo '<tr id="destination_extension_row"><th scope="row">File extension';
|
5 |
+
echo helpIcon('<p>Controls the filename of the converted file.</p><p>The "Append" option result in file names such as "image.png.webp". The "Set" option results in file names such as "image.webp". Note that if you choose "Set", it will be a problem if you ie both have a logo.jpg and a logo.png in the same folder. If you are using WebP Express together with <a target="blank" href="https://da.wordpress.org/plugins/cache-enabler/">Cache enabler</a> or <a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a>, set this option to Set"</p><p>Changing this option will cause existing webp images to be renamed (only those in the upload folder, and only those that has a corresponding source image)</p>');
|
6 |
+
echo '</th><td>';
|
7 |
+
|
8 |
+
$destinationExtension = $config['destination-extension'];
|
9 |
+
|
10 |
+
echo '<select name="destination-extension">';
|
11 |
+
echo '<option value="append"' . ($destinationExtension == 'append' ? ' selected' : '') . '>Append ".webp"</option>';
|
12 |
+
echo '<option value="set"' . ($destinationExtension == 'set' ? ' selected' : '') . '>Set to ".webp"</option>';
|
13 |
+
echo '</select>';
|
14 |
+
|
15 |
+
echo '</td></tr>';
|
lib/options/options/conversion-options/destination-folder.inc
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Image types
|
3 |
+
// ------------
|
4 |
+
echo '<tr><th scope="row">Destination folder';
|
5 |
+
echo helpIcon('<p>If "In separate folder" is selected, the webp images will be saved to a common root (wp-content/webp-express/webp-images/doc-root), mirroring the folder structure. If on the other hand, "Mingled" is selected, the converter will try to save the webp image in the same folder as the original. If that fails (ie for theme or plugin images), the image will be saved in the separate folder. If you are using WebP Express together with <a target="blank" href="https://da.wordpress.org/plugins/cache-enabler/">Cache enabler</a> or <a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a>, set this option to "mingled"</p><p>Changing this option will cause existing webp images to be moved (only those in the upload folder, and only those that has a corresponding source image)</p>');
|
6 |
+
echo '</th><td>';
|
7 |
+
|
8 |
+
$destinationFolder = $config['destination-folder'];
|
9 |
+
|
10 |
+
echo '<select name="destination-folder" id="destination_folder">';
|
11 |
+
echo '<option value="separate"' . ($destinationFolder == 'separate' ? ' selected' : '') . '>In separate folder</option>';
|
12 |
+
echo '<option value="mingled"' . ($destinationFolder == 'mingled' ? ' selected' : '') . '>Mingled</option>';
|
13 |
+
echo '</select>';
|
14 |
+
|
15 |
+
echo '</td></tr>';
|
lib/options/options/{metadata.inc → conversion-options/metadata.inc}
RENAMED
File without changes
|
lib/options/options/{quality.inc → conversion-options/quality.inc}
RENAMED
File without changes
|
lib/options/options/do-not-pass-source-path-in-query-string.inc
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
echo '<tr><th scope="row"><span style="color:darkorange">Beta:</span> Do not pass source in Query String';
|
3 |
-
echo helpIcon('In v0.8 and below, the .htaccess always passed the filename of the image to the script through the query string. It however seems that the PHP can determine the original file name in a server variable, and therefore does not need it in the query string. Removing it has the benefit of reducing risk of firewalls blocking the request. This option will probably go away in the next release, when it is confirmed that the feature is stable. So you better test if it works now, thanks!');
|
4 |
-
echo '</th><td>';
|
5 |
-
echo '<input type="checkbox" id="do_not_pass_source_in_query_string" name="do-not-pass-source-in-query-string" value="true" ' . ($config['do-not-pass-source-in-query-string'] ? 'checked="checked"' : '') . '">';
|
6 |
-
echo '</td></tr>';
|
|
|
|
|
|
|
|
|
|
|
|
lib/options/options/image-types.inc
DELETED
@@ -1,22 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
// Image types
|
3 |
-
// ------------
|
4 |
-
echo '<tr><th scope="row">Image types to send to the converter';
|
5 |
-
echo helpIcon('Beware that the Gd conversion method cannot handle transparency for PNGs. PNG conversions havent been tested much yet. Please report any problems with PNG images <a target="_blank" href="https://github.com/rosell-dk/webp-convert/issues/42">here</a>');
|
6 |
-
echo '</th><td>';
|
7 |
-
|
8 |
-
// bitmask
|
9 |
-
// 1: JPEGs
|
10 |
-
// 2: PNG's
|
11 |
-
// Converting only jpegs is thus "1"
|
12 |
-
// Converting both jpegs and pngs is (1+2) = 3
|
13 |
-
//$imageTypes = get_option('webp_express_image_types_to_convert');
|
14 |
-
$imageTypes = $config['image-types'];
|
15 |
-
|
16 |
-
echo '<select name="image-types">';
|
17 |
-
echo '<option value="0"' . ($imageTypes == 0 ? ' selected' : '') . '>Do not convert any images!</option>';
|
18 |
-
echo '<option value="1"' . ($imageTypes == 1 ? ' selected' : '') . '>Only convert jpegs</option>';
|
19 |
-
echo '<option value="3"' . ($imageTypes == 3 ? ' selected' : '') . '>Convert both jpegs and pngs</option>';
|
20 |
-
echo '</select>';
|
21 |
-
|
22 |
-
echo '</td></tr>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/options/options/operation-mode.inc
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$operationMode = $config['operation-mode'];
|
3 |
+
?>
|
4 |
+
<fieldset class="block">
|
5 |
+
<h3>Operation mode: <?php echo helpIcon('<p>Think of the operation modes as presets that matches normal use-cases. Usually you want to stick with <i>Standard</i> or perhaps <i>Just convert</i>. The Tweaked mode has no presets. That is: Here, you can set all options.</p><p>Changing from ie. "Standard" mode to "Tweaked" mode enables you to see the underlying options for that mode (and tweak them). Changing back will override the tweaks (you will lose them).</p><p>You will never loose your converter configurations by changing mode</p>');?>
|
6 |
+
<input type="hidden" name="operation-mode" id="operation_mode" value="<?php echo $operationMode ?>">
|
7 |
+
<select name="change-operation-mode" id="change_operation_mode">
|
8 |
+
<option value="standard"<?php if ($operationMode == 'standard') echo ' selected'?>>Standard</option>
|
9 |
+
<option value="just-convert"<?php if ($operationMode == 'just-convert') echo ' selected'?>>Just convert</option>
|
10 |
+
<option value="just-redirect"<?php if ($operationMode == 'just-redirect') echo ' selected'?>>Just redirect</option>
|
11 |
+
<option value="tweaked"<?php if ($operationMode == 'tweaked') echo ' selected'?>>Tweaked</option>
|
12 |
+
</select></h3>
|
13 |
+
|
14 |
+
<?php if ($config['operation-mode'] == 'standard') : ?>
|
15 |
+
<p><div>
|
16 |
+
<i>In standard mode, WebP Express takes care of serving autogenerated WebP images instead of jpeg/png to browsers that supports WebP.</i>
|
17 |
+
<div class="help">?<div class="popup">
|
18 |
+
<i>WebP Express serves webp to browsers that supports it by redirecting
|
19 |
+
the original image request (internally on server, it is not a 301 redirect).
|
20 |
+
If no webp is yet generated, the request will be redirected to the image converter
|
21 |
+
which generates the webp. On subsequent requests, the image is redirected (again, internally) directly
|
22 |
+
to the webp, by means of a rule in the .htaccess.</i>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div></p>
|
26 |
+
<?php endif; ?>
|
27 |
+
<?php if ($config['operation-mode'] == 'just-convert') : ?>
|
28 |
+
<p><div>
|
29 |
+
<i>In "just convert" mode, WebP Express is used just for converting.<br>
|
30 |
+
Combined with a plugin that can alter HTML for webp-use (ie <a target="_blank" href="https://da.wordpress.org/plugins/cache-enabler/">Cache Enabler</a> or <a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a>), the redirection trick can be avoided.</i>
|
31 |
+
<div class="help">?<div class="popup">
|
32 |
+
<p>
|
33 |
+
Benefits of avoiding the redirection trick:
|
34 |
+
<ol>
|
35 |
+
<li>CDN's will not have to be set up to forward the Accept header</li>
|
36 |
+
<li>If a user downloads an image, it will not have wrong file extension</li>
|
37 |
+
</ol>
|
38 |
+
PS: Instructions for using WebPExpress with Cache Enabler and Shortpixel are found in the FAQ
|
39 |
+
</p>
|
40 |
+
<p>
|
41 |
+
PPS: Images refererenced from CSS or added dynamically with javascript will not be served as webp in this mode.
|
42 |
+
</p>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
<br><br>
|
46 |
+
<i>An auto-convert option is available!</i>
|
47 |
+
<div class="help">?<div class="popup">
|
48 |
+
<em>The auto-convertion works this way: When an image is requested, a rule in the .htaccess detects if
|
49 |
+
that image has been converted. If not, the request is redirected to the converter, which creates the
|
50 |
+
webp and returns <em>the original</em> image</em>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
+
</div></p>
|
54 |
+
<?php endif; ?>
|
55 |
+
<?php if ($config['operation-mode'] == 'just-redirect') : ?>
|
56 |
+
<p>
|
57 |
+
<div>
|
58 |
+
<i>In "just redirect" mode, WebP Express is used just for redirecting jpeg and pngs to existing webp images in the same folder.<br>
|
59 |
+
This mode can for example be used in combination with Optimus HQ.</i>
|
60 |
+
</div>
|
61 |
+
</p>
|
62 |
+
<?php endif; ?>
|
63 |
+
</fieldset>
|
64 |
+
<!--
|
65 |
+
<p><div>
|
66 |
+
<i>WebP Express takes care of serving autogenerated WebP images instead of jpeg/png to browsers that supports WebP.</i>
|
67 |
+
<div class="help">?<div class="popup"><ol>
|
68 |
+
<li>Some redirect rules set up in <i>.htaccess</i> redirects (unconverted) jpeg/png images to a PHP script for handling.</li>
|
69 |
+
<li>The PHP script reads the options and passes them to the <i><a target="_blank" href="https://github.com/rosell-dk/webp-convert/">WebP Convert</a></i> library for converting <i>and</i> serving.</li>
|
70 |
+
<li>If WebP Convert finds that the image already is converted, it will be served immediately (unless it is bigger than the original, or the original has been modified). Otherwise it will be converted and then served</li>
|
71 |
+
</ol></div></div>
|
72 |
+
</div></p>
|
73 |
+
-->
|
lib/options/options/redirect-to-existing.inc
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
// Redirect to existing with .htaccess
|
3 |
-
// --------------------------------
|
4 |
-
echo '<tr><th scope="row"><span style="color:darkorange">Beta:</span> Redirect directly to converted image when available';
|
5 |
-
echo helpIcon('This will add rules in the .htaccess that redirects directly to existing converted files. If you do not activate this setting, it will be the PHP script that handles the redirection to existing webp files. Best performance is achieved by redirecting in .htaccess, however the feature is new and has not been tested widely. Please try it out, and report any problems in the forum, thanks :)<br>Beware that there is currently no hooks for regenerating converted images when source image is edited.');
|
6 |
-
echo '</th><td>';
|
7 |
-
echo '<input type="checkbox" id="redirect_to_existing_in_htaccess" name="redirect-to-existing-in-htaccess" value="true" ' . ($config['redirect-to-existing-in-htaccess'] ? 'checked="checked"' : '') . '">';
|
8 |
-
echo '</td></tr>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/options/options/redirection-rules/add-vary-header-in-htaccess.inc
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!--
|
2 |
+
We do not need this setting currently.
|
3 |
+
We will rather let this be decided by the success-response option
|
4 |
+
<tr>
|
5 |
+
<th scope="row">
|
6 |
+
Add Vary:Accept Header for the images <?php echo helpIcon('The Vary:Accept header tells browsers (and CDNs) that the response depends on the Accept header (which is the header that browsers use to indicate that they accept webp images). Usually you should leave this on. But if you are using the Cache Enabler plugin, check it off. '); ?>
|
7 |
+
</th>
|
8 |
+
<td>
|
9 |
+
<input type="checkbox" id="add_vary_header_in_htaccess" name="add-vary-header-in-htaccess" value="true" <?php echo ($config['add-vary-header-in-htaccess'] ? 'checked="checked"' : '') ?> >
|
10 |
+
</td>
|
11 |
+
</tr>
|
12 |
+
-->
|
lib/options/options/redirection-rules/do-not-pass-source-path-in-query-string.inc
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo '<tr><th scope="row">Do not pass source in Query String';
|
3 |
+
echo helpIcon('You can try unchecking this, if you are experiencing that no images are converted. In v0.8 and below, the <i>.htaccess</i> always passed the filename of the image to the script through the query string. It however seems that passing through an environment variable instead works just fine. As passing it through the query string can cause some firewalls to block the request, we no longer do this per default.');
|
4 |
+
echo '</th><td>';
|
5 |
+
echo '<input type="checkbox" id="do_not_pass_source_in_query_string" name="do-not-pass-source-in-query-string" value="true" ' . ($config['do-not-pass-source-in-query-string'] ? 'checked="checked"' : '') . '">';
|
6 |
+
echo '</td></tr>';
|
lib/options/options/redirection-rules/enable-redirection-to-converter.inc
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">
|
3 |
+
<?php if ($config['operation-mode'] == 'just-convert'): ?>
|
4 |
+
Auto convert <?php echo helpIcon('<p><em>The auto-convertion works this way: When an image is requested, a rule in the .htaccess detects if that image has been converted. If not, the request is redirected to the converter, which creates the webp and returns <em>the original</em> image</em></p>'); ?>
|
5 |
+
<?php else: ?>
|
6 |
+
Enable redirection to converter?<?php echo helpIcon('This will add rules in the .htaccess that redirects to converter'); ?>
|
7 |
+
<?php endif; ?>
|
8 |
+
</th>
|
9 |
+
<td>
|
10 |
+
<input
|
11 |
+
id="enable_redirection_to_converter"
|
12 |
+
name="enable-redirection-to-converter"
|
13 |
+
<?php echo ($config['enable-redirection-to-converter'] ? 'checked="checked"' : '') ?>
|
14 |
+
value="true"
|
15 |
+
type="checkbox"
|
16 |
+
>
|
17 |
+
</td>
|
18 |
+
</tr>
|
lib/options/options/redirection-rules/image-types.inc
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Image types
|
3 |
+
// ------------
|
4 |
+
echo '<tr><th scope="row">';
|
5 |
+
switch ($config['operation-mode']) {
|
6 |
+
case 'standard':
|
7 |
+
echo 'Image types to work on';
|
8 |
+
break;
|
9 |
+
case 'just-convert':
|
10 |
+
echo 'Image types to convert';
|
11 |
+
break;
|
12 |
+
case 'just-redirect':
|
13 |
+
echo 'Image types to redirect';
|
14 |
+
break;
|
15 |
+
case 'tweaked':
|
16 |
+
echo 'Image types to send to the converter';
|
17 |
+
break;
|
18 |
+
}
|
19 |
+
echo helpIcon('<p>Beware that the Gd conversion method cannot handle transparency for PNGs. PNG conversions havent been tested much yet. Please report any problems with PNG images <a target="_blank" href="https://github.com/rosell-dk/webp-convert/issues/42">here</a></p><p>The term "send" means an internal redirect on the server (not to be confused with an external redirect, such as a 301 or 302 response)</p>');
|
20 |
+
echo '</th><td>';
|
21 |
+
|
22 |
+
// bitmask
|
23 |
+
// 1: JPEGs
|
24 |
+
// 2: PNG's
|
25 |
+
// Converting only jpegs is thus "1"
|
26 |
+
// Converting both jpegs and pngs is (1+2) = 3
|
27 |
+
//$imageTypes = get_option('webp_express_image_types_to_convert');
|
28 |
+
$imageTypes = $config['image-types'];
|
29 |
+
|
30 |
+
echo '<select name="image-types">';
|
31 |
+
echo '<option value="0"' . ($imageTypes == 0 ? ' selected' : '') . '>None! (disable)</option>';
|
32 |
+
echo '<option value="1"' . ($imageTypes == 1 ? ' selected' : '') . '>Only jpegs</option>';
|
33 |
+
echo '<option value="3"' . ($imageTypes == 3 ? ' selected' : '') . '>Both jpegs and pngs</option>';
|
34 |
+
echo '</select>';
|
35 |
+
|
36 |
+
echo '</td></tr>';
|
lib/options/options/redirection-rules/only-redirect-to-converter-for-webp-enabled-browsers.inc
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">
|
3 |
+
Only redirect to converter for webp-enabled browsers?<?php echo helpIcon('If checked, a condition is added to the .htaccess, that the <i>Accept</i> header contains "image/webp"'); ?>
|
4 |
+
</th>
|
5 |
+
<td>
|
6 |
+
<input
|
7 |
+
name="only-redirect-to-converter-for-webp-enabled-browsers"
|
8 |
+
<?php echo ($config['only-redirect-to-converter-for-webp-enabled-browsers'] ? 'checked="checked"' : '') ?>
|
9 |
+
value="true"
|
10 |
+
type="checkbox"
|
11 |
+
>
|
12 |
+
</td>
|
13 |
+
</tr>
|
lib/options/options/redirection-rules/only-redirect-to-converter-on-cache-miss.inc
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">
|
3 |
+
Only redirect to converter if no webp is found in cache <?php echo helpIcon('This will add a condition to the RewriteRule that redirects to the converter. Useful if you use WebP Express together with the Cache Enabler plugin.'); ?>
|
4 |
+
</th>
|
5 |
+
<td>
|
6 |
+
<input type="checkbox" name="only-redirect-to-converter-on-cache-miss" value="true" <?php echo ($config['only-redirect-to-converter-on-cache-miss'] ? 'checked="checked"' : '') ?> >
|
7 |
+
</td>
|
8 |
+
</tr>
|
lib/options/options/redirection-rules/redirect-to-existing.inc
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">
|
3 |
+
Redirect directly to converted image when available<?php
|
4 |
+
echo helpIcon('This will add rules in the .htaccess that redirects directly to existing converted files. ' .
|
5 |
+
'If you do not activate this setting, it will be the PHP script that handles the redirection to existing ' .
|
6 |
+
'webp files. Best performance is achieved by redirecting in .htaccess'); ?>
|
7 |
+
</th>
|
8 |
+
<td>
|
9 |
+
<input type="checkbox" id="redirect_to_existing_in_htaccess" name="redirect-to-existing-in-htaccess" value="true" <?php echo ($config['redirect-to-existing-in-htaccess'] ? 'checked="checked"' : '') ?> >
|
10 |
+
</td>
|
11 |
+
</tr>
|
lib/options/options/redirection-rules/redirection-rules.inc
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ($config['operation-mode'] == 'tweaked') : ?>
|
2 |
+
<fieldset class="block">
|
3 |
+
<h3>Redirection rules</h3>
|
4 |
+
<div><i>The options here affects the rules created in the .htaccess. <?php echo helpIcon('And so does some other options. If "Redirect directly to converted image" is set, the "Destination folder" and "File Extension" and "Caching" options will be used'); ?></i></div>
|
5 |
+
<table class="form-table">
|
6 |
+
<tbody>
|
7 |
+
<?php
|
8 |
+
include_once 'enable-redirection-to-converter.inc';
|
9 |
+
include_once 'only-redirect-to-converter-for-webp-enabled-browsers.inc';
|
10 |
+
include_once 'image-types.inc';
|
11 |
+
include_once 'do-not-pass-source-path-in-query-string.inc';
|
12 |
+
include_once 'only-redirect-to-converter-on-cache-miss.inc';
|
13 |
+
include_once 'redirect-to-existing.inc';
|
14 |
+
?>
|
15 |
+
</tbody>
|
16 |
+
</table>
|
17 |
+
</fieldset>
|
18 |
+
<?php
|
19 |
+
else:
|
20 |
+
if ($config['operation-mode'] == 'just-convert') {
|
21 |
+
// ps: we call it "auto convert", when in this mode
|
22 |
+
// PPS: we include it directly in page.php now.
|
23 |
+
//include_once 'enable-redirection-to-converter.inc';
|
24 |
+
|
25 |
+
//include_once 'only-redirect-to-converter-on-cache-miss.inc';
|
26 |
+
|
27 |
+
}
|
28 |
+
if ($config['operation-mode'] == 'standard') {
|
29 |
+
include_once 'redirect-to-existing.inc';
|
30 |
+
}
|
31 |
+
include_once 'image-types.inc';
|
32 |
+
endif;
|
33 |
+
?>
|
lib/options/options/serve-options/cache-control.inc
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//$maxQuality = get_option('webp_express_max_quality');
|
4 |
+
$cacheControl = $config['cache-control'];
|
5 |
+
$cacheControlCustom = $config['cache-control-custom'];
|
6 |
+
$cacheControlMaxAge = $config['cache-control-max-age'];
|
7 |
+
$cacheControlPublic = $config['cache-control-public'];
|
8 |
+
?>
|
9 |
+
|
10 |
+
<tr>
|
11 |
+
<th scope="row">Cache-Control header <?php echo helpIcon(
|
12 |
+
'<p>Controls the cache-control header on successful conversion and direct redirection to converted ' .
|
13 |
+
'image in .htaccess. In case of convert failure, headers will be sent to prevent caching.</p>' .
|
14 |
+
'<p>PS: In order to set <i>stale-while-revalidate</i> and <i>stale-if-error directives<i>, you must ' .
|
15 |
+
'currently choose "Custom". <a target="_blank" href="https://www.fastly.com/blog/stale-while-revalidate-stale-if-error-available-today">It is a good idea to set these</a>.' .
|
16 |
+
'</p>');
|
17 |
+
?>
|
18 |
+
</th>
|
19 |
+
<td>
|
20 |
+
<select id="cache_control_select" name="cache-control">
|
21 |
+
<option value="no-header" <?php if ($cacheControl == 'no-header') echo ' selected' ?>>Do not set</option>
|
22 |
+
<option value="set" <?php if ($cacheControl == 'set') echo ' selected' ?>>Set</option>
|
23 |
+
<option value="custom" <?php if ($cacheControl == 'custom') echo ' selected' ?>>Custom</option>
|
24 |
+
<?php
|
25 |
+
/*
|
26 |
+
echo '<option value="no-header"' . ($cacheControl == 'no-header' ? ' selected' : '') . '>Do not set Cache-Control header</option>';
|
27 |
+
echo '<option value="one-second"' . ($cacheControl == 'one-second' ? ' selected' : '') . '>One second</option>';
|
28 |
+
echo '<option value="one-minute"' . ($cacheControl == 'one-minute' ? ' selected' : '') . '>One minute</option>';
|
29 |
+
echo '<option value="one-hour"' . ($cacheControl == 'one-hour' ? ' selected' : '') . '>One hour</option>';
|
30 |
+
echo '<option value="one-day"' . ($cacheControl == 'one-day' ? ' selected' : '') . '>One day</option>';
|
31 |
+
echo '<option value="one-week"' . ($cacheControl == 'one-week' ? ' selected' : '') . '>One week</option>';
|
32 |
+
echo '<option value="one-month"' . ($cacheControl == 'one-month' ? ' selected' : '') . '>One month</option>';
|
33 |
+
echo '<option value="one-year"' . ($cacheControl == 'one-year' ? ' selected' : '') . '>One year</option>';
|
34 |
+
echo '<option value="custom"' . ($cacheControl == 'custom' ? ' selected' : '') . '>Custom Cache-Control header</option>';
|
35 |
+
*/
|
36 |
+
?>
|
37 |
+
</select>
|
38 |
+
<div id="cache_control_custom_div" style="display:inline-block;">
|
39 |
+
<input type="text" id="cache_control_custom" name="cache-control-custom" value="<?php echo $cacheControlCustom ?>">
|
40 |
+
<?php echo helpIcon(
|
41 |
+
'You can read about possible options ' .
|
42 |
+
'<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control">here</a>',
|
43 |
+
'no-margin-left'
|
44 |
+
);?>
|
45 |
+
</div>
|
46 |
+
|
47 |
+
<div id="cache_control_set_div" style="display:inline-block;">
|
48 |
+
<select id="cache_control_public" name="cache-control-public">
|
49 |
+
<?php
|
50 |
+
webpexpress_selectBoxOptions(($cacheControlPublic ? 'public' : 'private'), [
|
51 |
+
'public' => 'Public',
|
52 |
+
'private' => 'Private',
|
53 |
+
]);
|
54 |
+
?>
|
55 |
+
</select>
|
56 |
+
<?php echo helpIcon(
|
57 |
+
'<p>Set either the "public" or "private" directive. Setting this to public means that you are allow caching in shared caches. ' .
|
58 |
+
'Only do this, if you are sure your CDN or reverse proxy can handle that the ' .
|
59 |
+
'response varies depending on the Accept header.</p>' .
|
60 |
+
'<p>Note: I am not completely sure that all forward proxies handles varied responses. ' .
|
61 |
+
'This is discussed <a target="_blank" href="https://github.com/rosell-dk/webp-express/issues/144">here</a>.</p>'
|
62 |
+
,
|
63 |
+
'no-margin-left set-margin-right'
|
64 |
+
);
|
65 |
+
?>
|
66 |
+
</select>
|
67 |
+
<select id="cache_control_max_age" name="cache-control-max-age">
|
68 |
+
<?php
|
69 |
+
webpexpress_selectBoxOptions($cacheControlMaxAge, [
|
70 |
+
'one-second' => 'One second',
|
71 |
+
'one-minute' => 'One minute',
|
72 |
+
'one-hour' => 'One hour',
|
73 |
+
'one-day' => 'One day',
|
74 |
+
'one-week' => 'One week',
|
75 |
+
'one-month' => 'One month',
|
76 |
+
'one-year' => 'One year',
|
77 |
+
]);
|
78 |
+
?>
|
79 |
+
</select>
|
80 |
+
<?php echo helpIcon(
|
81 |
+
'This sets the max-age value. If want to set s-maxage, or generally need more control, ' .
|
82 |
+
'choose "custom" in the first combobox (You can read about possible options ' .
|
83 |
+
'<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control">here</a>)',
|
84 |
+
'no-margin-left'
|
85 |
+
);?>
|
86 |
+
</div>
|
87 |
+
<br>
|
88 |
+
<!--
|
89 |
+
<table>
|
90 |
+
<tbody>
|
91 |
+
<tr>
|
92 |
+
<td style="font-weight: bold; margin:0; padding:0">max-age</td>
|
93 |
+
<td>
|
94 |
+
</td>
|
95 |
+
</tr>
|
96 |
+
<tr>
|
97 |
+
<th scope="row">
|
98 |
+
Allow caching in shared caches (ie CDNs or reverse proxies)
|
99 |
+
<?php echo helpIcon(''); ?>
|
100 |
+
</th>
|
101 |
+
<td>
|
102 |
+
<input
|
103 |
+
name="cache-control-public"
|
104 |
+
<?php echo ($config['cache-control-public'] ? 'checked="checked"' : '') ?>
|
105 |
+
value="true"
|
106 |
+
type="checkbox"
|
107 |
+
>
|
108 |
+
</td>
|
109 |
+
</tr>
|
110 |
+
</tbody>
|
111 |
+
</table>
|
112 |
+
-->
|
113 |
+
|
114 |
+
</td>
|
115 |
+
</tr>
|
lib/options/options/{response-on-failure.inc → serve-options/response-on-failure.inc}
RENAMED
File without changes
|
lib/options/options/serve-options/response-on-success.inc
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo '<tr><th scope="row">Response on success';
|
3 |
+
echo helpIcon('<p>Determines what to serve when conversion is a success. If you are using the Cache Enabler plugin, set to "Original image", otherwise you would normally set it to "Converted image".</p><p>If set to "Converted image", a Vary:Accept header will be sent to indicate that the response depends on the Accept header (which indicates if a browser supports webp images or not)</p><p>If set to "Original image", make sure to disable the "Redirect directly to converted image when available" option in the Redirect rules</p>');
|
4 |
+
echo '</th><td>';
|
5 |
+
|
6 |
+
//$successResponse = get_option('webp_express_failure_response');
|
7 |
+
$successResponse = $config['success-response'];
|
8 |
+
echo '<select name="success-response">';
|
9 |
+
echo '<option value="original"' . ($successResponse == 'original' ? ' selected' : '') . '>Original image</option>';
|
10 |
+
echo '<option value="converted"' . ($successResponse == 'converted' ? ' selected' : '') . '>Converted image</option>';
|
11 |
+
echo '</select>';
|
12 |
+
echo '</td></tr>';
|
lib/options/options/serve-options/serve-options.inc
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ($config['operation-mode'] == 'tweaked') : ?>
|
2 |
+
<fieldset class="block">
|
3 |
+
<h3>Serve options</h3>
|
4 |
+
<p><i>The options here affects how the image is served after a successful / unsuccessful conversion</i></p>
|
5 |
+
<table class="form-table">
|
6 |
+
<tbody>
|
7 |
+
<?php
|
8 |
+
include_once 'cache-control.inc';
|
9 |
+
include_once 'response-on-failure.inc';
|
10 |
+
include_once 'response-on-success.inc';
|
11 |
+
?>
|
12 |
+
</tbody>
|
13 |
+
</table>
|
14 |
+
</fieldset>
|
15 |
+
<?php
|
16 |
+
else:
|
17 |
+
if ($config['operation-mode'] != 'just-convert') {
|
18 |
+
include_once 'cache-control.inc';
|
19 |
+
}
|
20 |
+
endif;
|
21 |
+
?>
|
lib/options/options/web-service-options/web-service-options.inc
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ($config['operation-mode'] == 'tweaked') : ?>
|
2 |
+
<fieldset class="block">
|
3 |
+
<h3>Web service</h3>
|
4 |
+
<table class="form-table">
|
5 |
+
<tbody>
|
6 |
+
<?php
|
7 |
+
include_once 'web-service.inc';
|
8 |
+
?>
|
9 |
+
</tbody>
|
10 |
+
</table>
|
11 |
+
</fieldset>
|
12 |
+
<?php
|
13 |
+
else:
|
14 |
+
include_once 'web-service.inc';
|
15 |
+
endif;
|
16 |
+
?>
|
lib/options/options/{web-service.inc → web-service-options/web-service.inc}
RENAMED
@@ -1,5 +1,5 @@
|
|
1 |
<?php
|
2 |
-
include_once __DIR__ . '
|
3 |
use \WebPExpress\Paths;
|
4 |
|
5 |
//$whitelist = $config['web-service']['whitelist'];
|
1 |
<?php
|
2 |
+
include_once __DIR__ . '/../../../classes/Paths.php';
|
3 |
use \WebPExpress\Paths;
|
4 |
|
5 |
//$whitelist = $config['web-service']['whitelist'];
|
lib/options/page-messages.php
CHANGED
@@ -40,7 +40,7 @@ if (!Paths::createContentDirIfMissing()) {
|
|
40 |
Messenger::printMessage(
|
41 |
'error',
|
42 |
'WebP Express needs to create a directory "webp-express" under your wp-content folder, but does not have permission to do so.<br>' .
|
43 |
-
'Please create the folder manually, or change the file permissions of your wp-content folder.'
|
44 |
);
|
45 |
} else {
|
46 |
if (!Paths::createConfigDirIfMissing()) {
|
40 |
Messenger::printMessage(
|
41 |
'error',
|
42 |
'WebP Express needs to create a directory "webp-express" under your wp-content folder, but does not have permission to do so.<br>' .
|
43 |
+
'Please create the folder manually, or change the file permissions of your wp-content folder (failed to create this folder: ' . Paths::getContentDirAbs() . ')'
|
44 |
);
|
45 |
} else {
|
46 |
if (!Paths::createConfigDirIfMissing()) {
|
lib/options/page.php
CHANGED
@@ -75,7 +75,7 @@ if (!$testResult) {
|
|
75 |
'error',
|
76 |
'WebP Express cannot save a test conversion, because it does not have write ' .
|
77 |
'access to your upload folder, nor your wp-content folder. Please provide!'
|
78 |
-
);
|
79 |
}
|
80 |
|
81 |
|
@@ -94,19 +94,9 @@ foreach (Paths::getHTAccessDirs() as $dir) {
|
|
94 |
// Generate a custom nonce value.
|
95 |
$webpexpress_settings_nonce = wp_create_nonce('webpexpress_settings_nonce');
|
96 |
?>
|
97 |
-
<p><div>
|
98 |
-
<i>WebP Express takes care of serving autogenerated WebP images instead of jpeg/png to browsers that supports WebP.</i>
|
99 |
-
<div class="help">?<div class="popup"><ol>
|
100 |
-
<li>Some redirect rules set up in <i>.htaccess</i> redirects (unconverted) jpeg/png images to a PHP script for handling.</li>
|
101 |
-
<li>The PHP script reads the options and passes them to the <i><a target="_blank" href="https://github.com/rosell-dk/webp-convert/">WebP Convert</a></i> library for converting <i>and</i> serving.</li>
|
102 |
-
<li>If WebP Convert finds that the image already is converted, it will be served immediately (unless it is bigger than the original, or the original has been modified). Otherwise it will be converted and then served</li>
|
103 |
-
</ol></div></div>
|
104 |
-
</div></p>
|
105 |
|
106 |
<?php
|
107 |
|
108 |
-
|
109 |
-
|
110 |
echo '<form id="webpexpress_settings" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" method="post" >';
|
111 |
?>
|
112 |
<input type="hidden" name="action" value="webpexpress_settings_submit">
|
@@ -121,64 +111,59 @@ echo '<form id="webpexpress_settings" action="' . esc_url( admin_url( 'admin-pos
|
|
121 |
</table>
|
122 |
</fieldset>
|
123 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
-
function
|
126 |
-
|
|
|
|
|
|
|
|
|
127 |
}
|
128 |
-
?>
|
129 |
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
<fieldset class="block">
|
135 |
-
<h3>Redirection rules</h3>
|
136 |
-
<p><i>The options here affects the rules created in the .htaccess.</i></p>
|
137 |
-
<table class="form-table">
|
138 |
-
<tbody>
|
139 |
-
<?php
|
140 |
-
include_once 'options/image-types.inc';
|
141 |
-
include_once 'options/redirect-to-existing.inc';
|
142 |
-
include_once 'options/do-not-pass-source-path-in-query-string.inc';
|
143 |
-
?>
|
144 |
-
</tbody>
|
145 |
-
</table>
|
146 |
-
</fieldset>
|
147 |
-
<fieldset class="block">
|
148 |
-
<h3>Conversion options</h3>
|
149 |
-
<p><i>The options here affects the conversion process</i></p>
|
150 |
-
<table class="form-table">
|
151 |
-
<tbody>
|
152 |
-
<?php
|
153 |
-
include_once 'options/quality.inc';
|
154 |
-
include_once 'options/metadata.inc';
|
155 |
-
include_once 'options/converters.inc';
|
156 |
-
?>
|
157 |
-
</tbody>
|
158 |
-
</table>
|
159 |
-
</fieldset>
|
160 |
-
<fieldset class="block">
|
161 |
-
<h3>Serve options</h3>
|
162 |
-
<p><i>The options here affects how the image is served after a successful / unsuccessful conversion</i></p>
|
163 |
-
<table class="form-table">
|
164 |
-
<tbody>
|
165 |
-
<?php
|
166 |
-
include_once 'options/cache-control.inc';
|
167 |
-
include_once 'options/response-on-failure.inc';
|
168 |
-
?>
|
169 |
-
</tbody>
|
170 |
-
</table>
|
171 |
-
</fieldset>
|
172 |
-
<fieldset class="block">
|
173 |
-
<h3>Web service</h3>
|
174 |
-
<table class="form-table">
|
175 |
-
<tbody>
|
176 |
-
<?php
|
177 |
-
include_once 'options/web-service.inc';
|
178 |
-
?>
|
179 |
-
</tbody>
|
180 |
-
</table>
|
181 |
-
</fieldset>
|
182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
</form>
|
184 |
</div>
|
75 |
'error',
|
76 |
'WebP Express cannot save a test conversion, because it does not have write ' .
|
77 |
'access to your upload folder, nor your wp-content folder. Please provide!'
|
78 |
+
);
|
79 |
}
|
80 |
|
81 |
|
94 |
// Generate a custom nonce value.
|
95 |
$webpexpress_settings_nonce = wp_create_nonce('webpexpress_settings_nonce');
|
96 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
<?php
|
99 |
|
|
|
|
|
100 |
echo '<form id="webpexpress_settings" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" method="post" >';
|
101 |
?>
|
102 |
<input type="hidden" name="action" value="webpexpress_settings_submit">
|
111 |
</table>
|
112 |
</fieldset>
|
113 |
<?php
|
114 |
+
function helpIcon($text, $customClass = '') {
|
115 |
+
$className = '';
|
116 |
+
if (strlen($text) < 80) {
|
117 |
+
$className = 'narrow';
|
118 |
+
}
|
119 |
+
if (strlen($text) > 150) {
|
120 |
+
if (strlen($text) > 300) {
|
121 |
+
$className = 'wider';
|
122 |
+
} else {
|
123 |
+
$className = 'wide';
|
124 |
+
}
|
125 |
+
}
|
126 |
+
return '<div class="help ' . $customClass . '">?<div class="popup ' . $className . '">' . $text . '</div></div>';
|
127 |
+
}
|
128 |
|
129 |
+
function webpexpress_selectBoxOptions($selected, $options) {
|
130 |
+
foreach ($options as $optionValue => $text) {
|
131 |
+
echo '<option value="' . $optionValue . '"' . ($optionValue == $selected ? ' selected' : '') . '>';
|
132 |
+
echo $text;
|
133 |
+
echo '</option>';
|
134 |
+
}
|
135 |
}
|
|
|
136 |
|
137 |
+
include_once 'options/operation-mode.inc';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
139 |
+
if ($config['operation-mode'] != 'tweaked') {
|
140 |
+
echo '<fieldset class="block">';
|
141 |
+
echo '<table class="form-table"><tbody>';
|
142 |
+
}
|
143 |
+
|
144 |
+
include_once 'options/redirection-rules/redirection-rules.inc';
|
145 |
+
if ($config['operation-mode'] != 'just-redirect') {
|
146 |
+
include_once 'options/conversion-options/conversion-options.inc';
|
147 |
+
}
|
148 |
+
if ($config['operation-mode'] == 'just-redirect') {
|
149 |
+
include_once 'options/conversion-options/destination-extension.inc';
|
150 |
+
}
|
151 |
+
include_once 'options/serve-options/serve-options.inc';
|
152 |
+
|
153 |
+
if ($config['operation-mode'] == 'just-convert') {
|
154 |
+
// ps: we call it "auto convert", when in this mode
|
155 |
+
include_once 'options/redirection-rules/enable-redirection-to-converter.inc';
|
156 |
+
}
|
157 |
+
|
158 |
+
if ($config['operation-mode'] != 'just-redirect') {
|
159 |
+
include_once 'options/web-service-options/web-service-options.inc';
|
160 |
+
}
|
161 |
+
|
162 |
+
if ($config['operation-mode'] != 'tweaked') {
|
163 |
+
echo '</tbody></table>';
|
164 |
+
echo '</fieldset>';
|
165 |
+
}
|
166 |
+
|
167 |
+
?>
|
168 |
</form>
|
169 |
</div>
|
lib/options/submit.php
CHANGED
@@ -1,9 +1,11 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
|
|
3 |
include_once __DIR__ . '/../classes/Config.php';
|
4 |
use \WebPExpress\Config;
|
5 |
|
6 |
-
|
7 |
include_once __DIR__ . '/../classes/HTAccess.php';
|
8 |
use \WebPExpress\HTAccess;
|
9 |
|
@@ -13,82 +15,6 @@ use \WebPExpress\Messenger;
|
|
13 |
include_once __DIR__ . '/../classes/Paths.php';
|
14 |
use \WebPExpress\Paths;
|
15 |
|
16 |
-
/**
|
17 |
-
* Generate valid salt for blowfish, using string that
|
18 |
-
* may contain invalid characters.
|
19 |
-
* The string supplied should preferably be at least 22 chars, but may be less
|
20 |
-
*/
|
21 |
-
function webp_express_generateBlowfishSalt($string) {
|
22 |
-
// http://php.net/manual/en/function.crypt.php
|
23 |
-
|
24 |
-
// Salt may only contain the following characters: "./0-9A-Za-z"
|
25 |
-
$salt = preg_replace('/([^a-zA-Z0-9.\\/])/', '', $string);
|
26 |
-
|
27 |
-
// Salt must be at least 22 chars
|
28 |
-
while (strlen($salt) < 22) {
|
29 |
-
$salt .= strtoupper($salt);
|
30 |
-
}
|
31 |
-
|
32 |
-
// It seems salt may be more than 22. But not sure. We trim
|
33 |
-
$salt = substr($salt, 0, 22);
|
34 |
-
|
35 |
-
return $salt;
|
36 |
-
}
|
37 |
-
|
38 |
-
function webp_express_hashItForMe($password) {
|
39 |
-
|
40 |
-
if (CRYPT_BLOWFISH == 1) {
|
41 |
-
$salt = webp_express_generateBlowfishSalt('./aATesting.123');
|
42 |
-
$crypted = crypt($password, '$2y$10$' . $salt . '$');
|
43 |
-
|
44 |
-
// No reason to store the first 28 character.
|
45 |
-
// The first 6 are always "$2y$10$". The next 22 is the salt, which we cannot allow to be
|
46 |
-
// random, because...
|
47 |
-
|
48 |
-
// Hm. perhaps, instead of a whitelist, we could have a list of authorized clients
|
49 |
-
// Procedure:
|
50 |
-
/*
|
51 |
-
On server:
|
52 |
-
- Click "Listen for requests".
|
53 |
-
That opens a dialog showing the URL that it is listening on
|
54 |
-
|
55 |
-
On client:
|
56 |
-
- Click "Send request". That opens a prompt for the URL
|
57 |
-
- Enter URL
|
58 |
-
- Client sends a request including a autogenerated password (crypted?).
|
59 |
-
The salt is included in the crypted password (crypt() output)
|
60 |
-
Blowfish is specified.
|
61 |
-
Perhaps also a callback URL, so client can display message upon connection.
|
62 |
-
But a "test connection" link would probably suffice
|
63 |
-
|
64 |
-
On server:
|
65 |
-
- The request is displayed (polling, including the client domain / IP
|
66 |
-
- Click "Accept" next to the request.
|
67 |
-
- The request is added to the authorized list (IP, domain? and the crypted password)
|
68 |
-
- The client
|
69 |
-
|
70 |
-
On client:
|
71 |
-
- When request
|
72 |
-
*/
|
73 |
-
return substr($crypted, 28);
|
74 |
-
}
|
75 |
-
|
76 |
-
/*
|
77 |
-
$salt = 'banana';
|
78 |
-
// TODO: Lets use the server URL (at the time of password creation) as salt
|
79 |
-
// This will work, even if site changes URL (not if new sites are connecting,
|
80 |
-
// to same though)
|
81 |
-
|
82 |
-
if (function_exists('md5')) {
|
83 |
-
return md5($password . $salt);
|
84 |
-
}
|
85 |
-
*/
|
86 |
-
// No, we cannot use password_hash.
|
87 |
-
// We need something that returns the same hash on server and client.
|
88 |
-
// So we need to specify salt, and ensure it is the same
|
89 |
-
//password_hash($entry['new_password'], PASSWORD_DEFAULT);
|
90 |
-
}
|
91 |
-
|
92 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
93 |
// checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
|
94 |
|
@@ -99,45 +25,65 @@ function webp_express_sanitize_quality_field($text) {
|
|
99 |
$q = round($q);
|
100 |
return max(0, min($q, 100));
|
101 |
}
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
|
|
|
|
|
|
|
|
107 |
'image-types' => sanitize_text_field($_POST['image-types']),
|
108 |
-
'metadata' => sanitize_text_field($_POST['metadata']),
|
109 |
'forward-query-string' => true,
|
110 |
-
'do-not-pass-source-in-query-string' => isset($_POST['do-not-pass-source-in-query-string']),
|
111 |
-
'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
|
112 |
-
'web-service' => [
|
113 |
-
'enabled' => isset($_POST['web-service-enabled']),
|
114 |
-
'whitelist' => json_decode(wp_unslash($_POST['whitelist']), true)
|
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 |
if (isset($oldConfig['web-service']['whitelist'])) {
|
142 |
foreach ($oldConfig['web-service']['whitelist'] as $existingWhitelistEntry) {
|
143 |
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
|
@@ -147,19 +93,27 @@ if ($oldConfig !== false) {
|
|
147 |
}
|
148 |
}
|
149 |
}
|
150 |
-
}
|
151 |
|
152 |
-
// Set new api keys in web service
|
153 |
-
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
|
154 |
-
|
155 |
-
|
156 |
-
|
|
|
157 |
}
|
158 |
-
}
|
159 |
|
160 |
-
//
|
161 |
-
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
foreach ($oldConfig['converters'] as &$converter) {
|
164 |
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
|
165 |
if (isset($converter['options']['api-key'])) {
|
@@ -167,59 +121,62 @@ if ($oldConfig !== false) {
|
|
167 |
}
|
168 |
}
|
169 |
}
|
170 |
-
}
|
171 |
|
172 |
-
// Set wpc api key in new config
|
173 |
-
// - either to the existing, or to a new
|
174 |
-
foreach ($config['converters'] as &$converter) {
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
182 |
}
|
183 |
}
|
184 |
}
|
185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
|
187 |
-
//
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
if ($entry['hash_new_password']) {
|
193 |
-
$entry['password'] = webp_express_hashItForMe($entry['new_password']);
|
194 |
-
} else {
|
195 |
-
$entry['password'] = $entry['new_password'];
|
196 |
-
}
|
197 |
-
|
198 |
-
unset($entry['hash_new_password']);
|
199 |
-
unset($entry['new_password']);
|
200 |
-
}
|
201 |
}
|
202 |
-
*/
|
203 |
|
|
|
|
|
204 |
$result = Config::saveConfigurationAndHTAccess($config, isset($_POST['force']));
|
205 |
|
206 |
-
/*
|
207 |
-
Messenger::addMessage(
|
208 |
-
'info',
|
209 |
-
isset($_POST['force']) ? 'force' : 'no-force' .
|
210 |
-
(HTAccess::doesRewriteRulesNeedUpdate($config) ? 'need' : 'no need')
|
211 |
-
);*/
|
212 |
-
|
213 |
-
/*
|
214 |
-
Messenger::addMessage(
|
215 |
-
'info',
|
216 |
-
'<pre>' . htmlentities(print_r($config, true)) . '</pre>'
|
217 |
-
);
|
218 |
|
219 |
-
|
220 |
-
|
221 |
-
'<pre>' . htmlentities(print_r($result, true)) . '</pre>'
|
222 |
-
);*/
|
223 |
|
224 |
if (!$result['saved-both-config']) {
|
225 |
if (!$result['saved-main-config']) {
|
@@ -237,6 +194,52 @@ if (!$result['saved-both-config']) {
|
|
237 |
|
238 |
}
|
239 |
} else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
if (!$result['rules-needed-update']) {
|
241 |
Messenger::addMessage(
|
242 |
'success',
|
1 |
<?php
|
2 |
|
3 |
+
include_once __DIR__ . '/../classes/CacheMover.php';
|
4 |
+
use \WebPExpress\CacheMover;
|
5 |
+
|
6 |
include_once __DIR__ . '/../classes/Config.php';
|
7 |
use \WebPExpress\Config;
|
8 |
|
|
|
9 |
include_once __DIR__ . '/../classes/HTAccess.php';
|
10 |
use \WebPExpress\HTAccess;
|
11 |
|
15 |
include_once __DIR__ . '/../classes/Paths.php';
|
16 |
use \WebPExpress\Paths;
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
19 |
// checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
|
20 |
|
25 |
$q = round($q);
|
26 |
return max(0, min($q, 100));
|
27 |
}
|
28 |
+
|
29 |
+
$config = Config::loadConfigAndFix();
|
30 |
+
$oldConfig = $config;
|
31 |
+
|
32 |
+
// Set options that are available in all operation modes
|
33 |
+
$config = array_merge($config, [
|
34 |
+
'operation-mode' => $_POST['operation-mode'],
|
35 |
+
|
36 |
+
// redirection rules
|
37 |
'image-types' => sanitize_text_field($_POST['image-types']),
|
|
|
38 |
'forward-query-string' => true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
+
// serve options
|
41 |
+
'cache-control' => sanitize_text_field($_POST['cache-control']),
|
42 |
+
'cache-control-custom' => sanitize_text_field($_POST['cache-control-custom']),
|
43 |
+
]);
|
44 |
+
|
45 |
+
$cacheControl = sanitize_text_field($_POST['cache-control']);
|
46 |
+
switch ($cacheControl) {
|
47 |
+
case 'no-header':
|
48 |
+
break;
|
49 |
+
case 'set':
|
50 |
+
$config['cache-control-max-age'] = sanitize_text_field($_POST['cache-control-max-age']);
|
51 |
+
$config['cache-control-public'] = (sanitize_text_field($_POST['cache-control-public']) == 'public');
|
52 |
+
break;
|
53 |
+
case 'custom':
|
54 |
+
$config['cache-control-custom'] = sanitize_text_field($_POST['cache-control-custom']);
|
55 |
+
break;
|
56 |
}
|
57 |
|
58 |
+
// Set options that are available in all operation modes, except the "just-redirect" mode
|
59 |
+
if ($_POST['operation-mode'] != 'just-redirect') {
|
60 |
|
61 |
+
// Metadata
|
62 |
+
// --------
|
63 |
+
$config['metadata'] = sanitize_text_field($_POST['metadata']);
|
|
|
64 |
|
65 |
+
// Quality
|
66 |
+
// --------
|
67 |
+
$auto = (isset($_POST['quality-auto']) && $_POST['quality-auto'] == 'auto_on');
|
68 |
+
$config['quality-auto'] = $auto;
|
69 |
|
70 |
+
if ($auto) {
|
71 |
+
$config['max-quality'] = webp_express_sanitize_quality_field($_POST['max-quality']);
|
72 |
+
$config['quality-specific'] = 70;
|
73 |
+
} else {
|
74 |
+
$config['max-quality'] = 80;
|
75 |
+
$config['quality-specific'] = webp_express_sanitize_quality_field($_POST['quality-specific']);
|
76 |
+
}
|
77 |
+
|
78 |
+
// Web Service
|
79 |
+
// -------------
|
80 |
+
|
81 |
+
$config['web-service'] = [
|
82 |
+
'enabled' => isset($_POST['web-service-enabled']),
|
83 |
+
'whitelist' => json_decode(wp_unslash($_POST['whitelist']), true)
|
84 |
+
];
|
85 |
+
|
86 |
+
// Set existing api keys in web service (we removed them from the json array, for security purposes)
|
87 |
if (isset($oldConfig['web-service']['whitelist'])) {
|
88 |
foreach ($oldConfig['web-service']['whitelist'] as $existingWhitelistEntry) {
|
89 |
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
|
93 |
}
|
94 |
}
|
95 |
}
|
|
|
96 |
|
97 |
+
// Set new api keys in web service
|
98 |
+
foreach ($config['web-service']['whitelist'] as &$whitelistEntry) {
|
99 |
+
if (!empty($whitelistEntry['new-api-key'])) {
|
100 |
+
$whitelistEntry['api-key'] = $whitelistEntry['new-api-key'];
|
101 |
+
unset($whitelistEntry['new-api-key']);
|
102 |
+
}
|
103 |
}
|
|
|
104 |
|
105 |
+
// Converters
|
106 |
+
// -------------
|
107 |
+
|
108 |
+
$config['converters'] = json_decode(wp_unslash($_POST['converters']), true); // holy moly! - https://stackoverflow.com/questions/2496455/why-are-post-variables-getting-escaped-in-php
|
109 |
+
|
110 |
+
// remove converter ids
|
111 |
+
foreach ($config['converters'] as &$converter) {
|
112 |
+
unset ($converter['id']);
|
113 |
+
}
|
114 |
+
|
115 |
+
// Get existing wpc api key from old config
|
116 |
+
$existingWpcApiKey = '';
|
117 |
foreach ($oldConfig['converters'] as &$converter) {
|
118 |
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
|
119 |
if (isset($converter['options']['api-key'])) {
|
121 |
}
|
122 |
}
|
123 |
}
|
|
|
124 |
|
125 |
+
// Set wpc api key in new config
|
126 |
+
// - either to the existing, or to a new
|
127 |
+
foreach ($config['converters'] as &$converter) {
|
128 |
+
if (isset($converter['converter']) && ($converter['converter'] == 'wpc')) {
|
129 |
+
unset($converter['options']['_api-key-non-empty']);
|
130 |
+
if (isset($converter['options']['new-api-key'])) {
|
131 |
+
$converter['options']['api-key'] = $converter['options']['new-api-key'];
|
132 |
+
unset($converter['options']['new-api-key']);
|
133 |
+
} else {
|
134 |
+
$converter['options']['api-key'] = $existingWpcApiKey;
|
135 |
+
}
|
136 |
}
|
137 |
}
|
138 |
}
|
139 |
|
140 |
+
switch ($_POST['operation-mode']) {
|
141 |
+
case 'standard':
|
142 |
+
$config = array_merge($config, [
|
143 |
+
'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
|
144 |
+
]);
|
145 |
+
break;
|
146 |
+
case 'just-convert':
|
147 |
+
$config = array_merge($config, [
|
148 |
+
'destination-extension' => $_POST['destination-extension'],
|
149 |
+
'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']), // PS: its called "autoconvert" in this mode
|
150 |
+
]);
|
151 |
+
break;
|
152 |
+
case 'tweaked':
|
153 |
+
$config = array_merge($config, [
|
154 |
+
'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']),
|
155 |
+
'only-redirect-to-converter-for-webp-enabled-browsers' => isset($_POST['only-redirect-to-converter-for-webp-enabled-browsers']),
|
156 |
+
'only-redirect-to-converter-on-cache-miss' => isset($_POST['only-redirect-to-converter-on-cache-miss']),
|
157 |
+
'do-not-pass-source-in-query-string' => isset($_POST['do-not-pass-source-in-query-string']),
|
158 |
+
'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
|
159 |
+
'destination-folder' => $_POST['destination-folder'],
|
160 |
+
'destination-extension' => (($_POST['destination-folder'] == 'mingled') ? $_POST['destination-extension'] : 'append'),
|
161 |
+
'fail' => sanitize_text_field($_POST['fail']),
|
162 |
+
'success-response' => sanitize_text_field($_POST['success-response']),
|
163 |
+
]);
|
164 |
+
break;
|
165 |
+
}
|
166 |
|
167 |
+
//echo '<pre>' . print_r($_POST, true) . '</pre>'; exit;
|
168 |
+
if ($_POST['operation-mode'] != $_POST['change-operation-mode']) {
|
169 |
+
$config['operation-mode'] = $_POST['change-operation-mode'];
|
170 |
+
$config = Config::applyOperationMode($config);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
}
|
|
|
172 |
|
173 |
+
// SAVE!
|
174 |
+
// -----
|
175 |
$result = Config::saveConfigurationAndHTAccess($config, isset($_POST['force']));
|
176 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
|
178 |
+
// Handle results
|
179 |
+
// ---------------
|
|
|
|
|
180 |
|
181 |
if (!$result['saved-both-config']) {
|
182 |
if (!$result['saved-main-config']) {
|
194 |
|
195 |
}
|
196 |
} else {
|
197 |
+
if (($config['destination-folder'] != $oldConfig['destination-folder']) || ($config['destination-extension'] != $oldConfig['destination-extension'])) {
|
198 |
+
$whatShouldIt = '';
|
199 |
+
if ($config['destination-folder'] == $oldConfig['destination-folder']) {
|
200 |
+
$whatShouldIt = 'renamed';
|
201 |
+
$whatShouldIt2 = 'rename';
|
202 |
+
} else {
|
203 |
+
if ($config['destination-extension'] == $oldConfig['destination-extension']) {
|
204 |
+
$whatShouldIt = 'relocated';
|
205 |
+
$whatShouldIt2 = 'relocate';
|
206 |
+
} else {
|
207 |
+
$whatShouldIt = 'relocated and renamed';
|
208 |
+
$whatShouldIt2 = 'relocate and rename';
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
list($numFilesMoved, $numFilesFailedMoving) = CacheMover::move($config, $oldConfig);
|
213 |
+
if ($numFilesFailedMoving == 0) {
|
214 |
+
if ($numFilesMoved == 0) {
|
215 |
+
Messenger::addMessage(
|
216 |
+
'notice',
|
217 |
+
'No cached webp files needed to be ' . $whatShouldIt
|
218 |
+
);
|
219 |
+
|
220 |
+
} else {
|
221 |
+
Messenger::addMessage(
|
222 |
+
'success',
|
223 |
+
'The webp files was ' . $whatShouldIt . ' (' . $whatShouldIt . ' ' . $numFilesMoved . ' images)'
|
224 |
+
);
|
225 |
+
}
|
226 |
+
} else {
|
227 |
+
if ($numFilesMoved == 0) {
|
228 |
+
Messenger::addMessage(
|
229 |
+
'warning',
|
230 |
+
'No webp files could not be ' . $whatShouldIt . ' (failed to ' . $whatShouldIt2 . ' ' . $numFilesFailedMoving . ' images)'
|
231 |
+
);
|
232 |
+
} else {
|
233 |
+
Messenger::addMessage(
|
234 |
+
'warning',
|
235 |
+
'Some webp files could not be ' . $whatShouldIt . ' (failed to ' . $whatShouldIt2 . ' ' . $numFilesFailedMoving . ' images, but successfully ' . $whatShouldIt . ' ' . $numFilesMoved . ' images)'
|
236 |
+
);
|
237 |
+
|
238 |
+
}
|
239 |
+
}
|
240 |
+
}
|
241 |
+
|
242 |
+
|
243 |
if (!$result['rules-needed-update']) {
|
244 |
Messenger::addMessage(
|
245 |
'success',
|
test/test.jpg.webp
ADDED
Binary file
|
test/test.webp
ADDED
Binary file
|
webp-express.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: WebP Express
|
4 |
* Plugin URI: https://github.com/rosell-dk/webp-express
|
5 |
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
|
6 |
-
* Version: 0.
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
3 |
* Plugin Name: WebP Express
|
4 |
* Plugin URI: https://github.com/rosell-dk/webp-express
|
5 |
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
|
6 |
+
* Version: 0.10.0
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
wod/.webp
ADDED
Binary file
|
wod/webp-on-demand.php
CHANGED
@@ -8,12 +8,12 @@ error_reporting(E_ALL);
|
|
8 |
//exit;
|
9 |
|
10 |
//require 'webp-on-demand-1.inc';
|
11 |
-
require '../vendor/rosell-dk/webp-convert/build/webp-on-demand-1.inc';
|
12 |
//require '../vendor/autoload.php';
|
13 |
|
14 |
//print_r($_GET); exit;
|
15 |
|
16 |
use \WebPConvert\WebPConvert;
|
|
|
17 |
|
18 |
function loadConfig($configFilename) {
|
19 |
if (!file_exists($configFilename)) {
|
@@ -96,29 +96,53 @@ if (!file_exists($source)) {
|
|
96 |
//echo $source; exit;
|
97 |
|
98 |
|
99 |
-
// Calculate destination
|
100 |
-
$imageRoot = $webExpressContentDirAbs . '/webp-images';
|
101 |
|
102 |
-
//
|
103 |
-
//
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
//
|
108 |
-
//
|
109 |
-
$
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
} else {
|
112 |
-
|
113 |
-
|
114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
}
|
116 |
|
117 |
-
// If we wanted webp images to be located in same folder, with ie ".jpg.webp" extension:
|
118 |
-
// $destination = $source . '.webp';
|
119 |
|
120 |
-
|
121 |
-
|
122 |
|
123 |
//echo $destination; exit;
|
124 |
|
@@ -126,9 +150,6 @@ if (substr($source, 0, strlen($docRoot) + 1) === $docRoot . '/') {
|
|
126 |
//echo '<pre>' . print_r($options, true) . '</pre>';
|
127 |
//exit;
|
128 |
|
129 |
-
$options['require-for-conversion'] = 'webp-on-demand-2.inc';
|
130 |
-
//$options['require-for-conversion'] = '../../../autoload.php';
|
131 |
-
|
132 |
foreach ($options['converters'] as &$converter) {
|
133 |
if (isset($converter['converter'])) {
|
134 |
$converterId = $converter['converter'];
|
@@ -149,5 +170,48 @@ if ($options['forward-query-string']) {
|
|
149 |
}
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
//echo "<pre>source: $source \ndestination: $destination \n\noptions:" . print_r($options, true) . '</pre>'; exit;
|
153 |
-
WebPConvert::convertAndServe($source, $destination, $options);
|
8 |
//exit;
|
9 |
|
10 |
//require 'webp-on-demand-1.inc';
|
|
|
11 |
//require '../vendor/autoload.php';
|
12 |
|
13 |
//print_r($_GET); exit;
|
14 |
|
15 |
use \WebPConvert\WebPConvert;
|
16 |
+
use \WebPConvert\ServeExistingOrHandOver;
|
17 |
|
18 |
function loadConfig($configFilename) {
|
19 |
if (!file_exists($configFilename)) {
|
96 |
//echo $source; exit;
|
97 |
|
98 |
|
|
|
|
|
99 |
|
100 |
+
// Calculate $destination
|
101 |
+
// ----------------------
|
102 |
+
$mingled = (isset($options['destination-folder']) && ($options['destination-folder'] == 'mingled'));
|
103 |
+
$storeMingled = false;
|
104 |
+
if ($mingled) {
|
105 |
+
// Test if source folder is writable.
|
106 |
+
// We will only store "mingled", if it is.
|
107 |
+
$sourceFolder = preg_replace('/\\/[^\\/]*$/', '', $source);
|
108 |
+
if (@is_writable($sourceFolder) && @is_executable($sourceFolder)) {
|
109 |
+
$storeMingled = true;
|
110 |
+
} else {
|
111 |
+
header('X-WebP-Express-Notice: Cannot save file in same directory as source, falling back to separate folder', true);
|
112 |
+
if (isset($_GET['debug'])) {
|
113 |
+
echo 'Notice: Cannot save file in same directory as source, falling back to separate folder<br><br>';
|
114 |
+
}
|
115 |
+
}
|
116 |
+
}
|
117 |
+
if ($storeMingled) {
|
118 |
+
if (isset($options['destination-extension']) && ($options['destination-extension'] == 'append')) {
|
119 |
+
$destination = $source . '.webp';
|
120 |
+
} else {
|
121 |
+
$destination = preg_replace('/\\.(jpe?g|png)$/', '', $source) . '.webp';
|
122 |
+
}
|
123 |
} else {
|
124 |
+
|
125 |
+
$imageRoot = $webExpressContentDirAbs . '/webp-images';
|
126 |
+
|
127 |
+
// Check if source is residing inside document root.
|
128 |
+
// (it is, if path starts with document root + '/')
|
129 |
+
if (substr($source, 0, strlen($docRoot) + 1) === $docRoot . '/') {
|
130 |
+
|
131 |
+
// We store relative to document root.
|
132 |
+
// "Eat" the left part off the source parameter which contains the document root.
|
133 |
+
// and also eat the slash (+1)
|
134 |
+
$sourceRel = substr($source, strlen($docRoot) + 1);
|
135 |
+
$destination = $imageRoot . '/doc-root/' . $sourceRel . '.webp';
|
136 |
+
} else {
|
137 |
+
// Source file is residing outside document root.
|
138 |
+
// we must add complete path to structure
|
139 |
+
$destination = $imageRoot . '/abs' . $source . '.webp';
|
140 |
+
}
|
141 |
}
|
142 |
|
|
|
|
|
143 |
|
144 |
+
|
145 |
+
|
146 |
|
147 |
//echo $destination; exit;
|
148 |
|
150 |
//echo '<pre>' . print_r($options, true) . '</pre>';
|
151 |
//exit;
|
152 |
|
|
|
|
|
|
|
153 |
foreach ($options['converters'] as &$converter) {
|
154 |
if (isset($converter['converter'])) {
|
155 |
$converterId = $converter['converter'];
|
170 |
}
|
171 |
}
|
172 |
|
173 |
+
function aboutToServeImageCallBack($servingWhat, $whyServingThis, $obj) {
|
174 |
+
return false; // do not serve!
|
175 |
+
}
|
176 |
+
|
177 |
+
$options['require-for-conversion'] = 'webp-on-demand-2.inc';
|
178 |
+
//$options['require-for-conversion'] = '../../../autoload.php';
|
179 |
+
|
180 |
+
include_once '../vendor/rosell-dk/webp-convert/build/webp-on-demand-1.inc';
|
181 |
+
|
182 |
+
if (isset($options['success-response']) && ($options['success-response'] == 'original')) {
|
183 |
+
|
184 |
+
/*
|
185 |
+
We want to convert, but serve the original. This is a bit unusual and requires a little tweaking
|
186 |
+
|
187 |
+
First, we use the "decideWhatToServe" method of WebPConvert to find out if we should convert or not
|
188 |
+
|
189 |
+
If result is "destination", it means there is a useful webp image at the destination (no reason to convert)
|
190 |
+
If result is "source", it means that source is lighter than existing webp image (no reason to convert)
|
191 |
+
If result is "fresh-conversion", it means we should convert
|
192 |
+
*/
|
193 |
+
$server = new \WebPConvert\Serve\ServeExistingOrHandOver($source, $destination, $options);
|
194 |
+
$server->decideWhatToServe();
|
195 |
+
|
196 |
+
if ($server->whatToServe == 'fresh-conversion') {
|
197 |
+
// Conversion time.
|
198 |
+
// To prevent the serving, we use the callback
|
199 |
+
$options['aboutToServeImageCallBack'] = 'aboutToServeImageCallBack';
|
200 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|
201 |
+
|
202 |
+
// remove the callback, we are going for another round
|
203 |
+
unset($options['aboutToServeImageCallBack']);
|
204 |
+
unset($options['require-for-conversion']);
|
205 |
+
}
|
206 |
+
|
207 |
+
// Serve time
|
208 |
+
$options['serve-original'] = true; // Serve original
|
209 |
+
$options['add-vary-header'] = false;
|
210 |
+
|
211 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|
212 |
+
|
213 |
+
} else {
|
214 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|
215 |
+
}
|
216 |
+
|
217 |
//echo "<pre>source: $source \ndestination: $destination \n\noptions:" . print_r($options, true) . '</pre>'; exit;
|
|