WebP Express - Version 0.12.0

Version Description

(released 5 mar 2019) * Multisite support (!) * A new operation mode: "No conversion", if you do not want to use WebP Express for converting. Replaces the old "Just redirect" mode * Added capability testing of .htaccess. The .htaccess rules are now tailored to the capabilities on the system. For example, on some platforms the filename of a requested image is passed to the converter script through the query string, but on platforms that supports passing it through an environment variable, that method is used instead * Picturefill.js is now optional (alter html, picture tag) * A great bunch more!

For more info, see the closed issues on the 0.12.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/12?closed=1

Download this release

Release Info

Developer rosell.dk
Plugin Icon 128x128 WebP Express
Version 0.12.0
Comparing to
See all releases

Code changes from version 0.11.3 to 0.12.0

Files changed (74) hide show
  1. README.md +46 -10
  2. README.txt +65 -9
  3. changelog.txt +19 -0
  4. docs/development.md +1 -1
  5. htaccess-capability-tests/.htaccess +6 -0
  6. htaccess-capability-tests/has-mod-header/.htaccess +3 -0
  7. htaccess-capability-tests/has-mod-header/test.php +9 -0
  8. htaccess-capability-tests/has-mod-rewrite/.htaccess +11 -0
  9. htaccess-capability-tests/has-mod-rewrite/1.php +2 -0
  10. htaccess-capability-tests/has-mod-rewrite/test.php +2 -0
  11. htaccess-capability-tests/pass-server-var-through-header/.htaccess +15 -0
  12. htaccess-capability-tests/pass-server-var-through-header/test.php +9 -0
  13. htaccess-capability-tests/pass-through-environment-var/.htaccess +13 -0
  14. htaccess-capability-tests/pass-through-environment-var/test.php +27 -0
  15. htaccess-capability-tests/request-uri-usable-in-this-dir/.htaccess +11 -0
  16. htaccess-capability-tests/request-uri-usable-in-this-dir/test.php +3 -0
  17. htaccess-capability-tests/request-uri-usable-in-this-dir/test2.php +51 -0
  18. htaccess-capability-tests/urls.txt +12 -0
  19. lib/activate-first-time.php +16 -10
  20. lib/admin.php +28 -9
  21. lib/classes/Actions.php +4 -2
  22. lib/classes/AlterHtmlHelper.php +10 -1
  23. lib/classes/AlterHtmlImageUrls.php +0 -48
  24. lib/classes/AlterHtmlInit.php +10 -8
  25. lib/classes/CapabilityTest.php +96 -0
  26. lib/classes/Config.php +57 -16
  27. lib/classes/FileHelper.php +42 -0
  28. lib/classes/HTAccess.php +161 -79
  29. lib/classes/KeepEwwwSubscriptionAlive.php +60 -0
  30. lib/classes/Messenger.php +5 -3
  31. lib/classes/Multisite.php +36 -0
  32. lib/classes/Option.php +39 -0
  33. lib/classes/Paths.php +13 -12
  34. lib/classes/State.php +5 -2
  35. lib/migrate/migrate.php +8 -34
  36. lib/migrate/migrate1.php +9 -8
  37. lib/migrate/migrate2.php +3 -1
  38. lib/migrate/migrate3.php +2 -1
  39. lib/migrate/migrate4.php +2 -1
  40. lib/migrate/migrate5.php +6 -4
  41. lib/migrate/migrate6.php +3 -10
  42. lib/migrate/migrate7.php +94 -0
  43. lib/options/css/webp-express-options-page.css +129 -2
  44. lib/options/enqueue_scripts.php +13 -9
  45. lib/options/js/page.js +142 -98
  46. lib/options/options-hooks.php +30 -15
  47. lib/options/options/alter-html/alter-html-options.inc +132 -39
  48. lib/options/options/alter-html/alter-html.inc +6 -9
  49. lib/options/options/conversion-options/conversion-options.inc +2 -17
  50. lib/options/options/conversion-options/destination-extension.inc +0 -24
  51. lib/options/options/conversion-options/metadata.inc +0 -1
  52. lib/options/options/{serve-options → general}/cache-control.inc +11 -21
  53. lib/options/options/general/destination-extension.inc +60 -0
  54. lib/options/options/{conversion-options → general}/destination-folder.inc +0 -0
  55. lib/options/options/general/general.inc +21 -0
  56. lib/options/options/{redirection-rules → general}/image-types.inc +11 -6
  57. lib/options/options/operation-mode.inc +12 -11
  58. lib/options/options/redirection-rules/enable-redirection-to-converter.inc +4 -4
  59. lib/options/options/redirection-rules/enable-redirection-to-webp-realizer.inc +4 -3
  60. lib/options/options/redirection-rules/only-redirect-to-converter-for-webp-enabled-browsers.inc +3 -2
  61. lib/options/options/redirection-rules/only-redirect-to-converter-on-cache-miss.inc +4 -4
  62. lib/options/options/redirection-rules/redirect-to-existing.inc +21 -4
  63. lib/options/options/redirection-rules/redirection-rules.inc +50 -26
  64. lib/options/options/serve-options/response-on-failure.inc +0 -1
  65. lib/options/options/serve-options/response-on-success.inc +0 -1
  66. lib/options/options/serve-options/serve-options.inc +0 -5
  67. lib/options/options/web-service-options/web-service-options.inc +1 -7
  68. lib/options/page-messages.php +97 -5
  69. lib/options/page.php +85 -29
  70. lib/options/submit.php +46 -22
  71. lib/uninstall.php +3 -2
  72. webp-express.php +15 -2
  73. wod/webp-on-demand.php +98 -29
  74. wod/webp-realizer.php +91 -22
