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 $&
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 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ use \WebPExpress\Multisite;
6
+
7
+ class Option
8
+ {
9
+
10
+ public static function getOption($optionName, $default = false)
11
+ {
12
+ if (Multisite::isNetworkActivated()) {
13
+ return get_site_option($optionName, $default);
14
+ } else {
15
+ return get_option($optionName, $default);
16
+ }
17
+ }
18
+
19
+ public static function updateOption($optionName, $value, $autoload = null)
20
+ {
21
+ if (Multisite::isNetworkActivated()) {
22
+ //error_log('update option (network):' . $optionName . ':' . $value);
23
+ return update_site_option($optionName, $value);
24
+ } else {
25
+ //error_log('update option:' . $optionName . ':' . $value);
26
+ return update_option($optionName, $value, $autoload);
27
+ }
28
+ }
29
+
30
+ public static function deleteOption($optionName)
31
+ {
32
+ if (Multisite::isNetworkActivated()) {
33
+ return delete_site_option($optionName);
34
+ } else {
35
+ return delete_option($optionName);
36
+ }
37
+
38
+ }
39
+ }
lib/classes/Paths.php CHANGED
@@ -8,6 +8,8 @@ use \WebPExpress\PathHelper;
8
  include_once "FileHelper.php";
9
  use \WebPExpress\FileHelper;
10
 
 
 
11
  class Paths
12
  {
13
 
@@ -252,7 +254,7 @@ APACHE
252
 
253
  public static function getPluginDirAbs()
254
  {
255
- return untrailingslashit(WP_PLUGIN_DIR);
256
  }
257
 
258
  public static function getPluginDirRel()
@@ -274,7 +276,7 @@ APACHE
274
 
275
  public static function getWebPExpressPluginDirAbs()
276
  {
277
- return untrailingslashit(WEBPEXPRESS_PLUGIN_DIR);
278
  }
279
 
280
  public static function getAbsDirId($absDir) {
@@ -379,7 +381,7 @@ APACHE
379
 
380
 
381
  /**
382
- * Get Url to plugin (this is in fact an incomplete URL, you need to append ie '/webp-on-demand.php' to get a full URL)
383
  */
384
  public static function getPluginUrl()
385
  {
@@ -433,18 +435,17 @@ APACHE
433
  ];
434
  }
435
 
436
- /* Get complete url to admin (no trailing slash) */
437
- public static function getAdminUrl()
438
  {
439
- if (!function_exists('get_admin_url')) {
440
  require_once ABSPATH . 'wp-includes/link-template.php';
441
  }
442
- return untrailingslashit(get_admin_url());
443
- }
444
-
445
- public static function getSettingsUrl()
446
- {
447
- return self::getAdminUrl() . '/' . 'options-general.php?page=webp_express_settings_page';
448
  }
449
 
450
  }
8
  include_once "FileHelper.php";
9
  use \WebPExpress\FileHelper;
10
 
11
+ use \WebPExpress\Multisite;
12
+
13
  class Paths
14
  {
15
 
254
 
255
  public static function getPluginDirAbs()
256
  {
257
+ return self::getAbsDir(WP_PLUGIN_DIR);
258
  }
259
 
260
  public static function getPluginDirRel()
276
 
277
  public static function getWebPExpressPluginDirAbs()
278
  {
279
+ return self::getAbsDir(WEBPEXPRESS_PLUGIN_DIR);
280
  }
281
 
282
  public static function getAbsDirId($absDir) {
381
 
382
 
383
  /**
384
+ * Get Url to WebP Express plugin (this is in fact an incomplete URL, you need to append ie '/webp-on-demand.php' to get a full URL)
385
  */
386
  public static function getPluginUrl()
387
  {
435
  ];
436
  }
437
 
438
+ public static function getSettingsUrl()
 
439
  {
440
+ if (!function_exists('admin_url')) {
441
  require_once ABSPATH . 'wp-includes/link-template.php';
442
  }
443
+ if (Multisite::isNetworkActivated()) {
444
+ // network_admin_url is also defined in link-template.php.
445
+ return network_admin_url('settings.php?page=webp_express_settings_page');
446
+ } else {
447
+ return admin_url('options-general.php?page=webp_express_settings_page');
448
+ }
449
  }
450
 
451
  }
lib/classes/State.php CHANGED
@@ -2,6 +2,8 @@
2
 
3
  namespace WebPExpress;
4
 
 
 
5
  /**
6
  * Store state in db
7
  * We are using update_option WITHOUT autoloading.
@@ -9,12 +11,13 @@ namespace WebPExpress;
9
  * For such things, use update_option / get_option directly
10
  */
11
 
 
12
  class State
13
  {
14
 
15
  public static function getStateObj() {
16
  // TODO: cache
17
- $json = get_option('webp-express-state', '[]');
18
  return json_decode($json, true);
19
  }
20
 
@@ -37,6 +40,6 @@ class State
37
  $json = json_encode($currentStateObj, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
38
 
39
  // Store in db. No autoloading.
40
- update_option('webp-express-state', $json, false);
41
  }
42
  }
2
 
3
  namespace WebPExpress;
4
 
5
+ use \WebPExpress\Option;
6
+
7
  /**
8
  * Store state in db
9
  * We are using update_option WITHOUT autoloading.
11
  * For such things, use update_option / get_option directly
12
  */
13
 
14
+
15
  class State
16
  {
17
 
18
  public static function getStateObj() {
19
  // TODO: cache
20
+ $json = Option::getOption('webp-express-state', '[]');
21
  return json_decode($json, true);
22
  }
23
 
40
  $json = json_encode($currentStateObj, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
41
 
42
  // Store in db. No autoloading.
43
+ Option::updateOption('webp-express-state', $json, false);
44
  }
45
  }
lib/migrate/migrate.php CHANGED
@@ -3,16 +3,16 @@
3
  include_once __DIR__ . '/../classes/State.php';
4
  use \WebPExpress\State;
5
 
6
- use \WebPConvert\Converters\Ewww;
7
  use \WebPExpress\Messenger;
8
  use \WebPExpress\Config;
 
9
 
10
 
11
  /*
12
  In 0.4.0, we had a 'webp-express-configured' option.
13
  As long as there are still users on 0.4 or below, we must do the following:
14
  */
15
- if (get_option('webp-express-configured', false)) {
16
  State::setState('configured', true);
17
  }
18
 
@@ -21,8 +21,8 @@ In 0.1, we did not have the 'webp-express-configured' option.
21
  To determine if WebP Express was configured in 0.1, we can test the (now obsolete) webp_express_converters option
22
  As long as there are still users on 0.1, we must do the following:
23
  */
24
- if (!get_option('webp-express-configured', false)) {
25
- if (!is_null(get_option('webp_express_converters', null))) {
26
  State::setState('configured', true);
27
  }
28
  }
@@ -31,11 +31,11 @@ if (!get_option('webp-express-configured', false)) {
31
  if (!(State::getState('configured', false))) {
32
  // Options has never has been saved, so no migration is needed.
33
  // We can set migrate-version to current
34
- update_option('webp-express-migration-version', WEBPEXPRESS_MIGRATION_VERSION);
35
  } else {
36
 
37
- for ($x = intval(get_option('webp-express-migration-version', 0)); $x < WEBPEXPRESS_MIGRATION_VERSION; $x++) {
38
- if (intval(get_option('webp-express-migration-version', 0)) == $x) {
39
  // run migration X+1, which upgrades from X to X+1
40
  // It must take care of updating the "webp-express-migration-version" option to X+1, - if successful.
41
  // If unsuccessful, it must leaves the option unaltered, which will prevent
@@ -46,30 +46,4 @@ if (!(State::getState('configured', false))) {
46
  }
47
  }
48
 
49
-
50
- function webpexpress_keepEwwwSubscriptionAlive() {
51
- include_once __DIR__ . '/../../vendor/autoload.php';
52
- include_once __DIR__ . '/../classes/Messenger.php';
53
- include_once __DIR__ . '/../classes/Config.php';
54
-
55
- $config = Config::loadConfigAndFix(false);
56
- foreach ($config['converters'] as $i => $converter) {
57
- if (
58
- ($converter['converter'] == 'ewww') &&
59
- (!(isset($converter['deactivated'])) || (!$converter['deactivated'])) &&
60
- (isset($converter['options']['key'])))
61
- {
62
- $ewwwConvertResult = Ewww::keepSubscriptionAlive(__DIR__ . '/../../test/very-small.jpg', $converter['options']['key']);
63
-
64
- if ($ewwwConvertResult === true) {
65
- Messenger::addMessage(
66
- 'info',
67
- 'Successfully optimized regular jpg with <i>ewww</i> converter in order to keep the subscription alive'
68
- );
69
- }
70
- }
71
- }
72
- }
73
-
74
- // create
75
- webpexpress_keepEwwwSubscriptionAlive();
3
  include_once __DIR__ . '/../classes/State.php';
4
  use \WebPExpress\State;
5
 
 
6
  use \WebPExpress\Messenger;
7
  use \WebPExpress\Config;
8
+ use \WebPExpress\Option;
9
 
10
 
11
  /*
12
  In 0.4.0, we had a 'webp-express-configured' option.
13
  As long as there are still users on 0.4 or below, we must do the following:
14
  */
15
+ if (Option::getOption('webp-express-configured', false)) {
16
  State::setState('configured', true);
17
  }
18
 
21
  To determine if WebP Express was configured in 0.1, we can test the (now obsolete) webp_express_converters option
22
  As long as there are still users on 0.1, we must do the following:
23
  */
24
+ if (!Option::getOption('webp-express-configured', false)) {
25
+ if (!is_null(Option::getOption('webp_express_converters', null))) {
26
  State::setState('configured', true);
27
  }
28
  }
31
  if (!(State::getState('configured', false))) {
32
  // Options has never has been saved, so no migration is needed.
33
  // We can set migrate-version to current
34
+ Option::updateOption('webp-express-migration-version', WEBPEXPRESS_MIGRATION_VERSION);
35
  } else {
36
 
37
+ for ($x = intval(Option::getOption('webp-express-migration-version', 0)); $x < WEBPEXPRESS_MIGRATION_VERSION; $x++) {
38
+ if (intval(Option::getOption('webp-express-migration-version', 0)) == $x) {
39
  // run migration X+1, which upgrades from X to X+1
40
  // It must take care of updating the "webp-express-migration-version" option to X+1, - if successful.
41
  // If unsuccessful, it must leaves the option unaltered, which will prevent
46
  }
47
  }
48
 
49
+ //KeepEwwwSubscriptionAlive::keepAliveIfItIsTime($config);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/migrate/migrate1.php CHANGED
@@ -14,10 +14,11 @@ use \WebPExpress\Paths;
14
  include_once __DIR__ . '/../classes/Messenger.php';
15
  use \WebPExpress\Messenger;
16
 
17
- //Messenger::addMessage('info', 'migration:' . get_option('webp-express-migration-version', 'not set'));
 
18
 
19
  // On successful migration:
20
- // update_option('webp-express-migration-version', '1', true);
21
 
22
  function webp_express_migrate1_createFolders()
23
  {
@@ -59,15 +60,15 @@ function webp_express_migrate1_createDummyConfigFiles()
59
 
60
  function webpexpress_migrate1_migrateOptions()
61
  {
62
- $converters = json_decode(get_option('webp_express_converters', '[]'), true);
63
  foreach ($converters as &$converter) {
64
  unset ($converter['id']);
65
  }
66
 
67
  $options = [
68
- 'image-types' => intval(get_option('webp_express_image_types_to_convert', 1)),
69
- 'max-quality' => intval(get_option('webp_express_max_quality', 80)),
70
- 'fail' => get_option('webp_express_failure_response', 'original'),
71
  'converters' => $converters,
72
  'forward-query-string' => true
73
  ];
@@ -168,7 +169,7 @@ function webpexpress_migrate1_deleteOldOptions() {
168
 
169
  ];
170
  foreach ($optionsToDelete as $i => $optionName) {
171
- delete_option($optionName);
172
  }
173
  }
174
 
@@ -199,7 +200,7 @@ if (webp_express_migrate1_createFolders()) {
199
  if (webpexpress_migrate1_migrateOptions()) {
200
  webpexpress_migrate1_deleteOldOptions();
201
  webpexpress_migrate1_deleteOldWebPImages();
202
- update_option('webp-express-migration-version', '1');
203
  }
204
  }
205
  }
14
  include_once __DIR__ . '/../classes/Messenger.php';
15
  use \WebPExpress\Messenger;
16
 
17
+ use \WebPExpress\Option;
18
+
19
 
20
  // On successful migration:
21
+ // Option::updateOption('webp-express-migration-version', '1', true);
22
 
23
  function webp_express_migrate1_createFolders()
24
  {
60
 
61
  function webpexpress_migrate1_migrateOptions()
62
  {
63
+ $converters = json_decode(Option::getOption('webp_express_converters', '[]'), true);
64
  foreach ($converters as &$converter) {
65
  unset ($converter['id']);
66
  }
67
 
68
  $options = [
69
+ 'image-types' => intval(Option::getOption('webp_express_image_types_to_convert', 1)),
70
+ 'max-quality' => intval(Option::getOption('webp_express_max_quality', 80)),
71
+ 'fail' => Option::getOption('webp_express_failure_response', 'original'),
72
  'converters' => $converters,
73
  'forward-query-string' => true
74
  ];
169
 
170
  ];
171
  foreach ($optionsToDelete as $i => $optionName) {
172
+ Option::deleteOption($optionName);
173
  }
174
  }
175
 
200
  if (webpexpress_migrate1_migrateOptions()) {
201
  webpexpress_migrate1_deleteOldOptions();
202
  webpexpress_migrate1_deleteOldWebPImages();
203
+ Option::updateOption('webp-express-migration-version', '1');
204
  }
205
  }
206
  }
lib/migrate/migrate2.php CHANGED
@@ -11,6 +11,8 @@ use \WebPExpress\Messenger;
11
  include_once __DIR__ . '/../classes/TestRun.php';
12
  use \WebPExpress\TestRun;
13
 
 
 
14
  /* helper. Remove dir recursively. No warnings - fails silently
15
  Set $removeTheDirItself to false if you want to empty the dir
16
  */
@@ -68,4 +70,4 @@ Messenger::addMessage(
68
  );
69
 
70
 
71
- update_option('webp-express-migration-version', '2');
11
  include_once __DIR__ . '/../classes/TestRun.php';
12
  use \WebPExpress\TestRun;
13
 
14
+ use \WebPExpress\Option;
15
+
16
  /* helper. Remove dir recursively. No warnings - fails silently
17
  Set $removeTheDirItself to false if you want to empty the dir
18
  */
70
  );
71
 
72
 
73
+ Option::updateOption('webp-express-migration-version', '2');
lib/migrate/migrate3.php CHANGED
@@ -15,6 +15,7 @@ use \WebPExpress\PathHelper;
15
  include_once __DIR__ . '/../classes/Messenger.php';
16
  use \WebPExpress\Messenger;
17
 
 
18
 
19
  if ( ! function_exists('webp_express_glob_recursive'))
20
  {
@@ -120,7 +121,7 @@ function webpexpress_migrate3() {
120
 
121
 
122
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
123
- update_option('webp-express-migration-version', '3');
124
 
125
  }
126
 
15
  include_once __DIR__ . '/../classes/Messenger.php';
16
  use \WebPExpress\Messenger;
17
 
18
+ use \WebPExpress\Option;
19
 
20
  if ( ! function_exists('webp_express_glob_recursive'))
21
  {
121
 
122
 
123
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
124
+ Option::updateOption('webp-express-migration-version', '3');
125
 
126
  }
127
 
lib/migrate/migrate4.php CHANGED
@@ -9,6 +9,7 @@ use \WebPExpress\Config;
9
  include_once __DIR__ . '/../classes/Messenger.php';
10
  use \WebPExpress\Messenger;
11
 
 
12
 
13
  function webpexpress_migrate4() {
14
  $config = Config::loadConfig();
@@ -61,7 +62,7 @@ function webpexpress_migrate4() {
61
  }
62
 
63
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
64
- update_option('webp-express-migration-version', '4');
65
 
66
  }
67
 
9
  include_once __DIR__ . '/../classes/Messenger.php';
10
  use \WebPExpress\Messenger;
11
 
12
+ use \WebPExpress\Option;
13
 
14
  function webpexpress_migrate4() {
15
  $config = Config::loadConfig();
62
  }
63
 
64
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
65
+ Option::updateOption('webp-express-migration-version', '4');
66
 
67
  }
68
 
lib/migrate/migrate5.php CHANGED
@@ -12,6 +12,8 @@ use \WebPExpress\Messenger;
12
  include_once __DIR__ . '/../classes/CacheMover.php';
13
  use \WebPExpress\CacheMover;
14
 
 
 
15
  function webpexpress_migrate5() {
16
 
17
  // Regenerate configuration file and wod-options.json.
@@ -20,7 +22,7 @@ function webpexpress_migrate5() {
20
  // By regenerating wod-options.json, we ensure that the new "paths" option is there, which is required in "mingled" mode for
21
  // determining if an image resides in the uploads folder or not.
22
 
23
- $config = Config::loadConfigAndFix();
24
  if ($config['operation-mode'] == 'just-convert') {
25
  $config['operation-mode'] = 'no-varied-responses';
26
  }
@@ -37,16 +39,16 @@ function webpexpress_migrate5() {
37
 
38
  Messenger::addMessage(
39
  'info',
40
- 'Successfully migrated webp express options for 0.11+'
41
  );
42
 
43
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
44
- update_option('webp-express-migration-version', '5');
45
 
46
  } else {
47
  Messenger::addMessage(
48
  'error',
49
- 'Failed migrating webp express options to 0.11+. Probably you need to grant write permissions in your wp-content folder.'
50
  );
51
  }
52
 
12
  include_once __DIR__ . '/../classes/CacheMover.php';
13
  use \WebPExpress\CacheMover;
14
 
15
+ use \WebPExpress\Option;
16
+
17
  function webpexpress_migrate5() {
18
 
19
  // Regenerate configuration file and wod-options.json.
22
  // By regenerating wod-options.json, we ensure that the new "paths" option is there, which is required in "mingled" mode for
23
  // determining if an image resides in the uploads folder or not.
24
 
25
+ $config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
26
  if ($config['operation-mode'] == 'just-convert') {
27
  $config['operation-mode'] = 'no-varied-responses';
28
  }
39
 
40
  Messenger::addMessage(
41
  'info',
42
+ 'Successfully migrated <i>WebP Express</i> options for 0.11+'
43
  );
44
 
45
  // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
46
+ Option::updateOption('webp-express-migration-version', '5');
47
 
48
  } else {
49
  Messenger::addMessage(
50
  'error',
51
+ 'Failed migrating WebP Express options to 0.11+. Probably you need to grant write permissions in your wp-content folder.'
52
  );
53
  }
54
 
lib/migrate/migrate6.php CHANGED
@@ -2,18 +2,11 @@
2
 
3
  namespace WebPExpress;
4
 
5
-
6
- include_once __DIR__ . '/../classes/Config.php';
7
  use \WebPExpress\Config;
8
-
9
- include_once __DIR__ . '/../classes/Messenger.php';
10
  use \WebPExpress\Messenger;
11
-
12
- include_once __DIR__ . '/../classes/HTAccess.php';
13
  use \WebPExpress\HTAccess;
14
-
15
- include_once __DIR__ . '/../classes/Paths.php';
16
  use \WebPExpress\Paths;
 
17
 
18
  /**
19
  * Fix records - if possible
@@ -35,7 +28,7 @@ function webpexpress_migrate6() {
35
  // Regenerate .htaccess file if placed in root (so rewrites does not apply in wp-admin area)
36
  if (HTAccess::isInActiveHTAccessDirsArray('index')) {
37
  if (Config::isConfigFileThere()) {
38
- $config = Config::loadConfigAndFix();
39
 
40
  $rules = HTAccess::generateHTAccessRulesFromConfigObj($config, 'index');
41
  $success = (HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', $rules, true));
@@ -69,7 +62,7 @@ function webpexpress_migrate6() {
69
  webpexpress_migrate6_fixHtaccessRecordsForDir($dirId);
70
  }
71
 
72
- update_option('webp-express-migration-version', '6');
73
  }
74
 
75
  webpexpress_migrate6();
2
 
3
  namespace WebPExpress;
4
 
 
 
5
  use \WebPExpress\Config;
 
 
6
  use \WebPExpress\Messenger;
 
 
7
  use \WebPExpress\HTAccess;
 
 
8
  use \WebPExpress\Paths;
9
+ use \WebPExpress\Option;
10
 
11
  /**
12
  * Fix records - if possible
28
  // Regenerate .htaccess file if placed in root (so rewrites does not apply in wp-admin area)
29
  if (HTAccess::isInActiveHTAccessDirsArray('index')) {
30
  if (Config::isConfigFileThere()) {
31
+ $config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
32
 
33
  $rules = HTAccess::generateHTAccessRulesFromConfigObj($config, 'index');
34
  $success = (HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', $rules, true));
62
  webpexpress_migrate6_fixHtaccessRecordsForDir($dirId);
63
  }
64
 
65
+ Option::updateOption('webp-express-migration-version', '6');
66
  }
67
 
68
  webpexpress_migrate6();
lib/migrate/migrate7.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebPExpress;
4
+
5
+ use \WebPExpress\Config;
6
+ use \WebPExpress\HTAccess;
7
+ use \WebPExpress\Messenger;
8
+ use \WebPExpress\CapabilityTest;
9
+
10
+ function webpexpress_migrate7() {
11
+
12
+ $config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
13
+ if ($config['operation-mode'] == 'just-redirect') {
14
+ $config['operation-mode'] = 'no-conversion';
15
+ }
16
+ if ($config['operation-mode'] == 'no-varied-responses') {
17
+ $config['operation-mode'] = 'cdn-friendly';
18
+ }
19
+ if ($config['operation-mode'] == 'varied-responses') {
20
+ $config['operation-mode'] = 'varied-image-responses';
21
+ }
22
+ if (isset($config['do-not-pass-source-in-query-string'])) {
23
+ unset($config['do-not-pass-source-in-query-string']);
24
+ }
25
+
26
+ // Migrate some configurations to the new "No conversion" mode
27
+ if ((!$config['enable-redirection-to-webp-realizer']) && (!$config['enable-redirection-to-converter']) && ($config['destination-folder'] == 'mingled') && ($config['operation-mode'] == 'cdn-friendly') && (!($config['web-service']['enabled']))) {
28
+ $config['operation-mode'] = 'no-conversion';
29
+ }
30
+
31
+ // In next migration, we can remove do-not-pass-source-in-query-string
32
+ // unset($config['do-not-pass-source-in-query-string']);
33
+ // and also do: grep -r 'do-not-pass' .
34
+
35
+ if (Config::saveConfigurationFileAndWodOptions($config)) {
36
+
37
+ $msg = 'Successfully migrated <i>WebP Express</i> options for 0.12. ';
38
+ // The webp realizer rules where errornous, so recreate rules, if neccessary. (see issue #195)
39
+
40
+ if (($config['enable-redirection-to-webp-realizer']) && ($config['destination-folder'] != 'mingled')) {
41
+ HTAccess::saveRules($config);
42
+ $msg .= 'Also fixed <a target="_blank" href="https://github.com/rosell-dk/webp-express/issues/195">buggy</a> <i>.htaccess</i> rules. ';
43
+ }
44
+
45
+ if (!$config['alter-html']['enabled']) {
46
+ if ($config['operation-mode'] == 'varied-responses') {
47
+ $msg .= '<br>In WebP Express 0.12, the <i>Alter HTML</i> option is no longer in beta. ' .
48
+ '<i>You should consider to go and <a href="' . Paths::getSettingsUrl() . '">activate it</a></i> - ' .
49
+ 'It works great in <i>Varied Image Responses</i> mode too. ';
50
+ } else {
51
+ $msg .= '<br>In WebP Express 0.12, Alter HTML is no longer in beta. ' .
52
+ '<i>Now would be a good time to <a href="' . Paths::getSettingsUrl() . '">go and activate it!</a></i>. ';
53
+ }
54
+ }
55
+
56
+ // Display announcement. But only show while it is fresh news (we don't want this to show when one is upgrading from 0.11 to 0.14 or something)
57
+ // - the next release with a migration in it will not show the announcement
58
+ if (WEBPEXPRESS_MIGRATION_VERSION == 7) {
59
+ $msg .= '<br><br>Btw: From this release and onward, WebP Express is <i>multisite compliant</i>.';
60
+ }
61
+
62
+ Messenger::addMessage(
63
+ 'info',
64
+ $msg
65
+ );
66
+
67
+ if ($config['operation-mode'] == 'no-conversion') {
68
+ Messenger::addMessage(
69
+ 'info',
70
+ 'WebP Express introduces a new operation mode: "No conversion". ' .
71
+ 'Your configuration has been migrated to this mode, because your previous settings matched that mode (nothing where set up to trigger a conversion).'
72
+ );
73
+ }
74
+
75
+ // PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
76
+ Option::updateOption('webp-express-migration-version', '7');
77
+
78
+
79
+ CapabilityTest::copyCapabilityTestsToWpContent();
80
+
81
+ // Not completely sure if this could fail miserably, so commented out.
82
+ // We should probably do it in upcoming migrations
83
+ // \WebPExpress\KeepEwwwSubscriptionAlive::keepAliveIfItIsTime($config);
84
+
85
+ } else {
86
+ Messenger::addMessage(
87
+ 'error',
88
+ 'Failed migrating webp express options to 0.12+. Probably you need to grant write permissions in your wp-content folder.'
89
+ );
90
+ }
91
+
92
+ }
93
+
94
+ webpexpress_migrate7();
lib/options/css/webp-express-options-page.css CHANGED
@@ -20,12 +20,12 @@
20
  }*/
21
 
22
  @media (min-width: 782px) {
23
- #webpexpress_settings .form-table th {
24
  padding-top: 5px;
25
  padding-bottom: 5px;
26
  width: 200px;
27
  }
28
- #webpexpress_settings .form-table td {
29
  padding-top: 1px;
30
  padding-bottom: 5px;
31
  }
@@ -428,6 +428,133 @@
428
  font-style: italic;
429
  }
430
 
 
431
  #alter_html_options_div > div {
432
  margin-top: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  }
