Version Description
(released: 09 Nov 2021) * Added option to disable creating log files and button to do delete them. Thanks to Amit Sonkhiya and many others for suggesting this. * WebP Express now prevents serving webps when they are bigger than the source. Added option for it (default is to prevent) * You can now prevent that a certain image is redirected to webp by appending "?original" to the URL. Also works for Alter HTML. * You can now prevent that a certain image is redirected to webp by placing a dummy ".do-not-convert" file next to the original. * The conversion manager now uses the new "?original" escape hatch to avoid that the original image is being redirected. Beware that if you are on Nginx and have created rewrite rules, you will need to implement the same escape hatch to avoid the "Original" image to be redirected to webp. However, in a future update, I will probably implement a PHP script for serving the original so you can also just wait. * Bugfix: Alter HTML could in some rare cases produce invalid HTML. For more info, see the closed issues on the webp-express 0.22 milestone * Bugfix: The "Enable redirection to converter" functionality was too greedy. It did not only redirect jpegs and pngs, but any file request. The bug occurred when Destination folder was set to "Image roots". The fix updates the .htaccess files if neccessary. * Minor bugfix: Symlinking the webp-express plugin folder would break "Redirection to converter" functionality
For more info, see the closed issues on the webp-express 0.22 milestone
Release Info
Developer | rosell.dk |
Plugin | WebP Express |
Version | 0.22.0 |
Comparing to | |
See all releases |
Code changes from version 0.21.1 to 0.22.0
- README.md +9 -16
- README.txt +29 -20
- changelog.txt +14 -0
- docs/publishing.md +2 -2
- lib/classes/AdminInit.php +12 -2
- lib/classes/AlterHtmlHelper.php +23 -6
- lib/classes/BiggerThanSource.php +33 -0
- lib/classes/BiggerThanSourceDummyFiles.php +135 -0
- lib/classes/BiggerThanSourceDummyFilesBulk.php +120 -0
- lib/classes/CachePurge.php +4 -0
- lib/classes/Config.php +47 -1
- lib/classes/Convert.php +24 -1
- lib/classes/ConvertHelperIndependent.php +21 -15
- lib/classes/HTAccessRules.php +80 -9
- lib/classes/HandleDeleteFileHook.php +7 -3
- lib/classes/LogPurge.php +99 -0
- lib/classes/PathHelper.php +14 -1
- lib/classes/Paths.php +17 -0
- lib/classes/WCFMApi.php +9 -8
- lib/classes/WebPOnDemand.php +13 -1
- lib/classes/WebPRealizer.php +13 -1
- lib/classes/WodConfigLoader.php +33 -14
- lib/migrate/migrate14.php +36 -0
- lib/options/enqueue_scripts.php +6 -1
- lib/options/js/0.19.0/bulk-convert.js +1 -1
- lib/options/js/0.19.0/purge-log.js +74 -0
- lib/options/options/conversion-options/conversion-options.inc +1 -0
- lib/options/options/conversion-options/logging.inc +24 -0
- lib/options/options/general/destination-extension.inc +2 -2
- lib/options/options/general/general.inc +2 -0
- lib/options/options/general/prevent-using-webps-larger-than-original.inc +15 -0
- lib/options/submit.php +11 -0
- vendor/composer/installed.json +7 -7
- vendor/composer/installed.php +5 -5
- vendor/rosell-dk/dom-util-for-webp/README.md +1 -1
- vendor/rosell-dk/dom-util-for-webp/src/PictureTags.php +87 -17
- webp-express.php +6 -1
@@ -664,28 +664,21 @@ The following lazy load plugins/frameworks has been tested and works with *WebP
|
|
664 |
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.
|
665 |
|
666 |
### Can I make an exceptions for some images?
|
667 |
-
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.
|
668 |
|
669 |
-
|
670 |
-
|
|
|
671 |
|
672 |
-
|
673 |
-
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*.
|
674 |
|
|
|
|
|
675 |
```
|
676 |
-
|
677 |
-
RewriteCond %{REQUEST_FILENAME} -f
|
678 |
-
RewriteRule . - [L]
|
679 |
```
|
680 |
-
|
681 |
|
682 |
-
Alternatively, you can specify the filenames individually in the `.htaccess`:
|
683 |
-
|
684 |
-
```
|
685 |
-
RewriteRule ^uploads/2019/02/example-of-jpg-compressed-to-80\.jpg - [L]
|
686 |
-
RewriteRule ^uploads/2019/02/image2\.jpg - [L]
|
687 |
-
RewriteRule . - [L]
|
688 |
-
```
|
689 |
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/)
|
690 |
|
691 |
### Alter HTML only replaces some of the images
|
664 |
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.
|
665 |
|
666 |
### Can I make an exceptions for some images?
|
667 |
+
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.
|
668 |
|
669 |
+
If you want an image to be served in the original format (jpeg og png), do one of the following things:
|
670 |
+
- Add "?original" to the image url.
|
671 |
+
- Place an empty file in the same folder as the jpeg/png. The file name must be the same as the jpeg/png with ".do-not-convert" appended
|
672 |
|
673 |
+
Doing this will bypass redirection to webp and also prevent Alter HTML to use the webp instead of the original.
|
|
|
674 |
|
675 |
+
*Bypassing for an entire folder*
|
676 |
+
To bypass redirection for an entire folder, you can put something like this into your index `.htaccess`:
|
677 |
```
|
678 |
+
RewriteRule ^wp-content/uploads/2021/06/ - [L]
|
|
|
|
|
679 |
```
|
680 |
+
PS: If *WebP Express* has placed rules in that .htaccess, you need to place the rule *above* the rules inserted by *WebP Express*
|
681 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
682 |
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/)
|
683 |
|
684 |
### Alter HTML only replaces some of the images
|
@@ -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.8
|
7 |
-
Stable tag: 0.
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
@@ -175,10 +175,9 @@ Bread on the table don't come for free, even though this plugin does, and always
|
|
175 |
* Ruben Solvang
|
176 |
|
177 |
**Persons who recently contributed with [ko-fi](https://ko-fi.com/rosell) - Thanks!**
|
|
|
178 |
* 29 Aug: Pawa Tecnologia
|
179 |
* 29 Jul: Brian Laursen
|
180 |
-
* 24 Jul: Hans Konings
|
181 |
-
* 8 Jul: Raj
|
182 |
|
183 |
**Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
|
184 |
|
@@ -719,28 +718,21 @@ The following lazy load plugins/frameworks has been tested and works with *WebP
|
|
719 |
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.
|
720 |
|
721 |
= Can I make an exceptions for some images? =
|
722 |
-
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.
|
723 |
|
724 |
-
|
725 |
-
|
|
|
726 |
|
727 |
-
|
728 |
-
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*.
|
729 |
|
|
|
|
|
730 |
`
|
731 |
-
|
732 |
-
RewriteCond %{REQUEST_FILENAME} -f
|
733 |
-
RewriteRule . - [L]
|
734 |
`
|
735 |
-
|
736 |
|
737 |
-
Alternatively, you can specify the filenames individually in the `.htaccess`:
|
738 |
-
|
739 |
-
`
|
740 |
-
RewriteRule ^uploads/2019/02/example-of-jpg-compressed-to-80\.jpg - [L]
|
741 |
-
RewriteRule ^uploads/2019/02/image2\.jpg - [L]
|
742 |
-
RewriteRule . - [L]
|
743 |
-
`
|
744 |
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/)
|
745 |
|
746 |
= Update failed and cannot reinstall =
|
@@ -762,7 +754,7 @@ No schedule. I move forward as time allows. I currently spend a lot of time answ
|
|
762 |
Right now I am focusing on the File Manager. I would like to add possibility for converting, bulk converting, viewing conversion logs, viewing stats, etc.
|
763 |
|
764 |
Here are other things in pipeline:
|
765 |
-
- Excluding certain files and folders.
|
766 |
- Supporting Save-Data header in Varied Image Responses mode (send extra compressed images to clients who wants to use as little bandwidth as possible).
|
767 |
- Displaying rules for NGINX.
|
768 |
- Allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript library 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.
|
@@ -783,6 +775,20 @@ If you want to make sure that my coffee supplies don't run dry, you can even buy
|
|
783 |
|
784 |
== Changelog ==
|
785 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
786 |
= 0.21.1 =
|
787 |
*(released: 27 Oct 2021)*
|
788 |
* Bugfix: File manager could not handle many images. It now loads tree branches on need basis instead of the complete tree in one go
|
@@ -822,6 +828,9 @@ For older releases, check out changelog.txt
|
|
822 |
|
823 |
== Upgrade Notice ==
|
824 |
|
|
|
|
|
|
|
825 |
= 0.21.1 =
|
826 |
* Two bug fixes
|
827 |
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 5.8
|
7 |
+
Stable tag: 0.22.0
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
175 |
* Ruben Solvang
|
176 |
|
177 |
**Persons who recently contributed with [ko-fi](https://ko-fi.com/rosell) - Thanks!**
|
178 |
+
* 26 Oct: Anonymous
|
179 |
* 29 Aug: Pawa Tecnologia
|
180 |
* 29 Jul: Brian Laursen
|
|
|
|
|
181 |
|
182 |
**Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
|
183 |
|
718 |
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.
|
719 |
|
720 |
= Can I make an exceptions for some images? =
|
721 |
+
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.
|
722 |
|
723 |
+
If you want an image to be served in the original format (jpeg og png), do one of the following things:
|
724 |
+
- Add "?original" to the image url.
|
725 |
+
- Place an empty file in the same folder as the jpeg/png. The file name must be the same as the jpeg/png with ".do-not-convert" appended
|
726 |
|
727 |
+
Doing this will bypass redirection to webp and also prevent Alter HTML to use the webp instead of the original.
|
|
|
728 |
|
729 |
+
*Bypassing for an entire folder*
|
730 |
+
To bypass redirection for an entire folder, you can put something like this into your root .htaccess:
|
731 |
`
|
732 |
+
RewriteRule ^uploads/2021/06/ - [L]
|
|
|
|
|
733 |
`
|
734 |
+
PS: If *WebP Express* has placed rules in that .htaccess, you need to place the rule *above* the rules inserted by *WebP Express*
|
735 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
736 |
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/)
|
737 |
|
738 |
= Update failed and cannot reinstall =
|
754 |
Right now I am focusing on the File Manager. I would like to add possibility for converting, bulk converting, viewing conversion logs, viewing stats, etc.
|
755 |
|
756 |
Here are other things in pipeline:
|
757 |
+
- Excluding certain files and folders.
|
758 |
- Supporting Save-Data header in Varied Image Responses mode (send extra compressed images to clients who wants to use as little bandwidth as possible).
|
759 |
- Displaying rules for NGINX.
|
760 |
- Allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript library 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.
|
775 |
|
776 |
== Changelog ==
|
777 |
|
778 |
+
= 0.22.0 =
|
779 |
+
*(released: 09 Nov 2021)*
|
780 |
+
* Added option to disable creating log files and button to do delete them. Thanks to Amit Sonkhiya and many others for suggesting this.
|
781 |
+
* WebP Express now prevents serving webps when they are bigger than the source. Added option for it (default is to prevent)
|
782 |
+
* You can now prevent that a certain image is redirected to webp by appending "?original" to the URL. Also works for Alter HTML.
|
783 |
+
* You can now prevent that a certain image is redirected to webp by placing a dummy ".do-not-convert" file next to the original.
|
784 |
+
* The conversion manager now uses the new "?original" escape hatch to avoid that the original image is being redirected. Beware that if you are on Nginx and have created rewrite rules, you will need to implement the same escape hatch to avoid the "Original" image to be redirected to webp. However, in a future update, I will probably implement a PHP script for serving the original so you can also just wait.
|
785 |
+
* Bugfix: Alter HTML could in some [rare cases](https://github.com/rosell-dk/webp-express/issues/528) produce invalid HTML.
|
786 |
+
For more info, see the closed issues on the [webp-express 0.22 milestone](https://github.com/rosell-dk/webp-express/milestone/13?closed=1)
|
787 |
+
* Bugfix: The "Enable redirection to converter" functionality was too greedy. It did not only redirect jpegs and pngs, but any file request. The bug occurred when Destination folder was set to "Image roots". The fix updates the .htaccess files if neccessary.
|
788 |
+
* Minor bugfix: Symlinking the webp-express plugin folder would break "Redirection to converter" functionality
|
789 |
+
|
790 |
+
For more info, see the closed issues on the [webp-express 0.22 milestone](https://github.com/rosell-dk/webp-express/milestone/13?closed=1)
|
791 |
+
|
792 |
= 0.21.1 =
|
793 |
*(released: 27 Oct 2021)*
|
794 |
* Bugfix: File manager could not handle many images. It now loads tree branches on need basis instead of the complete tree in one go
|
828 |
|
829 |
== Upgrade Notice ==
|
830 |
|
831 |
+
= 0.22.0 =
|
832 |
+
* Various improvements and bug fixes
|
833 |
+
|
834 |
= 0.21.1 =
|
835 |
* Two bug fixes
|
836 |
|
@@ -1,3 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
= 0.21.1 =
|
2 |
*(released: 27 Oct 2021)*
|
3 |
* Bugfix: File manager could not handle many images. It now loads tree branches on need basis instead of the complete tree in one go
|
1 |
+
= 0.22.0 =
|
2 |
+
*(released: 09 Nov 2021)*
|
3 |
+
* Added option to disable creating log files and button to do delete them. Thanks to Amit Sonkhiya and many others for suggesting this.
|
4 |
+
* WebP Express now prevents serving webps when they are bigger than the source. Added option for it (default is to prevent)
|
5 |
+
* You can now prevent that a certain image is redirected to webp by appending "?original" to the URL. Also works for Alter HTML.
|
6 |
+
* You can now prevent that a certain image is redirected to webp by placing a dummy ".do-not-convert" file next to the original.
|
7 |
+
* The conversion manager now uses the new "?original" escape hatch to avoid that the original image is being redirected. Beware that if you are on Nginx and have created rewrite rules, you will need to implement the same escape hatch to avoid the "Original" image to be redirected to webp. However, in a future update, I will probably implement a PHP script for serving the original so you can also just wait.
|
8 |
+
* Bugfix: Alter HTML could in some [rare cases](https://github.com/rosell-dk/webp-express/issues/528) produce invalid HTML.
|
9 |
+
For more info, see the closed issues on the [webp-express 0.22 milestone](https://github.com/rosell-dk/webp-express/milestone/13?closed=1)
|
10 |
+
* Bugfix: The "Enable redirection to converter" functionality was too greedy. It did not only redirect jpegs and pngs, but any file request. The bug occurred when Destination folder was set to "Image roots". The fix updates the .htaccess files if neccessary.
|
11 |
+
* Minor bugfix: Symlinking the webp-express plugin folder would break "Redirection to converter" functionality
|
12 |
+
|
13 |
+
For more info, see the closed issues on the [webp-express 0.22 milestone](https://github.com/rosell-dk/webp-express/milestone/13?closed=1)
|
14 |
+
|
15 |
= 0.21.1 =
|
16 |
*(released: 27 Oct 2021)*
|
17 |
* Bugfix: File manager could not handle many images. It now loads tree branches on need basis instead of the complete tree in one go
|
@@ -114,12 +114,12 @@ svn status | grep '^!' | awk '{print $2}' | xargs svn delete --force (t
|
|
114 |
Then add a new tag
|
115 |
```
|
116 |
cd svn
|
117 |
-
svn cp trunk tags/0.21.
|
118 |
```
|
119 |
|
120 |
And commit!
|
121 |
```
|
122 |
-
svn ci -m '0.21.
|
123 |
```
|
124 |
|
125 |
|
114 |
Then add a new tag
|
115 |
```
|
116 |
cd svn
|
117 |
+
svn cp trunk tags/0.21.1 (this will copy trunk into a new tag)
|
118 |
```
|
119 |
|
120 |
And commit!
|
121 |
```
|
122 |
+
svn ci -m '0.21.1'
|
123 |
```
|
124 |
|
125 |
|
@@ -25,7 +25,7 @@ class AdminInit
|
|
25 |
public static function runMigrationIfNeeded()
|
26 |
{
|
27 |
// When an update requires a migration, the number should be increased
|
28 |
-
define('WEBPEXPRESS_MIGRATION_VERSION', '
|
29 |
|
30 |
if (WEBPEXPRESS_MIGRATION_VERSION != Option::getOption('webp-express-migration-version', 0)) {
|
31 |
// run migration logic
|
@@ -33,7 +33,7 @@ class AdminInit
|
|
33 |
}
|
34 |
|
35 |
// uncomment next line to test-run a migration
|
36 |
-
//include WEBPEXPRESS_PLUGIN_DIR . '/lib/migrate/
|
37 |
}
|
38 |
|
39 |
public static function pageNowIs($pageId)
|
@@ -80,6 +80,7 @@ class AdminInit
|
|
80 |
add_action('wp_ajax_convert_file', array('\WebPExpress\Convert', 'processAjaxConvertFile'));
|
81 |
add_action('wp_ajax_webpexpress_view_log', array('\WebPExpress\ConvertLog', 'processAjaxViewLog'));
|
82 |
add_action('wp_ajax_webpexpress_purge_cache', array('\WebPExpress\CachePurge', 'processAjaxPurgeCache'));
|
|
|
83 |
add_action('wp_ajax_webpexpress_dismiss_message', array('\WebPExpress\DismissableMessages', 'processAjaxDismissMessage'));
|
84 |
add_action('wp_ajax_webpexpress_dismiss_global_message', array('\WebPExpress\DismissableGlobalMessages', 'processAjaxDismissGlobalMessage'));
|
85 |
add_action('wp_ajax_webpexpress_self_test', array('\WebPExpress\SelfTest', 'processAjax'));
|
@@ -103,11 +104,20 @@ class AdminInit
|
|
103 |
register_deactivation_hook(WEBPEXPRESS_PLUGIN, array('\WebPExpress\PluginDeactivate', 'deactivate'));
|
104 |
register_uninstall_hook(WEBPEXPRESS_PLUGIN, array('\WebPExpress\PluginUninstall', 'uninstall'));
|
105 |
|
|
|
|
|
|
|
|
|
|
|
106 |
// Some hooks must be registered AFTER admin_init...
|
107 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'addHooksAfterAdminInit'));
|
108 |
|
109 |
// Run migration AFTER admin_init hook (important, as insert_with_markers injection otherwise fails, see #394)
|
|
|
110 |
// PS: Unfortunately Message::addMessage doesnt print until next load now, we should look into that.
|
|
|
|
|
|
|
111 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'runMigrationIfNeeded'));
|
112 |
|
113 |
add_action("admin_notices", array('\WebPExpress\DismissableGlobalMessages', 'printMessages'));
|
25 |
public static function runMigrationIfNeeded()
|
26 |
{
|
27 |
// When an update requires a migration, the number should be increased
|
28 |
+
define('WEBPEXPRESS_MIGRATION_VERSION', '14');
|
29 |
|
30 |
if (WEBPEXPRESS_MIGRATION_VERSION != Option::getOption('webp-express-migration-version', 0)) {
|
31 |
// run migration logic
|
33 |
}
|
34 |
|
35 |
// uncomment next line to test-run a migration
|
36 |
+
//include WEBPEXPRESS_PLUGIN_DIR . '/lib/migrate/migrate14.php';
|
37 |
}
|
38 |
|
39 |
public static function pageNowIs($pageId)
|
80 |
add_action('wp_ajax_convert_file', array('\WebPExpress\Convert', 'processAjaxConvertFile'));
|
81 |
add_action('wp_ajax_webpexpress_view_log', array('\WebPExpress\ConvertLog', 'processAjaxViewLog'));
|
82 |
add_action('wp_ajax_webpexpress_purge_cache', array('\WebPExpress\CachePurge', 'processAjaxPurgeCache'));
|
83 |
+
add_action('wp_ajax_webpexpress_purge_log', array('\WebPExpress\LogPurge', 'processAjaxPurgeLog'));
|
84 |
add_action('wp_ajax_webpexpress_dismiss_message', array('\WebPExpress\DismissableMessages', 'processAjaxDismissMessage'));
|
85 |
add_action('wp_ajax_webpexpress_dismiss_global_message', array('\WebPExpress\DismissableGlobalMessages', 'processAjaxDismissGlobalMessage'));
|
86 |
add_action('wp_ajax_webpexpress_self_test', array('\WebPExpress\SelfTest', 'processAjax'));
|
104 |
register_deactivation_hook(WEBPEXPRESS_PLUGIN, array('\WebPExpress\PluginDeactivate', 'deactivate'));
|
105 |
register_uninstall_hook(WEBPEXPRESS_PLUGIN, array('\WebPExpress\PluginUninstall', 'uninstall'));
|
106 |
|
107 |
+
/*$start = microtime(true);
|
108 |
+
BiggerThanSourceDummyFilesBulk::updateStatus(Config::loadConfig());
|
109 |
+
echo microtime(true) - $start;*/
|
110 |
+
|
111 |
+
|
112 |
// Some hooks must be registered AFTER admin_init...
|
113 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'addHooksAfterAdminInit'));
|
114 |
|
115 |
// Run migration AFTER admin_init hook (important, as insert_with_markers injection otherwise fails, see #394)
|
116 |
+
// PS: "plugins_loaded" is to early, as insert_with_markers fails.
|
117 |
// PS: Unfortunately Message::addMessage doesnt print until next load now, we should look into that.
|
118 |
+
// PPS: It does run. It must be the Option that does not react
|
119 |
+
//add_action("admin_init", array('\WebPExpress\AdminInit', 'runMigrationIfNeeded'));
|
120 |
+
|
121 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'runMigrationIfNeeded'));
|
122 |
|
123 |
add_action("admin_notices", array('\WebPExpress\DismissableGlobalMessages', 'printMessages'));
|
@@ -43,7 +43,9 @@ class AlterHtmlHelper
|
|
43 |
public static function getOptions() {
|
44 |
if (!isset(self::$options)) {
|
45 |
self::$options = json_decode(Option::getOption('webp-express-alter-html-options', null), true);
|
46 |
-
|
|
|
|
|
47 |
// Set scope if it isn't there (it wasn't cached until 0.17.5)
|
48 |
if (!isset(self::$options['scope'])) {
|
49 |
$config = Config::loadConfig();
|
@@ -151,12 +153,13 @@ class AlterHtmlHelper
|
|
151 |
|
152 |
|
153 |
/**
|
154 |
-
*
|
155 |
-
*
|
156 |
*
|
157 |
-
*
|
158 |
-
*
|
159 |
-
*
|
|
|
160 |
*
|
161 |
* @param string $sourceUrl Url of source image (ie http://example.com/wp-content/image.jpg)
|
162 |
* @param string $rootId Id (created in Config::updateAutoloadedOptions). Ie "uploads", "content" or any image root id
|
@@ -216,6 +219,20 @@ class AlterHtmlHelper
|
|
216 |
return false;
|
217 |
}
|
218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
$destUrl = $destinationRoot['url'] . '/' . $relPathFromImageRootToDest;
|
220 |
|
221 |
// Fix scheme (use same as source)
|
43 |
public static function getOptions() {
|
44 |
if (!isset(self::$options)) {
|
45 |
self::$options = json_decode(Option::getOption('webp-express-alter-html-options', null), true);
|
46 |
+
if (!isset(self::$options['prevent-using-webps-larger-than-original'])) {
|
47 |
+
self::$options['prevent-using-webps-larger-than-original'] = true;
|
48 |
+
}
|
49 |
// Set scope if it isn't there (it wasn't cached until 0.17.5)
|
50 |
if (!isset(self::$options['scope'])) {
|
51 |
$config = Config::loadConfig();
|
153 |
|
154 |
|
155 |
/**
|
156 |
+
* Get url for webp from source url, (if ), given a certain baseUrl / baseDir.
|
157 |
+
* Base can for example be uploads or wp-content.
|
158 |
*
|
159 |
+
* returns false:
|
160 |
+
* - if no source file found in that base
|
161 |
+
* - if source file is found but webp file isn't there and the `only-for-webps-that-exists` option is set
|
162 |
+
* - if webp is marked as bigger than source
|
163 |
*
|
164 |
* @param string $sourceUrl Url of source image (ie http://example.com/wp-content/image.jpg)
|
165 |
* @param string $rootId Id (created in Config::updateAutoloadedOptions). Ie "uploads", "content" or any image root id
|
219 |
return false;
|
220 |
}
|
221 |
|
222 |
+
// check if webp is marked as bigger than source
|
223 |
+
/*
|
224 |
+
$biggerThanSourcePath = Paths::getBiggerThanSourceDirAbs() . '/' . $rootId . '/' . $relPathFromImageRootToDest;
|
225 |
+
if (@file_exists($biggerThanSourcePath)) {
|
226 |
+
return false;
|
227 |
+
}*/
|
228 |
+
|
229 |
+
// check if webp is larger than original
|
230 |
+
if (self::$options['prevent-using-webps-larger-than-original']) {
|
231 |
+
if (BiggerThanSource::bigger($srcPathAbs, $destPathAbs)) {
|
232 |
+
return false;
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
$destUrl = $destinationRoot['url'] . '/' . $relPathFromImageRootToDest;
|
237 |
|
238 |
// Fix scheme (use same as source)
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
This class is made to not be dependent on Wordpress functions and must be kept like that.
|
5 |
+
It is used by webp-on-demand.php. It is also used for bulk conversion.
|
6 |
+
*/
|
7 |
+
namespace WebPExpress;
|
8 |
+
|
9 |
+
|
10 |
+
class BiggerThanSource
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
* Check if webp is bigger than original.
|
14 |
+
*
|
15 |
+
* @return boolean|null True if it is bigger than original, false if not. NULL if it cannot be determined
|
16 |
+
*/
|
17 |
+
public static function bigger($source, $destination)
|
18 |
+
{
|
19 |
+
/*
|
20 |
+
if ((!@file_exists($source)) || (!@file_exists($destination) {
|
21 |
+
return null;
|
22 |
+
}*/
|
23 |
+
$filesizeDestination = @filesize($destination);
|
24 |
+
$filesizeSource = @filesize($source);
|
25 |
+
|
26 |
+
// sizes are FALSE on failure (ie if file does not exists)
|
27 |
+
if (($filesizeDestination === false) || ($filesizeDestination === false)) {
|
28 |
+
return null;
|
29 |
+
}
|
30 |
+
|
31 |
+
return ($filesizeDestination > $filesizeSource);
|
32 |
+
}
|
33 |
+
}
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
This class is made to not be dependent on Wordpress functions and must be kept like that.
|
5 |
+
It is used by webp-on-demand.php. It is also used for bulk conversion.
|
6 |
+
*/
|
7 |
+
namespace WebPExpress;
|
8 |
+
|
9 |
+
|
10 |
+
class BiggerThanSourceDummyFiles
|
11 |
+
{
|
12 |
+
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Create the directory for log files and put a .htaccess file into it, which prevents
|
16 |
+
* it to be viewed from the outside (not that it contains any sensitive information btw, but for good measure).
|
17 |
+
*
|
18 |
+
* @param string $logDir The folder where log files are kept
|
19 |
+
*
|
20 |
+
* @return boolean Whether it was created successfully or not.
|
21 |
+
*
|
22 |
+
*/
|
23 |
+
private static function createBiggerThanSourceBaseDir($dir)
|
24 |
+
{
|
25 |
+
if (!is_dir($dir)) {
|
26 |
+
@mkdir($dir, 0775, true);
|
27 |
+
@chmod($dir, 0775);
|
28 |
+
@file_put_contents(rtrim($dir . '/') . '/.htaccess', <<<APACHE
|
29 |
+
<IfModule mod_authz_core.c>
|
30 |
+
Require all denied
|
31 |
+
</IfModule>
|
32 |
+
<IfModule !mod_authz_core.c>
|
33 |
+
Order deny,allow
|
34 |
+
Deny from all
|
35 |
+
</IfModule>
|
36 |
+
APACHE
|
37 |
+
);
|
38 |
+
@chmod($dir . '/.htaccess', 0664);
|
39 |
+
}
|
40 |
+
return is_dir($dir);
|
41 |
+
}
|
42 |
+
|
43 |
+
public static function pathToDummyFile($source, $basedir, $imageRoots, $destinationFolder, $destinationExt)
|
44 |
+
{
|
45 |
+
$sourceResolved = realpath($source);
|
46 |
+
|
47 |
+
// Check roots until we (hopefully) get a match.
|
48 |
+
// (that is: find a root which the source is inside)
|
49 |
+
foreach ($imageRoots->getArray() as $i => $imageRoot) {
|
50 |
+
$rootPath = $imageRoot->getAbsPath();
|
51 |
+
|
52 |
+
// We can assume that $rootPath is resolvable using realpath (it ought to exist and be within open_basedir for WP to function)
|
53 |
+
// We can also assume that $source is resolvable (it ought to exist and within open_basedir)
|
54 |
+
// So: Resolve both! and test if the resolved source begins with the resolved rootPath.
|
55 |
+
if (strpos($sourceResolved, realpath($rootPath)) !== false) {
|
56 |
+
$relPath = substr($sourceResolved, strlen(realpath($rootPath)) + 1);
|
57 |
+
$relPath = ConvertHelperIndependent::appendOrSetExtension($relPath, $destinationFolder, $destinationExt, false);
|
58 |
+
|
59 |
+
return $basedir . '/' . $imageRoot->id . '/' . $relPath;
|
60 |
+
break;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
return false;
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function pathToDummyFileRootAndRelKnown($source, $basedir, $rootId, $destinationFolder, $destinationExt)
|
67 |
+
{
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Check if webp is bigger than original.
|
72 |
+
*
|
73 |
+
* @return boolean|null True if it is bigger than original, false if not. NULL if it cannot be determined
|
74 |
+
*/
|
75 |
+
public static function bigger($source, $destination)
|
76 |
+
{
|
77 |
+
/*
|
78 |
+
if ((!@file_exists($source)) || (!@file_exists($destination) {
|
79 |
+
return null;
|
80 |
+
}*/
|
81 |
+
$filesizeDestination = @filesize($destination);
|
82 |
+
$filesizeSource = @filesize($source);
|
83 |
+
|
84 |
+
// sizes are FALSE on failure (ie if file does not exists)
|
85 |
+
if (($filesizeDestination === false) || ($filesizeDestination === false)) {
|
86 |
+
return null;
|
87 |
+
}
|
88 |
+
|
89 |
+
return ($filesizeDestination > $filesizeSource);
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Update the status for a single image (when rootId is unknown)
|
94 |
+
*
|
95 |
+
* Checks if webp is bigger than original. If it is, a dummy file is placed. Otherwise, it is
|
96 |
+
* removed (if exists)
|
97 |
+
*
|
98 |
+
* @param string $source Path to the source file that was converted
|
99 |
+
*
|
100 |
+
*
|
101 |
+
*/
|
102 |
+
public static function updateStatus($source, $destination, $webExpressContentDirAbs, $imageRoots, $destinationFolder, $destinationExt)
|
103 |
+
{
|
104 |
+
$basedir = $webExpressContentDirAbs . '/webp-images-bigger-than-source';
|
105 |
+
if (!file_exists($basedir)) {
|
106 |
+
self::createBiggerThanSourceBaseDir($basedir);
|
107 |
+
}
|
108 |
+
$bigWebP = BiggerThanSource::bigger($source, $destination);
|
109 |
+
|
110 |
+
$file = self::pathToDummyFile($source, $basedir, $imageRoots, $destinationFolder, $destinationExt);
|
111 |
+
if ($file === false) {
|
112 |
+
return;
|
113 |
+
}
|
114 |
+
|
115 |
+
if ($bigWebP === true) {
|
116 |
+
// place dummy file, which marks that webp is bigger than source
|
117 |
+
|
118 |
+
$folder = @dirname($file);
|
119 |
+
if (!@file_exists($folder)) {
|
120 |
+
mkdir($folder, 0777, true);
|
121 |
+
}
|
122 |
+
if (@file_exists($folder)) {
|
123 |
+
file_put_contents($file, '');
|
124 |
+
}
|
125 |
+
|
126 |
+
} else {
|
127 |
+
// remove dummy file (if exists)
|
128 |
+
if (@file_exists($file)) {
|
129 |
+
@unlink($file);
|
130 |
+
}
|
131 |
+
}
|
132 |
+
|
133 |
+
}
|
134 |
+
|
135 |
+
}
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
|
6 |
+
class BiggerThanSourceDummyFilesBulk
|
7 |
+
{
|
8 |
+
|
9 |
+
private static $settings;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Update the status for a all images.
|
13 |
+
*
|
14 |
+
*/
|
15 |
+
public static function updateStatus($config = null)
|
16 |
+
{
|
17 |
+
if (is_null($config)) {
|
18 |
+
$config = Config::loadConfigAndFix(false);
|
19 |
+
}
|
20 |
+
self::$settings = [
|
21 |
+
'ext' => $config['destination-extension'],
|
22 |
+
'destination-folder' => $config['destination-folder'], /* hm, "destination-folder" is a bad name... */
|
23 |
+
'webExpressContentDirAbs' => Paths::getWebPExpressContentDirAbs(),
|
24 |
+
'uploadDirAbs' => Paths::getUploadDirAbs(),
|
25 |
+
'useDocRootForStructuringCacheDir' => (($config['destination-structure'] == 'doc-root') && (Paths::canUseDocRootForStructuringCacheDir())),
|
26 |
+
//'imageRoots' => new ImageRoots(Paths::getImageRootsDefForSelectedIds($config['scope'])), // (Paths::getImageRootsDef()
|
27 |
+
'imageRoots' => new ImageRoots(Paths::getImageRootsDefForSelectedIds(Paths::getImageRootIds())), // (Paths::getImageRootsDef()
|
28 |
+
'image-types' => $config['image-types'],
|
29 |
+
];
|
30 |
+
|
31 |
+
|
32 |
+
//$rootIds = Paths::filterOutSubRoots($config['scope']);
|
33 |
+
|
34 |
+
// We want to update status on ALL root dirs (so we don't have to re-run when user changes scope)
|
35 |
+
$rootIds = Paths::filterOutSubRoots(Paths::getImageRootIds());
|
36 |
+
//$rootIds = ['uploads'];
|
37 |
+
//$rootIds = ['uploads', 'themes'];
|
38 |
+
|
39 |
+
foreach ($rootIds as $rootId) {
|
40 |
+
self::updateStatusForRoot($rootId);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Pre-requirement: self::$settings is set.
|
46 |
+
*
|
47 |
+
* Idea for improvement: Traverse destination dirs instead. This will be quicker, as there will not be
|
48 |
+
* as many images (unless all have been converted), and not as many folders (non-image folders will not be present.
|
49 |
+
* however, index does not take too long to traverse, even though it has many non-image folders, so it will only
|
50 |
+
* be a problem if there are plugins or themes with extremely many folders).
|
51 |
+
*/
|
52 |
+
private static function updateStatusForRoot($rootId, $dir = '')
|
53 |
+
{
|
54 |
+
if ($dir == '') {
|
55 |
+
$dir = Paths::getAbsDirById($rootId);
|
56 |
+
}
|
57 |
+
|
58 |
+
// Canonicalize because dir might contain "/./", which causes file_exists to fail (#222)
|
59 |
+
$dir = PathHelper::canonicalize($dir);
|
60 |
+
|
61 |
+
if (!@file_exists($dir) || !@is_dir($dir)) {
|
62 |
+
return [];
|
63 |
+
}
|
64 |
+
|
65 |
+
$fileIterator = new \FilesystemIterator($dir);
|
66 |
+
|
67 |
+
$results = [];
|
68 |
+
|
69 |
+
while ($fileIterator->valid()) {
|
70 |
+
$filename = $fileIterator->getFilename();
|
71 |
+
|
72 |
+
if (($filename != ".") && ($filename != "..")) {
|
73 |
+
if (@is_dir($dir . "/" . $filename)) {
|
74 |
+
$newDir = $dir . "/" . $filename;
|
75 |
+
|
76 |
+
// The new dir might have its own root id
|
77 |
+
$newRootId = Paths::findImageRootOfPath($newDir, Paths::getImageRootIds());
|
78 |
+
//echo $newRootId . ': ' . $newDir . "\n";
|
79 |
+
self::updateStatusForRoot($newRootId, $newDir);
|
80 |
+
} else {
|
81 |
+
// its a file - check if its a valid image type (jpeg or png)
|
82 |
+
$regex = '#\.(jpe?g|png)$#';
|
83 |
+
if (preg_match($regex, $filename)) {
|
84 |
+
|
85 |
+
$source = $dir . "/" . $filename;
|
86 |
+
|
87 |
+
$destination = ConvertHelperIndependent::getDestination(
|
88 |
+
$source,
|
89 |
+
self::$settings['destination-folder'],
|
90 |
+
self::$settings['ext'],
|
91 |
+
self::$settings['webExpressContentDirAbs'],
|
92 |
+
self::$settings['uploadDirAbs'],
|
93 |
+
self::$settings['useDocRootForStructuringCacheDir'],
|
94 |
+
self::$settings['imageRoots'],
|
95 |
+
//$rootId
|
96 |
+
|
97 |
+
);
|
98 |
+
$webpExists = @file_exists($destination);
|
99 |
+
|
100 |
+
//echo ($webpExists ? 'YES' : 'NO') . ' ' . $rootId . ': ' . $source . "\n";
|
101 |
+
|
102 |
+
BiggerThanSourceDummyFiles::updateStatus(
|
103 |
+
$source,
|
104 |
+
$destination,
|
105 |
+
self::$settings['webExpressContentDirAbs'],
|
106 |
+
self::$settings['imageRoots'],
|
107 |
+
self::$settings['destination-folder'],
|
108 |
+
self::$settings['ext'],
|
109 |
+
// TODO: send rootId so the function doesn't need to try all
|
110 |
+
// $rootId,
|
111 |
+
);
|
112 |
+
|
113 |
+
}
|
114 |
+
}
|
115 |
+
}
|
116 |
+
$fileIterator->next();
|
117 |
+
}
|
118 |
+
return $results;
|
119 |
+
}
|
120 |
+
}
|
@@ -38,6 +38,10 @@ class CachePurge
|
|
38 |
$numFailed += $f;
|
39 |
}
|
40 |
|
|
|
|
|
|
|
|
|
41 |
|
42 |
return [
|
43 |
'delete-count' => $numDeleted,
|
38 |
$numFailed += $f;
|
39 |
}
|
40 |
|
41 |
+
// Now, purge dummy files too
|
42 |
+
$dir = Paths::getBiggerThanSourceDirAbs();
|
43 |
+
self::purgeWebPFilesInDir($dir, $filter, $config);
|
44 |
+
FileHelper::removeEmptySubFolders($dir);
|
45 |
|
46 |
return [
|
47 |
'delete-count' => $numDeleted,
|
@@ -36,6 +36,8 @@ class Config
|
|
36 |
'cache-control-max-age' => 'one-week',
|
37 |
'cache-control-public' => false,
|
38 |
'scope' => ['themes', 'uploads'],
|
|
|
|
|
39 |
|
40 |
// redirection rules
|
41 |
'enable-redirection-to-converter' => true,
|
@@ -155,6 +157,12 @@ class Config
|
|
155 |
return $config;
|
156 |
}
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
public static function fix($config, $checkQualityDetection = true)
|
159 |
{
|
160 |
if ($config === false) {
|
@@ -412,6 +420,7 @@ class Config
|
|
412 |
$obj['destination-structure'] = $config['destination-structure'];
|
413 |
$obj['scope'] = $config['scope'];
|
414 |
$obj['image-types'] = $config['image-types']; // 0=none,1=jpg, 2=png, 3=both
|
|
|
415 |
|
416 |
Option::updateOption(
|
417 |
'webp-express-alter-html-options',
|
@@ -420,6 +429,9 @@ class Config
|
|
420 |
);
|
421 |
}
|
422 |
|
|
|
|
|
|
|
423 |
public static function saveConfigurationFile($config)
|
424 |
{
|
425 |
$config['paths-used-in-htaccess'] = [
|
@@ -580,6 +592,7 @@ class Config
|
|
580 |
// WOD options
|
581 |
// -------------
|
582 |
$wod = [
|
|
|
583 |
'enable-redirection-to-converter' => $config['enable-redirection-to-converter'],
|
584 |
'enable-redirection-to-webp-realizer' => $config['enable-redirection-to-webp-realizer'],
|
585 |
'base-htaccess-on-these-capability-tests' => $config['base-htaccess-on-these-capability-tests'],
|
@@ -638,13 +651,46 @@ class Config
|
|
638 |
return (self::saveWodOptionsFile($options));
|
639 |
}
|
640 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
641 |
/**
|
642 |
*
|
643 |
* $rewriteRulesNeedsUpdate:
|
644 |
*/
|
645 |
public static function saveConfigurationAndHTAccess($config, $forceRuleUpdating = false)
|
646 |
{
|
647 |
-
|
648 |
// Important to do this check before saving config, because the method
|
649 |
// compares against existing config.
|
650 |
|
36 |
'cache-control-max-age' => 'one-week',
|
37 |
'cache-control-public' => false,
|
38 |
'scope' => ['themes', 'uploads'],
|
39 |
+
'enable-logging' => false,
|
40 |
+
'prevent-using-webps-larger-than-original' => true,
|
41 |
|
42 |
// redirection rules
|
43 |
'enable-redirection-to-converter' => true,
|
157 |
return $config;
|
158 |
}
|
159 |
|
160 |
+
/**
|
161 |
+
* Fix config.
|
162 |
+
*
|
163 |
+
* Among other things, the config is merged with default config, to ensure all options are present
|
164 |
+
*
|
165 |
+
*/
|
166 |
public static function fix($config, $checkQualityDetection = true)
|
167 |
{
|
168 |
if ($config === false) {
|
420 |
$obj['destination-structure'] = $config['destination-structure'];
|
421 |
$obj['scope'] = $config['scope'];
|
422 |
$obj['image-types'] = $config['image-types']; // 0=none,1=jpg, 2=png, 3=both
|
423 |
+
$obj['prevent-using-webps-larger-than-original'] = $config['prevent-using-webps-larger-than-original'];
|
424 |
|
425 |
Option::updateOption(
|
426 |
'webp-express-alter-html-options',
|
429 |
);
|
430 |
}
|
431 |
|
432 |
+
/**
|
433 |
+
* Save configuration file. Also updates autoloaded options (such as alter html options)
|
434 |
+
*/
|
435 |
public static function saveConfigurationFile($config)
|
436 |
{
|
437 |
$config['paths-used-in-htaccess'] = [
|
592 |
// WOD options
|
593 |
// -------------
|
594 |
$wod = [
|
595 |
+
'enable-logging' => $config['enable-logging'],
|
596 |
'enable-redirection-to-converter' => $config['enable-redirection-to-converter'],
|
597 |
'enable-redirection-to-webp-realizer' => $config['enable-redirection-to-webp-realizer'],
|
598 |
'base-htaccess-on-these-capability-tests' => $config['base-htaccess-on-these-capability-tests'],
|
651 |
return (self::saveWodOptionsFile($options));
|
652 |
}
|
653 |
|
654 |
+
/**
|
655 |
+
* Regenerate config and .htaccess files
|
656 |
+
*
|
657 |
+
* It will only happen if configuration file exists. So the method is meant for updating - ie upon migration.
|
658 |
+
* It updates:
|
659 |
+
* - config files (both) - and ensures that capability tests have been run
|
660 |
+
* - autoloaded options (such as alter html options)
|
661 |
+
* - .htaccess files (all)
|
662 |
+
*/
|
663 |
+
public static function regenerateConfigAndHtaccessFiles() {
|
664 |
+
self::regenerateConfig(true);
|
665 |
+
}
|
666 |
+
|
667 |
+
/**
|
668 |
+
* Regenerate config and .htaccess files
|
669 |
+
*
|
670 |
+
* It will only happen if configuration file exists. So the method is meant for updating - ie upon migration.
|
671 |
+
* It updates:
|
672 |
+
* - config files (both) - and ensures that capability tests have been run
|
673 |
+
* - autoloaded options (such as alter html options)
|
674 |
+
* - .htaccess files - but only if needed due to configuration changes
|
675 |
+
*/
|
676 |
+
public static function regenerateConfig($forceRuleUpdating = false) {
|
677 |
+
if (!self::isConfigFileThere()) {
|
678 |
+
return;
|
679 |
+
}
|
680 |
+
$config = self::loadConfig();
|
681 |
+
$config = self::fix($config, false); // fix. We do not need examining if quality detection is working
|
682 |
+
if ($config === false) {
|
683 |
+
return;
|
684 |
+
}
|
685 |
+
self::saveConfigurationAndHTAccess($config, $forceRuleUpdating);
|
686 |
+
}
|
687 |
+
|
688 |
/**
|
689 |
*
|
690 |
* $rewriteRulesNeedsUpdate:
|
691 |
*/
|
692 |
public static function saveConfigurationAndHTAccess($config, $forceRuleUpdating = false)
|
693 |
{
|
|
|
694 |
// Important to do this check before saving config, because the method
|
695 |
// compares against existing config.
|
696 |
|
@@ -32,6 +32,24 @@ class Convert
|
|
32 |
);
|
33 |
}
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
public static function convertFile($source, $config = null, $convertOptions = null, $converter = null)
|
36 |
{
|
37 |
try {
|
@@ -84,7 +102,11 @@ class Convert
|
|
84 |
// Check log dir
|
85 |
// -------------------------------
|
86 |
$checking = 'conversion log dir';
|
87 |
-
|
|
|
|
|
|
|
|
|
88 |
|
89 |
|
90 |
} catch (\Exception $e) {
|
@@ -113,6 +135,7 @@ class Convert
|
|
113 |
}
|
114 |
//}
|
115 |
|
|
|
116 |
|
117 |
if ($result['success'] === true) {
|
118 |
$result['filesize-original'] = @filesize($source);
|
32 |
);
|
33 |
}
|
34 |
|
35 |
+
public static function updateBiggerThanOriginalMark($source, $destination = null, &$config = null)
|
36 |
+
{
|
37 |
+
if (is_null($config)) {
|
38 |
+
$config = Config::loadConfigAndFix();
|
39 |
+
}
|
40 |
+
if (is_null($destination)) {
|
41 |
+
$destination = self::getDestination($config);
|
42 |
+
}
|
43 |
+
BiggerThanSourceDummyFiles::updateStatus(
|
44 |
+
$source,
|
45 |
+
$destination,
|
46 |
+
Paths::getWebPExpressContentDirAbs(),
|
47 |
+
new ImageRoots(Paths::getImageRootsDef()),
|
48 |
+
$config['destination-folder'],
|
49 |
+
$config['destination-extension']
|
50 |
+
);
|
51 |
+
}
|
52 |
+
|
53 |
public static function convertFile($source, $config = null, $convertOptions = null, $converter = null)
|
54 |
{
|
55 |
try {
|
102 |
// Check log dir
|
103 |
// -------------------------------
|
104 |
$checking = 'conversion log dir';
|
105 |
+
if (isset($config['enable-logging']) && $config['enable-logging']) {
|
106 |
+
$logDir = SanityCheck::absPath(Paths::getWebPExpressContentDirAbs() . '/log');
|
107 |
+
} else {
|
108 |
+
$logDir = null;
|
109 |
+
}
|
110 |
|
111 |
|
112 |
} catch (\Exception $e) {
|
135 |
}
|
136 |
//}
|
137 |
|
138 |
+
self::updateBiggerThanOriginalMark($source, $destination, $config);
|
139 |
|
140 |
if ($result['success'] === true) {
|
141 |
$result['filesize-original'] = @filesize($source);
|
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
/*
|
4 |
This class is made to not be dependent on Wordpress functions and must be kept like that.
|
5 |
-
It is used by webp-on-demand.php
|
6 |
*/
|
7 |
namespace WebPExpress;
|
8 |
|
@@ -77,8 +77,8 @@ class ConvertHelperIndependent
|
|
77 |
/**
|
78 |
* Get destination path corresponding to the source path given (and some configurations)
|
79 |
*
|
80 |
-
*
|
81 |
-
*
|
82 |
*
|
83 |
* @param string $source Path to source file
|
84 |
* @param string $destinationFolder 'mingled' or 'separate'
|
@@ -571,7 +571,7 @@ APACHE
|
|
571 |
$text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
|
572 |
|
573 |
// TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
|
574 |
-
$text = 'WebP Express 0.
|
575 |
|
576 |
$logFile = self::getLogFilename($source, $logDir);
|
577 |
|
@@ -596,10 +596,10 @@ APACHE
|
|
596 |
* @param string $source Full path to the source file that was converted.
|
597 |
* @param string $destination Full path to the destination file (may exist or not).
|
598 |
* @param array $convertOptions Conversion options.
|
599 |
-
* @param string $logDir The folder where log files are kept
|
600 |
* @param string $converter (optional) Set it to convert with a specific converter.
|
601 |
*/
|
602 |
-
public static function convert($source, $destination, $convertOptions, $logDir, $converter = null) {
|
603 |
include_once __DIR__ . '/../../vendor/autoload.php';
|
604 |
|
605 |
// At this point, everything has already been checked for sanity. But for good meassure, lets
|
@@ -620,7 +620,9 @@ APACHE
|
|
620 |
|
621 |
// Check that log path is sane and inside document root
|
622 |
// -------------------------------------------------------
|
623 |
-
|
|
|
|
|
624 |
|
625 |
|
626 |
// PS: No need to check $logMsgTop. Log files are markdown and stored as ".md". They can do no harm.
|
@@ -658,7 +660,9 @@ APACHE
|
|
658 |
//$msg = 'oh no';
|
659 |
}
|
660 |
|
661 |
-
|
|
|
|
|
662 |
|
663 |
return [
|
664 |
'success' => $success,
|
@@ -672,7 +676,7 @@ APACHE
|
|
672 |
* Serve a converted file (if it does not already exist, a conversion is triggered - all handled in webp-convert).
|
673 |
*
|
674 |
*/
|
675 |
-
public static function serveConverted($source, $destination, $serveOptions, $logDir, $logMsgTop = '')
|
676 |
{
|
677 |
include_once __DIR__ . '/../../vendor/autoload.php';
|
678 |
|
@@ -697,8 +701,9 @@ APACHE
|
|
697 |
// Check that log path is sane
|
698 |
// -------------------------------------------------------
|
699 |
//$logDir = SanityCheck::absPathIsInDocRoot($logDir);
|
700 |
-
$logDir
|
701 |
-
|
|
|
702 |
|
703 |
// PS: No need to check $logMsgTop. Log files are markdown and stored as ".md". They can do no harm.
|
704 |
|
@@ -712,10 +717,11 @@ APACHE
|
|
712 |
|
713 |
$convertLogger = new BufferLogger();
|
714 |
WebPConvert::serveConverted($source, $destination, $serveOptions, null, $convertLogger);
|
715 |
-
|
716 |
-
|
717 |
-
|
|
|
|
|
718 |
}
|
719 |
-
|
720 |
}
|
721 |
}
|
2 |
|
3 |
/*
|
4 |
This class is made to not be dependent on Wordpress functions and must be kept like that.
|
5 |
+
It is used by webp-on-demand.php. It is also used for bulk conversion.
|
6 |
*/
|
7 |
namespace WebPExpress;
|
8 |
|
77 |
/**
|
78 |
* Get destination path corresponding to the source path given (and some configurations)
|
79 |
*
|
80 |
+
* If for example Operation mode is set to "mingled" and extension is set to "Append .webp",
|
81 |
+
* the result of finding the destination path that corresponds to "/path/to/logo.jpg" will be "/path/to/logo.jpg.webp".
|
82 |
*
|
83 |
* @param string $source Path to source file
|
84 |
* @param string $destinationFolder 'mingled' or 'separate'
|
571 |
$text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
|
572 |
|
573 |
// TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
|
574 |
+
$text = 'WebP Express 0.22.0. ' . $msgTop . ', ' . date("Y-m-d H:i:s") . "\n\r\n\r" . $text;
|
575 |
|
576 |
$logFile = self::getLogFilename($source, $logDir);
|
577 |
|
596 |
* @param string $source Full path to the source file that was converted.
|
597 |
* @param string $destination Full path to the destination file (may exist or not).
|
598 |
* @param array $convertOptions Conversion options.
|
599 |
+
* @param string $logDir The folder where log files are kept or null for no logging
|
600 |
* @param string $converter (optional) Set it to convert with a specific converter.
|
601 |
*/
|
602 |
+
public static function convert($source, $destination, $convertOptions, $logDir = null, $converter = null) {
|
603 |
include_once __DIR__ . '/../../vendor/autoload.php';
|
604 |
|
605 |
// At this point, everything has already been checked for sanity. But for good meassure, lets
|
620 |
|
621 |
// Check that log path is sane and inside document root
|
622 |
// -------------------------------------------------------
|
623 |
+
if (!is_null($logDir)) {
|
624 |
+
$logDir = SanityCheck::absPathIsInDocRoot($logDir);
|
625 |
+
}
|
626 |
|
627 |
|
628 |
// PS: No need to check $logMsgTop. Log files are markdown and stored as ".md". They can do no harm.
|
660 |
//$msg = 'oh no';
|
661 |
}
|
662 |
|
663 |
+
if (!is_null($logDir)) {
|
664 |
+
self::saveLog($source, $logDir, $logger->getMarkDown("\n\r"), 'Conversion triggered using bulk conversion');
|
665 |
+
}
|
666 |
|
667 |
return [
|
668 |
'success' => $success,
|
676 |
* Serve a converted file (if it does not already exist, a conversion is triggered - all handled in webp-convert).
|
677 |
*
|
678 |
*/
|
679 |
+
public static function serveConverted($source, $destination, $serveOptions, $logDir = null, $logMsgTop = '')
|
680 |
{
|
681 |
include_once __DIR__ . '/../../vendor/autoload.php';
|
682 |
|
701 |
// Check that log path is sane
|
702 |
// -------------------------------------------------------
|
703 |
//$logDir = SanityCheck::absPathIsInDocRoot($logDir);
|
704 |
+
if ($logDir != null) {
|
705 |
+
$logDir = SanityCheck::absPath($logDir);
|
706 |
+
}
|
707 |
|
708 |
// PS: No need to check $logMsgTop. Log files are markdown and stored as ".md". They can do no harm.
|
709 |
|
717 |
|
718 |
$convertLogger = new BufferLogger();
|
719 |
WebPConvert::serveConverted($source, $destination, $serveOptions, null, $convertLogger);
|
720 |
+
if (!is_null($logDir)) {
|
721 |
+
$convertLog = $convertLogger->getMarkDown("\n\r");
|
722 |
+
if ($convertLog != '') {
|
723 |
+
self::saveLog($source, $logDir, $convertLog, $logMsgTop);
|
724 |
+
}
|
725 |
}
|
|
|
726 |
}
|
727 |
}
|
@@ -74,6 +74,25 @@ class HTAccessRules
|
|
74 |
return false;
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
/**
|
78 |
* Decides if .htaccess rules needs to be updated.
|
79 |
*
|
@@ -122,7 +141,8 @@ class HTAccessRules
|
|
122 |
'destination-folder' => 'separate',
|
123 |
'destination-extension' => 'append',
|
124 |
'destination-structure' => 'doc-root',
|
125 |
-
'scope' => ['themes', 'uploads']
|
|
|
126 |
];
|
127 |
|
128 |
// If one of the props have changed, we need to update.
|
@@ -277,7 +297,6 @@ class HTAccessRules
|
|
277 |
{
|
278 |
$rules = '';
|
279 |
|
280 |
-
|
281 |
if (self::$mingled) {
|
282 |
// TODO:
|
283 |
// Only write mingled rules for "uploads" dir.
|
@@ -440,6 +459,8 @@ class HTAccessRules
|
|
440 |
$params[] = "wp-content=" . Paths::getContentDirRel();
|
441 |
}
|
442 |
|
|
|
|
|
443 |
$rewriteRuleStart = '^/?(.+)';
|
444 |
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ " .
|
445 |
"/" . self::getWebPRealizerUrlPath() .
|
@@ -458,7 +479,8 @@ class HTAccessRules
|
|
458 |
$flags = [];
|
459 |
|
460 |
if (!self::$passThroughEnvVarDefinitelyUnavailable) {
|
461 |
-
|
|
|
462 |
$flags[] = 'E=WE_DESTINATION_REL_HTACCESS:$0';
|
463 |
$flags[] = 'E=WE_HTACCESS_ID:' . self::$htaccessDir; // this will btw either be "uploads" or "cache"
|
464 |
}
|
@@ -466,7 +488,8 @@ class HTAccessRules
|
|
466 |
$flags[] = 'L';
|
467 |
|
468 |
if (!self::$passThroughEnvVarDefinitelyAvailable) {
|
469 |
-
|
|
|
470 |
$params[] = 'xdestination-rel-htaccess=x$0';
|
471 |
$params[] = 'htaccess-id=' . self::$htaccessDir;
|
472 |
}
|
@@ -643,9 +666,9 @@ class HTAccessRules
|
|
643 |
|
644 |
/*
|
645 |
Create something like this:
|
646 |
-
|
647 |
RewriteCond %{REQUEST_FILENAME} -f
|
648 |
-
|
|
|
649 |
*/
|
650 |
|
651 |
// Making sure the source exists
|
@@ -655,7 +678,8 @@ class HTAccessRules
|
|
655 |
$flags = [];
|
656 |
|
657 |
if (!self::$passThroughEnvVarDefinitelyUnavailable) {
|
658 |
-
|
|
|
659 |
$flags[] = 'E=WE_SOURCE_REL_HTACCESS:$0';
|
660 |
$flags[] = 'E=WE_HTACCESS_ID:' . self::$htaccessDir; // this will btw be one of the image roots. It will not be "cache"
|
661 |
}
|
@@ -663,16 +687,25 @@ class HTAccessRules
|
|
663 |
$flags[] = 'L';
|
664 |
|
665 |
if (!self::$passThroughEnvVarDefinitelyAvailable) {
|
666 |
-
|
|
|
667 |
$params[] = 'xsource-rel-htaccess=x$0';
|
668 |
$params[] = 'htaccess-id=' . self::$htaccessDir;
|
669 |
}
|
670 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
671 |
// self::$appendWebP cannot be used, we need the following in order for
|
672 |
// it to work for uploads in: Mingled, "Set to WebP", "Image roots".
|
673 |
// TODO! Will it work for ie theme images?
|
674 |
// - well, it should, because the script is passed $0. Not matching the ".png" part of the filename
|
675 |
// only means it is a bit more greedy than it has to
|
|
|
676 |
$appendWebP = !(self::$config['destination-extension'] == 'set');
|
677 |
|
678 |
$rules .= " RewriteRule (?i).*" . ($appendWebP ? "(" . self::$fileExtIncludingDot . ")" : "") . "$ " .
|
@@ -680,7 +713,7 @@ class HTAccessRules
|
|
680 |
(count($params) > 0 ? "?" . implode('&', $params) : "") .
|
681 |
" [" . implode(',', $flags) . "]\n";
|
682 |
|
683 |
-
|
684 |
/*
|
685 |
*/
|
686 |
|
@@ -849,6 +882,10 @@ class HTAccessRules
|
|
849 |
self::$modHeaderDefinitelyUnavailable = ($capTests['modHeaderWorking'] === false);
|
850 |
self::$passThroughHeaderDefinitelyUnavailable = ($capTests['passThroughHeaderWorking'] === false);
|
851 |
self::$passThroughHeaderDefinitelyAvailable = ($capTests['passThroughHeaderWorking'] === true);
|
|
|
|
|
|
|
|
|
852 |
self::$canDefinitelyRunTestScriptInWOD = ($capTests['canRunTestScriptInWOD'] === true);
|
853 |
self::$canDefinitelyRunTestScriptInWOD2 = ($capTests['canRunTestScriptInWOD2'] === true);
|
854 |
|
@@ -1016,6 +1053,40 @@ class HTAccessRules
|
|
1016 |
$rules .= "<IfModule mod_rewrite.c>\n" .
|
1017 |
" RewriteEngine On\n\n";
|
1018 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1019 |
if (self::$config['redirect-to-existing-in-htaccess']) {
|
1020 |
$rules .= self::redirectToExistingRules();
|
1021 |
}
|
74 |
return false;
|
75 |
}
|
76 |
|
77 |
+
/**
|
78 |
+
*
|
79 |
+
* Note that server variables are only allowed some places in the .htaccess.
|
80 |
+
* It is for example not allowed in CondPattern so something like this will not work:
|
81 |
+
* RewriteCond %{REQUEST_FILENAME} (?i)(%{DOCUMENT_ROOT}/wordpress/wp-content/themes/)(.*)(\.jpe?g|\.png)$
|
82 |
+
*/
|
83 |
+
private static function replaceDocRootWithApacheTokenIfDocRootAvailable($absPath)
|
84 |
+
{
|
85 |
+
// TODO: I would like to test this thoroughly before using so we do nothing now:
|
86 |
+
return $absPath;
|
87 |
+
|
88 |
+
if (PathHelper::isDocRootAvailable()) {
|
89 |
+
if (strpos($absPath, $_SERVER['DOCUMENT_ROOT']) === 0) {
|
90 |
+
return "%{DOCUMENT_ROOT}" . substr($absPath, strlen($_SERVER['DOCUMENT_ROOT']));
|
91 |
+
}
|
92 |
+
}
|
93 |
+
return $absPath;
|
94 |
+
}
|
95 |
+
|
96 |
/**
|
97 |
* Decides if .htaccess rules needs to be updated.
|
98 |
*
|
141 |
'destination-folder' => 'separate',
|
142 |
'destination-extension' => 'append',
|
143 |
'destination-structure' => 'doc-root',
|
144 |
+
'scope' => ['themes', 'uploads'],
|
145 |
+
'prevent-using-webps-larger-than-original' => true,
|
146 |
];
|
147 |
|
148 |
// If one of the props have changed, we need to update.
|
297 |
{
|
298 |
$rules = '';
|
299 |
|
|
|
300 |
if (self::$mingled) {
|
301 |
// TODO:
|
302 |
// Only write mingled rules for "uploads" dir.
|
459 |
$params[] = "wp-content=" . Paths::getContentDirRel();
|
460 |
}
|
461 |
|
462 |
+
// When matching from the beginning (^), we need the "/?" in order to make it work on litespeed too.
|
463 |
+
// Here is why: https://openlitespeed.org/kb/apache-rewrite-rules-in-openlitespeed/
|
464 |
$rewriteRuleStart = '^/?(.+)';
|
465 |
$rules .= " RewriteRule " . $rewriteRuleStart . "\.(webp)$ " .
|
466 |
"/" . self::getWebPRealizerUrlPath() .
|
479 |
$flags = [];
|
480 |
|
481 |
if (!self::$passThroughEnvVarDefinitelyUnavailable) {
|
482 |
+
//$flags[] = 'E=WE_WP_CONTENT_REL_TO_PLUGIN_DIR:' . Paths::getContentDirRelToPluginDir();
|
483 |
+
$flags[] = 'E=WE_WP_CONTENT_REL_TO_WE_PLUGIN_DIR:' . Paths::getContentDirRelToWebPExpressPluginDir();
|
484 |
$flags[] = 'E=WE_DESTINATION_REL_HTACCESS:$0';
|
485 |
$flags[] = 'E=WE_HTACCESS_ID:' . self::$htaccessDir; // this will btw either be "uploads" or "cache"
|
486 |
}
|
488 |
$flags[] = 'L';
|
489 |
|
490 |
if (!self::$passThroughEnvVarDefinitelyAvailable) {
|
491 |
+
//$params[] = 'xwp-content-rel-to-plugin-dir=x' . Paths::getContentDirRelToPluginDir();
|
492 |
+
$params[] = 'xwp-content-rel-to-we-plugin-dir=x' . Paths::getContentDirRelToWebPExpressPluginDir();
|
493 |
$params[] = 'xdestination-rel-htaccess=x$0';
|
494 |
$params[] = 'htaccess-id=' . self::$htaccessDir;
|
495 |
}
|
666 |
|
667 |
/*
|
668 |
Create something like this:
|
|
|
669 |
RewriteCond %{REQUEST_FILENAME} -f
|
670 |
+
RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$
|
671 |
+
RewriteRule (?i).*$ /wordpress/wp-content/plugins/webp-express/wod/webp-on-demand.php [E=WE_WP_CONTENT_REL_TO_WE_PLUGIN_DIR:../..,E=WE_SOURCE_REL_HTACCESS:$0,E=WE_HTACCESS_ID:uploads,NC,L]
|
672 |
*/
|
673 |
|
674 |
// Making sure the source exists
|
678 |
$flags = [];
|
679 |
|
680 |
if (!self::$passThroughEnvVarDefinitelyUnavailable) {
|
681 |
+
//$flags[] = 'E=WE_WP_CONTENT_REL_TO_PLUGIN_DIR:' . Paths::getContentDirRelToPluginDir();
|
682 |
+
$flags[] = 'E=WE_WP_CONTENT_REL_TO_WE_PLUGIN_DIR:' . Paths::getContentDirRelToWebPExpressPluginDir();
|
683 |
$flags[] = 'E=WE_SOURCE_REL_HTACCESS:$0';
|
684 |
$flags[] = 'E=WE_HTACCESS_ID:' . self::$htaccessDir; // this will btw be one of the image roots. It will not be "cache"
|
685 |
}
|
687 |
$flags[] = 'L';
|
688 |
|
689 |
if (!self::$passThroughEnvVarDefinitelyAvailable) {
|
690 |
+
//$params[] = 'xwp-content-rel-to-plugin-dir=x' . Paths::getContentDirRelToPluginDir();
|
691 |
+
$params[] = 'xwp-content-rel-to-we-plugin-dir=x' . Paths::getContentDirRelToWebPExpressPluginDir();
|
692 |
$params[] = 'xsource-rel-htaccess=x$0';
|
693 |
$params[] = 'htaccess-id=' . self::$htaccessDir;
|
694 |
}
|
695 |
|
696 |
+
$rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(.*)(" . self::$fileExtIncludingDot . ")$\n";
|
697 |
+
|
698 |
+
$rules .= " RewriteRule (?i).*$ " .
|
699 |
+
"/" . self::getWodUrlPath() .
|
700 |
+
(count($params) > 0 ? "?" . implode('&', $params) : "") .
|
701 |
+
" [" . implode(',', $flags) . "]\n";
|
702 |
+
|
703 |
// self::$appendWebP cannot be used, we need the following in order for
|
704 |
// it to work for uploads in: Mingled, "Set to WebP", "Image roots".
|
705 |
// TODO! Will it work for ie theme images?
|
706 |
// - well, it should, because the script is passed $0. Not matching the ".png" part of the filename
|
707 |
// only means it is a bit more greedy than it has to
|
708 |
+
/*
|
709 |
$appendWebP = !(self::$config['destination-extension'] == 'set');
|
710 |
|
711 |
$rules .= " RewriteRule (?i).*" . ($appendWebP ? "(" . self::$fileExtIncludingDot . ")" : "") . "$ " .
|
713 |
(count($params) > 0 ? "?" . implode('&', $params) : "") .
|
714 |
" [" . implode(',', $flags) . "]\n";
|
715 |
|
716 |
+
*/
|
717 |
/*
|
718 |
*/
|
719 |
|
882 |
self::$modHeaderDefinitelyUnavailable = ($capTests['modHeaderWorking'] === false);
|
883 |
self::$passThroughHeaderDefinitelyUnavailable = ($capTests['passThroughHeaderWorking'] === false);
|
884 |
self::$passThroughHeaderDefinitelyAvailable = ($capTests['passThroughHeaderWorking'] === true);
|
885 |
+
|
886 |
+
self::$passThroughEnvVarDefinitelyUnavailable = ($capTests['passThroughEnvWorking'] === false);
|
887 |
+
self::$passThroughEnvVarDefinitelyAvailable = ($capTests['passThroughEnvWorking'] === true);
|
888 |
+
|
889 |
self::$canDefinitelyRunTestScriptInWOD = ($capTests['canRunTestScriptInWOD'] === true);
|
890 |
self::$canDefinitelyRunTestScriptInWOD2 = ($capTests['canRunTestScriptInWOD2'] === true);
|
891 |
|
1053 |
$rules .= "<IfModule mod_rewrite.c>\n" .
|
1054 |
" RewriteEngine On\n\n";
|
1055 |
|
1056 |
+
$rules .= " # Escape hatch #1: Adding ?original to an url can be used to bypass redirection\n";
|
1057 |
+
$rules .= " RewriteCond %{QUERY_STRING} original$\n";
|
1058 |
+
$rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
|
1059 |
+
$rules .= " RewriteRule . - [L]\n\n";
|
1060 |
+
|
1061 |
+
$rules .= " # Escape hatch #2: Placing an empty file in the same folder as the jpeg/png which has same file name, but \".do-not-convert\" appended will bypass redirection\n";
|
1062 |
+
$rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$\n";
|
1063 |
+
$rules .= " RewriteCond %1%2\.do-not-convert -f\n";
|
1064 |
+
$rules .= " RewriteRule . - [L]\n\n";
|
1065 |
+
|
1066 |
+
if ($config['prevent-using-webps-larger-than-original']) {
|
1067 |
+
$rules .= " # Avoid redirecting to webp files that are bigger than the original\n";
|
1068 |
+
$rules .= " RewriteCond %{REQUEST_FILENAME} -f\n";
|
1069 |
+
|
1070 |
+
// Find relative path of source (accessible as %2%3)
|
1071 |
+
$rules .= " RewriteCond %{REQUEST_FILENAME} (?i)(" . self::$htaccessDirAbs . "/)(.*)(" .self::$fileExtIncludingDot . ")$\n";
|
1072 |
+
|
1073 |
+
// Check if dummy file exists
|
1074 |
+
$cacheDirForThisRoot = PathHelper::fixAbsPathToUseUnresolvedDocRoot(
|
1075 |
+
Paths::getBiggerThanSourceDirAbs() . '/' . self::$htaccessDir
|
1076 |
+
);
|
1077 |
+
$rules .= " RewriteCond " .
|
1078 |
+
self::replaceDocRootWithApacheTokenIfDocRootAvailable($cacheDirForThisRoot) .
|
1079 |
+
"/%2%3.webp -f\n";
|
1080 |
+
|
1081 |
+
$rules .= " RewriteRule . - [L]\n\n";
|
1082 |
+
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
// In the future, we could let user add exeptions in UI. Also for folders
|
1086 |
+
// in order to make this work for folders, we will need to update the .htaccess
|
1087 |
+
// and list the exceptions here with rules like this:
|
1088 |
+
// RewriteRule ^uploads/2021/06/ - [L]
|
1089 |
+
|
1090 |
if (self::$config['redirect-to-existing-in-htaccess']) {
|
1091 |
$rules .= self::redirectToExistingRules();
|
1092 |
}
|
@@ -20,12 +20,16 @@ class HandleDeleteFileHook
|
|
20 |
return $filename;
|
21 |
}
|
22 |
|
23 |
-
$
|
|
|
24 |
if (@file_exists($destination)) {
|
25 |
-
if (
|
|
|
|
|
26 |
error_log('WebP Express failed deleting webp:' . $destination);
|
27 |
-
}
|
28 |
}
|
|
|
29 |
return $filename;
|
30 |
}
|
31 |
}
|
20 |
return $filename;
|
21 |
}
|
22 |
|
23 |
+
$config = Config::loadConfigAndFix();
|
24 |
+
$destination = Convert::getDestination($filename, $config);
|
25 |
if (@file_exists($destination)) {
|
26 |
+
if (@unlink($destination)) {
|
27 |
+
Convert::updateBiggerThanOriginalMark($filename, $destination, $config);
|
28 |
+
} else {
|
29 |
error_log('WebP Express failed deleting webp:' . $destination);
|
30 |
+
}
|
31 |
}
|
32 |
+
|
33 |
return $filename;
|
34 |
}
|
35 |
}
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
class LogPurge
|
6 |
+
{
|
7 |
+
|
8 |
+
/**
|
9 |
+
* - Removes cache dir
|
10 |
+
* - Removes all files with ".webp" extension in upload dir (if set to mingled)
|
11 |
+
*/
|
12 |
+
public static function purge()
|
13 |
+
{
|
14 |
+
DismissableMessages::dismissMessage('0.14.0/suggest-wipe-because-lossless');
|
15 |
+
|
16 |
+
$filter = [
|
17 |
+
'only-png' => $onlyPng,
|
18 |
+
'only-with-corresponding-original' => false
|
19 |
+
];
|
20 |
+
|
21 |
+
$numDeleted = 0;
|
22 |
+
$numFailed = 0;
|
23 |
+
|
24 |
+
$dir = Paths::getLogDirAbs();
|
25 |
+
list($numDeleted, $numFailed) = self::purgeLogFilesInDir($dir);
|
26 |
+
FileHelper::removeEmptySubFolders($dir);
|
27 |
+
|
28 |
+
return [
|
29 |
+
'delete-count' => $numDeleted,
|
30 |
+
'fail-count' => $numFailed
|
31 |
+
];
|
32 |
+
|
33 |
+
//$successInRemovingCacheDir = FileHelper::rrmdir(Paths::getCacheDirAbs());
|
34 |
+
|
35 |
+
}
|
36 |
+
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Purge log files in a dir
|
40 |
+
*
|
41 |
+
* @return [num files deleted, num files failed to delete]
|
42 |
+
*/
|
43 |
+
private static function purgeLogFilesInDir($dir)
|
44 |
+
{
|
45 |
+
if (!@file_exists($dir) || !@is_dir($dir)) {
|
46 |
+
return [0, 0];
|
47 |
+
}
|
48 |
+
|
49 |
+
$numFilesDeleted = 0;
|
50 |
+
$numFilesFailedDeleting = 0;
|
51 |
+
|
52 |
+
$fileIterator = new \FilesystemIterator($dir);
|
53 |
+
while ($fileIterator->valid()) {
|
54 |
+
$filename = $fileIterator->getFilename();
|
55 |
+
|
56 |
+
if (($filename != ".") && ($filename != "..")) {
|
57 |
+
|
58 |
+
if (@is_dir($dir . "/" . $filename)) {
|
59 |
+
list($r1, $r2) = self::purgeLogFilesInDir($dir . "/" . $filename);
|
60 |
+
$numFilesDeleted += $r1;
|
61 |
+
$numFilesFailedDeleting += $r2;
|
62 |
+
} else {
|
63 |
+
|
64 |
+
// its a file
|
65 |
+
// Run through filters, which each may set "skipThis" to true
|
66 |
+
|
67 |
+
$skipThis = false;
|
68 |
+
|
69 |
+
// filter: It must have ".md" extension
|
70 |
+
if (!$skipThis && !preg_match('#\.md$#', $filename)) {
|
71 |
+
$skipThis = true;
|
72 |
+
}
|
73 |
+
|
74 |
+
if (!$skipThis) {
|
75 |
+
if (@unlink($dir . "/" . $filename)) {
|
76 |
+
$numFilesDeleted++;
|
77 |
+
} else {
|
78 |
+
$numFilesFailedDeleting++;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
82 |
+
}
|
83 |
+
$fileIterator->next();
|
84 |
+
}
|
85 |
+
return [$numFilesDeleted, $numFilesFailedDeleting];
|
86 |
+
}
|
87 |
+
|
88 |
+
public static function processAjaxPurgeLog()
|
89 |
+
{
|
90 |
+
|
91 |
+
if (!check_ajax_referer('webpexpress-ajax-purge-log-nonce', 'nonce', false)) {
|
92 |
+
wp_send_json_error('The security nonce has expired. You need to reload the settings page (press F5) and try again)');
|
93 |
+
wp_die();
|
94 |
+
}
|
95 |
+
$result = self::purge($config);
|
96 |
+
echo json_encode($result, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
|
97 |
+
wp_die();
|
98 |
+
}
|
99 |
+
}
|
@@ -7,7 +7,9 @@ class PathHelper
|
|
7 |
|
8 |
public static function isDocRootAvailable() {
|
9 |
|
10 |
-
//
|
|
|
|
|
11 |
|
12 |
if (!isset($_SERVER['DOCUMENT_ROOT'])) {
|
13 |
return false;
|
@@ -43,6 +45,17 @@ class PathHelper
|
|
43 |
);
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
public static function fixAbsPathToUseUnresolvedDocRoot($absPath) {
|
47 |
if (self::isDocRootAvailableAndResolvable()) {
|
48 |
if (strpos($absPath, realpath($_SERVER['DOCUMENT_ROOT'])) === 0) {
|
7 |
|
8 |
public static function isDocRootAvailable() {
|
9 |
|
10 |
+
// BTW:
|
11 |
+
// Note that DOCUMENT_ROOT does not end with trailing slash on old litespeed servers:
|
12 |
+
// https://www.litespeedtech.com/support/forum/threads/document_root-trailing-slash.5304/
|
13 |
|
14 |
if (!isset($_SERVER['DOCUMENT_ROOT'])) {
|
15 |
return false;
|
45 |
);
|
46 |
}
|
47 |
|
48 |
+
/**
|
49 |
+
* When the rewrite rules are using the absolute dir, the rewrite rules does not work if that dir
|
50 |
+
* is outside document root. This poses a problem if some part of the document root has been symlinked.
|
51 |
+
*
|
52 |
+
* This method "unresolves" the document root part of a dir.
|
53 |
+
* That is: It takes an absolute url, looks to see if it begins with the resolved document root.
|
54 |
+
* In case it does, it replaces the resolved document root with the unresolved document root.
|
55 |
+
*
|
56 |
+
* Unfortunately we can only unresolve when document root is available and resolvable.
|
57 |
+
* - which is sad, because the image-roots was introduced in order to get it to work on setups
|
58 |
+
*/
|
59 |
public static function fixAbsPathToUseUnresolvedDocRoot($absPath) {
|
60 |
if (self::isDocRootAvailableAndResolvable()) {
|
61 |
if (strpos($absPath, realpath($_SERVER['DOCUMENT_ROOT'])) === 0) {
|
@@ -163,6 +163,12 @@ class Paths
|
|
163 |
return ['uploads', 'themes', 'plugins', 'wp-content', 'index'];
|
164 |
}
|
165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
public static function findImageRootOfPath($path, $rootIdsToSearch) {
|
167 |
foreach ($rootIdsToSearch as $rootId) {
|
168 |
if (PathHelper::isPathWithinExistingDirPath($path, self::getAbsDirById($rootId))) {
|
@@ -339,6 +345,10 @@ class Paths
|
|
339 |
{
|
340 |
return PathHelper::getRelDir(self::getPluginDirAbs(), self::getContentDirAbs());
|
341 |
}
|
|
|
|
|
|
|
|
|
342 |
|
343 |
|
344 |
public static function isWPContentDirMoved()
|
@@ -493,6 +503,13 @@ APACHE
|
|
493 |
return self::getWebPExpressContentDirAbs() . '/log';
|
494 |
}
|
495 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
// ------------ Plugin Dir (all plugins) -------------
|
497 |
|
498 |
public static function getPluginDirAbs()
|
163 |
return ['uploads', 'themes', 'plugins', 'wp-content', 'index'];
|
164 |
}
|
165 |
|
166 |
+
/**
|
167 |
+
* Find which rootId a path belongs to.
|
168 |
+
*
|
169 |
+
* Note: If the root ids passed are ordered the way getImageRootIds() returns them, the root id
|
170 |
+
* returned will be the "deepest"
|
171 |
+
*/
|
172 |
public static function findImageRootOfPath($path, $rootIdsToSearch) {
|
173 |
foreach ($rootIdsToSearch as $rootId) {
|
174 |
if (PathHelper::isPathWithinExistingDirPath($path, self::getAbsDirById($rootId))) {
|
345 |
{
|
346 |
return PathHelper::getRelDir(self::getPluginDirAbs(), self::getContentDirAbs());
|
347 |
}
|
348 |
+
public static function getContentDirRelToWebPExpressPluginDir()
|
349 |
+
{
|
350 |
+
return PathHelper::getRelDir(self::getWebPExpressPluginDirAbs(), self::getContentDirAbs());
|
351 |
+
}
|
352 |
|
353 |
|
354 |
public static function isWPContentDirMoved()
|
503 |
return self::getWebPExpressContentDirAbs() . '/log';
|
504 |
}
|
505 |
|
506 |
+
// ------------ Bigger-than-source dir -------------
|
507 |
+
|
508 |
+
public static function getBiggerThanSourceDirAbs()
|
509 |
+
{
|
510 |
+
return self::getWebPExpressContentDirAbs() . '/webp-images-bigger-than-source';
|
511 |
+
}
|
512 |
+
|
513 |
// ------------ Plugin Dir (all plugins) -------------
|
514 |
|
515 |
public static function getPluginDirAbs()
|
@@ -209,10 +209,11 @@ class WCFMApi
|
|
209 |
$rootId = array_shift($pathTokens); // Shift off the first item, which is the scope
|
210 |
$relPath = implode('/', $pathTokens);
|
211 |
$config = Config::loadConfigAndFix();
|
212 |
-
|
213 |
if (!in_array($rootId, $rootIds)) {
|
214 |
-
throw new \Exception('Invalid scope');
|
215 |
-
}
|
|
|
216 |
|
217 |
$absPath = Paths::getAbsDirById($rootId) . '/' . $relPath;
|
218 |
//absPathExistsAndIsFile
|
@@ -222,7 +223,7 @@ class WCFMApi
|
|
222 |
//'filename' => $absPath,
|
223 |
//'abspath' => $absPath,
|
224 |
'size' => filesize($absPath),
|
225 |
-
'url' => Paths::getUrlById($rootId) . '/' . $relPath,
|
226 |
]
|
227 |
];
|
228 |
|
@@ -249,7 +250,7 @@ class WCFMApi
|
|
249 |
$result['converted'] = [
|
250 |
'abspath' => $absPathDest,
|
251 |
'size' => filesize($absPathDest),
|
252 |
-
'url' => $destinationUrl,
|
253 |
'log' => ''
|
254 |
];
|
255 |
}
|
@@ -315,9 +316,9 @@ class WCFMApi
|
|
315 |
}
|
316 |
|
317 |
$config = Config::loadConfigAndFix();
|
318 |
-
$rootIds = Paths::
|
319 |
-
|
320 |
if ($path == '/') {
|
|
|
321 |
$result = ['children'=>[]];
|
322 |
foreach ($rootIds as $rootId) {
|
323 |
$result['children'][] = [
|
@@ -354,8 +355,8 @@ class WCFMApi
|
|
354 |
|
355 |
//throw new \Exception('Invalid rootId' . print_r($listOptions));
|
356 |
|
357 |
-
|
358 |
$list = BulkConvert::getListRecursively($relPath, $listOptions);
|
|
|
359 |
return ['children' => $list];
|
360 |
}
|
361 |
|
209 |
$rootId = array_shift($pathTokens); // Shift off the first item, which is the scope
|
210 |
$relPath = implode('/', $pathTokens);
|
211 |
$config = Config::loadConfigAndFix();
|
212 |
+
/*$rootIds = Paths::filterOutSubRoots($config['scope']);
|
213 |
if (!in_array($rootId, $rootIds)) {
|
214 |
+
throw new \Exception('Invalid scope (have you perhaps changed the scope setting after igniting the file manager?)');
|
215 |
+
}*/
|
216 |
+
$rootIds = $rootIds = Paths::getImageRootIds();
|
217 |
|
218 |
$absPath = Paths::getAbsDirById($rootId) . '/' . $relPath;
|
219 |
//absPathExistsAndIsFile
|
223 |
//'filename' => $absPath,
|
224 |
//'abspath' => $absPath,
|
225 |
'size' => filesize($absPath),
|
226 |
+
'url' => Paths::getUrlById($rootId) . '/' . $relPath . '?' . SelfTestHelper::randomDigitsAndLetters(8) . '&original',
|
227 |
]
|
228 |
];
|
229 |
|
250 |
$result['converted'] = [
|
251 |
'abspath' => $absPathDest,
|
252 |
'size' => filesize($absPathDest),
|
253 |
+
'url' => $destinationUrl . '?' . SelfTestHelper::randomDigitsAndLetters(8),
|
254 |
'log' => ''
|
255 |
];
|
256 |
}
|
316 |
}
|
317 |
|
318 |
$config = Config::loadConfigAndFix();
|
319 |
+
$rootIds = Paths::getImageRootIds();
|
|
|
320 |
if ($path == '/') {
|
321 |
+
$rootIds = Paths::filterOutSubRoots($config['scope']);
|
322 |
$result = ['children'=>[]];
|
323 |
foreach ($rootIds as $rootId) {
|
324 |
$result['children'][] = [
|
355 |
|
356 |
//throw new \Exception('Invalid rootId' . print_r($listOptions));
|
357 |
|
|
|
358 |
$list = BulkConvert::getListRecursively($relPath, $listOptions);
|
359 |
+
|
360 |
return ['children' => $list];
|
361 |
}
|
362 |
|
@@ -242,14 +242,26 @@ class WebPOnDemand extends WodConfigLoader
|
|
242 |
}
|
243 |
}
|
244 |
|
|
|
|
|
|
|
245 |
ConvertHelperIndependent::serveConverted(
|
246 |
$source,
|
247 |
$destination,
|
248 |
$serveOptions,
|
249 |
-
|
250 |
'Conversion triggered with the conversion script (wod/webp-on-demand.php)'
|
251 |
);
|
252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
self::fixConfigIfEwwwDiscoveredNonFunctionalApiKeys();
|
254 |
}
|
255 |
|
242 |
}
|
243 |
}
|
244 |
|
245 |
+
$loggingEnabled = (isset($wodOptions['enable-logging']) ? $wodOptions['enable-logging'] : true);
|
246 |
+
$logDir = ($loggingEnabled ? self::$webExpressContentDirAbs . '/log' : null);
|
247 |
+
|
248 |
ConvertHelperIndependent::serveConverted(
|
249 |
$source,
|
250 |
$destination,
|
251 |
$serveOptions,
|
252 |
+
$logDir,
|
253 |
'Conversion triggered with the conversion script (wod/webp-on-demand.php)'
|
254 |
);
|
255 |
|
256 |
+
BiggerThanSourceDummyFiles::updateStatus(
|
257 |
+
$source,
|
258 |
+
$destination,
|
259 |
+
self::$webExpressContentDirAbs,
|
260 |
+
self::getImageRootsDef(),
|
261 |
+
$wodOptions['destination-folder'],
|
262 |
+
$wodOptions['destination-extension']
|
263 |
+
);
|
264 |
+
|
265 |
self::fixConfigIfEwwwDiscoveredNonFunctionalApiKeys();
|
266 |
}
|
267 |
|
@@ -239,14 +239,26 @@ class WebPRealizer extends WodConfigLoader
|
|
239 |
$serveOptions['fail-when-fail-fails'] = '404';
|
240 |
$serveOptions['serve-image']['headers']['vary-accept'] = false;
|
241 |
|
|
|
|
|
|
|
242 |
ConvertHelperIndependent::serveConverted(
|
243 |
$source,
|
244 |
$destination,
|
245 |
$serveOptions,
|
246 |
-
|
247 |
'Conversion triggered with the conversion script (wod/webp-realizer.php)'
|
248 |
);
|
249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
self::fixConfigIfEwwwDiscoveredNonFunctionalApiKeys();
|
251 |
}
|
252 |
|
239 |
$serveOptions['fail-when-fail-fails'] = '404';
|
240 |
$serveOptions['serve-image']['headers']['vary-accept'] = false;
|
241 |
|
242 |
+
$loggingEnabled = (isset($wodOptions['enable-logging']) ? $wodOptions['enable-logging'] : true);
|
243 |
+
$logDir = ($loggingEnabled ? self::$webExpressContentDirAbs . '/log' : null);
|
244 |
+
|
245 |
ConvertHelperIndependent::serveConverted(
|
246 |
$source,
|
247 |
$destination,
|
248 |
$serveOptions,
|
249 |
+
$logDir,
|
250 |
'Conversion triggered with the conversion script (wod/webp-realizer.php)'
|
251 |
);
|
252 |
|
253 |
+
BiggerThanSourceDummyFiles::updateStatus(
|
254 |
+
$source,
|
255 |
+
$destination,
|
256 |
+
self::$webExpressContentDirAbs,
|
257 |
+
self::getImageRootsDef(),
|
258 |
+
$wodOptions['destination-folder'],
|
259 |
+
$wodOptions['destination-extension']
|
260 |
+
);
|
261 |
+
|
262 |
self::fixConfigIfEwwwDiscoveredNonFunctionalApiKeys();
|
263 |
}
|
264 |
|
@@ -119,31 +119,48 @@ class WodConfigLoader
|
|
119 |
protected static function getWebPExpressContentDirNoDocRoot() {
|
120 |
// Check wp-content
|
121 |
// ----------------------
|
122 |
-
self::$checking = 'path
|
123 |
|
124 |
-
//
|
125 |
-
|
126 |
-
|
|
|
127 |
// Passed in QS?
|
128 |
-
if (isset($_GET['xwp-content-rel-to-plugin-dir'])) {
|
129 |
-
|
130 |
-
$
|
131 |
-
|
|
|
132 |
|
133 |
-
|
134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
}
|
|
|
136 |
}
|
137 |
|
|
|
138 |
// Check WebP Express content dir
|
139 |
// ---------------------------------
|
140 |
self::$checking = 'WebP Express content dir';
|
141 |
-
// echo 'dir:' . $wpContentDirRelToPluginDir . '<br>'; exit;
|
142 |
|
143 |
-
$
|
144 |
-
|
145 |
|
146 |
-
|
|
|
147 |
//echo $webExpressContentDirAbs; exit;
|
148 |
if (@!file_exists($webExpressContentDirAbs)) {
|
149 |
throw new \Exception('Dir not found');
|
@@ -166,6 +183,8 @@ class WodConfigLoader
|
|
166 |
protected static function loadConfig() {
|
167 |
|
168 |
$usingDocRoot = !(
|
|
|
|
|
169 |
isset($_GET['xwp-content-rel-to-plugin-dir']) ||
|
170 |
self::getEnvPassedInRewriteRule('WE_WP_CONTENT_REL_TO_PLUGIN_DIR')
|
171 |
);
|
119 |
protected static function getWebPExpressContentDirNoDocRoot() {
|
120 |
// Check wp-content
|
121 |
// ----------------------
|
122 |
+
self::$checking = 'relative path between webp-express plugin dir and wp-content dir';
|
123 |
|
124 |
+
// From v0.22.0, we pass relative to webp-express dir rather than to the general plugin dir.
|
125 |
+
// - this allows symlinking the webp-express dir.
|
126 |
+
$wpContentDirRelToWEPluginDir = self::getEnvPassedInRewriteRule('WE_WP_CONTENT_REL_TO_WE_PLUGIN_DIR');
|
127 |
+
if (!$wpContentDirRelToWEPluginDir) {
|
128 |
// Passed in QS?
|
129 |
+
if (isset($_GET['xwp-content-rel-to-we-plugin-dir'])) {
|
130 |
+
$xwpContentDirRelToWEPluginDir = SanityCheck::noControlChars($_GET['xwp-content-rel-to-we-plugin-dir']);
|
131 |
+
$wpContentDirRelToWEPluginDir = SanityCheck::pathDirectoryTraversalAllowed(substr($xwpContentDirRelToWEPluginDir, 1));
|
132 |
+
}
|
133 |
+
}
|
134 |
|
135 |
+
// Old .htaccess rules from before 0.22.0 passed relative path to general plugin dir.
|
136 |
+
// these rules must still be supported, which is what we do here:
|
137 |
+
if (!$wpContentDirRelToWEPluginDir) {
|
138 |
+
self::$checking = 'relative path between plugin dir and wp-content dir';
|
139 |
+
|
140 |
+
$wpContentDirRelToPluginDir = self::getEnvPassedInRewriteRule('WE_WP_CONTENT_REL_TO_PLUGIN_DIR');
|
141 |
+
if ($wpContentDirRelToPluginDir === false) {
|
142 |
+
// Passed in QS?
|
143 |
+
if (isset($_GET['xwp-content-rel-to-plugin-dir'])) {
|
144 |
+
$xwpContentDirRelToPluginDir = SanityCheck::noControlChars($_GET['xwp-content-rel-to-plugin-dir']);
|
145 |
+
$wpContentDirRelToPluginDir = SanityCheck::pathDirectoryTraversalAllowed(substr($xwpContentDirRelToPluginDir, 1));
|
146 |
+
|
147 |
+
} else {
|
148 |
+
throw new \Exception('Path to wp-content was not received in any way');
|
149 |
+
}
|
150 |
}
|
151 |
+
$wpContentDirRelToWEPluginDir = $wpContentDirRelToPluginDir . '/webp-express';
|
152 |
}
|
153 |
|
154 |
+
|
155 |
// Check WebP Express content dir
|
156 |
// ---------------------------------
|
157 |
self::$checking = 'WebP Express content dir';
|
|
|
158 |
|
159 |
+
$pathToWEPluginDir = dirname(dirname(__DIR__));
|
160 |
+
$webExpressContentDirAbs = SanityCheck::pathDirectoryTraversalAllowed($pathToWEPluginDir . '/' . $wpContentDirRelToWEPluginDir . '/webp-express');
|
161 |
|
162 |
+
//$pathToPluginDir = dirname(dirname(dirname(__DIR__)));
|
163 |
+
//$webExpressContentDirAbs = SanityCheck::pathDirectoryTraversalAllowed($pathToPluginDir . '/' . $wpContentDirRelToPluginDir . '/webp-express');
|
164 |
//echo $webExpressContentDirAbs; exit;
|
165 |
if (@!file_exists($webExpressContentDirAbs)) {
|
166 |
throw new \Exception('Dir not found');
|
183 |
protected static function loadConfig() {
|
184 |
|
185 |
$usingDocRoot = !(
|
186 |
+
isset($_GET['xwp-content-rel-to-we-plugin-dir']) ||
|
187 |
+
self::getEnvPassedInRewriteRule('WE_WP_CONTENT_REL_TO_WE_PLUGIN_DIR') ||
|
188 |
isset($_GET['xwp-content-rel-to-plugin-dir']) ||
|
189 |
self::getEnvPassedInRewriteRule('WE_WP_CONTENT_REL_TO_PLUGIN_DIR')
|
190 |
);
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
use \WebPExpress\Config;
|
6 |
+
use \WebPExpress\Messenger;
|
7 |
+
use \WebPExpress\Option;
|
8 |
+
|
9 |
+
function webpexpress_migrate14() {
|
10 |
+
|
11 |
+
// Update migrate version right away to minimize risk of running the update twice in a multithreaded environment
|
12 |
+
Option::updateOption('webp-express-migration-version', '14');
|
13 |
+
|
14 |
+
$config = Config::loadConfigAndFix(false); // false means we do not need the check if quality detection is supported
|
15 |
+
if (($config['enable-redirection-to-converter']) || ($config['redirect-to-existing-in-htaccess'])) {
|
16 |
+
|
17 |
+
// We need to regenerate .htaccess files in case redirection to webp is enabled. Two reasons:
|
18 |
+
// 1: WebP On Demand rules needs fixing (#520)
|
19 |
+
// 2: The new escape hatch (#522), which is needed for the File Manager (#521)
|
20 |
+
wp_schedule_single_event(time() + 10, 'webp_express_task_regenerate_config_and_htaccess');
|
21 |
+
} else {
|
22 |
+
/*
|
23 |
+
if (isset($config['alter-html']) && $config['alter-html']['enabled']) {
|
24 |
+
// Schedule to regenate config, because we need to update autoloaded options in order to
|
25 |
+
// autoload the new alter-html/prevent-using-webps-larger-than-original option
|
26 |
+
// (hm, actually it defaults to true, so it should be neccessary...)
|
27 |
+
wp_schedule_single_event(time() + 10, 'webp_express_task_regenerate_config');
|
28 |
+
}*/
|
29 |
+
}
|
30 |
+
|
31 |
+
// Schedule bulk update dummy files
|
32 |
+
wp_schedule_single_event(time() + 30, 'webp_express_task_bulk_update_dummy_files');
|
33 |
+
|
34 |
+
}
|
35 |
+
|
36 |
+
webpexpress_migrate14();
|
@@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
5 |
use \WebPExpress\Paths;
|
6 |
use \WebPExpress\Config;
|
7 |
|
8 |
-
$ver = '
|
9 |
$jsDir = 'js/0.19.0'; // We change dir when it is critical that no-one gets the cached version (there is a plugin that strips version strings out there...)
|
10 |
|
11 |
if (!function_exists('webp_express_add_inline_script')) {
|
@@ -102,6 +102,10 @@ if (!(isset($config['operation-mode']) && ($config['operation-mode'] == 'no-conv
|
|
102 |
wp_register_script('purgecache', plugins_url($jsDir . '/purge-cache.js', __FILE__), [], $ver);
|
103 |
wp_enqueue_script('purgecache');
|
104 |
|
|
|
|
|
|
|
|
|
105 |
}
|
106 |
|
107 |
//wp_register_script('api_keys', plugins_url($jsDir . 'api-keys.js', __FILE__), ['daspopup'], '0.7.0-dev8');
|
@@ -115,6 +119,7 @@ $javascriptVars = [
|
|
115 |
'convert' => wp_create_nonce('webpexpress-ajax-convert-nonce'),
|
116 |
'list-unconverted-files' => wp_create_nonce('webpexpress-ajax-list-unconverted-files-nonce'),
|
117 |
'purge-cache' => wp_create_nonce('webpexpress-ajax-purge-cache-nonce'),
|
|
|
118 |
'view-log' => wp_create_nonce('webpexpress-ajax-view-log-nonce'),
|
119 |
'self-test' => wp_create_nonce('webpexpress-ajax-self-test-nonce'),
|
120 |
],
|
5 |
use \WebPExpress\Paths;
|
6 |
use \WebPExpress\Config;
|
7 |
|
8 |
+
$ver = '8'; // note: Minimum 1
|
9 |
$jsDir = 'js/0.19.0'; // We change dir when it is critical that no-one gets the cached version (there is a plugin that strips version strings out there...)
|
10 |
|
11 |
if (!function_exists('webp_express_add_inline_script')) {
|
102 |
wp_register_script('purgecache', plugins_url($jsDir . '/purge-cache.js', __FILE__), [], $ver);
|
103 |
wp_enqueue_script('purgecache');
|
104 |
|
105 |
+
// purge log
|
106 |
+
wp_register_script('purgelog', plugins_url($jsDir . '/purge-log.js', __FILE__), [], $ver);
|
107 |
+
wp_enqueue_script('purgelog');
|
108 |
+
|
109 |
}
|
110 |
|
111 |
//wp_register_script('api_keys', plugins_url($jsDir . 'api-keys.js', __FILE__), ['daspopup'], '0.7.0-dev8');
|
119 |
'convert' => wp_create_nonce('webpexpress-ajax-convert-nonce'),
|
120 |
'list-unconverted-files' => wp_create_nonce('webpexpress-ajax-list-unconverted-files-nonce'),
|
121 |
'purge-cache' => wp_create_nonce('webpexpress-ajax-purge-cache-nonce'),
|
122 |
+
'purge-log' => wp_create_nonce('webpexpress-ajax-purge-log-nonce'),
|
123 |
'view-log' => wp_create_nonce('webpexpress-ajax-view-log-nonce'),
|
124 |
'self-test' => wp_create_nonce('webpexpress-ajax-self-test-nonce'),
|
125 |
],
|
@@ -279,7 +279,7 @@ function convertNextInBulkQueue() {
|
|
279 |
var group = bulkInfo.groups[bulkInfo.groupPointer];
|
280 |
var filename = group.files[bulkInfo.filePointer];
|
281 |
|
282 |
-
var result = JSON.parse(response);
|
283 |
|
284 |
//console.log(result);
|
285 |
|
279 |
var group = bulkInfo.groups[bulkInfo.groupPointer];
|
280 |
var filename = group.files[bulkInfo.filePointer];
|
281 |
|
282 |
+
var result = JSON.parse(response); // TODO: An parse error has been experienced (perhaps when token expired?)
|
283 |
|
284 |
//console.log(result);
|
285 |
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
function openDeleteLogFilesPopup() {
|
3 |
+
var html = '';
|
4 |
+
html += '<p><b>Are you sure you want to do that?</b></p>';
|
5 |
+
html += '<p>' +
|
6 |
+
'The log files contain information about the conversion settings used for each webp and the libraries ' +
|
7 |
+
'used, and the versions. This information will be visible in the conversion manager in a not too far future. ' +
|
8 |
+
'The information might also be used to notify you if the libraries / version of a library you have is ' +
|
9 |
+
'significantly better than the one used for the conversion. ' +
|
10 |
+
'If you delete the log files, you will not benefit from this functionality. ' +
|
11 |
+
'</p>';
|
12 |
+
|
13 |
+
html += '<p>' +
|
14 |
+
'The log files are btw located in <i>wp-content/webp-express/log/</i>, if you want to have a closer look.' +
|
15 |
+
'</p>';
|
16 |
+
//html += '<p>In a not too far future, the log files will be used in the conversion manager.</p>'
|
17 |
+
//html += 'They could become handy.</p>'
|
18 |
+
/*
|
19 |
+
html += '<p>This action cannot be reversed. Your log files will be gone. '
|
20 |
+
html += 'Dead. Completely. Forever. '
|
21 |
+
html += '(Unless of course you have a backup. Or, of course, there are ways of recovery... Anyway...). '
|
22 |
+
html += 'Ok, sorry for the babbeling. The dialog seemed bare without text.</p>';*/
|
23 |
+
html += '<button onclick="purgeLog()" class="button button-secondary" type="button">Yes, delete!</button>';
|
24 |
+
|
25 |
+
document.getElementById('purgelogcontent').innerHTML = '<div>' + html + '</div>';
|
26 |
+
tb_show('Delete all log Files?', '#TB_inline?inlineId=purgelogpopup&height=320&width=450');
|
27 |
+
|
28 |
+
}
|
29 |
+
|
30 |
+
function closePurgeLogDialog() {
|
31 |
+
tb_remove();
|
32 |
+
}
|
33 |
+
|
34 |
+
function purgeLog() {
|
35 |
+
var data = {
|
36 |
+
'action': 'webpexpress_purge_log',
|
37 |
+
'nonce' : window.webpExpress['ajax-nonces']['purge-log'],
|
38 |
+
};
|
39 |
+
jQuery.post(ajaxurl, data, function(response) {
|
40 |
+
if ((typeof response == 'object') && (response['success'] == false)) {
|
41 |
+
if (response['data'] && ((typeof response['data']) == 'string')) {
|
42 |
+
alert(response['data']);
|
43 |
+
} else {
|
44 |
+
alert('Something failed');
|
45 |
+
}
|
46 |
+
return;
|
47 |
+
}
|
48 |
+
|
49 |
+
var result = JSON.parse(response);
|
50 |
+
//console.log(result);
|
51 |
+
|
52 |
+
var html = '<div><p>';
|
53 |
+
|
54 |
+
if (result['fail-count'] == 0) {
|
55 |
+
if (result['delete-count'] == 0) {
|
56 |
+
html += 'No log files were found, so none was deleted.';
|
57 |
+
} else {
|
58 |
+
html += 'Successfully deleted ' + result['delete-count'] + ' log files';
|
59 |
+
}
|
60 |
+
} else {
|
61 |
+
if (result['delete-count'] == 0) {
|
62 |
+
html += 'Failed deleting ' + result['fail-count'] + ' log files. None was deleted, in fact.';
|
63 |
+
} else {
|
64 |
+
html += 'Deleted ' + result['delete-count'] + ' log files. However, failed deleting ' + result['fail-count'] + ' log files.';
|
65 |
+
}
|
66 |
+
}
|
67 |
+
html += '</p>';
|
68 |
+
html += '<button onclick="closePurgeLogDialog()" class="button button-secondary" type="button">Ok</button>';
|
69 |
+
html += '</div>';
|
70 |
+
|
71 |
+
document.getElementById('purgelogcontent').innerHTML = html;
|
72 |
+
|
73 |
+
});
|
74 |
+
}
|
@@ -10,6 +10,7 @@
|
|
10 |
include_once 'metadata.inc';
|
11 |
include_once 'converters.inc';
|
12 |
include_once 'convert-on-upload.inc';
|
|
|
13 |
include_once 'bulk-convert.inc';
|
14 |
?>
|
15 |
</tbody>
|
10 |
include_once 'metadata.inc';
|
11 |
include_once 'converters.inc';
|
12 |
include_once 'convert-on-upload.inc';
|
13 |
+
include_once 'logging.inc';
|
14 |
include_once 'bulk-convert.inc';
|
15 |
?>
|
16 |
</tbody>
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">
|
3 |
+
Enable logging
|
4 |
+
<?php
|
5 |
+
echo helpIcon(
|
6 |
+
'<p>Store conversion results in log files. ' .
|
7 |
+
'This can be useful in order to find out what went wrong in case a conversion failed or ' .
|
8 |
+
'the result is poor quality. ' .
|
9 |
+
'The log files reside in <i>wp-content/webp-express/log/conversions/</i>. ' .
|
10 |
+
'In not too far a future, the conversion logs will be accessible in the File Manager too.' .
|
11 |
+
'</p>'
|
12 |
+
);
|
13 |
+
?>
|
14 |
+
</th>
|
15 |
+
<td>
|
16 |
+
<input type="checkbox" id="enable_logging" name="enable-logging" value="true" <?php echo ($config['enable-logging'] ? 'checked="checked"' : '') ?> >
|
17 |
+
|
18 |
+
<button onclick="openDeleteLogFilesPopup()" class="button button-secondary" type="button">Delete log files</button>
|
19 |
+
<div id="purgelogpopup" style="display:none;">
|
20 |
+
<div id="purgelogcontent"></div>
|
21 |
+
</div>
|
22 |
+
|
23 |
+
</td>
|
24 |
+
</tr>
|
@@ -40,8 +40,8 @@
|
|
40 |
<?php
|
41 |
if ($config['operation-mode'] == 'no-conversion') {
|
42 |
webpexpress_radioButtons('destination-extension', $config['destination-extension'], [
|
43 |
-
'append' => '
|
44 |
-
'set' => '
|
45 |
], [
|
46 |
'append' => 'Original extension is kept and ".webp" is appended. ',
|
47 |
'set' => 'Original extension is replaced with ".webp".'
|
40 |
<?php
|
41 |
if ($config['operation-mode'] == 'no-conversion') {
|
42 |
webpexpress_radioButtons('destination-extension', $config['destination-extension'], [
|
43 |
+
'append' => 'Appended ".webp" (ie "image.jpg.webp")',
|
44 |
+
'set' => 'Replaced extension (ie "image.webp")',
|
45 |
], [
|
46 |
'append' => 'Original extension is kept and ".webp" is appended. ',
|
47 |
'set' => 'Original extension is replaced with ".webp".'
|
@@ -28,6 +28,8 @@
|
|
28 |
include_once 'cache-control.inc';
|
29 |
}
|
30 |
|
|
|
|
|
31 |
?>
|
32 |
</tbody>
|
33 |
</table>
|
28 |
include_once 'cache-control.inc';
|
29 |
}
|
30 |
|
31 |
+
include_once 'prevent-using-webps-larger-than-original.inc';
|
32 |
+
|
33 |
?>
|
34 |
</tbody>
|
35 |
</table>
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<th scope="row">Prevent using webps larger than original<?php
|
3 |
+
echo helpIcon(
|
4 |
+
'<p>For some images, the converted webp might turns out bigger than the original. ' .
|
5 |
+
'These are always kept on disk. However, with this option, you can choose whether they should be used or not. ' .
|
6 |
+
'If you are motivated by limiting bandwidth usage and having a fast website, keep this option enabled. ' .
|
7 |
+
'If you are more concerned about SEO and a penalty for serving jpegs and pngs rather than webps, disable it.' .
|
8 |
+
'</p>' .
|
9 |
+
'<p>The option is used both when generating .htaccess rules and in Alter HTML.</p>'
|
10 |
+
);
|
11 |
+
?></th>
|
12 |
+
<td>
|
13 |
+
<input type="checkbox" id="prevent_using_webps_larger_than_original" name="prevent-using-webps-larger-than-original" value="true" <?php echo ($config['prevent-using-webps-larger-than-original'] ? 'checked="checked"' : '') ?> >
|
14 |
+
</td>
|
15 |
+
</tr>
|
@@ -381,6 +381,7 @@ $sanitized = [
|
|
381 |
'private',
|
382 |
]),
|
383 |
'cache-control-custom' => webpexpress_getSanitizedCacheControlHeader('cache-control-custom'),
|
|
|
384 |
|
385 |
|
386 |
// Redirection rules
|
@@ -427,6 +428,7 @@ $sanitized = [
|
|
427 |
]),
|
428 |
'alpha-quality' => webpexpress_getSanitizedQuality('alpha-quality', 80),
|
429 |
'convert-on-upload' => isset($_POST['convert-on-upload']),
|
|
|
430 |
'converters' => webpexpress_getSanitizedConverters(),
|
431 |
|
432 |
|
@@ -505,6 +507,8 @@ switch ($sanitized['cache-control']) {
|
|
505 |
$config['cache-control-custom'] = $sanitized['cache-control-custom'];
|
506 |
break;
|
507 |
}
|
|
|
|
|
508 |
|
509 |
// Alter HTML
|
510 |
$config['alter-html'] = [];
|
@@ -565,6 +569,7 @@ if ($sanitized['operation-mode'] != 'no-conversion') {
|
|
565 |
|
566 |
// Other conversion options
|
567 |
$config['convert-on-upload'] = $sanitized['convert-on-upload'];
|
|
|
568 |
|
569 |
|
570 |
// Web Service
|
@@ -679,6 +684,12 @@ if ($sanitized['operation-mode'] != $sanitized['change-operation-mode']) {
|
|
679 |
// the redirect-to-existing-in-htaccess option
|
680 |
$config['redirect-to-existing-in-htaccess'] = true;
|
681 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
682 |
}
|
683 |
|
684 |
// If we are going to save .htaccess, run and store capability tests first
|
381 |
'private',
|
382 |
]),
|
383 |
'cache-control-custom' => webpexpress_getSanitizedCacheControlHeader('cache-control-custom'),
|
384 |
+
'prevent-using-webps-larger-than-original' => isset($_POST['prevent-using-webps-larger-than-original']),
|
385 |
|
386 |
|
387 |
// Redirection rules
|
428 |
]),
|
429 |
'alpha-quality' => webpexpress_getSanitizedQuality('alpha-quality', 80),
|
430 |
'convert-on-upload' => isset($_POST['convert-on-upload']),
|
431 |
+
'enable-logging' => isset($_POST['enable-logging']),
|
432 |
'converters' => webpexpress_getSanitizedConverters(),
|
433 |
|
434 |
|
507 |
$config['cache-control-custom'] = $sanitized['cache-control-custom'];
|
508 |
break;
|
509 |
}
|
510 |
+
$config['prevent-using-webps-larger-than-original'] = $sanitized['prevent-using-webps-larger-than-original'];
|
511 |
+
|
512 |
|
513 |
// Alter HTML
|
514 |
$config['alter-html'] = [];
|
569 |
|
570 |
// Other conversion options
|
571 |
$config['convert-on-upload'] = $sanitized['convert-on-upload'];
|
572 |
+
$config['enable-logging'] = $sanitized['enable-logging'];
|
573 |
|
574 |
|
575 |
// Web Service
|
684 |
// the redirect-to-existing-in-htaccess option
|
685 |
$config['redirect-to-existing-in-htaccess'] = true;
|
686 |
}
|
687 |
+
|
688 |
+
if ($config['operation-mode'] == 'no-conversion') {
|
689 |
+
// No conversion probably means that there are webps in the system not generated by
|
690 |
+
// webp express. Schedule a task to mark those that are bigger than originals
|
691 |
+
wp_schedule_single_event(time() + 30, 'webp_express_task_bulk_update_dummy_files');
|
692 |
+
}
|
693 |
}
|
694 |
|
695 |
// If we are going to save .htaccess, run and store capability tests first
|
@@ -156,17 +156,17 @@
|
|
156 |
},
|
157 |
{
|
158 |
"name": "rosell-dk/dom-util-for-webp",
|
159 |
-
"version": "0.4.
|
160 |
-
"version_normalized": "0.4.
|
161 |
"source": {
|
162 |
"type": "git",
|
163 |
"url": "https://github.com/rosell-dk/dom-util-for-webp.git",
|
164 |
-
"reference": "
|
165 |
},
|
166 |
"dist": {
|
167 |
"type": "zip",
|
168 |
-
"url": "https://api.github.com/repos/rosell-dk/dom-util-for-webp/zipball/
|
169 |
-
"reference": "
|
170 |
"shasum": ""
|
171 |
},
|
172 |
"require-dev": {
|
@@ -174,7 +174,7 @@
|
|
174 |
"phpunit/phpunit": "^9.3",
|
175 |
"squizlabs/php_codesniffer": "3.*"
|
176 |
},
|
177 |
-
"time": "2021-
|
178 |
"type": "library",
|
179 |
"extra": {
|
180 |
"scripts-descriptions": {
|
@@ -212,7 +212,7 @@
|
|
212 |
],
|
213 |
"support": {
|
214 |
"issues": "https://github.com/rosell-dk/dom-util-for-webp/issues",
|
215 |
-
"source": "https://github.com/rosell-dk/dom-util-for-webp/tree/0.4.
|
216 |
},
|
217 |
"funding": [
|
218 |
{
|
156 |
},
|
157 |
{
|
158 |
"name": "rosell-dk/dom-util-for-webp",
|
159 |
+
"version": "0.4.2",
|
160 |
+
"version_normalized": "0.4.2.0",
|
161 |
"source": {
|
162 |
"type": "git",
|
163 |
"url": "https://github.com/rosell-dk/dom-util-for-webp.git",
|
164 |
+
"reference": "f33515fbb90067cb982dc3109d7193f27ab97619"
|
165 |
},
|
166 |
"dist": {
|
167 |
"type": "zip",
|
168 |
+
"url": "https://api.github.com/repos/rosell-dk/dom-util-for-webp/zipball/f33515fbb90067cb982dc3109d7193f27ab97619",
|
169 |
+
"reference": "f33515fbb90067cb982dc3109d7193f27ab97619",
|
170 |
"shasum": ""
|
171 |
},
|
172 |
"require-dev": {
|
174 |
"phpunit/phpunit": "^9.3",
|
175 |
"squizlabs/php_codesniffer": "3.*"
|
176 |
},
|
177 |
+
"time": "2021-11-04T11:13:34+00:00",
|
178 |
"type": "library",
|
179 |
"extra": {
|
180 |
"scripts-descriptions": {
|
212 |
],
|
213 |
"support": {
|
214 |
"issues": "https://github.com/rosell-dk/dom-util-for-webp/issues",
|
215 |
+
"source": "https://github.com/rosell-dk/dom-util-for-webp/tree/0.4.2"
|
216 |
},
|
217 |
"funding": [
|
218 |
{
|
@@ -5,7 +5,7 @@
|
|
5 |
'type' => 'wordpress-plugin',
|
6 |
'install_path' => __DIR__ . '/../../',
|
7 |
'aliases' => array(),
|
8 |
-
'reference' => '
|
9 |
'name' => 'rosell-dk/webp-express',
|
10 |
'dev' => true,
|
11 |
),
|
@@ -20,12 +20,12 @@
|
|
20 |
'dev_requirement' => false,
|
21 |
),
|
22 |
'rosell-dk/dom-util-for-webp' => array(
|
23 |
-
'pretty_version' => '0.4.
|
24 |
-
'version' => '0.4.
|
25 |
'type' => 'library',
|
26 |
'install_path' => __DIR__ . '/../rosell-dk/dom-util-for-webp',
|
27 |
'aliases' => array(),
|
28 |
-
'reference' => '
|
29 |
'dev_requirement' => false,
|
30 |
),
|
31 |
'rosell-dk/htaccess-capability-tester' => array(
|
@@ -70,7 +70,7 @@
|
|
70 |
'type' => 'wordpress-plugin',
|
71 |
'install_path' => __DIR__ . '/../../',
|
72 |
'aliases' => array(),
|
73 |
-
'reference' => '
|
74 |
'dev_requirement' => false,
|
75 |
),
|
76 |
'roundcube/plugin-installer' => array(
|
5 |
'type' => 'wordpress-plugin',
|
6 |
'install_path' => __DIR__ . '/../../',
|
7 |
'aliases' => array(),
|
8 |
+
'reference' => 'f5035d6408254d4070e9edfb7b2b6348753d4e83',
|
9 |
'name' => 'rosell-dk/webp-express',
|
10 |
'dev' => true,
|
11 |
),
|
20 |
'dev_requirement' => false,
|
21 |
),
|
22 |
'rosell-dk/dom-util-for-webp' => array(
|
23 |
+
'pretty_version' => '0.4.2',
|
24 |
+
'version' => '0.4.2.0',
|
25 |
'type' => 'library',
|
26 |
'install_path' => __DIR__ . '/../rosell-dk/dom-util-for-webp',
|
27 |
'aliases' => array(),
|
28 |
+
'reference' => 'f33515fbb90067cb982dc3109d7193f27ab97619',
|
29 |
'dev_requirement' => false,
|
30 |
),
|
31 |
'rosell-dk/htaccess-capability-tester' => array(
|
70 |
'type' => 'wordpress-plugin',
|
71 |
'install_path' => __DIR__ . '/../../',
|
72 |
'aliases' => array(),
|
73 |
+
'reference' => 'f5035d6408254d4070e9edfb7b2b6348753d4e83',
|
74 |
'dev_requirement' => false,
|
75 |
),
|
76 |
'roundcube/plugin-installer' => array(
|
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
[![Latest Stable Version](https://img.shields.io/packagist/v/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://packagist.org/packages/rosell-dk/dom-util-for-webp)
|
4 |
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net)
|
5 |
-
[![Build Status](https://img.shields.io/
|
6 |
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/code-structure/master)
|
7 |
[![Quality Score](https://img.shields.io/scrutinizer/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/)
|
8 |
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/blob/master/LICENSE)
|
2 |
|
3 |
[![Latest Stable Version](https://img.shields.io/packagist/v/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://packagist.org/packages/rosell-dk/dom-util-for-webp)
|
4 |
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net)
|
5 |
+
[![Build Status](https://img.shields.io/github/workflow/status/rosell-dk/dom-util-for-webp/PHP?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/actions/workflows/php.yml)
|
6 |
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/code-structure/master)
|
7 |
[![Quality Score](https://img.shields.io/scrutinizer/g/rosell-dk/dom-util-for-webp.svg?style=flat-square)](https://scrutinizer-ci.com/g/rosell-dk/dom-util-for-webp/)
|
8 |
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/rosell-dk/dom-util-for-webp/blob/master/LICENSE)
|
@@ -84,6 +84,33 @@ class PictureTags
|
|
84 |
);
|
85 |
}
|
86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
private static function getAttributes($html)
|
88 |
{
|
89 |
if (function_exists("mb_convert_encoding")) {
|
@@ -100,6 +127,10 @@ class PictureTags
|
|
100 |
return $attributes;
|
101 |
} else {
|
102 |
//$dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
|
|
|
|
|
|
|
|
|
103 |
$dom = str_get_html($html, false, false, 'UTF-8', false);
|
104 |
if ($dom !== false) {
|
105 |
$elems = $dom->find('img,IMG');
|
@@ -151,14 +182,24 @@ class PictureTags
|
|
151 |
$srcsetInfo = self::lazyGet($imgAttributes, 'srcset');
|
152 |
$sizesInfo = self::lazyGet($imgAttributes, 'sizes');
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
// add the exclude class so if this content is processed again in other filter,
|
155 |
// the img is not converted again in picture
|
156 |
$imgAttributes['class'] = (isset($imgAttributes['class']) ? $imgAttributes['class'] . " " : "") .
|
157 |
"webpexpress-processed";
|
158 |
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
162 |
$srcsetArrWebP = [];
|
163 |
foreach ($srcsetArr as $i => $srcSetEntry) {
|
164 |
// $srcSetEntry is ie "http://example.com/image.jpg 520w"
|
@@ -167,26 +208,58 @@ class PictureTags
|
|
167 |
$width = null;
|
168 |
if ($result && count($result) >= 2) {
|
169 |
list($src, $width) = $result;
|
|
|
170 |
}
|
171 |
|
172 |
$webpUrl = $this->replaceUrlOr($src, false);
|
173 |
if ($webpUrl !== false) {
|
174 |
-
|
|
|
|
|
|
|
175 |
}
|
176 |
}
|
177 |
-
$
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
|
|
180 |
return $imgTag;
|
181 |
}
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
|
|
|
|
187 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
return '<picture>'
|
189 |
-
. '<source
|
190 |
. '<img' . self::createAttributes($imgAttributes) . '>'
|
191 |
. '</picture>';
|
192 |
} else {
|
@@ -206,7 +279,7 @@ class PictureTags
|
|
206 |
. '<source ' . $sourceSrcAttrName . '="' . $srcWebP . '" type="image/webp">'
|
207 |
. '<img' . self::createAttributes($imgAttributes) . '>'
|
208 |
. '</picture>';
|
209 |
-
}
|
210 |
}
|
211 |
|
212 |
/*
|
@@ -251,9 +324,6 @@ class PictureTags
|
|
251 |
/* Main replacer function */
|
252 |
public static function replace($html)
|
253 |
{
|
254 |
-
if (!function_exists('str_get_html')) {
|
255 |
-
require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
|
256 |
-
}
|
257 |
$pt = new static();
|
258 |
return $pt->replaceHtml($html);
|
259 |
}
|
84 |
);
|
85 |
}
|
86 |
|
87 |
+
/**
|
88 |
+
* Look for attribute such as "src", but also with prefixes such as "data-lazy-src" and "data-src"
|
89 |
+
*
|
90 |
+
* @param array $attributes an array of all attributes for the element
|
91 |
+
* @param string $attrName ie "src", "srcset" or "sizes"
|
92 |
+
*
|
93 |
+
* @return array an array with "value" key and "attrName" key. ("value" is the value of the attribute and
|
94 |
+
* "attrName" is the name of the attribute used)
|
95 |
+
*
|
96 |
+
*/
|
97 |
+
private static function findAttributesWithNameOrPrefixed($attributes, $attrName)
|
98 |
+
{
|
99 |
+
$tryThesePrefixes = ['', 'data-lazy-', 'data-'];
|
100 |
+
$result = [];
|
101 |
+
foreach ($tryThesePrefixes as $prefix) {
|
102 |
+
$name = $prefix . $attrName;
|
103 |
+
if (isset($attributes[$name]) && strlen($attributes[$name])) {
|
104 |
+
/*$result[] = [
|
105 |
+
'value' => trim($attributes[$name]),
|
106 |
+
'attrName' => $name,
|
107 |
+
];*/
|
108 |
+
$result[$name] = trim($attributes[$name]);
|
109 |
+
}
|
110 |
+
}
|
111 |
+
return $result;
|
112 |
+
}
|
113 |
+
|
114 |
private static function getAttributes($html)
|
115 |
{
|
116 |
if (function_exists("mb_convert_encoding")) {
|
127 |
return $attributes;
|
128 |
} else {
|
129 |
//$dom = HtmlDomParser::str_get_html($html, false, false, 'UTF-8', false);
|
130 |
+
if (!function_exists('str_get_html')) {
|
131 |
+
require_once __DIR__ . '/../src-vendor/simple_html_dom/simple_html_dom.inc';
|
132 |
+
}
|
133 |
+
|
134 |
$dom = str_get_html($html, false, false, 'UTF-8', false);
|
135 |
if ($dom !== false) {
|
136 |
$elems = $dom->find('img,IMG');
|
182 |
$srcsetInfo = self::lazyGet($imgAttributes, 'srcset');
|
183 |
$sizesInfo = self::lazyGet($imgAttributes, 'sizes');
|
184 |
|
185 |
+
$srcSetAttributes = self::findAttributesWithNameOrPrefixed($imgAttributes, 'srcset');
|
186 |
+
$srcAttributes = self::findAttributesWithNameOrPrefixed($imgAttributes, 'src');
|
187 |
+
|
188 |
+
if ((!isset($srcSetAttributes['srcset'])) && (!isset($srcAttributes['src']))) {
|
189 |
+
// better not mess with this html...
|
190 |
+
return $imgTag;
|
191 |
+
}
|
192 |
+
|
193 |
// add the exclude class so if this content is processed again in other filter,
|
194 |
// the img is not converted again in picture
|
195 |
$imgAttributes['class'] = (isset($imgAttributes['class']) ? $imgAttributes['class'] . " " : "") .
|
196 |
"webpexpress-processed";
|
197 |
|
198 |
+
// Process srcset (also data-srcset etc)
|
199 |
+
$atLeastOneWebp = false;
|
200 |
+
$sourceTagAttributes = [];
|
201 |
+
foreach ($srcSetAttributes as $attrName => $attrValue) {
|
202 |
+
$srcsetArr = explode(', ', $attrValue);
|
203 |
$srcsetArrWebP = [];
|
204 |
foreach ($srcsetArr as $i => $srcSetEntry) {
|
205 |
// $srcSetEntry is ie "http://example.com/image.jpg 520w"
|
208 |
$width = null;
|
209 |
if ($result && count($result) >= 2) {
|
210 |
list($src, $width) = $result;
|
211 |
+
|
212 |
}
|
213 |
|
214 |
$webpUrl = $this->replaceUrlOr($src, false);
|
215 |
if ($webpUrl !== false) {
|
216 |
+
if (substr($src, 0, 5) != 'data:') {
|
217 |
+
$atLeastOneWebp = true;
|
218 |
+
$srcsetArrWebP[] = $webpUrl . (isset($width) ? ' ' . $width : '');
|
219 |
+
}
|
220 |
}
|
221 |
}
|
222 |
+
$sourceTagAttributes[$attrName] = implode(', ', $srcsetArrWebP);
|
223 |
+
}
|
224 |
+
|
225 |
+
foreach ($srcAttributes as $attrName => $attrValue) {
|
226 |
+
|
227 |
+
if (substr($attrValue, 0, 5) == 'data:') {
|
228 |
+
// ignore tags with data urls, such as <img src="data:...
|
229 |
return $imgTag;
|
230 |
}
|
231 |
+
// Make sure not to override existing srcset with src
|
232 |
+
if (!isset($sourceTagAttributes[$attrName . 'set'])) {
|
233 |
+
$srcWebP = $this->replaceUrlOr($attrValue, false);
|
234 |
+
if ($srcWebP !== false) {
|
235 |
+
$atLeastOneWebp = true;
|
236 |
+
}
|
237 |
+
$sourceTagAttributes[$attrName . 'set'] = $srcWebP;
|
238 |
}
|
239 |
+
}
|
240 |
+
|
241 |
+
if ($sizesInfo['value']) {
|
242 |
+
$sourceTagAttributes[$sizesInfo['attrName']] = $sizesInfo['value'];
|
243 |
+
}
|
244 |
+
|
245 |
+
if (!$atLeastOneWebp) {
|
246 |
+
// We have no webps for you, so no reason to create <picture> tag
|
247 |
+
return $imgTag;
|
248 |
+
}
|
249 |
+
|
250 |
+
return '<picture>'
|
251 |
+
. '<source' . self::createAttributes($sourceTagAttributes) . ' type="image/webp">'
|
252 |
+
. '<img' . self::createAttributes($imgAttributes) . '>'
|
253 |
+
. '</picture>';
|
254 |
+
|
255 |
+
/*
|
256 |
+
//if ($srcsetInfo['value']) {
|
257 |
+
if (isset($srcSetAttributes['srcset'])) {
|
258 |
+
$sourceTagAttributes = $srcSetAttributes;
|
259 |
+
|
260 |
+
|
261 |
return '<picture>'
|
262 |
+
. '<source' . self::createAttributes($sourceTagAttributes) . ' type="image/webp">'
|
263 |
. '<img' . self::createAttributes($imgAttributes) . '>'
|
264 |
. '</picture>';
|
265 |
} else {
|
279 |
. '<source ' . $sourceSrcAttrName . '="' . $srcWebP . '" type="image/webp">'
|
280 |
. '<img' . self::createAttributes($imgAttributes) . '>'
|
281 |
. '</picture>';
|
282 |
+
}*/
|
283 |
}
|
284 |
|
285 |
/*
|
324 |
/* Main replacer function */
|
325 |
public static function replace($html)
|
326 |
{
|
|
|
|
|
|
|
327 |
$pt = new static();
|
328 |
return $pt->replaceHtml($html);
|
329 |
}
|
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: WebP Express
|
4 |
* Plugin URI: https://github.com/rosell-dk/webp-express
|
5 |
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
|
6 |
-
* Version: 0.
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
@@ -61,3 +61,8 @@ add_filter('image_make_intermediate_size', array('\WebPExpress\HandleUploadHooks
|
|
61 |
add_filter('wp_delete_file', array('\WebPExpress\HandleDeleteFileHook', 'deleteAssociatedWebP'), 10, 2);
|
62 |
|
63 |
//add_action( 'template_redirect', 'webp_express_template_redirect' );
|
|
|
|
|
|
|
|
|
|
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.22.0
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
61 |
add_filter('wp_delete_file', array('\WebPExpress\HandleDeleteFileHook', 'deleteAssociatedWebP'), 10, 2);
|
62 |
|
63 |
//add_action( 'template_redirect', 'webp_express_template_redirect' );
|
64 |
+
|
65 |
+
// Add hooks for tasks that might be scheduled for wp_cron
|
66 |
+
add_action('webp_express_task_bulk_update_dummy_files', array('\WebPExpress\BiggerThanSourceDummyFilesBulk', 'updateStatus'), 10, 0);
|
67 |
+
add_action('webp_express_task_regenerate_config', array('\WebPExpress\Config', 'regenerateConfig'), 10, 0);
|
68 |
+
add_action('webp_express_task_regenerate_config_and_htaccess', array('\WebPExpress\Config', 'regenerateConfigAndHtaccessFiles'), 10, 0);
|