README.md CHANGED
@@ -31,9 +31,11 @@ The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) an
31
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
32
- Currently ~73% of all traffic, and ~79% of mobile browsing traffic are done with browsers supporting webp. With Mozilla and Microsoft [finally on board](https://medium.com/@richard_90141/webp-image-support-an-8-year-saga-7aa2bedb8d02), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
33
34
35
## Installation
36
-
37
1. Upload the plugin files to the `/wp-content/plugins/webp-express` directory, or install the plugin through the WordPress plugins screen directly.
38
2. Activate the plugin through the 'Plugins' screen in WordPress
39
3. Configure it (the plugin doesn't do anything until configured)
@@ -100,14 +102,10 @@ The redirect rules created in *.htaccess* are pointing to a PHP script. If you h
100
*Note:*
101
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
102
103
- *Note:*
104
- The plugin has not been tested in multisite configurations.
105
-
106
107
## Limitations
108
109
- * The plugin does not work on Microsoft IIS server, nor in WAMP
110
- * The plugin has not been tested with multisite installation
111
112
## Frequently Asked Questions
113
@@ -146,6 +144,8 @@ It is possible to make WebP Express work on NGINX, but it requires manually inse
146
147
There are two different approaches to achieve the redirections. One based on *rewrite* and one based on *try_files*. As *try_files* performs best, I shall recommend that.
148
149
#### method 1 (try_files)
150
151
Lets take this step by step.
@@ -247,7 +247,7 @@ Insert the following in the `server` context:
247
# WebP Express rules
248
# --------------------
249
if ($http_accept ~* "webp"){
250
- rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?wp-content=wp-content break;
251
}
252
# ------------------- (WebP Express rules ends here)
253
```
@@ -330,6 +330,7 @@ location ~* ^/wp-content/.*\.webp$ {
330
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
331
And here: https://github.com/rosell-dk/webp-express/issues/166
332
333
334
### I am on a WAMP stack
335
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?
@@ -447,7 +448,7 @@ To make *WebP Express* work on a free Cloudflare account, you have the following
447
448
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.
449
450
- 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
451
452
### WebP Express / ShortPixel setup
453
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.
@@ -555,21 +556,56 @@ In a webp-enabled browser, the HTML may look like this: `<img src="image.webp">`
555
### Does it work with lazy loaded images?
556
No plugins/frameworks has yet been discovered, which does not work with *WebP Express*.
557
558
- 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.
559
560
The following lazy load plugins/frameworks has been tested and works with *WebP Express*:
561
- [BJ Lazy Load](https://da.wordpress.org/plugins/bj-lazy-load/)
562
- [Owl Carousel 2](https://owlcarousel2.github.io/OwlCarousel2/)
563
564
I have only tested the above in *Varied image responses* mode, but it should also work in *CDN friendly* mode. Both *Alter HTML* options have been designed to work with standard lazy load attributes.
565
566
### When is feature X coming? / Roadmap
567
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.
568
569
- Here are my current plans ahead: 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 be multisite support, as this has been requested by many. 0.14 might be adding some diagnose tool – this should release some time spend in the forum. 0.54 could be focused on PNG. 0.16 might be displaying rules for NGINX. 0.17 might be supporting Save-Data header (send extra compressed images to clients who wants to use as little bandwidth as possible). 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
570
571
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.
572
573
## Changes in 0.11.0
574
- Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
575
- Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
31
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
32
- Currently ~73% of all traffic, and ~79% of mobile browsing traffic are done with browsers supporting webp. With Mozilla and Microsoft [finally on board](https://medium.com/@richard_90141/webp-image-support-an-8-year-saga-7aa2bedb8d02), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
33
34
+ ### Recent news
35
+ Feb 2019: Multisite is now supported (0.12.0)
36
+ Jan 2019: Plugin can now alter HTML (0.11.0)
37
38
## Installation
39
1. Upload the plugin files to the `/wp-content/plugins/webp-express` directory, or install the plugin through the WordPress plugins screen directly.
40
2. Activate the plugin through the 'Plugins' screen in WordPress
41
3. Configure it (the plugin doesn't do anything until configured)
102
*Note:*
103
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
104
105
106
## Limitations
107
108
+ * The plugin has not been tested by the developer on Microsoft IIS server. [Some however reports that it works](https://wordpress.org/support/topic/iis-and-webp-works/)
109
110
## Frequently Asked Questions
111
144
145
There are two different approaches to achieve the redirections. One based on *rewrite* and one based on *try_files*. As *try_files* performs best, I shall recommend that.
146
147
+ For multisite on NGINX, read [here](https://github.com/rosell-dk/webp-express/issues/8)
148
+
149
#### method 1 (try_files)
150
151
Lets take this step by step.
247
# WebP Express rules
248
# --------------------
249
if ($http_accept ~* "webp"){
250
+ rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?xsource=x$request_filename&wp-content=wp-content break;
251
}
252
# ------------------- (WebP Express rules ends here)
253
```
330
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
331
And here: https://github.com/rosell-dk/webp-express/issues/166
332
333
+ Here are rules if you need to replace the file extension with ".webp" rather than appending ".webp" to it: https://www.keycdn.com/support/optimus/configuration-to-deliver-webp
334
335
### I am on a WAMP stack
336
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?
448
449
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.
450
451
+ 3. You can switch operation mode to "CDN friendly" and use HTML altering.
452
453
### WebP Express / ShortPixel setup
454
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.
556
### Does it work with lazy loaded images?
557
No plugins/frameworks has yet been discovered, which does not work with *WebP Express*.
558
559
+ The most common way of lazy-loading is by setting a *data-src* attribute on the image and let javascript use that value for setting 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.
560
561
The following lazy load plugins/frameworks has been tested and works with *WebP Express*:
562
- [BJ Lazy Load](https://da.wordpress.org/plugins/bj-lazy-load/)
563
- [Owl Carousel 2](https://owlcarousel2.github.io/OwlCarousel2/)
564
+ - [Lazy Load by WP Rocket](https://wordpress.org/plugins/rocket-lazy-load/)
565
566
I have only tested the above in *Varied image responses* mode, but it should also work in *CDN friendly* mode. Both *Alter HTML* options have been designed to work with standard lazy load attributes.
567
568
+ ### Can I make an exceptions for some images?
569
+ There can be instances where you actually need to serve a jpeg or png. For example if you are demonstrating how a jpeg looks using some compression settings. It is possible to bypass both the redirection and the HTML altering for certain images. Here is how:
570
+
571
+ *Alter HTML*
572
+ Alter HTML is programmed not to substitute image URLs with query strings (better safe than sorry). You can exploit that and simply add ie ?original to the image URLs in question.
573
+
574
+ *Redirection*
575
+ To bypass the *redirection*, you can add the following in the `.htaccess` where *WebP Express* has placed its rules (this is usually in the `wp-content` folder). The rules needs to be added *above* the rules inserted by *WebP Express*.
576
+
577
+ ```
578
+ RewriteCond %{QUERY_STRING} original
579
+ RewriteCond %{REQUEST_FILENAME} -f
580
+ RewriteRule . - [L]
581
+ ```
582
+ With those rules in place, you can add "?original" to the URLs of those images that you want to keep serving as jpg / png.
583
+
584
+ Alternatively, you can specify the filenames individually in the `.htaccess`:
585
+
586
+ ```
587
+ RewriteRule ^uploads/2019/02/example-of-jpg-compressed-to-80\.jpg - [L]
588
+ RewriteRule ^uploads/2019/02/image2\.jpg - [L]
589
+ RewriteRule . - [L]
590
+ ```
591
+ If you got any further questions, look at, or comment on [this topic](https://wordpress.org/support/topic/can-i-make-an-exception-for-specific-post-image/)
592
+
593
### When is feature X coming? / Roadmap
594
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.
595
596
+ Here are my current plans ahead: 0.13 might be bulk conversion and addition of a 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 a file manager-like interface for inspecting generated webp files. 0.18 might be an effort to allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript librare does not (currently) support srcset attributes, which is why I moved this item down the priority list. We need srcset to be supported for the feature to be useful. 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
597
598
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.
599
600
+ ## Changes in 0.12.0
601
+ - Multisite support (!)
602
+ - A new operation mode: "No conversion", if you do not want to use WebP Express for converting. Replaces the old "Just redirect" mode
603
+ - Added capability testing of .htaccess. The .htaccess rules are now tailored to the capabilities on the system. For example, on some platforms the filename of a requested image is passed to the converter script through the query string, but on platforms that supports passing it through an environment variable, that method is used instead
604
+ - Picturefill.js is now optional (alter html, picture tag)
605
+ - A great bunch more!
606
+
607
+ For more info, see the closed issues on the 0.12.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/12?closed=1
608
+
609
## Changes in 0.11.0
610
- Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
611
- Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
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.1
7
- Stable tag: 0.11.3
8
Requires PHP: 5.6
9
License: GPLv3
10
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -37,6 +37,10 @@ The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) an
37
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
38
- Currently ~73% of all traffic, and ~79% of mobile browsing traffic are done with browsers supporting webp. With Mozilla and Microsoft [finally on board](https://medium.com/@richard_90141/webp-image-support-an-8-year-saga-7aa2bedb8d02), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
39
40
== Installation ==
41
42
1. Upload the plugin files to the `/wp-content/plugins/webp-express` directory, or install the plugin through the WordPress plugins screen directly.
@@ -87,13 +91,9 @@ The redirect rules created in *.htaccess* are pointing to a PHP script. If you h
87
*Note:*
88
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
89
90
- *Note:*
91
- The plugin has not been tested in multisite configurations. It's on the roadmap...
92
-
93
== Limitations ==
94
95
- * The plugin does not work on Microsoft IIS server, nor in WAMP
96
- * The plugin has not been tested with multisite installation (it is on the roadmap!).
97
98
== Supporting WebP Express ==
99
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 wasting time on this plugin:
@@ -154,6 +154,8 @@ It is possible to make WebP Express work on NGINX, but it requires manually inse
154
155
There are two different approaches to achieve the redirections. One based on *rewrite* and one based on *try_files*. As *try_files* performs best, I shall recommend that.
156
157
**method 1 (try_files)**
158
159
Lets take this step by step.
@@ -252,7 +254,8 @@ Insert the following in the `server` context:
252
253
`
254
if ($http_accept ~* "webp"){
255
- rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?wp-content=wp-content break;
256
}
257
`
258
@@ -328,6 +331,8 @@ location ~* ^/wp-content/.*\.webp$ {
328
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
329
And here: https://github.com/rosell-dk/webp-express/issues/166
330
331
332
= I am on a WAMP stack =
333
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?
@@ -443,7 +448,7 @@ To make *WebP Express* work on a free Cloudflare account, you have the following
443
444
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.
445
446
- 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
447
448
### WebP Express / ShortPixel setup
449
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.
@@ -559,10 +564,35 @@ The following lazy load plugins/frameworks has been tested and works with *WebP
559
560
I have only tested the above in *Varied image responses* mode, but it should also work in *CDN friendly* mode. Both *Alter HTML* options have been designed to work with standard lazy load attributes.
561
562
= When is feature X coming? / Roadmap =
563
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.
564
565
- Here are my current plans ahead: 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 be multisite support, as this has been requested by many. 0.14 might be adding some diagnose tool – this should release some time spend in the forum. 0.54 could be focused on PNG. 0.16 might be displaying rules for NGINX. 0.17 might be supporting Save-Data header (send extra compressed images to clients who wants to use as little bandwidth as possible). 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
566
567
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.
568
@@ -574,7 +604,19 @@ Easy enough! - [Go here!](https://ko-fi.com/rosell). Or [here](https://buymeacof
574
1. WebP Express settings
575
576
== Changelog ==
577
= 0.11.3 =
578
* Fixed bug: Alter HTML caused media library not to display images on some systems. Alter HTML is now disabled in admin mode.
579
* Alter HTML (picture tags) could produce the source tags with "src" attribute. But source tags inside picture tags must use "srcset" attribute. Fixed.
580
* Alter HTML (image urls): srcsets containing "x" descriptors wasn't handled (ie, srcset="image.jpg 1x")
@@ -583,19 +625,23 @@ Easy enough! - [Go here!](https://ko-fi.com/rosell). Or [here](https://buymeacof
583
* Fixed bug: The code that determined if WebP Express had placed rules in a .htaccess failed in "CDN friendly" mode. The effect was that these rules was not cleaned up upon plugin deactivation
584
585
= 0.11.2 =
586
* Fixed bug which caused Alter HTML to fail miserably on some setups
587
* AlterHTML now also looks for lazy load attributes in DIV and LI tags.
588
589
= 0.11.1 =
590
* Fixed bug which caused the new "Convert non-existing webp-files upon request" not to work on all setups
591
592
= 0.11.0 =
593
* Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
594
* Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
595
596
For more info, see the closed issues on the 0.11.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/14?closed=1
597
598
= 0.10.0 =
599
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
600
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
601
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
@@ -615,9 +661,11 @@ For more info, see the closed issues on the 0.10.0 milestone on the github repos
615
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
616
617
= 0.8.1 =
618
* Fixed javascript bug
619
620
= 0.8.0 =
621
* New conversion method, which calls imagick binary directly. This will make WebP express work out of the box on more systems
622
* Made sure not to trigger LFI warning i Wordfence (to activate, click the force .htaccess button)
623
* Imagick can now be configured to set quality to auto on systems where the auto option isn't generally available
@@ -628,17 +676,21 @@ For more info, see the closed issues on the 0.9.0 milestone on the github reposi
628
For more info, see the closed issues on the 0.8.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.8.0
629
630
= 0.7.2 =
631
Fixed a critical bug which generated an error message which caused corrupt images. It was not the bug itself, but the error message it generated, that caused the images to be corrupted. It only happened when debugging was enabled in php.ini
632
633
= 0.7.1 =
634
Fixed minor "bug". The Api version combobox in Remote WebP Express converter was showing on new sites, but I only want it to show when old api is being used.
635
636
= 0.7.0 =
637
This version added option to provide conversion service to other sites!
638
639
For more info, see the closed issues on the 0.7.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.7.0
640
641
= 0.6.0 =
642
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
643
644
* Added option for caching
@@ -656,6 +708,7 @@ This version added option for setting caching header, fixed a serious issue with
656
For more info, see the closed issues on the 0.6.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.6.0
657
658
= 0.5.0 =
659
This version works on many more setups than the previous. Also uses less resources and handles when images are changed.
660
661
* Configuration is now stored in a separate configuration file instead of storing directly in the *.htaccess* file and passing it on via query string. When updating, these settings are migrated automatically.
@@ -682,6 +735,9 @@ For older releases, check out changelog.txt
682
683
== Upgrade Notice ==
684
685
= 0.11.3 =
686
Fixed several bugs. You should update :)
687
4
Tags: webp, images, performance
5
Requires at least: 4.0
6
Tested up to: 5.1
7
+ Stable tag: 0.12.0
8
Requires PHP: 5.6
9
License: GPLv3
10
License URI: https://www.gnu.org/licenses/gpl-3.0.html
37
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
38
- Currently ~73% of all traffic, and ~79% of mobile browsing traffic are done with browsers supporting webp. With Mozilla and Microsoft [finally on board](https://medium.com/@richard_90141/webp-image-support-an-8-year-saga-7aa2bedb8d02), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
39
40
+ ### Recent news
41
+ Feb 2019: Multisite is now supported (0.12.0)
42
+ Jan 2019: Plugin can now alter HTML (0.11.0)
43
+
44
== Installation ==
45
46
1. Upload the plugin files to the `/wp-content/plugins/webp-express` directory, or install the plugin through the WordPress plugins screen directly.
91
*Note:*
92
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
93
94
== Limitations ==
95
96
+ * The plugin has not been tested by the developer on Microsoft IIS server. [Some however reports that it works](https://wordpress.org/support/topic/iis-and-webp-works/)
97
98
== Supporting WebP Express ==
99
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 wasting time on this plugin:
154
155
There are two different approaches to achieve the redirections. One based on *rewrite* and one based on *try_files*. As *try_files* performs best, I shall recommend that.
156
157
+ For multisite on NGINX, read [here](https://github.com/rosell-dk/webp-express/issues/8)
158
+
159
**method 1 (try_files)**
160
161
Lets take this step by step.
254
255
`
256
if ($http_accept ~* "webp"){
257
+ rewrite ^/(.*).(jpe?g|png)$ /wp-content/plugins/webp-express/wod/webp-on-demand.php?xsource=x$request_filename&wp-content=wp-content break;
258
+ }
259
}
260
`
261
331
Discussion on this topic [here](https://wordpress.org/support/topic/nginx-rewrite-rules-4/)
332
And here: https://github.com/rosell-dk/webp-express/issues/166
333
334
+ Here are rules if you need to replace the file extension with ".webp" rather than appending ".webp" to it: https://www.keycdn.com/support/optimus/configuration-to-deliver-webp
335
+
336
337
= I am on a WAMP stack =
338
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?
448
449
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.
450
451
+ 3. You can switch operation mode to "CDN friendly" and use HTML altering.
452
453
### WebP Express / ShortPixel setup
454
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.
564
565
I have only tested the above in *Varied image responses* mode, but it should also work in *CDN friendly* mode. Both *Alter HTML* options have been designed to work with standard lazy load attributes.
566
567
+ = Can I make an exceptions for some images? =
568
+ There can be instances where you actually need to serve a jpeg or png. For example if you are demonstrating how a jpeg looks using some compression settings. It is possible to bypass both the redirection and the HTML altering for certain images. Here is how:
569
+
570
+ *Alter HTML*
571
+ Alter HTML is programmed not to substitute image URLs with query strings (better safe than sorry). You can exploit that and simply add ie ?original to the image URLs in question.
572
+
573
+ *Redirection*
574
+ To bypass the *redirection*, you can add the following in the `.htaccess` where *WebP Express* has placed its rules (this is usually in the `wp-content` folder). The rules needs to be added *above* the rules inserted by *WebP Express*.
575
+
576
+ `
577
+ RewriteCond %{QUERY_STRING} original
578
+ RewriteCond %{REQUEST_FILENAME} -f
579
+ RewriteRule . - [L]
580
+ `
581
+ With those rules in place, you can add "?original" to the URLs of those images that you want to keep serving as jpg / png.
582
+
583
+ Alternatively, you can specify the filenames individually in the `.htaccess`:
584
+
585
+ `
586
+ RewriteRule ^uploads/2019/02/example-of-jpg-compressed-to-80\.jpg - [L]
587
+ RewriteRule ^uploads/2019/02/image2\.jpg - [L]
588
+ RewriteRule . - [L]
589
+ `
590
+ If you got any further questions, look at, or comment on [this topic](https://wordpress.org/support/topic/can-i-make-an-exception-for-specific-post-image/)
591
+
592
= When is feature X coming? / Roadmap =
593
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.
594
595
+ Here are my current plans ahead: 0.13 might be bulk conversion and addition of a 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 a file manager-like interface for inspecting generated webp files. 0.18 might be an effort to allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript librare does not (currently) support srcset attributes, which is why I moved this item down the priority list. We need srcset to be supported for the feature to be useful. 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
596
597
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.
598
604
1. WebP Express settings
605
606
== Changelog ==
607
+
608
+ = 0.12.0 =
609
+ *(released 5 mar 2019)*
610
+ * Multisite support (!)
611
+ * A new operation mode: "No conversion", if you do not want to use WebP Express for converting. Replaces the old "Just redirect" mode
612
+ * Added capability testing of .htaccess. The .htaccess rules are now tailored to the capabilities on the system. For example, on some platforms the filename of a requested image is passed to the converter script through the query string, but on platforms that supports passing it through an environment variable, that method is used instead
613
+ * Picturefill.js is now optional (alter html, picture tag)
614
+ * A great bunch more!
615
+
616
+ For more info, see the closed issues on the 0.12.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/12?closed=1
617
+
618
= 0.11.3 =
619
+ *(released 18 feb 2019)*
620
* Fixed bug: Alter HTML caused media library not to display images on some systems. Alter HTML is now disabled in admin mode.
621
* Alter HTML (picture tags) could produce the source tags with "src" attribute. But source tags inside picture tags must use "srcset" attribute. Fixed.
622
* Alter HTML (image urls): srcsets containing "x" descriptors wasn't handled (ie, srcset="image.jpg 1x")
625
* Fixed bug: The code that determined if WebP Express had placed rules in a .htaccess failed in "CDN friendly" mode. The effect was that these rules was not cleaned up upon plugin deactivation
626
627
= 0.11.2 =
628
+ *(released 14 feb 2019)*
629
* Fixed bug which caused Alter HTML to fail miserably on some setups
630
* AlterHTML now also looks for lazy load attributes in DIV and LI tags.
631
632
= 0.11.1 =
633
+ *(released 6 feb 2019)*
634
* Fixed bug which caused the new "Convert non-existing webp-files upon request" not to work on all setups
635
636
= 0.11.0 =
637
+ *(released 6 feb 2019)*
638
* Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
639
* Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
640
641
For more info, see the closed issues on the 0.11.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/14?closed=1
642
643
= 0.10.0 =
644
+ *(released 7 jan 2019)*
645
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
646
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
647
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
661
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
662
663
= 0.8.1 =
664
+ *(released 11 dec 2018)*
665
* Fixed javascript bug
666
667
= 0.8.0 =
668
+ *(released 11 dec 2018)*
669
* New conversion method, which calls imagick binary directly. This will make WebP express work out of the box on more systems
670
* Made sure not to trigger LFI warning i Wordfence (to activate, click the force .htaccess button)
671
* Imagick can now be configured to set quality to auto on systems where the auto option isn't generally available
676
For more info, see the closed issues on the 0.8.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.8.0
677
678
= 0.7.2 =
679
+ *(released 21 nov 2018)*
680
Fixed a critical bug which generated an error message which caused corrupt images. It was not the bug itself, but the error message it generated, that caused the images to be corrupted. It only happened when debugging was enabled in php.ini
681
682
= 0.7.1 =
683
+ *(released 9 nov 2018)*
684
Fixed minor "bug". The Api version combobox in Remote WebP Express converter was showing on new sites, but I only want it to show when old api is being used.
685
686
= 0.7.0 =
687
+ *(released 9 nov 2018)*
688
This version added option to provide conversion service to other sites!
689
690
For more info, see the closed issues on the 0.7.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.7.0
691
692
= 0.6.0 =
693
+ *(released 4 okt 2018)*
694
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
695
696
* Added option for caching
708
For more info, see the closed issues on the 0.6.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.6.0
709
710
= 0.5.0 =
711
+ *(released 14 sep 2018)*
712
This version works on many more setups than the previous. Also uses less resources and handles when images are changed.
713
714
* Configuration is now stored in a separate configuration file instead of storing directly in the *.htaccess* file and passing it on via query string. When updating, these settings are migrated automatically.
735
736
== Upgrade Notice ==
737
738
+ = 0.12.0 =
739
+ Multisite support and a new operation mode
740
+
741
= 0.11.3 =
742
Fixed several bugs. You should update :)
743
changelog.txt CHANGED
@@ -1,4 +1,15 @@
1
= 0.11.3 =
2
* Fixed bug: Alter HTML caused media library not to display images on some systems. Alter HTML is now disabled in admin mode.
3
* Alter HTML (picture tags) could produce the source tags with "src" attribute. But source tags inside picture tags must use "srcset" attribute. Fixed.
4
* Alter HTML (image urls): srcsets containing "x" descriptors wasn't handled (ie, srcset="image.jpg 1x")
@@ -7,19 +18,23 @@
7
* Fixed bug: The code that determined if WebP Express had placed rules in a .htaccess failed in "CDN friendly" mode. The effect was that these rules was not cleaned up upon plugin deactivation
8
9
= 0.11.2 =
10
* Fixed bug which caused Alter HTML to fail miserably on some setups
11
* AlterHTML now also looks for lazy load attributes in DIV and LI tags.
12
13
= 0.11.1 =
14
* Fixed bug which caused the new "Convert non-existing webp-files upon request" not to work on all setups
15
16
= 0.11.0 =
17
* Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
18
* Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
19
20
For more info, see the closed issues on the 0.11.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/14?closed=1
21
22
= 0.10.0 =
23
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
24
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
25
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
@@ -54,17 +69,21 @@ For more info, see the closed issues on the 0.9.0 milestone on the github reposi
54
For more info, see the closed issues on the 0.8.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.8.0
55
56
= 0.7.2 =
57
Fixed a critical bug which generated an error message which caused corrupt images. It was not the bug itself, but the error message it generated, that caused the images to be corrupted. It only happened when debugging was enabled in php.ini
58
59
= 0.7.1 =
60
Fixed minor "bug". The Api version combobox in Remote WebP Express converter was showing on new sites, but I only want it to show when old api is being used.
61
62
= 0.7.0 =
63
This version added option to provide conversion service to other sites!
64
65
For more info, see the closed issues on the 0.7.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.7.0
66
67
= 0.6.0 =
68
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
69
70
* Added option for caching
1
+ = 0.12.0 =
2
+ *(released 5 mar 2019)*
3
+ * Multisite support (!)
4
+ * A new operation mode: "No conversion", if you do not want to use WebP Express for converting. Replaces the old "Just redirect" mode
5
+ * Added capability testing of .htaccess. The .htaccess rules are now tailored to the capabilities on the system. For example, on some platforms the filename of a requested image is passed to the converter script through the query string, but on platforms that supports passing it through an environment variable, that method is used instead
6
+ * Picturefill.js is now optional (alter html, picture tag)
7
+ * A great bunch more!
8
+
9
+ For more info, see the closed issues on the 0.12.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/12?closed=1
10
+
11
= 0.11.3 =
12
+ *(released 18 feb 2019)*
13
* Fixed bug: Alter HTML caused media library not to display images on some systems. Alter HTML is now disabled in admin mode.
14
* Alter HTML (picture tags) could produce the source tags with "src" attribute. But source tags inside picture tags must use "srcset" attribute. Fixed.
15
* Alter HTML (image urls): srcsets containing "x" descriptors wasn't handled (ie, srcset="image.jpg 1x")
18
* Fixed bug: The code that determined if WebP Express had placed rules in a .htaccess failed in "CDN friendly" mode. The effect was that these rules was not cleaned up upon plugin deactivation
19
20
= 0.11.2 =
21
+ *(released 14 feb 2019)*
22
* Fixed bug which caused Alter HTML to fail miserably on some setups
23
* AlterHTML now also looks for lazy load attributes in DIV and LI tags.
24
25
= 0.11.1 =
26
+ *(released 6 feb 2019)*
27
* Fixed bug which caused the new "Convert non-existing webp-files upon request" not to work on all setups
28
29
= 0.11.0 =
30
+ *(released 6 feb 2019)*
31
* Alter HTML to point to webp files (choose between picture tags or simply altering all image urls)
32
* Convert non-existing webp-files upon request (means you can reference the converted webp files before they are actually converted!)
33
34
For more info, see the closed issues on the 0.11.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/milestone/14?closed=1
35
36
= 0.10.0 =
37
+ *(released 7 jan 2019)*
38
* Introduced "Operation modes" in order to keep setting screens simple but still allow tweaking
39
* WebP Express can now be used in conjunction with Cache Enabler and ShortPixel
40
* Cache-Control header is now added in *.htaccess*, when redirecting directly to existing webp
69
For more info, see the closed issues on the 0.8.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.8.0
70
71
= 0.7.2 =
72
+ *(released 21 nov 2018)*
73
Fixed a critical bug which generated an error message which caused corrupt images. It was not the bug itself, but the error message it generated, that caused the images to be corrupted. It only happened when debugging was enabled in php.ini
74
75
= 0.7.1 =
76
+ *(released 9 nov 2018)*
77
Fixed minor "bug". The Api version combobox in Remote WebP Express converter was showing on new sites, but I only want it to show when old api is being used.
78
79
= 0.7.0 =
80
+ *(released 9 nov 2018)*
81
This version added option to provide conversion service to other sites!
82
83
For more info, see the closed issues on the 0.7.0 milestone on the github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.7.0
84
85
= 0.6.0 =
86
+ *(released 4 okt 2018)*
87
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
88
89
* Added option for caching
docs/development.md CHANGED
@@ -1,3 +1,3 @@
1
The plugin published on github now uses composer. I still include the vendor files on the svn (the Wordpress "codex").
2
3
- For the few, who might be using this thing here on github: To get the dependent libraries, you need to cd into the plugin dir and run `composer update`. This gets you the latest dev releases of "webp-convert" and "webp-convert-cloud-service" on github. You must change the composer.json if you rather want the latest stable release (remove the repositories and change the minimum requirements). On the svn, I simply rsync everything, including the vendor folder, before committing.
1
The plugin published on github now uses composer. I still include the vendor files on the svn (the Wordpress "codex").
2
3
+ For the few, who might be using this thing here on github: To get the dependent libraries, you need to cd into the plugin dir and run `composer install`. This gets you the latest dev releases of "webp-convert" and "webp-convert-cloud-service" on github. You must change the composer.json if you rather want the latest stable release (remove the repositories and change the minimum requirements). On the svn, I simply rsync everything, including the vendor folder, before committing.
htaccess-capability-tests/.htaccess ADDED
@@ -0,0 +1,6 @@
1
+ <IfModule mod_rewrite.c>
2
+ #RewriteEngine on
3
+ #RewriteCond %{REQUEST_URI} !request-uri-usable
4
+ #RewriteRule ^(.*)$ request-uri-usable/$1
5
+
6
+ </IfModule>
htaccess-capability-tests/has-mod-header/.htaccess ADDED
@@ -0,0 +1,3 @@
1
+ <IfModule mod_headers.c>
2
+ RequestHeader set HEADERFORTEST "test"
3
+ </IfModule>
htaccess-capability-tests/has-mod-header/test.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ //echo '<pre>'. print_r($_SERVER, 1) . '</pre>';
4
+
5
+ if (isset($_SERVER['HTTP_HEADERFORTEST'])) {
6
+ echo ($_SERVER['HTTP_HEADERFORTEST'] == 'test' ? 1 : 0);
7
+ exit;
8
+ }
9
+ echo '0';
htaccess-capability-tests/has-mod-rewrite/.htaccess ADDED
@@ -0,0 +1,11 @@
1
+ <IfModule mod_rewrite.c>
2
+
3
+ # Testing for mod_rewrite
4
+ # -----------------------
5
+ # If mod_rewrite is enabled, redirect to 1.php, which returns "1".
6
+ # If mod_rewrite is disabled, the rewriting fails, and we end at test.php, which always returns 0.
7
+
8
+ RewriteEngine On
9
+ RewriteRule ^test\.php$ 1.php [L]
10
+
11
+ </IfModule>
htaccess-capability-tests/has-mod-rewrite/1.php ADDED
@@ -0,0 +1,2 @@
1
+ <?php
2
+ echo '1';
htaccess-capability-tests/has-mod-rewrite/test.php ADDED
@@ -0,0 +1,2 @@
1
+ <?php
2
+ echo '0';
htaccess-capability-tests/pass-server-var-through-header/.htaccess ADDED
@@ -0,0 +1,15 @@
1
+
2
+
3
+
4
+ <IfModule mod_rewrite.c>
5
+ RewriteEngine On
6
+
7
+ # PASSTHROUGHHEADERing if we can pass environment variable through request header
8
+ # We pass document root, because that can easily be checked by the script
9
+
10
+ <IfModule mod_headers.c>
11
+ RequestHeader set PASSTHROUGHHEADER "%{PASSTHROUGHHEADER}e" env=PASSTHROUGHHEADER
12
+ </IfModule>
13
+ RewriteRule ^test\.php$ - [E=PASSTHROUGHHEADER:%{DOCUMENT_ROOT},L]
14
+
15
+ </IfModule>
htaccess-capability-tests/pass-server-var-through-header/test.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ //echo '<pre>'. print_r($_SERVER, 1) . '</pre>';
4
+
5
+ if (isset($_SERVER['HTTP_PASSTHROUGHHEADER'])) {
6
+ echo ($_SERVER['HTTP_PASSTHROUGHHEADER'] == $_SERVER['DOCUMENT_ROOT'] ? 1 : 0);
7
+ exit;
8
+ }
9
+ echo '0';
htaccess-capability-tests/pass-through-environment-var/.htaccess ADDED
@@ -0,0 +1,13 @@
1
+
2
+
3
+
4
+
5
+ <IfModule mod_rewrite.c>
6
+
7
+ # Testing if we can pass environment variable from .htaccess to script in a RewriteRule
8
+ # We pass document root, because that can easily be checked by the script
9
+
10
+ RewriteEngine On
11
+ RewriteRule ^test\.php$ - [E=PASSTHROUGHENV:%{DOCUMENT_ROOT},L]
12
+
13
+ </IfModule>
htaccess-capability-tests/pass-through-environment-var/test.php ADDED
@@ -0,0 +1,27 @@
1
+ <?php
2
+
3
+ /**
4
+ * Get environment variable set with mod_rewrite module
5
+ * Return false if the environment variable isn't found
6
+ */
7
+ function getEnvPassedInRewriteRule($envName) {
8
+ // Envirenment variables passed through the REWRITE module have "REWRITE_" as a prefix (in Apache, not Litespeed, if I recall correctly)
9
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
10
+ // We simply look for an environment variable that ends with what we are looking for.
11
+ // (so make sure to make it unique)
12
+ $len = strlen($envName);
13
+ foreach ($_SERVER as $key => $item) {
14
+ if (substr($key, -$len) == $envName) {
15
+ return $item;
16
+ }
17
+ }
18
+ return false;
19
+ }
20
+
21
+
22
+ $result = getEnvPassedInRewriteRule('PASSTHROUGHENV');
23
+ if ($result === false) {
24
+ echo '0';
25
+ exit;
26
+ }
27
+ echo ($result == $_SERVER['DOCUMENT_ROOT'] ? '1' : '0');
htaccess-capability-tests/request-uri-usable-in-this-dir/.htaccess ADDED
@@ -0,0 +1,11 @@
1
+ <IfModule mod_rewrite.c>
2
+
3
+ # Testing for mod_rewrite
4
+ # -----------------------
5
+ # If mod_rewrite is enabled, redirect to 1.php, which returns "1".
6
+ # If mod_rewrite is disabled, the rewriting fails, and we end at test.php, which always returns 0.
7
+
8
+ RewriteEngine On
9
+ RewriteRule ^test\.php$ test2.php [L]
10
+
11
+ </IfModule>
htaccess-capability-tests/request-uri-usable-in-this-dir/test.php ADDED
@@ -0,0 +1,3 @@
1
+ <?php
2
+
3
+ echo '0';
htaccess-capability-tests/request-uri-usable-in-this-dir/test2.php ADDED
@@ -0,0 +1,51 @@
1
+ <?php
2
+
3
+ //echo '<pre>'. print_r($_SERVER, 1) . '</pre>';
4
+
5
+ /*
6
+ Something like this is fine
7
+ [REQUEST_URI] => /wp-content/webp-express/capability-tests/request-uri-usable/test.php
8
+ [SCRIPT_NAME] => /wp-content/webp-express/capability-tests/request-uri-usable/test2.php
9
+
10
+ But this is indication of failure:
11
+ [REQUEST_URI] => /wp-content/webp-express/capability-tests/request-uri-usable/test.php
12
+ [SCRIPT_NAME] => /my_subdir/wp-content/webp-express/capability-tests/request-uri-usable/test2.php
13
+ */
14
+
15
+ function stripFilename($dirName) {
16
+ //echo 'dir:' . $dirName . '<br>';
17
+ //echo 'pos: ' . strrpos($dirName, '/') . '<br>';
18
+ return substr($dirName, 0, strrpos($dirName, '/'));
19
+
20
+ }
21
+ //echo stripFilename($_SERVER['REQUEST_URI']) . '<br>';
22
+ //echo stripFilename($_SERVER['SCRIPT_NAME']) . '<br>';
23
+
24
+ $equalDirs = (stripFilename($_SERVER['REQUEST_URI']) == stripFilename($_SERVER['SCRIPT_NAME']));
25
+
26
+ echo $equalDirs ? '1' : '0';
27
+
28
+
29
+ //echo preg_match('#$#')
30
+
31
+ //$_SERVER['REQUEST_URI'];
32
+ //$_SERVER['SCRIPT_NAME'];
33
+
34
+
35
+ /*
36
+ function getEnvPassedInRewriteRule($envName) {
37
+ // Envirenment variables passed through the REWRITE module have "REWRITE_" as a prefix (in Apache, not Litespeed)
38
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
39
+ // We simply look for an environment variable that ends with what we are looking for.
40
+ // (so make sure to make it unique)
41
+ $len = strlen($envName);
42
+ foreach ($_SERVER as $key => $item) {
43
+ if (substr($key, -$len) == $envName) {
44
+ return $item;
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+
50
+ //$result = getEnvPassedInRewriteRule('PASSTHROUGHENV');
51
+ */
htaccess-capability-tests/urls.txt ADDED
@@ -0,0 +1,12 @@
1
+ We 0:
2
+
3
+ http://we0/wp-content-moved/webp-express/capability-tests/has-mod-rewrite/test.php
4
+ http://we0/wp-content-moved/webp-express/capability-tests/pass-through-environment-var/test.php
5
+ http://we0/wp-content-moved/webp-express/capability-tests/pass-server-var-through-header/test.php
6
+ http://we0/wp-content-moved/webp-express/capability-tests/request-uri-usable/test.php
7
+
8
+
9
+
10
+ We 7:
11
+ ------
12
+ http://we7/wp-content/webp-express/capability-tests/request-uri-usable/test.php
lib/activate-first-time.php CHANGED
@@ -3,6 +3,9 @@
3
include_once __DIR__ . '/classes/Actions.php';
4
use \WebPExpress\Actions;
5
6
include_once __DIR__ . '/classes/Config.php';
7
use \WebPExpress\Config;
8
@@ -18,31 +21,31 @@ use \WebPExpress\PlatformInfo;
18
include_once __DIR__ . '/classes/State.php';
19
use \WebPExpress\State;
20
21
// First check basic requirements.
22
// -------------------------------
23
24
if (PlatformInfo::isMicrosoftIis()) {
25
- Messenger::addMessage('error', 'You are on Microsof IIS server. The plugin does not work on IIS (yet). The plugin has been <i>deactivated</i> again!');
26
- Actions::procastinate('deactivate');
27
-
28
- // Well, that was it.
29
- return;
30
}
31
32
33
if ( is_multisite() ) {
34
- Messenger::addMessage('error', 'You are on multisite. It is not supported yet. BUT IT IS ON THE ROADMAP! Stay tuned! The plugin has been <i>deactivated</i> again!');
35
- Actions::procastinate('deactivate');
36
- return;
37
}
38
39
if (!version_compare(PHP_VERSION, '5.5.0', '>=')) {
40
- //$msg = sprintf(__( 'You are on a very old version of PHP (%s). WebP Express may not work as intended.', 'webp-express' ), phpversion());
41
Messenger::addMessage(
42
'warning',
43
'You are on a very old version of PHP. WebP Express may not work correctly. Your PHP version:' . phpversion()
44
);
45
- return;
46
}
47
48
// Next issue warnings, if any
@@ -66,3 +69,6 @@ Messenger::addMessage(
66
'WebP Express was installed successfully. To start using it, you must ' .
67
'<a href="' . Paths::getSettingsUrl() . '">configure it here</a>.'
68
);
3
include_once __DIR__ . '/classes/Actions.php';
4
use \WebPExpress\Actions;
5
6
+ include_once __DIR__ . '/classes/CapabilityTest.php';
7
+ use \WebPExpress\CapabilityTest;
8
+
9
include_once __DIR__ . '/classes/Config.php';
10
use \WebPExpress\Config;
11
21
include_once __DIR__ . '/classes/State.php';
22
use \WebPExpress\State;
23
24
+
25
// First check basic requirements.
26
// -------------------------------
27
28
if (PlatformInfo::isMicrosoftIis()) {
29
+ Messenger::addMessage(
30
+ 'warning',
31
+ 'You are on Microsoft IIS server. The developer of WebP Express has no money for Microsoft products, so no testing have been done on IIS. Use at own risk. If you are on WAMP, things might work. Without Apache, you will need to create redirect rules yourself.'
32
+ );
33
}
34
35
36
if ( is_multisite() ) {
37
+ Messenger::addMessage(
38
+ 'warning',
39
+ 'Multisite functionality in WebP Express has just been added with current release (0.12.0). ' .
40
+ 'While it has been tested on several setups, there might be a bug or two yet to be found.'
41
+ );
42
}
43
44
if (!version_compare(PHP_VERSION, '5.5.0', '>=')) {
45
Messenger::addMessage(
46
'warning',
47
'You are on a very old version of PHP. WebP Express may not work correctly. Your PHP version:' . phpversion()
48
);
49
}
50
51
// Next issue warnings, if any
69
'WebP Express was installed successfully. To start using it, you must ' .
70
'<a href="' . Paths::getSettingsUrl() . '">configure it here</a>.'
71
);
72
+
73
+ // While not neccessary, lets get those tests copied right away. Some servers are a bit slow to pick up on changes in the filesystem
74
+ CapabilityTest::copyCapabilityTestsToWpContent();
lib/admin.php CHANGED
@@ -1,23 +1,26 @@
1
<?php
2
use \WebPExpress\State;
3
4
// When an update requires a migration, the number should be increased
5
- define('WEBPEXPRESS_MIGRATION_VERSION', '6');
6
7
- if (WEBPEXPRESS_MIGRATION_VERSION != get_option('webp-express-migration-version', 0)) {
8
// run migration logic
9
include __DIR__ . '/migrate/migrate.php';
10
}
11
12
// uncomment next line to test-run a migration
13
- // include __DIR__ . '/migrate/migrate6.php';
14
15
// uncomment next line to debug an error during activation
16
//include __DIR__ . "/debug.php";
17
18
include __DIR__ . '/options/options-hooks.php';
19
20
- register_activation_hook(WEBPEXPRESS_PLUGIN, function () {
21
include __DIR__ . '/activate-hook.php';
22
});
23
@@ -25,13 +28,14 @@ register_deactivation_hook(WEBPEXPRESS_PLUGIN, function () {
25
include __DIR__ . '/deactivate.php';
26
});
27
28
- if (get_option('webp-express-messages-pending')) {
29
include_once __DIR__ . '/classes/Messenger.php';
30
- add_action( 'admin_notices', function() {
31
\WebPExpress\Messenger::printPendingMessages();
32
});
33
}
34
- if (get_option('webp-express-actions-pending')) {
35
include_once __DIR__ . '/classes/Actions.php';
36
\WebPExpress\Actions::processQueuedActions();
37
}
@@ -46,9 +50,24 @@ register_uninstall_hook(WEBPEXPRESS_PLUGIN, 'webp_express_uninstall');
46
47
// Add settings link on the plugins page
48
add_filter('plugin_action_links_' . plugin_basename(WEBPEXPRESS_PLUGIN), function ( $links ) {
49
$mylinks = array(
50
- '<a href="' . admin_url( 'options-general.php?page=webp_express_settings_page' ) . '">Settings</a>',
51
- '<a href="https://ko-fi.com/rosell" target="_blank">Buy the maintainer a cup of coffee</a>',
52
);
53
return array_merge($links, $mylinks);
54
});
1
<?php
2
use \WebPExpress\State;
3
+ use \WebPExpress\Option;
4
+ use \WebPExpress\Multisite;
5
6
// When an update requires a migration, the number should be increased
7
+ define('WEBPEXPRESS_MIGRATION_VERSION', '7');
8
9
+ if (WEBPEXPRESS_MIGRATION_VERSION != Option::getOption('webp-express-migration-version', 0)) {
10
// run migration logic
11
include __DIR__ . '/migrate/migrate.php';
12
}
13
14
// uncomment next line to test-run a migration
15
+ //include __DIR__ . '/migrate/migrate7.php';
16
17
// uncomment next line to debug an error during activation
18
//include __DIR__ . "/debug.php";
19
20
include __DIR__ . '/options/options-hooks.php';
21
22
+ register_activation_hook(WEBPEXPRESS_PLUGIN, function ($network_active) {
23
+ Multisite::overrideIsNetworkActivated($network_active);
24
include __DIR__ . '/activate-hook.php';
25
});
26
28
include __DIR__ . '/deactivate.php';
29
});
30
31
+ if (Option::getOption('webp-express-messages-pending')) {
32
include_once __DIR__ . '/classes/Messenger.php';
33
+
34
+ add_action(Multisite::isNetworkActivated() ? 'network_admin_notices' : 'admin_notices', function() {
35
\WebPExpress\Messenger::printPendingMessages();
36
});
37
}
38
+ if (Option::getOption('webp-express-actions-pending')) {
39
include_once __DIR__ . '/classes/Actions.php';
40
\WebPExpress\Actions::processQueuedActions();
41
}
50
51
// Add settings link on the plugins page
52
add_filter('plugin_action_links_' . plugin_basename(WEBPEXPRESS_PLUGIN), function ( $links ) {
53
+ if (Multisite::isNetworkActivated()) {
54
+ $mylinks= [
55
+ '<a href="https://ko-fi.com/rosell" target="_blank">donate?</a>',
56
+ ];
57
+ } else {
58
+ $mylinks = array(
59
+ '<a href="' . admin_url('options-general.php?page=webp_express_settings_page') . '">Settings</a>',
60
+ '<a href="https://ko-fi.com/rosell" target="_blank">Provide coffee for the developer</a>',
61
+ );
62
+
63
+ }
64
+ return array_merge($links, $mylinks);
65
+ });
66
+
67
+ add_filter('network_admin_plugin_action_links_' . plugin_basename(WEBPEXPRESS_PLUGIN), function ( $links ) {
68
$mylinks = array(
69
+ '<a href="' . network_admin_url('settings.php?page=webp_express_settings_page') . '">Settings</a>',
70
+ '<a href="https://ko-fi.com/rosell" target="_blank">donate?</a>',
71
);
72
return array_merge($links, $mylinks);
73
});
lib/classes/Actions.php CHANGED
@@ -5,6 +5,8 @@ namespace WebPExpress;
5
include_once "State.php";
6
use \WebPExpress\State;
7
8
/**
9
*
10
*/
@@ -15,7 +17,7 @@ class Actions
15
* $action: identifier
16
*/
17
public static function procastinate($action) {
18
- update_option('webp-express-actions-pending', true, true);
19
20
$pendingActions = State::getState('pendingActions', []);
21
$pendingActions[] = $action;
@@ -40,7 +42,7 @@ class Actions
40
}
41
42
State::setState('pendingActions', []);
43
- update_option('webp-express-actions-pending', false, true);
44
45
}
46
}
5
include_once "State.php";
6
use \WebPExpress\State;
7
8
+ use \WebPExpress\Option;
9
+
10
/**
11
*
12
*/
17
* $action: identifier
18
*/
19
public static function procastinate($action) {
20
+ Option::updateOption('webp-express-actions-pending', true, true);
21
22
$pendingActions = State::getState('pendingActions', []);
23
$pendingActions[] = $action;
42
}
43
44
State::setState('pendingActions', []);
45
+ Option::updateOption('webp-express-actions-pending', false, true);
46
47
}
48
}
lib/classes/AlterHtmlHelper.php CHANGED
@@ -10,6 +10,10 @@ use \WebPExpress\Paths;
10
include_once "PathHelper.php";
11
use \WebPExpress\PathHelper;
12
13
class AlterHtmlHelper
14
{
15
@@ -144,6 +148,7 @@ class AlterHtmlHelper
144
*/
145
private static function getWebPUrlInBase($sourceUrl, $baseUrl, $baseDir)
146
{
147
148
$srcPathRel = self::getRelUrlPath($sourceUrl, $baseUrl);
149
@@ -205,7 +210,7 @@ class AlterHtmlHelper
205
public static function getWebPUrl($sourceUrl, $returnValueOnFail)
206
{
207
if (!isset(self::$options)) {
208
- self::$options = json_decode(get_option('webp-express-alter-html-options', null), true);
209
}
210
211
@@ -239,6 +244,10 @@ class AlterHtmlHelper
239
}
240
241
foreach (self::$options['bases'] as $id => list($baseDir, $baseUrl)) {
242
243
$result = self::getWebPUrlInBase($sourceUrl, $baseUrl, $baseDir);
244
if ($result !== false) {
10
include_once "PathHelper.php";
11
use \WebPExpress\PathHelper;
12
13
+ use \WebPExpress\Multisite;
14
+
15
+ use \WebPExpress\Option;
16
+
17
class AlterHtmlHelper
18
{
19
148
*/
149
private static function getWebPUrlInBase($sourceUrl, $baseUrl, $baseDir)
150
{
151
+ //error_log('getWebPUrlInBase:' . $sourceUrl . ':' . $baseUrl . ':' . $baseDir);
152
153
$srcPathRel = self::getRelUrlPath($sourceUrl, $baseUrl);
154
210
public static function getWebPUrl($sourceUrl, $returnValueOnFail)
211
{
212
if (!isset(self::$options)) {
213
+ self::$options = json_decode(Option::getOption('webp-express-alter-html-options', null), true);
214
}
215
216
244
}
245
246
foreach (self::$options['bases'] as $id => list($baseDir, $baseUrl)) {
247
+ if (Multisite::isMultisite() && ($id == 'uploads')) {
248
+ $baseUrl = Paths::getUploadUrl();
249
+ $baseDir = Paths::getUploadDirAbs();
250
+ }
251
252
$result = self::getWebPUrlInBase($sourceUrl, $baseUrl, $baseDir);
253
if ($result !== false) {
lib/classes/AlterHtmlImageUrls.php CHANGED
@@ -32,52 +32,4 @@ class AlterHtmlImageUrls extends ImageUrlReplacer
32
//return preg_match('#^(src|srcset|data-(src|srcset|cvpsrc|cvpset|thumb|bg-url|large_image|lazyload|source-url|srcsmall|srclarge|srcfull|slide-img|lazy-original))$#i', $attrName);
33
}
34
35
- /*
36
- public static function alter($content) {
37
- require_once "AlterHtmlHelper.php";
38
-
39
-
40
- //Find image urls in HTML attributes.
41
- //- Ignore URLs with query string
42
- //- Matches src, src-set and data-attributes in a limited set of tags
43
- //- Only jpeg, jpg or png (NO GIFs)
44
- //- Both relative and absolute URLs are matched
45
- //- tag name is returned in $1, url in amp;
46
-
47
- //Pattern for attributes can be tested here: https://regexr.com/46jat
48
- //PS: Based on regex found in Cache Enabler 1.3.2: https://regexr.com/46isf
49
-
50
- //TODO: Dont match PNG, unless choosen
51
- $regex_rule = '#(?<=(?:<(img|source|input|iframe)[^>]*\s+(src|srcset|data-[^=]*)\s*=\s*[\"\']?))(?:[^\"\'>]+)(\.png|\.jp[e]?g)(\s\d+w)?(?=\/?[\"\'\s\>])#';
52
- return preg_replace_callback($regex_rule, 'self::replaceCallback', $content);
53
-
54
- // TODO: css too. I already got the regex ready: https://regexr.com/46jcg
55
-
56
-
57
- }
58
-
59
- /*
60
- private static function replaceCallback($match) {
61
- list($attrValue, $attrName) = $match;
62
-
63
- // A data attribute contain a srcset or single url.
64
- // We should probably examine the attrValue further. For now, we however just use the attrName as a clue.
65
- // If it contains "set", we handle it as a srcset. This takes care of both "data-cvpset" and "srcset"
66
- if (strpos($attrName, 'set') > 0) {
67
- $srcsetArr = explode(',', $attrValue);
68
- foreach ($srcsetArr as $i => $srcSetEntry) {
69
- // $srcSetEntry is ie "http://example.com/image.jpg 520w"
70
- list($src, $width) = preg_split('/\s+/', trim($srcSetEntry)); // $width might not be set, but thats ok.
71
-
72
- $webpUrl = \WebPExpress\AlterHtmlHelper::getWebPUrl($src, false);
73
- if ($webpUrl !== false) {
74
- $srcsetArr[$i] = $webpUrl . (isset($width) ? ' ' . $width : '');
75
- }
76
- }
77
- return implode(', ', $srcsetArr);
78
- } else {
79
- return \WebPExpress\AlterHtmlHelper::getWebPUrl($attrValue, $attrValue);
80
- }
81
- }*/
82
-
83
}
32
//return preg_match('#^(src|srcset|data-(src|srcset|cvpsrc|cvpset|thumb|bg-url|large_image|lazyload|source-url|srcsmall|srclarge|srcfull|slide-img|lazy-original))$#i', $attrName);
33
}
34
35
}
lib/classes/AlterHtmlInit.php CHANGED
@@ -5,6 +5,8 @@ namespace WebPExpress;
5
include_once "AlterHtmlHelper.php";
6
use AlterHtmlHelper;
7
8
class AlterHtmlInit
9
{
10
public static $options = null;
@@ -27,7 +29,7 @@ class AlterHtmlInit
27
return $content;
28
}
29
30
- if (get_option('webp-express-alter-html-replacement') == 'picture') {
31
if(function_exists('is_amp_endpoint') && is_amp_endpoint()) {
32
//for AMP pages the <picture> tag is not allowed
33
return $content;
@@ -35,7 +37,7 @@ class AlterHtmlInit
35
}
36
37
if (!isset(self::$options)) {
38
- self::$options = json_decode(get_option('webp-express-alter-html-options', null), true);
39
//AlterHtmlHelper::$options = self::$options;
40
}
41
@@ -43,7 +45,7 @@ class AlterHtmlInit
43
return $content;
44
}
45
46
- if (get_option('webp-express-alter-html-replacement') == 'picture') {
47
require_once __DIR__ . "/../../vendor/autoload.php";
48
require_once __DIR__ . '/AlterHtmlHelper.php';
49
require_once __DIR__ . '/AlterHtmlPicture.php';
@@ -56,7 +58,7 @@ class AlterHtmlInit
56
}
57
}
58
59
- public static function addPictureJs()
60
{
61
// Don't do anything with the RSS feed.
62
// - and no need for PictureJs in the admin
@@ -67,7 +69,7 @@ class AlterHtmlInit
67
. 'if(!window.HTMLPictureElement && document.addEventListener) {'
68
. 'window.addEventListener("DOMContentLoaded", function() {'
69
. 'var s = document.createElement("script");'
70
- . 's.src = "' . plugins_url('/js/picturefill.min.js', __FILE__) . '";'
71
. 'document.body.appendChild(s);'
72
. '});'
73
. '}'
@@ -76,11 +78,11 @@ class AlterHtmlInit
76
77
public static function setHooks() {
78
79
- if (get_option('webp-express-alter-html-replacement') == 'picture') {
80
- // add_action( 'wp_head', '\\WebPExpress\\AlterHtmlInit::addPictureJs');
81
}
82
83
- if (get_option('webp-express-alter-html-hooks', 'ob') == 'ob') {
84
/* TODO:
85
Which hook should we use, and should we make it optional?
86
- Cache enabler uses 'template_redirect'
5
include_once "AlterHtmlHelper.php";
6
use AlterHtmlHelper;
7
8
+ use \WebPExpress\Option;
9
+
10
class AlterHtmlInit
11
{
12
public static $options = null;
29
return $content;
30
}
31
32
+ if (Option::getOption('webp-express-alter-html-replacement') == 'picture') {
33
if(function_exists('is_amp_endpoint') && is_amp_endpoint()) {
34
//for AMP pages the <picture> tag is not allowed
35
return $content;
37
}
38
39
if (!isset(self::$options)) {
40
+ self::$options = json_decode(Option::getOption('webp-express-alter-html-options', null), true);
41
//AlterHtmlHelper::$options = self::$options;
42
}
43
45
return $content;
46
}
47
48
+ if (Option::getOption('webp-express-alter-html-replacement') == 'picture') {
49
require_once __DIR__ . "/../../vendor/autoload.php";
50
require_once __DIR__ . '/AlterHtmlHelper.php';
51
require_once __DIR__ . '/AlterHtmlPicture.php';
58
}
59
}
60
61
+ public static function addPictureFillJs()
62
{
63
// Don't do anything with the RSS feed.
64
// - and no need for PictureJs in the admin
69
. 'if(!window.HTMLPictureElement && document.addEventListener) {'
70
. 'window.addEventListener("DOMContentLoaded", function() {'
71
. 'var s = document.createElement("script");'
72
+ . 's.src = "' . plugins_url('/js/picturefill.min.js', WEBPEXPRESS_PLUGIN) . '";'
73
. 'document.body.appendChild(s);'
74
. '});'
75
. '}'
78
79
public static function setHooks() {
80
81
+ if (Option::getOption('webp-express-alter-html-add-picturefill-js')) {
82
+ add_action( 'wp_head', '\\WebPExpress\\AlterHtmlInit::addPictureFillJs');
83
}
84
85
+ if (Option::getOption('webp-express-alter-html-hooks', 'ob') == 'ob') {
86
/* TODO:
87
Which hook should we use, and should we make it optional?
88
- Cache enabler uses 'template_redirect'
lib/classes/CapabilityTest.php ADDED
@@ -0,0 +1,96 @@
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ use \WebPExpress\FileHelper;
6
+ use \WebPExpress\Paths;
7
+
8
+ class CapabilityTest
9
+ {
10
+
11
+ public static function copyCapabilityTestsToWpContent()
12
+ {
13
+ return FileHelper::cpdir(Paths::getWebPExpressPluginDirAbs() . '/htaccess-capability-tests', Paths::getWebPExpressContentDirAbs() . '/htaccess-capability-tests');
14
+ }
15
+
16
+
17
+ /**
18
+ * Run one of the tests in wp-content/webp-express/capability-tests
19
+ * Three possible outcomes: true, false or null (null if request fails)
20
+ */
21
+ public static function runTest($testDir)
22
+ {
23
+ //echo 'running test:' . $testDir . '<br>';
24
+ if (!@file_exists(Paths::getWebPExpressPluginDirAbs() . '/htaccess-capability-tests/' . $testDir)) {
25
+ // test does not even exist
26
+ //echo 'test does not exist: ' . $testDir . '<br>';
27
+ return null;
28
+ }
29
+
30
+ if (!@file_exists(Paths::getWebPExpressContentDirAbs() . '/htaccess-capability-tests/' . $testDir)) {
31
+ self::copyCapabilityTestsToWpContent();
32
+ }
33
+
34
+ // If copy failed, we can use the test in plugin path
35
+ if (!@file_exists(Paths::getWebPExpressContentDirAbs() . '/htaccess-capability-tests/' . $testDir)) {
36
+ $testUrl = Paths::getContentUrl() . '/' . 'webp-express/htaccess-capability-tests/' . $testDir . '/test.php';
37
+ } else {
38
+ $testUrl = Paths::getPluginUrl() . '/' . 'htaccess-capability-tests/' . $testDir . '/test.php';
39
+ }
40
+
41
+ //echo 'test url: ' . $testUrl . '<br>';
42
+ // TODO: Should we test if wp_remote_get exists first? - and if not, include wp-includes/http.php ?
43
+
44
+ $response = wp_remote_get($testUrl, ['timeout' => 10]);
45
+ //echo '<pre>' . print_r($response, true) . '</pre>';
46
+ if (wp_remote_retrieve_response_code($response) != '200') {
47
+ return null;
48
+ }
49
+ $responseBody = wp_remote_retrieve_body($response);
50
+ if ($responseBody == '') {
51
+ return null; // Some failure
52
+ }
53
+ if ($responseBody == '0') {
54
+ return false;
55
+ }
56
+ if ($responseBody == '1') {
57
+ return true;
58
+ }
59
+ return null;
60
+ }
61
+
62
+
63
+ /**
64
+ * Three possible outcomes: true, false or null (null if failed to run test)
65
+ */
66
+ public static function modRewriteWorking()
67
+ {
68
+ return self::runTest('has-mod-rewrite');
69
+ }
70
+
71
+ /**
72
+ * Three possible outcomes: true, false or null (null if failed to run test)
73
+ */
74
+ public static function modHeaderWorking()
75
+ {
76
+ return self::runTest('has-mod-header');
77
+ }
78
+
79
+ /**
80
+ * Three possible outcomes: true, false or null (null if failed to run test)
81
+ */
82
+ public static function passThroughEnvWorking()
83
+ {
84
+ return self::runTest('pass-through-environment-var');
85
+ }
86
+
87
+ /**
88
+ * Three possible outcomes: true, false or null (null if failed to run test)
89
+ */
90
+ public static function passThroughHeaderWorking()
91
+ {
92
+ return self::runTest('pass-server-var-through-header');
93
+ }
94
+
95
+
96
+ }
lib/classes/Config.php CHANGED
@@ -23,6 +23,8 @@ use \WebPExpress\State;
23
include_once "TestRun.php";
24
use \WebPExpress\TestRun;
25
26
class Config
27
{
28
@@ -67,14 +69,14 @@ class Config
67
68
return [
69
70
- 'operation-mode' => 'varied-responses',
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
'enable-redirection-to-webp-realizer' => true,
@@ -101,8 +103,9 @@ class Config
101
'enabled' => false,
102
'replacement' => 'picture', // "picture" or "url"
103
'hooks' => 'ob', // "content-hooks" or "ob"
104
- 'only-for-webp-enabled-browsers' => false, // If true, there will be two HTML versions of each page
105
'only-for-webps-that-exists' => false,
106
],
107
108
// web service
@@ -130,29 +133,30 @@ class Config
130
public static function applyOperationMode($config)
131
{
132
if (!isset($config['operation-mode'])) {
133
- $config['operation-mode'] = 'varied-responses';
134
}
135
136
- if ($config['operation-mode'] == 'varied-responses') {
137
$config = array_merge($config, [
138
'enable-redirection-to-converter' => true,
139
'only-redirect-to-converter-for-webp-enabled-browsers' => true,
140
'only-redirect-to-converter-on-cache-miss' => false,
141
- 'do-not-pass-source-in-query-string' => true,
142
//'redirect-to-existing-in-htaccess' => true,
143
'fail' => 'original',
144
'success-response' => 'converted',
145
]);
146
- } elseif ($config['operation-mode'] == 'no-varied-responses') {
147
$config = array_merge($config, [
148
'only-redirect-to-converter-for-webp-enabled-browsers' => false,
149
'only-redirect-to-converter-on-cache-miss' => true,
150
- 'do-not-pass-source-in-query-string' => true,
151
'redirect-to-existing-in-htaccess' => false,
152
'fail' => 'original',
153
'success-response' => 'original',
154
]);
155
- } elseif ($config['operation-mode'] == 'just-redirect') {
156
157
// TODO: Go through these...
158
@@ -161,6 +165,9 @@ class Config
161
'destination-folder' => 'mingled',
162
'enable-redirection-to-webp-realizer' => false,
163
]);
164
}
165
166
return $config;
@@ -188,13 +195,23 @@ class Config
188
$config = self::applyOperationMode($config);
189
190
if (!isset($config['web-service'])) {
191
- $config['web-service'] = [];
192
}
193
if (($config['cache-control'] == 'set') && ($config['cache-control-max-age'] == '')) {
194
$config['cache-control-max-age'] = 'one-week';
195
}
196
197
- if ($config['converters'] == null) {
198
$config['converters'] = [];
199
}
200
@@ -251,9 +268,20 @@ class Config
251
}
252
}
253
254
return $config;
255
}
256
257
/**
258
* Loads Config (if available), fills in the rest with defaults
259
* also applies operation mode.
@@ -372,11 +400,13 @@ class Config
372
{
373
$config = self::fix($config, false);
374
375
- update_option('webp-express-alter-html', $config['alter-html']['enabled'], true);
376
- update_option('webp-express-alter-html-hooks', $config['alter-html']['hooks'], true);
377
- update_option('webp-express-alter-html-replacement', $config['alter-html']['replacement'], true);
378
379
- //update_option('webp-express-alter-html', $config['alter-html']['enabled'], true);
380
381
$obj = $config['alter-html'];
382
unset($obj['enabled']);
@@ -394,7 +424,7 @@ class Config
394
];
395
$obj['image-types'] = $config['image-types']; // 0=none,1=jpg, 2=png, 3=both
396
397
- update_option(
398
'webp-express-alter-html-options',
399
json_encode($obj, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK),
400
true
@@ -551,6 +581,7 @@ class Config
551
*/
552
public static function saveConfigurationAndHTAccess($config, $forceRuleUpdating = false)
553
{
554
// Important to do this check before saving config, because the method
555
// compares against existing config.
556
@@ -594,4 +625,14 @@ class Config
594
];
595
}
596
}
597
}
23
include_once "TestRun.php";
24
use \WebPExpress\TestRun;
25
26
+ use \WebPExpress\Option;
27
+
28
class Config
29
{
30
69
70
return [
71
72
+ 'operation-mode' => 'varied-image-responses',
73
74
// redirection rules
75
'enable-redirection-to-converter' => true,
76
'image-types' => 1,
77
'only-redirect-to-converter-on-cache-miss' => false,
78
'only-redirect-to-converter-for-webp-enabled-browsers' => true,
79
+ 'do-not-pass-source-in-query-string' => false, // In 0.13 we can remove this. migration7.php depends on it
80
'redirect-to-existing-in-htaccess' => true,
81
'forward-query-string' => false,
82
'enable-redirection-to-webp-realizer' => true,
103
'enabled' => false,
104
'replacement' => 'picture', // "picture" or "url"
105
'hooks' => 'ob', // "content-hooks" or "ob"
106
+ 'only-for-webp-enabled-browsers' => true, // If true, there will be two HTML versions of each page
107
'only-for-webps-that-exists' => false,
108
+ 'alter-html-add-picturefill-js' => true,
109
],
110
111
// web service
133
public static function applyOperationMode($config)
134
{
135
if (!isset($config['operation-mode'])) {
136
+ $config['operation-mode'] = 'varied-image-responses';
137
}
138
139
+ if ($config['operation-mode'] == 'varied-image-responses') {
140
$config = array_merge($config, [
141
'enable-redirection-to-converter' => true,
142
'only-redirect-to-converter-for-webp-enabled-browsers' => true,
143
'only-redirect-to-converter-on-cache-miss' => false,
144
+ 'do-not-pass-source-in-query-string' => true, // Will be removed in 0.13
145
//'redirect-to-existing-in-htaccess' => true,
146
'fail' => 'original',
147
'success-response' => 'converted',
148
]);
149
+ } elseif ($config['operation-mode'] == 'cdn-friendly') {
150
$config = array_merge($config, [
151
'only-redirect-to-converter-for-webp-enabled-browsers' => false,
152
'only-redirect-to-converter-on-cache-miss' => true,
153
+ 'do-not-pass-source-in-query-string' => true, // Will be removed in 0.13
154
'redirect-to-existing-in-htaccess' => false,
155
'fail' => 'original',
156
'success-response' => 'original',
157
+ // cache-control => 'no-header' (we do not need this, as it is not important what it is set to in cdn-friendly mode, and we dont the value to be lost when switching operation mode)
158
]);
159
+ } elseif ($config['operation-mode'] == 'no-conversion') {
160
161
// TODO: Go through these...
162
165
'destination-folder' => 'mingled',
166
'enable-redirection-to-webp-realizer' => false,
167
]);
168
+ $config['alter-html']['only-for-webps-that-exists'] = true;
169
+ $config['web-service']['enabled'] = false;
170
+
171
}
172
173
return $config;
195
$config = self::applyOperationMode($config);
196
197
if (!isset($config['web-service'])) {
198
+ $config['web-service'] = [
199
+ 'enabled' => false
200
+ ];
201
}
202
+ if (!is_array($config['web-service']['whitelist'])) {
203
+ $config['web-service']['whitelist'] = [];
204
+ }
205
+ // remove whitelist entries without required fields (label, ip)
206
+ $config['web-service']['whitelist'] = array_filter($config['web-service']['whitelist'], function($var) {
207
+ return (isset($var['label']) && (isset($var['ip'])));
208
+ });
209
+
210
if (($config['cache-control'] == 'set') && ($config['cache-control-max-age'] == '')) {
211
$config['cache-control-max-age'] = 'one-week';
212
}
213
214
+ if (!is_array($config['converters'])) {
215
$config['converters'] = [];
216
}
217
268
}
269
}
270
271
+
272
return $config;
273
}
274
275
+
276
+ public static function runAndStoreCapabilityTests(&$config)
277
+ {
278
+ $config['base-htaccess-on-these-capability-tests'] = [
279
+ 'passThroughHeaderWorking' => CapabilityTest::passThroughHeaderWorking(),
280
+ 'passThroughEnvWorking' => CapabilityTest::passThroughEnvWorking(),
281
+ 'modHeaderWorking' => CapabilityTest::modHeaderWorking(),
282
+ ];
283
+ }
284
+
285
/**
286
* Loads Config (if available), fills in the rest with defaults
287
* also applies operation mode.
400
{
401
$config = self::fix($config, false);
402
403
+ Option::updateOption('webp-express-alter-html', $config['alter-html']['enabled'], true);
404
+ Option::updateOption('webp-express-alter-html-hooks', $config['alter-html']['hooks'], true);
405
+ Option::updateOption('webp-express-alter-html-replacement', $config['alter-html']['replacement'], true);
406
+ Option::updateOption('webp-express-alter-html-add-picturefill-js', (($config['alter-html']['replacement'] == 'picture') && (isset($config['alter-html']['alter-html-add-picturefill-js']) && $config['alter-html']['alter-html-add-picturefill-js'])), true);
407
+
408
409
+ //Option::updateOption('webp-express-alter-html', $config['alter-html']['enabled'], true);
410
411
$obj = $config['alter-html'];
412
unset($obj['enabled']);
424
];
425
$obj['image-types'] = $config['image-types']; // 0=none,1=jpg, 2=png, 3=both
426
427
+ Option::updateOption(
428
'webp-express-alter-html-options',
429
json_encode($obj, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK),
430
true
581
*/
582
public static function saveConfigurationAndHTAccess($config, $forceRuleUpdating = false)
583
{
584
+
585
// Important to do this check before saving config, because the method
586
// compares against existing config.
587
625
];
626
}
627
}
628
+
629
+ public static function getConverterByName($config, $converterName)
630
+ {
631
+ foreach ($config['converters'] as $i => $converter) {
632
+ if ($converter['converter'] == $converterName) {
633
+ return $converter;
634
+ }
635
+ }
636
+ }
637
+
638
}
lib/classes/FileHelper.php CHANGED
@@ -255,4 +255,46 @@ class FileHelper
255
}
256
}
257
258
}
255
}
256
}
257
258
+
259
+ /**
260
+ * Copy dir and all its files.
261
+ * Existing files are overwritten.
262
+ *
263
+ * @return $success
264
+ */
265
+ public static function cpdir($sourceDir, $destinationDir)
266
+ {
267
+ if (!@is_dir($sourceDir)) {
268
+ return false;
269
+ }
270
+ if (!@file_exists($destinationDir)) {
271
+ if (!@mkdir($destinationDir)) {
272
+ return false;
273
+ }
274
+ }
275
+
276
+ $fileIterator = new \FilesystemIterator($sourceDir);
277
+ $success = true;
278
+
279
+ while ($fileIterator->valid()) {
280
+ $filename = $fileIterator->getFilename();
281
+
282
+ if (($filename != ".") && ($filename != "..")) {
283
+ //$filePerm = FileHelper::filePermWithFallback($filename, 0777);
284
+
285
+ if (@is_dir($sourceDir . "/" . $filename)) {
286
+ if (!self::cpdir($sourceDir . "/" . $filename, $destinationDir . "/" . $filename)) {
287
+ $success = false;
288
+ }
289
+ } else {
290
+ // its a file.
291
+ if (!copy($sourceDir . "/" . $filename, $destinationDir . "/" . $filename)) {
292
+ $success = false;
293
+ }
294
+ }
295
+ }
296
+ $fileIterator->next();
297
+ }
298
+ return $success;
299
+ }
300
}
lib/classes/HTAccess.php CHANGED
@@ -23,6 +23,9 @@ class HTAccess
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,
@@ -40,6 +43,29 @@ class 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, and the "convert non-existing webp-files upon request" option has not been enabled)';
41
}
42
43
/* Calculate $fileExt */
44
$imageTypes = $config['image-types'];
45
$fileExtensions = [];
@@ -78,48 +104,54 @@ class HTAccess
78
$ccRules .= " </IfModule>\n\n";
79
80
// Fall back to mod_expires if mod_headers is unavailable
81
- $cacheControl = $config['cache-control'];
82
- if ($cacheControl == 'custom') {
83
- $expires = '';
84
-
85
- // Do not add Expire header if private is set
86
- // - because then the user don't want caching in proxies / CDNs.
87
- // the Expires header doesn't differentiate between private/public
88
- if (!(preg_match('/private/', $config['cache-control-custom']))) {
89
- if (preg_match('/max-age=(\d+)/', $config['cache-control-custom'], $matches)) {
90
- if (isset($matches[1])) {
91
- $expires = $matches[1] . ' seconds';
92
}
93
}
94
- }
95
96
- } elseif ($cacheControl == 'no-header') {
97
- $expires = '';
98
- } elseif ($cacheControl == 'set') {
99
- if ($config['cache-control-public']) {
100
- $cacheControlOptions = [
101
- 'no-header' => '',
102
- 'one-second' => '1 seconds',
103
- 'one-minute' => '1 minutes',
104
- 'one-hour' => '1 hours',
105
- 'one-day' => '1 days',
106
- 'one-week' => '1 weeks',
107
- 'one-month' => '1 months',
108
- 'one-year' => '1 years',
109
- ];
110
- $expires = $cacheControlOptions[$config['cache-control-max-age']];
111
}
112
- }
113
114
- if ($expires != '') {
115
- // in case mod_headers is missing, try mod_expires
116
- $ccRules .= " # Fall back to mod_expires if mod_headers is unavailable\n";
117
- $ccRules .= " <IfModule !mod_headers.c>\n";
118
- $ccRules .= " <IfModule mod_expires.c>\n";
119
- $ccRules .= " ExpiresActive On\n";
120
- $ccRules .= " ExpiresByType image/webp \"access plus " . $expires . "\"\n";
121
- $ccRules .= " </IfModule>\n";
122
- $ccRules .= " </IfModule>\n\n";
123
}
124
}
125
@@ -186,7 +218,6 @@ class HTAccess
186
break;
187
}
188
189
- $passSourceInQS = !($config['do-not-pass-source-in-query-string']);
190
191
// TODO: Is it possible to handle when wp-content is outside document root?
192
@@ -224,6 +255,23 @@ class HTAccess
224
225
}
226
227
if ($config['enable-redirection-to-webp-realizer']) {
228
/*
229
# Pass REQUEST_FILENAME to PHP in request header
@@ -239,7 +287,6 @@ class HTAccess
239
RewriteCond %{DOCUMENT_ROOT}/wordpress/uploads-moved/$1 -f
240
RewriteRule ^(.*)\.(webp)$ /plugins-moved/webp-express/wod/webp-realizer.php?wp-content=wp-content-moved [NC,L]
241
*/
242
- $passSourceInQSRealizer = $passSourceInQS;
243
244
$basicConditionsRealizer = '';
245
$basicConditionsRealizer .= " RewriteCond %{REQUEST_FILENAME} !-f\n";
@@ -253,22 +300,32 @@ class HTAccess
253
//$basicConditionsRealizer .= " RewriteCond %{DOCUMENT_ROOT}/" . $cacheDirRel . "/" . $htaccessDirRel . "/$1.$2.webp !-f\n";
254
}
255
256
-
257
- $rules .= " # Pass REQUEST_FILENAME to webp-realizer.php in request header\n";
258
- $rules .= $basicConditionsRealizer;
259
- $rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ - [E=REQFN:%{REQUEST_FILENAME}]\n" .
260
- " <IfModule mod_headers.c>\n" .
261
- " RequestHeader set REQFN \"%{REQFN}e\" env=REQFN\n" .
262
- " </IfModule>\n\n";
263
-
264
$rules .= " # WebP Realizer: Redirect non-existing webp images to webp-realizer.php, which will locate corresponding jpg/png, convert it, and deliver the webp (if possible) \n";
265
$rules .= $basicConditionsRealizer;
266
267
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ " .
268
"/" . Paths::getWebPRealizerUrlPath() .
269
- ($passSourceInQSRealizer ? "?xdestination=x%{SCRIPT_FILENAME}&" : "?") .
270
"wp-content=" . Paths::getContentDirRel() .
271
- " [NC,L]\n\n"; // E=WOD:1
272
273
if (!$config['redirect-to-existing-in-htaccess']) {
274
$rules .= $ccRules;
@@ -293,16 +350,6 @@ class HTAccess
293
}
294
}
295
296
-
297
- if (!$passSourceInQS) {
298
- $rules .= " # Pass REQUEST_FILENAME to webp-on-demand.php in request header\n";
299
- $rules .= $basicConditions;
300
- $rules .= " RewriteRule ^(.*)\.(" . $fileExt . ")$ - [E=REQFN:%{REQUEST_FILENAME}]\n" .
301
- " <IfModule mod_headers.c>\n" .
302
- " RequestHeader set REQFN \"%{REQFN}e\" env=REQFN\n" .
303
- " </IfModule>\n\n";
304
- }
305
-
306
$rules .= " # Redirect images to webp-on-demand.php ";
307
if ($config['only-redirect-to-converter-for-webp-enabled-browsers']) {
308
$rules .= "(if browser supports webp)\n";
@@ -327,34 +374,51 @@ class HTAccess
327
// https://github.com/rosell-dk/webp-convert/issues/95
328
// (and try testing spaces in directory paths)
329
330
// TODO: When $rewriteRuleStart is empty, we don't need the .*, do we? - test
331
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(" . $fileExt . ")$ " .
332
"/" . Paths::getWodUrlPath() .
333
- ($passSourceInQS ? "?xsource=x%{SCRIPT_FILENAME}&" : "?") .
334
- "wp-content=" . Paths::getContentDirRel() .
335
- ($config['forward-query-string'] ? '&%1' : '') .
336
- " [NC,L]\n"; // E=WOD:1
337
338
- $rules .= "\n <IfModule mod_headers.c>\n";
339
$rules .= " <IfModule mod_setenvif.c>\n";
340
341
- if (($config['success-response'] == 'converted') || ($config['redirect-to-existing-in-htaccess'])) {
342
- $rules .= " # Set Vary:Accept header for the image types handled by WebP Express.\n" .
343
- " # 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" .
344
" SetEnvIf Request_URI \"\.(" . $fileExt . ")\" ADDVARY\n" .
345
" Header append \"Vary\" \"Accept\" env=ADDVARY\n\n";
346
- }
347
348
- $rules .= " # Set X-WebP-Express header for diagnose purposes\n" .
349
" # Apache appends \"REDIRECT_\" in front of the environment variables defined in mod_rewrite, but LiteSpeed does not.\n" .
350
" # So, the next line is for Apache, in order to set environment variables without \"REDIRECT_\"\n" .
351
" SetEnvIf REDIRECT_EXISTING 1 EXISTING=1\n" .
352
//" SetEnvIf REDIRECT_WOD 1 WOD=1\n\n" .
353
//" # Set the debug header\n" .
354
- " Header set \"X-WebP-Express\" \"Redirected directly to existing webp\" env=EXISTING\n" .
355
//" Header set \"X-WebP-Express\" \"Redirected to image converter\" env=WOD\n" .
356
- " </IfModule>\n" .
357
- " </IfModule>\n\n";
358
}
359
$rules .="</IfModule>\n";
360
@@ -430,7 +494,6 @@ class HTAccess
430
$propsToCompare = [
431
'forward-query-string' => true,
432
'image-types' => 1,
433
- 'do-not-pass-source-in-query-string' => false,
434
'redirect-to-existing-in-htaccess' => false,
435
'only-redirect-to-converter-on-cache-miss' => false,
436
'success-response' => 'converted',
@@ -438,6 +501,8 @@ class HTAccess
438
'cache-control-custom' => 'public, max-age:3600',
439
'cache-control-max-age' => 'one-week',
440
'cache-control-public' => true,
441
];
442
443
if (isset($newConfig['redirect-to-existing-in-htaccess']) && $newConfig['redirect-to-existing-in-htaccess']) {
@@ -509,7 +574,7 @@ class HTAccess
509
510
/**
511
* Sneak peak into .htaccess to see if we have rules in it
512
- * This may not be possible.
513
* Return true, false, or null if we just can't tell
514
*/
515
public static function haveWeRulesInThisHTAccess($filename) {
@@ -549,6 +614,7 @@ class HTAccess
549
// We were not allowed to sneak-peak.
550
// Well, good thing that we stored successful .htaccess write locations ;)
551
// If we recorded a successful write, then we assume there are still rules there
552
$dir = FileHelper::dirName($filename);
553
return self::hasRecordOfSavingHTAccessToDir($dir);
554
}
@@ -665,11 +731,25 @@ class HTAccess
665
666
public static function testLinks($config) {
667
if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false )) {
668
- if ($config['image-types'] != 0) {
669
- $webpExpressRoot = Paths::getPluginUrlPath();
670
- return '<br>' .
671
- '<a href="/' . $webpExpressRoot . '/test/test.jpg?debug&time=' . time() . '" target="_blank">Convert test image (show debug)</a><br>' .
672
- '<a href="/' . $webpExpressRoot . '/test/test.jpg?' . time() . '" target="_blank">Convert test image</a><br>';
673
}
674
}
675
return '';
@@ -730,6 +810,8 @@ class HTAccess
730
}
731
} else {
732
$mainResult = 'wp-content';
733
HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', '# WebP Express has placed its rules in your wp-content dir. Go there.', false);
734
}
735
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
+
27
+ // TODO: can we use the new fix method instead?
28
+
29
$defaults = [
30
'enable-redirection-to-converter' => true,
31
'forward-query-string' => true,
43
return '# WebP Express does not need to write any rules (it has not been set up to redirect to converter, nor to existing webp, and the "convert non-existing webp-files upon request" option has not been enabled)';
44
}
45
46
+ if (isset($config['base-htaccess-on-these-capability-tests'])) {
47
+ $capTests = $config['base-htaccess-on-these-capability-tests'];
48
+ $modHeaderDefinitelyUnavailable = ($capTests['modHeaderWorking'] === false);
49
+ $passThroughHeaderDefinitelyUnavailable = ($capTests['passThroughHeaderWorking'] === false);
50
+ $passThroughHeaderDefinitelyAavailable = ($capTests['passThroughHeaderWorking'] === true);
51
+ $passThrougEnvVarDefinitelyUnavailable = ($capTests['passThroughEnvWorking'] === false);
52
+ $passThrougEnvVarDefinitelyAvailable =($capTests['passThroughEnvWorking'] === true);
53
+ } else {
54
+ $modHeaderDefinitelyUnavailable = false;
55
+ $passThroughHeaderDefinitelyUnavailable = false;
56
+ $passThroughHeaderDefinitelyAavailable = false;
57
+ $passThrougEnvVarDefinitelyUnavailable = false;
58
+ $passThrougEnvVarDefinitelyAvailable = false;
59
+ }
60
+
61
+ $setEnvVar = !$passThrougEnvVarDefinitelyUnavailable;
62
+ $passFullFilePathInQS = false;
63
+ $passRelativeFilePathInQS = !($passThrougEnvVarDefinitelyAvailable || $passThroughHeaderDefinitelyAavailable);
64
+ $passFullFilePathInQSRealizer = false;
65
+ $passRelativeFilePathInQSRealizer = $passRelativeFilePathInQS;
66
+
67
+
68
+
69
/* Calculate $fileExt */
70
$imageTypes = $config['image-types'];
71
$fileExtensions = [];
104
$ccRules .= " </IfModule>\n\n";
105
106
// Fall back to mod_expires if mod_headers is unavailable
107
+
108
+
109
+
110
+ if ($modHeaderDefinitelyUnavailable) {
111
+ $cacheControl = $config['cache-control'];
112
+
113
+ if ($cacheControl == 'custom') {
114
+ $expires = '';
115
+
116
+ // Do not add Expire header if private is set
117
+ // - because then the user don't want caching in proxies / CDNs.
118
+ // the Expires header doesn't differentiate between private/public
119
+ if (!(preg_match('/private/', $config['cache-control-custom']))) {
120
+ if (preg_match('/max-age=(\d+)/', $config['cache-control-custom'], $matches)) {
121
+ if (isset($matches[1])) {
122
+ $expires = $matches[1] . ' seconds';
123
+ }
124
}
125
}
126
127
+ } elseif ($cacheControl == 'no-header') {
128
+ $expires = '';
129
+ } elseif ($cacheControl == 'set') {
130
+ if ($config['cache-control-public']) {
131
+ $cacheControlOptions = [
132
+ 'no-header' => '',
133
+ 'one-second' => '1 seconds',
134
+ 'one-minute' => '1 minutes',
135
+ 'one-hour' => '1 hours',
136
+ 'one-day' => '1 days',
137
+ 'one-week' => '1 weeks',
138
+ 'one-month' => '1 months',
139
+ 'one-year' => '1 years',
140
+ ];
141
+ $expires = $cacheControlOptions[$config['cache-control-max-age']];
142
+ }
143
}
144
145
+ if ($expires != '') {
146
+ // in case mod_headers is missing, try mod_expires
147
+ $ccRules .= " # Fall back to mod_expires if mod_headers is unavailable\n";
148
+ $ccRules .= " <IfModule !mod_headers.c>\n";
149
+ $ccRules .= " <IfModule mod_expires.c>\n";
150
+ $ccRules .= " ExpiresActive On\n";
151
+ $ccRules .= " ExpiresByType image/webp \"access plus " . $expires . "\"\n";
152
+ $ccRules .= " </IfModule>\n";
153
+ $ccRules .= " </IfModule>\n\n";
154
+ }
155
}
156
}
157
218
break;
219
}
220
221
222
// TODO: Is it possible to handle when wp-content is outside document root?
223
255
256
}
257
258
+ // Do not add header magic if passing through env is definitely working
259
+ // Do not add either, if we definitily know it isn't working
260
+ if ((!$passThrougEnvVarDefinitelyAvailable) && (!$passThroughHeaderDefinitelyUnavailable)) {
261
+ if ($config['enable-redirection-to-converter']) {
262
+ $rules .= " # Pass REQUEST_FILENAME to webp-on-demand.php in request header\n";
263
+ //$rules .= $basicConditions;
264
+ //$rules .= " RewriteRule ^(.*)\.(" . $fileExt . ")$ - [E=REQFN:%{REQUEST_FILENAME}]\n" .
265
+ $rules .= " <IfModule mod_headers.c>\n" .
266
+ " RequestHeader set REQFN \"%{REQFN}e\" env=REQFN\n" .
267
+ " </IfModule>\n\n";
268
+
269
+ }
270
+ if ($config['enable-redirection-to-webp-realizer']) {
271
+ // We haven't implemented a clever way to pass through header for webp-realizer yet
272
+ }
273
+ }
274
+
275
if ($config['enable-redirection-to-webp-realizer']) {
276
/*
277
# Pass REQUEST_FILENAME to PHP in request header
287
RewriteCond %{DOCUMENT_ROOT}/wordpress/uploads-moved/$1 -f
288
RewriteRule ^(.*)\.(webp)$ /plugins-moved/webp-express/wod/webp-realizer.php?wp-content=wp-content-moved [NC,L]
289
*/
290
291
$basicConditionsRealizer = '';
292
$basicConditionsRealizer .= " RewriteCond %{REQUEST_FILENAME} !-f\n";
300
//$basicConditionsRealizer .= " RewriteCond %{DOCUMENT_ROOT}/" . $cacheDirRel . "/" . $htaccessDirRel . "/$1.$2.webp !-f\n";
301
}
302
303
$rules .= " # WebP Realizer: Redirect non-existing webp images to webp-realizer.php, which will locate corresponding jpg/png, convert it, and deliver the webp (if possible) \n";
304
$rules .= $basicConditionsRealizer;
305
306
+ /*
307
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ " .
308
"/" . Paths::getWebPRealizerUrlPath() .
309
+ ($passFullFilePathInQS ? "?xdestination=x%{SCRIPT_FILENAME}&" : "?") .
310
"wp-content=" . Paths::getContentDirRel() .
311
+ " [" . ($setEnvVar ? ('E=REQFN:%{REQUEST_FILENAME}' . ','): '') . "NC,L]\n\n"; // E=WOD:1
312
+ */
313
+ $params = [];
314
+ if ($passFullFilePathInQSRealizer) {
315
+ $params[] = 'xdestination=x%{SCRIPT_FILENAME}';
316
+ } elseif ($passRelativeFilePathInQSRealizer) {
317
+ $params[] = 'xdestination-rel=x' . $htaccessDirRel . '/$1.$2';
318
+ }
319
+ if (!$passThrougEnvVarDefinitelyAvailable) {
320
+ $params[] = "wp-content=" . Paths::getContentDirRel();
321
+ }
322
+
323
+ // TODO: When $rewriteRuleStart is empty, we don't need the .*, do we? - test
324
+ $rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ " .
325
+ "/" . Paths::getWebPRealizerUrlPath() .
326
+ ((count($params) > 0) ? "?" . implode('&', $params) : '') .
327
+ " [" . ($setEnvVar ? ('E=DESTINATIONREL:' . $htaccessDirRel . '/$0' . ','): '') . (!$passThrougEnvVarDefinitelyUnavailable ? 'E=WPCONTENT:' . Paths::getContentDirRel() . ',' : '') . "NC,L]\n\n"; // E=WOD:1
328
+
329
330
if (!$config['redirect-to-existing-in-htaccess']) {
331
$rules .= $ccRules;
350
}
351
}
352
353
$rules .= " # Redirect images to webp-on-demand.php ";
354
if ($config['only-redirect-to-converter-for-webp-enabled-browsers']) {
355
$rules .= "(if browser supports webp)\n";
374
// https://github.com/rosell-dk/webp-convert/issues/95
375
// (and try testing spaces in directory paths)
376
377
+ $params = [];
378
+ if ($passFullFilePathInQS) {
379
+ $params[] = 'xsource=x%{SCRIPT_FILENAME}';
380
+ } elseif ($passRelativeFilePathInQS) {
381
+ $params[] = 'xsource-rel=x' . $htaccessDirRel . '/$1.$2';
382
+ }
383
+ if (!$passThrougEnvVarDefinitelyAvailable) {
384
+ $params[] = "wp-content=" . Paths::getContentDirRel();
385
+ }
386
+ if ($config['forward-query-string']) {
387
+ $params[] = '%1';
388
+ }
389
+
390
// TODO: When $rewriteRuleStart is empty, we don't need the .*, do we? - test
391
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(" . $fileExt . ")$ " .
392
"/" . Paths::getWodUrlPath() .
393
+ "?" . implode('&', $params) .
394
+ " [" . ($setEnvVar ? ('E=REQFN:%{REQUEST_FILENAME},'): '') . (!$passThrougEnvVarDefinitelyUnavailable ? 'E=WPCONTENT:' . Paths::getContentDirRel() . ',' : '') . "NC,L]\n"; // E=WOD:1
395
+
396
+ $rules .= "\n";
397
+ }
398
+
399
+ $addVary = ($config['enable-redirection-to-converter'] && ($config['success-response'] == 'converted')) || ($config['redirect-to-existing-in-htaccess']);
400
401
+ if ($addVary) {
402
+ $rules .= " <IfModule mod_headers.c>\n";
403
$rules .= " <IfModule mod_setenvif.c>\n";
404
405
+ $rules .= " # Set Vary:Accept header for the image types handled by WebP Express.\n" .
406
+ " # The purpose is to make proxies and CDNs aware that the response varies with the Accept header. \n" .
407
" SetEnvIf Request_URI \"\.(" . $fileExt . ")\" ADDVARY\n" .
408
" Header append \"Vary\" \"Accept\" env=ADDVARY\n\n";
409
410
+ if ($config['redirect-to-existing-in-htaccess']) {
411
+ $rules .= " # Set X-WebP-Express header for diagnose purposes\n" .
412
" # Apache appends \"REDIRECT_\" in front of the environment variables defined in mod_rewrite, but LiteSpeed does not.\n" .
413
" # So, the next line is for Apache, in order to set environment variables without \"REDIRECT_\"\n" .
414
" SetEnvIf REDIRECT_EXISTING 1 EXISTING=1\n" .
415
//" SetEnvIf REDIRECT_WOD 1 WOD=1\n\n" .
416
//" # Set the debug header\n" .
417
+ " Header set \"X-WebP-Express\" \"Redirected directly to existing webp\" env=EXISTING\n";
418
//" Header set \"X-WebP-Express\" \"Redirected to image converter\" env=WOD\n" .
419
+ }
420
+ $rules .= " </IfModule>\n" .
421
+ " </IfModule>\n\n";
422
}
423
$rules .="</IfModule>\n";
424
494
$propsToCompare = [
495
'forward-query-string' => true,
496
'image-types' => 1,
497
'redirect-to-existing-in-htaccess' => false,
498
'only-redirect-to-converter-on-cache-miss' => false,
499
'success-response' => 'converted',
501
'cache-control-custom' => 'public, max-age:3600',
502
'cache-control-max-age' => 'one-week',
503
'cache-control-public' => true,
504
+ 'enable-redirection-to-webp-realizer' => false,
505
+ 'enable-redirection-to-converter' => true
506
];
507
508
if (isset($newConfig['redirect-to-existing-in-htaccess']) && $newConfig['redirect-to-existing-in-htaccess']) {
574
575
/**
576
* Sneak peak into .htaccess to see if we have rules in it
577
+ * This may not be possible (it requires read permission)
578
* Return true, false, or null if we just can't tell
579
*/
580
public static function haveWeRulesInThisHTAccess($filename) {
614
// We were not allowed to sneak-peak.
615
// Well, good thing that we stored successful .htaccess write locations ;)
616
// If we recorded a successful write, then we assume there are still rules there
617
+ // If we did not, we assume there are no rules there
618
$dir = FileHelper::dirName($filename);
619
return self::hasRecordOfSavingHTAccessToDir($dir);
620
}
731
732
public static function testLinks($config) {
733
if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false )) {
734
+ if ($config['operation-mode'] != 'no-conversion') {
735
+ if ($config['image-types'] != 0) {
736
+ $webpExpressRoot = Paths::getPluginUrlPath();
737
+ if ($config['enable-redirection-to-converter']) {
738
+ $links = '<br>';
739
+ $links .= '<a href="/' . $webpExpressRoot . '/test/test.jpg?debug&time=' . time() . '" target="_blank">Convert test image (show debug)</a><br>';
740
+ $links .= '<a href="/' . $webpExpressRoot . '/test/test.jpg?' . time() . '" target="_blank">Convert test image</a><br>';
741
+ }
742
+ // TODO: webp-realizer test links (to missing webp)
743
+ if ($config['enable-redirection-to-webp-realizer']) {
744
+ }
745
+
746
+ // TODO: test link for testing redirection to existing
747
+ if ($config['redirect-to-existing-in-htaccess']) {
748
+
749
+ }
750
+
751
+ return $links;
752
+ }
753
}
754
}
755
return '';
810
}
811
} else {
812
$mainResult = 'wp-content';
813
+ // TODO: Change to something like "The rules are placed in the .htaccess file in your wp-content dir."
814
+ // BUT! - current text is searched for in page-messages.php
815
HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', '# WebP Express has placed its rules in your wp-content dir. Go there.', false);
816
}
817
lib/classes/KeepEwwwSubscriptionAlive.php ADDED
@@ -0,0 +1,60 @@
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ use \WebPExpress\Config;
6
+ use \WebPExpress\Messenger;
7
+ use \WebPExpress\State;
8
+ use \WebPConvert\Converters\Ewww;
9
+
10
+ /**
11
+ *
12
+ */
13
+
14
+ class KeepEwwwSubscriptionAlive
15
+ {
16
+ public static function keepAlive($config = null) {
17
+ include_once __DIR__ . '/../../vendor/autoload.php';
18
+
19
+ if (is_null($config)) {
20
+ $config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
21
+ }
22
+
23
+ $ewww = Config::getConverterByName($config, 'ewww');
24
+ if (!isset($ewww['options']['key'])) {
25
+ return;
26
+ }
27
+ if (!$ewww['working']) {
28
+ return;
29
+ }
30
+
31
+ $ewwwConvertResult = Ewww::keepSubscriptionAlive(__DIR__ . '/../../test/very-small.jpg', $ewww['options']['key']);
32
+ if ($ewwwConvertResult === true) {
33
+ Messenger::addMessage(
34
+ 'info',
35
+ 'Successfully optimized regular jpg with <i>ewww</i> converter in order to keep the subscription alive'
36
+ );
37
+ State::setState('last-ewww-optimize', time());
38
+ } else {
39
+ Messenger::addMessage(
40
+ 'warning',
41
+ 'Failed optimizing regular jpg with <i>ewww</i> converter in order to keep the subscription alive'
42
+ );
43
+ }
44
+ }
45
+
46
+ public static function keepAliveIfItIsTime($config = null) {
47
+
48
+ $timeSinseLastSuccesfullOptimize = time() - State::getState('last-ewww-optimize', 0);
49
+ if ($timeSinseLastSuccesfullOptimize > 3 * 30 * 24 * 60 * 60) {
50
+
51
+ $timeSinseLastOptimizeAttempt = time() - State::getState('last-ewww-optimize-attempt', 0);
52
+ if ($timeSinseLastOptimizeAttempt > 14 * 24 * 60 * 60) {
53
+ State::setState('last-ewww-optimize-attempt', time());
54
+ self::keepAlive($config);
55
+ }
56
+ }
57
+
58
+ }
59
+
60
+ }
lib/classes/Messenger.php CHANGED
@@ -5,6 +5,8 @@ namespace WebPExpress;
5
include_once "State.php";
6
use \WebPExpress\State;
7
8
class Messenger
9
{
10
private static $printedStyles = false;
@@ -17,8 +19,9 @@ class Messenger
17
* $msg = sprintf(__( 'You are on a very old version of PHP (%s). WebP Express may not work as intended.', 'webp-express' ), phpversion());
18
*/
19
public static function addMessage($level, $msg) {
20
21
- update_option('webp-express-messages-pending', true, true); // We want this option to be autoloaded
22
$pendingMessages = State::getState('pendingMessages', []);
23
24
// Ensure we do not add a message that is already pending.
@@ -80,7 +83,6 @@ class Messenger
80
81
public static function printPendingMessages() {
82
83
-
84
$messages = State::getState('pendingMessages', []);
85
86
foreach ($messages as $message) {
@@ -88,6 +90,6 @@ class Messenger
88
}
89
90
State::setState('pendingMessages', []);
91
- update_option('webp-express-messages-pending', false, true);
92
}
93
}
5
include_once "State.php";
6
use \WebPExpress\State;
7
8
+ use \WebPExpress\Option;
9
+
10
class Messenger
11
{
12
private static $printedStyles = false;
19
* $msg = sprintf(__( 'You are on a very old version of PHP (%s). WebP Express may not work as intended.', 'webp-express' ), phpversion());
20
*/
21
public static function addMessage($level, $msg) {
22
+ //error_log('add message:' . $msg);
23
24
+ Option::updateOption('webp-express-messages-pending', true, true); // We want this option to be autoloaded
25
$pendingMessages = State::getState('pendingMessages', []);
26
27
// Ensure we do not add a message that is already pending.
83
84
public static function printPendingMessages() {
85
86
$messages = State::getState('pendingMessages', []);
87
88
foreach ($messages as $message) {
90
}
91
92
State::setState('pendingMessages', []);
93
+ Option::updateOption('webp-express-messages-pending', false, true);
94
}
95
}
lib/classes/Multisite.php ADDED
@@ -0,0 +1,36 @@
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ class Multisite
6
+ {
7
+ public static $networkActive;
8
+
9
+ /*
10
+ Needed because is_plugin_active_for_network() does not return true right after network activation
11
+ */
12
+ public static function overrideIsNetworkActivated($networkActive)
13
+ {
14
+ self::$networkActive = $networkActive;
15
+ }
16
+
17
+ public static function isNetworkActivated()
18
+ {
19
+ if (!is_null(self::$networkActive)) {
20
+ return self::$networkActive;
21
+ }
22
+ if (!self::isMultisite()) {
23
+ return false;
24
+ }
25
+ if (!function_exists( 'is_plugin_active_for_network')) {
26
+ require_once(ABSPATH . '/wp-admin/includes/plugin.php');
27
+ }
28
+ return is_plugin_active_for_network('webp-express/webp-express.php');
29
+ }
30
+
31
+ public static function isMultisite()
32
+ {
33
+ return is_multisite();
34
+ }
35
+
36
+ }
lib/classes/Option.php ADDED
@@ -0,0 +1,39 @@