20
  }*/
21
 
22
  @media (min-width: 782px) {
23
+ #webpexpress_settings .form-table > tbody > tr > th {
24
  padding-top: 5px;
25
  padding-bottom: 5px;
26
  width: 200px;
27
  }
28
+ #webpexpress_settings .form-table > tbody > tr > td {
29
  padding-top: 1px;
30
  padding-bottom: 5px;
31
  }
428
  font-style: italic;
429
  }
430
 
431
+ /*
432
  #alter_html_options_div > div {
433
  margin-top: 15px;
434
+ }*/
435
+
436
+ .form-table table th {
437
+ font-weight: unset;
438
+ padding: 5px 0px;
439
+ width: auto;
440
+ }
441
+
442
+ .form-table table td {
443
+ padding: 0 10px;
444
+ width: auto;
445
+ }
446
+
447
+
448
+ .form-table td input[type=checkbox] {
449
+ margin-top: 6px;
450
+ }
451
+
452
+ .form-table h2 {
453
+ /*font-size: 1.6em;*/
454
+ text-transform: uppercase;
455
+ color: #222;
456
+ }
457
+ .form-table th[colspan='2'] {
458
+ font-weight: normal;
459
+ font-size: 14px;
460
+ }
461
+ .form-table th.header-section h2 {
462
+ margin-top: 30px;
463
+ margin-bottom: 10px;
464
+ }
465
+ .form-table th.header-section h2 + p {
466
+ margin-top: 10px;
467
+ }
468
+ .form-table th.header-section p,
469
+ .form-table th.header-section h2,
470
+ fieldset.block p,
471
+ fieldset.block div.p {
472
+ max-width: 750px;
473
+ }
474
+
475
+ .toggler.effect-slider {
476
+ overflow-y: hidden;
477
+ transition: all 0.3s ease-in-out;
478
+ /*transition: all 0.5s cubic-bezier(0, 1, 0.5, 1);*/
479
+ }
480
+ .toggler.effect-slider.closed {
481
+ transition: all 0.5s cubic-bezier(0, 1, 0.5, 1);
482
+ max-height: 0px !important;
483
+ }
484
+
485
+ .toggler.effect-opacity.closed {
486
+ opacity: 0.5;
487
+ pointer-events: none;
488
+ font-weight: 300 !important;
489
+ }
490
+ .form-table .toggler.effect-opacity.closed th {
491
+ font-weight: 400 !important;
492
+ }
493
+
494
+ .toggler.effect-visibility {
495
+ /*position: static;
496
+ visibility: inherit;*/
497
+ }
498
+ .toggler.effect-visibility.closed {
499
+ visibility: hidden;
500
+ position: absolute;
501
+ }
502
+
503
+ .form-table h4 {
504
+ margin-bottom: 0;
505
+ text-decoration: underline;
506
+ }
507
+
508
+ table.designed {
509
+ border-collapse: collapse;
510
+ margin-bottom: 20px;
511
+ /*box-shadow: 2px 2px 5px 2px rgba(0, 0, 0, 0.1)*/
512
+ }
513
+ table.designed th {
514
+ font-weight: bold;
515
+ background-color: #fff;
516
+ }
517
+ table.designed td,
518
+ table.designed th {
519
+ text-align: left;
520
+ padding: 9px 17px;
521
+ border: 1px solid #999;
522
+ vertical-align: top;
523
+ }
524
+ table.designed td,
525
+ table.designed th,
526
+ table.designed p {
527
+ font-size: 12px;
528
+ line-height: 1.3;
529
+ }
530
+ table.designed td > p:first-child {
531
+ margin-top: 0;
532
+ }
533
+ table.designed tr:nth-child(odd) > td {
534
+ background-color: #eee;
535
+ }
536
+ table.designed tr:nth-child(even) > td {
537
+ background-color: #ddd;
538
+ }
539
+ table.designed th:first-child {
540
+ border-left-width: 0;
541
+ }
542
+ table.designed tr:first-child > th {
543
+ border-top-width: 0;
544
+ }
545
+ table.designed tr > *:last-child {
546
+ border-right-width: 0;
547
+ }
548
+
549
+ #hide_alterhtml_chart_btn {
550
+ margin-bottom: 20px;
551
+ }
552
+
553
+ /*table.designed tr:last-child > * {
554
+ border-bottom-width: 0;
555
+ }*/
556
+
557
+ ul.with-bullets {
558
+ padding-left: 20px;
559
+ list-style: unset;
560
  }
lib/options/enqueue_scripts.php CHANGED
@@ -6,16 +6,20 @@ use \WebPExpress\Paths;
6
  include_once __DIR__ . '/../classes/Config.php';
7
  use \WebPExpress\Config;
8
 
9
- $version = '0.11.0-dev1';
10
-
11
- function webp_express_add_inline_script($id, $script, $position) {
12
- if (function_exists('wp_add_inline_script')) {
13
- // wp_add_inline_script is available from Wordpress 4.5
14
- wp_add_inline_script($id, $script, $position);
15
- } else {
16
- echo '<script>' . $script . '</script>';
 
 
 
17
  }
18
  }
 
19
  wp_register_script('sortable', plugins_url('js/sortable.min.js', __FILE__), [], '1.9.0');
20
  wp_enqueue_script('sortable');
21
 
@@ -24,7 +28,7 @@ wp_enqueue_script('daspopup');
24
 
25
  $config = Config::getConfigForOptionsPage();
26
 
