WebP Express - Version 0.4.0

Version Description

  • Fixed bug: .htaccess was not updated every time the settings was saved.
  • Fixed bug: The plugin generated error upon activation.
  • Now produces X-WebP-Convert-And-Serve headers with info about the conversion - useful for validating that converter receives the expected arguments and executes correctly.
  • WebPExpress options are now removed when plugin is uninstalled.
  • No longer generates .htaccess rules on install. The user now has to actively go to Web Express setting and save first
  • Added a "first time" message on options page and a reactivation message

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

=

Download this release

Release Info

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

Code changes from version 0.3.0 to 0.4.0

README.md CHANGED
@@ -6,18 +6,15 @@ Serve autogenerated WebP images instead of jpeg/png to browsers that supports We
6
7
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
8
9
- The approach has the benefit that is works regardless of how an image found its way into your site. The plugin does not need to hook into Media Library events, Gallery events etc, because it does not need to maintain a complete collection of converted images. It makes it so much simpler -- and lighter.
10
11
- The plugin works by .htaccess magic coupled with an image converter. Basically, jpegs and pngs are routed to the image converter, unless the image converter has already converted the image. In that case, it is routed directly to the converted image. The images are saved in a subfolder to the "uploads" folder, preserving the same structure as the originals. In order to allow caching on CDN, the .htaccess rules add a "Vary" HTTP header when serving the WebP images.
12
13
- *Note:*
14
- The rules created in .htaccess are sensitive to the location of your image folder and the location of wordpress. If you at some point change one of these, the rules will have to be updated. .htaccess rules are updated whenever you change a setting (all configuration is actually stored in .htaccess, which allows the converter to run faster, than if it had the overhead of bootstrapping Wordpress)
15
-
16
- *Note:*
17
- 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.
18
-
19
- *Note:*
20
- The plugin has not been tested in multisite configurations. It's on the roadmap!
21
22
23
## Installation
@@ -29,8 +26,6 @@ The plugin has not been tested in multisite configurations. It's on the roadmap!
29
30
You configure the plugin in *Settings > WebP Express*.
31
32
- The *Image types to convert* option is initially set to "Do not convert any images!". This allows you to test that there is a working converter, before redirecting images to the converter.
33
-
34
WebPExpress uses [WebPConvert](https://github.com/rosell-dk/webp-convert) to convert images. This is how WebPConvert describes itself:
35
36
*The current state of WebP conversion in PHP is this: There are several ways to do it, but they all require something of the server setup. What works on one shared host might not work on another. WebPConvert combines these methods by iterating over them (optionally in the desired order) until one of them is successful - or all of them fail.*
@@ -52,8 +47,21 @@ Note that the plugin does not change any HTML. In the HTML the image src is stil
52
- Reload the page
53
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
54
55
You can also append `?debug` after any image url, in order to run a conversion, and see the conversion report. Btw: If you append `?reconvert` after an image url, you will force a reconversion of the image.
56
57
58
## Limitations
59
6
7
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
8
9
+ The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
10
11
+ The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and some of the ecosystem around it: [WebPConvertAndServe](https://github.com/rosell-dk/webp-convert-and-serve) and [WebPOnDemand](https://github.com/rosell-dk/webp-on-demand)
12
13
+ #### Benefits
14
+ - Much faster load time on images in Chrome browsers. The converted images are typically less than half the size (for jpeg), while maintaining the same quality. Bear in mind that images typically are responsible for most of the bandwidth usage.
15
+ - Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
16
+ - Better ranking in Google searches (performance is taken into account by Google)
17
+ - Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
18
19
20
## Installation
26
27
You configure the plugin in *Settings > WebP Express*.
28
29
WebPExpress uses [WebPConvert](https://github.com/rosell-dk/webp-convert) to convert images. This is how WebPConvert describes itself:
30
31
*The current state of WebP conversion in PHP is this: There are several ways to do it, but they all require something of the server setup. What works on one shared host might not work on another. WebPConvert combines these methods by iterating over them (optionally in the desired order) until one of them is successful - or all of them fail.*
47
- Reload the page
48
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
49
50
+ In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-On-Demand" header. It should say Routed to image converter" the first time, but "Routed to existing converted image" on subsequent requests (WebP-Express is based upon WebP On Demand). When routed to image converter, there should also be some headers beginning with "X-WebP-Convert-And-Serve", which reveals information about the conversion.
51
+
52
You can also append `?debug` after any image url, in order to run a conversion, and see the conversion report. Btw: If you append `?reconvert` after an image url, you will force a reconversion of the image.
53
54
+ ### Notes
55
+
56
+ *Note:*
57
+ The redirect rules created in .htaccess are sensitive to the location of your image folder and the location of Wordpress. If you at some point change one of these, the rules will have to be updated. .htaccess rules are updated whenever you change a setting (all configuration is actually stored in .htaccess, which allows the converter to run faster, than if it had the overhead of bootstrapping Wordpress)
58
+
59
+ *Note:*
60
+ 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.
61
+
62
+ *Note:*
63
+ The plugin has not been tested in multisite configurations. It's on the roadmap!
64
+
65
66
## Limitations
67
README.txt CHANGED
@@ -2,9 +2,9 @@
2
Contributors: rosell.dk
3
Donate link: https://www.bitwise-it.dk/contact
4
Tags: webp, images, performance
5
- Requires at least: 4.7.5
6
- Tested up to: 4.9.7
7
- Stable tag: 0.3.0
8
Requires PHP: 5.5
9
License: GPLv3
10
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -15,15 +15,15 @@ Serve autogenerated WebP images instead of jpeg/png to browsers that supports We
15
16
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
17
18
- The approach has the benefit that is works regardless of how an image found its way into your site. The plugin does not need to hook into Media Library events, Gallery events etc, because it does not need to maintain a complete collection of converted images. It makes it so much simpler -- and lighter.
19
20
- The plugin works by .htaccess magic coupled with an image converter. Basically, jpegs and pngs are routed to the image converter, unless the image converter has already converted the image. In that case, it is routed directly to the converted image. The images are saved in a subfolder to the "uploads" folder, preserving the same structure as the originals. In order to allow caching on CDN, the .htaccess rules add a "Vary" HTTP header when serving the WebP images.
21
22
- Note: The rules created in .htaccess are sensitive to the location of your image folder and the location of wordpress. If you at some point change one of these, the rules will have to be updated. .htaccess rules are updated whenever you change a setting (all configuration is actually stored in .htaccess, which allows the converter to run faster, than if it had the overhead of bootstrapping Wordpress)
23
-
24
- Note: 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.
25
-
26
- Note: The plugin has not been tested in multisite configurations. It's on the roadmap!
27
28
29
== Installation ==
@@ -35,8 +35,6 @@ Note: The plugin has not been tested in multisite configurations. It's on the ro
35
36
You configure the plugin in Settings > WebP Express.
37
38
- The "Image types to convert" option is initially set to "Do not convert any images!". This allows you to test that there is a working converter, before redirecting images to the converter.
39
-
40
WebPExpress uses WebPConvert (https://github.com/rosell-dk/webp-convert) to convert images. This is how WebPConvert describes itself:
41
42
"The current state of WebP conversion in PHP is this: There are several ways to do it, but they all require something of the server setup. What works on one shared host might not work on another. WebPConvert combines these methods by iterating over them (optionally in the desired order) until one of them is successful - or all of them fail."
@@ -59,9 +57,22 @@ Note that the plugin does not change any HTML. In the HTML the image src is stil
59
- Reload the page
60
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
61
62
You can also append ?debug after any image url, in order to run a conversion, and see the conversion report.
63
Btw: If you append ?reconvert after an image url, you will force a reconversion of the image.
64
65
== Screenshots ==
66
67
@@ -94,9 +105,20 @@ Putting this question in the "frequently" asked questions section is of course s
94
95
== Changelog ==
96
97
- = 0.3 =
98
- * Now works on LiteSpeed webservers
99
- * Now sends X-WebP-On-Demand headers for easier debugging
100
101
== Roadmap ==
102
2
Contributors: rosell.dk
3
Donate link: https://www.bitwise-it.dk/contact
4
Tags: webp, images, performance
5
+ Requires at least: 4.7
6
+ Tested up to: 4.9
7
+ Stable tag: 0.4.0
8
Requires PHP: 5.5
9
License: GPLv3
10
License URI: https://www.gnu.org/licenses/gpl-3.0.html
15
16
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
17
18
+ The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
19
20
+ The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and some of the ecosystem around it: [WebPConvertAndServe](https://github.com/rosell-dk/webp-convert-and-serve) and [WebPOnDemand](https://github.com/rosell-dk/webp-on-demand)
21
22
+ #### Benefits
23
+ - Much faster load time on images in Chrome browsers. The converted images are typically less than half the size (for jpeg), while maintaining the same quality. Bear in mind that images typically are responsible for most of the bandwidth usage.
24
+ - Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
25
+ - Better ranking in Google searches (performance is taken into account by Google)
26
+ - Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
27
28
29
== Installation ==
35
36
You configure the plugin in Settings > WebP Express.
37
38
WebPExpress uses WebPConvert (https://github.com/rosell-dk/webp-convert) to convert images. This is how WebPConvert describes itself:
39
40
"The current state of WebP conversion in PHP is this: There are several ways to do it, but they all require something of the server setup. What works on one shared host might not work on another. WebPConvert combines these methods by iterating over them (optionally in the desired order) until one of them is successful - or all of them fail."
57
- Reload the page
58
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
59
60
+ In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-On-Demand" header. It should say Routed to image converter" the first time, but "Routed to existing converted image" on subsequent requests (WebP-Express is based upon WebP On Demand). When routed to image converter, there should also be some headers beginning with "X-WebP-Convert-And-Serve", which reveals information about the conversion.
61
+
62
You can also append ?debug after any image url, in order to run a conversion, and see the conversion report.
63
Btw: If you append ?reconvert after an image url, you will force a reconversion of the image.
64
65
+ ### Notes
66
+
67
+ *Note:*
68
+ The redirect rules created in .htaccess are sensitive to the location of your image folder and the location of Wordpress. If you at some point change one of these, the rules will have to be updated. .htaccess rules are updated whenever you change a setting (all configuration is actually stored in .htaccess, which allows the converter to run faster, than if it had the overhead of bootstrapping Wordpress)
69
+
70
+ *Note:*
71
+ 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.
72
+
73
+ *Note:*
74
+ The plugin has not been tested in multisite configurations. It's on the roadmap!
75
+
76
== Screenshots ==
77
78
105
106
== Changelog ==
107
108
+ = 0.4.0 =
109
+ * Fixed bug: .htaccess was not updated every time the settings was saved.
110
+ * Fixed bug: The plugin generated error upon activation.
111
+ * Now produces X-WebP-Convert-And-Serve headers with info about the conversion - useful for validating that converter receives the expected arguments and executes correctly.
112
+ * WebPExpress options are now removed when plugin is uninstalled.
113
+ * No longer generates .htaccess rules on install. The user now has to actively go to Web Express setting and save first
114
+ * Added a "first time" message on options page and a reactivation message
115
+
116
+ For more info, see the closed issues on the github repository: https://github.com/rosell-dk/webp-express/milestone/1?closed=1
117
+
118
+ == Upgrade Notice ==
119
+
120
+ = 0.4.0 =
121
+ This version fixes some misbehaviours and provides new http headers with info about the conversion process.
122
123
== Roadmap ==
124
assets/banner-772x250.jpg ADDED
Binary file
assets/icon-128x128.png ADDED
Binary file
assets/icon-256x256.png ADDED
Binary file
assets/icon.svg ADDED
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ version="1.1"
11
+ width="150"
12
+ height="150"
13
+ id="svg3062"
14
+ xml:space="preserve"><metadata
15
+ id="metadata3068"><rdf:RDF><cc:Work
16
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
17
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
18
+ id="defs3066" /><g
19
+ transform="matrix(1.25,0,0,-1.25,0,150)"
20
+ id="g3070"><g
21
+ id="g3072"><path
22
+ d="M 0,0 120,0 120,120 0,120 0,0 z"
23
+ id="path3074"
24
+ style="fill:#154889;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
25
+ d="m 39.695,22.855 -31.695,0 23.77,74.29 10.648,0 -2.723,-74.29 z m 8.914,0 -2.722,74.29 10.648,0 8.008,-25.036 c 6.035,6.606 13.895,11.528 22.473,14.075 l -9.563,8.027 c -0.875,0.773 -0.535,2.473 0.574,2.844 0.172,0.058 0.352,0.09 0.536,0.09 l 31.761,0 c 1.102,0 1.969,-1.313 1.547,-2.325 L 99.566,65.535 c -0.453,-1.078 -2.171,-1.297 -2.875,-0.363 -0.113,0.144 -0.199,0.305 -0.253,0.476 l -4.727,14.106 c -4.535,-1.649 -8.715,-4.25 -11.859,-7.379 -3.145,-3.129 -5.243,-6.773 -5.95,-10.34 l -0.05,-0.277 C 72.445,54.531 73.543,43.988 76.738,34 l 3.567,-11.145 -31.696,0 z"
26
+ id="path3076"
27
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /></g></g></svg>
assets/screenshot-1.png ADDED
Binary file
changelog.txt ADDED
@@ -0,0 +1,6 @@
1
+ = 0.3.1 =
2
+ * The "Only jpeg" setting wasn't respected in 0.3.0. It now works again
3
+
4
+ = 0.3 =
5
+ * Now works on LiteSpeed webservers
6
+ * Now sends X-WebP-On-Demand headers for easier debugging
convert.php DELETED
@@ -1,38 +0,0 @@
1
- <?php
2
-
3
- //require 'webp-on-demand/vendor/autoload.php';
4
-
5
-
6
- //require 'vendor/webp-convert-and-serve/autoload.php';
7
- require 'vendor/webp-on-demand/autoload.php';
8
-
9
- //echo '<br>done';
10
-
11
- //require '../webp-convert/WebPConvert.php';
12
-
13
-
14
- /*use WebPConvert\WebPConvert;
15
-
16
- $source = __DIR__ . '/test/test.jpg';
17
- $destination = __DIR__ . '/test/test.jpg.webp';
18
-
19
- // .. fire up WebP conversion
20
- $success = WebPConvert::convert($source, $destination, array(
21
- 'quality' => 90,
22
- // more options available!
23
- ));
24
-
25
-
26
- //$status = WebPOnDemand::serve(__DIR__);
27
-
28
- //echo 'hi';
29
- */
30
-
31
-
32
- use WebPOnDemand\WebPOnDemand;
33
-
34
- $status = WebPOnDemand::serve(__DIR__);
35
- if ($status < 0) {
36
- // Conversion failed.
37
- // you could message your application about the problem here...
38
- }
lib/activate.php CHANGED
@@ -5,24 +5,30 @@ include_once( plugin_dir_path( __FILE__ ) . 'helpers.php');
5
class WebPExpressActivate {
6
7
8
- public function activate() {
9
10
update_option( 'webp-express-message-pending', true, false );
11
12
update_option( 'webp-express-just-activated', true, false );
13
14
15
- if ( strpos( strtolower($_SERVER['SERVER_SOFTWARE']), 'microsoft-iis') !== false ) {
16
update_option( 'webp-express-microsoft-iis', true, false );
17
update_option( 'webp-express-deactivate', true, false );
18
return;
19
}
20
21
22
- if ( strpos( strtolower($_SERVER['SERVER_SOFTWARE']), 'litespeed') !== false ) {
23
- update_option( 'webp-express-not-tested-on-litespeed', true, false );
24
- } else if (!( strpos( strtolower($_SERVER['SERVER_SOFTWARE']), 'apache') !== false )) {
25
- update_option( 'webp-express-not-apache', true, false );
26
}
27
28
@@ -52,9 +58,27 @@ class WebPExpressActivate {
52
return;
53
}
54
55
- // Add rules to .htaccess
56
- $rules = WebPExpressHelpers::generateHTAccessRules();
57
- WebPExpressHelpers::insertHTAccessRules($rules);
58
59
60
}
5
class WebPExpressActivate {
6
7
8
+ public static function activate() {
9
10
update_option( 'webp-express-message-pending', true, false );
11
12
update_option( 'webp-express-just-activated', true, false );
13
14
15
+ $server = strtolower($_SERVER['SERVER_SOFTWARE']);
16
+
17
+ $server_is_microsoft_iis = ( strpos( $server, 'microsoft-iis') !== false );
18
+ if ($server_is_microsoft_iis) {
19
update_option( 'webp-express-microsoft-iis', true, false );
20
update_option( 'webp-express-deactivate', true, false );
21
return;
22
}
23
24
25
+ $server_is_litespeed = ( strpos( $server, 'litespeed') !== false );
26
+ $server_is_apache = ( strpos( $server, 'apache') !== false );
27
+
28
+ if ($server_is_litespeed || $server_is_apache) {
29
+ // all is well.
30
+ } else {
31
+ update_option( 'webp-express-not-apache-nor-litespeed', true, false );
32
}
33
34
58
return;
59
}
60
61
+ if (!empty(get_option('webp-express-configured'))) {
62
+
63
+ // The plugin has been reactivated.
64
+ // We must regenerate the .htaccess rules.
65
+ $rules = WebPExpressHelpers::generateHTAccessRules();
66
+ WebPExpressHelpers::insertHTAccessRules($rules);
67
+
68
+ } else {
69
+ // WebP Express has not been configured yet.
70
+
71
+ // Should we perhaps write to .htaccess, in order to determine if there is a permission problem or not ?
72
+ // like this:
73
+ /*
74
+ if (WebPExpressHelpers::doInsertHTAccessRules('# WebP Express has not been configured yet, so here are no rules yet.')) {
75
+
76
+ } else {
77
+ update_option('webp-express-failed-inserting-rules', true, false);
78
+ }*/
79
+
80
+
81
+ }
82
83
84
}
lib/helpers.php CHANGED
@@ -72,10 +72,19 @@ class WebPExpressHelpers
72
73
public static function generateHTAccessRules()
74
{
75
$options = '';
76
- $options .= '&max-quality=' . get_option('webp_express_max_quality');
77
//$options .= '&method=' . get_option('webp_express_method');
78
- $options .= '&fail=' . get_option('webp_express_failure_response');
79
$options .= '&critical-fail=report';
80
81
$converters_and_options = json_decode(get_option('webp_express_converters'), true);
@@ -97,7 +106,7 @@ class WebPExpressHelpers
97
$urls = $urlsAndPaths['urls'];
98
$filePaths = $urlsAndPaths['filePaths'];
99
100
- $imageTypes = get_option('webp_express_image_types_to_convert');
101
$fileExtensions = [];
102
if ($imageTypes & 1) {
103
$fileExtensions[] = 'jpe?g';
@@ -188,7 +197,7 @@ class WebPExpressHelpers
188
" RewriteCond %{QUERY_STRING} (^reconvert.*)|(^debug.*) [OR]\n" .
189
" RewriteCond %{DOCUMENT_ROOT}/" . $basePath . "/" . $destinationRoot . "/$1.$2.webp !-f\n" .
190
" RewriteCond %{QUERY_STRING} (.*)\n" .
191
- " RewriteRule ^\/?(.*)\.(jpe?g|png)$ " . $scriptPath . "/webp-on-demand.php?base-path=" . $basePath . "&destination-root=" . $destinationRoot . "&source=$1.$2" . $options . "&%1 [NC,E=WEBPACCEPT:1,E=WEBPNEW:1]\n" .
192
"</IfModule>\n\n" .
193
194
"<IfModule mod_headers.c>\n" .
@@ -210,7 +219,9 @@ class WebPExpressHelpers
210
return $rules;
211
}
212
213
- private static function doInsertHTAccessRules($rules) {
214
if (!function_exists('get_home_path')) {
215
require_once ABSPATH . 'wp-admin/includes/file.php';
216
}
72
73
public static function generateHTAccessRules()
74
{
75
+ //global $wpdb;
76
+ //$hasWebPExpressOptionBeenSaved = ($wpdb->get_row( "SELECT * FROM $wpdb->options WHERE option_name = 'webp_express_converters'" ) !== null);
77
+ //if (!$hasWebPExpressOptionBeenSaved) {
78
+
79
+ if (empty(get_option('webp-express-configured')) || empty(get_option('webp_express_converters'))) {
80
+ // This should not happen, because generateHTAccessRules should not be called at this stage.
81
+ // But if it did happen anyway, better to exit with a comment than failing totally.
82
+ return '# Cannot generate the htaccess rules yet. - WebP Express has not been configured yet.';
83
+ }
84
$options = '';
85
+ $options .= '&max-quality=' . get_option('webp_express_max_quality', '85');
86
//$options .= '&method=' . get_option('webp_express_method');
87
+ $options .= '&fail=' . get_option('webp_express_failure_response', 'original');
88
$options .= '&critical-fail=report';
89
90
$converters_and_options = json_decode(get_option('webp_express_converters'), true);
106
$urls = $urlsAndPaths['urls'];
107
$filePaths = $urlsAndPaths['filePaths'];
108
109
+ $imageTypes = get_option('webp_express_image_types_to_convert', 1);
110
$fileExtensions = [];
111
if ($imageTypes & 1) {
112
$fileExtensions[] = 'jpe?g';
197
" RewriteCond %{QUERY_STRING} (^reconvert.*)|(^debug.*) [OR]\n" .
198
" RewriteCond %{DOCUMENT_ROOT}/" . $basePath . "/" . $destinationRoot . "/$1.$2.webp !-f\n" .
199
" RewriteCond %{QUERY_STRING} (.*)\n" .
200
+ " RewriteRule ^\/?(.*)\.(" . $fileExt . ")$ " . $scriptPath . "/webp-on-demand.php?base-path=" . $basePath . "&destination-root=" . $destinationRoot . "&source=$1.$2" . $options . "&%1 [NC,E=WEBPACCEPT:1,E=WEBPNEW:1]\n" .
201
"</IfModule>\n\n" .
202
203
"<IfModule mod_headers.c>\n" .
219
return $rules;
220
}
221
222
+ // Insert .htaccess rules.
223
+ // @return (bool) True if successful, false if not.
224
+ public static function doInsertHTAccessRules($rules) {
225
if (!function_exists('get_home_path')) {
226
require_once ABSPATH . 'wp-admin/includes/file.php';
227
}
lib/message.php CHANGED
@@ -30,7 +30,6 @@ add_action( 'admin_notices', function() {
30
if ( get_option( 'webp-express-just-activated' ) ) {
31
delete_option( 'webp-express-just-activated');
32
33
-
34
if ( get_option( 'webp-express-microsoft-iis' ) ) {
35
delete_option( 'webp-express-microsoft-iis');
36
printf(
@@ -39,25 +38,14 @@ add_action( 'admin_notices', function() {
39
esc_html( __( 'You are on Microsof IIS server. The plugin does not work on IIS', 'webp-express' ) )
40
);
41
return;
42
- }
43
- else if ( get_option( 'webp-express-not-apache' ) ) {
44
- delete_option( 'webp-express-not-apache');
45
printf(
46
'<div class="%1$s"><p>%2$s</p></div>',
47
esc_attr( 'notice notice-warning is-dismissible' ),
48
- esc_html( __( 'You are not on Apache server. WebP Express has only been tested on Apache - continue at own risk (but please tell me if it works!). Your server is: ' . $_SERVER['SERVER_SOFTWARE'], 'webp-express' ) )
49
);
50
}
51
- if ( get_option( 'webp-express-not-tested-on-litespeed' ) ) {
52
- delete_option( 'webp-express-not-tested-on-litespeed');
53
- printf(
54
- '<div class="%1$s"><p>%2$s</p></div>',
55
- esc_attr( 'notice notice-warning is-dismissible' ),
56
- esc_html( __( 'You are on LiteSpeed server. WebP Express has only been tested sporadic on LiteSpeed... Continue at own risk', 'webp-express' ) )
57
- );
58
- return;
59
- }
60
-
61
62
if ( get_option( 'webp-express-no-multisite' ) ) {
63
delete_option( 'webp-express-no-multisite');
@@ -122,17 +110,19 @@ add_action( 'admin_notices', function() {
122
return;
123
}
124
125
- printf(
126
- '<div class="%1$s"><p>%2$s</p></div>',
127
- esc_attr( 'notice notice-info is-dismissible' ),
128
- 'WebP Express was installed successfully. <a href="options-general.php?page=webp_express_settings_page">Configure it here</a>.'
129
- );
130
-
131
- printf(
132
- '<div class="%1$s"><p>%2$s</p></div>',
133
- esc_attr( 'notice notice-info is-dismissible' ),
134
- esc_html( __( 'If you at some point change the upload directory or move Wordpress, you will have to disable and reenable WebPExpress', 'webp-express' ) )
135
- );
136
}
137
});
138
30
if ( get_option( 'webp-express-just-activated' ) ) {
31
delete_option( 'webp-express-just-activated');
32
33
if ( get_option( 'webp-express-microsoft-iis' ) ) {
34
delete_option( 'webp-express-microsoft-iis');
35
printf(
38
esc_html( __( 'You are on Microsof IIS server. The plugin does not work on IIS', 'webp-express' ) )
39
);
40
return;
41
+ } else if ( get_option( 'webp-express-not-apache-nor-litespeed' ) ) {
42
+ delete_option( 'webp-express-not-apache-nor-litespeed');
43
printf(
44
'<div class="%1$s"><p>%2$s</p></div>',
45
esc_attr( 'notice notice-warning is-dismissible' ),
46
+ esc_html( __( 'You are not on Apache server, nor on LiteSpeed. WebP Express has only been tested on Apache and LiteSpeed - continue at own risk (but please tell me if it works!). Your server is: ' . $_SERVER['SERVER_SOFTWARE'], 'webp-express' ) )
47
);
48
}
49
50
if ( get_option( 'webp-express-no-multisite' ) ) {
51
delete_option( 'webp-express-no-multisite');
110
return;
111
}
112
113
+ if (empty(get_option('webp-express-configured'))) {
114
+ printf(
115
+ '<div class="%1$s"><p>%2$s</p></div>',
116
+ esc_attr( 'notice notice-info is-dismissible' ),
117
+ 'WebP Express was installed successfully. To start using it, you must <a href="options-general.php?page=webp_express_settings_page">configure it here</a>.'
118
+ );
119
+ } else {
120
+ printf(
121
+ '<div class="%1$s"><p>%2$s</p></div>',
122
+ esc_attr( 'notice notice-info is-dismissible' ),
123
+ 'WebP Express reactivated successfully.<br>The image redirections should be in effect again (you should see a "WebP Express updated .htaccess" message above this...)<br><br>Just a quick reminder: If you at some point change the upload directory or move Wordpress, you will have to regenerate the .htaccess.<br>You do that by changing the configuration <a href="options-general.php?page=webp_express_settings_page">(here)</a>'
124
+ );
125
+ }
126
}
127
});
128
lib/options.php CHANGED
@@ -6,6 +6,14 @@
6
7
include_once 'helpers.php';
8
9
add_action('admin_enqueue_scripts', function () {
10
// https://github.com/RubaXa/Sortable
11
@@ -46,11 +54,6 @@ add_action('admin_init', 'webp_express_option_group_init');
46
47
function webp_express_option_group_init()
48
{
49
- /*
50
- register_setting(
51
- 'webp_express_option_group', // A settings group name. Must exist prior to the register_setting call. This must match the group name in settings_fields()
52
- 'webp_express_options' //The name of an option to sanitize and save.
53
- );*/
54
register_setting(
55
'webp_express_option_group', // A settings group name. Must exist prior to the register_setting call. This must match the group name in settings_fields()
56
'webp_express_max_quality', //The name of an option to sanitize and save.
@@ -65,7 +68,7 @@ function webp_express_option_group_init()
65
'webp_express_image_types_to_convert',
66
[
67
'type' => 'integer',
68
- 'default' => '3',
69
'sanitize_callback' => 'sanitize_text_field',
70
]
71
);
@@ -173,14 +176,30 @@ function webp_express_settings_page_content()
173
<div class="wrap">
174
<h2>WebP Express Settings</h2>
175
176
<form action="options.php" method="post">
177
<?php
178
settings_fields('webp_express_option_group');
179
do_settings_sections('webp_express_settings_page');
180
181
182
//echo '<pre>' . print_r(WebPExpressHelpers::calculateUrlsAndPaths(), true) . '</pre>';
183
-
184
$localConverters = ['cwebp', 'imagick', 'gd'];
185
186
/*
@@ -251,10 +270,12 @@ http://php.net/manual/en/function.set-include-path.php
251
<div class="cwebp converter-options">
252
<h3>cwebp</h3>
253
<div class="info">
254
- cwebp works by executing the cwebp binary from Google. This should be your first choice.
255
- Its best in terms of quality, speed and options. The only catch is that it requires the exec function to be enabled,
256
- and that the webserver user is allowed to execute the cwebp binary (either at known system locations, or one of the precompiled binaries,
257
- that comes with this library). If you are on a shared host that doesn't allow that, the second best choice would probably be the wpc cloud converter.
258
</div>
259
<h3>cweb options</h3>
260
<div>
@@ -313,10 +334,12 @@ http://php.net/manual/en/function.set-include-path.php
313
<div class="ewww converter-options">
314
<h3>Ewww</h3>
315
<p>
316
- <a href="https://ewww.io/" target="_blank">ewww</a> is a cloud service. It is a decent alternative for those who don't have the technical know-how to install wpc.
317
ewww is using cwebp to do the conversion, so quality is great.
318
- ewww however only provides one conversion option (quality), and it is not free.
319
- But very cheap. Like in almost free.
320
</p>
321
<h3>Ewww options</h3>
322
<div>
@@ -404,22 +427,31 @@ http://php.net/manual/en/function.set-include-path.php
404
<?php
405
}
406
407
- add_action('updated_option', function($option_name, $old_value, $value) {
408
- switch ($option_name) {
409
- case 'webp_express_max_quality':
410
- //case 'webp_express_method':
411
- case 'webp_express_converters':
412
- case 'webp_express_image_types_to_convert':
413
- case 'webp_express_failure_response':
414
- //update_option('webp-express-htaccess-needs-updating', true, false);
415
-
416
- $rules = WebPExpressHelpers::generateHTAccessRules();
417
- WebPExpressHelpers::insertHTAccessRules($rules);
418
-
419
- break;
420
}
421
}, 10, 3);
422
423
424
425
//End webp_express_settings_page_content
6
7
include_once 'helpers.php';
8
9
+ /*
10
+ These lines should enable us to know whether quality can be detected.
11
+ But needs testing...
12
+ require WEBPEXPRESS_PLUGIN_DIR . '/vendor/require-webp-convert.php';
13
+ $detectedQualityOfTestJpg = \WebPConvert\Converters\ConverterHelper::detectQualityOfJpg(WEBPEXPRESS_PLUGIN_DIR . '/test/focus.jpg');
14
+ $canDetectQualityOfJpegs = ($detectedQualityOfTestJpg == 100);
15
+ */
16
+
17
add_action('admin_enqueue_scripts', function () {
18
// https://github.com/RubaXa/Sortable
19
54
55
function webp_express_option_group_init()
56
{
57
register_setting(
58
'webp_express_option_group', // A settings group name. Must exist prior to the register_setting call. This must match the group name in settings_fields()
59
'webp_express_max_quality', //The name of an option to sanitize and save.
68
'webp_express_image_types_to_convert',
69
[
70
'type' => 'integer',
71
+ 'default' => '1',
72
'sanitize_callback' => 'sanitize_text_field',
73
]
74
);
176
<div class="wrap">
177
<h2>WebP Express Settings</h2>
178
179
+ <?php
180
+
181
+ global $wpdb;
182
+ //$hasWebPExpressOptionBeenSaved = ($wpdb->get_row( "SELECT * FROM $wpdb->options WHERE option_name = 'webp_express_converters'" ) !== null);
183
+ //if (!$hasWebPExpressOptionBeenSaved) {
184
+ if (empty(get_option('webp-express-configured'))) {
185
+ echo '<div style="background-color: #cfc; padding: 20px; border: 1px solid #ccc">';
186
+ echo '<h3>Welcome!<h3>';
187
+ echo '<p>The rewrite rules are not active yet. They will be activated the first time you click the "Save settings" button.</p>';
188
+ echo '<p>Before you do that, I suggest you find out which converters that works. Start from the top. Click "test" next to a converter to test it. Try also clicking the "configure" buttons</p>';
189
+ echo '</div>';
190
+ }
191
+
192
+ global $wpdb;
193
+ $results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}options WHERE option_id = 1", OBJECT );
194
+ ?>
195
<form action="options.php" method="post">
196
<?php
197
settings_fields('webp_express_option_group');
198
do_settings_sections('webp_express_settings_page');
199
200
+ //print_r(get_option('plugin_error'));
201
202
//echo '<pre>' . print_r(WebPExpressHelpers::calculateUrlsAndPaths(), true) . '</pre>';
203
$localConverters = ['cwebp', 'imagick', 'gd'];
204
205
/*
270
<div class="cwebp converter-options">
271
<h3>cwebp</h3>
272
<div class="info">
273
+ cwebp works by executing the cwebp binary from Google. This should normally be your first choice.
274
+ Its best in terms of quality, speed and options.
275
+ The only catch is that it requires the exec function to be enabled, and that the webserver user is
276
+ allowed to execute the cwebp binary (either at known system locations, or one of the precompiled binaries,
277
+ that comes with this library).
278
+ If you are on a shared host that doesn't allow that, the second best choice would probably be the wpc cloud converter.
279
</div>
280
<h3>cweb options</h3>
281
<div>
334
<div class="ewww converter-options">
335
<h3>Ewww</h3>
336
<p>
337
+ <a href="https://ewww.io/" target="_blank">ewww</a> is a cloud service.
338
+ It is a decent alternative for those who don't have the technical know-how to install wpc.
339
ewww is using cwebp to do the conversion, so quality is great.
340
+ ewww however only provides one conversion option (quality), and it does not support "auto"
341
+ quality (yet - I have requested the feature and the maintainer are considering it).
342
+ Also, it is not free. But very cheap. Like in almost free.
343
</p>
344
<h3>Ewww options</h3>
345
<div>
427
<?php
428
}
429
430
+ // This hook is invoked when a option is changed away from default value
431
+ add_action('added_option', function($option_name, $value) {
432
+
433
+ // Notice that we use underscore in "webp_express" for the configuration, but dash for other options (such as messages and state)
434
+ if (strpos($option_name, 'webp_express') === 0) {
435
+
436
+ // Store the fact that webp options has been changed.
437
+ // When nobody is using 0.3 or below, we can test on the existence of that option, instead of
438
+ // querying the database directly ($hasWebPExpressOptionBeenSaved)
439
+ add_option('webp-express-configured', true);
440
+
441
+ $rules = WebPExpressHelpers::generateHTAccessRules();
442
+ WebPExpressHelpers::insertHTAccessRules($rules);
443
}
444
}, 10, 3);
445
446
+ // This hook is invoked when a option is changed (but not when the old value is the same as its default value)
447
+ add_action('updated_option', function($option_name, $old_value, $value) {
448
+
449
+ // Notice that we use underscore in "webp_express" for the configuration, but dash for other options (such as messages and state)
450
+ if (strpos($option_name, 'webp_express') === 0) {
451
+ $rules = WebPExpressHelpers::generateHTAccessRules();
452
+ WebPExpressHelpers::insertHTAccessRules($rules);
453
+ }
454
+ }, 10, 3);
455
456
457
//End webp_express_settings_page_content
test-run.php CHANGED
@@ -4,7 +4,13 @@
4
5
6
//require 'vendor/webp-convert-and-serve/autoload.php';
7
- require 'vendor/webp-convert/autoload.php';
8
9
//use WebPConvertAndServe\WebPConvertAndServe;
10
use WebPConvert\WebPConvert;
4
5
6
//require 'vendor/webp-convert-and-serve/autoload.php';
7
+ //require 'vendor/webp-convert/autoload.php';
8
+
9
+ error_reporting(E_ALL);
10
+ ini_set("display_errors", 1);
11
+
12
+ //require 'vendor/webp-convert/require-all.inc';
13
+ require 'vendor/require-webp-convert.php';
14
15
//use WebPConvertAndServe\WebPConvertAndServe;
16
use WebPConvert\WebPConvert;
vendor/require-webp-convert-and-serve.php ADDED
@@ -0,0 +1,4 @@
1
+ <?php
2
+ require_once(__DIR__ . "/webp-convert-and-serve/../require-webp-convert.php");
3
+ require_once(__DIR__ . "/webp-convert-and-serve/BufferLogger.php");
4
+ require_once(__DIR__ . "/webp-convert-and-serve/WebPConvertAndServe.php");
vendor/require-webp-convert.php ADDED
@@ -0,0 +1,20 @@
1
+ <?php
2
+ require_once(__DIR__ . "/webp-convert/Exceptions/WebPConvertBaseException.php");
3
+ require_once(__DIR__ . "/webp-convert/Loggers/BaseLogger.php");
4
+ require_once(__DIR__ . "/webp-convert/WebPConvert.php");
5
+ require_once(__DIR__ . "/webp-convert/Converters/ConverterHelper.php");
6
+ require_once(__DIR__ . "/webp-convert/Converters/Cwebp.php");
7
+ require_once(__DIR__ . "/webp-convert/Converters/Ewww.php");
8
+ require_once(__DIR__ . "/webp-convert/Converters/Gd.php");
9
+ require_once(__DIR__ . "/webp-convert/Converters/Imagick.php");
10
+ require_once(__DIR__ . "/webp-convert/Converters/Wpc.php");
11
+ require_once(__DIR__ . "/webp-convert/Exceptions/ConverterNotFoundException.php");
12
+ require_once(__DIR__ . "/webp-convert/Exceptions/CreateDestinationFileException.php");
13
+ require_once(__DIR__ . "/webp-convert/Exceptions/CreateDestinationFolderException.php");
14
+ require_once(__DIR__ . "/webp-convert/Exceptions/InvalidFileExtensionException.php");
15
+ require_once(__DIR__ . "/webp-convert/Exceptions/TargetNotFoundException.php");
16
+ require_once(__DIR__ . "/webp-convert/Converters/Exceptions/ConversionDeclinedException.php");
17
+ require_once(__DIR__ . "/webp-convert/Converters/Exceptions/ConverterFailedException.php");
18
+ require_once(__DIR__ . "/webp-convert/Converters/Exceptions/ConverterNotOperationalException.php");
19
+ require_once(__DIR__ . "/webp-convert/Loggers/EchoLogger.php");
20
+ require_once(__DIR__ . "/webp-convert/Loggers/VoidLogger.php");
vendor/require-webp-on-demand.php ADDED
@@ -0,0 +1,3 @@
1
+ <?php
2
+ require_once(__DIR__ . "/webp-on-demand/../require-webp-convert-and-serve.php");
3
+ require_once(__DIR__ . "/webp-on-demand/WebPOnDemand.php");
vendor/webp-convert-and-serve/BufferLogger.php ADDED
@@ -0,0 +1,57 @@
1
+ <?php
2
+
3
+ namespace WebPConvertAndServe;
4
+ use WebPConvert\Loggers\BaseLogger;
5
+
6
+ class BufferLogger extends BaseLogger
7
+ {
8
+ public $entries = array();
9
+
10
+ public function log($msg, $style = '')
11
+ {
12
+ $this->entries[] = [$msg, $style];
13
+ }
14
+
15
+ public function ln()
16
+ {
17
+ $this->entries[] = '';
18
+ }
19
+
20
+ public function getHtml()
21
+ {
22
+ $html = '';
23
+ foreach ($this->entries as $entry) {
24
+ if ($entry == '') {
25
+ $html .= '<br>';
26
+ } else {
27
+ list($msg, $style) = $entry;
28
+
29
+ if ($style == 'bold') {
30
+ $html .= '<b>' . $msg . '</b>';
31
+ } elseif ($style == 'italic') {
32
+ $html .= '<i>' . $msg . '</i>';
33
+ } else {
34
+ $html .= $msg;
35
+ }
36
+ }
37
+ }
38
+ return $html;
39
+ }
40
+
41
+ public function getText($newLineChar = ' ')
42
+ {
43
+ $text = '';
44
+ foreach ($this->entries as $entry) {
45
+ if ($entry == '') {
46
+ if (substr($text, -2) != '. ') {
47
+ $text .= '. ';
48
+ }
49
+ } else {
50
+ list($msg, $style) = $entry;
51
+ $text .= $msg;
52
+ }
53
+ }
54
+
55
+ return $text;
56
+ }
57
+ }
vendor/webp-convert-and-serve/WebPConvertAndServe.php CHANGED
@@ -2,7 +2,7 @@
2
namespace WebPConvertAndServe;
3
4
use WebPConvert\WebPConvert;
5
- use WebPConvertAndServe\PathHelper;
6
use WebPConvert\Converters\ConverterHelper;
7
//use WebPConvert\Loggers\EchoLogger;
8
@@ -61,41 +61,95 @@ class WebPConvertAndServe
61
62
public static function convertAndServeImage($source, $destination, $options, $failAction, $criticalFailAction, $debug = false)
63
{
64
- /*
65
if ($debug) {
66
error_reporting(E_ALL);
67
ini_set('display_errors', 'On');
68
} else {
69
ini_set('display_errors', 'Off');
70
- }*/
71
72
$criticalFail = false;
73
74
$success = false;
75
76
- $echoLogger = null;
77
- if (class_exists('WebPConvert\Loggers\EchoLogger')) {
78
- $echoLogger = new \WebPConvert\Loggers\EchoLogger();
79
- }
80
81
- ob_start();
82
try {
83
- $success = WebPConvert::convert($source, $destination, $options, $echoLogger);
84
85
- if (!$success) {
86
$msg = 'No converters are operational';
87
}
88
} catch (\WebPConvert\Exceptions\InvalidFileExtensionException $e) {
89
$criticalFail = true;
90
$msg = $e->getMessage();
91
} catch (\WebPConvert\Exceptions\TargetNotFoundException $e) {
92
$criticalFail = true;
93
$msg = $e->getMessage();
94
} catch (\Exception $e) {
95
$msg = $e->getMessage();
96
}
97
- $conversionInsights = ob_get_contents();
98
- ob_end_clean();
99
100
if ($success) {
101
header('Content-type: image/webp');
@@ -114,29 +168,25 @@ class WebPConvertAndServe
114
self::serve404();
115
break;
116
case WebPConvertAndServe::$REPORT_AS_IMAGE:
117
- self::serveErrorMessageImage($msg);
118
break;
119
case WebPConvertAndServe::$REPORT:
120
- echo '<h1>' . $msg . '</h1>';
121
- if ($echoLogger) {
122
- echo '<p>This is how conversion process went:</p>' . $conversionInsights;
123
- }
124
break;
125
}
126
return $action;
127
}
128
}
129
130
- public static function convertAndReport($source, $destination, $options)
131
{
132
- echo '<html><style>td {vertical-align: top} table {color: #666}</style>';
133
- echo '<body><table>';
134
- echo '<tr><td><i>source:</i></td><td>' . $source . '</td></tr>';
135
- echo '<tr><td><i>destination:</i></td><td>' . $destination . '<td></tr>';
136
137
- // Take care of not displaing sensitive converter options.
138
- // (psst: the is_callable check is needed in order to work with WebPConvert v1.0)
139
140
if (is_callable('ConverterHelper', 'getClassNameOfConverter')) {
141
142
$printable_options = $options;
@@ -159,23 +209,31 @@ class WebPConvertAndServe
159
}
160
}
161
}
162
- echo '<tr><td><i>options:</i></td><td>' . print_r($printable_options, true) . '</td></tr>';
163
}
164
echo '</table>';
165
166
// TODO:
167
// We could display warning if unknown options are set
168
// but that requires that WebPConvert also describes its general options
169
170
-
171
-
172
echo '<br>';
173
174
try {
175
- $echoLogger = null;
176
- if (class_exists('WebPConvert\Loggers\EchoLogger')) {
177
- $echoLogger = new \WebPConvert\Loggers\EchoLogger();
178
- }
179
$success = WebPConvert::convert($source, $destination, $options, $echoLogger);
180
} catch (\Exception $e) {
181
$success = false;
2
namespace WebPConvertAndServe;
3
4
use WebPConvert\WebPConvert;
5
+ use WebPConvertAndServe\BufferLogger;
6
use WebPConvert\Converters\ConverterHelper;
7
//use WebPConvert\Loggers\EchoLogger;
8
61
62
public static function convertAndServeImage($source, $destination, $options, $failAction, $criticalFailAction, $debug = false)
63
{
64
if ($debug) {
65
error_reporting(E_ALL);
66
ini_set('display_errors', 'On');
67
} else {
68
ini_set('display_errors', 'Off');
69
+ }
70
71
$criticalFail = false;
72
73
$success = false;
74
75
+ $bufferLogger = new BufferLogger();
76
77
try {
78
+ $success = WebPConvert::convert($source, $destination, $options, $bufferLogger);
79
80
+ if ($success) {
81
+ $status = 'Success';
82
+ $msg = 'Success';
83
+ } else {
84
+ $status = 'Failure (no converters are operational)';
85
$msg = 'No converters are operational';
86
}
87
} catch (\WebPConvert\Exceptions\InvalidFileExtensionException $e) {
88
$criticalFail = true;
89
+ $status = 'Failure (invalid file extension)';
90
$msg = $e->getMessage();
91
} catch (\WebPConvert\Exceptions\TargetNotFoundException $e) {
92
$criticalFail = true;
93
+ $status = 'Failure (target file not found)';
94
+ $msg = $e->getMessage();
95
+ } catch (\WebPConvert\Converters\Exceptions\ConverterFailedException $e) {
96
+ // No converters could convert the image. At least one converter failed, even though it appears to be operational
97
+ $status = 'Failure (no converters could convert the image)';
98
+ $msg = $e->getMessage();
99
+ } catch (\WebPConvert\Converters\Exceptions\ConversionDeclinedException $e) {
100
+ // (no converters could convert the image. At least one converter declined
101
+ $status = 'Failure (no converters could/wanted to convert the image)';
102
+ $msg = $e->getMessage();
103
+ } catch (\WebPConvert\Exceptions\ConverterNotFoundException $e) {
104
+ $status = 'Failure (a converter was not found!)';
105
+ $msg = $e->getMessage();
106
+ } catch (\WebPConvert\Exceptions\CreateDestinationFileException $e) {
107
+ $status = 'Failure (cannot create destination file)';
108
+ $msg = $e->getMessage();
109
+ } catch (\WebPConvert\Exceptions\CreateDestinationFolderException $e) {
110
+ $status = 'Failure (cannot create destination folder)';
111
$msg = $e->getMessage();
112
} catch (\Exception $e) {
113
+ $status = 'Failure (an unanticipated exception was thrown)';
114
$msg = $e->getMessage();
115
}
116
+
117
+ $optionsForPrint = [];
118
+ foreach (self::getPrintableOptions($options) as $optionName => $optionValue) {
119
+ if ($optionName == 'converters') {
120
+ $converterNames = [];
121
+ $extraConvertOptions = [];
122
+ foreach ($optionValue as $converter) {
123
+ if (is_array($converter)) {
124
+ $converterNames[] = $converter['converter'];
125
+ if (isset($converter['options'])) {
126
+ $extraConvertOptions[$converter['converter']] = $converter['options'];
127
+ }
128
+ } else {
129
+ $converterNames[] = $converter;
130
+ }
131
+ }
132
+ $optionsForPrint[] = 'converters:' . implode(',', $converterNames);
133
+ foreach ($extraConvertOptions as $converter => $extraOptions) {
134
+ $opt = [];
135
+ foreach ($extraOptions as $oName => $oValue) {
136
+ $opt[] = $oName . ':"' . $oValue . '"';
137
+ }
138
+ $optionsForPrint[] = $converter . ' options:(' . implode($opt, ', ') . ')';
139
+ }
140
+ } else {
141
+ $optionsForPrint[] = $optionName . ':' . $optionValue ;
142
+ }
143
+
144
+ }
145
+
146
+ header('X-WebP-Convert-And-Serve-Options:' . implode('. ', $optionsForPrint));
147
+
148
+ header('X-WebP-Convert-And-Serve-Status: ' . $status);
149
+
150
+ // Next line is commented out, because we need to be absolute sure that the details does not violate header syntax
151
+ // We could either try to filter it, or we could change WebPConvert, such that it only provides safe texts.
152
+ // header('X-WebP-Convert-And-Serve-Details: ' . $bufferLogger->getText());
153
154
if ($success) {
155
header('Content-type: image/webp');
168
self::serve404();
169
break;
170
case WebPConvertAndServe::$REPORT_AS_IMAGE:
171
+ self::serveErrorMessageImage($status . '. ' . $msg);
172
break;
173
case WebPConvertAndServe::$REPORT:
174
+ echo '<h1>' . $status . '</h1>';
175
+ echo $msg;
176
+ echo '<p>This is how conversion process went:</p>' . $bufferLogger->getHtml();
177
break;
178
}
179
return $action;
180
}
181
}
182
183
+ /* Hides sensitive options */
184
+ private static function getPrintableOptions($options)
185
{
186
187
+ $printable_options = [];
188
189
+ // (psst: the is_callable check is needed in order to work with WebPConvert v1.0)
190
if (is_callable('ConverterHelper', 'getClassNameOfConverter')) {
191
192
$printable_options = $options;
209
}
210
}
211
}
212
}
213
+ return $printable_options;
214
+ }
215
+
216
+ public static function convertAndReport($source, $destination, $options)
217
+ {
218
+ error_reporting(E_ALL);
219
+ ini_set('display_errors', 'On');
220
+
221
+ echo '<html><style>td {vertical-align: top} table {color: #666}</style>';
222
+ echo '<body><table>';
223
+ echo '<tr><td><i>source:</i></td><td>' . $source . '</td></tr>';
224
+ echo '<tr><td><i>destination:</i></td><td>' . $destination . '<td></tr>';
225
+
226
+ echo '<tr><td><i>options:</i></td><td>' . print_r(self::getPrintableOptions($options), true) . '</td></tr>';
227
echo '</table>';
228
229
// TODO:
230
// We could display warning if unknown options are set
231
// but that requires that WebPConvert also describes its general options
232
233
echo '<br>';
234
235
try {
236
+ $echoLogger = new \WebPConvert\Loggers\EchoLogger();
237
$success = WebPConvert::convert($source, $destination, $options, $echoLogger);
238
} catch (\Exception $e) {
239
$success = false;
vendor/webp-convert-and-serve/autoload.php DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
-
3
- function autoloadWebPConvertAndServe()
4
- {
5
- $dirsToAutoload = [
6
- '../webp-convert',
7
- '.',
8
- ];
9
- foreach ($dirsToAutoload as $dir) {
10
- $dirAbs = __DIR__ . '/' . $dir;
11
-
12
- // If directory has its own autoload.php, use that (but ignore autoload in current folder)
13
- if ((file_exists($dirAbs . '/autoload.php') && ($dir != '.'))) {
14
- require_once($dirAbs . '/autoload.php');
15
- } else {
16
- $files = glob($dirAbs . '/*.php');
17
- foreach ($files as $file) {
18
- // only require files that begins with uppercase (A-Z)
19
- if (preg_match('/\/[A-Z][a-zA-Z]*\.php/', $file)) {
20
- require_once($file);
21
- }
22
- }
23
- }
24
- }
25
- }
26
- autoloadWebPConvertAndServe();
vendor/webp-convert/Converters/Binaries/test DELETED
File without changes
vendor/webp-convert/Converters/ConverterHelper.php CHANGED
@@ -97,7 +97,7 @@ class ConverterHelper
97
98
// The required function is available as from PECL imagick v2.2.2
99
if (method_exists($img, 'getImageCompressionQuality')) {
100
- return $img->getImageCompressionQuality();
101
}
102
}
103
97
98
// The required function is available as from PECL imagick v2.2.2
99
if (method_exists($img, 'getImageCompressionQuality')) {
100
+ return $img->getImageCompressionQuality();
101
}
102
}
103
vendor/webp-convert/Converters/Cwebp.php CHANGED
@@ -41,13 +41,19 @@ class Cwebp
41
42
private static function escapeFilename($string)
43
{
44
- // Escaping whitespaces & quotes
45
$string = preg_replace('/\s/', '\\ ', $string);
46
- $string = filter_var($string, FILTER_SANITIZE_MAGIC_QUOTES);
47
48
- // Stripping control characters
49
- // see https://stackoverflow.com/questions/12769462/filter-flag-strip-low-vs-filter-flag-strip-high
50
- $string = filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
51
52
return $string;
53
}
@@ -197,25 +203,32 @@ class Cwebp
197
// The file should exist, but may have been removed manually.
198
if (file_exists($binaryFile)) {
199
// File exists, now generate its hash
200
- $binaryHash = hash_file('sha256', $binaryFile);
201
202
- // Throw an exception if binary file checksum & deposited checksum do not match
203
- if ($binaryHash != $hash) {
204
- //throw new ConverterNotOperationalException('Binary checksum is invalid.');
205
- $errorMsg .= 'Binary checksum of supplied binary is invalid! Did you transfer with FTP, but not in binary mode? File:' . $binaryFile . '. Expected checksum: ' . $hash . ' Actual checksum:' . $binaryHash . '. ';
206
- } else {
207
$returnCode = self::executeBinary($binaryFile, $commandOptions, $useNice, $logger);
208
if ($returnCode == 0) {
209
$success = true;
210
} else {
211
$errorMsg .= 'Tried executing supplied binary (' . $binaryFile . '), but that failed too: ';
212
switch ($returnCode) {
213
- case 126:
214
- $errorMsg .= 'Permission denied (user "' . trim(shell_exec('whoami')) . '" does not have permission to execute the binary)';
215
- break;
216
- default:
217
- $errorMsg .= 'Fail code: ' . $returnCode;
218
- }
219
}
220
}
221
} else {
41
42
private static function escapeFilename($string)
43
{
44
+ // Escaping whitespace
45
$string = preg_replace('/\s/', '\\ ', $string);
46
47
+ // filter_var() is should normally be available, but it is not always
48
+ // - https://stackoverflow.com/questions/11735538/call-to-undefined-function-filter-var
49
+ if (function_exists('filter_var')) {
50
+ // Sanitize quotes
51
+ $string = filter_var($string, FILTER_SANITIZE_MAGIC_QUOTES);
52
+
53
+ // Stripping control characters
54
+ // see https://stackoverflow.com/questions/12769462/filter-flag-strip-low-vs-filter-flag-strip-high
55
+ $string = filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
56
+ }
57
58
return $string;
59
}
203
// The file should exist, but may have been removed manually.
204
if (file_exists($binaryFile)) {
205
// File exists, now generate its hash
206
207
+ // hash_file() is normally available, but it is not always
208
+ // - https://stackoverflow.com/questions/17382712/php-5-3-20-undefined-function-hash
209
+ // If available, validate that hash is correct.
210
+ $proceedAfterHashCheck = true;
211
+ if (function_exists('hash_file')) {
212
+ $binaryHash = hash_file('sha256', $binaryFile);
213
+
214
+ if ($binaryHash != $hash) {
215
+ $errorMsg .= 'Binary checksum of supplied binary is invalid! Did you transfer with FTP, but not in binary mode? File:' . $binaryFile . '. Expected checksum: ' . $hash . ' Actual checksum:' . $binaryHash . '. ';
216
+ $proceedAfterHashCheck = false;
217
+ }
218
+ }
219
+ if ($proceedAfterHashCheck) {
220
$returnCode = self::executeBinary($binaryFile, $commandOptions, $useNice, $logger);
221
if ($returnCode == 0) {
222
$success = true;
223
} else {
224
$errorMsg .= 'Tried executing supplied binary (' . $binaryFile . '), but that failed too: ';
225
switch ($returnCode) {
226
+ case 126:
227
+ $errorMsg .= 'Permission denied (user "' . trim(shell_exec('whoami')) . '" does not have permission to execute the binary)';
228
+ break;
229
+ default:
230
+ $errorMsg .= 'Fail code: ' . $returnCode;
231
+ }
232
}
233
}
234
} else {
vendor/webp-convert/Converters/Wpc.php CHANGED
@@ -44,8 +44,19 @@ class Wpc
44
throw new ConverterNotOperationalException('Required url_init() function is not available.');
45
}
46
47
if (!function_exists('curl_file_create')) {
48
- throw new ConverterNotOperationalException('Required curl_file_create() function is not available (requires PHP > 5.5).');
49
}
50
51
// Got some code here:
@@ -86,20 +97,45 @@ class Wpc
86
]);
87
88
$response = curl_exec($ch);
89
-
90
if (curl_errno($ch)) {
91
- throw new ConverterNotOperationalException(curl_error($ch));
92
}
93
94
// The WPC cloud service either returns an image or an error message
95
// Images has application/octet-stream.
96
-
97
- // TODO: Check for 404 response, and handle that here
98
-
99
// Verify that we got an image back.
100
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
101
curl_close($ch);
102
- throw new ConverterFailedException($response);
103
//throw new ConverterNotOperationalException($response);
104
}
105
44
throw new ConverterNotOperationalException('Required url_init() function is not available.');
45
}
46
47
+
48
if (!function_exists('curl_file_create')) {
49
+ throw new ConverterNotOperationalException('Required curl_file_create() PHP function is not available (requires PHP > 5.5).');
50
+ }
51
+
52
+ if (!empty($options['secret'])) {
53
+ // if secret is set, we need md5() and md5_file() functions
54
+ if (!function_exists('md5')) {
55
+ throw new ConverterNotOperationalException('A secret has been set, which requires us to create a md5 hash from the secret and the file contents. But the required md5() PHP function is not available.');
56
+ }
57
+ if (!function_exists('md5_file')) {
58
+ throw new ConverterNotOperationalException('A secret has been set, which requires us to create a md5 hash from the secret and the file contents. But the required md5_file() PHP function is not available.');
59
+ }
60
}
61
62
// Got some code here:
97
]);
98
99
$response = curl_exec($ch);
100
if (curl_errno($ch)) {
101
+ throw new ConverterNotOperationalException('Curl error:' . curl_error($ch));
102
+ }
103
+
104
+ // Check if we got a 404
105
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
106
+ if ($httpCode == 404) {
107
+ curl_close($ch);
108
+ throw new ConverterFailedException('WPC was not found and the specified URL - we got a 404 response.');
109
}
110
111
// The WPC cloud service either returns an image or an error message
112
// Images has application/octet-stream.
113
// Verify that we got an image back.
114
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
115
curl_close($ch);
116
+
117
+ if (substr($response, 0, 1) == '{') {
118
+ $responseObj = json_decode($response, true);
119
+ if (isset($responseObj['errorCode'])) {
120
+ switch ($responseObj['errorCode']) {
121
+ case 0:
122
+ throw new ConverterFailedException('WPC reported problems with server setup: "' . $responseObj['errorMessage'] . '"');
123
+ case 1:
124
+ throw new ConverterFailedException('WPC denied us access to the service: "' . $responseObj['errorMessage'] . '"');
125
+ default:
126
+ throw new ConverterFailedException('WPC failed: "' . $responseObj['errorMessage'] . '"');
127
+ }
128
+ }
129
+ }
130
+
131
+ // WPC 0.1 returns 'failed![error messag]' when conversion fails. Handle that.
132
+ if (substr($response, 0, 7) == 'failed!') {
133
+ throw new ConverterFailedException('WPC failed converting image: "' . substr($response, 7) . '"');
134
+ }
135
+
136
+ $errorMsg = 'Error: Unexpected result. We did not receive an image. We received: "';
137
+ $errorMsg .= str_replace("\r", '', str_replace("\n", '', htmlentities(substr($response, 0, 400))));
138
+ throw new ConverterFailedException($errorMsg . '..."');
139
//throw new ConverterNotOperationalException($response);
140
}
141
vendor/webp-convert/WebPConvert.php CHANGED
@@ -89,7 +89,13 @@ class WebPConvert
89
}
90
}
91
92
- $logger->logLn('Conversion failed. None of the tried converters are operational', 'bold');
93
94
// No converters could do the job.
95
// If one of them failed moderately bad, rethrow that exception.
89
}
90
}
91
92
+ if ($firstFailException) {
93
+ // At least one converter failed or declined.
94
+ $logger->logLn('Conversion failed. None of the tried converters could convert the image', 'bold');
95
+ } else {
96
+ // All converters threw a ConverterNotOperationalException
97
+ $logger->logLn('Conversion failed. None of the tried converters are operational', 'bold');
98
+ }
99
100
// No converters could do the job.
101
// If one of them failed moderately bad, rethrow that exception.
vendor/webp-convert/autoload.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
-
3
- function autoloadWebPConvert()
4
- {
5
- // load base classes, which are required for other classes
6
- require_once(__DIR__ . '/Exceptions/WebPConvertBaseException.php');
7
- require_once(__DIR__ . '/Loggers/BaseLogger.php');
8
-
9
- $dirsToAutoload = [
10
- '.',
11
- 'Converters',
12
- 'Exceptions',
13
- 'Converters/Exceptions',
14
- 'Loggers',
15
- ];
16
- foreach ($dirsToAutoload as $dir) {
17
- $dirAbs = __DIR__ . '/' . $dir;
18
-
19
- // If directory has its own autoload.php, use that (but ignore autoload in current folder)
20
- if ((file_exists($dirAbs . '/autoload.php') && ($dir != '.'))) {
21
- require_once($dirAbs . '/autoload.php');
22
- } else {
23
- $files = glob($dirAbs . '/*.php');
24
- foreach ($files as $file) {
25
- // only require files that begins with uppercase (A-Z)
26
- if (preg_match('/\/[A-Z][a-zA-Z]*\.php/', $file)) {
27
- require_once($file);
28
- }
29
- }
30
- }
31
- }
32
- }
33
- autoloadWebPConvert();
vendor/webp-convert/require-all.inc ADDED
@@ -0,0 +1,20 @@
1
+ <?php
2
+ require_once(__DIR__ . "/Exceptions/WebPConvertBaseException.php");
3
+ require_once(__DIR__ . "/Loggers/BaseLogger.php");
4
+ require_once(__DIR__ . "/WebPConvert.php");
5
+ require_once(__DIR__ . "/Converters/ConverterHelper.php");
6
+ require_once(__DIR__ . "/Converters/Cwebp.php");
7
+ require_once(__DIR__ . "/Converters/Ewww.php");
8
+ require_once(__DIR__ . "/Converters/Gd.php");
9
+ require_once(__DIR__ . "/Converters/Imagick.php");
10
+ require_once(__DIR__ . "/Converters/Wpc.php");
11
+ require_once(__DIR__ . "/Exceptions/ConverterNotFoundException.php");
12
+ require_once(__DIR__ . "/Exceptions/CreateDestinationFileException.php");
13
+ require_once(__DIR__ . "/Exceptions/CreateDestinationFolderException.php");
14
+ require_once(__DIR__ . "/Exceptions/InvalidFileExtensionException.php");
15
+ require_once(__DIR__ . "/Exceptions/TargetNotFoundException.php");
16
+ require_once(__DIR__ . "/Converters/Exceptions/ConversionDeclinedException.php");
17
+ require_once(__DIR__ . "/Converters/Exceptions/ConverterFailedException.php");
18
+ require_once(__DIR__ . "/Converters/Exceptions/ConverterNotOperationalException.php");
19
+ require_once(__DIR__ . "/Loggers/EchoLogger.php");
20
+ require_once(__DIR__ . "/Loggers/VoidLogger.php");
vendor/webp-on-demand/autoload.php DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
-
3
- function autoloadWebOnDemand()
4
- {
5
- $dirsToAutoload = [
6
- '../webp-convert-and-serve',
7
- '.',
8
- ];
9
- foreach ($dirsToAutoload as $dir) {
10
- $dirAbs = __DIR__ . '/' . $dir;
11
-
12
- // If directory has its own autoload.php, use that (but ignore autoload in current folder)
13
- if ((file_exists($dirAbs . '/autoload.php') && ($dir != '.'))) {
14
- require_once($dirAbs . '/autoload.php');
15
- } else {
16
- $files = glob($dirAbs . '/*.php');
17
- foreach ($files as $file) {
18
- // only require files that begins with uppercase (A-Z)
19
- if (preg_match('/\/[A-Z][a-zA-Z]*\.php/', $file)) {
20
- require_once($file);
21
- }
22
- }
23
- }
24
- }
25
- }
26
- autoloadWebOnDemand();
webp-express.php CHANGED
@@ -3,7 +3,7 @@
3
* Plugin Name: WebP Express
4
* Plugin URI: https://github.com/rosell-dk/webp-express
5
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
6
- * Version: 0.3.1
7
* Author: Bjørn Rosell
8
* Author URI: https://www.bitwise-it.dk
9
* License: GPL2
@@ -14,9 +14,33 @@
14
Note: Perhaps create a plugin page on my website?, ie https://www.bitwise-it.dk/software/wordpress/webp-express
15
*/
16
17
define('WEBPEXPRESS_PLUGIN', __FILE__);
18
define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
19
20
add_action( 'admin_menu', function() {
21
22
//Add Settings Page
@@ -60,3 +84,36 @@ if (get_option('webp-express-deactivate')) {
60
});
61
delete_option('webp-express-deactivate');
62
}
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.4.0
7
* Author: Bjørn Rosell
8
* Author URI: https://www.bitwise-it.dk
9
* License: GPL2
14
Note: Perhaps create a plugin page on my website?, ie https://www.bitwise-it.dk/software/wordpress/webp-express
15
*/
16
17
+
18
+ /*
19
+ // uncomment this block to debug an error during activation
20
+ function tl_save_error() {
21
+ update_option( 'webp-express-activation-error', ob_get_contents() );
22
+ }
23
+ add_action( 'activated_plugin', 'tl_save_error' );
24
+ if (!empty(get_option('plugin_error'))) {
25
+ add_filter( 'admin_footer_text', function() {
26
+ return 'Activation error:' . get_option('webp-express-activation-error');
27
+ });
28
+ }*/
29
+
30
define('WEBPEXPRESS_PLUGIN', __FILE__);
31
define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
32
33
+ if (empty(get_option('webp-express-configured'))) {
34
+ global $wpdb;
35
+ $hasWebPExpressOptionBeenSaved = ($wpdb->get_row( "SELECT * FROM $wpdb->options WHERE option_name = 'webp_express_converters'" ) !== null);
36
+ if ($hasWebPExpressOptionBeenSaved) {
37
+ // Store the fact that webp options has been changed.
38
+ // When nobody is using 0.3 or below, we can test on the existence of that option, instead of
39
+ // querying the database directly ($hasWebPExpressOptionBeenSaved)
40
+ add_option('webp-express-configured', true);
41
+ }
42
+ }
43
+
44
add_action( 'admin_menu', function() {
45
46
//Add Settings Page
84
});
85
delete_option('webp-express-deactivate');
86
}
87
+
88
+ function webp_express_register_uninstall_hook() {
89
+ $optionsToDelete = [
90
+ 'webp_express_max_quality',
91
+ 'webp_express_image_types_to_convert',
92
+ 'webp_express_failure_response',
93
+ 'webp_express_converters',
94
+ 'webp-express-inserted-rules-ok',
95
+ 'webp-express-configured',
96
+ ];
97
+ foreach ($optionsToDelete as $i => $optionName) {
98
+ delete_option($optionName);
99
+ }
100
+ /*
101
+ webp_express_fail_action
102
+ webp_express_method
103
+ webp_express_quality
104
+ */
105
+ // Should we also call unregister_setting ?
106
+ }
107
+
108
+ // interestingly, I get "Serialization of 'Closure' is not allowed" if I pass anonymous function
109
+ // ... perhaps we should not do that in the other hooks either.
110
+ register_uninstall_hook( __FILE__, 'webp_express_register_uninstall_hook');
111
+
112
+
113
+ // Add settings link on the plugins page
114
+ add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), function ( $links ) {
115
+ $mylinks = array(
116
+ '<a href="' . admin_url( 'options-general.php?page=webp_express_settings_page' ) . '">Settings</a>',
117
+ );
118
+ return array_merge( $links, $mylinks );
119
+ });
webp-on-demand.php CHANGED
@@ -1,36 +1,15 @@
1
<?php
2
3
- //require 'webp-on-demand/vendor/autoload.php';
4
5
- require 'vendor/webp-on-demand/autoload.php';
6
- //require 'vendor/webp-convert-and-serve/autoload.php';
7
//require 'vendor/webp-on-demand/autoload.php';
8
-
9
- //echo '<br>done';
10
-
11
- //require '../webp-convert/WebPConvert.php';
12
-
13
-
14
- /*use WebPConvert\WebPConvert;
15
-
16
- $source = __DIR__ . '/test/test.jpg';
17
- $destination = __DIR__ . '/test/test.jpg.webp';
18
-
19
- // .. fire up WebP conversion
20
- $success = WebPConvert::convert($source, $destination, array(
21
- 'quality' => 90,
22
- // more options available!
23
- ));
24
-
25
-
26
- //$status = WebPOnDemand::serve(__DIR__);
27
-
28
- //echo 'hi';
29
- */
30
-
31
32
use WebPOnDemand\WebPOnDemand;
33
34
$status = WebPOnDemand::serve(__DIR__);
35
if ($status < 0) {
36
// Conversion failed.
1
<?php
2
3
+ error_reporting(E_ALL);
4
+ ini_set('display_errors', 'On');
5
6
+ //require 'webp-on-demand/vendor/autoload.php';
7
//require 'vendor/webp-on-demand/autoload.php';
8
+ require 'vendor/require-webp-on-demand.php';
9
10
use WebPOnDemand\WebPOnDemand;
11
12
+
13
$status = WebPOnDemand::serve(__DIR__);
14
if ($status < 0) {
15
// Conversion failed.