27
- if (!(isset($config['operation-mode']) && $config['operation-mode'] == 'just-redirect')) {
28
 
29
  // Remove empty options arrays.
30
  // These cause trouble in json because they are encoded as [] rather than {}
6
  include_once __DIR__ . '/../classes/Config.php';
7
  use \WebPExpress\Config;
8
 
9
+ $version = '0.12.0';
10
+
11
+
12
+ if (!function_exists('webp_express_add_inline_script')) {
13
+ function webp_express_add_inline_script($id, $script, $position) {
14
+ if (function_exists('wp_add_inline_script')) {
15
+ // wp_add_inline_script is available from Wordpress 4.5
16
+ wp_add_inline_script($id, $script, $position);
17
+ } else {
18
+ echo '<script>' . $script . '</script>';
19
+ }
20
  }
21
  }
22
+
23
  wp_register_script('sortable', plugins_url('js/sortable.min.js', __FILE__), [], '1.9.0');
24
  wp_enqueue_script('sortable');
25
 
28
 
29
  $config = Config::getConfigForOptionsPage();
30
 
31
+ if (!(isset($config['operation-mode']) && $config['operation-mode'] == 'no-conversion')) {
32
 
33
  // Remove empty options arrays.
34
  // These cause trouble in json because they are encoded as [] rather than {}
lib/options/js/page.js CHANGED
@@ -1,156 +1,200 @@
1
- function setOptionVisibility(elmId, show) {
2
  var elm = document.getElementById(elmId);
3
  if (!elm) {
4
  return;
5
  }
 
 
 
 
 
6
  if (show) {
7
- elm.style['visibility'] = 'inherit';
8
- elm.style['position'] = 'static';
9
  } else {
10
- elm.style['visibility'] = 'hidden';
11
- elm.style['position'] = 'absolute';
12
  }
13
  }
14
 
15
- function updateAlterHTMLVisibility() {
16
- if (document.getElementById('alter_html_enabled')) {
17
- setOptionVisibility('alter_html_options_div', document.getElementById('alter_html_enabled').checked);
18
  }
19
- }
20
 
21
- function updateAlterHTMLReplaceVisibility() {
22
- if (document.getElementById('alter_html_replacement_url')) {
23
- setOptionVisibility('alter_html_url_options_div', document.getElementById('alter_html_replacement_url').checked);
 
 
 
 
 
 
24
  }
25
- }
26
 
27
 
 
 
 
28
 
29
- function updateCacheControlCustomVisibility() {
30
 
31
- if (document.getElementById('cache_control_select') == null) {
32
- // Well, it seems that the cache control option isn't available in this operation mode
33
- return;
34
- }
35
- if (document.getElementById('cache_control_custom') == null) {
36
- alert('document.getElementById("cache_control_custom") returns null. Strange! Please report.');
37
- return;
38
- }
39
- if (document.getElementById('cache_control_public') == null) {
40
- alert('document.getElementById("cache_control_public") returns null. Strange! Please report.');
41
- return;
42
- }
43
 
44
- var cacheControlValue = document.getElementById('cache_control_select').value;
45
- /*
46
- var customEl = document.getElementById('cache_control_custom');
47
- if (cacheControlValue == 'custom') {
48
- customEl.setAttribute('type', 'text');
49
- } else {
50
- customEl.setAttribute('type', 'hidden');
51
- }*/
52
 
53
- setOptionVisibility('cache_control_custom_div', (cacheControlValue == 'custom'));
54
 
55
- setOptionVisibility('cache_control_set_div', (cacheControlValue == 'set'));
 
 
 
 
56
 
57
- }
 
 
 
58
 
59
- function updateQualityVisibility() {
60
- var qualityAutoEl = document.getElementById('quality_auto_select');
61
- if (!qualityAutoEl) {
62
- return;
63
- }
64
- var qualityAutoValue = qualityAutoEl.value;
65
- var maxQualityRowEl = document.getElementById('max_quality_row');
66
- var qualitySpecificRowEl = document.getElementById('quality_specific_row');
67
-
68
- //alert(qualityAutoValue);
69
- if (qualityAutoValue == 'auto_on') {
70
- maxQualityRowEl.style['display'] = 'table-row';
71
- qualitySpecificRowEl.style['display'] = 'none';
72
- } else {
73
- maxQualityRowEl.style['display'] = 'none';
74
- qualitySpecificRowEl.style['display'] = 'table-row';
75
- }
76
- }
77
 
78
- function updateDestinationExtensionVisibility() {
79
- var destinationFolderEl = document.getElementById('destination_folder');
80
- if (!destinationFolderEl) {
81
- return;
82
- }
83
- var destinationFolderValue = destinationFolderEl.value;
84
- var destinationExtensionEl = document.getElementById('destination_extension_row');
85
 
86
- //alert(qualityAutoValue);
87
- if (destinationFolderValue == 'mingled') {
88
- destinationExtensionEl.style['display'] = 'table-row';
89
- } else {
90
- destinationExtensionEl.style['display'] = 'none';
 
 
91
  }
92
 
93
- }
94
 
95
- function updateServerSettingsVisibility() {
96
- var enabledEl = document.getElementById('web_service_enabled');
97
- if (!enabledEl) {
98
- return;
 
 
 
 
 
 
 
 
99
  }
100
- var enabled = enabledEl.checked;
101
- //document.getElementById('whitelist_row').style['display'] = (enabled ? 'table-row' : 'none');
102
- //document.getElementById('server_url').style['display'] = (enabled ? 'table-row' : 'none');
103
- document.getElementById('whitelist_div').style['display'] = (enabled ? 'block' : 'none');
104
- }
105
 
106
- document.addEventListener('DOMContentLoaded', function() {
107
- //resetToDefaultConverters();
108
- updateCacheControlCustomVisibility();
109
- updateQualityVisibility();
110
- updateServerSettingsVisibility();
111
- updateAlterHTMLVisibility();
112
- updateAlterHTMLReplaceVisibility();
113
- updateDestinationExtensionVisibility();
114
-
115
- if (document.getElementById('cache_control_select')) {
116
- document.getElementById('cache_control_select').addEventListener('change', function() {
117
- updateCacheControlCustomVisibility();
118
  });
119
  }
120
 
121
- if (document.getElementById('quality_auto_select')) {
122
- document.getElementById('quality_auto_select').addEventListener('change', function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  updateQualityVisibility();
124
  });
125
  }
126
 
127
- if (document.getElementById('destination_folder')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  document.getElementById('destination_folder').addEventListener('change', function() {
129
  updateDestinationExtensionVisibility();
130
  });
131
  }
132
 
133
- if (document.getElementById('web_service_enabled')) {
 
 
 
 
 
 
 
134
  document.getElementById('web_service_enabled').addEventListener('change', function() {
135
  updateServerSettingsVisibility();
136
  });
137
  }
138
 
139
- if (document.getElementById('alter_html_enabled')) {
140
- document.getElementById('alter_html_enabled').addEventListener('change', function() {
 
 
 
 
 
 
 
 
 
141
  updateAlterHTMLVisibility();
142
  });
143
  }
144
 
145
- if (document.getElementById('alter_html_replacement_url')) {
146
- document.getElementById('alter_html_replacement_url').addEventListener('change', function() {
 
 
 
 
 
 
 
 
 
147
  updateAlterHTMLReplaceVisibility();
148
  });
149
- document.getElementById('alter_html_replacement_picture').addEventListener('change', function() {
150
  updateAlterHTMLReplaceVisibility();
151
  });
152
  }
153
 
 
 
 
 
 
 
154
 
155
 
156
  document.getElementById('change_operation_mode').addEventListener('change', function() {
1
+ function toggleVisibility(elmId, show) {
2
  var elm = document.getElementById(elmId);
3
  if (!elm) {
4
  return;
5
  }
6
+ elm.classList.add('toggler');
7
+ /*
8
+ if (!elm.style.maxHeight) {
9
+ elm.style['maxHeight'] = (elm.clientHeight + 40) + 'px';
10
+ }*/
11
  if (show) {
12
+ elm.classList.remove('closed');
 
13
  } else {
14
+ elm.classList.add('closed');
 
15
  }
16
  }
17
 
18
+ function updateAlterHTMLChartVisibility(show) {
19
+ function el(elmId) {
20
+ return document.getElementById(elmId);
21
  }
 
22
 
23
+
24
+ var elm = el('alter_html_comparison_chart');
25
+ //elm.style['maxHeight'] = (elm.clientHeight + 40) + 'px';
26
+ //elm.style['maxHeight'] = '600px';
27
+ //elm.style.display = (show ? 'block' : 'none');
28
+ if (show) {
29
+ elm.classList.remove('closed');
30
+ } else {
31
+ elm.classList.add('closed');
32
  }
 
33
 
34
 
35
+ el('hide_alterhtml_chart_btn').style.display = (show ? 'block' : 'none');
36
+ el('show_alterhtml_chart_btn').style.display = (show ? 'none' : 'inline-block');
37
+ el('ui_show_alter_html_chart').value = (show ? 'true' : 'false');
38
 
 
39
 
40
+ }
 
 
 
 
 
 
 
 
 
 
 
41
 
 
 
 
 
 
 
 
 
42
 
 
43
 
44
+ document.addEventListener('DOMContentLoaded', function() {
45
+ //resetToDefaultConverters();
46
+ function el(elmId) {
47
+ return document.getElementById(elmId);
48
+ }
49
 
50
+ if (el('cache_control_select') && el('cache_control_custom_div') && el('cache_control_set_div')) {
51
+ el('cache_control_custom_div').classList.add('effect-visibility');
52
+ el('cache_control_set_div').classList.add('effect-visibility');
53
+ function updateCacheControlCustomVisibility() {
54
 
55
+ var cacheControlValue = document.getElementById('cache_control_select').value;
56
+ /*
57
+ var customEl = document.getElementById('cache_control_custom');
58
+ if (cacheControlValue == 'custom') {
59
+ customEl.setAttribute('type', 'text');
60
+ } else {
61
+ customEl.setAttribute('type', 'hidden');
62
+ }*/
 
 
 
 
 
 
 
 
 
 
63
 
64
+ toggleVisibility('cache_control_custom_div', (cacheControlValue == 'custom'));
 
 
 
 
 
 
65
 
66
+ toggleVisibility('cache_control_set_div', (cacheControlValue == 'set'));
67
+
68
+ }
69
+ updateCacheControlCustomVisibility();
70
+ el('cache_control_select').addEventListener('change', function() {
71
+ updateCacheControlCustomVisibility();
72
+ });
73
  }
74
 
 
75
 
76
+ // In "No conversion" and "CDN friendly" mode, toggle cache control div when redirect is enabled/disabled
77
+ if (el('operation_mode') && (el('operation_mode').value == 'no-conversion')) {
78
+ if (el('redirect_to_existing_in_htaccess') && el('cache_control_div')) {
79
+ el('cache_control_div').classList.add('effect-opacity');
80
+ function updateCacheControlHeaderVisibility() {
81
+ toggleVisibility('cache_control_div', el('redirect_to_existing_in_htaccess').checked);
82
+ }
83
+ updateCacheControlHeaderVisibility();
84
+ el('redirect_to_existing_in_htaccess').addEventListener('change', function() {
85
+ updateCacheControlHeaderVisibility();
86
+ });
87
+ }
88
  }
 
 
 
 
 
89
 
90
+ if (el('only_redirect_to_converter_for_webp_enabled_browsers_row') && el('enable_redirection_to_converter')) {
91
+ el('only_redirect_to_converter_for_webp_enabled_browsers_row').classList.add('effect-opacity');
92
+ el('only_redirect_to_converter_on_cache_miss_row').classList.add('effect-opacity');
93
+ function updateRedirectionOnlyWebPVisibility() {
94
+ toggleVisibility('only_redirect_to_converter_for_webp_enabled_browsers_row', el('enable_redirection_to_converter').checked);
95
+ toggleVisibility('only_redirect_to_converter_on_cache_miss_row', el('enable_redirection_to_converter').checked);
96
+
97
+ }
98
+ updateRedirectionOnlyWebPVisibility();
99
+ el('enable_redirection_to_converter').addEventListener('change', function() {
100
+ updateRedirectionOnlyWebPVisibility();
 
101
  });
102
  }
103
 
104
+
105
+ // Toggle Quality (auto / specific)
106
+ if (el('quality_auto_select') && el('max_quality_row') && el('quality_specific_row')) {
107
+ function updateQualityVisibility() {
108
+ var qualityAutoValue = el('quality_auto_select').value;
109
+ if (qualityAutoValue == 'auto_on') {
110
+ el('max_quality_row').style['display'] = 'table-row';
111
+ el('quality_specific_row').style['display'] = 'none';
112
+ } else {
113
+ el('max_quality_row').style['display'] = 'none';
114
+ el('quality_specific_row').style['display'] = 'table-row';
115
+ }
116
+ }
117
+ updateQualityVisibility();
118
+ el('quality_auto_select').addEventListener('change', function() {
119
  updateQualityVisibility();
120
  });
121
  }
122
 
123
+ // Toggle File Extension (only show when "mingled" is selected)
124
+ if (el('destination_folder') && el('destination_extension_row') && el('destination_extension')) {
125
+ el('destination_extension_row').classList.add('effect-opacity');
126
+ function updateDestinationExtensionVisibility() {
127
+ toggleVisibility('destination_extension_row', el('destination_folder').value == 'mingled');
128
+
129
+ if (el('destination_folder').value == 'separate') {
130
+ el('destination_extension').value = 'append';
131
+ }
132
+ /*
133
+ if (document.getElementById('destination_folder').value == 'mingled') {
134
+ el('destination_extension_row').style['display'] = 'table-row';
135
+ } else {
136
+ el('destination_extension_row').style['display'] = 'none';
137
+ }*/
138
+
139
+ }
140
+ updateDestinationExtensionVisibility();
141
  document.getElementById('destination_folder').addEventListener('change', function() {
142
  updateDestinationExtensionVisibility();
143
  });
144
  }
145
 
146
+ // Toggle webservice
147
+ if (el('web_service_enabled') && el('whitelist_div')) {
148
+ el('whitelist_div').classList.add('effect-opacity');
149
+ function updateServerSettingsVisibility() {
150
+ toggleVisibility('whitelist_div', el('web_service_enabled').checked);
151
+ //document.getElementById('whitelist_div').style['display'] = (el('web_service_enabled').checked ? 'block' : 'none');
152
+ }
153
+ updateServerSettingsVisibility();
154
  document.getElementById('web_service_enabled').addEventListener('change', function() {
155
  updateServerSettingsVisibility();
156
  });
157
  }
158
 
159
+ // Toggle Alter HTML options
160
+ if (el('alter_html_enabled') && (el('alter_html_options_div'))) {
161
+ el('alter_html_options_div').classList.add('effect-opacity');
162
+ el('alter_html_comparison_chart').classList.add('effect-slider');
163
+ function updateAlterHTMLVisibility() {
164
+ toggleVisibility('alter_html_options_div', el('alter_html_enabled').checked);
165
+ // toggleVisibility('alter_html_comparison_chart', el('alter_html_enabled').checked);
166
+
167
+ }
168
+ updateAlterHTMLVisibility();
169
+ el('alter_html_enabled').addEventListener('change', function() {
170
  updateAlterHTMLVisibility();
171
  });
172
  }
173
 
174
+ // Show/hide "Only do the replacements in webp enabled browsers" when "What to replace" is changed
175
+ if (el('alter_html_replacement_url') && el('alter_html_url_options_div')) {
176
+ el('alter_html_url_options_div').classList.add('effect-opacity');
177
+ el('alter_html_picture_options_div').classList.add('effect-opacity');
178
+ function updateAlterHTMLReplaceVisibility() {
179
+ toggleVisibility('alter_html_url_options_div', el('alter_html_replacement_url').checked);
180
+ toggleVisibility('alter_html_picture_options_div', el('alter_html_replacement_picture').checked);
181
+ }
182
+ updateAlterHTMLReplaceVisibility();
183
+
184
+ el('alter_html_replacement_url').addEventListener('change', function() {
185
  updateAlterHTMLReplaceVisibility();
186
  });
187
+ el('alter_html_replacement_picture').addEventListener('change', function() {
188
  updateAlterHTMLReplaceVisibility();
189
  });
190
  }
191
 
192
+ if (el('ui_show_alter_html_chart') && el('alter_html_comparison_chart')) {
193
+ var elm = el('alter_html_comparison_chart');
194
+ elm.style['maxHeight'] = (elm.clientHeight + 80) + 'px';
195
+
196
+ updateAlterHTMLChartVisibility(el('ui_show_alter_html_chart').value == 'true');
197
+ }
198
 
199
 
200
  document.getElementById('change_operation_mode').addEventListener('change', function() {
lib/options/options-hooks.php CHANGED
@@ -1,16 +1,30 @@
1
  <?php
 
 
2
 
3
- add_action( 'admin_menu', function() {
4
-
5
- //Add Settings Page
6
- add_options_page(
7
- 'WebP Express Settings', //Page Title
8
- 'WebP Express', //Menu Title
9
- 'manage_options', //capability
10
- 'webp_express_settings_page', //menu slug
11
- 'webp_express_settings_page_content' //The function to be called to output the content for this page.
12
- );
13
- });
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  add_action('admin_post_webpexpress_settings_submit', function() {
16
  include __DIR__ . '/submit.php';
@@ -25,11 +39,12 @@ function webp_express_settings_page_content()
25
  function webp_express_admin_init() {
26
 
27
  global $pagenow;
28
- if ( ( 'options-general.php' === $pagenow ) && ( isset( $_GET['page'] ) ) && ( 'webp_express_settings_page' === $_GET['page'] ) ) {
29
- add_action( 'admin_enqueue_scripts', function () {
30
- include __DIR__ . '/enqueue_scripts.php';
31
- } );
32
  }
 
33
  }
34
 
35
  add_action( 'admin_init', 'webp_express_admin_init');
1
  <?php
2
+ use \WebPExpress\Config;
3
+ use \WebPExpress\Multisite;
4
 
5
+ if (Multisite::isNetworkActivated()) {
6
+ add_action("network_admin_menu", function() {
7
+ add_submenu_page(
8
+ 'settings.php', // Parent element
9
+ 'WebP Express settings (for network)', // Text in browser title bar
10
+ 'WebP Express', // Text to be displayed in the menu.
11
+ 'manage_network_options', // Capability
12
+ 'webp_express_settings_page', // slug
13
+ 'webp_express_settings_page_content' // Callback function which displays the page
14
+ );
15
+ });
16
+ } else {
17
+ add_action( 'admin_menu', function() {
18
+ //Add Settings Page
19
+ add_options_page(
20
+ 'WebP Express Settings', //Page Title
21
+ 'WebP Express', //Menu Title
22
+ 'manage_options', //capability
23
+ 'webp_express_settings_page', // slug
24
+ 'webp_express_settings_page_content' //The function to be called to output the content for this page.
25
+ );
26
+ });
27
+ }
28
 
29
  add_action('admin_post_webpexpress_settings_submit', function() {
30
  include __DIR__ . '/submit.php';
39
  function webp_express_admin_init() {
40
 
41
  global $pagenow;
42
+ if ((('options-general.php' === $pagenow) || (('settings.php' === $pagenow))) && (isset( $_GET['page'])) && ('webp_express_settings_page' === $_GET['page'])) {
43
+ add_action( 'admin_enqueue_scripts', function () {
44
+ include __DIR__ . '/enqueue_scripts.php';
45
+ } );
46
  }
47
+
48
  }
49
 
50
  add_action( 'admin_init', 'webp_express_admin_init');
lib/options/options/alter-html/alter-html-options.inc CHANGED
@@ -1,9 +1,9 @@
1
  <tr>
2
- <th scope="row">Alter HTML? <span style="color:darkorange">(beta)</span><?php echo helpIcon(
3
  '<p>Alter HTML to either use picture tag syntax for pointing to webp versions or point directly to webps.</p>' .
4
- '<p>The feature is new in 0.11.0. It is marked as beta because of that, but it has been tested on many setups and with ' .
5
- 'many test cases, so it should be quite stable.</p>' .
6
- (($config['operation-mode'] == 'varied-responses') ?
7
  '<p>You do not need to enable this in <i>Varied image responses</i> operation mode, but enabling it has some benefits: ' .
8
  'Caching is improved if you are on a CDN as the webp images that are requested directly does not need to be keyed by the Accept header. ' .
9
  'Also, when a user downloads an image, it will have the correct extension.</p>' : '')
@@ -18,37 +18,130 @@
18
  value="true"
19
  type="checkbox"
20
  >
 
 
 
 
21
  <div id="alter_html_options_div">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  <div>
23
  <label>What to replace:</label>
 
24
  <?php
25
- webpexpress_radioButtons('alter-html-replacement', $config['alter-html']['replacement'], [
26
- 'picture' => 'Replace &lt;img&gt; tags with &lt;picture&gt; tags, adding the webp to srcset.',
27
- 'url' => 'Replace image URLs',
28
- ], [
29
- 'picture' => '<p>"Picture tag" replaces &lt;img&gt tags with &lt;picture&gt; tags and adds the webp as an extra source. ' .
 
30
  'This effectively points webp-enabled browsers to the webp variant and other browsers to ' .
31
- 'the original image. It also adds a script that dynamically loads picturefill.js in browsers ' .
32
- 'that doesnt support the picture tag.</p>' .
33
  '<p><em>Beware that this structural change may affect styling!</em></p>' .
34
  '<p>PS: This functionality is handled by ' .
35
  '<a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this external library</a>' .
36
- ' (I have pushed the code to an external library so it can be used by other projects besides this plugin)</p>',
37
- 'url' => '<p>"Image URLs" replaces the image URLs to point to ' .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  'the webp <i>rather than</i> the original. Handles src, srcset, common lazy-load attributes and even ' .
39
  'inline styles</p>' .
40
  '<p>Note that you will have to do something for the browsers that does not support webp. ' .
41
- 'For example, you can enable the <i>Only do the replacements in webp enabled browsers</i> option, which ' .
42
  'will show up when you enable this option. ' .
43
- 'Or you can add the <a href="https://webpjs.appspot.com/">webpjs</a> javascript library. ' .
44
- 'In the next release, you will be able to add the webjs library with this plugin. ' .
45
  '<p>PS: This replace functionality is handled by ' .
46
  '<a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this external library</a>' .
47
- ', created for the purpose.</p>',
48
- ]
49
  );
50
  ?>
51
- <div id="alter_html_url_options_div" style="margin-left:39px; margin-top: -5px;">
 
52
  <?php
53
  webpexpress_checkbox(
54
  'alter-html-only-for-webp-enabled-browsers',
@@ -56,32 +149,32 @@
56
  'Only do the replacements in webp enabled browsers',
57
  'If you enable this option, the replacements will only be made, when the request is from ' .
58
  'a browser that supports webp. Note that this will not play well with plugins that caches ' .
59
- 'the page. Instead of enabling this option, you should consider using the Cache Enabler plugin, ' .
60
- 'which does the same, but with page caching.'
61
  );
62
  ?>
63
- </div>
64
- </div>
65
- <div>
66
- <div style="margin-left: 11px">
67
- <?php
68
- webpexpress_checkbox(
69
- 'alter-html-for-webps-that-has-yet-to-exist',
70
- (!$config['alter-html']['only-for-webps-that-exists']),
71
- 'Reference webps that hasn\'t been converted yet',
72
- 'If you enable this option, there will be references to webp files that doesnt exist yet. ' .
73
- 'And that will be ok! - Just make sure to enable the option to convert missing webp files ' .
74
- 'upon request'
75
- );
76
- ?>
77
- </div>
78
  </div>
79
- <div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  <label>Where to replace: <?php echo helpIcon(
81
  '<p></p>',
82
  'no-margin-left set-margin-right');
83
  ?></label>
84
-
85
  <?php
86
  webpexpress_radioButtons('alter-html-hooks', $config['alter-html']['hooks'], [
87
  'content-hooks' => 'Use content filtering hooks (the_content, the_excerpt, etc)',
@@ -94,5 +187,5 @@
94
 
95
  </div>
96
 
97
- </td>
98
  </tr>
1
  <tr>
2
+ <th scope="row">Alter HTML?</span><?php echo helpIcon(
3
  '<p>Alter HTML to either use picture tag syntax for pointing to webp versions or point directly to webps.</p>' .
4
+ '<p>Pro picture tag syntax: The browser selects the webp if it supports it.</p>' .
5
+ '<p>Pro image urls: Also works on inline styles</p>' .
6
+ (($config['operation-mode'] == 'varied-image-responses') ?
7
  '<p>You do not need to enable this in <i>Varied image responses</i> operation mode, but enabling it has some benefits: ' .
8
  'Caching is improved if you are on a CDN as the webp images that are requested directly does not need to be keyed by the Accept header. ' .
9
  'Also, when a user downloads an image, it will have the correct extension.</p>' : '')
18
  value="true"
19
  type="checkbox"
20
  >
21
+ </td>
22
+ </tr>
23
+ <tr>
24
+ <th scope="row" colspan=2>
25
  <div id="alter_html_options_div">
26
+ <p>
27
+ Two distinct methods for altering HTML are supported. <a id="show_alterhtml_chart_btn" href="javascript:updateAlterHTMLChartVisibility(true);">View comparison chart</a>
28
+ <input type="hidden" name="ui-show-alter-html-chart" id="ui_show_alter_html_chart" value="<?php echo 'false'; ?>">
29
+ </p>
30
+ <div id="alter_html_comparison_chart" name="alter-html-comparison-chart" class="toggler effect-slider">
31
+ <table class="designed">
32
+ <tr>
33
+ <th></th>
34
+ <th>Method 1: Replacing &lt;img&gt; tags with &lt;picture&gt; tags</th>
35
+ <th>Method 2: Replacing image URLs</th>
36
+ </tr>
37
+ <tr>
38
+ <th>How it works</th>
39
+ <td>
40
+ <p>
41
+ It replaces &lt;img&gt; tags with &lt;picture&gt; tags, adding two &lt;source&gt; tags - one for the original image(s), and one
42
+ for the webp image(s).
43
+ Browsers that supports webp picks the &lt;source&gt; tag with <i>type</i> attribute set to "image/webp".
44
+ A small javascript can be optionally added for dynamically loading picturefill.js on browsers that doesn't support the picture tag.
45
+ </p>
46
+ <p>
47
+ We are using <a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this library</a>.
48
+ You can visit it for more information.
49
+ </p>
50
+ </td>
51
+ <td>
52
+ It replaces any image url it can find.
53
+ We are using <a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this library</a>.
54
+ You can visit it for more information.
55
+ </td>
56
+ </tr>
57
+ <tr>
58
+ <th>Page caching</th>
59
+ <td>Works great with page caching, because all browsers are served the same HTML</td>
60
+ <td>
61
+ <p>
62
+ As the HTML varies with the webp-capability of the browser, page caching is tricky.
63
+ However, it can be achieved with the wonderful <i>Cache Enabler</i> plugin, which maintains two cached versions of each page.<br><br>
64
+ <span style="font-size:10px">
65
+ Note: <i>Cache Enabler</i> also has HTML altering, but their implementation has <a target="_blank" href="https://github.com/keycdn/cache-enabler/issues/51">limitations</a>.
66
+ It for example doesn't replace background images in inline styles and it does not look for all common lazy load attributes. It also has some problems in edge cases.
67
+ For this reason, I recommend activating HTML altering in WebP Express, even when <i>Cache Enabler</i> is used.
68
+ By doing that, both plugins will have a go at it (WebP Express comes first).
69
+ At least it will take care of the limitations in <i>Cache Enabler</i>.
70
+ It does however not cure the edge cases where Cache Enabler replaces things it should not.
71
+ </span>
72
+ </p>
73
+ </td>
74
+ </tr>
75
+ <tr>
76
+ <th><nobr>Styling and javascript</nobr></th>
77
+ <td>May break because of changed HTML structure</td>
78
+ <td>No problems</td>
79
+ </tr>
80
+ <tr>
81
+ <th>Comprehensiveness</th>
82
+ <td>Only replaces &lt;img&gt; tags - other images are untouched</td>
83
+ <td>Very comprehensive. Replaces images in inline styles, image urls in lazy load attributes set in &lt;div&gt; or &lt;li&gt; tags, etc.</td>
84
+ </tr>
85
+ </table>
86
+ <p>
87
+ Note: The altering only happens for images that are converted and which exists in the same folder as the source with the extension selected in the GENERAL section.
88
+ </p>
89
+ </div>
90
+ <a id="hide_alterhtml_chart_btn" href="javascript:updateAlterHTMLChartVisibility(false);">Hide comparison chart</a>
91
  <div>
92
  <label>What to replace:</label>
93
+ <ul style="margin-left: 20px; margin-top: 5px"><li>
94
  <?php
95
+ webpexpress_radioButton(
96
+ 'alter-html-replacement',
97
+ 'picture',
98
+ 'Replace &lt;img&gt; tags with &lt;picture&gt; tags, adding the webp to srcset.',
99
+ $config['alter-html']['replacement'],
100
+ '<p>"Picture tag" replaces &lt;img&gt tags with &lt;picture&gt; tags and adds the webp as an extra source. ' .
101
  'This effectively points webp-enabled browsers to the webp variant and other browsers to ' .
102
+ 'the original image.</p>' .
 
103
  '<p><em>Beware that this structural change may affect styling!</em></p>' .
104
  '<p>PS: This functionality is handled by ' .
105
  '<a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this external library</a>' .
106
+ ' (I have pushed the code to an external library so it can be used by other projects besides this plugin)</p>'
107
+ );
108
+ ?>
109
+ </li>
110
+ <li><div id="alter_html_picture_options_div" style="margin-left:18px; margin-bottom: 13px;">
111
+ <?php
112
+ webpexpress_checkbox(
113
+ 'alter-html-add-picturefill-js',
114
+ $config['alter-html']['alter-html-add-picturefill-js'],
115
+ 'Dynamically load picturefill.js on older browsers',
116
+ 'If you enable this option, a small script will be added which detects if picture tags are supported and loads ' .
117
+ '<a href="https://github.com/scottjehl/picturefill" target="_blank">picturefill.js</a> if not. ' .
118
+ 'It is recommended to activate this option, unless your theme or another plugin adds such a script. ' .
119
+ 'Picture tag support is currently <a href="https://caniuse.com/#feat=picture" target="_blank">~88%</a>'
120
+ );
121
+ ?>
122
+ </div></li>
123
+ <li>
124
+ <?php
125
+ webpexpress_radioButton(
126
+ 'alter-html-replacement',
127
+ 'url',
128
+ 'Replace image URLs',
129
+ $config['alter-html']['replacement'],
130
+ '<p>"Image URLs" replaces the image URLs to point to ' .
131
  'the webp <i>rather than</i> the original. Handles src, srcset, common lazy-load attributes and even ' .
132
  'inline styles</p>' .
133
  '<p>Note that you will have to do something for the browsers that does not support webp. ' .
134
+ 'And that something is in most cases to enable the <i>Only do the replacements in webp enabled browsers</i> option, which ' .
135
  'will show up when you enable this option. ' .
136
+ 'Or you can experiment with javascript solutions. There is for example the <a href="https://webpjs.appspot.com/">webpjs</a> javascript library. ' .
137
+ 'But it does not support srcset, which is a showstopper. There are other libraries out there. ' .
138
  '<p>PS: This replace functionality is handled by ' .
139
  '<a target="_blank" href="https://github.com/rosell-dk/dom-util-for-webp">this external library</a>' .
140
+ ', created for the purpose.</p>'
 
141
  );
142
  ?>
143
+ </li>
144
+ <li><div id="alter_html_url_options_div" style="margin-left:18px; margin-bottom: 13px;">
145
  <?php
146
  webpexpress_checkbox(
147
  'alter-html-only-for-webp-enabled-browsers',
149
  'Only do the replacements in webp enabled browsers',
150
  'If you enable this option, the replacements will only be made, when the request is from ' .
151
  'a browser that supports webp. Note that this will not play well with plugins that caches ' .
152
+ 'the page. To overcome that, you can use the Cache Enabler plugin, '
 
153
  );
154
  ?>
155
+ </div></li>
156
+ </ul>
157
+
 
 
 
 
 
 
 
 
 
 
 
 
158
  </div>
159
+ <?php
160
+ if ($config['operation-mode'] != 'no-conversion') {
161
+ echo '<div><div style="margin-left: 11px">';
162
+ webpexpress_checkbox(
163
+ 'alter-html-for-webps-that-has-yet-to-exist',
164
+ (!$config['alter-html']['only-for-webps-that-exists']),
165
+ 'Reference webps that hasn\'t been converted yet',
166
+ 'If you enable this option, there will be references to webp files that doesnt exist yet. ' .
167
+ 'And that will be ok! - Just make sure to enable the option to convert missing webp files ' .
168
+ 'upon request'
169
+ );
170
+ echo '</div></div>';
171
+ }
172
+ ?>
173
+ <div style="margin-top: 20px">
174
  <label>Where to replace: <?php echo helpIcon(
175
  '<p></p>',
176
  'no-margin-left set-margin-right');
177
  ?></label>
 
178
  <?php
179
  webpexpress_radioButtons('alter-html-hooks', $config['alter-html']['hooks'], [
180
  'content-hooks' => 'Use content filtering hooks (the_content, the_excerpt, etc)',
187
 
188
  </div>
189
 
190
+ </th>
191
  </tr>
lib/options/options/alter-html/alter-html.inc CHANGED
@@ -1,6 +1,11 @@
1
- <?php if ($config['operation-mode'] == 'tweaked') : ?>
2
  <fieldset class="block">
3
  <h3>Alter HTML</h3>
 
 
 
 
 
 
4
  <table class="form-table">
5
  <tbody>
6
  <?php
@@ -9,11 +14,3 @@
9
  </tbody>
10
  </table>
11
  </fieldset>
12
- <?php
13
- else:
14
-
15
- if ($config['operation-mode'] != 'just-redirect') {
16
- include_once 'alter-html-options.inc';
17
- }
18
- endif;
19
- ?>
 
1
  <fieldset class="block">
2
  <h3>Alter HTML</h3>
3
+ <p>
4
+ Enabling this alters the HTML code such that webp images are served to browsers that supports webp.
5
+ It is <i>recommended to enable</i> this even when the redirection is also enabled, so the varied image responses are only used for
6
+ those images that cannot be replaced in HTML. The varied responses generally leads to poorer caching in proxies and CDN's. And if
7
+ users download those images, they will have jpg/png extension, even though they are webp.
8
+ </p>
9
  <table class="form-table">
10
  <tbody>
11
  <?php
14
  </tbody>
15
  </table>
16
  </fieldset>
 
 
 
 
 
 
 
 
lib/options/options/conversion-options/conversion-options.inc CHANGED
@@ -1,28 +1,13 @@
1
- <?php if ($config['operation-mode'] == 'tweaked') : ?>
2
  <fieldset class="block">
3
- <h3>Conversion options</h3>
4
- <p><i>The options here affects the conversion process</i></p>
5
  <table class="form-table">
6
  <tbody>
7
  <?php
8
  include_once 'quality.inc';
9
  include_once 'metadata.inc';
10
  include_once 'converters.inc';
11
- include_once 'destination-folder.inc';
12
- include_once 'destination-extension.inc';
13
  ?>
14
  </tbody>
15
  </table>
16
  </fieldset>
17
- <?php
18
- else:
19
- include_once 'quality.inc';
20
- include_once 'metadata.inc';
21
- include_once 'converters.inc';
22
-
23
- if (($config['operation-mode'] == 'varied-responses') || ($config['operation-mode'] == 'no-varied-responses')) {
24
- include_once 'destination-folder.inc';
25
- }
26
- include_once 'destination-extension.inc';
27
- endif;
28
- ?>
 
1
  <fieldset class="block">
2
+ <h3>Conversion</h3>
3
+ <!--<p><i>The options here affects the conversion process</i></p>-->
4
  <table class="form-table">
5
  <tbody>
6
  <?php
7
  include_once 'quality.inc';
8
  include_once 'metadata.inc';
9
  include_once 'converters.inc';
 
 
10
  ?>
11
  </tbody>
12
  </table>
13
  </fieldset>
 
 
 
 
 
 
 
 
 
 
 
 
lib/options/options/conversion-options/destination-extension.inc DELETED
@@ -1,24 +0,0 @@
1
- <tr id="destination_extension_row"><th scope="row">File extension<?php
2
- echo helpIcon(
3
- '<p>Controls the filename of the converted file.</p>' .
4
- '<p>The "Append" option result in file names such as "image.png.webp". ' .
5
- 'The "Set" option results in file names such as "image.webp". ' .
6
- 'Note that if you choose "Set", it will be a problem if you ie both have a logo.jpg and a logo.png in the same folder. ' .
7
- 'If you are using WebP Express together with <a target="blank" href="https://da.wordpress.org/plugins/cache-enabler/">Cache enabler</a> ' .
8
- 'or <a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a>, set this option to Set"</p>' .
9
- (($config['operation-mode'] == 'no-varied-responses') ? '<p>In this mode, the webp files will be stored in the same folder as the originals, except for images that are not inside the uploads folder (these are stored in wp-content/webp-express/webp-images/doc-root).</p>' : '') .
10
- '<p>Changing this option will cause existing webp images to be renamed (only those in the upload folder, and only those that has a ' .
11
- 'corresponding source image)</p>'
12
- );?>
13
- </th>
14
- <td>
15
- <select name="destination-extension">
16
- <?php
17
- webpexpress_selectBoxOptions($config['destination-extension'], [
18
- 'append' => 'Append ".webp"',
19
- 'set' => 'Set to ".webp"',
20
- ]);
21
- ?>
22
- </select>
23
- </td>
24
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/options/options/conversion-options/metadata.inc CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  // Metadata
3
  // --------------------
4
- //$maxQuality = get_option('webp_express_max_quality');
5
  $metadata = $config['metadata'];
6
 
7
  echo '<tr><th scope="row">Metadata';
1
  <?php
2
  // Metadata
3
  // --------------------
 
4
  $metadata = $config['metadata'];
5
 
6
  echo '<tr><th scope="row">Metadata';
lib/options/options/{serve-options → general}/cache-control.inc RENAMED
@@ -1,19 +1,22 @@
1
  <?php
2
 
3
- //$maxQuality = get_option('webp_express_max_quality');
4
  $cacheControl = $config['cache-control'];
5
  $cacheControlCustom = $config['cache-control-custom'];
6
  $cacheControlMaxAge = $config['cache-control-max-age'];
7
  $cacheControlPublic = $config['cache-control-public'];
8
  ?>
9
 
10
- <tr>
11
- <th scope="row">Cache-Control header <?php echo helpIcon(
12
- '<p>Controls the cache-control header on successful conversion and direct redirection to converted ' .
13
- 'image in .htaccess. In case of convert failure, headers will be sent to prevent caching.</p>' .
14
- '<p>PS: In order to set <i>stale-while-revalidate</i> and <i>stale-if-error directives<i>, you must ' .
15
- 'currently choose "Custom". <a target="_blank" href="https://www.fastly.com/blog/stale-while-revalidate-stale-if-error-available-today">It is a good idea to set these</a>.' .
16
- '</p>');
 
 
 
 
17
  ?>
18
  </th>
19
  <td>
@@ -21,19 +24,6 @@ $cacheControlPublic = $config['cache-control-public'];
21
  <option value="no-header" <?php if ($cacheControl == 'no-header') echo ' selected' ?>>Do not set</option>
22
  <option value="set" <?php if ($cacheControl == 'set') echo ' selected' ?>>Set</option>
23
  <option value="custom" <?php if ($cacheControl == 'custom') echo ' selected' ?>>Custom</option>
24
- <?php
25
- /*
26
- echo '<option value="no-header"' . ($cacheControl == 'no-header' ? ' selected' : '') . '>Do not set Cache-Control header</option>';
27
- echo '<option value="one-second"' . ($cacheControl == 'one-second' ? ' selected' : '') . '>One second</option>';
28
- echo '<option value="one-minute"' . ($cacheControl == 'one-minute' ? ' selected' : '') . '>One minute</option>';
29
- echo '<option value="one-hour"' . ($cacheControl == 'one-hour' ? ' selected' : '') . '>One hour</option>';
30
- echo '<option value="one-day"' . ($cacheControl == 'one-day' ? ' selected' : '') . '>One day</option>';
31
- echo '<option value="one-week"' . ($cacheControl == 'one-week' ? ' selected' : '') . '>One week</option>';
32
- echo '<option value="one-month"' . ($cacheControl == 'one-month' ? ' selected' : '') . '>One month</option>';
33
- echo '<option value="one-year"' . ($cacheControl == 'one-year' ? ' selected' : '') . '>One year</option>';
34
- echo '<option value="custom"' . ($cacheControl == 'custom' ? ' selected' : '') . '>Custom Cache-Control header</option>';
35
- */
36
- ?>
37
  </select>
38
  <div id="cache_control_custom_div" style="display:inline-block;">
39
  <input type="text" id="cache_control_custom" name="cache-control-custom" value="<?php echo $cacheControlCustom ?>">
1
  <?php
2
 
 
3
  $cacheControl = $config['cache-control'];
4
  $cacheControlCustom = $config['cache-control-custom'];
5
  $cacheControlMaxAge = $config['cache-control-max-age'];
6
  $cacheControlPublic = $config['cache-control-public'];
7
  ?>
8
 
9
+ <tr id="cache_control_div">
10
+ <th scope="row">Cache-Control header <?php
11
+ if ($config['operation-mode'] == 'no-conversion') {
12
+ echo helpIcon('<p>Optionally set cache-control header for the internally redirected images (recommended!)</p>');
13
+ } else {
14
+ echo helpIcon('<p>Controls the cache-control header on successful conversion and direct redirection to converted ' .
15
+ 'image in .htaccess. In case of convert failure, headers will be sent to prevent caching.</p>' .
16
+ '<p>PS: In order to set <i>stale-while-revalidate</i> and <i>stale-if-error directives<i>, you must ' .
17
+ 'currently choose "Custom". <a target="_blank" href="https://www.fastly.com/blog/stale-while-revalidate-stale-if-error-available-today">It is a good idea to set these</a>.' .
18
+ '</p>');
19
+ }
20
  ?>
21
  </th>
22
  <td>
24
  <option value="no-header" <?php if ($cacheControl == 'no-header') echo ' selected' ?>>Do not set</option>
25
  <option value="set" <?php if ($cacheControl == 'set') echo ' selected' ?>>Set</option>
26
  <option value="custom" <?php if ($cacheControl == 'custom') echo ' selected' ?>>Custom</option>
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  </select>
28
  <div id="cache_control_custom_div" style="display:inline-block;">
29
  <input type="text" id="cache_control_custom" name="cache-control-custom" value="<?php echo $cacheControlCustom ?>">
lib/options/options/general/destination-extension.inc ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <tr id="destination_extension_row"><?php
2
+
3
+ if ($config['operation-mode'] == 'no-conversion') {
4
+ echo '<th scope="row">Filename of the webp files';
5
+ echo helpIcon(
6
+ '<p>Select under which naming convention the webp files are stored. ' .
7
+ 'It is assumed that webp files are located in the same folder as the originals.</p>' .
8
+ '<style>' .
9
+ '#plugin-conventions th {font-style:italic;}' .
10
+ '#plugin-conventions td, #plugin-conventions th {padding:0;}' .
11
+ '#plugin-conventions td:last-child, #plugin-conventions th:last-child {padding-left:10px;}' .
12
+ '</style>' .
13
+ '<table id="plugin-conventions"><tbody>' .
14
+ '<tr><th>Plugin</td><th>Convention</th></tr>' .
15
+ //'<tr><td><a target="blank" href="https://wordpress.org/plugins/cache-enabler/">Cache enabler</a></td><td>Replaces extension</td></tr>' .
16
+ '<tr><td><a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a></td><td>Replaces extension</td></tr>' .
17
+ '<tr><td><a target="_blank" href="https://wordpress.org/plugins/ewww-image-optimizer/">Ewww</a></td><td>Appends extension</td></tr>' .
18
+ '<tr><td><a target="_blank" href="https://optimus.io/en/">Optimus HQ</a></td><td>Replaces extension</td></tr>' .
19
+ // todo:
20
+ '</tbody></table>'
21
+ );
22
+ } else {
23
+ echo '<th scope="row">File extension';
24
+ echo helpIcon(
25
+ '<p>Controls the filename of the converted file.</p>' .
26
+ '<p>The "Append" option result in file names such as "image.png.webp". ' .
27
+ 'The "Set" option results in file names such as "image.webp". ' .
28
+ 'Note that if you choose "Set", it will be a problem if you ie both have a logo.jpg and a logo.png in the same folder. ' .
29
+ 'If you are using WebP Express together with <a target="blank" href="https://wordpress.org/plugins/cache-enabler/">Cache enabler</a> ' .
30
+ 'or <a target="_blank" href="https://wordpress.org/plugins/shortpixel-image-optimiser/">Shortpixel</a>, set this option to Set"</p>' .
31
+ (($config['operation-mode'] == 'cdn-friendly') ? '<p>In this mode, the webp files will be stored in the same folder as the originals, except for images that are not inside the uploads folder (these are stored in wp-content/webp-express/webp-images/doc-root).</p>' : '') .
32
+ '<p>Changing this option will cause existing webp images to be renamed (only those in the upload folder, and only those that has a ' .
33
+ 'corresponding source image)</p>'
34
+ );
35
+ }
36
+ ?>
37
+ </th>
38
+ <td>
39
+ <?php
40
+ if ($config['operation-mode'] == 'no-conversion') {
41
+ webpexpress_radioButtons('destination-extension', $config['destination-extension'], [
42
+ 'append' => 'Original extension is kept (ie "image.jpg.webp")',
43
+ 'set' => 'Original extension is replaced (ie "image.webp")',
44
+ ], [
45
+ 'append' => 'Original extension is kept and ".webp" is appended. ',
46
+ 'set' => 'Original extension is replaced with ".webp".'
47
+ ], 'margin-left: 0px; margin-top: 5px');
48
+
49
+ } else {
50
+ echo '<select name="destination-extension" id="destination_extension">';
51
+ webpexpress_selectBoxOptions($config['destination-extension'], [
52
+ 'append' => 'Append ".webp"',
53
+ 'set' => 'Set to ".webp"',
54
+ ]);
55
+ echo '</select>';
56
+ }
57
+ ?>
58
+
59
+ </td>
60
+ </tr>
lib/options/options/{conversion-options → general}/destination-folder.inc RENAMED
File without changes
lib/options/options/general/general.inc ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <fieldset class="block">
2
+ <h3>General</h3>
3
+ <!--<div><i>The options here affects the rules created in the .htaccess. <?php echo helpIcon('And so does some other options. If "Redirect directly to converted image" is set, the "Destination folder" and "File Extension" and "Caching" options will be used'); ?></i></div>-->
4
+ <table class="form-table">
5
+ <tbody>
6
+ <?php
7
+ include_once 'image-types.inc';
8
+
9
+ if (($config['operation-mode'] != 'no-conversion')) {
10
+ include_once 'destination-folder.inc';
11
+ }
12
+ include_once 'destination-extension.inc';
13
+
14
+ if (($config['operation-mode'] == 'tweaked') || ($config['operation-mode'] == 'varied-image-responses')) {
15
+ include_once 'cache-control.inc';
16
+ }
17
+
18
+ ?>
19
+ </tbody>
20
+ </table>
21
+ </fieldset>
lib/options/options/{redirection-rules → general}/image-types.inc RENAMED
@@ -3,20 +3,26 @@
3
  // ------------
4
  echo '<tr><th scope="row">';
5
  switch ($config['operation-mode']) {
6
- case 'varied-responses':
7
  echo 'Image types to work on';
8
  break;
9
- case 'no-varied-responses':
10
  echo 'Image types to convert';
11
  break;
12
- case 'just-redirect':
13
- echo 'Image types to redirect';
14
  break;
15
  case 'tweaked':
16
  echo 'Image types to send to the converter';
17
  break;
18
  }
19
- echo helpIcon('<p>Beware that the Gd conversion method cannot handle transparency for PNGs. PNG conversions havent been tested much yet. Please report any problems with PNG images <a target="_blank" href="https://github.com/rosell-dk/webp-convert/issues/42">here</a></p><p>The term "send" means an internal redirect on the server (not to be confused with an external redirect, such as a 301 or 302 response)</p>');
 
 
 
 
 
 
20
  echo '</th><td>';
21
 
22
  // bitmask
@@ -24,7 +30,6 @@ echo '</th><td>';
24
  // 2: PNG's
25
  // Converting only jpegs is thus "1"
26
  // Converting both jpegs and pngs is (1+2) = 3
27
- //$imageTypes = get_option('webp_express_image_types_to_convert');
28
  $imageTypes = $config['image-types'];
29
 
30
  echo '<select name="image-types">';
3
  // ------------
4
  echo '<tr><th scope="row">';
5
  switch ($config['operation-mode']) {
6
+ case 'varied-image-responses':
7
  echo 'Image types to work on';
8
  break;
9
+ case 'cdn-friendly':
10
  echo 'Image types to convert';
11
  break;
12
+ case 'no-conversion':
13
+ echo 'Image types to work on';
14
  break;
15
  case 'tweaked':
16
  echo 'Image types to send to the converter';
17
  break;
18
  }
19
+ if ($config['operation-mode'] == 'no-conversion') {
20
+ echo helpIcon('<p>Select which types of images you would like to redirect and/or have altered in the HTML</p>');
21
+
22
+ } else {
23
+ echo helpIcon('<p>Beware that the Gd conversion method cannot handle transparency for PNGs. PNG conversions havent been tested much yet. Please report any problems with PNG images <a target="_blank" href="https://github.com/rosell-dk/webp-convert/issues/42">here</a></p><p>The term "send" means an internal redirect on the server (not to be confused with an external redirect, such as a 301 or 302 response)</p>');
24
+
25
+ }
26
  echo '</th><td>';
27
 
28
  // bitmask
30
  // 2: PNG's
31
  // Converting only jpegs is thus "1"
32
  // Converting both jpegs and pngs is (1+2) = 3
 
33
  $imageTypes = $config['image-types'];
34
 
35
  echo '<select name="image-types">';
lib/options/options/operation-mode.inc CHANGED
@@ -12,14 +12,14 @@ $operationMode = $config['operation-mode'];
12
  ?>
13
  <input type="hidden" name="operation-mode" id="operation_mode" value="<?php echo $operationMode ?>">
14
  <select name="change-operation-mode" id="change_operation_mode">
15
- <option value="varied-responses"<?php if ($operationMode == 'varied-responses') echo ' selected'?>>Varied image responses</option>
16
- <option value="no-varied-responses"<?php if ($operationMode == 'no-varied-responses') echo ' selected'?>>CDN friendly</option>
17
- <option value="just-redirect"<?php if ($operationMode == 'just-redirect') echo ' selected'?>>Just redirect</option>
18
  <option value="tweaked"<?php if ($operationMode == 'tweaked') echo ' selected'?>>Tweaked</option>
19
  </select></h3>
20
 
21
- <?php if ($config['operation-mode'] == 'varied-responses') : ?>
22
- <p><div>
23
  <i>In the "Varied image responses" mode, WebP Express creates redirection rules for images, such that a request for a jpeg will
24
  result in a webp &ndash; but only if the request comes from a webp-enabled browser.
25
  If a webp already exists, it is served immediately. Otherwise it is converted and then served.
@@ -27,8 +27,8 @@ $operationMode = $config['operation-mode'];
27
  </i>
28
  </div></p>
29
  <?php endif; ?>
30
- <?php if ($config['operation-mode'] == 'no-varied-responses') : ?>
31
- <p><div>
32
  <i>In "CDN friendly" mode, a jpeg is always served as a jpeg.
33
  Instead of varying the image response, WebP Express alters the HTML for webp usage.</i>
34
  <div class="help">?<div class="popup">
@@ -50,11 +50,12 @@ $operationMode = $config['operation-mode'];
50
  <i>A couple of options are available for automatically triggering webp conversion.</i>
51
  </div></p>
52
  <?php endif; ?>
53
- <?php if ($config['operation-mode'] == 'just-redirect') : ?>
54
  <p>
55
- <div>
56
- <i>In "just redirect" mode, WebP Express is used just for redirecting jpeg and pngs to existing webp images in the same folder.<br>
57
- This mode can for example be used in combination with Optimus HQ.</i>
 
58
  </div>
59
  </p>
60
  <?php endif; ?>
12
  ?>
13
  <input type="hidden" name="operation-mode" id="operation_mode" value="<?php echo $operationMode ?>">
14
  <select name="change-operation-mode" id="change_operation_mode">
15
+ <option value="varied-image-responses"<?php if ($operationMode == 'varied-image-responses') echo ' selected'?>>Varied image responses</option>
16
+ <option value="cdn-friendly"<?php if ($operationMode == 'cdn-friendly') echo ' selected'?>>CDN friendly</option>
17
+ <option value="no-conversion"<?php if ($operationMode == 'no-conversion') echo ' selected'?>>No conversion</option>
18
  <option value="tweaked"<?php if ($operationMode == 'tweaked') echo ' selected'?>>Tweaked</option>
19
  </select></h3>
20
 
21
+ <?php if ($config['operation-mode'] == 'varied-image-responses') : ?>
22
+ <p><div class="p">
23
  <i>In the "Varied image responses" mode, WebP Express creates redirection rules for images, such that a request for a jpeg will
24
  result in a webp &ndash; but only if the request comes from a webp-enabled browser.
25
  If a webp already exists, it is served immediately. Otherwise it is converted and then served.
27
  </i>
28
  </div></p>
29
  <?php endif; ?>
30
+ <?php if ($config['operation-mode'] == 'cdn-friendly') : ?>
31
+ <p><div class="p">
32
  <i>In "CDN friendly" mode, a jpeg is always served as a jpeg.
33
  Instead of varying the image response, WebP Express alters the HTML for webp usage.</i>
34
  <div class="help">?<div class="popup">
50
  <i>A couple of options are available for automatically triggering webp conversion.</i>
51
  </div></p>
52
  <?php endif; ?>
53
+ <?php if ($config['operation-mode'] == 'no-conversion') : ?>
54
  <p>
55
+ <div class="p">
56
+ <i>The "No conversion" mode is for scenarios where you are using another plugin for converting images.
57
+ Perhaps the other plugin doesn't have the redirection or alter HTML feature, or perhaps it doesn't do it as well
58
+ as WebP Express does. PS: The two methods below works great in tandem.</i>
59
  </div>
60
  </p>
61
  <?php endif; ?>
lib/options/options/redirection-rules/enable-redirection-to-converter.inc CHANGED
@@ -1,9 +1,9 @@
1
  <tr>
2
  <th scope="row">
3
- <?php if ($config['operation-mode'] == 'no-varied-responses'): ?>
4
- Convert non-existing webp-files upon request to original image <span style="color:darkorange">(almost obsolete)<?php
5
  echo helpIcon(
6
- //'<p><em>The auto-convertion works this way: When an image is requested, a rule in the .htaccess detects if that image has been converted. If not, the request is redirected to the converter, which creates the webp and returns <em>the original</em> image</em></p>
7
  '<p>This works the following way:' .
8
  '<ol>' .
9
  '<li>WebP adds rules in the <i>.htaccess</i> that redirects requests for jpg/png images to the converter, <i>when no corresponding webp image is found</i></li>' .
@@ -14,7 +14,7 @@
14
  'the rule will not trigger because it now detects a corresponding webp</p>' .
15
  '<p>Note: After the introduction of the <i>Convert non-existing webp-files upon request?</i> option, ' .
16
  'you probably will not need this option. There are however rare cases, where it could be useful. ' .
17
- '<b>From the next release on on, this option will only be available in the <i>Tweaked</i> operation mode</b></p>'
18
  ); ?>
19
  <?php else: ?>
20
  Enable redirection to converter?<?php echo helpIcon('This will add rules in the .htaccess that redirects images (jpg/png) to the script'); ?>
1
  <tr>
2
  <th scope="row">
3
+ <?php if ($config['operation-mode'] == 'cdn-friendly'): ?>
4
+ Redirect requests for jpg/png to converter, but only when there is no webp, and serve the original<?php
5
  echo helpIcon(
6
+ //'<p><em>The auto-conversion works this way: When an image is requested, a rule in the .htaccess detects if that image has been converted. If not, the request is redirected to the converter, which creates the webp and returns <em>the original</em> image</em></p>
7
  '<p>This works the following way:' .
8
  '<ol>' .
9
  '<li>WebP adds rules in the <i>.htaccess</i> that redirects requests for jpg/png images to the converter, <i>when no corresponding webp image is found</i></li>' .
14
  'the rule will not trigger because it now detects a corresponding webp</p>' .
15
  '<p>Note: After the introduction of the <i>Convert non-existing webp-files upon request?</i> option, ' .
16
  'you probably will not need this option. There are however rare cases, where it could be useful. ' .
17
+ '</p>'
18
  ); ?>
19
  <?php else: ?>
20
  Enable redirection to converter?<?php echo helpIcon('This will add rules in the .htaccess that redirects images (jpg/png) to the script'); ?>
lib/options/options/redirection-rules/enable-redirection-to-webp-realizer.inc CHANGED
@@ -1,9 +1,10 @@
1
  <tr>
2
  <th scope="row">
3
- Convert non-existing webp-files upon request <span style="color:darkorange">(beta)</span>
4
  <?php echo helpIcon(
5
- '<p>Have ie. "image.jpg.webp" automatically generated from "image.jpg" the first time the webp is requested.</p>' .
6
- '<p>This works the following way:' .
 
7
  '<ol>' .
8
  '<li>WebP adds rules in the <i>.htaccess</i> that redirects requests for non-existing webp files to <i>webp-realizer.php</i></li>' .
9
  '<li><i>webp-realizer.php</i> looks for a corresponding jpg/png. If found, it is converted and saved, so the webp will be directly available the next time it is requested &ndash; and it tells the browser to fetch the same URL again (302 redirect to same location). In case no corresponding jpg/png is found, a 404 is returned</li>' .
1
  <tr>
2
  <th scope="row">
3
+ Redirect requests for non-existing webp-files to converter</span>
4
  <?php echo helpIcon(
5
+ '<p>Have ie. "image.jpg.webp" automatically generated from "image.jpg" the first time the webp is requested. ' .
6
+ 'This way you can reference webps before they actually exists.</p>' .
7
+ '<p>The feature works the following way:' .
8
  '<ol>' .
9
  '<li>WebP adds rules in the <i>.htaccess</i> that redirects requests for non-existing webp files to <i>webp-realizer.php</i></li>' .
10
  '<li><i>webp-realizer.php</i> looks for a corresponding jpg/png. If found, it is converted and saved, so the webp will be directly available the next time it is requested &ndash; and it tells the browser to fetch the same URL again (302 redirect to same location). In case no corresponding jpg/png is found, a 404 is returned</li>' .
lib/options/options/redirection-rules/only-redirect-to-converter-for-webp-enabled-browsers.inc CHANGED
@@ -1,10 +1,11 @@
1
- <tr>
2
  <th scope="row">
3
- Only redirect to converter for webp-enabled browsers?<?php echo helpIcon('If checked, a condition is added to the .htaccess, that the <i>Accept</i> header contains "image/webp"'); ?>
4
  </th>
5
  <td>
 
6
  <input
7
  name="only-redirect-to-converter-for-webp-enabled-browsers"
 
8
  <?php echo ($config['only-redirect-to-converter-for-webp-enabled-browsers'] ? 'checked="checked"' : '') ?>
9
  value="true"
10
  type="checkbox"
1
+ <tr id="only_redirect_to_converter_for_webp_enabled_browsers_row">
2
  <th scope="row">
 
3
  </th>
4
  <td>
5
+ Only redirect to converter for webp-enabled browsers?<?php echo helpIcon('If checked, a condition is added to the .htaccess, that the <i>Accept</i> header contains "image/webp"'); ?>
6
  <input
7
  name="only-redirect-to-converter-for-webp-enabled-browsers"
8
+ id="only_redirect_to_converter_for_webp_enabled_browsers"
9
  <?php echo ($config['only-redirect-to-converter-for-webp-enabled-browsers'] ? 'checked="checked"' : '') ?>
10
  value="true"
11
  type="checkbox"
lib/options/options/redirection-rules/only-redirect-to-converter-on-cache-miss.inc CHANGED
@@ -1,16 +1,16 @@
1
- <tr>
2
  <th scope="row">
 
 
3
  Only redirect to converter if no webp exists <?php
4
  echo helpIcon(
5
  '<p>This extra condition is not needed if you enabled the ' .
6
  '<i>Redirect directly to converted image when available</i> option.</p>' .
7
  '<p>The option was created in order to make it possible to achieve the functionality behind the ' .
8
- '<i>Convert non-existing webp-files upon request to original image?</i> option found in the ' .
9
  '"CDN friendly" operation mode.</p>'
10
  );
11
  ?>
12
- </th>
13
- <td>
14
  <input type="checkbox" name="only-redirect-to-converter-on-cache-miss" value="true" <?php echo ($config['only-redirect-to-converter-on-cache-miss'] ? 'checked="checked"' : '') ?> >
15
  </td>
16
  </tr>
1
+ <tr id="only_redirect_to_converter_on_cache_miss_row">
2
  <th scope="row">
3
+ </th>
4
+ <td>
5
  Only redirect to converter if no webp exists <?php
6
  echo helpIcon(
7
  '<p>This extra condition is not needed if you enabled the ' .
8
  '<i>Redirect directly to converted image when available</i> option.</p>' .
9
  '<p>The option was created in order to make it possible to achieve the functionality behind the ' .
10
+ '<i>Redirect requests for non-existing webp-files to converter</i> option found in the ' .
11
  '"CDN friendly" operation mode.</p>'
12
  );
13
  ?>
 
 
14
  <input type="checkbox" name="only-redirect-to-converter-on-cache-miss" value="true" <?php echo ($config['only-redirect-to-converter-on-cache-miss'] ? 'checked="checked"' : '') ?> >
15
  </td>
16
  </tr>
lib/options/options/redirection-rules/redirect-to-existing.inc CHANGED
@@ -1,11 +1,28 @@
1
  <tr>
2
  <th scope="row">
3
- Redirect directly to converted image when available<?php
4
- echo helpIcon('This will add rules in the .htaccess that redirects directly to existing converted files. ' .
5
- 'If you do not activate this setting, it will be the PHP script that handles the redirection to existing ' .
6
- 'webp files. Best performance is achieved by redirecting in .htaccess'); ?>
 
 
 
 
 
 
 
 
7
  </th>
8
  <td>
9
  <input type="checkbox" id="redirect_to_existing_in_htaccess" name="redirect-to-existing-in-htaccess" value="true" <?php echo ($config['redirect-to-existing-in-htaccess'] ? 'checked="checked"' : '') ?> >
 
 
 
 
 
 
 
 
 
10
  </td>
11
  </tr>
1
  <tr>
2
  <th scope="row">
3
+ <?php
4
+
5
+ if ($config['operation-mode'] == 'no-conversion') {
6
+ echo 'Activate redirection';
7
+ echo helpIcon('This will add rules in the .htaccess that redirects directly to existing converted files (note that it is an internal redirect, which is much faster than a 301 or 302 redirect).');
8
+ } else {
9
+ echo 'Redirect directly to existing converted images';
10
+ echo helpIcon('This will add rules in the .htaccess that redirects directly to existing converted files. ' .
11
+ 'If you do not activate this setting, it will be the PHP script that handles the redirection to existing ' .
12
+ 'webp files. Best performance is achieved by redirecting in .htaccess');
13
+ }
14
+ ?>
15
  </th>
16
  <td>
17
  <input type="checkbox" id="redirect_to_existing_in_htaccess" name="redirect-to-existing-in-htaccess" value="true" <?php echo ($config['redirect-to-existing-in-htaccess'] ? 'checked="checked"' : '') ?> >
18
+
19
+ <?php
20
+ /*if ($config['operation-mode'] == 'no-conversion') {
21
+ // Cache control header
22
+ echo '<div id="cache_control_div"><table style="margin-top: 10px">';
23
+ include_once __DIR__ . '/../serve-options/cache-control.inc';
24
+ echo '</table></div>';
25
+ }*/
26
+ ?>
27
  </td>
28
  </tr>
lib/options/options/redirection-rules/redirection-rules.inc CHANGED
@@ -1,35 +1,59 @@
1
- <?php if ($config['operation-mode'] == 'tweaked') : ?>
2
  <fieldset class="block">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <h3>Redirection rules</h3>
4
- <div><i>The options here affects the rules created in the .htaccess. <?php echo helpIcon('And so does some other options. If "Redirect directly to converted image" is set, the "Destination folder" and "File Extension" and "Caching" options will be used'); ?></i></div>
 
 
 
 
 
 
 
 
5
  <table class="form-table">
6
  <tbody>
7
  <?php
8
- include_once 'enable-redirection-to-converter.inc';
9
- include_once 'only-redirect-to-converter-for-webp-enabled-browsers.inc';
10
- include_once 'image-types.inc';
11
- include_once 'do-not-pass-source-path-in-query-string.inc';
12
- include_once 'only-redirect-to-converter-on-cache-miss.inc';
13
- include_once 'redirect-to-existing.inc';
14
- include_once 'enable-redirection-to-webp-realizer.inc';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  ?>
16
  </tbody>
17
  </table>
18
  </fieldset>
19
- <?php
20
- else:
21
- if ($config['operation-mode'] == 'no-varied-responses') {
22
- // ps: we call it "auto convert", when in this mode
23
- // PPS: we include it directly in page.php now.
24
- //include_once 'enable-redirection-to-converter.inc';
25
-
26
- //include_once 'only-redirect-to-converter-on-cache-miss.inc';
27
-
28
- }
29
- if ($config['operation-mode'] == 'varied-responses') {
30
- include_once 'redirect-to-existing.inc';
31
- //include_once 'enable-redirection-to-webp-realizer.inc';
32
- }
33
- include_once 'image-types.inc';
34
- endif;
35
- ?>
 
1
  <fieldset class="block">
2
+ <?php if ($config['operation-mode'] == 'no-conversion') : ?>
3
+ <h2>Redirecting jpeg/png to existing webp (varied image response)</h2>
4
+ <p>
5
+ Enabling this adds rules to the <i>.htaccess</i> which internally redirects jpg/pngs to webp
6
+ and sets the <i>Vary:Accept</i> response header.
7
+ <i>Beware that special attention is needed if you are using a CDN (see FAQ).</i>
8
+ </p>
9
+ <?php elseif ($config['operation-mode'] == 'cdn-friendly') : ?>
10
+ <h2><i>.htaccess</i> rules for webp generation</h2>
11
+ <p>
12
+ The following redirect rules will not produce varied image responses.
13
+ Their job is simply to trigger webp conversion. Note that this is achieved <i>without</i> producing varied responses.
14
+ On most systems you need only to activate the first option. The second option can be used if the first one fails on your system.
15
+ </p>
16
+ <?php elseif ($config['operation-mode'] == 'varied-image-responses') : ?>
17
  <h3>Redirection rules</h3>
18
+ <div><i>The options here affects the rules created in the .htaccess.<br>
19
+ Note: The option for enabling/disabling redirects to the converter is not available in this operation mode, as
20
+ that redirection is part of what defines this mode.
21
+ <?php echo helpIcon('Note: The general options also affects the rules.'); ?></i></div>
22
+ <?php else : ?>
23
+ <h3>Redirection rules</h3>
24
+ <div><i>The options here affects the rules created in the .htaccess. <?php echo helpIcon('Note: The general options also affects the rules.'); ?></i></div>
25
+ <?php endif; ?>
26
+
27
  <table class="form-table">
28
  <tbody>
29
  <?php
30
+ switch ($config['operation-mode']) {
31
+ case 'tweaked':
32
+ include_once 'enable-redirection-to-converter.inc';
33
+ include_once 'only-redirect-to-converter-for-webp-enabled-browsers.inc';
34
+ include_once 'only-redirect-to-converter-on-cache-miss.inc';
35
+ include_once 'do-not-pass-source-path-in-query-string.inc';
36
+ include_once 'redirect-to-existing.inc';
37
+ include_once 'enable-redirection-to-webp-realizer.inc';
38
+ break;
39
+ case 'no-conversion':
40
+ include_once 'redirect-to-existing.inc';
41
+ include_once __DIR__. '/../general/cache-control.inc';
42
+
43
+ break;
44
+ case 'cdn-friendly':
45
+ //include_once 'redirect-to-existing.inc';
46
+ include_once 'enable-redirection-to-webp-realizer.inc';
47
+
48
+ // ps: we call it "auto convert", when in this mode
49
+ include_once 'enable-redirection-to-converter.inc';
50
+ break;
51
+ case 'varied-image-responses':
52
+ include_once 'redirect-to-existing.inc';
53
+ include_once 'enable-redirection-to-webp-realizer.inc';
54
+ break;
55
+ }
56
  ?>
57
  </tbody>
58
  </table>
59
  </fieldset>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/options/options/serve-options/response-on-failure.inc CHANGED
@@ -5,7 +5,6 @@ echo '<tr><th scope="row">Response on failure';
5
  echo helpIcon('Determines what to serve in case the image conversion should fail.');
6
  echo '</th><td>';
7
 
8
- //$fail = get_option('webp_express_failure_response');
9
  $fail = $config['fail'];
10
  echo '<select name="fail">';
11
  echo '<option value="original"' . ($fail == 'original' ? ' selected' : '') . '>Original image</option>';
5
  echo helpIcon('Determines what to serve in case the image conversion should fail.');
6
  echo '</th><td>';
7
 
 
8
  $fail = $config['fail'];
9
  echo '<select name="fail">';
10
  echo '<option value="original"' . ($fail == 'original' ? ' selected' : '') . '>Original image</option>';
lib/options/options/serve-options/response-on-success.inc CHANGED
@@ -3,7 +3,6 @@ echo '<tr><th scope="row">Response on success';
3
  echo helpIcon('<p>Determines what to serve when conversion is a success. If you are using the Cache Enabler plugin, set to "Original image", otherwise you would normally set it to "Converted image".</p><p>If set to "Converted image", a Vary:Accept header will be sent to indicate that the response depends on the Accept header (which indicates if a browser supports webp images or not)</p><p>If set to "Original image", make sure to disable the "Redirect directly to converted image when available" option in the Redirect rules</p>');
4
  echo '</th><td>';
5
 
6
- //$successResponse = get_option('webp_express_failure_response');
7
  $successResponse = $config['success-response'];
8
  echo '<select name="success-response">';
9
  echo '<option value="original"' . ($successResponse == 'original' ? ' selected' : '') . '>Original image</option>';
3
  echo helpIcon('<p>Determines what to serve when conversion is a success. If you are using the Cache Enabler plugin, set to "Original image", otherwise you would normally set it to "Converted image".</p><p>If set to "Converted image", a Vary:Accept header will be sent to indicate that the response depends on the Accept header (which indicates if a browser supports webp images or not)</p><p>If set to "Original image", make sure to disable the "Redirect directly to converted image when available" option in the Redirect rules</p>');
4
  echo '</th><td>';
5
 
 
6
  $successResponse = $config['success-response'];
7
  echo '<select name="success-response">';
8
  echo '<option value="original"' . ($successResponse == 'original' ? ' selected' : '') . '>Original image</option>';
lib/options/options/serve-options/serve-options.inc CHANGED
@@ -5,7 +5,6 @@
5
  <table class="form-table">
6
  <tbody>
7
  <?php
8
- include_once 'cache-control.inc';
9
  include_once 'response-on-failure.inc';
10
  include_once 'response-on-success.inc';
11
  ?>
@@ -13,9 +12,5 @@
13
  </table>
14
  </fieldset>
15
  <?php
16
- else:
17
- if ($config['operation-mode'] != 'no-varied-responses') {
18
- include_once 'cache-control.inc';
19
- }
20
  endif;
21
  ?>
5
  <table class="form-table">
6
  <tbody>
7
  <?php
 
8
  include_once 'response-on-failure.inc';
9
  include_once 'response-on-success.inc';
10
  ?>
12
  </table>
13
  </fieldset>
14
  <?php
 
 
 
 
15
  endif;
16
  ?>
lib/options/options/web-service-options/web-service-options.inc CHANGED
@@ -1,5 +1,4 @@
1
- <?php if ($config['operation-mode'] == 'tweaked') : ?>
2
- <fieldset class="block">
3
  <h3>Web service</h3>
4
  <table class="form-table">
5
  <tbody>
@@ -9,8 +8,3 @@
9
  </tbody>
10
  </table>
11
  </fieldset>
12
- <?php
13
- else:
14
- include_once 'web-service.inc';
15
- endif;
16
- ?>
1
+ <fieldset class="block">
 
2
  <h3>Web service</h3>
3
  <table class="form-table">
4
  <tbody>
8
  </tbody>
9
  </table>
10
  </fieldset>
 
 
 
 
 
lib/options/page-messages.php CHANGED
@@ -7,7 +7,7 @@ use \WebPExpress\State;
7
  use \WebPExpress\Messenger;
8
  use \WebPExpress\PlatformInfo;
9
  use \WebPExpress\FileHelper;
10
-
11
  //include __DIR__ . "/page-welcome.php";
12
 
13
  //echo 'display errors:' . ini_get('display_errors');
@@ -16,12 +16,102 @@ if ((!State::getState('configured', false))) {
16
  include __DIR__ . "/page-welcome.php";
17
  }
18
 
19
- if (PlatformInfo::definitelyNotGotModRewrite()) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  Messenger::printMessage(
21
- 'error',
22
- "Rewriting isn't enabled on your server. WebP Express cannot work without it. Tell your host or system administrator to enable the 'mod_rewrite' module. If you are on a shared host, chances are that mod_rewrite can be turned on in your control panel."
23
  );
24
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  /*
26
  if (Config::isConfigFileThereAndOk() ) { // && PlatformInfo::definitelyGotModEnv()
27
  if (!isset($_SERVER['HTACCESS'])) {
@@ -81,6 +171,8 @@ $haveRulesInIndexDir = HTAccess::haveWeRulesInThisHTAccessBestGuess(Paths::getIn
81
  $haveRulesInContentDir = HTAccess::haveWeRulesInThisHTAccessBestGuess(Paths::getContentDirAbs() . '/.htaccess');
82
 
83
  if ($haveRulesInIndexDir && $haveRulesInContentDir) {
 
 
84
  if (!HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', '# WebP Express has placed its rules in your wp-content dir. Go there.', false)) {
85
  Messenger::printMessage(
86
  'warning',
@@ -104,7 +196,7 @@ if ($ht !== false) {
104
  'In order for the "Convert non-existing webp-files upon request" functionality to work, you need to either:<br>' .
105
  '- Move the WebP Express rules above the Wordpress rules in the .htaccess file located in your root dir<br>' .
106
  '- Grant the webserver permission to your wp-content dir, so it can create its rules there instead.'
107
- );
108
  }
109
  }
110
  }
7
  use \WebPExpress\Messenger;
8
  use \WebPExpress\PlatformInfo;
9
  use \WebPExpress\FileHelper;
10
+ use \WebPExpress\CapabilityTest;
11
  //include __DIR__ . "/page-welcome.php";
12
 
13
  //echo 'display errors:' . ini_get('display_errors');
16
  include __DIR__ . "/page-welcome.php";
17
  }
18
 
19
+
20
+ /*
21
+ if (CapabilityTest::modRewriteWorking()) {
22
+ echo 'mod rewrite works. that is nice';
23
+ }*/
24
+
25
+ /*if (CapabilityTest::modHeaderWorking() === true) {
26
+ //echo 'nice!';
27
+ }*/
28
+ /*
29
+ if (CapabilityTest::copyCapabilityTestsToWpContent()) {
30
+ echo 'copy ok!';
31
+ } else {
32
+ echo 'copy failed!';
33
+ }*/
34
+
35
+
36
+
37
+ $anyRedirectionToConverterEnabled = (($config['enable-redirection-to-converter']) || ($config['enable-redirection-to-webp-realizer']));
38
+ $anyRedirectionEnabled = ($anyRedirectionToConverterEnabled || $config['redirect-to-existing-in-htaccess']);
39
+
40
+ if ($anyRedirectionEnabled) {
41
+ if (PlatformInfo::definitelyNotGotModRewrite()) {
42
+ Messenger::printMessage(
43
+ 'error',
44
+ "Rewriting isn't enabled on your server. ' .
45
+ 'Currently, the only way to make WebP Express generate webp files is with rewriting. '
46
+ 'If you got the webp files through other means, you can use CDN friendly mode and disable the rewrites. ' .
47
+ 'Or perhaps you want to enable rewriting? Tell your host or system administrator to enable the 'mod_rewrite' module. ' .
48
+ 'If you are on a shared host, chances are that mod_rewrite can be turned on in your control panel."
49
+ );
50
+ }
51
+ }
52
+
53
+ $cacheEnablerActivated = in_array('cache-enabler/cache-enabler.php', get_option('active_plugins', []));
54
+ if ($cacheEnablerActivated) {
55
+ $cacheEnablerSettings = get_option('cache-enabler', []);
56
+ $webpEnabled = (isset($cacheEnablerSettings['webp']) && $cacheEnablerSettings['webp']);
57
+ }
58
+
59
+ if ($cacheEnablerActivated && !$webpEnabled) {
60
  Messenger::printMessage(
61
+ 'warning',
62
+ 'You are using Cache Enabler, but have not enabled the webp option, so Cache Enabler is not operating with a separate cache for webp-enabled browsers.'
63
  );
64
  }
65
+
66
+ if (($config['operation-mode'] == 'cdn-friendly') && !$config['alter-html']['enabled']) {
67
+ //echo print_r(get_option('cache-enabler'), true);
68
+
69
+
70
+ if ($cacheEnablerActivated) {
71
+ if ($webpEnabled) {
72
+ Messenger::printMessage(
73
+ 'info',
74
+ 'You should consider enabling Alter HTML. This is not neccessary, as you have <i>Cache Enabler</i> enabled, which alters HTML. ' .
75
+ 'However, it is a good idea because currently <i>Cache Enabler</i> does not replace as many URLs as WebP Express (ie background images in inline styles)'
76
+ );
77
+ }
78
+
79
+ } else {
80
+ Messenger::printMessage(
81
+ 'warning',
82
+ 'You are in CDN friendly mode but have not enabled Alter HTML (and you are not using Cache Enabler either). ' .
83
+ 'This is usually a misconfiguration because in this mode, the only way to get webp files is by referencing them in the HTML.'
84
+ );
85
+
86
+ }
87
+ }
88
+
89
+ if (!$anyRedirectionToConverterEnabled && ($config['operation-mode'] == 'cdn-friendly')) {
90
+ // this can not happen in varied image responses. it is ok in no-conversion, and also tweaked, because one could wish to tweak the no-conversion mode
91
+ Messenger::printMessage(
92
+ 'warning',
93
+ 'You have not enabled any of the redirects to the converter. ' .
94
+ 'At least one of the redirects is required for triggering WebP generation.'
95
+ );
96
+ }
97
+
98
+ if ($config['alter-html']['enabled'] && !$config['alter-html']['only-for-webps-that-exists'] && !$config['enable-redirection-to-webp-realizer']) {
99
+ Messenger::printMessage(
100
+ 'warning',
101
+ 'You have configured Alter HTML to make references to WebP files that are yet to exist, ' .
102
+ '<i>but you have not enabled the option that makes these files come true when requested</i>. Do that!'
103
+ );
104
+ }
105
+
106
+ if ($config['enable-redirection-to-webp-realizer'] && $config['alter-html']['enabled'] && $config['alter-html']['only-for-webps-that-exists']) {
107
+ Messenger::printMessage(
108
+ 'warning',
109
+ 'You have enabled the option that redirects requests for non-existing webp files to the converter, ' .
110
+ '<i>but you have not enabled the option to point to these in Alter HTML</i>. Please do that!'
111
+ );
112
+ }
113
+
114
+
115
  /*
116
  if (Config::isConfigFileThereAndOk() ) { // && PlatformInfo::definitelyGotModEnv()
117
  if (!isset($_SERVER['HTACCESS'])) {
171
  $haveRulesInContentDir = HTAccess::haveWeRulesInThisHTAccessBestGuess(Paths::getContentDirAbs() . '/.htaccess');
172
 
173
  if ($haveRulesInIndexDir && $haveRulesInContentDir) {
174
+ // TODO: Use new method for determining if htaccess contains rules.
175
+ // (either haveWeRulesInThisHTAccessBestGuess($filename) or haveWeRulesInThisHTAccess($filename))
176
  if (!HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', '# WebP Express has placed its rules in your wp-content dir. Go there.', false)) {
177
  Messenger::printMessage(
178
  'warning',
196
  'In order for the "Convert non-existing webp-files upon request" functionality to work, you need to either:<br>' .
197
  '- Move the WebP Express rules above the Wordpress rules in the .htaccess file located in your root dir<br>' .
198
  '- Grant the webserver permission to your wp-content dir, so it can create its rules there instead.'
199
+ );
200
  }
201
  }
202
  }
lib/options/page.php CHANGED
@@ -15,6 +15,9 @@ use \WebPExpress\HTAccess;
15
  include_once __DIR__ . '/../classes/Messenger.php';
16
  use \WebPExpress\Messenger;
17
 
 
 
 
18
  include_once __DIR__ . '/../classes/Paths.php';
19
  use \WebPExpress\Paths;
20
 
@@ -27,12 +30,13 @@ use \WebPExpress\State;
27
  include_once __DIR__ . '/../classes/TestRun.php';
28
  use \WebPExpress\TestRun;
29
 
 
30
  if (!current_user_can('manage_options')) {
31
  wp_die('You do not have sufficient permissions to access this page.');
32
  }
33
  ?>
34
  <div class="wrap">
35
- <h2>WebP Express Settings</h2>
36
 
37
  <?php
38
 
@@ -64,12 +68,15 @@ function printAutoQualityOptionForConverter($converterId) {
64
  </div>
65
  <?php
66
  }
67
- //update_option('webp-express-migration-version', '1');
68
 
69
  $canDetectQuality = TestRun::isLocalQualityDetectionWorking();
70
  $testResult = TestRun::getConverterStatus();
71
  $config = Config::getConfigForOptionsPage();
72
 
 
 
 
 
73
  if (!$testResult) {
74
  Messenger::printMessage(
75
  'error',
@@ -98,9 +105,11 @@ $webpexpress_settings_nonce = wp_create_nonce('webpexpress_settings_nonce');
98
  <?php
99
  //echo get_theme_root_uri();
100
 
101
- include_once __DIR__ . '/../classes/AlterHtmlHelper.php';
 
 
102
 
103
- echo '<form id="webpexpress_settings" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" method="post" >';
104
  ?>
105
  <input type="hidden" name="action" value="webpexpress_settings_submit">
106
  <input type="hidden" name="webpexpress_settings_nonce" value="<?php echo $webpexpress_settings_nonce ?>" />
@@ -141,11 +150,30 @@ function webpexpress_selectBoxOptions($selected, $options) {
141
  }
142
  }
143
 
144
- function webpexpress_radioButtons($optionName, $selected, $options, $helpTexts = []) {
145
- echo '<ul style="margin-left: 20px; margin-top: 5px">';
146
- foreach ($options as $optionValue => $text) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  $id = str_replace('-', '_', $optionName . '_' . $optionValue);
148
  echo '<li>';
 
 
 
 
149
  echo '<input type="radio" id="' . $id . '"';
150
  if ($optionValue == $selected) {
151
  echo ' checked="checked"';
@@ -157,6 +185,7 @@ function webpexpress_radioButtons($optionName, $selected, $options, $helpTexts =
157
  echo helpIcon($helpTexts[$optionValue]);
158
  }
159
  echo '</label>';
 
160
  echo '</li>';
161
  }
162
  echo '</ul>';
@@ -182,44 +211,71 @@ function webpexpress_checkbox($optionName, $checked, $label, $helpText = '') {
182
  }
183
 
184
  include_once 'options/operation-mode.inc';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
  if ($config['operation-mode'] != 'tweaked') {
187
- echo '<fieldset class="block">';
188
- echo '<table class="form-table"><tbody>';
189
  }
190
 
191
- include_once 'options/redirection-rules/redirection-rules.inc';
192
- if ($config['operation-mode'] != 'just-redirect') {
193
- include_once 'options/conversion-options/conversion-options.inc';
194
- }
195
- if ($config['operation-mode'] == 'just-redirect') {
 
 
196
  include_once 'options/conversion-options/destination-extension.inc';
197
- }
198
- include_once 'options/serve-options/serve-options.inc';
199
 
200
- if ($config['operation-mode'] != 'just-redirect') {
201
  include_once 'options/alter-html/alter-html.inc';
202
- }
 
 
 
 
203
 
204
- if ($config['operation-mode'] == 'no-varied-responses') {
205
- include_once 'options/redirection-rules/enable-redirection-to-webp-realizer.inc';
206
 
207
- // ps: we call it "auto convert", when in this mode
208
- include_once 'options/redirection-rules/enable-redirection-to-converter.inc';
209
- }
210
 
211
- if ($config['operation-mode'] == 'varied-responses') {
212
- include_once 'options/redirection-rules/enable-redirection-to-webp-realizer.inc';
213
- }
214
 
 
 
 
 
215
 
216
- if ($config['operation-mode'] != 'just-redirect') {
217
  include_once 'options/web-service-options/web-service-options.inc';
218
  }
219
 
220
  if ($config['operation-mode'] != 'tweaked') {
221
- echo '</tbody></table>';
222
- echo '</fieldset>';
223
  }
224
 
225
  ?>
15
  include_once __DIR__ . '/../classes/Messenger.php';
16
  use \WebPExpress\Messenger;
17
 
18
+ include_once __DIR__ . '/../classes/Multisite.php';
19
+ use \WebPExpress\Multisite;
20
+
21
  include_once __DIR__ . '/../classes/Paths.php';
22
  use \WebPExpress\Paths;
23
 
30
  include_once __DIR__ . '/../classes/TestRun.php';
31
  use \WebPExpress\TestRun;
32
 
33
+
34
  if (!current_user_can('manage_options')) {
35
  wp_die('You do not have sufficient permissions to access this page.');
36
  }
37
  ?>
38
  <div class="wrap">
39
+ <h2>WebP Express Settings<?php echo Multisite::isNetworkActivated() ? ' (network)' : ''; ?></h2>
40
 
41
  <?php
42
 
68
  </div>
69
  <?php
70
  }
 
71
 
72
  $canDetectQuality = TestRun::isLocalQualityDetectionWorking();
73
  $testResult = TestRun::getConverterStatus();
74
  $config = Config::getConfigForOptionsPage();
75
 
76
+ //State::setState('last-ewww-optimize-attempt', 0);
77
+ //State::setState('last-ewww-optimize', 0);
78
+ \WebPExpress\KeepEwwwSubscriptionAlive::keepAliveIfItIsTime($config);
79
+
80
  if (!$testResult) {
81
  Messenger::printMessage(
82
  'error',
105
  <?php
106
  //echo get_theme_root_uri();
107
 
108
+ //include_once __DIR__ . '/../classes/AlterHtmlHelper.php';
109
+ //$actionUrl = Multisite::isNetworkActivated() ? network_admin_url( 'admin-post.php' ) : admin_url( 'admin-post.php' );
110
+ $actionUrl = admin_url('admin-post.php');
111
 
112
+ echo '<form id="webpexpress_settings" action="' . esc_url($actionUrl) . '" method="post" >';
113
  ?>
114
  <input type="hidden" name="action" value="webpexpress_settings_submit">
115
  <input type="hidden" name="webpexpress_settings_nonce" value="<?php echo $webpexpress_settings_nonce ?>" />
150
  }
151
  }
152
 
153
+ function webpexpress_radioButton($optionName, $optionValue, $label, $selectedValue, $helpText = null) {
154
+ $id = str_replace('-', '_', $optionName . '_' . $optionValue);
155
+ echo '<input type="radio" id="' . $id . '"';
156
+ if ($optionValue == $selectedValue) {
157
+ echo ' checked="checked"';
158
+ }
159
+ echo ' name="' . $optionName . '" value="' . $optionValue . '" style="margin-right: 10px">';
160
+ echo '<label for="' . $id . '">';
161
+ echo $label;
162
+ if (!is_null($helpText)) {
163
+ echo helpIcon($helpText);
164
+ }
165
+ echo '</label>';
166
+ }
167
+
168
+ function webpexpress_radioButtons($optionName, $selected, $options, $helpTexts = [], $style='margin-left: 20px; margin-top: 5px') {
169
+ echo '<ul style="' . $style . '">';
170
+ foreach ($options as $optionValue => $label) {
171
  $id = str_replace('-', '_', $optionName . '_' . $optionValue);
172
  echo '<li>';
173
+
174
+ webpexpress_radioButton($optionName, $optionValue, $label, $selected, isset($helpTexts[$optionValue]) ? $helpTexts[$optionValue] : null);
175
+
176
+ /*
177
  echo '<input type="radio" id="' . $id . '"';
178
  if ($optionValue == $selected) {
179
  echo ' checked="checked"';
185
  echo helpIcon($helpTexts[$optionValue]);
186
  }
187
  echo '</label>';
188
+ */
189
  echo '</li>';
190
  }
191
  echo '</ul>';
211
  }
212
 
213
  include_once 'options/operation-mode.inc';
214
+ include_once 'options/general/general.inc';
215
+
216
+
217
+ /*
218
+ idea:
219
+
220
+ $options = [
221
+ 'tweaked' => [
222
+ 'general' => [
223
+ 'image-types',
224
+ 'destination-folder',
225
+ 'destination-extension',
226
+ 'cache-control'
227
+ ]
228
+ ],
229
+ ...
230
+ ];
231
+ */
232
+
233
 
234
  if ($config['operation-mode'] != 'tweaked') {
235
+ // echo '<fieldset class="block">';
236
+ // echo '<table class="form-table"><tbody>';
237
  }
238
 
239
+ if ($config['operation-mode'] == 'no-conversion') {
240
+
241
+ // General
242
+ /*
243
+ echo '<tr><th colspan=2>';
244
+ echo '<h2>General</h2>';
245
+ echo '</th></tr>';
246
  include_once 'options/conversion-options/destination-extension.inc';
247
+ include_once 'options/general/image-types.inc';
248
+ */
249
 
250
+ include_once 'options/redirection-rules/redirection-rules.inc';
251
  include_once 'options/alter-html/alter-html.inc';
252
+ } else {
253
+ include_once 'options/redirection-rules/redirection-rules.inc';
254
+ include_once 'options/conversion-options/conversion-options.inc';
255
+ //include_once 'options/conversion-options/destination-extension.inc';
256
+ include_once 'options/serve-options/serve-options.inc';
257
 
258
+ include_once 'options/alter-html/alter-html.inc';
 
259
 
260
+ /*
261
+ if ($config['operation-mode'] == 'cdn-friendly') {
262
+ include_once 'options/redirection-rules/enable-redirection-to-webp-realizer.inc';
263
 
264
+ // ps: we call it "auto convert", when in this mode
265
+ include_once 'options/redirection-rules/enable-redirection-to-converter.inc';
266
+ }
267
 
268
+ if ($config['operation-mode'] == 'varied-image-responses') {
269
+ include_once 'options/redirection-rules/enable-redirection-to-webp-realizer.inc';
270
+ }
271
+ */
272
 
 
273
  include_once 'options/web-service-options/web-service-options.inc';
274
  }
275
 
276
  if ($config['operation-mode'] != 'tweaked') {
277
+ // echo '</tbody></table>';
278
+ // echo '</fieldset>';
279
  }
280
 
281
  ?>
lib/options/submit.php CHANGED
@@ -15,6 +15,9 @@ use \WebPExpress\Messenger;
15
  include_once __DIR__ . '/../classes/Paths.php';
16
  use \WebPExpress\Paths;
17
 
 
 
 
18
  // https://premium.wpmudev.org/blog/handling-form-submissions/
19
  // checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
20
 
@@ -26,7 +29,7 @@ function webp_express_sanitize_quality_field($text) {
26
  return max(0, min($q, 100));
27
  }
28
 
29
- $config = Config::loadConfigAndFix();
30
  $oldConfig = $config;
31
 
32
  // Set options that are available in all operation modes
@@ -40,7 +43,7 @@ $config = array_merge($config, [
40
  ]);
41
 
42
  // Set options that are available in all operation modes, except the "CDN friendly" mode
43
- if ($_POST['operation-mode'] != 'no-varied-responses') {
44
 
45
  $cacheControl = sanitize_text_field($_POST['cache-control']);
46
  $config['cache-control'] = $cacheControl;
@@ -58,13 +61,35 @@ if ($_POST['operation-mode'] != 'no-varied-responses') {
58
  }
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- // Set options that are available in all operation modes, except the "just-redirect" mode
63
- if ($_POST['operation-mode'] != 'just-redirect') {
64
 
65
- $config['enable-redirection-to-webp-realizer'] = isset($_POST['enable-redirection-to-webp-realizer']);
 
66
 
67
 
 
 
68
  // Metadata
69
  // --------
70
  $config['metadata'] = sanitize_text_field($_POST['metadata']);
@@ -142,37 +167,30 @@ if ($_POST['operation-mode'] != 'just-redirect') {
142
  }
143
  }
144
  }
145
-
146
- // Alter HTML
147
-
148
- $config['alter-html'] = [];
149
- $config['alter-html']['enabled'] = isset($_POST['alter-html-enabled']);
150
- if ($_POST['alter-html-replacement'] == 'url') {
151
- $config['alter-html']['only-for-webp-enabled-browsers'] = isset($_POST['alter-html-only-for-webp-enabled-browsers']);
152
- } else {
153
- $config['alter-html']['only-for-webp-enabled-browsers'] = false;
154
- }
155
- $config['alter-html']['only-for-webps-that-exists'] = (!isset($_POST['alter-html-for-webps-that-has-yet-to-exist']));
156
- $config['alter-html']['replacement'] = $_POST['alter-html-replacement'];
157
- $config['alter-html']['hooks'] = $_POST['alter-html-hooks'];
158
-
159
  }
160
 
 
161
  switch ($_POST['operation-mode']) {
162
- case 'varied-responses':
163
  $config = array_merge($config, [
164
  'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
165
  'destination-folder' => $_POST['destination-folder'],
166
  'destination-extension' => (($_POST['destination-folder'] == 'mingled') ? $_POST['destination-extension'] : 'append'),
167
  ]);
168
  break;
169
- case 'no-varied-responses':
170
  $config = array_merge($config, [
171
  'destination-folder' => $_POST['destination-folder'],
172
  'destination-extension' => (($_POST['destination-folder'] == 'mingled') ? $_POST['destination-extension'] : 'append'),
173
  'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']), // PS: its called "autoconvert" in this mode
174
  ]);
175
  break;
 
 
 
 
 
 
176
  case 'tweaked':
177
  $config = array_merge($config, [
178
  'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']),
@@ -194,6 +212,12 @@ if ($_POST['operation-mode'] != $_POST['change-operation-mode']) {
194
  $config = Config::applyOperationMode($config);
195
  }
196
 
 
 
 
 
 
 
197
  // SAVE!
198
  // -----
199
  $result = Config::saveConfigurationAndHTAccess($config, isset($_POST['force']));
@@ -312,7 +336,7 @@ if (!$result['saved-both-config']) {
312
 
313
  Messenger::addMessage(
314
  'success',
315
- 'Configuration saved. Rewrite rules were saved to your <i>.htaccess</i> in your <i>' . $mainResult . '</i> folder' .
316
  (Paths::isWPContentDirMoved() ? ' (which you moved, btw)' : '') .
317
  ($savedToPluginsToo ? ' as well as in your <i>plugins</i> folder' : '') .
318
  ((Paths::isWPContentDirMoved() && $savedToPluginsToo) ? ' (you moved that as well!)' : '.') .
15
  include_once __DIR__ . '/../classes/Paths.php';
16
  use \WebPExpress\Paths;
17
 
18
+ use \WebPExpress\CapabilityTest;
19
+
20
+
21
  // https://premium.wpmudev.org/blog/handling-form-submissions/
22
  // checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
23
 
29
  return max(0, min($q, 100));
30
  }
31
 
32
+ $config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
33
  $oldConfig = $config;
34
 
35
  // Set options that are available in all operation modes
43
  ]);
44
 
45
  // Set options that are available in all operation modes, except the "CDN friendly" mode
46
+ if ($_POST['operation-mode'] != 'cdn-friendly') {
47
 
48
  $cacheControl = sanitize_text_field($_POST['cache-control']);
49
  $config['cache-control'] = $cacheControl;
61
  }
62
  }
63
 
64
+ // Set options that are available in ALL operation modes
65
+
66
+ // Alter HTML
67
+ $config['alter-html'] = [];
68
+ $config['alter-html']['enabled'] = isset($_POST['alter-html-enabled']);
69
+ if ($_POST['alter-html-replacement'] == 'url') {
70
+ $config['alter-html']['only-for-webp-enabled-browsers'] = isset($_POST['alter-html-only-for-webp-enabled-browsers']);
71
+ } else {
72
+ $config['alter-html']['only-for-webp-enabled-browsers'] = false;
73
+ }
74
+ if ($_POST['alter-html-replacement'] == 'picture') {
75
+ $config['alter-html']['alter-html-add-picturefill-js'] = isset($_POST['alter-html-add-picturefill-js']);
76
+ }
77
+ if ($_POST['operation-mode'] != 'no-conversion') {
78
+ $config['alter-html']['only-for-webps-that-exists'] = (!isset($_POST['alter-html-for-webps-that-has-yet-to-exist']));
79
+ } else {
80
+ $config['alter-html']['only-for-webps-that-exists'] = true;
81
+ }
82
+
83
+ $config['alter-html']['replacement'] = $_POST['alter-html-replacement'];
84
+ $config['alter-html']['hooks'] = $_POST['alter-html-hooks'];
85
 
 
 
86
 
87
+ // Set options that are available in all operation modes, except the "no-conversion" mode
88
+ if ($_POST['operation-mode'] != 'no-conversion') {
89
 
90
 
91
+ $config['enable-redirection-to-webp-realizer'] = isset($_POST['enable-redirection-to-webp-realizer']);
92
+
93
  // Metadata
94
  // --------
95
  $config['metadata'] = sanitize_text_field($_POST['metadata']);
167
  }
168
  }
169
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
172
+
173
  switch ($_POST['operation-mode']) {
174
+ case 'varied-image-responses':
175
  $config = array_merge($config, [
176
  'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
177
  'destination-folder' => $_POST['destination-folder'],
178
  'destination-extension' => (($_POST['destination-folder'] == 'mingled') ? $_POST['destination-extension'] : 'append'),
179
  ]);
180
  break;
181
+ case 'cdn-friendly':
182
  $config = array_merge($config, [
183
  'destination-folder' => $_POST['destination-folder'],
184
  'destination-extension' => (($_POST['destination-folder'] == 'mingled') ? $_POST['destination-extension'] : 'append'),
185
  'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']), // PS: its called "autoconvert" in this mode
186
  ]);
187
  break;
188
+ case 'no-conversion':
189
+ $config = array_merge($config, [
190
+ 'redirect-to-existing-in-htaccess' => isset($_POST['redirect-to-existing-in-htaccess']),
191
+ 'destination-extension' => $_POST['destination-extension'],
192
+ ]);
193
+ break;
194
  case 'tweaked':
195
  $config = array_merge($config, [
196
  'enable-redirection-to-converter' => isset($_POST['enable-redirection-to-converter']),
212
  $config = Config::applyOperationMode($config);
213
  }
214
 
215
+ // If we are going to save .htaccess, run and store capability tests first (we should only store results when .htaccess is updated as well)
216
+ if (isset($_POST['force']) || HTAccess::doesRewriteRulesNeedUpdate($config)) {
217
+ Config::runAndStoreCapabilityTests($config);
218
+ }
219
+
220
+
221
  // SAVE!
222
  // -----
223
  $result = Config::saveConfigurationAndHTAccess($config, isset($_POST['force']));
336
 
337
  Messenger::addMessage(
338
  'success',
339
+ 'Configuration saved.<br>Rewrite rules were saved to your <i>.htaccess</i> in your <i>' . $mainResult . '</i> folder' .
340
  (Paths::isWPContentDirMoved() ? ' (which you moved, btw)' : '') .
341
  ($savedToPluginsToo ? ' as well as in your <i>plugins</i> folder' : '') .
342
  ((Paths::isWPContentDirMoved() && $savedToPluginsToo) ? ' (you moved that as well!)' : '.') .
lib/uninstall.php CHANGED
@@ -6,6 +6,7 @@
6
  include_once __DIR__ . '/classes/Paths.php';
7
  use \WebPExpress\Paths;
8
 
 
9
 
10
  /* helper. Remove dir recursively. No warnings - fails silently */
11
  function webpexpress_rrmdir($dir) {
@@ -32,8 +33,8 @@ $optionsToDelete = [
32
  'webp-express-migration-version'
33
  ];
34
  foreach ($optionsToDelete as $i => $optionName) {
35
- delete_option($optionName);
36
  }
37
 
38
- // remove content dir (config plus images)
39
  webpexpress_rrmdir(Paths::getWebPExpressContentDirAbs());
6
  include_once __DIR__ . '/classes/Paths.php';
7
  use \WebPExpress\Paths;
8
 
9
+ use \WebPExpress\Option;
10
 
11
  /* helper. Remove dir recursively. No warnings - fails silently */
12
  function webpexpress_rrmdir($dir) {
33
  'webp-express-migration-version'
34
  ];
35
  foreach ($optionsToDelete as $i => $optionName) {
36
+ Option::deleteOption($optionName);
37
  }
38
 
39
+ // remove content dir (config plus images plus htaccess-tests)
40
  webpexpress_rrmdir(Paths::getWebPExpressContentDirAbs());
webp-express.php CHANGED
@@ -3,10 +3,11 @@
3
  * Plugin Name: WebP Express
4
  * Plugin URI: https://github.com/rosell-dk/webp-express
5
  * Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
6
- * Version: 0.11.3
7
  * Author: Bjørn Rosell
8
  * Author URI: https://www.bitwise-it.dk
9
  * License: GPL2
 
10
  */
11
 
12
  /*
@@ -16,6 +17,17 @@ Note: Perhaps create a plugin page on my website?, ie https://www.bitwise-it.dk/
16
  define('WEBPEXPRESS_PLUGIN', __FILE__);
17
  define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
18
 
 
 
 
 
 
 
 
 
 
 
 
19
  if (is_admin()) {
20
  include __DIR__ . '/lib/admin.php';
21
  }
@@ -36,7 +48,8 @@ function webp_express_process_post() {
36
  }
37
  add_action( 'init', 'webp_express_process_post' );
38
 
39
- if (get_option('webp-express-alter-html', false)) {
 
40
  require_once __DIR__ . '/lib/classes/AlterHtmlInit.php';
41
  \WebPExpress\AlterHtmlInit::setHooks();
42
  }
3
  * Plugin Name: WebP Express
4
  * Plugin URI: https://github.com/rosell-dk/webp-express
5
  * Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
6
+ * Version: 0.12.0
7
  * Author: Bjørn Rosell
8
  * Author URI: https://www.bitwise-it.dk
9
  * License: GPL2
10
+ * Network: true
11
  */
12
 
13
  /*
17
  define('WEBPEXPRESS_PLUGIN', __FILE__);
18
  define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
19
 
20
+ use \WebPExpress\Option;
21
+
22
+ spl_autoload_register('webpexpress_autoload');
23
+ function webpexpress_autoload($class) {
24
+ //echo $class . "\n<br>";
25
+ if (strpos($class, 'WebPExpress\\') === 0) {
26
+ //echo WEBPEXPRESS_PLUGIN_DIR . '/lib/classes/' . substr($class, 12) . '.php' . "\n<br><br>";
27
+ require_once WEBPEXPRESS_PLUGIN_DIR . '/lib/classes/' . substr($class, 12) . '.php';
28
+ }
29
+ }
30
+
31
  if (is_admin()) {
32
  include __DIR__ . '/lib/admin.php';
33
  }
48
  }
49
  add_action( 'init', 'webp_express_process_post' );
50
 
51
+
52
+ if (Option::getOption('webp-express-alter-html', false)) {
53
  require_once __DIR__ . '/lib/classes/AlterHtmlInit.php';
54
  \WebPExpress\AlterHtmlInit::setHooks();
55
  }
wod/webp-on-demand.php CHANGED
@@ -15,6 +15,36 @@ error_reporting(E_ALL);
15
  use \WebPConvert\WebPConvert;
16
  use \WebPConvert\ServeExistingOrHandOver;
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  function loadConfig($configFilename) {
19
  if (!file_exists($configFilename)) {
20
  header('X-WebP-Express-Error: Configuration file not found!', true);
@@ -30,61 +60,100 @@ function loadConfig($configFilename) {
30
  return json_decode($json, true);
31
  }
32
 
33
- function getSource($allowInQS, $allowInHeader) {
34
- //echo '<pre>' . print_r($_SERVER, true) . '</pre>'; exit;
 
35
 
36
  // First check if it is in an environment variable - thats the safest way
37
- foreach ($_SERVER as $key => $item) {
38
- if (substr($key, -14) == 'REDIRECT_REQFN') {
39
- return $item;
40
- }
41
  }
42
 
43
- if ($allowInHeader) {
 
 
 
 
 
 
 
 
 
44
  if (isset($_SERVER['HTTP_REQFN'])) {
45
  return $_SERVER['HTTP_REQFN'];
46
  }
47
  }
48
 
49
- if ($allowInQS) {
50
- if (isset($_GET['source'])) {
51
- return $_GET['source']; // No url decoding needed as $_GET is already decoded
52
- } elseif (isset($_GET['xsource'])) {
53
- return substr($_GET['xsource'], 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
 
55
  }
56
 
57
  // Last resort is to use $_SERVER['REQUEST_URI'], well knowing that it does not give the
58
  // correct result in all setups (ie "folder method 1")
59
  $requestUriNoQS = explode('?', $_SERVER['REQUEST_URI'])[0];
60
- $docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
61
  $source = $docRoot . urldecode($requestUriNoQS);
62
  if (file_exists($source)) {
63
  return $source;
64
  }
65
 
66
- header('X-WebP-Express-Error: None of the available methods for locating source file works', true);
67
- echo 'None of the available methods for locating source file works!';
68
- if (!$allowInHeader) {
69
- echo '<br>Have you tried allowing source to be passed as a request header?';
 
 
 
 
 
70
  }
71
- if (!$allowInQS) {
72
- echo '<br>Have you tried allowing source to be passed in querystring?';
 
 
73
  }
74
- exit;
 
 
75
  }
76
 
77
  $docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
78
- $wpContentDirRel = (isset($_GET['wp-content']) ? $_GET['wp-content'] : 'wp-content');
79
- $webExpressContentDirRel = $wpContentDirRel . '/webp-express';
80
- $webExpressContentDirAbs = $docRoot . '/' . $webExpressContentDirRel;
81
- $configFilename = $webExpressContentDirAbs . '/config/wod-options.json';
82
-
83
- $options = loadConfig($configFilename);
84
 
85
- $allowInQS = !(isset($options['do-not-pass-source-in-query-string']) && $options['do-not-pass-source-in-query-string']);
86
- $allowInHeader = true; // todo: implement setting
87
- $source = getSource($allowInQS, $allowInHeader);
88
  //$source = getSource(false, false);
89
 
90
  //echo $source; exit;
15
  use \WebPConvert\WebPConvert;
16
  use \WebPConvert\ServeExistingOrHandOver;
17
 
18
+ function exitWithError($msg) {
19
+ header('X-WebP-Express-Error: ' . $msg, true);
20
+ echo $msg;
21
+ exit;
22
+ }
23
+
24
+ if (preg_match('#webp-on-demand.php#', $_SERVER['REQUEST_URI'])) {
25
+ exitWithError('Direct access is not allowed');
26
+ exit;
27
+ }
28
+
29
+ /**
30
+ * Get environment variable set with mod_rewrite module
31
+ * Return false if the environment variable isn't found
32
+ */
33
+ function getEnvPassedInRewriteRule($envName) {
34
+ // Envirenment variables passed through the REWRITE module have "REWRITE_" as a prefix (in Apache, not Litespeed, if I recall correctly)
35
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
36
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
37
+ // We simply look for an environment variable that ends with what we are looking for.
38
+ // (so make sure to make it unique)
39
+ $len = strlen($envName);
40
+ foreach ($_SERVER as $key => $item) {
41
+ if (substr($key, -$len) == $envName) {
42
+ return $item;
43
+ }
44
+ }
45
+ return false;
46
+ }
47
+
48
  function loadConfig($configFilename) {
49
  if (!file_exists($configFilename)) {
50
  header('X-WebP-Express-Error: Configuration file not found!', true);
60
  return json_decode($json, true);
61
  }
62
 
63
+ function getSource() {
64
+ global $options;
65
+ global $docRoot;
66
 
67
  // First check if it is in an environment variable - thats the safest way
68
+ $source = getEnvPassedInRewriteRule('REQFN');
69
+ if ($source !== false) {
70
+ return $source;
 
71
  }
72
 
73
+ // Then header
74
+ if (isset($options['base-htaccess-on-these-capability-tests'])) {
75
+ $capTests = $options['base-htaccess-on-these-capability-tests'];
76
+ $passThroughHeaderDefinitelyUnavailable = ($capTests['passThroughHeaderWorking'] === false);
77
+ $passThrougEnvVarDefinitelyAvailable =($capTests['passThroughEnvWorking'] === true);
78
+ } else {
79
+ $passThroughHeaderDefinitelyUnavailable = false;
80
+ $passThrougEnvVarDefinitelyAvailable = false;
81
+ }
82
+ if ((!$passThrougEnvVarDefinitelyAvailable) && (!$passThroughHeaderDefinitelyUnavailable)) {
83
  if (isset($_SERVER['HTTP_REQFN'])) {
84
  return $_SERVER['HTTP_REQFN'];
85
  }
86
  }
87
 
88
+ // Then querystring (full path)
89
+ if (isset($_GET['xsource'])) {
90
+ return substr($_GET['xsource'], 1); // No url decoding needed as $_GET is already decoded
91
+ } elseif (isset($_GET['source'])) {
92
+ return $_GET['source'];
93
+ }
94
+
95
+ // Then querystring (relative path)
96
+ $srcRel = '';
97
+ if (isset($_GET['xsource-rel'])) {
98
+ $srcRel = substr($_GET['xsource-rel'], 1);
99
+ } elseif (isset($_GET['source-rel'])) {
100
+ $srcRel = $_GET['source-rel'];
101
+ }
102
+ if ($srcRel != '') {
103
+ if (isset($_GET['source-rel-filter'])) {
104
+ if ($_GET['source-rel-filter'] == 'discard-parts-before-wp-content') {
105
+ $parts = explode('/', $srcRel);
106
+ $wp_content = isset($_GET['wp-content']) ? $_GET['wp-content'] : 'wp-content';
107
+
108
+ if (in_array($wp_content, $parts)) {
109
+ foreach($parts as $index => $part) {
110
+ if($part !== $wp_content) {
111
+ unset($parts[$index]);
112
+ } else {
113
+ break;
114
+ }
115
+ }
116
+ $srcRel = implode('/', $parts);
117
+ }
118
+ }
119
  }
120
+ return $docRoot . '/' . $srcRel;
121
  }
122
 
123
  // Last resort is to use $_SERVER['REQUEST_URI'], well knowing that it does not give the
124
  // correct result in all setups (ie "folder method 1")
125
  $requestUriNoQS = explode('?', $_SERVER['REQUEST_URI'])[0];
126
+ //$docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
127
  $source = $docRoot . urldecode($requestUriNoQS);
128
  if (file_exists($source)) {
129
  return $source;
130
  }
131
 
132
+ // No luck whatsoever!
133
+ exitWithError('webp-on-demand.php was not passed any filename to convert');
134
+ }
135
+
136
+ function getWpContentRel() {
137
+ // Passed in env variable?
138
+ $wpContentDirRel = getEnvPassedInRewriteRule('WPCONTENT');
139
+ if ($wpContentDirRel !== false) {
140
+ return $wpContentDirRel;
141
  }
142
+
143
+ // Passed in QS?
144
+ if (isset($_GET['wp-content'])) {
145
+ return $_GET['wp-content'];
146
  }
147
+
148
+ // In case above fails, fall back to standard location
149
+ return 'wp-content';
150
  }
151
 
152
  $docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
153
+ $webExpressContentDirAbs = $docRoot . '/' . getWpContentRel() . '/webp-express';
154
+ $options = loadConfig($webExpressContentDirAbs . '/config/wod-options.json');
 
 
 
 
155
 
156
+ $source = getSource();
 
 
157
  //$source = getSource(false, false);
158
 
159
  //echo $source; exit;
wod/webp-realizer.php CHANGED
@@ -10,11 +10,39 @@ error_reporting(E_ALL);
10
  //require 'webp-on-demand-1.inc';
11
  //require '../vendor/autoload.php';
12
 
13
- //print_r($_GET); exit;
14
-
15
  use \WebPConvert\WebPConvert;
16
  use \WebPConvert\ServeExistingOrHandOver;
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  function loadConfig($configFilename) {
19
  if (!file_exists($configFilename)) {
20
  header('X-WebP-Express-Error: Configuration file not found!', true);
@@ -30,6 +58,7 @@ function loadConfig($configFilename) {
30
  return json_decode($json, true);
31
  }
32
 
 
33
  function getDestinationRealPath($dest) {
34
  //echo $_SERVER["DOCUMENT_ROOT"] . '<br>' . $dest . '<br>';
35
  if (strpos($dest, $_SERVER["DOCUMENT_ROOT"]) === 0) {
@@ -37,21 +66,51 @@ function getDestinationRealPath($dest) {
37
  } else {
38
  return $dest;
39
  }
40
- }
 
 
 
 
41
 
42
- function getDestination($allowInQS, $allowInHeader) {
43
  // First check if it is in an environment variable - thats the safest way
44
- foreach ($_SERVER as $key => $item) {
45
- if (substr($key, -14) == 'REDIRECT_REQFN') {
46
- return getDestinationRealPath($item);
47
- }
48
  }
49
 
50
- if ($allowInHeader) {
51
- if (isset($_SERVER['HTTP_REQFN'])) {
52
- //echo 'dest:' . $_SERVER['HTTP_REQFN'];
53
- return getDestinationRealPath($_SERVER['HTTP_REQFN']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
 
55
  }
56
 
57
  // Last resort is to use $_SERVER['REQUEST_URI'], well knowing that it does not give the
@@ -62,20 +121,30 @@ function getDestination($allowInQS, $allowInHeader) {
62
  return $dest;
63
  }
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  $docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
66
- $wpContentDirRel = (isset($_GET['wp-content']) ? $_GET['wp-content'] : 'wp-content');
67
- $webExpressContentDirRel = $wpContentDirRel . '/webp-express';
68
- $webExpressContentDirAbs = $docRoot . '/' . $webExpressContentDirRel;
69
- $configFilename = $webExpressContentDirAbs . '/config/wod-options.json';
70
 
71
- $options = loadConfig($configFilename);
72
 
73
- $allowInQS = !(isset($options['do-not-pass-source-in-query-string']) && $options['do-not-pass-source-in-query-string']);
74
- $allowInHeader = true; // todo: implement setting
75
- $destination = getDestination($allowInQS, $allowInHeader);
76
- //$destination = getDestination(false, false);
77
 
78
- //echo $destination; exit;
79
 
80
  // Try to find source in same folder.
81
  // Return false on failure
10
  //require 'webp-on-demand-1.inc';
11
  //require '../vendor/autoload.php';
12
 
 
 
13
  use \WebPConvert\WebPConvert;
14
  use \WebPConvert\ServeExistingOrHandOver;
15
 
16
+ function exitWithError($msg) {
17
+ header('X-WebP-Express-Error: ' . $msg, true);
18
+ echo $msg;
19
+ exit;
20
+ }
21
+
22
+ if (preg_match('#webp-realizer.php#', $_SERVER['REQUEST_URI'])) {
23
+ exitWithError('Direct access is not allowed');
24
+ exit;
25
+ }
26
+
27
+ /**
28
+ * Get environment variable set with mod_rewrite module
29
+ * Return false if the environment variable isn't found
30
+ */
31
+ function getEnvPassedInRewriteRule($envName) {
32
+ // Envirenment variables passed through the REWRITE module have "REWRITE_" as a prefix (in Apache, not Litespeed, if I recall correctly)
33
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
34
+ // Multiple iterations causes multiple REWRITE_ prefixes, and we get many environment variables set.
35
+ // We simply look for an environment variable that ends with what we are looking for.
36
+ // (so make sure to make it unique)
37
+ $len = strlen($envName);
38
+ foreach ($_SERVER as $key => $item) {
39
+ if (substr($key, -$len) == $envName) {
40
+ return $item;
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+
46
  function loadConfig($configFilename) {
47
  if (!file_exists($configFilename)) {
48
  header('X-WebP-Express-Error: Configuration file not found!', true);
58
  return json_decode($json, true);
59
  }
60
 
61
+ /*
62
  function getDestinationRealPath($dest) {
63
  //echo $_SERVER["DOCUMENT_ROOT"] . '<br>' . $dest . '<br>';
64
  if (strpos($dest, $_SERVER["DOCUMENT_ROOT"]) === 0) {
66
  } else {
67
  return $dest;
68
  }
69
+ }*/
70
+
71
+ function getDestination() {
72
+ global $options;
73
+ global $docRoot;
74
 
 
75
  // First check if it is in an environment variable - thats the safest way
76
+ $destinationRel = getEnvPassedInRewriteRule('DESTINATIONREL');
77
+ if ($destinationRel !== false) {
78
+ return $docRoot . '/' . $destinationRel;
 
79
  }
80
 
81
+ // Next, check querystring (full path)
82
+ if (isset($_GET['xdestination'])) {
83
+ return substr($_GET['xdestination'], 1); // No url decoding needed as $_GET is already decoded
84
+ } elseif (isset($_GET['destination'])) {
85
+ return $_GET['destination'];
86
+ }
87
+
88
+ // Next, check querystring (relative path)
89
+ $destinationRel = '';
90
+ if (isset($_GET['xdestination-rel'])) {
91
+ $destinationRel = substr($_GET['xdestination-rel'], 1);
92
+ } elseif (isset($_GET['destination-rel'])) {
93
+ $destinationRel = $_GET['destination-rel'];
94
+ }
95
+ if ($destinationRel != '') {
96
+ if (isset($_GET['source-rel-filter'])) {
97
+ if ($_GET['source-rel-filter'] == 'discard-parts-before-wp-content') {
98
+ $parts = explode('/', $destinationRel);
99
+ $wp_content = isset($_GET['wp-content']) ? $_GET['wp-content'] : 'wp-content';
100
+
101
+ if (in_array($wp_content, $parts)) {
102
+ foreach($parts as $index => $part) {
103
+ if($part !== $wp_content) {
104
+ unset($parts[$index]);
105
+ } else {
106
+ break;
107
+ }
108
+ }
109
+ $destinationRel = implode('/', $parts);
110
+ }
111
+ }
112
  }
113
+ return $docRoot . '/' . $destinationRel;
114
  }
115
 
116
  // Last resort is to use $_SERVER['REQUEST_URI'], well knowing that it does not give the
121
  return $dest;
122
  }
123
 
124
+ function getWpContentRel() {
125
+ // Passed in env variable?
126
+ $wpContentDirRel = getEnvPassedInRewriteRule('WPCONTENT');
127
+ if ($wpContentDirRel !== false) {
128
+ return $wpContentDirRel;
129
+ }
130
+
131
+ // Passed in QS?
132
+ if (isset($_GET['wp-content'])) {
133
+ return $_GET['wp-content'];
134
+ }
135
+
136
+ // In case above fails, fall back to standard location
137
+ return 'wp-content';
138
+ }
139
+
140
  $docRoot = rtrim(realpath($_SERVER["DOCUMENT_ROOT"]), '/');
141
+ $webExpressContentDirAbs = $docRoot . '/' . getWpContentRel() . '/webp-express';
142
+ $options = loadConfig($webExpressContentDirAbs . '/config/wod-options.json');
 
 
143
 
144
+ $destination = getDestination();
145
 
146
+ //echo 'destination: ' . $destination; exit;
 
 
 
147
 
 
148
 
149
  // Try to find source in same folder.
150
  // Return false on failure