Converter for Media – Optimize images | Convert WebP & AVIF - Version 3.0.0

Version Description

(2021-05-02) = * [Removed] Filter webpc_get_values * [Removed] Filter webpc_get_options * [Removed] Filter webpc_get_methods * [Changed] Error messages on plugin settings page * [Added] Conversion of images to multiple output formats * [Added] Compatibility with NextGEN Gallery plugin * [Added] Data displayed on "Server configuration" tab on plugin settings page * [Added] Changes to improve performance of plugin * [Added] Changes to improve security of plugin

Download this release

Release Info

Developer mateuszgbiorczyk
Plugin Icon 128x128 Converter for Media – Optimize images | Convert WebP & AVIF
Version 3.0.0
Comparing to
See all releases

Code changes from version 2.4.0 to 3.0.0

Files changed (259) hide show
  1. app/Action/Convert.php +0 -48
  2. app/Action/Cron.php +0 -36
  3. app/Action/Delete.php +0 -38
  4. app/Action/Regenerate.php +0 -23
  5. app/Action/_Core.php +0 -14
  6. app/Admin/Assets.php +0 -31
  7. app/Admin/Modal.php +0 -32
  8. app/Admin/Notice.php +0 -63
  9. app/Admin/Plugin.php +0 -54
  10. app/Admin/_Core.php +0 -13
  11. app/Convert/Dir.php +0 -43
  12. app/Convert/Directory.php +0 -46
  13. app/Convert/Paths.php +0 -84
  14. app/Convert/Server.php +0 -26
  15. app/Convert/Size.php +0 -36
  16. app/Convert/_Core.php +0 -13
  17. app/Error/ErrorAbstract.php +0 -24
  18. app/Error/ErrorInterface.php +0 -14
  19. app/Error/LibsError.php +0 -39
  20. app/Error/PassthruError.php +0 -45
  21. app/Error/PathsError.php +0 -58
  22. app/Error/RestapiError.php +0 -31
  23. app/Error/RewritesError.php +0 -102
  24. app/Error/SettingsError.php +0 -35
  25. app/Loader/Htaccess.php +0 -162
  26. app/Loader/LoaderAbstract.php +0 -42
  27. app/Loader/LoaderInterface.php +0 -20
  28. app/Loader/Passthru.php +0 -103
  29. app/Loader/_Core.php +0 -12
  30. app/Media/Attachment.php +0 -55
  31. app/Media/Delete.php +0 -21
  32. app/Media/Upload.php +0 -64
  33. app/Media/_Core.php +0 -12
  34. app/Method/Gd.php +0 -118
  35. app/Method/Imagick.php +0 -77
  36. app/Method/MethodAbstract.php +0 -95
  37. app/Method/MethodIntegrator.php +0 -39
  38. app/Method/MethodInterface.php +0 -31
  39. app/Plugin/Activation.php +0 -55
  40. app/Plugin/Deactivation.php +0 -29
  41. app/Plugin/Uninstall.php +0 -97
  42. app/Plugin/Update.php +0 -70
  43. app/Plugin/_Core.php +0 -14
  44. app/Regenerate/Endpoints.php +0 -104
  45. app/Regenerate/Paths.php +0 -27
  46. app/Regenerate/Regenerate.php +0 -45
  47. app/Regenerate/Skip.php +0 -32
  48. app/Regenerate/_Core.php +0 -12
  49. app/Settings/Errors.php +0 -96
  50. app/Settings/Methods.php +0 -27
  51. app/Settings/Options.php +0 -129
  52. app/Settings/Page.php +0 -72
  53. app/Settings/Save.php +0 -54
  54. app/Settings/Server.php +0 -190
  55. app/Settings/Values.php +0 -33
  56. app/Settings/_Core.php +0 -16
  57. app/Traits/FileLoaderTrait.php +0 -50
  58. app/WebpConverter.php +0 -18
  59. assets/build/css/styles.css +1 -0
  60. {public → assets}/build/js/scripts.js +0 -0
  61. {public → assets}/fonts/Exo2/Exo2-Regular.ttf +0 -0
  62. {public → assets}/fonts/Exo2/Exo2-Regular.woff +0 -0
  63. {public → assets}/fonts/Exo2/Exo2-Regular.woff2 +0 -0
  64. {public → assets}/fonts/Exo2/Exo2-SemiBold.ttf +0 -0
  65. {public → assets}/fonts/Exo2/Exo2-SemiBold.woff +0 -0
  66. {public → assets}/fonts/Exo2/Exo2-SemiBold.woff2 +0 -0
  67. {public → assets}/img/author.jpg +0 -0
  68. {public → assets}/img/debug/.htaccess +0 -0
  69. {public → assets}/img/debug/icon-after.png +0 -0
  70. {public → assets}/img/debug/icon-after.png2 +0 -0
  71. {public → assets}/img/debug/icon-before.png +0 -0
  72. {public → assets}/img/debug/icon-before.png2 +0 -0
  73. {public → assets}/img/icon-test.png +0 -0
  74. {public → assets}/img/icon-test.webp +0 -0
  75. includes/passthru.php +114 -0
  76. libs/passthru.php +0 -70
  77. public/build/css/styles.css +0 -1
  78. readme.txt +650 -674
  79. resources/components/errors/bypassing-apache.php +0 -15
  80. resources/components/errors/libs-not-installed.php +0 -18
  81. resources/components/errors/libs-without-webp-support.php +0 -16
  82. resources/components/errors/passthru-execution.php +0 -14
  83. resources/components/errors/passthru-info.php +0 -8
  84. resources/components/errors/path-htaccess-not-writable.php +0 -8
  85. resources/components/errors/path-uploads-unavailable.php +0 -9
  86. resources/components/errors/path-webp-duplicated.php +0 -7
  87. resources/components/errors/path-webp-not-writable.php +0 -9
  88. resources/components/errors/rest-api-disabled.php +0 -8
  89. resources/components/errors/rewrites-cached.php +0 -7
  90. resources/components/errors/rewrites-not-working.php +0 -9
  91. resources/components/errors/settings-incorrect.php +0 -7
  92. resources/components/fields/checkbox.php +0 -28
  93. resources/components/fields/quality.php +0 -23
  94. resources/components/fields/radio.php +0 -28
  95. resources/components/notices/thanks.php +0 -32
  96. resources/components/notices/welcome.php +0 -25
  97. resources/components/widgets/about.php +0 -28
  98. resources/components/widgets/donate.php +0 -17
  99. resources/components/widgets/errors.php +0 -19
  100. resources/components/widgets/options.php +0 -37
  101. resources/components/widgets/regenerate.php +0 -96
  102. resources/components/widgets/server.php +0 -33
  103. resources/components/widgets/support.php +0 -41
  104. resources/views/deactivation-modal.php +0 -86
  105. resources/views/settings.php +0 -42
  106. src/Action/ConvertAttachment.php +38 -0
  107. src/Action/ConvertDir.php +34 -0
  108. src/Action/ConvertPaths.php +37 -0
  109. src/Action/DeletePaths.php +57 -0
  110. src/Action/RegenerateAll.php +36 -0
  111. src/Conversion/Cron/Event.php +41 -0
  112. src/Conversion/Cron/Schedules.php +38 -0
  113. src/Conversion/Directories.php +72 -0
  114. src/Conversion/Directory/DirectoriesIntegration.php +164 -0
  115. src/Conversion/Directory/DirectoryAbstract.php +58 -0
  116. src/Conversion/Directory/DirectoryInterface.php +58 -0
  117. src/Conversion/Directory/GalleryDirectory.php +42 -0
  118. src/Conversion/Directory/PluginsDirectory.php +42 -0
  119. src/Conversion/Directory/ThemesDirectory.php +42 -0
  120. src/Conversion/Directory/UploadsDirectory.php +42 -0
  121. src/Conversion/Directory/UploadsWebpcDirectory.php +51 -0
  122. src/Conversion/DirectoryFiles.php +75 -0
  123. src/Conversion/Endpoint/EndpointAbstract.php +39 -0
  124. src/Conversion/Endpoint/EndpointIntegration.php +61 -0
  125. src/Conversion/Endpoint/EndpointInterface.php +42 -0
  126. src/Conversion/Endpoint/PathsEndpoint.php +92 -0
  127. src/Conversion/Endpoint/RegenerateEndpoint.php +85 -0
  128. src/Conversion/Endpoints.php +39 -0
  129. src/Conversion/Exception/ConversionErrorException.php +35 -0
  130. src/Conversion/Exception/ExceptionAbstract.php +21 -0
  131. src/Conversion/Exception/ExceptionInterface.php +32 -0
  132. src/Conversion/Exception/ExtensionUnsupportedException.php +35 -0
  133. src/Conversion/Exception/FunctionUnavailableException.php +35 -0
  134. src/Conversion/Exception/ImageInvalidException.php +35 -0
  135. src/Conversion/Exception/ImagickNotSupportWebpException.php +35 -0
  136. src/Conversion/Exception/ImagickUnavailableException.php +35 -0
  137. src/Conversion/Exception/LargerThanOriginalException.php +35 -0
  138. src/Conversion/Exception/OutputPathException.php +35 -0
  139. src/Conversion/Exception/ResolutionOversizeException.php +35 -0
  140. src/Conversion/Exception/ServerConfigurationException.php +35 -0
  141. src/Conversion/Exception/SourcePathException.php +35 -0
  142. src/Conversion/Format/AvifFormat.php +53 -0
  143. src/Conversion/Format/FormatAbstract.php +32 -0
  144. src/Conversion/Format/FormatInterface.php +39 -0
  145. src/Conversion/Format/WebpFormat.php +41 -0
  146. src/Conversion/Formats.php +90 -0
  147. src/Conversion/Media/Attachment.php +98 -0
  148. src/Conversion/Media/Delete.php +33 -0
  149. src/Conversion/Media/Upload.php +106 -0
  150. src/Conversion/Method/GdMethod.php +189 -0
  151. src/Conversion/Method/ImagickMethod.php +138 -0
  152. src/Conversion/Method/MethodAbstract.php +182 -0
  153. src/Conversion/Method/MethodIntegrator.php +59 -0
  154. src/Conversion/Method/MethodInterface.php +139 -0
  155. src/Conversion/Methods.php +83 -0
  156. src/Conversion/OutputPath.php +103 -0
  157. src/Conversion/SkipExists.php +74 -0
  158. src/Conversion/SkipLarger.php +52 -0
  159. src/Error/ErrorAbstract.php +22 -0
  160. src/Error/ErrorInterface.php +18 -0
  161. src/Error/Errors.php +159 -0
  162. src/Error/LibsInstalledError.php +37 -0
  163. src/Error/LibsSupportAvifError.php +41 -0
  164. src/Error/LibsSupportWebpError.php +40 -0
  165. src/Error/PassthruError.php +63 -0
  166. src/Error/PathsError.php +81 -0
  167. src/Error/RestapiError.php +37 -0
  168. src/Error/RewritesError.php +140 -0
  169. src/Error/SettingsError.php +45 -0
  170. src/Helper/FileLoader.php +79 -0
  171. src/Helper/ViewLoader.php +28 -0
  172. src/HookableInterface.php +16 -0
  173. src/Loader/HtaccessLoader.php +256 -0
  174. src/Loader/LoaderAbstract.php +34 -0
  175. src/Loader/LoaderIntegration.php +73 -0
  176. src/Loader/LoaderInterface.php +42 -0
  177. src/Loader/Loaders.php +39 -0
  178. src/Loader/PassthruLoader.php +153 -0
  179. src/Notice/NoticeAbstract.php +29 -0
  180. src/Notice/NoticeIntegration.php +88 -0
  181. src/Notice/NoticeInterface.php +59 -0
  182. src/Notice/Notices.php +23 -0
  183. src/Notice/ThanksNotice.php +89 -0
  184. src/Notice/WelcomeNotice.php +73 -0
  185. src/Plugin/Activation.php +35 -0
  186. src/Plugin/Activation/DefaultSettings.php +23 -0
  187. src/Plugin/Activation/RefreshLoader.php +20 -0
  188. src/Plugin/Activation/WebpDirectory.php +21 -0
  189. src/Plugin/Deactivation.php +40 -0
  190. src/Plugin/Deactivation/CronReset.php +20 -0
  191. src/Plugin/Deactivation/Modal.php +87 -0
  192. src/Plugin/Deactivation/RefreshLoader.php +20 -0
  193. src/Plugin/Links.php +91 -0
  194. src/Plugin/Uninstall.php +37 -0
  195. src/Plugin/Uninstall/DebugFiles.php +27 -0
  196. src/Plugin/Uninstall/HtaccessFile.php +21 -0
  197. src/Plugin/Uninstall/PluginSettings.php +28 -0
  198. src/Plugin/Uninstall/WebpFiles.php +78 -0
  199. src/Plugin/Update.php +48 -0
  200. src/PluginAccessAbstract.php +54 -0
  201. src/PluginAccessInterface.php +37 -0
  202. src/Settings/AdminAssets.php +57 -0
  203. src/Settings/Option/ConversionMethodOption.php +100 -0
  204. src/Settings/Option/ExtraFeaturesOption.php +128 -0
  205. src/Settings/Option/ImagesQualityOption.php +79 -0
  206. src/Settings/Option/LoaderTypeOption.php +85 -0
  207. src/Settings/Option/OptionAbstract.php +46 -0
  208. src/Settings/Option/OptionIntegration.php +85 -0
  209. src/Settings/Option/OptionInterface.php +78 -0
  210. src/Settings/Option/OutputFormatsOption.php +97 -0
  211. src/Settings/Option/SupportedDirectoriesOption.php +84 -0
  212. src/Settings/Option/SupportedExtensionsOption.php +79 -0
  213. src/Settings/Options.php +71 -0
  214. src/Settings/Page/DebugPage.php +85 -0
  215. src/Settings/Page/PageAbstract.php +22 -0
  216. src/Settings/Page/PageInterface.php +25 -0
  217. src/Settings/Page/SettingsPage.php +65 -0
  218. src/Settings/Pages.php +121 -0
  219. src/Settings/SettingsSave.php +52 -0
  220. src/WebpConverter.php +98 -0
  221. templates/components/errors/bypassing-apache.php +29 -0
  222. templates/components/errors/libs-not-installed.php +20 -0
  223. templates/components/errors/libs-without-avif-support.php +21 -0
  224. templates/components/errors/libs-without-webp-support.php +26 -0
  225. templates/components/errors/passthru-execution.php +27 -0
  226. templates/components/errors/passthru-info.php +21 -0
  227. templates/components/errors/path-htaccess-not-writable.php +19 -0
  228. templates/components/errors/path-uploads-unavailable.php +22 -0
  229. templates/components/errors/path-webp-duplicated.php +20 -0
  230. templates/components/errors/path-webp-not-writable.php +22 -0
  231. templates/components/errors/rest-api-disabled.php +21 -0
  232. templates/components/errors/rewrites-cached.php +28 -0
  233. templates/components/errors/rewrites-not-working.php +27 -0
  234. templates/components/errors/settings-incorrect.php +15 -0
  235. templates/components/fields/checkbox.php +36 -0
  236. templates/components/fields/quality.php +31 -0
  237. templates/components/fields/radio.php +36 -0
  238. templates/components/notices/thanks.php +54 -0
  239. templates/components/notices/welcome.php +35 -0
  240. templates/components/server/debug.php +55 -0
  241. templates/components/server/filters.php +62 -0
  242. templates/components/server/gd.php +14 -0
  243. templates/components/server/imagick.php +14 -0
  244. templates/components/server/wordpress.php +19 -0
  245. templates/components/widgets/about.php +43 -0
  246. templates/components/widgets/donate.php +37 -0
  247. templates/components/widgets/errors.php +33 -0
  248. templates/components/widgets/options.php +49 -0
  249. templates/components/widgets/regenerate.php +124 -0
  250. templates/components/widgets/server.php +59 -0
  251. templates/components/widgets/support.php +64 -0
  252. templates/views/deactivation-modal.php +64 -0
  253. templates/views/settings-debug.php +37 -0
  254. templates/views/settings.php +45 -0
  255. vendor/autoload.php +1 -1
  256. vendor/composer/autoload_psr4.php +1 -1
  257. vendor/composer/autoload_real.php +4 -4
  258. vendor/composer/autoload_static.php +4 -4
  259. webp-converter-for-media.php +20 -20
app/Action/Convert.php DELETED
@@ -1,48 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Action;
4
-
5
- use WebpConverter\Media\Attachment;
6
- use WebpConverter\Method\MethodIntegrator;
7
-
8
- class Convert
9
- {
10
- public function __construct()
11
- {
12
- add_action('webpc_convert_paths', [$this, 'convertFilesByPaths']);
13
- add_action('webpc_convert_attachment', [$this, 'convertFilesByAttachment']);
14
- add_action('webpc_convert_dir', [$this, 'convertFilesByDirectory'], 10, 2);
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- public function convertFilesByPaths($paths)
22
- {
23
- $settings = apply_filters('webpc_get_values', []);
24
-
25
- $convertMethod = (new MethodIntegrator())->getMethodUsed($settings['method']);
26
- if ($convertMethod === null) {
27
- return false;
28
- }
29
-
30
- foreach ($paths as $path) {
31
- $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
32
- if (!in_array($extension, $settings['extensions'])) continue;
33
- $convertMethod->convertImage($path);
34
- }
35
- }
36
-
37
- public function convertFilesByAttachment($postId)
38
- {
39
- $paths = (new Attachment())->getAttachmentPaths($postId);
40
- do_action('webpc_convert_paths', $paths);
41
- }
42
-
43
- public function convertFilesByDirectory($dirPath, $skipExists = true)
44
- {
45
- $paths = apply_filters('webpc_dir_files', [], $dirPath, $skipExists);
46
- do_action('webpc_convert_paths', $paths);
47
- }
48
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Action/Cron.php DELETED
@@ -1,36 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Action;
4
-
5
- class Cron
6
- {
7
- const CRON_ACTION = 'webpc_regenerate_all';
8
-
9
- public function __construct()
10
- {
11
- add_filter('cron_schedules', [$this, 'addCronInterval']);
12
- add_action('init', [$this, 'addCronEvent']);
13
- }
14
-
15
- /* ---
16
- Functions
17
- --- */
18
-
19
- public function addCronInterval($schedules)
20
- {
21
- $schedules['webpc_cron'] = [
22
- 'interval' => apply_filters('webpc_cron_interval', HOUR_IN_SECONDS),
23
- 'display' => 'WebP Converter for Media',
24
- ];
25
- return $schedules;
26
- }
27
-
28
- public function addCronEvent()
29
- {
30
- if (wp_next_scheduled(self::CRON_ACTION)
31
- || (!$settings = apply_filters('webpc_get_values', []))
32
- || !in_array('cron_enabled', $settings['features'])) return;
33
-
34
- wp_schedule_event(time(), 'webpc_cron', self::CRON_ACTION);
35
- }
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Action/Delete.php DELETED
@@ -1,38 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Action;
4
-
5
- use WebpConverter\Convert\Directory;
6
- use WebpConverter\Convert\Size;
7
-
8
- class Delete
9
- {
10
- public function __construct()
11
- {
12
- add_action('webpc_delete_paths', [$this, 'deleteFilesByPaths']);
13
- }
14
-
15
- /* ---
16
- Functions
17
- --- */
18
-
19
- public function deleteFilesByPaths($paths)
20
- {
21
- foreach ($paths as $path) {
22
- $this->deleteFileByPath($path);
23
- }
24
- }
25
-
26
- private function deleteFileByPath($path)
27
- {
28
- if (!($sourceWebP = Directory::getPath($path))) {
29
- return;
30
- }
31
-
32
- if (is_writable($sourceWebP)) {
33
- unlink($sourceWebP);
34
- } else if (is_writable($sourceWebP . SIZE::DELETED_FILE_EXTENSION)) {
35
- unlink($sourceWebP . SIZE::DELETED_FILE_EXTENSION);
36
- }
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Action/Regenerate.php DELETED
@@ -1,23 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Action;
4
-
5
- use WebpConverter\Regenerate\Paths;
6
-
7
- class Regenerate
8
- {
9
- public function __construct()
10
- {
11
- add_action('webpc_regenerate_all', [$this, 'runRegenerationAllImages']);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function runRegenerationAllImages()
19
- {
20
- $paths = (new Paths())->getPaths(true);
21
- do_action('webpc_convert_paths', $paths);
22
- }
23
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Action/_Core.php DELETED
@@ -1,14 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Action;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Convert();
10
- new Cron();
11
- new Delete();
12
- new Regenerate();
13
- }
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Assets.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- class Assets
6
- {
7
- private $pathCss = WEBPC_URL . 'public/build/css/styles.css';
8
- private $pathJs = WEBPC_URL . 'public/build/js/scripts.js';
9
-
10
- public function __construct()
11
- {
12
- add_filter('admin_enqueue_scripts', [$this, 'loadStyles']);
13
- add_filter('admin_enqueue_scripts', [$this, 'loadScripts']);
14
- }
15
-
16
- /* ---
17
- Functions
18
- --- */
19
-
20
- public function loadStyles()
21
- {
22
- wp_register_style('webp-converter', $this->pathCss, '', WEBPC_VERSION);
23
- wp_enqueue_style('webp-converter');
24
- }
25
-
26
- public function loadScripts()
27
- {
28
- wp_register_script('webp-converter', $this->pathJs, 'jquery', WEBPC_VERSION, true);
29
- wp_enqueue_script('webp-converter');
30
- }
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Modal.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- use WebpConverter\Admin\Assets;
6
-
7
- class Modal
8
- {
9
- public function __construct()
10
- {
11
- add_action('admin_init', [$this, 'showDeactivationModal']);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function showDeactivationModal()
19
- {
20
- if (basename(($_SERVER['SCRIPT_FILENAME'] ?? ''), '.php') !== 'plugins') {
21
- return;
22
- }
23
-
24
- new Assets();
25
- add_action('admin_footer', ['WebpConverter\Admin\Modal', 'loadDeactivationModal']);
26
- }
27
-
28
- public static function loadDeactivationModal()
29
- {
30
- require_once WEBPC_PATH . 'resources/views/deactivation-modal.php';
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Notice.php DELETED
@@ -1,63 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- use WebpConverter\Admin\Assets;
6
- use WebpConverter\Plugin\Activation;
7
-
8
- class Notice
9
- {
10
- const NOTICE_THANKS_OPTION = 'webpc_notice_hidden';
11
-
12
- public function __construct()
13
- {
14
- add_action('admin_init', [$this, 'showWelcomeNotice']);
15
- add_action('admin_init', [$this, 'showThanksNotice']);
16
- add_action('wp_ajax_webpc_notice', [$this, 'hideThanksNotice']);
17
- }
18
-
19
- /* ---
20
- Functions
21
- --- */
22
-
23
- public function showWelcomeNotice()
24
- {
25
- if (get_option(Activation::NEW_INSTALLATION_OPTION) !== '1') return;
26
-
27
- new Assets();
28
- add_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
29
- add_action('network_admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
30
- }
31
-
32
- public static function loadWelcomeNotice()
33
- {
34
- require_once WEBPC_PATH . 'resources/components/notices/welcome.php';
35
- }
36
-
37
- public function showThanksNotice()
38
- {
39
- if ((basename($_SERVER['PHP_SELF']) !== 'index.php')
40
- || (get_option(self::NOTICE_THANKS_OPTION, 0) >= time())) return;
41
-
42
- if (!is_multisite()) {
43
- new Assets();
44
- add_action('admin_notices', [$this, 'loadThanksNotice']);
45
- } else if (is_network_admin()) {
46
- new Assets();
47
- add_action('network_admin_notices', [$this, 'loadThanksNotice']);
48
- }
49
- }
50
-
51
- public function loadThanksNotice()
52
- {
53
- require_once WEBPC_PATH . 'resources/components/notices/thanks.php';
54
- }
55
-
56
- public function hideThanksNotice()
57
- {
58
- $isPermanent = isset($_POST['is_permanently']) && $_POST['is_permanently'];
59
- $expires = strtotime($isPermanent ? '+10 years' : '+ 1 month');
60
-
61
- update_option(self::NOTICE_THANKS_OPTION, $expires);
62
- }
63
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Plugin.php DELETED
@@ -1,54 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- use WebpConverter\Settings\Page;
6
-
7
- class Plugin
8
- {
9
- public function __construct()
10
- {
11
- add_filter('plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToSettingsForAdmin']);
12
- add_filter('network_admin_plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToSettingsForNetwork']);
13
- add_filter('plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToDonate']);
14
- add_filter('network_admin_plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToDonate']);
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- public function addLinkToSettingsForAdmin($links)
22
- {
23
- if (is_multisite()) {
24
- return $links;
25
- }
26
-
27
- return $this->addLinkToSettings($links);
28
- }
29
-
30
- public function addLinkToSettingsForNetwork($links)
31
- {
32
- return $this->addLinkToSettings($links);
33
- }
34
-
35
- private function addLinkToSettings($links)
36
- {
37
- array_unshift($links, sprintf(
38
- esc_html(__('%sSettings%s', 'webp-converter-for-media')),
39
- '<a href="' . Page::getSettingsPageUrl() . '">',
40
- '</a>'
41
- ));
42
- return $links;
43
- }
44
-
45
- public function addLinkToDonate($links)
46
- {
47
- $links[] = sprintf(
48
- esc_html(__('%sProvide us a coffee%s', 'webp-converter-for-media')),
49
- '<a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=plugin-links" target="_blank">',
50
- '</a>'
51
- );
52
- return $links;
53
- }
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/_Core.php DELETED
@@ -1,13 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Modal();
10
- new Notice();
11
- new Plugin();
12
- }
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/Dir.php DELETED
@@ -1,43 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class Dir
6
- {
7
- public function __construct()
8
- {
9
- add_filter('webpc_dir_files', [$this, 'getFilesByDirectory'], 10, 3);
10
- }
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public function getFilesByDirectory($value, $dirPath, $skipExists = false)
17
- {
18
- if (!file_exists($dirPath)) return $value;
19
-
20
- $settings = apply_filters('webpc_get_values', []);
21
- $excluded = apply_filters('webpc_dir_excluded', []);
22
-
23
- $paths = $this->findFilesInDirectory($dirPath, $settings['extensions'], $excluded);
24
- return apply_filters('webpc_files_paths', $paths, $skipExists);
25
- }
26
-
27
- private function findFilesInDirectory($dirPath, $allowedExts, $excludedDirs)
28
- {
29
- $paths = scandir($dirPath);
30
- $list = [];
31
- foreach ($paths as $path) {
32
- if (in_array($path, $excludedDirs)) continue;
33
-
34
- $currentPath = $dirPath . '/' . urlencode($path);
35
- if (is_dir($currentPath)) {
36
- $list = array_merge($list, $this->findFilesInDirectory($currentPath, $allowedExts, $excludedDirs));
37
- } else if (in_array(strtolower(pathinfo($currentPath, PATHINFO_EXTENSION)), $allowedExts)) {
38
- $list[] = $currentPath;
39
- }
40
- }
41
- return $list;
42
- }
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/Directory.php DELETED
@@ -1,46 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class Directory
6
- {
7
- /* ---
8
- Functions
9
- --- */
10
-
11
- public static function getPath($path, $createDirectory = false)
12
- {
13
- $webpRoot = apply_filters('webpc_dir_path', '', 'webp');
14
- $uploadsRoot = dirname($webpRoot);
15
- $outputPath = str_replace(realpath($uploadsRoot), '', realpath($path));
16
- $outputPath = trim($outputPath, '\/');
17
-
18
- $newPath = sprintf('%s/%s.webp', $webpRoot, $outputPath);
19
- if (!$createDirectory) return $newPath;
20
-
21
- if (!$paths = self::checkDirectories($newPath)) return $newPath;
22
- else if (!self::makeDirectories($paths)) return null;
23
- else return $newPath;
24
- }
25
-
26
- private static function checkDirectories($path)
27
- {
28
- $current = dirname($path);
29
- $paths = [];
30
- while (!file_exists($current)) {
31
- $paths[] = $current;
32
- $current = dirname($current);
33
- }
34
- return $paths;
35
- }
36
-
37
- private static function makeDirectories($paths)
38
- {
39
- $paths = array_reverse($paths);
40
- foreach ($paths as $path) {
41
- if (!is_writable(dirname($path))) return false;
42
- mkdir($path);
43
- }
44
- return true;
45
- }
46
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/Paths.php DELETED
@@ -1,84 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class Paths
6
- {
7
- const PATH_PLUGINS = 'wp-content/plugins';
8
- const PATH_THEMES = 'wp-content/themes';
9
- const PATH_UPLOADS = 'wp-content/uploads';
10
- const PATH_OUTPUT = 'wp-content/uploads-webpc';
11
- const DIRS_EXCLUDED = ['.', '..', '.git', '.svn', 'node_modules'];
12
-
13
- public function __construct()
14
- {
15
- add_filter('webpc_dir_name', [$this, 'getDirAsName'], 0, 2);
16
- add_filter('webpc_dir_path', [$this, 'getDirAsPath'], 0, 2);
17
- add_filter('webpc_dir_url', [$this, 'getDirAsUrl'], 0, 2);
18
- add_filter('webpc_uploads_prefix', [$this, 'getPrefixPath'], 0);
19
- add_filter('webpc_dir_excluded', [$this, 'getExcludedDirs'], 0);
20
- }
21
-
22
- /* ---
23
- Functions
24
- --- */
25
-
26
- public function getDirAsName($value, $directory)
27
- {
28
- switch ($directory) {
29
- case 'plugins':
30
- return self::PATH_PLUGINS;
31
- break;
32
- case 'themes':
33
- return self::PATH_THEMES;
34
- break;
35
- case 'uploads':
36
- return self::PATH_UPLOADS;
37
- break;
38
- case 'webp':
39
- return self::PATH_OUTPUT;
40
- break;
41
- }
42
- return null;
43
- }
44
-
45
- public function getDirAsPath($value, $directory)
46
- {
47
- $sourcePath = apply_filters('webpc_site_root', realpath(ABSPATH));
48
- switch ($directory) {
49
- default:
50
- if ($path = apply_filters('webpc_dir_name', null, $directory)) {
51
- return $sourcePath . '/' . $path;
52
- }
53
- break;
54
- }
55
- return null;
56
- }
57
-
58
- public function getDirAsUrl($value, $directory)
59
- {
60
- $sourceUrl = apply_filters('webpc_site_url', get_site_url());
61
- switch ($directory) {
62
- default:
63
- if ($path = apply_filters('webpc_dir_name', null, $directory)) {
64
- return $sourceUrl . '/' . $path;
65
- }
66
- break;
67
- }
68
- }
69
-
70
- public function getPrefixPath($value)
71
- {
72
- $docDir = realpath($_SERVER['DOCUMENT_ROOT']);
73
- $wpDir = apply_filters('webpc_site_root', realpath(ABSPATH));
74
- $diffDir = trim(str_replace($docDir, '', $wpDir), '\/');
75
- $diffPath = sprintf('/%s/', $diffDir);
76
-
77
- return str_replace('//', '/', $diffPath);
78
- }
79
-
80
- public function getExcludedDirs($value)
81
- {
82
- return self::DIRS_EXCLUDED;
83
- }
84
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/Server.php DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class Server
6
- {
7
- /* ---
8
- Functions
9
- --- */
10
-
11
- public static function setSettings()
12
- {
13
- ini_set('memory_limit', '1G');
14
-
15
- if (strpos(ini_get('disable_functions'), 'set_time_limit') === false) {
16
- set_time_limit(120);
17
- }
18
- }
19
-
20
- public static function checkIfFileExists($path)
21
- {
22
- if (is_readable($path)) return true;
23
- else if (!file_exists($path)) return sprintf('File "%s" does not exist. Please check file path using.', $path);
24
- else return sprintf('File "%s" is unreadable. Please check file permissions.', $path);
25
- }
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/Size.php DELETED
@@ -1,36 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class Size
6
- {
7
- const DELETED_FILE_EXTENSION = '.deleted';
8
-
9
- public function __construct()
10
- {
11
- add_action('webpc_convert_after', [$this, 'removeImageIfIsLarger'], 10, 2);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function removeImageIfIsLarger($webpPath, $originalPath)
19
- {
20
- if ((!$settings = apply_filters('webpc_get_values', []))
21
- || !in_array('only_smaller', $settings['features'])
22
- || (!file_exists($webpPath) || !file_exists($originalPath))
23
- || (filesize($webpPath) < filesize($originalPath))) return;
24
-
25
- $file = fopen($webpPath . self::DELETED_FILE_EXTENSION, 'w');
26
- fclose($file);
27
- unlink($webpPath);
28
-
29
- $e = new \Exception(sprintf(
30
- 'Image "%s" converted to WebP is larger than original and has been deleted.',
31
- $originalPath
32
- ));
33
- $e->status = 'larger_than_original';
34
- throw $e;
35
- }
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Convert/_Core.php DELETED
@@ -1,13 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Convert;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Dir();
10
- new Paths();
11
- new Size();
12
- }
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/ErrorAbstract.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorInterface;
6
-
7
- abstract class ErrorAbstract implements ErrorInterface
8
- {
9
- private $settings = [];
10
-
11
- public function __construct()
12
- {
13
- $this->settings = apply_filters('webpc_get_values', []);
14
- }
15
-
16
- /* ---
17
- Functions
18
- --- */
19
-
20
- public function getSettings()
21
- {
22
- return $this->settings;
23
- }
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/ErrorInterface.php DELETED
@@ -1,14 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- interface ErrorInterface
6
- {
7
- /* ---
8
- Functions
9
- --- */
10
-
11
- public function getSettings();
12
-
13
- public function getErrorCodes();
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/LibsError.php DELETED
@@ -1,39 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
- use WebpConverter\Method\Gd;
8
- use WebpConverter\Method\Imagick;
9
-
10
- class LibsError extends ErrorAbstract implements ErrorInterface
11
- {
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public function getErrorCodes()
17
- {
18
- $errors = [];
19
-
20
- if ($this->ifLibsAreInstalled() !== true) {
21
- $errors[] = 'libs_not_installed';
22
- } else if ($this->ifLibsSupportWebp() !== true) {
23
- $errors[] = 'libs_without_webp_support';
24
- }
25
-
26
- return $errors;
27
- }
28
-
29
- private function ifLibsAreInstalled()
30
- {
31
- return (Gd::isMethodInstalled() || Imagick::isMethodInstalled());
32
- }
33
-
34
- private function ifLibsSupportWebp()
35
- {
36
- $methods = apply_filters('webpc_get_methods', []);
37
- return (count($methods) > 0);
38
- }
39
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/PassthruError.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
- use WebpConverter\Loader\Passthru;
8
-
9
- class PassthruError extends ErrorAbstract implements ErrorInterface
10
- {
11
- /* ---
12
- Functions
13
- --- */
14
-
15
- public function getErrorCodes()
16
- {
17
- $errors = [];
18
-
19
- if ($this->ifPassthruExecutionAllowed() !== true) {
20
- $errors[] = 'passthru_execution';
21
- }
22
-
23
- return $errors;
24
- }
25
-
26
- private function ifPassthruExecutionAllowed()
27
- {
28
- if (Passthru::isActiveLoader() !== true) {
29
- return true;
30
- }
31
-
32
- $url = Passthru::getLoaderUrl() . '?nocache=1';
33
- $ch = curl_init($url);
34
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
35
- curl_setopt($ch, CURLOPT_NOBODY, 1);
36
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
37
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
38
- curl_setopt($ch, CURLOPT_TIMEOUT, 3);
39
- curl_exec($ch);
40
- $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
41
- curl_close($ch);
42
-
43
- return ($code === 200);
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/PathsError.php DELETED
@@ -1,58 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
-
8
- class PathsError extends ErrorAbstract implements ErrorInterface
9
- {
10
- /* ---
11
- Functions
12
- --- */
13
-
14
- public function getErrorCodes()
15
- {
16
- $errors = [];
17
-
18
- if ($this->ifUploadsPathExists() !== true) {
19
- $errors[] = 'path_uploads_unavailable';
20
- } else if ($this->ifHtaccessIsWriteable() !== true) {
21
- $errors[] = 'path_htaccess_not_writable';
22
- }
23
- if ($this->ifPathsAreDifferent() !== true) {
24
- $errors[] = 'path_webp_duplicated';
25
- } else if ($this->ifWebpPathIsWriteable() !== true) {
26
- $errors[] = 'path_webp_not_writable';
27
- }
28
-
29
- return $errors;
30
- }
31
-
32
- private function ifUploadsPathExists()
33
- {
34
- $path = apply_filters('webpc_dir_path', '', 'uploads');
35
- return (is_dir($path) && ($path !== ABSPATH));
36
- }
37
-
38
- private function ifHtaccessIsWriteable()
39
- {
40
- $pathDir = apply_filters('webpc_dir_path', '', 'uploads');
41
- $pathFile = $pathDir . '/.htaccess';
42
- if (file_exists($pathFile)) return (is_readable($pathFile) && is_writable($pathFile));
43
- else return is_writable($pathDir);
44
- }
45
-
46
- private function ifPathsAreDifferent()
47
- {
48
- $pathUploads = apply_filters('webpc_dir_path', '', 'uploads');
49
- $pathWebp = apply_filters('webpc_dir_path', '', 'webp');
50
- return ($pathUploads !== $pathWebp);
51
- }
52
-
53
- private function ifWebpPathIsWriteable()
54
- {
55
- $path = apply_filters('webpc_dir_path', '', 'webp');
56
- return (is_dir($path) || is_writable(dirname($path)));
57
- }
58
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/RestapiError.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
-
8
- class RestapiError extends ErrorAbstract implements ErrorInterface
9
- {
10
- /* ---
11
- Functions
12
- --- */
13
-
14
- public function getErrorCodes()
15
- {
16
- $errors = [];
17
-
18
- if ($this->ifRestApiIsEnabled() !== true) {
19
- $errors[] = 'rest_api_disabled';
20
- }
21
-
22
- return $errors;
23
- }
24
-
25
- private function ifRestApiIsEnabled()
26
- {
27
- return ((apply_filters('rest_enabled', true) === true)
28
- && (apply_filters('rest_jsonp_enabled', true) === true)
29
- && (apply_filters('rest_authentication_errors', true) === true));
30
- }
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/RewritesError.php DELETED
@@ -1,102 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
- use WebpConverter\Convert\Directory;
8
- use WebpConverter\Loader\LoaderAbstract;
9
- use WebpConverter\Traits\FileLoaderTrait;
10
-
11
- class RewritesError extends ErrorAbstract implements ErrorInterface
12
- {
13
- use FileLoaderTrait;
14
-
15
- const PATH_SOURCE_FILE_PNG = '/public/img/icon-test.png';
16
- const PATH_SOURCE_FILE_WEBP = '/public/img/icon-test.webp';
17
- const PATH_OUTPUT_FILE_PNG = '/webp-converter-for-media-test.png';
18
- const PATH_OUTPUT_FILE_PNG2 = '/webp-converter-for-media-test.png2';
19
- const PATH_OUTPUT_FILE_PNG_AS_WEBP = self::PATH_OUTPUT_FILE_PNG . '.webp';
20
- const PATH_OUTPUT_FILE_PNG2_AS_WEBP = self::PATH_OUTPUT_FILE_PNG2 . '.webp';
21
-
22
- /* ---
23
- Functions
24
- --- */
25
-
26
- public function getErrorCodes()
27
- {
28
- $this->convertImagesForDebug();
29
- $errors = [];
30
-
31
- add_filter('webpc_get_values', ['WebpConverter\Settings\Errors', 'setExtensionsForDebug']);
32
- do_action(LoaderAbstract::ACTION_NAME, true);
33
-
34
- if ($this->ifRedirectsAreWorks() !== true) {
35
- if ($this->ifBypassingApacheIsActive() === true) {
36
- $errors[] = 'bypassing_apache';
37
- } else {
38
- $errors[] = 'rewrites_not_working';
39
- }
40
- } else if ($this->ifRedirectsAreCached() === true) {
41
- $errors[] = 'rewrites_cached';
42
- }
43
-
44
- remove_filter('webpc_get_values', ['WebpConverter\Settings\Errors', 'setExtensionsForDebug']);
45
- do_action(LoaderAbstract::ACTION_NAME, true);
46
-
47
- return $errors;
48
- }
49
-
50
- private function convertImagesForDebug()
51
- {
52
- $uploadsDir = apply_filters('webpc_dir_path', '', 'uploads');
53
- $pathFilePng = $uploadsDir . self::PATH_OUTPUT_FILE_PNG;
54
- $pathFilePng2 = $uploadsDir . self::PATH_OUTPUT_FILE_PNG2;
55
- if (!is_writable($uploadsDir)) {
56
- return;
57
- }
58
-
59
- if (!file_exists($pathFilePng) || !file_exists($pathFilePng2)) {
60
- copy(WEBPC_PATH . self::PATH_SOURCE_FILE_PNG, $pathFilePng);
61
- copy(WEBPC_PATH . self::PATH_SOURCE_FILE_PNG, $pathFilePng2);
62
- }
63
-
64
- if (($outputPath = Directory::getPath($pathFilePng, true)) && !file_exists($outputPath)) {
65
- copy(WEBPC_PATH . self::PATH_SOURCE_FILE_WEBP, $outputPath);
66
- }
67
- if (($outputPath = Directory::getPath($pathFilePng2, true)) && !file_exists($outputPath)) {
68
- copy(WEBPC_PATH . self::PATH_SOURCE_FILE_WEBP, $outputPath);
69
- }
70
- }
71
-
72
- private function ifRedirectsAreWorks()
73
- {
74
- $uploadsDir = apply_filters('webpc_dir_path', '', 'uploads');
75
- $uploadsUrl = apply_filters('webpc_dir_url', '', 'uploads');
76
-
77
- $fileSize = $this->getFileSizeByPath($uploadsDir . self::PATH_OUTPUT_FILE_PNG);
78
- $fileWebp = $this->getFileSizeByUrl($uploadsUrl . self::PATH_OUTPUT_FILE_PNG);
79
-
80
- return ($fileWebp < $fileSize);
81
- }
82
-
83
- private function ifBypassingApacheIsActive()
84
- {
85
- $uploadsUrl = apply_filters('webpc_dir_url', '', 'uploads');
86
-
87
- $filePng = $this->getFileSizeByUrl($uploadsUrl . self::PATH_OUTPUT_FILE_PNG);
88
- $filePng2 = $this->getFileSizeByUrl($uploadsUrl . self::PATH_OUTPUT_FILE_PNG2);
89
-
90
- return ($filePng > $filePng2);
91
- }
92
-
93
- private function ifRedirectsAreCached()
94
- {
95
- $uploadsUrl = apply_filters('webpc_dir_url', '', 'uploads');
96
-
97
- $fileWebp = $this->getFileSizeByUrl($uploadsUrl . self::PATH_OUTPUT_FILE_PNG);
98
- $fileOriginal = $this->getFileSizeByUrl($uploadsUrl . self::PATH_OUTPUT_FILE_PNG, false);
99
-
100
- return (($fileWebp > 0) && ($fileWebp === $fileOriginal));
101
- }
102
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Error/SettingsError.php DELETED
@@ -1,35 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Error;
4
-
5
- use WebpConverter\Error\ErrorAbstract;
6
- use WebpConverter\Error\ErrorInterface;
7
-
8
- class SettingsError extends ErrorAbstract implements ErrorInterface
9
- {
10
- /* ---
11
- Functions
12
- --- */
13
-
14
- public function getErrorCodes()
15
- {
16
- $errors = [];
17
-
18
- if ($this->ifSettingsAreCorrect() !== true) {
19
- $errors[] = 'settings_incorrect';
20
- }
21
-
22
- return $errors;
23
- }
24
-
25
- private function ifSettingsAreCorrect()
26
- {
27
- $settings = $this->getSettings();
28
- if ((!isset($settings['extensions']) || !$settings['extensions'])
29
- || (!isset($settings['dirs']) || !$settings['dirs'])
30
- || (!isset($settings['method']) || !in_array($settings['method'], apply_filters('webpc_get_methods', [])))
31
- || (!isset($settings['quality']) || !$settings['quality'])) return false;
32
-
33
- return true;
34
- }
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Loader/Htaccess.php DELETED
@@ -1,162 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Loader;
4
-
5
- use WebpConverter\Loader\LoaderAbstract;
6
- use WebpConverter\Loader\LoaderInterface;
7
-
8
- class Htaccess extends LoaderAbstract implements LoaderInterface
9
- {
10
- const LOADER_TYPE = 'htaccess';
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public static function isActiveLoader()
17
- {
18
- $settings = apply_filters('webpc_get_values', []);
19
- return (!isset($settings['loader_type']) || ($settings['loader_type'] === self::LOADER_TYPE));
20
- }
21
-
22
- public function activateLoader()
23
- {
24
- $this->addRewriteRulesToWpContent(true);
25
- $this->addRewriteRulesToUploads(true);
26
- $this->addRewriteRulesToUploadsWebp(true);
27
- }
28
-
29
- public function deactivateLoader()
30
- {
31
- $this->addRewriteRulesToWpContent(false);
32
- $this->addRewriteRulesToUploads(false);
33
- $this->addRewriteRulesToUploadsWebp(false);
34
- }
35
-
36
- private function addRewriteRulesToWpContent($isActive)
37
- {
38
- $path = dirname(apply_filters('webpc_dir_path', '', 'uploads'));
39
- if (!$isActive) return $this->saveRewritesInHtaccesss($path);
40
-
41
- $settings = apply_filters('webpc_get_values', []);
42
- $rows = [
43
- $this->getModRewriteRules($settings),
44
- ];
45
-
46
- $content = $this->addCommentsToRules($rows);
47
- $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
48
- $this->saveRewritesInHtaccesss($path, $content);
49
- }
50
-
51
- private function addRewriteRulesToUploads($isActive)
52
- {
53
- $path = apply_filters('webpc_dir_path', '', 'uploads');
54
- if (!$isActive) return $this->saveRewritesInHtaccesss($path);
55
-
56
- $settings = apply_filters('webpc_get_values', []);
57
- $pathParts = explode('/', apply_filters('webpc_dir_name', '', 'uploads'));
58
- $rows = [
59
- $this->getModRewriteRules($settings, end($pathParts)),
60
- ];
61
-
62
- $content = $this->addCommentsToRules($rows);
63
- $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
64
- $this->saveRewritesInHtaccesss($path, $content);
65
- }
66
-
67
- private function addRewriteRulesToUploadsWebp($isActive)
68
- {
69
- $path = apply_filters('webpc_dir_path', '', 'webp');
70
- if (!$isActive) return $this->saveRewritesInHtaccesss($path);
71
-
72
- $values = apply_filters('webpc_get_values', []);
73
- $rows = [
74
- $this->getModMimeRules($values),
75
- $this->getModExpiresRules($values),
76
- ];
77
-
78
- $content = $this->addCommentsToRules($rows);
79
- $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
80
- $this->saveRewritesInHtaccesss($path, $content);
81
- }
82
-
83
- private function getModRewriteRules($settings, $outputPath = null)
84
- {
85
- $content = '';
86
- if (!$settings['extensions']) return $content;
87
-
88
- $path = apply_filters('webpc_uploads_prefix', '/');
89
- $path .= apply_filters('webpc_dir_name', '', 'webp');
90
- if ($outputPath !== null) $path .= '/' . $outputPath;
91
-
92
- $content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
93
- $content .= ' RewriteEngine On' . PHP_EOL;
94
- foreach ($settings['extensions'] as $ext) {
95
- $content .= ' RewriteCond %{HTTP_ACCEPT} image/webp' . PHP_EOL;
96
- $content .= " RewriteCond %{DOCUMENT_ROOT}${path}/$1.${ext}.webp -f" . PHP_EOL;
97
- if (!in_array('referer_disabled', $settings['features'])) {
98
- $content .= " RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} ^([^@]*)@@https?://\\1/.*" . PHP_EOL;
99
- }
100
- $content .= " RewriteRule (.+)\.${ext}$ ${path}/$1.${ext}.webp [NC,T=image/webp,E=cache-control:no-cache,L]" . PHP_EOL;
101
- }
102
- $content .= '</IfModule>';
103
-
104
- $content = apply_filters('webpc_htaccess_mod_rewrite', $content, $path);
105
- return $content;
106
- }
107
-
108
- private function getModExpiresRules($settings)
109
- {
110
- $content = '';
111
- if (!in_array('mod_expires', $settings['features'])) return $content;
112
-
113
- $content .= '<IfModule mod_expires.c>' . PHP_EOL;
114
- $content .= ' ExpiresActive On' . PHP_EOL;
115
- $content .= ' ExpiresByType image/webp "access plus 1 year"' . PHP_EOL;
116
- $content .= '</IfModule>';
117
-
118
- $content = apply_filters('webpc_htaccess_mod_expires', $content);
119
- return $content;
120
- }
121
-
122
- private function getModMimeRules($settings)
123
- {
124
- $content = '';
125
- if (!$settings['extensions']) return $content;
126
-
127
- $content .= '<IfModule mod_mime.c>' . PHP_EOL;
128
- $content .= ' AddType image/webp .webp' . PHP_EOL;
129
- $content .= '</IfModule>';
130
-
131
- $content = apply_filters('webpc_htaccess_mod_mime', $content);
132
- return $content;
133
- }
134
-
135
- private function addCommentsToRules($rules)
136
- {
137
- if (!$rules) return '';
138
-
139
- $rows = [];
140
- $rows[] = '';
141
- $rows[] = '# BEGIN WebP Converter';
142
- $rows[] = '# ! --- DO NOT EDIT PREVIOUS LINE --- !';
143
- $rows = array_merge($rows, array_filter($rules));
144
- $rows[] = '# ! --- DO NOT EDIT NEXT LINE --- !';
145
- $rows[] = '# END WebP Converter';
146
- $rows[] = '';
147
-
148
- return implode(PHP_EOL, $rows);
149
- }
150
-
151
- private function saveRewritesInHtaccesss($pathDir, $rules = '')
152
- {
153
- $pathFile = $pathDir . '/.htaccess';
154
-
155
- $code = (is_readable($pathFile)) ? file_get_contents($pathFile) : '';
156
- $code = preg_replace('/((:?[\r\n|\r|\n]?)# BEGIN WebP Converter(.*?)# END WebP Converter(:?(:?[\r\n|\r|\n]+)?))/s', '', $code);
157
- if ($rules && $code) $code = PHP_EOL . $code;
158
- $code = $rules . $code;
159
-
160
- if (is_writable($pathDir)) file_put_contents($pathFile, $code);
161
- }
162
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Loader/LoaderAbstract.php DELETED
@@ -1,42 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Loader;
4
-
5
- use WebpConverter\Loader\LoaderInterface;
6
-
7
- abstract class LoaderAbstract implements LoaderInterface
8
- {
9
- const ACTION_NAME = 'webpc_rewrite_htaccess';
10
-
11
- public function __construct()
12
- {
13
- add_action(self::ACTION_NAME, [$this, 'refreshLoader']);
14
- add_action('plugins_loaded', [$this, 'initHooks']);
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- public function initHooks()
22
- {
23
- if (!static::isActiveLoader() || apply_filters('webpc_server_errors', [], true)) {
24
- return;
25
- }
26
- $this->hooks();
27
- }
28
-
29
- public function hooks() {}
30
-
31
- public function refreshLoader($isActive) {
32
- if ($isActive && static::isActiveLoader()) {
33
- $this->activateLoader();
34
- } else {
35
- $this->deactivateLoader();
36
- }
37
- }
38
-
39
- public function activateLoader() {}
40
-
41
- public function deactivateLoader() {}
42
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Loader/LoaderInterface.php DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Loader;
4
-
5
- interface LoaderInterface
6
- {
7
- /* ---
8
- Functions
9
- --- */
10
-
11
- public function hooks();
12
-
13
- public static function isActiveLoader();
14
-
15
- public function refreshLoader($isActive);
16
-
17
- public function activateLoader();
18
-
19
- public function deactivateLoader();
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Loader/Passthru.php DELETED
@@ -1,103 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Loader;
4
-
5
- use WebpConverter\Loader\LoaderAbstract;
6
- use WebpConverter\Loader\LoaderInterface;
7
-
8
- class Passthru extends LoaderAbstract implements LoaderInterface
9
- {
10
- const LOADER_TYPE = 'passthru';
11
- const PATH_LOADER = '/webpc-passthru.php';
12
-
13
- /* ---
14
- Functions
15
- --- */
16
-
17
- public function hooks()
18
- {
19
- add_action('get_header', [$this, 'startBuffer']);
20
- }
21
-
22
- public static function isActiveLoader()
23
- {
24
- $settings = apply_filters('webpc_get_values', []);
25
- return (isset($settings['loader_type']) && ($settings['loader_type'] === self::LOADER_TYPE));
26
- }
27
-
28
- public function activateLoader()
29
- {
30
- $pathSource = WEBPC_PATH . 'libs/passthru.php';
31
- $sourceCode = (is_readable($pathSource)) ? file_get_contents($pathSource) : '';
32
- if (!$sourceCode) {
33
- return;
34
- }
35
-
36
- $pathDirUploads = apply_filters('webpc_dir_name', '', 'uploads');
37
- $pathDirWebp = apply_filters('webpc_dir_name', '', 'webp');
38
- $uploadSuffix = implode('/', array_diff(explode('/', $pathDirUploads), explode('/', $pathDirWebp)));
39
-
40
- $sourceCode = preg_replace(
41
- '/(PATH_UPLOADS = \')(\')/',
42
- '$1' . $pathDirUploads . '$2',
43
- $sourceCode);
44
- $sourceCode = preg_replace(
45
- '/(PATH_UPLOADS_WEBP = \')(\')/',
46
- '$1' . $pathDirWebp . '/' . $uploadSuffix . '$2',
47
- $sourceCode);
48
-
49
- $dirOutput = dirname(apply_filters('webpc_dir_path', '', 'uploads'));
50
- if (is_writable($dirOutput)) {
51
- file_put_contents($dirOutput . self::PATH_LOADER, $sourceCode);
52
- }
53
- }
54
-
55
- public function deactivateLoader()
56
- {
57
- $pathOutput = dirname(apply_filters('webpc_dir_path', '', 'uploads')) . self::PATH_LOADER;
58
- if (is_writable($pathOutput)) unlink($pathOutput);
59
- }
60
-
61
- public function startBuffer()
62
- {
63
- ob_start(['WebpConverter\Loader\Passthru', 'updateImageUrls']);
64
- }
65
-
66
- public static function updateImageUrls($buffer)
67
- {
68
- if (!self::isActiveLoader()) {
69
- return $buffer;
70
- }
71
-
72
- $settings = apply_filters('webpc_get_values', []);
73
- $extensions = implode('|', $settings['extensions'] ?? []);
74
- if (!$extensions || (!$sourceDir = self::getLoaderUrl())
75
- || (!$allowedDirs = self::getAllowedDirs())) {
76
- return $buffer;
77
- }
78
-
79
- $dirPaths = str_replace('/', '\\/', implode('|', self::getAllowedDirs()));
80
- return preg_replace(
81
- '/(https?:\/\/(?:[^\s()"\']+)(?:' . $dirPaths . ')(?:[^\s()"\']+)\.(?:' . $extensions . '))/',
82
- $sourceDir . '?src=$1&nocache=1',
83
- $buffer);
84
- }
85
-
86
- public static function getLoaderUrl()
87
- {
88
- if (!$sourceDir = dirname(apply_filters('webpc_dir_url', '', 'uploads'))) {
89
- return null;
90
- }
91
- return $sourceDir . self::PATH_LOADER;
92
- }
93
-
94
- public static function getAllowedDirs()
95
- {
96
- $settings = apply_filters('webpc_get_values', []);
97
- $dirs = [];
98
- foreach ($settings['dirs'] as $dir) {
99
- $dirs[] = apply_filters('webpc_dir_name', null, $dir);
100
- }
101
- return array_filter($dirs);
102
- }
103
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Loader/_Core.php DELETED
@@ -1,12 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Loader;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Htaccess();
10
- new Passthru();
11
- }
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
app/Media/Attachment.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Media;
4
-
5
- class Attachment
6
- {
7
- private $uploadDir, $imageSizes;
8
-
9
- public function __construct()
10
- {
11
- $this->uploadDir = wp_upload_dir();
12
- $this->imageSizes = get_intermediate_image_sizes();
13
- }
14
-
15
- /* ---
16
- Functions
17
- --- */
18
-
19
- public function getAttachmentPaths($attachmentId)
20
- {
21
- $settings = apply_filters('webpc_get_values', []);
22
- $paths = $this->getPathsByAttachment($attachmentId, $settings);
23
- return $paths;
24
- }
25
-
26
- private function getPathsByAttachment($postId, $settings)
27
- {
28
- $list = [];
29
- $metadata = wp_get_attachment_metadata($postId);
30
- if (!$metadata) return $list;
31
-
32
- $extension = strtolower(pathinfo($metadata['file'], PATHINFO_EXTENSION));
33
- if (!isset($metadata['file'])
34
- || !in_array($extension, $settings['extensions'])) return $list;
35
-
36
- $paths = $this->getPathsBySizes($postId, $metadata['file']);
37
- $paths = apply_filters('webpc_attachment_paths', $paths, $postId);
38
- $paths = apply_filters('webpc_files_paths', $paths, false);
39
- return $paths;
40
- }
41
-
42
- private function getPathsBySizes($postId, $path)
43
- {
44
- $list = [];
45
- $list[] = str_replace('\\', '/', implode('/', [$this->uploadDir['basedir'], $path]));
46
-
47
- foreach ($this->imageSizes as $size) {
48
- $src = wp_get_attachment_image_src($postId, $size);
49
- $url = str_replace($this->uploadDir['baseurl'], $this->uploadDir['basedir'], $src[0]);
50
- $url = str_replace('\\', '/', $url);
51
- $list[] = $url;
52
- }
53
- return array_values(array_unique($list));
54
- }
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Media/Delete.php DELETED
@@ -1,21 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Media;
4
-
5
- class Delete
6
- {
7
- public function __construct()
8
- {
9
- add_filter('wp_delete_file', [$this, 'deleteAttachmentFile']);
10
- }
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public function deleteAttachmentFile($path)
17
- {
18
- do_action('webpc_delete_paths', [$path]);
19
- return $path;
20
- }
21
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Media/Upload.php DELETED
@@ -1,64 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Media;
4
-
5
- class Upload
6
- {
7
- private $convertedPaths = [];
8
-
9
- public function __construct()
10
- {
11
- add_filter('wp_update_attachment_metadata', [$this, 'initAttachmentConvert'], 10, 2);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function initAttachmentConvert($data, $attachmentId)
19
- {
20
- if (!$data || !isset($data['file']) || !isset($data['sizes'])) return $data;
21
-
22
- $paths = $this->getSizesPaths($data);
23
- $paths = apply_filters('webpc_attachment_paths', $paths, $attachmentId);
24
- $paths = apply_filters('webpc_files_paths', $paths, false);
25
-
26
- $paths = array_diff($paths, $this->convertedPaths);
27
- $this->convertedPaths = array_merge($this->convertedPaths, $paths);
28
- $this->initConversion($paths);
29
-
30
- return $data;
31
- }
32
-
33
- private function getSizesPaths($data)
34
- {
35
- $directory = $this->getAttachmentDirectory($data['file']);
36
- $list = [];
37
-
38
- $list[] = $directory . basename($data['file']);
39
- foreach ($data['sizes'] as $key => $size) {
40
- $path = $directory . $size['file'];
41
- if (!in_array($path, $list)) $list[] = $path;
42
- }
43
- return array_values(array_unique($list));
44
- }
45
-
46
- private function getAttachmentDirectory($path)
47
- {
48
- $upload = wp_upload_dir();
49
- $source = rtrim($upload['basedir'], '/\\') . '/' . rtrim(dirname($path), '/\\') . '/';
50
- $source = str_replace('\\', '/', $source);
51
- return $source;
52
- }
53
-
54
- private function initConversion($paths)
55
- {
56
- $settings = apply_filters('webpc_get_values', []);
57
-
58
- if (in_array('cron_conversion', $settings['features'])) {
59
- wp_schedule_single_event((time() + 1), 'webpc_convert_paths', [$paths]);
60
- } else {
61
- do_action('webpc_convert_paths', $paths);
62
- }
63
- }
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Media/_Core.php DELETED
@@ -1,12 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Media;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Delete();
10
- new Upload();
11
- }
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
app/Method/Gd.php DELETED
@@ -1,118 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Method;
4
-
5
- use WebpConverter\Method\MethodAbstract;
6
- use WebpConverter\Method\MethodInterface;
7
-
8
- class Gd extends MethodAbstract implements MethodInterface
9
- {
10
- const METHOD_NAME = 'gd';
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public static function isMethodInstalled()
17
- {
18
- return (extension_loaded('gd'));
19
- }
20
-
21
- public static function isMethodActive()
22
- {
23
- return (self::isMethodInstalled() && function_exists('imagewebp'));
24
- }
25
-
26
- public function createImageByPath($sourcePath)
27
- {
28
- $extension = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION));
29
- $methods = apply_filters('webpc_gd_create_methods', [
30
- 'imagecreatefromjpeg' => ['jpg', 'jpeg'],
31
- 'imagecreatefrompng' => ['png'],
32
- 'imagecreatefromgif' => ['gif'],
33
- ]);
34
-
35
- foreach ($methods as $method => $extensions) {
36
- if (!in_array($extension, $extensions)) {
37
- continue;
38
- } else if (!function_exists($method)) {
39
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', $method));
40
- $e->status = 'server_configuration';
41
- throw $e;
42
- } else if (!$image = @$method($sourcePath)) {
43
- $e = new \Exception(sprintf('"%s" is not a valid image file.', $sourcePath));
44
- $e->status = 'invalid_image';
45
- throw $e;
46
- }
47
- }
48
-
49
- if (!isset($image)) {
50
- $e = new \Exception(sprintf('Unsupported extension "%s" for file "%s"', $extension, $sourcePath));
51
- $e->status = 'unsupported_extension';
52
- throw $e;
53
- }
54
-
55
- return $this->updateImageResource($image, $extension);
56
- }
57
-
58
- private function updateImageResource($image, $extension)
59
- {
60
- if (!function_exists('imageistruecolor')) {
61
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imageistruecolor'));
62
- $e->status = 'server_configuration';
63
- throw $e;
64
- }
65
-
66
- if (!imageistruecolor($image)) {
67
- if (!function_exists('imagepalettetotruecolor')) {
68
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagepalettetotruecolor'));
69
- $e->status = 'server_configuration';
70
- throw $e;
71
- }
72
- imagepalettetotruecolor($image);
73
- }
74
-
75
- switch ($extension) {
76
- case 'png':
77
- if (!function_exists('imagealphablending')) {
78
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagealphablending'));
79
- $e->status = 'server_configuration';
80
- throw $e;
81
- }
82
- imagealphablending($image, false);
83
-
84
- if (!function_exists('imagesavealpha')) {
85
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagesavealpha'));
86
- $e->status = 'server_configuration';
87
- throw $e;
88
- }
89
- imagesavealpha($image, true);
90
- break;
91
- }
92
-
93
- return $image;
94
- }
95
-
96
- public function convertImageToWebP($image, $sourcePath, $outputPath)
97
- {
98
- $image = apply_filters('webpc_gd_before_saving', $image, $sourcePath);
99
-
100
- if (!function_exists('imagewebp')) {
101
- $e = new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagewebp'));
102
- $e->status = 'server_configuration';
103
- throw $e;
104
- } else if ((imagesx($image) > 8192) || (imagesy($image) > 8192)) {
105
- $e = new \Exception(sprintf('Image is larger than maximum 8K resolution: "%s".', $sourcePath));
106
- $e->status = 'max_resolution';
107
- throw $e;
108
- } else if (!$success = imagewebp($image, $outputPath, $this->getSettings('quality'))) {
109
- $e = new \Exception(sprintf('Error occurred while converting image: "%s".', $sourcePath));
110
- $e->status = 'convert_error';
111
- throw $e;
112
- }
113
-
114
- if (filesize($outputPath) % 2 === 1) {
115
- file_put_contents($outputPath, "\0", FILE_APPEND);
116
- }
117
- }
118
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Method/Imagick.php DELETED
@@ -1,77 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Method;
4
-
5
- use WebpConverter\Method\MethodAbstract;
6
- use WebpConverter\Method\MethodInterface;
7
-
8
- class Imagick extends MethodAbstract implements MethodInterface
9
- {
10
- const METHOD_NAME = 'imagick';
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public static function isMethodInstalled()
17
- {
18
- return (extension_loaded('imagick') && class_exists('\Imagick'));
19
- }
20
-
21
- public static function isMethodActive()
22
- {
23
- if (!self::isMethodInstalled()) {
24
- return false;
25
- }
26
-
27
- $formats = (new \Imagick)->queryformats();
28
- return (in_array('WEBP', $formats));
29
- }
30
-
31
- public function createImageByPath($sourcePath)
32
- {
33
- $extension = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION));
34
- if (!extension_loaded('imagick') || !class_exists('Imagick')) {
35
- $e = new \Exception('Server configuration: Imagick module is not available with this PHP installation.');
36
- $e->status = 'server_configuration';
37
- throw $e;
38
- } else if (!$image = new \Imagick($sourcePath)) {
39
- $e = new \Exception(sprintf('"%s" is not a valid image file.', $sourcePath));
40
- $e->status = 'invalid_image';
41
- throw $e;
42
- }
43
-
44
- if (!isset($image)) {
45
- $e = new \Exception(sprintf('Unsupported extension "%s" for file "%s"', $extension, $sourcePath));
46
- $e->status = 'unsupported_extension';
47
- throw $e;
48
- }
49
-
50
- return $image;
51
- }
52
-
53
- public function convertImageToWebP($image, $sourcePath, $outputPath)
54
- {
55
- $image = apply_filters('webpc_imagick_before_saving', $image, $sourcePath);
56
-
57
- if (!in_array('WEBP', $image->queryFormats())) {
58
- $e = new \Exception('Server configuration: Imagick does not support WebP format.');
59
- $e->status = 'server_configuration';
60
- throw $e;
61
- }
62
-
63
- $image->setImageFormat('WEBP');
64
- if (!in_array('keep_metadata', $this->getSettings('features'))) {
65
- $image->stripImage();
66
- }
67
- $image->setImageCompressionQuality($this->getSettings('quality'));
68
- $blob = $image->getImageBlob();
69
-
70
- $success = file_put_contents($outputPath, $blob);
71
- if (!$success) {
72
- $e = new \Exception('Error occurred while converting image.');
73
- $e->status = 'convert_error';
74
- throw $e;
75
- }
76
- }
77
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Method/MethodAbstract.php DELETED
@@ -1,95 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Method;
4
-
5
- use WebpConverter\Convert\Directory;
6
- use WebpConverter\Convert\Server;
7
- use WebpConverter\Convert\Size;
8
- use WebpConverter\Method\MethodInterface;
9
-
10
- abstract class MethodAbstract implements MethodInterface
11
- {
12
- private $settings = [];
13
-
14
- public function __construct()
15
- {
16
- $this->settings = apply_filters('webpc_get_values', []);
17
- }
18
-
19
- /* ---
20
- Functions
21
- --- */
22
-
23
- public function getSettings($settingsKey)
24
- {
25
- return $this->settings[$settingsKey] ?? null;
26
- }
27
-
28
- public function convertImage($path)
29
- {
30
- Server::setSettings();
31
-
32
- try {
33
- $sourcePath = $this->getImageSourcePath($path);
34
- $image = $this->createImageByPath($sourcePath);
35
- $outputPath = $this->getImageOutputPath($sourcePath);
36
-
37
- if (file_exists($outputPath . Size::DELETED_FILE_EXTENSION)) {
38
- unlink($outputPath . Size::DELETED_FILE_EXTENSION);
39
- }
40
-
41
- $this->convertImageToWebP($image, $sourcePath, $outputPath);
42
- do_action('webpc_convert_after', $outputPath, $sourcePath);
43
-
44
- return [
45
- 'success' => true,
46
- 'message' => null,
47
- 'data' => $this->getConversionStats($sourcePath, $outputPath),
48
- ];
49
- } catch (\Exception $e) {
50
- if (in_array('debug_enabled', $this->getSettings('features'))) {
51
- error_log(sprintf('WebP Converter for Media: %s', $e->getMessage()));
52
- }
53
-
54
- return [
55
- 'success' => false,
56
- 'message' => apply_filters('webpc_convert_error', $e->getMessage(), $e->status),
57
- 'data' => null,
58
- ];
59
- }
60
- }
61
-
62
- public function getImageSourcePath($sourcePath)
63
- {
64
- $path = urldecode($sourcePath);
65
- if (!$status = Server::checkIfFileExists($path)) {
66
- $e = new \Exception(sprintf('Source path "%s" for image does not exist.', $path));
67
- $e->status = 'file_unreadable';
68
- throw $e;
69
- }
70
-
71
- return $path;
72
- }
73
-
74
- public function getImageOutputPath($sourcePath)
75
- {
76
- if (!$outputPath = Directory::getPath($sourcePath, true)) {
77
- $e = new \Exception(sprintf('An error occurred creating destination directory for "%s" file.', $sourcePath));
78
- $e->status = 'output_path';
79
- throw $e;
80
- }
81
-
82
- return $outputPath;
83
- }
84
-
85
- public function getConversionStats($sourcePath, $outputPath)
86
- {
87
- $sizeBefore = filesize($sourcePath);
88
- $sizeAfter = (file_exists($outputPath)) ? filesize($outputPath) : $sizeBefore;
89
-
90
- return [
91
- 'size_before' => $sizeBefore,
92
- 'size_after' => $sizeAfter,
93
- ];
94
- }
95
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Method/MethodIntegrator.php DELETED
@@ -1,39 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Method;
4
-
5
- use WebpConverter\Method\Gd;
6
- use WebpConverter\Method\Imagick;
7
-
8
- class MethodIntegrator
9
- {
10
- /* ---
11
- Functions
12
- --- */
13
-
14
- public function getMethodsActive()
15
- {
16
- $list = [];
17
- if (Gd::isMethodActive()) {
18
- $list[] = Gd::METHOD_NAME;
19
- }
20
- if (Imagick::isMethodActive()) {
21
- $list[] = Imagick::METHOD_NAME;
22
- }
23
- return $list;
24
- }
25
-
26
- public function getMethodUsed($methodKey)
27
- {
28
- if (apply_filters('webpc_server_errors', [], true)) {
29
- return null;
30
- }
31
-
32
- if ($methodKey === Gd::METHOD_NAME) {
33
- return (new Gd());
34
- } else if ($methodKey === Imagick::METHOD_NAME) {
35
- return (new Imagick());
36
- }
37
- return null;
38
- }
39
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Method/MethodInterface.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Method;
4
-
5
- use WebpConverter\Convert\Directory;
6
- use WebpConverter\Convert\Server;
7
-
8
- interface MethodInterface
9
- {
10
- /* ---
11
- Functions
12
- --- */
13
-
14
- public function getSettings($settingsKey);
15
-
16
- public static function isMethodInstalled();
17
-
18
- public static function isMethodActive();
19
-
20
- public function convertImage($path);
21
-
22
- public function getImageSourcePath($sourcePath);
23
-
24
- public function createImageByPath($sourcePath);
25
-
26
- public function getImageOutputPath($sourcePath);
27
-
28
- public function convertImageToWebP($image, $sourcePath, $outputPath);
29
-
30
- public function getConversionStats($sourcePath, $outputPath);
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Plugin/Activation.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Plugin;
4
-
5
- use WebpConverter\Action\Cron;
6
- use WebpConverter\Admin\Notice;
7
- use WebpConverter\Loader\LoaderAbstract;
8
-
9
- class Activation
10
- {
11
- const PHP_REQUIRED_VERSION = '7.0.0';
12
- const NEW_INSTALLATION_OPTION = 'webpc_is_new_installation';
13
-
14
- public function __construct()
15
- {
16
- register_activation_hook(WEBPC_FILE, [$this, 'disablePluginForOldPhp']);
17
- register_activation_hook(WEBPC_FILE, [$this, 'createDirectoryForUploadsWebp']);
18
- register_activation_hook(WEBPC_FILE, [$this, 'addDefaultOptions']);
19
- register_activation_hook(WEBPC_FILE, [$this, 'refreshRewriteRules']);
20
- }
21
-
22
- /* ---
23
- Functions
24
- --- */
25
-
26
- public function disablePluginForOldPhp()
27
- {
28
- if (version_compare(PHP_VERSION,self::PHP_REQUIRED_VERSION, '>=')) return;
29
-
30
- deactivate_plugins(basename(WEBPC_FILE));
31
- wp_die(sprintf(
32
- __('%sWebP Converter for Media%s plugin requires a minimum PHP %s version. Sorry about that!', 'webp-converter-for-media'),
33
- '<strong>',
34
- '</strong>',
35
- self::PHP_REQUIRED_VERSION
36
- ));
37
- }
38
-
39
- public function createDirectoryForUploadsWebp()
40
- {
41
- $path = apply_filters('webpc_dir_path', '', 'webp');
42
- if (!file_exists($path) && is_writable(dirname($path))) mkdir($path);
43
- }
44
-
45
- public function addDefaultOptions()
46
- {
47
- add_option(Notice::NOTICE_THANKS_OPTION, strtotime('+ 1 week'));
48
- add_option(self::NEW_INSTALLATION_OPTION, '1');
49
- }
50
-
51
- public function refreshRewriteRules()
52
- {
53
- do_action(LoaderAbstract::ACTION_NAME, true);
54
- }
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Plugin/Deactivation.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Plugin;
4
-
5
- use WebpConverter\Action\Cron;
6
- use WebpConverter\Loader\LoaderAbstract;
7
-
8
- class Deactivation
9
- {
10
- public function __construct()
11
- {
12
- register_deactivation_hook(WEBPC_FILE, [$this, 'refreshRewriteRules']);
13
- register_deactivation_hook(WEBPC_FILE, [$this, 'resetCronEvent']);
14
- }
15
-
16
- /* ---
17
- Functions
18
- --- */
19
-
20
- public function refreshRewriteRules()
21
- {
22
- do_action(LoaderAbstract::ACTION_NAME, false);
23
- }
24
-
25
- public function resetCronEvent()
26
- {
27
- wp_clear_scheduled_hook(Cron::CRON_ACTION);
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Plugin/Uninstall.php DELETED
@@ -1,97 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Plugin;
4
-
5
- use WebpConverter\Admin\Notice;
6
- use WebpConverter\Convert\Size;
7
- use WebpConverter\Error\RewritesError;
8
- use WebpConverter\Settings\Errors;
9
- use WebpConverter\Settings\Save;
10
-
11
- class Uninstall
12
- {
13
- public function __construct()
14
- {
15
- register_uninstall_hook(WEBPC_FILE, ['WebpConverter\Plugin\Uninstall', 'removePluginSettings']);
16
- }
17
-
18
- /* ---
19
- Functions
20
- --- */
21
-
22
- public static function removePluginSettings()
23
- {
24
- delete_option(Activation::NEW_INSTALLATION_OPTION);
25
- delete_option(Errors::ERRORS_CACHE_OPTION);
26
- delete_option(Save::SETTINGS_OPTION);
27
- delete_option(Notice::NOTICE_THANKS_OPTION);
28
- delete_option(Update::VERSION_OPTION);
29
-
30
- self::removeHtaccessFile();
31
- self::removeWebpFiles();
32
- self::removeDebugFiles();
33
- }
34
-
35
- private static function removeHtaccessFile()
36
- {
37
- $path = sprintf('%s/.htaccess', apply_filters('webpc_dir_path', '', 'webp'));
38
- if (is_writable($path)) {
39
- unlink($path);
40
- }
41
- }
42
-
43
- public static function removeWebpFiles()
44
- {
45
- $path = apply_filters('webpc_dir_path', '', 'webp');
46
- $paths = self::getPathsFromLocation($path);
47
- $paths[] = $path;
48
- self::removeFiles($paths);
49
- }
50
-
51
- public static function removeDebugFiles()
52
- {
53
- $uploadsDir = apply_filters('webpc_dir_path', '', 'uploads');
54
-
55
- if (is_writable($uploadsDir . RewritesError::PATH_OUTPUT_FILE_PNG)) {
56
- unlink($uploadsDir . RewritesError::PATH_OUTPUT_FILE_PNG);
57
- }
58
- if (is_writable($uploadsDir . RewritesError::PATH_OUTPUT_FILE_PNG2)) {
59
- unlink($uploadsDir . RewritesError::PATH_OUTPUT_FILE_PNG2);
60
- }
61
- }
62
-
63
- private static function getPathsFromLocation($path, $paths = [])
64
- {
65
- if (!file_exists($path)) return $paths;
66
- $path .= '/';
67
- $files = glob($path . '*');
68
- foreach ($files as $file) {
69
- if (is_dir($file)) {
70
- $paths = self::getPathsFromLocation($file, $paths);
71
- }
72
- $paths[] = $file;
73
- }
74
- return $paths;
75
- }
76
-
77
- private static function removeFiles($paths)
78
- {
79
- if (!$paths) {
80
- return;
81
- }
82
-
83
- $deletedExtension = trim(Size::DELETED_FILE_EXTENSION, '.');
84
- foreach ($paths as $path) {
85
- if (!is_writable($path) || !is_writable(dirname($path))) {
86
- continue;
87
- }
88
-
89
- $extension = pathinfo($path, PATHINFO_EXTENSION);
90
- if (is_file($path) && in_array($extension, ['webp', $deletedExtension])) {
91
- unlink($path);
92
- } else if (is_dir($path)) {
93
- rmdir($path);
94
- }
95
- }
96
- }
97
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Plugin/Update.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Plugin;
4
-
5
- use WebpConverter\Loader\LoaderAbstract;
6
- use WebpConverter\Plugin\Uninstall;
7
- use WebpConverter\Settings\Save;
8
-
9
- class Update
10
- {
11
- const VERSION_OPTION = 'webpc_latest_version';
12
-
13
- public function __construct()
14
- {
15
- add_action('admin_init', [$this, 'runActionsAfterUpdate']);
16
- }
17
-
18
- /* ---
19
- Functions
20
- --- */
21
-
22
- public function runActionsAfterUpdate()
23
- {
24
- $version = get_option(self::VERSION_OPTION, null);
25
- if ($version === WEBPC_VERSION) return;
26
-
27
- if ($version !== null) {
28
- update_option(Save::SETTINGS_OPTION, $this->updateSettingsForOldVersions($version));
29
- $this->moveFilesToUploadsSubdirectory($version);
30
-
31
- update_option(Activation::NEW_INSTALLATION_OPTION, '0');
32
- remove_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
33
- }
34
-
35
- do_action(LoaderAbstract::ACTION_NAME, true);
36
- update_option(self::VERSION_OPTION, WEBPC_VERSION);
37
- }
38
-
39
- private function updateSettingsForOldVersions($version)
40
- {
41
- $settings = apply_filters('webpc_get_values', []);
42
-
43
- if (version_compare($version, '1.1.2', '<=')) {
44
- $settings['features'][] = 'only_smaller';
45
- }
46
-
47
- if (version_compare($version, '1.2.7', '<=') && !isset($settings['dirs'])) {
48
- $settings['dirs'] = ['uploads'];
49
- }
50
-
51
- if (version_compare($version, '1.3.1', '<=')) {
52
- $settings['features'][] = 'debug_enabled';
53
- }
54
-
55
- if (version_compare($version, '1.6.0', '<=') && !isset($settings['loader_type'])) {
56
- $settings['loader_type'] = 'htaccess';
57
- }
58
-
59
- $settings['features'] = array_unique($settings['features']);
60
- return $settings;
61
- }
62
-
63
- private function moveFilesToUploadsSubdirectory($version)
64
- {
65
- if (version_compare($version, '1.2.7', '>')) return;
66
-
67
- Uninstall::removeWebpFiles();
68
- do_action('webpc_regenerate_all');
69
- }
70
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Plugin/_Core.php DELETED
@@ -1,14 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Plugin;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Activation();
10
- new Deactivation();
11
- new Uninstall();
12
- new Update();
13
- }
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Regenerate/Endpoints.php DELETED
@@ -1,104 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Regenerate;
4
-
5
- use WebpConverter\Regenerate\Paths;
6
- use WebpConverter\Regenerate\Regenerate;
7
-
8
- class Endpoints
9
- {
10
- const ROUTE_NAMESPACE = 'webp-converter/v1';
11
- const PATHS_PER_REQUEST = 10;
12
-
13
- public function __construct()
14
- {
15
- add_action('rest_api_init', [$this, 'restApiEndpoints']);
16
- add_filter('webpc_rest_api_paths', [$this, 'showApiPathsUrl']);
17
- add_filter('webpc_rest_api_regenerate', [$this, 'showApiRegenerateUrl']);
18
- }
19
-
20
- /* ---
21
- Functions
22
- --- */
23
-
24
- public function restApiEndpoints()
25
- {
26
- register_rest_route(
27
- self::ROUTE_NAMESPACE,
28
- 'paths',
29
- [
30
- 'methods' => \WP_REST_Server::ALLMETHODS,
31
- 'permission_callback' => function() {
32
- return (isset($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wp_rest')
33
- && current_user_can('manage_options'));
34
- },
35
- 'callback' => [$this, 'getPaths'],
36
- 'args' => [
37
- 'regenerate_force' => [
38
- 'description' => 'Option to force all images to be converted again (set `1` to enable)',
39
- 'required' => false,
40
- 'default' => false,
41
- 'sanitize_callback' => function($value, $request, $param) {
42
- return ($value === '1') ? true : false;
43
- }
44
- ],
45
- ],
46
- ]
47
- );
48
-
49
- register_rest_route(
50
- self::ROUTE_NAMESPACE,
51
- 'regenerate',
52
- [
53
- 'methods' => \WP_REST_Server::ALLMETHODS,
54
- 'permission_callback' => function() {
55
- return (isset($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wp_rest')
56
- && current_user_can('manage_options'));
57
- },
58
- 'callback' => [$this, 'convertImages'],
59
- 'args' => [
60
- 'paths' => [
61
- 'description' => 'Array of file paths (server paths)',
62
- 'required' => true,
63
- 'default' => [],
64
- 'validate_callback' => function($value, $request, $param) {
65
- return is_array($value) && $value;
66
- }
67
- ],
68
- ],
69
- ]
70
- );
71
- }
72
-
73
- public function getPaths($request)
74
- {
75
- $params = $request->get_params();
76
- $skipExists = (!$params['regenerate_force']) ? true : false;
77
-
78
- $data = (new Paths())->getPaths($skipExists, self::PATHS_PER_REQUEST);
79
- if ($data !== false) return new \WP_REST_Response($data, 200);
80
- else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
81
- }
82
-
83
- public function convertImages($request)
84
- {
85
- $params = $request->get_params();
86
- $data = (new Regenerate())->convertImages($params['paths']);
87
- if ($data !== false) return new \WP_REST_Response($data, 200);
88
- else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
89
- }
90
-
91
- public function showApiPathsUrl()
92
- {
93
- $nonce = wp_create_nonce('wp_rest');
94
- $url = get_rest_url(null, self::ROUTE_NAMESPACE . '/paths?_wpnonce=' . $nonce);
95
- return $url;
96
- }
97
-
98
- public function showApiRegenerateUrl()
99
- {
100
- $nonce = wp_create_nonce('wp_rest');
101
- $url = get_rest_url(null, self::ROUTE_NAMESPACE . '/regenerate?_wpnonce=' . $nonce);
102
- return $url;
103
- }
104
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Regenerate/Paths.php DELETED
@@ -1,27 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Regenerate;
4
-
5
- class Paths
6
- {
7
- /* ---
8
- Functions
9
- --- */
10
-
11
- public function getPaths($skipExists = false, $chunkSize = null)
12
- {
13
- $settings = apply_filters('webpc_get_values', []);
14
- $dirs = array_filter(array_map(function($dirName) {
15
- return apply_filters('webpc_dir_path', '', $dirName);
16
- }, $settings['dirs']));
17
-
18
- $list = [];
19
- foreach ($dirs as $dirPath) {
20
- $paths = apply_filters('webpc_dir_files', [], $dirPath, $skipExists);
21
- $list = array_merge($list, $paths);
22
- }
23
-
24
- if ($chunkSize === null) return $list;
25
- return array_chunk($list, $chunkSize);
26
- }
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Regenerate/Regenerate.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Regenerate;
4
-
5
- use WebpConverter\Method\MethodIntegrator;
6
-
7
- class Regenerate
8
- {
9
- /* ---
10
- Functions
11
- --- */
12
-
13
- public function convertImages($paths)
14
- {
15
- $settings = apply_filters('webpc_get_values', []);
16
- $errors = [];
17
- $sizeBefore = 0;
18
- $sizeAfter = 0;
19
-
20
- $convertMethod = (new MethodIntegrator())->getMethodUsed($settings['method']);
21
- if ($convertMethod === null) {
22
- return false;
23
- }
24
-
25
- foreach ($paths as $path) {
26
- $response = $convertMethod->convertImage($path);
27
-
28
- if ($response['success'] !== true) {
29
- $errors[] = $response['message'];
30
- } else {
31
- $sizeBefore += $response['data']['size_before'];
32
- $sizeAfter += $response['data']['size_after'];
33
- }
34
- }
35
- $errors = array_filter($errors);
36
-
37
- return [
38
- 'errors' => apply_filters('webpc_convert_errors', $errors),
39
- 'size' => [
40
- 'before' => $sizeBefore,
41
- 'after' => $sizeAfter,
42
- ],
43
- ];
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Regenerate/Skip.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Regenerate;
4
-
5
- use WebpConverter\Convert\Directory;
6
- use WebpConverter\Convert\Size;
7
-
8
- class Skip
9
- {
10
- public function __construct()
11
- {
12
- add_filter('webpc_files_paths', [$this, 'skipExistsImages'], 10, 2);
13
- }
14
-
15
- /* ---
16
- Functions
17
- --- */
18
-
19
- public function skipExistsImages($paths, $skipExists = true)
20
- {
21
- if (!$skipExists) return $paths;
22
-
23
- $directory = new Directory();
24
- foreach ($paths as $key => $path) {
25
- $output = $directory->getPath(urldecode($path), false);
26
- if (file_exists($output) || file_exists($output . Size::DELETED_FILE_EXTENSION)) {
27
- unset($paths[$key]);
28
- }
29
- }
30
- return $paths;
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Regenerate/_Core.php DELETED
@@ -1,12 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Regenerate;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Endpoints();
10
- new Skip();
11
- }
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Errors.php DELETED
@@ -1,96 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Error\LibsError;
6
- use WebpConverter\Error\PassthruError;
7
- use WebpConverter\Error\PathsError;
8
- use WebpConverter\Error\RestapiError;
9
- use WebpConverter\Error\RewritesError;
10
- use WebpConverter\Error\SettingsError;
11
-
12
- class Errors
13
- {
14
- const ERRORS_CACHE_OPTION = 'webpc_errors_cache';
15
-
16
- private $cache = [];
17
- private $filePath = WEBPC_PATH . '/resources/components/errors/%s.php';
18
- private $allowedErrors = ['rewrites_cached'];
19
-
20
- public function __construct()
21
- {
22
- add_filter('webpc_server_errors', [$this, 'getServerErrors'], 10, 3);
23
- add_filter('webpc_server_errors_messages', [$this, 'getServerErrorsMessages'], 10, 3);
24
- }
25
-
26
- /* ---
27
- Functions
28
- --- */
29
-
30
- public function getServerErrors($values, $onlyErrors = false, $isForceRefresh = false)
31
- {
32
- $errors = get_option(self::ERRORS_CACHE_OPTION, $this->cache);
33
- if ($isForceRefresh) {
34
- $errors = $this->getErrorsList();
35
- }
36
- $errors = array_filter($errors, function($error) use ($onlyErrors) {
37
- return (!$onlyErrors || !in_array($error, $this->allowedErrors));
38
- });
39
-
40
- return $errors;
41
- }
42
-
43
- public function getServerErrorsMessages($values, $onlyErrors = false, $isForceRefresh = false)
44
- {
45
- $errors = $this->getServerErrors($values, $onlyErrors, $isForceRefresh);
46
- return $this->loadErrorMessages($errors);
47
- }
48
-
49
- private function loadErrorMessages($errors)
50
- {
51
- $list = [];
52
- foreach ($errors as $error) {
53
- ob_start();
54
- include sprintf($this->filePath, str_replace('_', '-', $error));
55
- $list[$error] = ob_get_clean();
56
- }
57
-
58
- return $list;
59
- }
60
-
61
- private function getErrorsList()
62
- {
63
- $errors = [];
64
- if ($newErrors = (new LibsError())->getErrorCodes()) {
65
- $errors = array_merge($errors, $newErrors);
66
- }
67
- if ($newErrors = (new RestapiError())->getErrorCodes()) {
68
- $errors = array_merge($errors, $newErrors);
69
- }
70
- if ($newErrors = (new PathsError())->getErrorCodes()) {
71
- $errors = array_merge($errors, $newErrors);
72
- }
73
- if ($newErrors = (new PassthruError())->getErrorCodes()) {
74
- $errors = array_merge($errors, $newErrors);
75
- } else if ($newErrors = (new RewritesError())->getErrorCodes()) {
76
- $errors = array_merge($errors, $newErrors);
77
- }
78
- if (!$errors && ($newErrors = (new SettingsError())->getErrorCodes())) {
79
- $errors = array_merge($errors, $newErrors);
80
- }
81
-
82
- $this->cache = $errors;
83
- update_option(self::ERRORS_CACHE_OPTION, $errors);
84
-
85
- return $errors;
86
- }
87
-
88
- public static function setExtensionsForDebug($settings)
89
- {
90
- $settings['extensions'] = array_unique(array_merge(
91
- ['png2', 'png'],
92
- $settings['extensions']
93
- ));
94
- return $settings;
95
- }
96
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Methods.php DELETED
@@ -1,27 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Method\MethodIntegrator;
6
-
7
- class Methods
8
- {
9
- private $cache = null;
10
-
11
- public function __construct()
12
- {
13
- add_filter('webpc_get_methods', [$this, 'getAvaiableMethods']);
14
- }
15
-
16
- /* ---
17
- Functions
18
- --- */
19
-
20
- public function getAvaiableMethods()
21
- {
22
- if ($this->cache !== null) return $this->cache;
23
-
24
- $this->cache = (new MethodIntegrator())->getMethodsActive();
25
- return $this->cache;
26
- }
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Options.php DELETED
@@ -1,129 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Loader\Htaccess;
6
- use WebpConverter\Loader\Passthru;
7
- use WebpConverter\Method\Gd;
8
- use WebpConverter\Method\Imagick;
9
-
10
- class Options
11
- {
12
- public function __construct()
13
- {
14
- add_filter('webpc_get_options', [$this, 'getOptions']);
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- public function getOptions($options)
22
- {
23
- return [
24
- [
25
- 'name' => 'loader_type',
26
- 'type' => 'radio',
27
- 'label' => __('Image loading mode', 'webp-converter-for-media'),
28
- 'info' => __('By changing image loading mode it allows you to bypass some server configuration problems.', 'webp-converter-for-media'),
29
- 'values' => [
30
- Htaccess::LOADER_TYPE => sprintf(
31
- __('%s (recommended)', 'webp-converter-for-media'),
32
- __('via .htaccess', 'webp-converter-for-media')),
33
- Passthru::LOADER_TYPE => sprintf(
34
- __('%s (without rewrites in .htacces files or Nginx configuration)', 'webp-converter-for-media'),
35
- 'Pass Thru'),
36
- ],
37
- 'disabled' => $this->getDisabledValues('loader_type'),
38
- ],
39
- [
40
- 'name' => 'extensions',
41
- 'type' => 'checkbox',
42
- 'label' => __('List of supported files extensions', 'webp-converter-for-media'),
43
- 'info' => '',
44
- 'values' => [
45
- 'jpg' => '.jpg',
46
- 'jpeg' => '.jpeg',
47
- 'png' => '.png',
48
- 'gif' => '.gif',
49
- ],
50
- 'disabled' => $this->getDisabledValues('extensions'),
51
- ],
52
- [
53
- 'name' => 'dirs',
54
- 'type' => 'checkbox',
55
- 'label' => __('List of supported directories', 'webp-converter-for-media'),
56
- 'info' => __('Files from these directories will be supported in WebP format.', 'webp-converter-for-media'),
57
- 'values' => [
58
- 'plugins' => '/plugins',
59
- 'themes' => '/themes',
60
- 'uploads' => '/uploads',
61
- ],
62
- 'disabled' => $this->getDisabledValues('dirs'),
63
- ],
64
- [
65
- 'name' => 'method',
66
- 'type' => 'radio',
67
- 'label' => __('Conversion method', 'webp-converter-for-media'),
68
- 'info' => __('The configuration for advanced users.', 'webp-converter-for-media'),
69
- 'values' => [
70
- Gd::METHOD_NAME => sprintf(__('%s (recommended)', 'webp-converter-for-media'), 'GD'),
71
- Imagick::METHOD_NAME => 'Imagick',
72
- ],
73
- 'disabled' => $this->getDisabledValues('method'),
74
- ],
75
- [
76
- 'name' => 'quality',
77
- 'type' => 'quality',
78
- 'label' => __('Images quality', 'webp-converter-for-media'),
79
- 'info' => __('Adjust the quality of the images being converted. Remember that higher quality also means larger file sizes. The recommended value is 85%.', 'webp-converter-for-media'),
80
- 'values' => [
81
- '75' => '75%',
82
- '80' => '80%',
83
- '85' => '85%',
84
- '90' => '90%',
85
- '95' => '95%',
86
- '100' => '100%',
87
- ],
88
- 'disabled' => $this->getDisabledValues('quality'),
89
- ],
90
- [
91
- 'name' => 'features',
92
- 'type' => 'checkbox',
93
- 'label' => __('Extra features', 'webp-converter-for-media'),
94
- 'info' => __('Options allow you to enable new functionalities that will increase capabilities of plugin.', 'webp-converter-for-media'),
95
- 'values' => [
96
- 'only_smaller' => __('Automatic removal of WebP files larger than original', 'webp-converter-for-media'),
97
- 'mod_expires' => __('Browser Caching for WebP files (saving images in browser cache memory)', 'webp-converter-for-media'),
98
- 'keep_metadata' => __('Keep images metadata stored in EXIF or XMP formats (only available for Imagick conversion method)', 'webp-converter-for-media'),
99
- 'cron_enabled' => __('Enable cron to automatically convert images from outside Media Library (images from Media Library are converted immediately after upload)', 'webp-converter-for-media'),
100
- 'cron_conversion' => __('Enable cron to convert images uploaded to Media Library to speed up process of adding images (deactivate this option if images added to Media Library are not automatically converted)', 'webp-converter-for-media'),
101
- 'referer_disabled' => __('Force redirections to WebP for all domains (by default, images in WebP are loaded only in domain of your website - when image is displayed via URL on another domain that original file is loaded)', 'webp-converter-for-media'),
102
- 'debug_enabled' => __('Log errors while converting to debug.log file (when debugging in WordPress is active)', 'webp-converter-for-media'),
103
- ],
104
- 'disabled' => $this->getDisabledValues('features'),
105
- ],
106
- ];
107
- }
108
-
109
- private function getDisabledValues($optionName)
110
- {
111
- $list = [];
112
- switch ($optionName) {
113
- case 'method':
114
- $methods = apply_filters('webpc_get_methods', []);
115
- if (!in_array(Gd::METHOD_NAME, $methods)) {
116
- $list[] = Gd::METHOD_NAME;
117
- }
118
- if (!in_array(Imagick::METHOD_NAME, $methods)) {
119
- $list[] = Imagick::METHOD_NAME;
120
- }
121
- break;
122
- case 'features':
123
- $settings = apply_filters('webpc_get_values', []);
124
- if ($settings['method'] !== 'imagick') $list[] = 'keep_metadata';
125
- break;
126
- }
127
- return $list;
128
- }
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Page.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Admin\Assets;
6
- use WebpConverter\Plugin\Activation;
7
- use WebpConverter\Settings\Save;
8
-
9
- class Page
10
- {
11
- private $filePath = WEBPC_PATH . '/resources/views/settings.php';
12
-
13
- public function __construct()
14
- {
15
- add_action('admin_menu', [$this, 'addSettingsPageForAdmin']);
16
- add_action('network_admin_menu', [$this, 'addSettingsPageForNetwork']);
17
- }
18
-
19
- /* ---
20
- Functions
21
- --- */
22
-
23
- public static function getSettingsPageUrl()
24
- {
25
- if (!is_multisite()) {
26
- return menu_page_url('webpc_admin_page', false);
27
- } else {
28
- return network_admin_url('settings.php?page=webpc_admin_page');
29
- }
30
- }
31
-
32
- public function addSettingsPageForAdmin()
33
- {
34
- if (is_multisite()) {
35
- return;
36
- }
37
- $this->addSettingsPage('options-general.php');
38
- }
39
-
40
- public function addSettingsPageForNetwork()
41
- {
42
- $this->addSettingsPage('settings.php');
43
- }
44
-
45
- private function addSettingsPage($menuPage)
46
- {
47
- $page = add_submenu_page(
48
- $menuPage,
49
- 'WebP Converter for Media',
50
- 'WebP Converter',
51
- 'manage_options',
52
- 'webpc_admin_page',
53
- [$this, 'showSettingsPage']
54
- );
55
- add_action('load-' . $page, [$this, 'loadScriptsForPage']);
56
- }
57
-
58
- public function showSettingsPage()
59
- {
60
- new Save();
61
- require_once $this->filePath;
62
- }
63
-
64
- public function loadScriptsForPage()
65
- {
66
- update_option(Activation::NEW_INSTALLATION_OPTION, '0');
67
- remove_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
68
- remove_action('network_admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
69
-
70
- new Assets();
71
- }
72
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Save.php DELETED
@@ -1,54 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Action\Cron;
6
- use WebpConverter\Loader\LoaderAbstract;
7
-
8
- class Save
9
- {
10
- const SETTINGS_OPTION = 'webpc_settings';
11
-
12
- public function __construct()
13
- {
14
- $this->saveConfig();
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- private function saveConfig()
22
- {
23
- if (!isset($_POST['webpc_save']) || !isset($_REQUEST['_wpnonce'])
24
- || !wp_verify_nonce($_REQUEST['_wpnonce'], 'webpc-save')) return;
25
-
26
- $values = $this->getValues();
27
- update_option(self::SETTINGS_OPTION, $values);
28
- $settings = apply_filters('webpc_get_values', [], true);
29
-
30
- do_action(LoaderAbstract::ACTION_NAME, true);
31
- wp_clear_scheduled_hook(Cron::CRON_ACTION);
32
- }
33
-
34
- private function getValues()
35
- {
36
- $options = apply_filters('webpc_get_options', []);
37
- $values = [];
38
- foreach ($options as $key => $option) {
39
- $name = $option['name'];
40
- $values[$name] = (isset($_POST[$name]))
41
- ? $this->setValuesForOption($_POST[$name], $option['values'])
42
- : (($option['type'] === 'checkbox') ? [] : null);
43
- }
44
-
45
- return $values;
46
- }
47
-
48
- private function setValuesForOption($value, $options)
49
- {
50
- $values = array_keys($options);
51
- if (is_array($value)) return array_intersect($value, $values);
52
- else return (in_array($value, $values)) ? $value : null;
53
- }
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Server.php DELETED
@@ -1,190 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- use WebpConverter\Error\RewritesError;
6
- use WebpConverter\Loader\LoaderAbstract;
7
- use WebpConverter\Settings\Errors;
8
- use WebpConverter\Traits\FileLoaderTrait;
9
-
10
- class Server
11
- {
12
- use FileLoaderTrait;
13
-
14
- private $extensions = ['gd', 'imagick', 'core'];
15
-
16
- public function __construct()
17
- {
18
- add_filter('webpc_server_info', [$this, 'getContent']);
19
- }
20
-
21
- /* ---
22
- Functions
23
- --- */
24
-
25
- public function getContent($content = '')
26
- {
27
- ob_start();
28
-
29
- add_filter('webpc_get_values', ['WebpConverter\Settings\Errors', 'setExtensionsForDebug']);
30
- do_action(LoaderAbstract::ACTION_NAME, true);
31
- echo $this->getFiltersInfo();
32
- remove_filter('webpc_get_values', ['WebpConverter\Settings\Errors', 'setExtensionsForDebug']);
33
- do_action(LoaderAbstract::ACTION_NAME, true);
34
-
35
- foreach ($this->extensions as $extension) {
36
- $this->getExtensionInfo($extension);
37
- }
38
-
39
- $content = ob_get_contents();
40
- ob_end_clean();
41
- return $content;
42
- }
43
-
44
- private function getExtensionInfo($extension)
45
- {
46
- ?>
47
- <h4><?= $extension; ?></h4>
48
- <?php
49
- if (!extension_loaded($extension)) :
50
- ?>
51
- <p>-</p>
52
- <?php
53
- else :
54
- $ext = new \ReflectionExtension($extension);
55
- $ext->info();
56
- endif;
57
- }
58
-
59
- private function getFiltersInfo()
60
- {
61
- $uploadsUrl = apply_filters('webpc_dir_url', '', 'uploads');
62
- $uploadsPath = apply_filters('webpc_dir_path', '', 'uploads');
63
-
64
- ob_start();
65
-
66
- ?>
67
- <h4>Filters</h4>
68
- <table>
69
- <tbody>
70
- <tr>
71
- <td class="e">webpc_get_values</td>
72
- <td class="v">
73
- <?= json_encode(apply_filters('webpc_get_values', [], null)); ?>
74
- </td>
75
- </tr>
76
- <tr>
77
- <td class="e">webpc_get_methods</td>
78
- <td class="v">
79
- <?= implode(' | ', apply_filters('webpc_get_methods', [])); ?>
80
- </td>
81
- </tr>
82
- <tr>
83
- <td class="e">webpc_site_root</td>
84
- <td class="v">
85
- <?= apply_filters('webpc_site_root', ABSPATH); ?>
86
- </td>
87
- </tr>
88
- <tr>
89
- <td class="e">webpc_site_url</td>
90
- <td class="v">
91
- <?= apply_filters('webpc_site_url', get_site_url()); ?>
92
- </td>
93
- </tr>
94
- <td class="e">webpc_dir_path <em>(plugins)</em></td>
95
- <td class="v">
96
- <?= apply_filters('webpc_dir_path', '', 'plugins'); ?>
97
- </td>
98
- </tr>
99
- <tr>
100
- <td class="e">webpc_dir_path <em>(themes)</em></td>
101
- <td class="v">
102
- <?= apply_filters('webpc_dir_path', '', 'themes'); ?>
103
- </td>
104
- </tr>
105
- <tr>
106
- <td class="e">webpc_dir_path <em>(uploads)</em></td>
107
- <td class="v">
108
- <?= apply_filters('webpc_dir_path', '', 'uploads'); ?>
109
- </td>
110
- </tr>
111
- <tr>
112
- <td class="e">webpc_dir_path <em>(webp)</em></td>
113
- <td class="v">
114
- <?= apply_filters('webpc_dir_path', '', 'webp'); ?>
115
- </td>
116
- </tr>
117
- <tr>
118
- <td class="e">webpc_uploads_prefix</td>
119
- <td class="v">
120
- <?= apply_filters('webpc_uploads_prefix', '/'); ?>
121
- </td>
122
- </tr>
123
- <tr>
124
- <tr>
125
- <td class="e">webpc_dir_excluded</td>
126
- <td class="v">
127
- <?= implode(' | ', apply_filters('webpc_dir_excluded', [])); ?>
128
- </td>
129
- </tr>
130
- </tbody>
131
- </table>
132
- <h4>WordPress</h4>
133
- <table>
134
- <tbody>
135
- <tr>
136
- <td class="e">ABSPATH</td>
137
- <td class="v">
138
- <?= ABSPATH; ?>
139
- </td>
140
- </tr>
141
- </tbody>
142
- </table>
143
- <h4>Errors debug</h4>
144
- <table>
145
- <tbody>
146
- <tr>
147
- <td class="e">Size of PNG <em>(by server path)</em></td>
148
- <td class="v">
149
- <?= $this->getFileSizeByPath($uploadsPath . RewritesError::PATH_OUTPUT_FILE_PNG); ?>
150
- </td>
151
- </tr>
152
- <tr>
153
- <td class="e">Size of PNG2 <em>(by server path)</em></td>
154
- <td class="v">
155
- <?= $this->getFileSizeByPath($uploadsPath . RewritesError::PATH_OUTPUT_FILE_PNG2); ?>
156
- </td>
157
- </tr>
158
- <tr>
159
- <td class="e">Size of PNG as WEBP <em>(by URL)</em></td>
160
- <td class="v">
161
- <?= $this->getFileSizeByUrl($uploadsUrl . RewritesError::PATH_OUTPUT_FILE_PNG); ?>
162
- </td>
163
- </tr>
164
- <tr>
165
- <td class="e">Size of PNG as PNG <em>(by URL)</em></td>
166
- <td class="v">
167
- <?= $this->getFileSizeByUrl($uploadsUrl . RewritesError::PATH_OUTPUT_FILE_PNG, false); ?>
168
- </td>
169
- </tr>
170
- <tr>
171
- <td class="e">Size of PNG2 as WEBP <em>(by URL)</em></td>
172
- <td class="v">
173
- <?= $this->getFileSizeByUrl($uploadsUrl . RewritesError::PATH_OUTPUT_FILE_PNG2); ?>
174
- </td>
175
- </tr>
176
- <tr>
177
- <td class="e">Size of PNG2 as PNG2 <em>(by URL)</em></td>
178
- <td class="v">
179
- <?= $this->getFileSizeByUrl($uploadsUrl . RewritesError::PATH_OUTPUT_FILE_PNG2, false); ?>
180
- </td>
181
- </tr>
182
- </tbody>
183
- </table>
184
- <?php
185
-
186
- $content = ob_get_contents();
187
- ob_end_clean();
188
- return $content;
189
- }
190
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Values.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- class Values
6
- {
7
- private $cache = null;
8
-
9
- public function __construct()
10
- {
11
- add_filter('webpc_get_values', [$this, 'getValues'], 10, 2);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function getValues($value, $isForce = false)
19
- {
20
- if ($isForce && ($this->cache !== null)) return $this->cache;
21
-
22
- $methods = apply_filters('webpc_get_methods', []);
23
- $this->cache = get_option(Save::SETTINGS_OPTION, [
24
- 'loader_type' => 'htaccess',
25
- 'extensions' => ['jpg', 'jpeg', 'png'],
26
- 'dirs' => ['uploads'],
27
- 'method' => ($methods) ? $methods[0] : '',
28
- 'features' => ['only_smaller', 'mod_expires', 'cron_conversion', 'debug_enabled'],
29
- 'quality' => 85,
30
- ]);
31
- return $this->cache;
32
- }
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/_Core.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- class _Core
6
- {
7
- public function __construct()
8
- {
9
- new Errors();
10
- new Methods();
11
- new Options();
12
- new Page();
13
- new Server();
14
- new Values();
15
- }
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Traits/FileLoaderTrait.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Traits;
4
-
5
- use WebpConverter\Loader\Passthru;
6
-
7
- trait FileLoaderTrait
8
- {
9
- /* ---
10
- Functions
11
- --- */
12
-
13
- private function getFileSizeByUrl($url, $setHeaders = true)
14
- {
15
- $headers = [
16
- 'Accept: image/webp',
17
- 'Referer: ' . WEBPC_URL,
18
- ];
19
-
20
- $imageUrl = Passthru::updateImageUrls($url);
21
- return $this->getFileSizeForLoadedFile($imageUrl, ($setHeaders) ? $headers : []);
22
- }
23
-
24
- private function getFileSizeByPath($path)
25
- {
26
- if (!file_exists($path)) return 0;
27
- return filesize($path);
28
- }
29
-
30
- private function getFileSizeForLoadedFile($url, $headers)
31
- {
32
- foreach (wp_get_nocache_headers() as $headerKey => $headerValue) {
33
- $headers[] = sprintf('%s: %s', $headerKey, $headerValue);
34
- }
35
-
36
- $ch = curl_init($url);
37
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
38
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
39
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
40
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
41
- curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
42
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
43
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
44
- $response = curl_exec($ch);
45
- $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
46
- curl_close($ch);
47
-
48
- return ($code === 200) ? strlen($response) : 0;
49
- }
50
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/WebpConverter.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter;
4
-
5
- class WebpConverter
6
- {
7
- public function __construct()
8
- {
9
- new Action\_Core();
10
- new Admin\_Core();
11
- new Convert\_Core();
12
- new Loader\_Core();
13
- new Media\_Core();
14
- new Plugin\_Core();
15
- new Regenerate\_Core();
16
- new Settings\_Core();
17
- }
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/build/css/styles.css ADDED
@@ -0,0 +1 @@
 
1
+ @keyframes dotsLoading{0%,to{content:"..."}25%{content:"\A0.."}50%{content:".\A0."}75%{content:"..\A0"}}@font-face{font-family:Exo\ 2;src:url(../../fonts/Exo2/Exo2-Regular.woff2) format("woff2"),url(../../fonts/Exo2/Exo2-Regular.woff) format("woff"),url(../../fonts/Exo2/Exo2-Regular.ttf) format("truetype");font-weight:400;font-style:"normal"}@font-face{font-family:Exo\ 2;src:url(../../fonts/Exo2/Exo2-SemiBold.woff2) format("woff2"),url(../../fonts/Exo2/Exo2-SemiBold.woff) format("woff"),url(../../fonts/Exo2/Exo2-SemiBold.ttf) format("truetype");font-weight:500;font-style:"normal"}.webpModal [hidden]{display:none!important}.webpModal *,.webpModal :after,.webpModal :before{margin:0;padding:0;box-sizing:border-box}.webpModal__outer{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.75);z-index:9999}.webpModal__form{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 40px);padding:20px 30px;font-family:Exo\ 2,sans-serif;font-size:0;background-color:#fff}.webpModal__headline{padding:4px 0;font-weight:500;font-size:16px;line-height:1.5}.webpModal__desc{padding:4px 0;font-size:14px;line-height:1.64}.webpModal__table{margin-top:10px}.webpModal__textarea{display:none;width:100%;margin-top:10px;padding:4px 10px;font-size:14px;line-height:1.64;border:1px solid #b4b9be!important;border-radius:0}.webpModal__textarea[placeholder]{display:block}.webpModal__textarea[placeholder=""]{display:none}.webpModal__buttons{display:flex;flex-wrap:wrap;align-items:center;margin:5px -5px 0;padding:5px 0}.webpModal__button{width:50%;padding:5px}.webpModal__buttonInner{width:100%}.webpPage{margin:0;padding:0 20px 0 0;font-family:Exo\ 2,sans-serif;color:#444;overflow:hidden}.webpPage *,.webpPage :after,.webpPage :before{margin:0;padding:0;box-sizing:border-box}.webpPage [hidden]{display:none!important}.webpPage .webpPage__headline{margin:0;padding:15px 0 23px;font-size:24px;line-height:1.25}.webpPage__alert{margin-bottom:30px;padding:15px 20px;font-size:14px;line-height:1.64;color:#fff;background-color:#46b450}.webpPage__columns{margin:0 -30px;overflow:hidden}.webpPage__column{float:left;padding:0 30px}.webpPage__column--large{width:66.666%}.webpPage__column--small{width:33.333%}.webpPage__widget{background-color:#fff}.webpPage__widget+.webpPage__widget{margin-top:60px}.webpPage__widgetTitle{padding:14px 30px;font-weight:400;font-size:16px;line-height:1.5;color:#fff;background-color:#0073aa}.webpPage__widgetTitle--second{background-color:#a0a5aa}.webpPage__widgetTitle--error{background-color:#dc3232}.webpPage__widgetRow{padding-bottom:10px}.webpPage__widgetRow:last-child{padding-bottom:0}.webpPage__widgetRow .webpButton{margin:10px 0}.webpPage__quality{display:flex;flex-wrap:wrap;margin:10px 0;border:1px solid #a0a5aa}.webpPage__qualityItem{flex:1;margin-left:-1px;text-align:center;border-left:1px solid #a0a5aa}.webpPage__qualityItemInput{display:none!important}.webpPage__qualityItemLabel{position:relative;display:block;padding:14px 20px;font-size:14px;line-height:1.64;transition:color .3s,background-color .3s}.webpPage__qualityItemInput:checked+.webpPage__qualityItemLabel{margin:-1px;padding:15px 21px;color:#fff;background-color:#46b450}.webpPage__qualityItemInput[disabled]+.webpPage__qualityItemLabel{opacity:0;pointer-events:none}.notice[data-notice=webp-converter]{margin-top:20px;padding:0}.webpButton{position:relative;display:inline-block;min-width:180px;padding:9px 30px;font-weight:500;font-size:14px;line-height:1.63;text-align:center;text-decoration:none;background-color:#fff;text-decoration:none!important;opacity:1!important;box-sizing:border-box;box-shadow:none!important;outline:none!important;border:1px solid transparent;transition:color .3s!important;z-index:10;cursor:pointer}p>.webpButton{margin:6px 0}.webpButton:before{float:left;margin-right:10px;font-family:dashicons;font-size:20px;line-height:1.1}.webpButton:after{content:"";position:absolute;top:0;left:0;width:0;height:100%;transition:width .3s;z-index:-1}.webpButton:hover:after{width:100%}.webpButton[disabled]{pointer-events:none;opacity:.5!important}.webpButton--blue:hover,.webpButton--green:hover{color:#fff!important}.webpButton--blue{color:#0073aa!important;border-color:#0073aa}.webpButton--blue:after{background-color:#0073aa}.webpButton--green{color:#46b450!important;border-color:#46b450}.webpButton--green:after{background-color:#46b450}.webpCheckbox__input{display:none!important}.webpCheckbox__input[type=checkbox]+label:after{content:"\F147"}.webpCheckbox__input[type=radio]+label:after{content:"\F335"}.webpCheckbox__input+label{position:relative;display:inline-block}.webpCheckbox__input+label:after,.webpCheckbox__input+label:before{content:"";display:flex;align-items:center;justify-content:center;width:22px;height:22px}.webpCheckbox__input+label:before{border:1px solid #b4b9be}.webpCheckbox__input+label:after{position:absolute;top:0;left:0;font-family:dashicons;font-size:20px;line-height:1;color:#46b450;transform:scale(0);transition:transform .3s}.webpCheckbox__input[disabled]+label{opacity:.25;pointer-events:none}.webpCheckbox__input:checked+label:after{transform:scale(1)}.webpCheckbox__label{display:inline-block;max-width:650px;font-size:14px;line-height:1.64}.webpContent{font-family:Exo\ 2,sans-serif;padding:20px 30px}.webpContent p{max-width:800px;font-size:14px;line-height:1.64}.webpContent p.center{text-align:center}.webpContent--wide p{max-width:100%}.webpContent a{color:#0073aa;text-decoration:underline;box-shadow:none;outline:none;transition:opacity .3s}.webpContent a:hover{opacity:.5}.webpContent h1,.webpContent h2,.webpContent h3,.webpContent h4,.webpContent h5,.webpContent h6{font-weight:500;font-size:16px;line-height:1.5}.webpContent h1,.webpContent h2,.webpContent h3,.webpContent h4,.webpContent h5,.webpContent h6,.webpContent p{margin:10px 0 0;padding:4px 0}.webpContent h1:first-child,.webpContent h2:first-child,.webpContent h3:first-child,.webpContent h4:first-child,.webpContent h5:first-child,.webpContent h6:first-child,.webpContent p:first-child{margin-top:0}.webpContent h1+p,.webpContent h2+p,.webpContent h3+p,.webpContent h4+p,.webpContent h5+p,.webpContent h6+p{margin-top:0;font-size:12px;line-height:1.67}.webpContent--notice h1+p,.webpContent--notice h2+p,.webpContent--notice h3+p,.webpContent--notice h4+p,.webpContent--notice h5+p,.webpContent--notice h6+p{font-size:14px;line-height:1.64}.webpContent__buttons{margin-top:-10px;padding:10px 0;overflow:hidden}.webpContent__button{float:left;margin:20px 20px 0 0}.webpContent__button:last-child{margin-right:0}.webpLoader__status{position:relative;padding:20px 0 10px}.webpLoader__bar--hidden{display:none}.webpLoader__barProgress{position:relative;font-size:0;line-height:0;height:20px}.webpLoader__barProgress:before{content:"";position:absolute;top:0;left:0;width:0;height:100%;background-color:#46b450;transition:width .3s}.webpLoader__barProgress--error:before{background-color:#dc3232}.webpLoader__barProgress[data-percent="0"]:before{width:0}.webpLoader__barProgress[data-percent="1"]:before{width:1%}.webpLoader__barProgress[data-percent="2"]:before{width:2%}.webpLoader__barProgress[data-percent="3"]:before{width:3%}.webpLoader__barProgress[data-percent="4"]:before{width:4%}.webpLoader__barProgress[data-percent="5"]:before{width:5%}.webpLoader__barProgress[data-percent="6"]:before{width:6%}.webpLoader__barProgress[data-percent="7"]:before{width:7%}.webpLoader__barProgress[data-percent="8"]:before{width:8%}.webpLoader__barProgress[data-percent="9"]:before{width:9%}.webpLoader__barProgress[data-percent="10"]:before{width:10%}.webpLoader__barProgress[data-percent="11"]:before{width:11%}.webpLoader__barProgress[data-percent="12"]:before{width:12%}.webpLoader__barProgress[data-percent="13"]:before{width:13%}.webpLoader__barProgress[data-percent="14"]:before{width:14%}.webpLoader__barProgress[data-percent="15"]:before{width:15%}.webpLoader__barProgress[data-percent="16"]:before{width:16%}.webpLoader__barProgress[data-percent="17"]:before{width:17%}.webpLoader__barProgress[data-percent="18"]:before{width:18%}.webpLoader__barProgress[data-percent="19"]:before{width:19%}.webpLoader__barProgress[data-percent="20"]:before{width:20%}.webpLoader__barProgress[data-percent="21"]:before{width:21%}.webpLoader__barProgress[data-percent="22"]:before{width:22%}.webpLoader__barProgress[data-percent="23"]:before{width:23%}.webpLoader__barProgress[data-percent="24"]:before{width:24%}.webpLoader__barProgress[data-percent="25"]:before{width:25%}.webpLoader__barProgress[data-percent="26"]:before{width:26%}.webpLoader__barProgress[data-percent="27"]:before{width:27%}.webpLoader__barProgress[data-percent="28"]:before{width:28%}.webpLoader__barProgress[data-percent="29"]:before{width:29%}.webpLoader__barProgress[data-percent="30"]:before{width:30%}.webpLoader__barProgress[data-percent="31"]:before{width:31%}.webpLoader__barProgress[data-percent="32"]:before{width:32%}.webpLoader__barProgress[data-percent="33"]:before{width:33%}.webpLoader__barProgress[data-percent="34"]:before{width:34%}.webpLoader__barProgress[data-percent="35"]:before{width:35%}.webpLoader__barProgress[data-percent="36"]:before{width:36%}.webpLoader__barProgress[data-percent="37"]:before{width:37%}.webpLoader__barProgress[data-percent="38"]:before{width:38%}.webpLoader__barProgress[data-percent="39"]:before{width:39%}.webpLoader__barProgress[data-percent="40"]:before{width:40%}.webpLoader__barProgress[data-percent="41"]:before{width:41%}.webpLoader__barProgress[data-percent="42"]:before{width:42%}.webpLoader__barProgress[data-percent="43"]:before{width:43%}.webpLoader__barProgress[data-percent="44"]:before{width:44%}.webpLoader__barProgress[data-percent="45"]:before{width:45%}.webpLoader__barProgress[data-percent="46"]:before{width:46%}.webpLoader__barProgress[data-percent="47"]:before{width:47%}.webpLoader__barProgress[data-percent="48"]:before{width:48%}.webpLoader__barProgress[data-percent="49"]:before{width:49%}.webpLoader__barProgress[data-percent="50"]:before{width:50%}.webpLoader__barProgress[data-percent="51"]:before{width:51%}.webpLoader__barProgress[data-percent="52"]:before{width:52%}.webpLoader__barProgress[data-percent="53"]:before{width:53%}.webpLoader__barProgress[data-percent="54"]:before{width:54%}.webpLoader__barProgress[data-percent="55"]:before{width:55%}.webpLoader__barProgress[data-percent="56"]:before{width:56%}.webpLoader__barProgress[data-percent="57"]:before{width:57%}.webpLoader__barProgress[data-percent="58"]:before{width:58%}.webpLoader__barProgress[data-percent="59"]:before{width:59%}.webpLoader__barProgress[data-percent="60"]:before{width:60%}.webpLoader__barProgress[data-percent="61"]:before{width:61%}.webpLoader__barProgress[data-percent="62"]:before{width:62%}.webpLoader__barProgress[data-percent="63"]:before{width:63%}.webpLoader__barProgress[data-percent="64"]:before{width:64%}.webpLoader__barProgress[data-percent="65"]:before{width:65%}.webpLoader__barProgress[data-percent="66"]:before{width:66%}.webpLoader__barProgress[data-percent="67"]:before{width:67%}.webpLoader__barProgress[data-percent="68"]:before{width:68%}.webpLoader__barProgress[data-percent="69"]:before{width:69%}.webpLoader__barProgress[data-percent="70"]:before{width:70%}.webpLoader__barProgress[data-percent="71"]:before{width:71%}.webpLoader__barProgress[data-percent="72"]:before{width:72%}.webpLoader__barProgress[data-percent="73"]:before{width:73%}.webpLoader__barProgress[data-percent="74"]:before{width:74%}.webpLoader__barProgress[data-percent="75"]:before{width:75%}.webpLoader__barProgress[data-percent="76"]:before{width:76%}.webpLoader__barProgress[data-percent="77"]:before{width:77%}.webpLoader__barProgress[data-percent="78"]:before{width:78%}.webpLoader__barProgress[data-percent="79"]:before{width:79%}.webpLoader__barProgress[data-percent="80"]:before{width:80%}.webpLoader__barProgress[data-percent="81"]:before{width:81%}.webpLoader__barProgress[data-percent="82"]:before{width:82%}.webpLoader__barProgress[data-percent="83"]:before{width:83%}.webpLoader__barProgress[data-percent="84"]:before{width:84%}.webpLoader__barProgress[data-percent="85"]:before{width:85%}.webpLoader__barProgress[data-percent="86"]:before{width:86%}.webpLoader__barProgress[data-percent="87"]:before{width:87%}.webpLoader__barProgress[data-percent="88"]:before{width:88%}.webpLoader__barProgress[data-percent="89"]:before{width:89%}.webpLoader__barProgress[data-percent="90"]:before{width:90%}.webpLoader__barProgress[data-percent="91"]:before{width:91%}.webpLoader__barProgress[data-percent="92"]:before{width:92%}.webpLoader__barProgress[data-percent="93"]:before{width:93%}.webpLoader__barProgress[data-percent="94"]:before{width:94%}.webpLoader__barProgress[data-percent="95"]:before{width:95%}.webpLoader__barProgress[data-percent="96"]:before{width:96%}.webpLoader__barProgress[data-percent="97"]:before{width:97%}.webpLoader__barProgress[data-percent="98"]:before{width:98%}.webpLoader__barProgress[data-percent="99"]:before{width:99%}.webpLoader__barProgress[data-percent="100"]:before{width:100%}.webpLoader__barCount{position:relative;display:inline-block;padding:0 5px;font-family:monospace;font-size:12px;line-height:20px;color:#fff;background-color:#46b450}.webpLoader__barProgress--error .webpLoader__barCount{background-color:#dc3232}.webpLoader__barCount:after{content:"...";margin-left:5px;animation:dotsLoading 1s linear infinite}.webpLoader__barProgress--error .webpLoader__barCount:after,.webpLoader__barProgress[data-percent="100"] .webpLoader__barCount:after{display:none}.webpLoader__barProgress[data-percent="0"] .webpLoader__barCount:before{content:"0%"}.webpLoader__barProgress[data-percent="1"] .webpLoader__barCount:before{content:"1%"}.webpLoader__barProgress[data-percent="2"] .webpLoader__barCount:before{content:"2%"}.webpLoader__barProgress[data-percent="3"] .webpLoader__barCount:before{content:"3%"}.webpLoader__barProgress[data-percent="4"] .webpLoader__barCount:before{content:"4%"}.webpLoader__barProgress[data-percent="5"] .webpLoader__barCount:before{content:"5%"}.webpLoader__barProgress[data-percent="6"] .webpLoader__barCount:before{content:"6%"}.webpLoader__barProgress[data-percent="7"] .webpLoader__barCount:before{content:"7%"}.webpLoader__barProgress[data-percent="8"] .webpLoader__barCount:before{content:"8%"}.webpLoader__barProgress[data-percent="9"] .webpLoader__barCount:before{content:"9%"}.webpLoader__barProgress[data-percent="10"] .webpLoader__barCount:before{content:"10%"}.webpLoader__barProgress[data-percent="11"] .webpLoader__barCount:before{content:"11%"}.webpLoader__barProgress[data-percent="12"] .webpLoader__barCount:before{content:"12%"}.webpLoader__barProgress[data-percent="13"] .webpLoader__barCount:before{content:"13%"}.webpLoader__barProgress[data-percent="14"] .webpLoader__barCount:before{content:"14%"}.webpLoader__barProgress[data-percent="15"] .webpLoader__barCount:before{content:"15%"}.webpLoader__barProgress[data-percent="16"] .webpLoader__barCount:before{content:"16%"}.webpLoader__barProgress[data-percent="17"] .webpLoader__barCount:before{content:"17%"}.webpLoader__barProgress[data-percent="18"] .webpLoader__barCount:before{content:"18%"}.webpLoader__barProgress[data-percent="19"] .webpLoader__barCount:before{content:"19%"}.webpLoader__barProgress[data-percent="20"] .webpLoader__barCount:before{content:"20%"}.webpLoader__barProgress[data-percent="21"] .webpLoader__barCount:before{content:"21%"}.webpLoader__barProgress[data-percent="22"] .webpLoader__barCount:before{content:"22%"}.webpLoader__barProgress[data-percent="23"] .webpLoader__barCount:before{content:"23%"}.webpLoader__barProgress[data-percent="24"] .webpLoader__barCount:before{content:"24%"}.webpLoader__barProgress[data-percent="25"] .webpLoader__barCount:before{content:"25%"}.webpLoader__barProgress[data-percent="26"] .webpLoader__barCount:before{content:"26%"}.webpLoader__barProgress[data-percent="27"] .webpLoader__barCount:before{content:"27%"}.webpLoader__barProgress[data-percent="28"] .webpLoader__barCount:before{content:"28%"}.webpLoader__barProgress[data-percent="29"] .webpLoader__barCount:before{content:"29%"}.webpLoader__barProgress[data-percent="30"] .webpLoader__barCount:before{content:"30%"}.webpLoader__barProgress[data-percent="31"] .webpLoader__barCount:before{content:"31%"}.webpLoader__barProgress[data-percent="32"] .webpLoader__barCount:before{content:"32%"}.webpLoader__barProgress[data-percent="33"] .webpLoader__barCount:before{content:"33%"}.webpLoader__barProgress[data-percent="34"] .webpLoader__barCount:before{content:"34%"}.webpLoader__barProgress[data-percent="35"] .webpLoader__barCount:before{content:"35%"}.webpLoader__barProgress[data-percent="36"] .webpLoader__barCount:before{content:"36%"}.webpLoader__barProgress[data-percent="37"] .webpLoader__barCount:before{content:"37%"}.webpLoader__barProgress[data-percent="38"] .webpLoader__barCount:before{content:"38%"}.webpLoader__barProgress[data-percent="39"] .webpLoader__barCount:before{content:"39%"}.webpLoader__barProgress[data-percent="40"] .webpLoader__barCount:before{content:"40%"}.webpLoader__barProgress[data-percent="41"] .webpLoader__barCount:before{content:"41%"}.webpLoader__barProgress[data-percent="42"] .webpLoader__barCount:before{content:"42%"}.webpLoader__barProgress[data-percent="43"] .webpLoader__barCount:before{content:"43%"}.webpLoader__barProgress[data-percent="44"] .webpLoader__barCount:before{content:"44%"}.webpLoader__barProgress[data-percent="45"] .webpLoader__barCount:before{content:"45%"}.webpLoader__barProgress[data-percent="46"] .webpLoader__barCount:before{content:"46%"}.webpLoader__barProgress[data-percent="47"] .webpLoader__barCount:before{content:"47%"}.webpLoader__barProgress[data-percent="48"] .webpLoader__barCount:before{content:"48%"}.webpLoader__barProgress[data-percent="49"] .webpLoader__barCount:before{content:"49%"}.webpLoader__barProgress[data-percent="50"] .webpLoader__barCount:before{content:"50%"}.webpLoader__barProgress[data-percent="51"] .webpLoader__barCount:before{content:"51%"}.webpLoader__barProgress[data-percent="52"] .webpLoader__barCount:before{content:"52%"}.webpLoader__barProgress[data-percent="53"] .webpLoader__barCount:before{content:"53%"}.webpLoader__barProgress[data-percent="54"] .webpLoader__barCount:before{content:"54%"}.webpLoader__barProgress[data-percent="55"] .webpLoader__barCount:before{content:"55%"}.webpLoader__barProgress[data-percent="56"] .webpLoader__barCount:before{content:"56%"}.webpLoader__barProgress[data-percent="57"] .webpLoader__barCount:before{content:"57%"}.webpLoader__barProgress[data-percent="58"] .webpLoader__barCount:before{content:"58%"}.webpLoader__barProgress[data-percent="59"] .webpLoader__barCount:before{content:"59%"}.webpLoader__barProgress[data-percent="60"] .webpLoader__barCount:before{content:"60%"}.webpLoader__barProgress[data-percent="61"] .webpLoader__barCount:before{content:"61%"}.webpLoader__barProgress[data-percent="62"] .webpLoader__barCount:before{content:"62%"}.webpLoader__barProgress[data-percent="63"] .webpLoader__barCount:before{content:"63%"}.webpLoader__barProgress[data-percent="64"] .webpLoader__barCount:before{content:"64%"}.webpLoader__barProgress[data-percent="65"] .webpLoader__barCount:before{content:"65%"}.webpLoader__barProgress[data-percent="66"] .webpLoader__barCount:before{content:"66%"}.webpLoader__barProgress[data-percent="67"] .webpLoader__barCount:before{content:"67%"}.webpLoader__barProgress[data-percent="68"] .webpLoader__barCount:before{content:"68%"}.webpLoader__barProgress[data-percent="69"] .webpLoader__barCount:before{content:"69%"}.webpLoader__barProgress[data-percent="70"] .webpLoader__barCount:before{content:"70%"}.webpLoader__barProgress[data-percent="71"] .webpLoader__barCount:before{content:"71%"}.webpLoader__barProgress[data-percent="72"] .webpLoader__barCount:before{content:"72%"}.webpLoader__barProgress[data-percent="73"] .webpLoader__barCount:before{content:"73%"}.webpLoader__barProgress[data-percent="74"] .webpLoader__barCount:before{content:"74%"}.webpLoader__barProgress[data-percent="75"] .webpLoader__barCount:before{content:"75%"}.webpLoader__barProgress[data-percent="76"] .webpLoader__barCount:before{content:"76%"}.webpLoader__barProgress[data-percent="77"] .webpLoader__barCount:before{content:"77%"}.webpLoader__barProgress[data-percent="78"] .webpLoader__barCount:before{content:"78%"}.webpLoader__barProgress[data-percent="79"] .webpLoader__barCount:before{content:"79%"}.webpLoader__barProgress[data-percent="80"] .webpLoader__barCount:before{content:"80%"}.webpLoader__barProgress[data-percent="81"] .webpLoader__barCount:before{content:"81%"}.webpLoader__barProgress[data-percent="82"] .webpLoader__barCount:before{content:"82%"}.webpLoader__barProgress[data-percent="83"] .webpLoader__barCount:before{content:"83%"}.webpLoader__barProgress[data-percent="84"] .webpLoader__barCount:before{content:"84%"}.webpLoader__barProgress[data-percent="85"] .webpLoader__barCount:before{content:"85%"}.webpLoader__barProgress[data-percent="86"] .webpLoader__barCount:before{content:"86%"}.webpLoader__barProgress[data-percent="87"] .webpLoader__barCount:before{content:"87%"}.webpLoader__barProgress[data-percent="88"] .webpLoader__barCount:before{content:"88%"}.webpLoader__barProgress[data-percent="89"] .webpLoader__barCount:before{content:"89%"}.webpLoader__barProgress[data-percent="90"] .webpLoader__barCount:before{content:"90%"}.webpLoader__barProgress[data-percent="91"] .webpLoader__barCount:before{content:"91%"}.webpLoader__barProgress[data-percent="92"] .webpLoader__barCount:before{content:"92%"}.webpLoader__barProgress[data-percent="93"] .webpLoader__barCount:before{content:"93%"}.webpLoader__barProgress[data-percent="94"] .webpLoader__barCount:before{content:"94%"}.webpLoader__barProgress[data-percent="95"] .webpLoader__barCount:before{content:"95%"}.webpLoader__barProgress[data-percent="96"] .webpLoader__barCount:before{content:"96%"}.webpLoader__barProgress[data-percent="97"] .webpLoader__barCount:before{content:"97%"}.webpLoader__barProgress[data-percent="98"] .webpLoader__barCount:before{content:"98%"}.webpLoader__barProgress[data-percent="99"] .webpLoader__barCount:before{content:"99%"}.webpLoader__barProgress[data-percent="100"] .webpLoader__barCount:before{content:"100%"}.webpLoader__size{margin-bottom:-10px;padding:4px 0;font-size:14px;line-height:1.64}.webpLoader__sizeProgress{font-weight:500}.webpLoader__success{position:relative;margin-top:20px;padding:4px 0 4px 20px}.webpLoader__success:before{content:"";position:absolute;top:0;left:0;width:2px;height:100%;background-color:#46b450}.webpLoader__successContent{font-weight:500;font-size:14px;line-height:1.64;color:#46b450}.webpLoader__successContent a{color:inherit}.webpLoader__errors{margin-top:20px;border-left:2px solid #a0a5aa}.webpLoader__errorsTitle{display:inline-block;padding:4px 22px;font-size:14px;line-height:1.64;color:#fff;background-color:#a0a5aa}.webpLoader__errorsContent{padding:14px 0 14px 20px;font-size:12px;line-height:1.75}.webpLoader__errorsContentMessage{font-weight:500;color:#dc3232;font-size:14px;line-height:1.64}.webpLoader__button--disabled{pointer-events:none;opacity:.25!important}.webpPopup{margin-top:20px}.webpPopup__inner{display:flex;flex-wrap:wrap;background-color:#fff}.webpPopup__image{width:152px;background-image:url(../../img/author.jpg);background-position:50%;background-size:cover;background-repeat:no-repeat}.webpPopup__content{flex:1;padding:10px 20px;border:1px solid #a0a5aa;border-left:0}.webpServerInfo{color:#222;text-align:center}.webpServerInfo pre{margin:0;font-family:monospace}.webpServerInfo h1,.webpServerInfo h2{display:none}.webpServerInfo p{max-width:100%}.webpServerInfo table{border-collapse:collapse;border:0;width:100%;margin:10px auto}.webpServerInfo td,.webpServerInfo th{border:1px solid #666;vertical-align:baseline;padding:4px 5px;font-size:12px;line-height:1.67;text-align:center}.webpServerInfo .p{text-align:left}.webpServerInfo .e{background-color:#ccf;width:300px;font-weight:700}.webpServerInfo .h{background-color:#99c;font-weight:700}.webpServerInfo .v{background-color:#ddd;max-width:300px;overflow-x:auto;word-wrap:break-word}.webpServerInfo .v i{color:#999}.webpServerInfo img{float:right;border:0}.webpTable{width:100%;margin:5px 0;border-spacing:0}.webpTable td{padding:5px 0;vertical-align:top}.webpTable td:first-child{width:22px;padding-right:30px}@media screen and (max-width:1024px){.webpPage__column--large{width:100%}.webpPage__column--small{width:100%;margin-top:40px}.webpPage__widget+.webpPage__widget{margin-top:40px}}@media screen and (max-width:782px){.webpModal__button{width:100%}.webpPage{padding-right:10px}.webpPopup__inner{display:block;border:1px solid #a0a5aa}.webpPopup__image{height:152px;margin:20px auto 0}.webpPopup__content{border:0}}@media screen and (max-width:768px){.webpPage__quality{display:block}.webpPage__qualityItem{border-left:0}.webpPage__qualityItem+.webpPage__qualityItem{border-top:1px solid #a0a5aa}}
{public → assets}/build/js/scripts.js RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-Regular.ttf RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-Regular.woff RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-Regular.woff2 RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-SemiBold.ttf RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-SemiBold.woff RENAMED
File without changes
{public → assets}/fonts/Exo2/Exo2-SemiBold.woff2 RENAMED
File without changes
{public → assets}/img/author.jpg RENAMED
File without changes
{public → assets}/img/debug/.htaccess RENAMED
File without changes
{public → assets}/img/debug/icon-after.png RENAMED
File without changes
{public → assets}/img/debug/icon-after.png2 RENAMED
File without changes
{public → assets}/img/debug/icon-before.png RENAMED
File without changes
{public → assets}/img/debug/icon-before.png2 RENAMED
File without changes
{public → assets}/img/icon-test.png RENAMED
File without changes
{public → assets}/img/icon-test.webp RENAMED
File without changes
includes/passthru.php ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Loads images in WebP format or original images if browser does not support WebP.
4
+ *
5
+ * @category WordPress Plugin
6
+ * @package WebP Converter for Media
7
+ * @author Mateusz Gbiorczyk
8
+ * @link https://wordpress.org/plugins/webp-converter-for-media/
9
+ */
10
+
11
+ /**
12
+ * Loads lighter weight image files in output format instead of original formats.
13
+ */
14
+ class PassthruLoader {
15
+
16
+ const PATH_UPLOADS = '';
17
+ const PATH_UPLOADS_WEBP = '';
18
+ const MIME_TYPES = '';
19
+
20
+ /**
21
+ * PassthruLoader constructor.
22
+ */
23
+ public function __construct() {
24
+ if ( ! ( $image_url = $_GET['src'] ?? null ) ) { // phpcs:ignore
25
+ return;
26
+ } elseif ( ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) {
27
+ $this->load_image_default( $image_url );
28
+ }
29
+
30
+ $this->load_converted_image( $image_url );
31
+ }
32
+
33
+ /**
34
+ * Initializes loading of image in supported output format.
35
+ *
36
+ * @param string $image_url URL of source image.
37
+ *
38
+ * @return void
39
+ */
40
+ private function load_converted_image( string $image_url ) {
41
+ $mime_types = json_decode( self::MIME_TYPES, true );
42
+ $header = function_exists( 'getallheaders' )
43
+ ? ( getallheaders()['Accept'] ?? '' )
44
+ : ( $_SERVER['HTTP_ACCEPT'] ?? '' ); // phpcs:ignore
45
+
46
+ foreach ( $mime_types as $extension => $mime_type ) {
47
+ if ( ( strpos( $header, $mime_type ) !== false )
48
+ && ( $source = $this->load_image_source( $image_url, $extension ) ) ) {
49
+ header( 'Content-Type: ' . $mime_type );
50
+ echo $source; // phpcs:ignore
51
+ exit;
52
+ }
53
+ }
54
+ $this->load_image_default( $image_url );
55
+ }
56
+
57
+ /**
58
+ * Loads image output format.
59
+ *
60
+ * @param string $image_url URL of source image.
61
+ * @param string $extension Extension of output format.
62
+ *
63
+ * @return string|null Content of image in output format.
64
+ */
65
+ private function load_image_source( string $image_url, string $extension ) {
66
+ $url = $this->generate_source_url( $image_url, $extension );
67
+ $ch = curl_init( $url );
68
+ if ( $ch === false ) {
69
+ return null;
70
+ }
71
+
72
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
73
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
74
+
75
+ $response = curl_exec( $ch );
76
+ $code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
77
+ curl_close( $ch );
78
+
79
+ if ( ( $code !== 200 ) || ! $response ) {
80
+ return null;
81
+ } else {
82
+ return ( is_string( $response ) ) ? $response : null;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Returns URL of output image by replacing URL of source image.
88
+ *
89
+ * @param string $image_url URL of source image.
90
+ * @param string $extension Extension of output format.
91
+ *
92
+ * @return string URL of image in output format.
93
+ */
94
+ private function generate_source_url( string $image_url, string $extension ): string {
95
+ return sprintf(
96
+ '%1$s.%2$s',
97
+ str_replace( self::PATH_UPLOADS, self::PATH_UPLOADS_WEBP, $image_url ),
98
+ $extension
99
+ );
100
+ }
101
+
102
+ /**
103
+ * Redirects to source image.
104
+ *
105
+ * @param string $image_url URL of source image.
106
+ *
107
+ * @return void
108
+ */
109
+ private function load_image_default( string $image_url ) {
110
+ header( 'Location: ' . $image_url );
111
+ }
112
+ }
113
+
114
+ new PassthruLoader();
libs/passthru.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Loads images in WebP format or original images if browser does not support WebP.
5
- *
6
- * @category WordPress Plugin
7
- * @package WebP Converter for Media
8
- * @author Mateusz Gbiorczyk
9
- * @link https://wordpress.org/plugins/webp-converter-for-media/
10
- */
11
-
12
- class PassthruLoader
13
- {
14
- const PATH_UPLOADS = '';
15
- const PATH_UPLOADS_WEBP = '';
16
-
17
- public function __construct()
18
- {
19
- if (!isset($_GET['src'])) {
20
- return;
21
- }
22
-
23
- $this->loadImageWebP($_GET['src']);
24
- }
25
-
26
- private function loadImageWebP($imageUrl)
27
- {
28
- $header = function_exists('getallheaders')
29
- ? (getallheaders()['Accept'] ?? '')
30
- : ($_SERVER['HTTP_ACCEPT'] ?? '');
31
-
32
- if ((strpos($header, 'image/webp') === false)
33
- || (!$source = $this->loadWebpSource($imageUrl))) {
34
- return $this->loadImageDefault($imageUrl);
35
- }
36
-
37
- header('Content-Type: image/webp');
38
- echo $source;
39
- }
40
-
41
- private function loadImageDefault($imageUrl)
42
- {
43
- header('Location: ' . $imageUrl);
44
- }
45
-
46
- private function loadWebpSource($imageUrl)
47
- {
48
- $url = $this->generateWebpUrl($imageUrl);
49
- $ch = curl_init($url);
50
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
51
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
52
-
53
- $response = curl_exec($ch);
54
- $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
55
- curl_close($ch);
56
-
57
- if (($code !== 200) || !$response) {
58
- return null;
59
- } else {
60
- return $response;
61
- }
62
- }
63
-
64
- private function generateWebpUrl($imageUrl)
65
- {
66
- return str_replace(self::PATH_UPLOADS, self::PATH_UPLOADS_WEBP, $imageUrl) . '.webp';
67
- }
68
- }
69
-
70
- new PassthruLoader();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/build/css/styles.css DELETED
@@ -1 +0,0 @@
1
- @keyframes dotsLoading{0%,to{content:"..."}25%{content:"\A0.."}50%{content:".\A0."}75%{content:"..\A0"}}@font-face{font-family:Exo\ 2;src:url(../../fonts/Exo2/Exo2-Regular.woff2) format("woff2"),url(../../fonts/Exo2/Exo2-Regular.woff) format("woff"),url(../../fonts/Exo2/Exo2-Regular.ttf) format("truetype");font-weight:400;font-style:"normal"}@font-face{font-family:Exo\ 2;src:url(../../fonts/Exo2/Exo2-SemiBold.woff2) format("woff2"),url(../../fonts/Exo2/Exo2-SemiBold.woff) format("woff"),url(../../fonts/Exo2/Exo2-SemiBold.ttf) format("truetype");font-weight:500;font-style:"normal"}.webpModal [hidden]{display:none!important}.webpModal *,.webpModal :after,.webpModal :before{margin:0;padding:0;box-sizing:border-box}.webpModal__outer{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.75);z-index:9999}.webpModal__form{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 40px);padding:20px 30px;font-family:Exo\ 2,sans-serif;font-size:0;background-color:#fff}.webpModal__headline{padding:4px 0;font-weight:500;font-size:16px;line-height:1.5}.webpModal__desc{padding:4px 0;font-size:14px;line-height:1.64}.webpModal__table{margin-top:10px}.webpModal__textarea{display:none;width:100%;margin-top:10px;padding:4px 10px;font-size:14px;line-height:1.64;border:1px solid #b4b9be!important;border-radius:0}.webpModal__textarea[placeholder]{display:block}.webpModal__textarea[placeholder=""]{display:none}.webpModal__buttons{display:flex;flex-wrap:wrap;align-items:center;margin:5px -5px 0;padding:5px 0}.webpModal__button{width:50%;padding:5px}.webpModal__buttonInner{width:100%}.webpPage{margin:20px 0 0;padding:0 20px 0 0;font-family:Exo\ 2,sans-serif;color:#444;overflow:hidden}.webpPage *,.webpPage :after,.webpPage :before{margin:0;padding:0;box-sizing:border-box}.webpPage [hidden]{display:none!important}.webpPage__alert{margin-bottom:30px;padding:15px 20px;font-size:14px;line-height:1.64;color:#fff;background-color:#46b450}.webpPage__columns{margin:0 -30px;overflow:hidden}.webpPage__column{float:left;padding:0 30px}.webpPage__column--large{width:66.666%}.webpPage__column--small{width:33.333%}.webpPage__widget{background-color:#fff}.webpPage__widget+.webpPage__widget{margin-top:60px}.webpPage__widgetTitle{padding:14px 30px;font-weight:400;font-size:16px;line-height:1.5;color:#fff;background-color:#0073aa}.webpPage__widgetTitle--second{background-color:#a0a5aa}.webpPage__widgetTitle--error{background-color:#dc3232}.webpPage__widgetRow{padding-bottom:10px}.webpPage__widgetRow:last-child{padding-bottom:0}.webpPage__widgetRow .webpButton{margin:10px 0}.webpPage__quality{display:flex;flex-wrap:wrap;margin:10px 0;border:1px solid #a0a5aa}.webpPage__qualityItem{flex:1;margin-left:-1px;text-align:center;border-left:1px solid #a0a5aa}.webpPage__qualityItemInput{display:none!important}.webpPage__qualityItemLabel{position:relative;display:block;padding:14px 20px;font-size:14px;line-height:1.64;transition:color .3s,background-color .3s}.webpPage__qualityItemInput:checked+.webpPage__qualityItemLabel{margin:-1px;padding:15px 21px;color:#fff;background-color:#46b450}.webpPage__qualityItemInput[disabled]+.webpPage__qualityItemLabel{opacity:0;pointer-events:none}.notice[data-notice=webp-converter]{margin-top:20px;padding:0}.webpButton{position:relative;display:inline-block;min-width:180px;padding:9px 30px;font-weight:500;font-size:14px;line-height:1.63;text-align:center;text-decoration:none;background-color:#fff;text-decoration:none!important;opacity:1!important;box-sizing:border-box;box-shadow:none!important;outline:none!important;border:1px solid transparent;transition:color .3s!important;z-index:10;cursor:pointer}p>.webpButton{margin:6px 0}.webpButton:before{float:left;margin-right:10px;font-family:dashicons;font-size:20px;line-height:1.1}.webpButton:after{content:"";position:absolute;top:0;left:0;width:0;height:100%;transition:width .3s;z-index:-1}.webpButton:hover:after{width:100%}.webpButton[disabled]{pointer-events:none;opacity:.5!important}.webpButton--blue:hover,.webpButton--green:hover{color:#fff!important}.webpButton--blue{color:#0073aa!important;border-color:#0073aa}.webpButton--blue:after{background-color:#0073aa}.webpButton--green{color:#46b450!important;border-color:#46b450}.webpButton--green:after{background-color:#46b450}.webpCheckbox__input{display:none!important}.webpCheckbox__input[type=checkbox]+label:after{content:"\F147"}.webpCheckbox__input[type=radio]+label:after{content:"\F335"}.webpCheckbox__input+label{position:relative;display:inline-block}.webpCheckbox__input+label:after,.webpCheckbox__input+label:before{content:"";display:flex;align-items:center;justify-content:center;width:22px;height:22px}.webpCheckbox__input+label:before{border:1px solid #b4b9be}.webpCheckbox__input+label:after{position:absolute;top:0;left:0;font-family:dashicons;font-size:20px;line-height:1;color:#46b450;transform:scale(0);transition:transform .3s}.webpCheckbox__input[disabled]+label{opacity:.25;pointer-events:none}.webpCheckbox__input:checked+label:after{transform:scale(1)}.webpCheckbox__label{display:inline-block;max-width:650px;font-size:14px;line-height:1.64}.webpContent{font-family:Exo\ 2,sans-serif;padding:20px 30px}.webpContent p{max-width:800px;font-size:14px;line-height:1.64}.webpContent p.center{text-align:center}.webpContent--wide p{max-width:100%}.webpContent a{color:#0073aa;text-decoration:underline;box-shadow:none;outline:none;transition:opacity .3s}.webpContent a:hover{opacity:.5}.webpContent h1,.webpContent h2,.webpContent h3,.webpContent h4,.webpContent h5,.webpContent h6{font-weight:500;font-size:16px;line-height:1.5}.webpContent h1,.webpContent h2,.webpContent h3,.webpContent h4,.webpContent h5,.webpContent h6,.webpContent p{margin:10px 0 0;padding:4px 0}.webpContent h1:first-child,.webpContent h2:first-child,.webpContent h3:first-child,.webpContent h4:first-child,.webpContent h5:first-child,.webpContent h6:first-child,.webpContent p:first-child{margin-top:0}.webpContent h1+p,.webpContent h2+p,.webpContent h3+p,.webpContent h4+p,.webpContent h5+p,.webpContent h6+p{margin-top:0;font-size:12px;line-height:1.67}.webpContent--notice h1+p,.webpContent--notice h2+p,.webpContent--notice h3+p,.webpContent--notice h4+p,.webpContent--notice h5+p,.webpContent--notice h6+p{font-size:14px;line-height:1.64}.webpContent__buttons{margin-top:-10px;padding:10px 0;overflow:hidden}.webpContent__button{float:left;margin:20px 20px 0 0}.webpContent__button:last-child{margin-right:0}.webpLoader__status{position:relative;padding:20px 0 10px}.webpLoader__bar--hidden{display:none}.webpLoader__barProgress{position:relative;font-size:0;line-height:0;height:20px}.webpLoader__barProgress:before{content:"";position:absolute;top:0;left:0;width:0;height:100%;background-color:#46b450;transition:width .3s}.webpLoader__barProgress--error:before{background-color:#dc3232}.webpLoader__barProgress[data-percent="0"]:before{width:0}.webpLoader__barProgress[data-percent="1"]:before{width:1%}.webpLoader__barProgress[data-percent="2"]:before{width:2%}.webpLoader__barProgress[data-percent="3"]:before{width:3%}.webpLoader__barProgress[data-percent="4"]:before{width:4%}.webpLoader__barProgress[data-percent="5"]:before{width:5%}.webpLoader__barProgress[data-percent="6"]:before{width:6%}.webpLoader__barProgress[data-percent="7"]:before{width:7%}.webpLoader__barProgress[data-percent="8"]:before{width:8%}.webpLoader__barProgress[data-percent="9"]:before{width:9%}.webpLoader__barProgress[data-percent="10"]:before{width:10%}.webpLoader__barProgress[data-percent="11"]:before{width:11%}.webpLoader__barProgress[data-percent="12"]:before{width:12%}.webpLoader__barProgress[data-percent="13"]:before{width:13%}.webpLoader__barProgress[data-percent="14"]:before{width:14%}.webpLoader__barProgress[data-percent="15"]:before{width:15%}.webpLoader__barProgress[data-percent="16"]:before{width:16%}.webpLoader__barProgress[data-percent="17"]:before{width:17%}.webpLoader__barProgress[data-percent="18"]:before{width:18%}.webpLoader__barProgress[data-percent="19"]:before{width:19%}.webpLoader__barProgress[data-percent="20"]:before{width:20%}.webpLoader__barProgress[data-percent="21"]:before{width:21%}.webpLoader__barProgress[data-percent="22"]:before{width:22%}.webpLoader__barProgress[data-percent="23"]:before{width:23%}.webpLoader__barProgress[data-percent="24"]:before{width:24%}.webpLoader__barProgress[data-percent="25"]:before{width:25%}.webpLoader__barProgress[data-percent="26"]:before{width:26%}.webpLoader__barProgress[data-percent="27"]:before{width:27%}.webpLoader__barProgress[data-percent="28"]:before{width:28%}.webpLoader__barProgress[data-percent="29"]:before{width:29%}.webpLoader__barProgress[data-percent="30"]:before{width:30%}.webpLoader__barProgress[data-percent="31"]:before{width:31%}.webpLoader__barProgress[data-percent="32"]:before{width:32%}.webpLoader__barProgress[data-percent="33"]:before{width:33%}.webpLoader__barProgress[data-percent="34"]:before{width:34%}.webpLoader__barProgress[data-percent="35"]:before{width:35%}.webpLoader__barProgress[data-percent="36"]:before{width:36%}.webpLoader__barProgress[data-percent="37"]:before{width:37%}.webpLoader__barProgress[data-percent="38"]:before{width:38%}.webpLoader__barProgress[data-percent="39"]:before{width:39%}.webpLoader__barProgress[data-percent="40"]:before{width:40%}.webpLoader__barProgress[data-percent="41"]:before{width:41%}.webpLoader__barProgress[data-percent="42"]:before{width:42%}.webpLoader__barProgress[data-percent="43"]:before{width:43%}.webpLoader__barProgress[data-percent="44"]:before{width:44%}.webpLoader__barProgress[data-percent="45"]:before{width:45%}.webpLoader__barProgress[data-percent="46"]:before{width:46%}.webpLoader__barProgress[data-percent="47"]:before{width:47%}.webpLoader__barProgress[data-percent="48"]:before{width:48%}.webpLoader__barProgress[data-percent="49"]:before{width:49%}.webpLoader__barProgress[data-percent="50"]:before{width:50%}.webpLoader__barProgress[data-percent="51"]:before{width:51%}.webpLoader__barProgress[data-percent="52"]:before{width:52%}.webpLoader__barProgress[data-percent="53"]:before{width:53%}.webpLoader__barProgress[data-percent="54"]:before{width:54%}.webpLoader__barProgress[data-percent="55"]:before{width:55%}.webpLoader__barProgress[data-percent="56"]:before{width:56%}.webpLoader__barProgress[data-percent="57"]:before{width:57%}.webpLoader__barProgress[data-percent="58"]:before{width:58%}.webpLoader__barProgress[data-percent="59"]:before{width:59%}.webpLoader__barProgress[data-percent="60"]:before{width:60%}.webpLoader__barProgress[data-percent="61"]:before{width:61%}.webpLoader__barProgress[data-percent="62"]:before{width:62%}.webpLoader__barProgress[data-percent="63"]:before{width:63%}.webpLoader__barProgress[data-percent="64"]:before{width:64%}.webpLoader__barProgress[data-percent="65"]:before{width:65%}.webpLoader__barProgress[data-percent="66"]:before{width:66%}.webpLoader__barProgress[data-percent="67"]:before{width:67%}.webpLoader__barProgress[data-percent="68"]:before{width:68%}.webpLoader__barProgress[data-percent="69"]:before{width:69%}.webpLoader__barProgress[data-percent="70"]:before{width:70%}.webpLoader__barProgress[data-percent="71"]:before{width:71%}.webpLoader__barProgress[data-percent="72"]:before{width:72%}.webpLoader__barProgress[data-percent="73"]:before{width:73%}.webpLoader__barProgress[data-percent="74"]:before{width:74%}.webpLoader__barProgress[data-percent="75"]:before{width:75%}.webpLoader__barProgress[data-percent="76"]:before{width:76%}.webpLoader__barProgress[data-percent="77"]:before{width:77%}.webpLoader__barProgress[data-percent="78"]:before{width:78%}.webpLoader__barProgress[data-percent="79"]:before{width:79%}.webpLoader__barProgress[data-percent="80"]:before{width:80%}.webpLoader__barProgress[data-percent="81"]:before{width:81%}.webpLoader__barProgress[data-percent="82"]:before{width:82%}.webpLoader__barProgress[data-percent="83"]:before{width:83%}.webpLoader__barProgress[data-percent="84"]:before{width:84%}.webpLoader__barProgress[data-percent="85"]:before{width:85%}.webpLoader__barProgress[data-percent="86"]:before{width:86%}.webpLoader__barProgress[data-percent="87"]:before{width:87%}.webpLoader__barProgress[data-percent="88"]:before{width:88%}.webpLoader__barProgress[data-percent="89"]:before{width:89%}.webpLoader__barProgress[data-percent="90"]:before{width:90%}.webpLoader__barProgress[data-percent="91"]:before{width:91%}.webpLoader__barProgress[data-percent="92"]:before{width:92%}.webpLoader__barProgress[data-percent="93"]:before{width:93%}.webpLoader__barProgress[data-percent="94"]:before{width:94%}.webpLoader__barProgress[data-percent="95"]:before{width:95%}.webpLoader__barProgress[data-percent="96"]:before{width:96%}.webpLoader__barProgress[data-percent="97"]:before{width:97%}.webpLoader__barProgress[data-percent="98"]:before{width:98%}.webpLoader__barProgress[data-percent="99"]:before{width:99%}.webpLoader__barProgress[data-percent="100"]:before{width:100%}.webpLoader__barCount{position:relative;display:inline-block;padding:0 5px;font-family:monospace;font-size:12px;line-height:20px;color:#fff;background-color:#46b450}.webpLoader__barProgress--error .webpLoader__barCount{background-color:#dc3232}.webpLoader__barCount:after{content:"...";margin-left:5px;animation:dotsLoading 1s linear infinite}.webpLoader__barProgress--error .webpLoader__barCount:after,.webpLoader__barProgress[data-percent="100"] .webpLoader__barCount:after{display:none}.webpLoader__barProgress[data-percent="0"] .webpLoader__barCount:before{content:"0%"}.webpLoader__barProgress[data-percent="1"] .webpLoader__barCount:before{content:"1%"}.webpLoader__barProgress[data-percent="2"] .webpLoader__barCount:before{content:"2%"}.webpLoader__barProgress[data-percent="3"] .webpLoader__barCount:before{content:"3%"}.webpLoader__barProgress[data-percent="4"] .webpLoader__barCount:before{content:"4%"}.webpLoader__barProgress[data-percent="5"] .webpLoader__barCount:before{content:"5%"}.webpLoader__barProgress[data-percent="6"] .webpLoader__barCount:before{content:"6%"}.webpLoader__barProgress[data-percent="7"] .webpLoader__barCount:before{content:"7%"}.webpLoader__barProgress[data-percent="8"] .webpLoader__barCount:before{content:"8%"}.webpLoader__barProgress[data-percent="9"] .webpLoader__barCount:before{content:"9%"}.webpLoader__barProgress[data-percent="10"] .webpLoader__barCount:before{content:"10%"}.webpLoader__barProgress[data-percent="11"] .webpLoader__barCount:before{content:"11%"}.webpLoader__barProgress[data-percent="12"] .webpLoader__barCount:before{content:"12%"}.webpLoader__barProgress[data-percent="13"] .webpLoader__barCount:before{content:"13%"}.webpLoader__barProgress[data-percent="14"] .webpLoader__barCount:before{content:"14%"}.webpLoader__barProgress[data-percent="15"] .webpLoader__barCount:before{content:"15%"}.webpLoader__barProgress[data-percent="16"] .webpLoader__barCount:before{content:"16%"}.webpLoader__barProgress[data-percent="17"] .webpLoader__barCount:before{content:"17%"}.webpLoader__barProgress[data-percent="18"] .webpLoader__barCount:before{content:"18%"}.webpLoader__barProgress[data-percent="19"] .webpLoader__barCount:before{content:"19%"}.webpLoader__barProgress[data-percent="20"] .webpLoader__barCount:before{content:"20%"}.webpLoader__barProgress[data-percent="21"] .webpLoader__barCount:before{content:"21%"}.webpLoader__barProgress[data-percent="22"] .webpLoader__barCount:before{content:"22%"}.webpLoader__barProgress[data-percent="23"] .webpLoader__barCount:before{content:"23%"}.webpLoader__barProgress[data-percent="24"] .webpLoader__barCount:before{content:"24%"}.webpLoader__barProgress[data-percent="25"] .webpLoader__barCount:before{content:"25%"}.webpLoader__barProgress[data-percent="26"] .webpLoader__barCount:before{content:"26%"}.webpLoader__barProgress[data-percent="27"] .webpLoader__barCount:before{content:"27%"}.webpLoader__barProgress[data-percent="28"] .webpLoader__barCount:before{content:"28%"}.webpLoader__barProgress[data-percent="29"] .webpLoader__barCount:before{content:"29%"}.webpLoader__barProgress[data-percent="30"] .webpLoader__barCount:before{content:"30%"}.webpLoader__barProgress[data-percent="31"] .webpLoader__barCount:before{content:"31%"}.webpLoader__barProgress[data-percent="32"] .webpLoader__barCount:before{content:"32%"}.webpLoader__barProgress[data-percent="33"] .webpLoader__barCount:before{content:"33%"}.webpLoader__barProgress[data-percent="34"] .webpLoader__barCount:before{content:"34%"}.webpLoader__barProgress[data-percent="35"] .webpLoader__barCount:before{content:"35%"}.webpLoader__barProgress[data-percent="36"] .webpLoader__barCount:before{content:"36%"}.webpLoader__barProgress[data-percent="37"] .webpLoader__barCount:before{content:"37%"}.webpLoader__barProgress[data-percent="38"] .webpLoader__barCount:before{content:"38%"}.webpLoader__barProgress[data-percent="39"] .webpLoader__barCount:before{content:"39%"}.webpLoader__barProgress[data-percent="40"] .webpLoader__barCount:before{content:"40%"}.webpLoader__barProgress[data-percent="41"] .webpLoader__barCount:before{content:"41%"}.webpLoader__barProgress[data-percent="42"] .webpLoader__barCount:before{content:"42%"}.webpLoader__barProgress[data-percent="43"] .webpLoader__barCount:before{content:"43%"}.webpLoader__barProgress[data-percent="44"] .webpLoader__barCount:before{content:"44%"}.webpLoader__barProgress[data-percent="45"] .webpLoader__barCount:before{content:"45%"}.webpLoader__barProgress[data-percent="46"] .webpLoader__barCount:before{content:"46%"}.webpLoader__barProgress[data-percent="47"] .webpLoader__barCount:before{content:"47%"}.webpLoader__barProgress[data-percent="48"] .webpLoader__barCount:before{content:"48%"}.webpLoader__barProgress[data-percent="49"] .webpLoader__barCount:before{content:"49%"}.webpLoader__barProgress[data-percent="50"] .webpLoader__barCount:before{content:"50%"}.webpLoader__barProgress[data-percent="51"] .webpLoader__barCount:before{content:"51%"}.webpLoader__barProgress[data-percent="52"] .webpLoader__barCount:before{content:"52%"}.webpLoader__barProgress[data-percent="53"] .webpLoader__barCount:before{content:"53%"}.webpLoader__barProgress[data-percent="54"] .webpLoader__barCount:before{content:"54%"}.webpLoader__barProgress[data-percent="55"] .webpLoader__barCount:before{content:"55%"}.webpLoader__barProgress[data-percent="56"] .webpLoader__barCount:before{content:"56%"}.webpLoader__barProgress[data-percent="57"] .webpLoader__barCount:before{content:"57%"}.webpLoader__barProgress[data-percent="58"] .webpLoader__barCount:before{content:"58%"}.webpLoader__barProgress[data-percent="59"] .webpLoader__barCount:before{content:"59%"}.webpLoader__barProgress[data-percent="60"] .webpLoader__barCount:before{content:"60%"}.webpLoader__barProgress[data-percent="61"] .webpLoader__barCount:before{content:"61%"}.webpLoader__barProgress[data-percent="62"] .webpLoader__barCount:before{content:"62%"}.webpLoader__barProgress[data-percent="63"] .webpLoader__barCount:before{content:"63%"}.webpLoader__barProgress[data-percent="64"] .webpLoader__barCount:before{content:"64%"}.webpLoader__barProgress[data-percent="65"] .webpLoader__barCount:before{content:"65%"}.webpLoader__barProgress[data-percent="66"] .webpLoader__barCount:before{content:"66%"}.webpLoader__barProgress[data-percent="67"] .webpLoader__barCount:before{content:"67%"}.webpLoader__barProgress[data-percent="68"] .webpLoader__barCount:before{content:"68%"}.webpLoader__barProgress[data-percent="69"] .webpLoader__barCount:before{content:"69%"}.webpLoader__barProgress[data-percent="70"] .webpLoader__barCount:before{content:"70%"}.webpLoader__barProgress[data-percent="71"] .webpLoader__barCount:before{content:"71%"}.webpLoader__barProgress[data-percent="72"] .webpLoader__barCount:before{content:"72%"}.webpLoader__barProgress[data-percent="73"] .webpLoader__barCount:before{content:"73%"}.webpLoader__barProgress[data-percent="74"] .webpLoader__barCount:before{content:"74%"}.webpLoader__barProgress[data-percent="75"] .webpLoader__barCount:before{content:"75%"}.webpLoader__barProgress[data-percent="76"] .webpLoader__barCount:before{content:"76%"}.webpLoader__barProgress[data-percent="77"] .webpLoader__barCount:before{content:"77%"}.webpLoader__barProgress[data-percent="78"] .webpLoader__barCount:before{content:"78%"}.webpLoader__barProgress[data-percent="79"] .webpLoader__barCount:before{content:"79%"}.webpLoader__barProgress[data-percent="80"] .webpLoader__barCount:before{content:"80%"}.webpLoader__barProgress[data-percent="81"] .webpLoader__barCount:before{content:"81%"}.webpLoader__barProgress[data-percent="82"] .webpLoader__barCount:before{content:"82%"}.webpLoader__barProgress[data-percent="83"] .webpLoader__barCount:before{content:"83%"}.webpLoader__barProgress[data-percent="84"] .webpLoader__barCount:before{content:"84%"}.webpLoader__barProgress[data-percent="85"] .webpLoader__barCount:before{content:"85%"}.webpLoader__barProgress[data-percent="86"] .webpLoader__barCount:before{content:"86%"}.webpLoader__barProgress[data-percent="87"] .webpLoader__barCount:before{content:"87%"}.webpLoader__barProgress[data-percent="88"] .webpLoader__barCount:before{content:"88%"}.webpLoader__barProgress[data-percent="89"] .webpLoader__barCount:before{content:"89%"}.webpLoader__barProgress[data-percent="90"] .webpLoader__barCount:before{content:"90%"}.webpLoader__barProgress[data-percent="91"] .webpLoader__barCount:before{content:"91%"}.webpLoader__barProgress[data-percent="92"] .webpLoader__barCount:before{content:"92%"}.webpLoader__barProgress[data-percent="93"] .webpLoader__barCount:before{content:"93%"}.webpLoader__barProgress[data-percent="94"] .webpLoader__barCount:before{content:"94%"}.webpLoader__barProgress[data-percent="95"] .webpLoader__barCount:before{content:"95%"}.webpLoader__barProgress[data-percent="96"] .webpLoader__barCount:before{content:"96%"}.webpLoader__barProgress[data-percent="97"] .webpLoader__barCount:before{content:"97%"}.webpLoader__barProgress[data-percent="98"] .webpLoader__barCount:before{content:"98%"}.webpLoader__barProgress[data-percent="99"] .webpLoader__barCount:before{content:"99%"}.webpLoader__barProgress[data-percent="100"] .webpLoader__barCount:before{content:"100%"}.webpLoader__size{margin-bottom:-10px;padding:4px 0;font-size:14px;line-height:1.64}.webpLoader__sizeProgress{font-weight:500}.webpLoader__success{position:relative;margin-top:20px;padding:4px 0 4px 20px}.webpLoader__success:before{content:"";position:absolute;top:0;left:0;width:2px;height:100%;background-color:#46b450}.webpLoader__successContent{font-weight:500;font-size:14px;line-height:1.64;color:#46b450}.webpLoader__successContent a{color:inherit}.webpLoader__errors{margin-top:20px;border-left:2px solid #a0a5aa}.webpLoader__errorsTitle{display:inline-block;padding:4px 22px;font-size:14px;line-height:1.64;color:#fff;background-color:#a0a5aa}.webpLoader__errorsContent{padding:14px 0 14px 20px;font-size:12px;line-height:1.75}.webpLoader__errorsContentMessage{font-weight:500;color:#dc3232;font-size:14px;line-height:1.64}.webpLoader__button--disabled{pointer-events:none;opacity:.25!important}.webpPopup{margin-top:20px}.webpPopup__inner{display:flex;flex-wrap:wrap;background-color:#fff}.webpPopup__image{width:152px;background-image:url(../../img/author.jpg);background-position:50%;background-size:cover;background-repeat:no-repeat}.webpPopup__content{flex:1;padding:10px 20px;border:1px solid #a0a5aa;border-left:0}.webpServerInfo{color:#222;text-align:center}.webpServerInfo pre{margin:0;font-family:monospace}.webpServerInfo h1,.webpServerInfo h2{display:none}.webpServerInfo p{max-width:100%}.webpServerInfo table{border-collapse:collapse;border:0;width:100%;margin:10px auto}.webpServerInfo td,.webpServerInfo th{border:1px solid #666;vertical-align:baseline;padding:4px 5px;font-size:12px;line-height:1.67;text-align:center}.webpServerInfo .p{text-align:left}.webpServerInfo .e{background-color:#ccf;width:300px;font-weight:700}.webpServerInfo .h{background-color:#99c;font-weight:700}.webpServerInfo .v{background-color:#ddd;max-width:300px;overflow-x:auto;word-wrap:break-word}.webpServerInfo .v i{color:#999}.webpServerInfo img{float:right;border:0}.webpTable{width:100%;margin:5px 0;border-spacing:0}.webpTable td{padding:5px 0;vertical-align:top}.webpTable td:first-child{width:22px;padding-right:30px}@media screen and (max-width:1024px){.webpPage__column--large{width:100%}.webpPage__column--small{width:100%;margin-top:40px}.webpPage__widget+.webpPage__widget{margin-top:40px}}@media screen and (max-width:782px){.webpModal__button{width:100%}.webpPage{padding-right:10px}.webpPopup__inner{display:block;border:1px solid #a0a5aa}.webpPopup__image{height:152px;margin:20px auto 0}.webpPopup__content{border:0}}@media screen and (max-width:768px){.webpPage__quality{display:block}.webpPage__qualityItem{border-left:0}.webpPage__qualityItem+.webpPage__qualityItem{border-top:1px solid #a0a5aa}}
 
readme.txt CHANGED
@@ -1,674 +1,650 @@
1
- === WebP Converter for Media ===
2
- Contributors: mateuszgbiorczyk
3
- Donate link: https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-donate
4
- Tags: convert webp, webp, optimize images, images, webp converter, performance, optimisation
5
- Requires at least: 4.9
6
- Tested up to: 5.7
7
- Requires PHP: 7.0
8
- Stable tag: trunk
9
- License: GPLv2 or later
10
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
-
12
- Speed up your website by serving WebP images instead of standard formats JPEG, PNG and GIF.
13
-
14
- == Description ==
15
-
16
- Speed up your website by serving WebP images. By replacing files in standard JPEG, PNG and GIF formats with WebP format, you can save over a half of the page weight without losing quality.
17
-
18
- When installing a plugin you do not have to do anything more. Your current images will be converted into a new format. Users will automatically receive new, much lighter images than the original ones.
19
-
20
- As of today, nearly 90% of users use browsers that support the WebP format. The loading time of your website depends to a large extent on its weight. Now you can speed up it in a few seconds without much effort!
21
-
22
- This will be a profit both for your users who will not have to download so much data, but also for a server that will be less loaded. Remember that a better optimized website also affects your Google ranking.
23
-
24
- #### Support for additional directories
25
-
26
- Now you can also convert files not only from `/uploads` directory but also from `/plugins` and `/themes` directories. This allows full integration with the WebP format!
27
-
28
- #### How does this work?
29
-
30
- - By adding images to your Media Library, they are automatically converted and saved in a separate directory.
31
- - If you have just installed the plugin, you can convert all existing images with one click.
32
- - Converting to WebP format works for all image sizes. As WebP you will see all the images added to the Media Library.
33
- - Images are converted using PHP `GD` or `Imagick` extension *(you can modify the compression level)*.
34
- - When the browser tries to download an image file, the server verifies if it supports `image/webp` files and if the file exists.
35
- - If everything is OK, instead of the original image, the browser will receive its equivalent in WebP format.
36
- - In default loading mode **the plugin does not change image URLs, so there are no problems with saving the HTML code of website to the cache and time of its generation does not increase.** It does not matter if the image display as an `img` HTML tag or you use `background-image`. It works always!
37
- - The name of the loaded image does not contain the WebP extension. Only the source of the loaded file changes to a WebP file. As a result, you always have one URL to a file. Regardless of whether the browser supports WebP or not.
38
- - Image URLs are modified using the module `mod_rewrite` on the server, i.e. the same, and thanks to this we can use friendly links in WordPress. Additionally, the MIME type of the sent file is modified to `image/webp`.
39
- - In case rewriting by rules from .htaccess file is blocked, a mode is available which loads images via PHP file. Then image URLs are changed, but the logic of operation is the same as in the case of the default mode.
40
- - The final result is that your users download less than half of the data, and the website itself loads faster!
41
-
42
- #### WebP images are the future!
43
-
44
- Raise your website to a new level now! Install the plugin and enjoy the website that loads faster. Surely you and your users will appreciate it.
45
-
46
- #### Support to the development of plugin
47
-
48
- We spend hours working on the development of this plugin. Technical support also requires a lot of time, but we do it because we want to offer you the best plugin. We enjoy every new plugin installation.
49
-
50
- If you would like to appreciate it, you can [provide us a coffee](https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-content). **If every user bought at least one, we could work on the plugin 24 hours a day!**
51
-
52
- #### Please also read the FAQ below. Thank you for being with us!
53
-
54
- == Installation ==
55
-
56
- 1. Upload the plugin files to `/wp-content/plugins/webp-converter-for-media` directory, or install plugin through the WordPress plugins screen directly.
57
- 2. Activate plugin through `Plugins` screen in WordPress Admin Panel.
58
- 3. Use `Settings -> Settings -> WebP Converter` screen to configure the plugin.
59
- 4. Click on the button `Regenerate All`.
60
- 5. Check if everything works fine.
61
-
62
- That's all! Your website is already loading faster!
63
-
64
- == Frequently Asked Questions ==
65
-
66
- = How to get technical support? (before you ask for help) =
67
-
68
- Please always adding your thread, **read all other questions in the FAQ of plugin and other threads in support forum first**. Perhaps someone had a similar problem and it has been resolved.
69
-
70
- When adding a thread, follow these steps and reply to each of them:
71
-
72
- **1.** Do you have any error on the plugin settings page? Enter error codes. Have you consulted your server administrator or developer?
73
-
74
- **2.** URL of your website. If your site is not publicly available, add it to test environment.
75
-
76
- **3.** Configuration of your server *(link to it can be found on the settings page of plugin in the section **"We are waiting for your message"**)* - please take a screenshot of the ENTIRE page and send it to me.
77
-
78
- **4.** Settings of plugin - please take a screenshot of the ENTIRE page and send it to me.
79
-
80
- **5.** Do you use CDN? If so, please see the question **"Does the plugin support CDN?"** in plugin FAQ.
81
-
82
- **6.** Please do the test, which is described in the FAQ in question `How to check if plugin works?`. Please send a screenshot of Devtools with test results.
83
-
84
- **7.** Content of your `.htaccess` files from directories `/wp-content`, `/wp-content/uploads` and `/wp-content/uploads-webpc` *(pasting the code using the `CODE` shortcode in the editor)*.
85
-
86
- **8.** Do you use any plugin filters or actions from this FAQ? If so, list them all.
87
-
88
- **9.** What plugin version are you using? If it is not the latest then update and check everything again.
89
-
90
- **10.** Used Wordpress version.
91
-
92
- **11.** A list of all the plugins you use. Have you tried checking the plugin operation by turning off all others and activating the default theme? If not, please try whenever possible. **This is very important because other plugins or themes can cause problems.** Therefore, we recommend disabling all necessary plugins and enabling the default theme.
93
-
94
- Please remember to include the answers for all 11 questions by adding a thread. It is much easier and accelerate the solution of your problem.
95
-
96
- = Error on plugin settings screen? =
97
-
98
- If you have an error on the plugin settings screen, first of all please read it carefully. They are displayed when there is a problem with the configuration of your server or website.
99
-
100
- The messages are designed to reduce the number of support requests that are repeated. It saves your and our time. If you have information in the message that you should contact the administrator of your server, please do so.
101
-
102
- When contacting the administrator, give him all the information available in the message. If you still cannot solve the problem, please contact us.
103
-
104
- We want to solve as many similar problems as possible automatically. This eliminates the need to wait for our response and you can try to solve the problem alone. This is very important for us.
105
-
106
- = Server configuration error on Cloudflare =
107
-
108
- For Cloudflare servers, a recurring problem is the error code **rewrites_cached** that is displayed on the plugin settings page. To solve this problem, you need to disable the cache for the website from the server.
109
-
110
- Please follow the steps below:
111
- **1.** Enter Cloudflare management panel and then to **Page Rules** Tab.
112
- **2.** Click **Create page rule** button.
113
- **3.** Enter your domain name (example: **yourdomain.com/\***).
114
- **4.** Choose **Cache Level** option, set **Bypass** value and click **Save** button.
115
- **5.** Click **Save and Deploy** button.
116
- **6.** Wait, it may take several minutes for the changes to be deployed.
117
-
118
- = Error while converting? =
119
-
120
- You can get several types of errors when converting. First of all, carefully read their content. For the most part, you can solve this problem yourself. Try to do this or contact the server administrator.
121
-
122
- If you get an error: `File "%s" does not exist. Please check file path.` means that the [file_exists()](https://www.php.net/manual/en/function.file-exists.php) function in PHP returned `false` using the file path given in the error message. Check this path and make sure it is correct.
123
-
124
- If you get an error: `File "%s" is unreadable. Please check file permissions.` means that the [is_readable()](https://www.php.net/manual/en/function.is-readable.php) function in PHP returned `false` using the file path given in the error message. Check the permissions for the file and the directory in which the file is located.
125
-
126
- If you get an error: `"%s" is not a valid image file.` means that the file is damaged in some way. Download the file to disk, save it again using any graphics program and add again to the page. If the error applies to individual images then you can ignore it - just the original images will load, not WebP.
127
-
128
- If you get an error: `"%s" converted to WebP is larger than original and has been deleted.` means the original image weighed less than WebP. This happens when images have been compressed before. Disable the *"Automatic removal of WebP files larger than original"* option in plugin settings to force always using WebP.
129
-
130
- In the case of the above problems, **contacting the support forum will be useless**. Unfortunately, we are unable to help you if your files are damaged. You have to fix it yourself. If you have previously used other tools that changed the original files and damaged them, you will do nothing more.
131
-
132
- Remember that it happens that other plugins can cause problems with accessing files or the REST API. Please try to disable all other plugins and set the default theme to make sure that it is not one of them that causes these types of problems.
133
-
134
- = What are requirements of plugin? =
135
-
136
- Practically every hosting meets these requirements. You must use PHP at least 7.0 and have the `GD` or `Imagick` extension installed. **The extension must support `WebP format`.** If you have an error saying that the GD or Imagick library are not installed, but you have it installed then they are probably incorrectly configured and do not have WebP support.
137
-
138
- They are required native PHP extensions, used among others by WordPress to generate thumbnails. Your server must also have the modules `mod_mime`, `mod_rewrite` and `mod_expires` enabled.
139
-
140
- An example of the correct server configuration can be found [here](https://gbiorczyk.pl/webp-converter/serverinfo.png). Link to your current configuration can be found in the administration panel, on the management plugin page in the section **"We are waiting for your message"** *(or using the URL path: `/wp-admin/options-general.php?page=webpc_admin_page&action=server`)*.
141
-
142
- **Note the items marked in red.** If the values marked in red do not appear in your case, it means that your server does not meet the technical requirements. Pay attention to the **WebP Support** value for the GD library and **WEBP in the list of supported extensions** for the Imagick library.
143
-
144
- In a situation where your server does not meet the technical requirements, please contact your server Administrator. We are not able to help you. Please do not contact us about this matter, because this is a server configuration problem, not a plugin.
145
-
146
- Also REST API must be enabled and work without additional restrictions. If you have a problem with it, please contact the Developer who created your website. He should easily find the issue with the REST API not working.
147
-
148
- = What to do after installing plugin? =
149
-
150
- After installing the plugin, you should convert all existing images.
151
-
152
- In the WordPress admin panel, on the `Settings -> WebP Converter` subpage there is a module that allows you to process all your images.
153
-
154
- It uses the WordPress REST API by downloading addresses of all images and converting all files gradually.
155
-
156
- This process may take few or more than ten minutes depending on the number of files.
157
-
158
- **It should be done once after installing the plugin.** New images from the Media Library will be converted automatically. For other images, e.g. from the /themes directory, you must start manual conversion after adding new images.
159
-
160
- = How to check if plugin works? =
161
-
162
- When you have installed plugin and converted all images, follow these steps:
163
-
164
- 1. Run `Google Chrome` and enable `Dev Tools` *(F12)*.
165
- 2. Go to the `Network` tab and select filtering for `Img` *(Images)*.
166
- 3. Refresh your website page.
167
- 4. Check list of loaded images. Note `Type` column.
168
- 5. If value of `webp` is there, then everything works fine.
169
- 6. Remember that this plugin does not change URLs. This means that e.g. link will have path to .jpg file, but `.jpg.webp file will be loaded instead of original .jpg`.
170
- 7. In addition, you can check weight of website before and after using plugin. The difference will be huge!
171
- 8. More information: [here](https://gbiorczyk.pl/webp-converter/check-devtools.png)
172
-
173
- Please remember that in default loading mode *(via .htaccess)* URLs will remain unchanged. When you open the image in a new tab or look at its URL, you'll see the original URL. When you try to save the image to disk *(e.g. by clicking Save as...)* the original image will be saved.
174
-
175
- WebP is only used when loading a image on a website. In default loading mode *(via .htaccess)* it is done by the rules from the .htaccess file, on the server side, without the visible URL change to the image. Yes, it can be called magic :)
176
-
177
- That is why the plugin should be tested in Dev Tools. If the Type of file is `WebP`, then everything is working properly. You can also turn off the plugin for a moment and check the weight of your website, then turn it on and test again. The difference should be visible.
178
-
179
- The operation of the plugin for non-advanced users may sometimes be less understood, but everything is fine. Thanks to this, regardless of whether your browser supports WebP or not, everything works without problems.
180
-
181
- Only images from the `/uploads` directory are automatically converted. If you use other plugins that also save images in the `/uploads` directory then this may not work. Therefore, check the plugin settings and try converting all images again.
182
-
183
- = Why are some images not in WebP? =
184
-
185
- If the converted image in WebP format is larger than the original, the browser will use the original file. This converted file will be deleted. Therefore, you can also see files other than WebP on the list. When this happens, you will receive information in debug.log.
186
-
187
- When such a situation occurs, a file in `.webp.deleted` format will be created. This avoids re-converting images that were larger than original after converting to WebP. If the option of forced conversion of all images is checked, this image will also be re-converted.
188
-
189
- If you want to force the use of WebP files, uncheck the `Automatic removal of WebP files larger than original` option in the plugin settings. Then click on the `Regenerate All` button to convert all images again.
190
-
191
- Remember that this plugin supports images from the `/wp-content` directory, e.g. files downloaded from the Media Library. Redirections will not work if your images are downloaded from another domain, i.e. from an external service.
192
-
193
- When checking the operation of the plugin, e.g. in Dev Tools, pay attention to the path from which the files are downloaded and which directories you have enabled in the settings of plugin.
194
-
195
- = Where are converted images stored? =
196
-
197
- All WebP images are stored in the `/wp-content/uploads-webpc/` directory. Inside the directory there is the same structure as in the original `/wp-content` directory. The files have original extensions in the name along with the new `.webp`.
198
-
199
- In case the location of the original file is as follows: `/wp-content/uploads/2019/06/example.jpg` then its converted version will be in the following location: `/wp-content/uploads-webpc/uploads/2019/06/example.jpg.webp`.
200
-
201
- In case the location of the original file is as follows: `/wp-content/themes/my-theme/public/img/example.jpg` then its converted version will be in the following location: `/wp-content/uploads-webpc/themes/my-theme/public/img/example.jpg.webp`.
202
-
203
- Original images are not changed. If you remove plugins, only WebP files will be deleted. Your images are not changed in any way.
204
-
205
- = How to change path to uploads? =
206
-
207
- This is possible using the following types of filters to change default paths. It is a solution for advanced users. If you are not, please skip this question.
208
-
209
- Path to the root installation directory of WordPress *(`ABSPATH` by default)*:
210
-
211
- `add_filter('webpc_site_root', function($path) {
212
- return ABSPATH;
213
- });`
214
-
215
- Path to `/uploads` directory *(relative to the root directory)*:
216
-
217
- `add_filter('webpc_dir_name', function($path, $directory) {
218
- if ($directory !== 'uploads') {
219
- return $path;
220
- }
221
- return 'wp-content/uploads';
222
- }, 10, 2);`
223
-
224
- Directory path with converted WebP files *(relative to the root directory)*:
225
-
226
- `add_filter('webpc_dir_name', function($path, $directory) {
227
- if ($directory !== 'webp') {
228
- return $path;
229
- }
230
- return 'wp-content/uploads-webpc';
231
- }, 10, 2);`
232
-
233
- **Note that the `/uploads-webpc` directory must be at the same nesting level as the `/uploads`, `/plugins` and `/themes` directories.**
234
-
235
- Prefix in URL of `/wp-content/` directory or equivalent *(used in .htaccess)*:
236
-
237
- `add_filter('webpc_uploads_prefix', function($prefix) {
238
- return '/';
239
- });`
240
-
241
- For the following sample custom WordPress structure:
242
-
243
- `...
244
- ├── web
245
- ...
246
- ├── app
247
- │ ├── mu-plugins
248
- │ ├── plugins
249
- │ ├── themes
250
- │ └── uploads
251
- ├── wp-config.php
252
- ...`
253
-
254
- Use the following filters:
255
-
256
- `add_filter('webpc_site_root', function($path) {
257
- return 'C:/WAMP/www/project/webp'; // your valid path to root
258
- });
259
- add_filter('webpc_dir_name', function($path, $directory) {
260
- if ($directory !== 'uploads') {
261
- return $path;
262
- }
263
- return 'app/uploads';
264
- }, 10, 2);
265
- add_filter('webpc_dir_name', function($path, $directory) {
266
- if ($directory !== 'webp') {
267
- return $path;
268
- }
269
- return 'app/uploads-webpc';
270
- }, 10, 2);`
271
- `add_filter('webpc_uploads_prefix', function($prefix) {
272
- return '/';
273
- });`
274
-
275
- After setting the filters go to `Settings -> WebP Converter` in the admin panel and click the `Save Changes` button. `.htaccess` files with appropriate rules should be created in the directories `/uploads` and `/uploads-webpc`.
276
-
277
- = How to run manually conversion? =
278
-
279
- By default, all images are converted when you click on the `Regenerate All` button. In addition, conversion is automatic when you add new files to your Media Library.
280
-
281
- Remember that our plugin takes into account images generated by WordPress. There are many plugins that generate, for example, images of a different size or in a different version.
282
-
283
- If you would like to integrate with your plugin, which generates images by yourself, you can do it. Our plugin provides the possibility of this type of integration. This works for all images in the `/wp-content` directory.
284
-
285
- It is a solution for advanced users. If you would like to integrate with another plugin, it's best to contact the author of that plugin and give him information about the actions available in our plugin. This will help you find a solution faster.
286
-
287
- You can automatically run the option to regenerate all new images. This is useful when you use external plugins that generate images themselves. To do this, use the following code:
288
-
289
- `do_action('webpc_regenerate_all', $paths);`
290
-
291
- Below is an example of how to use this action to automatically regenerate images after changing the theme:
292
-
293
- `add_action('init', function()
294
- {
295
- do_action('webpc_regenerate_all');
296
- });`
297
-
298
- To manually start converting selected files, you can use the action to which you will pass an array with a list of paths *(they must be absolute server paths)*:
299
-
300
- `do_action('webpc_convert_paths', $paths);`
301
-
302
- An alternative method is to manually start converting the selected attachment by passing the post ID from the Media Library. Remember to run this action after registering all image sizes *(i.e. after running the `add_image_size` function)*:
303
-
304
- `do_action('webpc_convert_attachment', $postId);`
305
-
306
- In addition, you can edit the list of files that will be converted. For example, to add some to the exceptions. To do this, use the following filter, which by default returns a list of all paths:
307
-
308
- `add_filter('webpc_files_paths', function($paths, $skipExists) {
309
- return $paths;
310
- }, 10, 2);`
311
-
312
- Argument `$paths` is array of absolute server paths and `$skipExists` means whether to skip converted images.
313
-
314
- You can also modify the list of image paths for an attachment, e.g. to exclude one image size. To do this, use the following filter:
315
-
316
- `add_filter('webpc_attachment_paths', function($paths, $attachmentId) {
317
- return $paths;
318
- }, 10, 2);`
319
-
320
- Argument `$paths` is array of absolute server paths and `$attachmentId` is the post ID of attachment, added to the Media Library.
321
-
322
- To delete manually converted files, use the following action, providing as an argument an array of absolute server paths to the files *(this will delete manually converted files)*:
323
-
324
- `do_action('webpc_delete_paths', $paths);`
325
-
326
- = How to change .htaccess rules? =
327
-
328
- Manually editing the rules in the .htaccess file is a task only for experienced developers. Remember that the wrong rules can cause your website to stop working.
329
-
330
- Below is a list of filters that allow you to modify all rules. Remember that it's best to use your own rule set rather than edit parts of exists. This will ensure greater failure-free after plugin update.
331
-
332
- Returning an empty string will delete these rules the next time you save the plugin settings. You must do this after each filter edit.
333
-
334
- Rules for redirects: *(returns rules for `mod_rewrite` module)*:
335
-
336
- `add_filter('webpc_htaccess_mod_rewrite', function($rules, $path) {
337
- return '';
338
- }, 10, 2);`
339
-
340
- Argument `$path` is absolute server path for `.htaccess` file *(`/wp-content/.htaccess` or `/wp-content/uploads/.htaccess`)*.
341
-
342
- Rules for `image/webp` MIME type: *(returns rules for `mod_mime` module)*:
343
-
344
- `add_filter('webpc_htaccess_mod_mime', function($rules) {
345
- return '';
346
- });`
347
-
348
- Rules for Browser Caching: *(returns rules for `mod_expires` module)*:
349
-
350
- `add_filter('webpc_htaccess_mod_expires', function($rules) {
351
- return '';
352
- });`
353
-
354
- All rules from the files `/wp-content/.htaccess`, `/wp-content/uploads/.htaccess` and `/wp-content/uploads-webpc/.htaccess`: *(returns rules for modules: `mod_rewrite`, `mod_mime` and `mod_expires`)*:
355
-
356
- `add_filter('webpc_htaccess_rules', function($rules, $path) {
357
- return '';
358
- }, 10, 2);`
359
-
360
- Argument `$path` is absolute server path for `.htaccess` file.
361
-
362
- = Does plugin support CDN? =
363
-
364
- Unfortunately not. This is due to the logic of the plugin's operation. Plugins that enable integration with the CDN servers modify the HTML of the website, changing URLs for media files. This plugin does not modify URLs. Replacing URLs in the HTML code is not an optimal solution.
365
-
366
- The main problem when changing URLs is cache. When we modify the image URL for WebP supporting browser, then use the browser without WebP support, it will still have the URL address of an image in .webp format, because it will be in the cache.
367
-
368
- While in the case of the `img` tag you can solve this problem, in the case of `background-image` it is possible. We wanted full support so that all images would be supported - no matter how they are displayed on the website.
369
-
370
- Therefore in this plugin for browsers supporting the WebP format, only the source of the file is replaced by using the `mod_rewrite` module on the server. The URL for image remains the same. This solves the whole problem, but it is impossible to do when the files are stored on the CDN server.
371
-
372
- If you are using a CDN server, find one that automatically converts images to WebP format and properly sends the correct image format to the browser.
373
-
374
- = Configuration for Apache =
375
-
376
- In the case of Apache, when saving the settings, .htaccess files will be generated automatically in the following locations:
377
- - `/wp-content/.htaccess`
378
- - `/wp-content/uploads/.htaccess`
379
- - `/wp-content/uploads-webpc/.htaccess`
380
-
381
- If these files are missing or empty, try disabling and re-enabling the plugin or saving the plugin settings again. Also check the write permissions of the directories where these files are located.
382
-
383
- If your server is a combination of Apache and Nginx, remember that the image files must be supported by Apache. Only then will the redirections in the .htaccess file work properly. Alternatively, you can use the configuration for Nginx.
384
-
385
- = Configuration for Nginx =
386
-
387
- Please edit the configuration file:
388
- - `/etc/nginx/mime.types`
389
-
390
- and add this code line:
391
-
392
- `types {`
393
- ` # ...`
394
- ` image/webp webp;`
395
- `}`
396
-
397
- Then find the configuration file in one of the paths *(remember to select configuration file used by your vhost)*:
398
- - `/etc/nginx/sites-enabled/`
399
- - `/etc/nginx/conf.d/`
400
-
401
- and add below code in this file *(add these lines to very beginning of file if possible - if they will be at the bottom, other rules may block the rules for WebP from working)*:
402
-
403
- `server {`
404
- ` location ~ /wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif)$ {`
405
- ` if ($http_accept !~* "image/webp") {`
406
- ` break;`
407
- ` }`
408
- ` add_header Vary Accept;`
409
- ` expires 365d;`
410
- ` try_files /wp-content/uploads-webpc/$path.$ext.webp $uri =404;`
411
- ` }`
412
- ` # ...`
413
- `}`
414
-
415
- After making changes, remember to restart the machine: `systemctl restart nginx`.
416
-
417
- = Configuration for Multisite Network =
418
-
419
- Multisite Network mode works fine but requires adding configuration manually.
420
-
421
- Please manually paste the following code **at the beginning of .htaccess file** in the `/wp-content` directory:
422
-
423
- `# BEGIN WebP Converter`
424
- `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
425
- `<IfModule mod_rewrite.c>
426
- RewriteEngine On
427
- RewriteCond %{HTTP_ACCEPT} image/webp
428
- RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpg.webp -f
429
- RewriteRule (.+)\.jpg$ /wp-content/uploads-webpc/$1.jpg.webp [NC,T=image/webp,E=cache-control:no-cache,L]
430
- RewriteCond %{HTTP_ACCEPT} image/webp
431
- RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpeg.webp -f
432
- RewriteRule (.+)\.jpeg$ /wp-content/uploads-webpc/$1.jpeg.webp [NC,T=image/webp,E=cache-control:no-cache,L]
433
- RewriteCond %{HTTP_ACCEPT} image/webp
434
- RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.png.webp -f
435
- RewriteRule (.+)\.png$ /wp-content/uploads-webpc/$1.png.webp [NC,T=image/webp,E=cache-control:no-cache,L]
436
- </IfModule>`
437
- `# ! --- DO NOT EDIT NEXT LINE --- !`
438
- `# END WebP Converter`
439
-
440
- And the following code **at the beginning of .htaccess file** in the `/wp-content/uploads-webpc` directory:
441
-
442
- `# BEGIN WebP Converter`
443
- `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
444
- `<IfModule mod_mime.c>
445
- AddType image/webp .webp
446
- </IfModule>
447
- <IfModule mod_expires.c>
448
- ExpiresActive On
449
- ExpiresByType image/webp "access plus 1 year"
450
- </IfModule>`
451
- `# ! --- DO NOT EDIT NEXT LINE --- !`
452
- `# END WebP Converter`
453
-
454
- = Is the plugin completely free? =
455
-
456
- Yes. The plugin is completely free.
457
-
458
- However, working on plugins and technical support requires many hours of work. If you want to appreciate it, you can [provide us a coffee](https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-faq). Thanks everyone!
459
-
460
- Thank you for all the ratings and reviews.
461
-
462
- If you are satisfied with this plugin, please recommend it to your friends. Every new person using our plugin is valuable to us.
463
-
464
- This is all very important to us and allows us to do even better things for you!
465
-
466
- == Screenshots ==
467
-
468
- 1. How to start using plugin few moments?
469
- 2. Screenshot of the options panel
470
- 3. Screenshot when regenerating images
471
-
472
- == Changelog ==
473
-
474
- = 2.4.0 (2021-02-28) =
475
- * `[Fixed]` Error detection of redirects without .png as supported file extension
476
- * `[Fixed]` Pass Thru loading mode for servers not supporting `getallheaders()` function
477
- * `[Changed]` Level of error for cached redirects of images to WebP files
478
- * `[Added]` Skip re-converting images that were larger than original after converting to WebP
479
-
480
- = 2.3.0 (2021-01-31) =
481
- * `[Fixed]` Encoding paths to files
482
- * `[Fixed]` Retaining PNG transparency using Gd method
483
- * `[Added]` Cron to convert images uploaded to Media Library
484
-
485
- = 2.2.0 (2021-01-13) =
486
- * `[Added]` Support for WordPress Multisite
487
-
488
- = 2.1.3 (2020-12-28) =
489
- * `[Fixed]` Regex for Pass Thru loading mode
490
-
491
- = 2.1.2 (2020-12-27) =
492
- * `[Fixed]` Converting images using Imagick method
493
-
494
- = 2.1.1 (2020-12-21) =
495
- * `[Fixed]` Modal when deactivating plugin
496
-
497
- = 2.1.0 (2020-12-21) =
498
- * `[Changed]` Structure of conversion methods
499
- * `[Changed]` Structure of error detection methods
500
-
501
- = 2.0.1 (2020-12-16) =
502
- * `[Fixed]` Actions initiated after plugin update
503
-
504
- = 2.0.0 (2020-12-16) =
505
- * `[Removed]` Filter `webpc_uploads_path`
506
- * `[Removed]` Filter `webpc_uploads_webp`
507
- * `[Removed]` Filter `webpc_uploads_dir`
508
- * `[Removed]` Filter `webpc_uploads_root`
509
- * `[Changed]` Error messages in administration panel
510
- * `[Added]` Image loading mode: `Pass Thru` (without rewrites in .htacces files or Nginx configuration)
511
- * `[Added]` Filter `webpc_dir_name` to change default directory paths
512
- * `[Added]` Filter `webpc_site_root` to change path for root installation directory of WordPress
513
- * `[Added]` Filter `webpc_site_url` to change Site URL of WordPress
514
-
515
- = 1.6.0 (2020-12-12) =
516
- * `[Added]` Escaping functions for translated phrases
517
- * `[Added]` Error codes in error messages on plugin settings page
518
- * `[Added]` Modal when deactivating plugin
519
-
520
- = 1.5.1 (2020-11-02) =
521
- * `[Changed]` Error messages related to non-working redirects from .htaccess file
522
-
523
- = 1.5.0 (2020-10-28) =
524
- * `[Added]` Filter `webpc_files_paths` to modify paths of images to be converted
525
- * `[Added]` Filter `webpc_convert_error` to management of errors content displayed during conversion
526
- * `[Added]` Filter `webpc_convert_errors` to management of errors displayed during conversion
527
-
528
- = 1.4.6 (2020-10-23) =
529
- * `[Fixed]` Error detection of non-working redirects without .png as supported file extension
530
-
531
- = 1.4.5 (2020-10-19) =
532
- * `[Fixed]` Content for translations
533
-
534
- = 1.4.4 (2020-10-18) =
535
- * `[Changed]` Information after conversion process is completed
536
-
537
- = 1.4.3 (2020-09-30) =
538
- * `[Changed]` Directory for error detection of non-working redirects of images to WebP files
539
- * `[Changed]` Button for `Server configuration` tab
540
- * `[Added]` Information about error detection in `Server configuration` tab
541
-
542
- = 1.4.2 (2020-08-24) =
543
- * `[Fixed]` Cache-Control for redirects of images to WebP files
544
- * `[Added]` Error detection of cached redirects of images to WebP files
545
-
546
- = 1.4.1 (2020-08-19) =
547
- * `[Changed]` Error detection method on plugin settings page
548
- * `[Added]` Error detection of non-working redirects of images to WebP files
549
-
550
- = 1.4.0 (2020-08-13) =
551
- * `[Removed]` Filter `webpc_notice_url`
552
- * `[Changed]` Error messages for server requirements
553
- * `[Changed]` Loading CSS and JS files only on plugin settings page
554
- * `[Changed]` Minor changes for plugin settings page
555
- * `[Changed]` Validation of saved settings values for security
556
- * `[Added]` Blocking redirects to WebP when displaying images on other domains
557
- * `[Added]` Cron to automatically regenerate new images outside of Media Library
558
- * `[Added]` Filter `webpc_cron_interval` to change cron interval
559
- * `[Added]` Error message for incorrect plugin settings
560
- * `[Added]` Error when converting when WebP file is larger than original and has been deleted
561
- * `[Added]` Notice after plugin installation with description of first steps
562
- * `[Added]` Option to log errors while converting to debug.log file
563
- * `[Added]` Option to preserve metadata for WebP files *(available for Imagick library)*
564
- * `[Added]` Value of `ABSPATH` in `Server configuration` tab
565
-
566
- = 1.3.1 (2020-07-03) =
567
- * `[Fixed]` Text Domain for Internationalization
568
-
569
- = 1.3.0 (2020-06-12) =
570
- * `[Removed]` Ability to skip converting existing images when `Regenerate All`
571
- * `[Fixed]` Creating `/uploads-webpc` directory webpc after re-activation plugin
572
- * `[Fixed]` Error message about not supporting old PHP version
573
- * `[Fixed]` Ignoring case sensitivity when verifying image extensions
574
- * `[Changed]` Error messages when converting images
575
- * `[Changed]` New argument for filter `webpc_htaccess_mod_rewrite` and support for multiple .htaccess files
576
- * `[Added]` Converting all images from `/uploads` directory *(also other than from Media Library)*.
577
- * `[Added]` Converting images from `/plugins` directory
578
- * `[Added]` Converting images from `/themes` directory
579
- * `[Added]` Information about used filters in `Server configuration` tab
580
- * `[Added]` Option to force all images to be converted again when `Regenerate All`
581
-
582
- = 1.2.7 (2020-06-11) =
583
- * `[Changed]` Moving converted WebP files to `/uploads-webpc/uploads` directory from `/uploads-webpc` directory *(**required manual configuration change for Nginx and WordPress Multisite**)*
584
- * `[Changed]` Validation when converting images
585
-
586
- = 1.2.6 (2020-05-28) =
587
- * `[Fixed]` Removal of WebP files larger than original during upload
588
-
589
- = 1.2.5 (2020-05-10) =
590
- * `[Removed]` Link to plugin settings on Network Admin Screen for WordPress Multisite
591
- * `[Fixed]` Path in RewriteRule for WordPress Multisite
592
- * `[Changed]` Error messages in administration panel
593
- * `[Added]` Support for `disable_functions` setting for using `set_time_limit` function
594
- * `[Added]` Support for blocked function `file_get_contents`
595
-
596
- = 1.2.4 (2020-04-24) =
597
- * `[Changed]` Error messages in administration panel
598
- * `[Added]` Action `webpc_delete_paths` to delete images by paths
599
-
600
- = 1.2.3 (2020-04-15) =
601
- * `[Added]` Blocking server cache for rewrite rules
602
- * `[Added]` Detecting whether requests to images are processed by server bypassing Apache
603
-
604
- = 1.2.2 (2020-04-08) =
605
- * `[Changed]` Moving rules for modules `mod_mime` and `mod_expires` to `/uploads-webpc/.htaccess` file
606
- * `[Changed]` New argument for filter `webpc_htaccess_rules` with server path of file
607
-
608
- = 1.2.1 (2020-04-07) =
609
- * `[Removed]` Filter `webpc_option_disabled`
610
- * `[Fixed]` Converting images multiple times when uploading to Media Library
611
- * `[Added]` Action `webpc_convert_paths` to convert images by paths
612
- * `[Added]` Action `webpc_convert_attachment` to convert images by Post ID
613
-
614
- = 1.2.0 (2020-04-05) =
615
- * `[Changed]` Moving rules from .htaccess file in root directory of WordPress to `/wp-content/uploads` directory
616
- * `[Added]` Ability to disable automatic removal of WebP files larger than original
617
- * `[Added]` Error validation for a non-writable .htaccess file
618
- * `[Added]` Filter `webpc_uploads_root` to change path for root installation directory of WordPress
619
-
620
- = 1.1.2 (2020-03-03) =
621
- * `[Added]` Zero padding at end for odd-sized WebP files using `GD` library
622
-
623
- = 1.1.1 (2020-02-13) =
624
- * `[Changed]` Unknown error handling when converting images
625
- * `[Added]` Ability to skip converting existing images when `Regenerate All`
626
- * `[Added]` Button for simple checking of server configuration
627
-
628
- = 1.1.0 (2020-02-10) =
629
- * `[Fixed]` Support for WordPress installation in subdirectory
630
- * `[Fixed]` Error detecting WebP support by Imagick
631
-
632
- = 1.0.9 (2020-01-03) =
633
- * `[Added]` Limit of maximum image resolution limit using `GD` library
634
-
635
- = 1.0.8 (2019-12-19) =
636
- * `[Fixed]` File deletion for custom paths with converted WebP files
637
- * `[Changed]` Rules management in .htaccess file when activating or deactivating plugin
638
- * `[Added]` Error detection system in server configuration
639
- * `[Added]` Blocking image conversion when `GD` or `Imagick` libraries are unavailable
640
-
641
- = 1.0.7 (2019-12-17) =
642
- * `[Changed]` Rewrite rules in .htaccess file
643
- * `[Added]` Custom path support for original uploads files
644
- * `[Added]` Custom path support for saving converted WebP files
645
- * `[Added]` Filter `webpc_uploads_path` to change path for original uploads files
646
- * `[Added]` Filter `webpc_uploads_webp` to change path for saving converted WebP files
647
-
648
- = 1.0.6 (2019-11-06) =
649
- * `[Changed]` Way of generating file path _(without `ABSPATH`)_
650
- * `[Added]` Automatic deletion of converted files larger than original
651
-
652
- = 1.0.5 (2019-09-16) =
653
- * `[Added]` Information on available FAQ
654
-
655
- = 1.0.4 (2019-07-11) =
656
- * `[Changed]` Limits of maximum execution time
657
-
658
- = 1.0.3 (2019-06-26) =
659
- * `[Added]` Additional security rules
660
-
661
- = 1.0.2 (2019-06-25) =
662
- * `[Changed]` Error messages
663
- * `[Added]` Tab in Settings page about server configuration
664
-
665
- = 1.0.1 (2019-06-23) =
666
- * `[Changed]` Securing access to REST API
667
- * `[Added]` Error handler for undefined `GD` extension
668
-
669
- = 1.0.0 (2019-06-16) =
670
- * The first stable release
671
-
672
- == Upgrade Notice ==
673
-
674
- None.
1
+ === WebP Converter for Media ===
2
+ Contributors: mateuszgbiorczyk
3
+ Donate link: https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-donate
4
+ Tags: convert webp, webp, optimize images, images, webp converter
5
+ Requires at least: 4.9
6
+ Tested up to: 5.7
7
+ Requires PHP: 7.0
8
+ Stable tag: trunk
9
+ License: GPLv2 or later
10
+ License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
+
12
+ Speed up your website by serving WebP images instead of standard formats JPEG, PNG and GIF.
13
+
14
+ == Description ==
15
+
16
+ Speed up your website by serving WebP images. By replacing files in standard JPEG, PNG and GIF formats with WebP format, you can save over a half of the page weight without losing quality.
17
+
18
+ When installing a plugin you do not have to do anything more. Your current images will be converted into a new format. Users will automatically receive new, much lighter images than the original ones.
19
+
20
+ As of today, over 90% of users use browsers that support the WebP format. The loading time of your website depends to a large extent on its weight. Now you can speed up it in a few seconds without much effort!
21
+
22
+ This will be a profit both for your users who will not have to download so much data, but also for a server that will be less loaded. Remember that a better optimized website also affects your Google ranking.
23
+
24
+ #### Support for additional directories
25
+
26
+ Now you can also convert files not only from `/uploads` directory but also from `/plugins` and `/themes` directories. This allows full integration with the WebP format!
27
+
28
+ #### How does this work?
29
+
30
+ - By adding images to your Media Library, they are automatically converted and saved in a separate directory.
31
+ - If you have just installed the plugin, you can convert all existing images with one click.
32
+ - As WebP you will see all the images added to the Media Library and other selected directories.
33
+ - When the browser tries to download an image file, the server verifies if it supports `image/webp` files and if the file exists.
34
+ - If everything is OK, instead of the original image, the browser will receive its equivalent in WebP format.
35
+ - In default loading mode **the plugin does not change image URLs, so there are no problems with saving the HTML code of website to the cache and time of its generation does not increase.** It does not matter if the image display as an `img` HTML tag or you use `background-image`. It works always!
36
+ - The name of the loaded image does not contain the WebP extension. Only the source of the loaded file changes to a WebP file. As a result, you always have one URL to a file. Regardless of whether the browser supports WebP or not.
37
+ - Image URLs are modified using the module `mod_rewrite` on the server, i.e. the same, and thanks to this we can use friendly links in WordPress. Additionally, the MIME type of the sent file is modified to `image/webp`.
38
+ - In case rewriting by rules from .htaccess file is blocked, a mode is available which loads images via PHP file. Then image URLs are changed, but the logic of operation is the same as in the case of the default mode.
39
+ - The final result is that your users download less than half of the data, and the website itself loads faster!
40
+
41
+ #### WebP images are the future!
42
+
43
+ Raise your website to a new level now! Install the plugin and enjoy the website that loads faster. Surely you and your users will appreciate it.
44
+
45
+ #### Support to the development of plugin
46
+
47
+ We spend hours working on the development of this plugin. Technical support also requires a lot of time, but we do it because we want to offer you the best plugin. We enjoy every new plugin installation.
48
+
49
+ If you would like to appreciate it, you can [provide us a coffee](https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-content). **If every user bought at least one, we could work on the plugin 24 hours a day!**
50
+
51
+ #### Please also read the FAQ below. Thank you for being with us!
52
+
53
+ == Installation ==
54
+
55
+ 1. Upload the plugin files to `/wp-content/plugins/webp-converter-for-media` directory, or install plugin through the WordPress plugins screen directly.
56
+ 2. Activate plugin through `Plugins` screen in WordPress Admin Panel.
57
+ 3. Use `Settings -> Settings -> WebP Converter` screen to configure the plugin.
58
+ 4. Click on the button `Regenerate All`.
59
+ 5. Check if everything works fine.
60
+
61
+ That's all! Your website is already loading faster!
62
+
63
+ == Frequently Asked Questions ==
64
+
65
+ = How to get technical support? (before you ask for help) =
66
+
67
+ Please always adding your thread, **read all other questions in the FAQ of plugin and other threads in support forum first**. Perhaps someone had a similar problem and it has been resolved.
68
+
69
+ When adding a thread, follow these steps and reply to each of them:
70
+
71
+ **1.** Do you have any error on the plugin settings page? Please read [this thread](https://wordpress.org/support/topic/server-configuration-error-what-to-do/) if you have any errors.
72
+
73
+ **2.** URL of your website. If your site is not publicly available, add it to test environment.
74
+
75
+ **3.** Configuration of your server *(link to it can be found on the settings page of plugin in the section **"We are waiting for your message"**)* - please take a screenshot of the ENTIRE page and send it to me.
76
+
77
+ **4.** Settings of plugin - please take a screenshot of the ENTIRE page and send it to me.
78
+
79
+ **5.** Please do the test, which is described in the FAQ in question `How to check if plugin works?`. Please send a screenshot of Devtools with test results.
80
+
81
+ **6.** Do you use any plugin filters or actions from this FAQ? If so, list them all.
82
+
83
+ **7.** What plugin version are you using? If it is not the latest then update and check everything again.
84
+
85
+ **8.** A list of all the plugins you use. Have you tried checking the plugin operation by turning off all others and activating the default theme? If not, please try whenever possible. **This is very important because other plugins or themes can cause problems.** Therefore, we recommend disabling all necessary plugins and enabling the default theme.
86
+
87
+ Please remember to include the answers for all questions by adding a thread. It is much easier and accelerate the solution of your problem.
88
+
89
+ = Error on plugin settings screen? =
90
+
91
+ If you have an error on the plugin settings screen, first of all please read it carefully. They are displayed when there is a problem with the configuration of your server or website.
92
+
93
+ The messages are designed to reduce the number of support requests that are repeated. It saves your and our time. Please read [this thread](https://wordpress.org/support/topic/server-configuration-error-what-to-do/) for more information.
94
+
95
+ = Server configuration error on Cloudflare =
96
+
97
+ For Cloudflare servers, a recurring problem is the error code **rewrites_cached**. To solve this problem, you need to disable the cache for the website from the server.
98
+
99
+ Please follow the steps below:
100
+ - Enter Cloudflare management panel and then to **Page Rules** Tab.
101
+ - Click **Create page rule** button.
102
+ - Enter your domain name.
103
+ - Choose **Cache Level** option, set **Bypass** value and click **Save** button.
104
+ - Click **Save and Deploy** button.
105
+
106
+ = Error while converting? =
107
+
108
+ You can get several types of errors when converting. First of all, carefully read their content. For the most part, you can solve this problem yourself. Try to do this or contact the server administrator.
109
+
110
+ If you get an error: `File "%s" does not exist. Please check file path.` means that the [file_exists()](https://www.php.net/manual/en/function.file-exists.php) function in PHP returned `false` using the file path given in the error message. Check this path and make sure it is correct.
111
+
112
+ If you get an error: `File "%s" is unreadable. Please check file permissions.` means that the [is_readable()](https://www.php.net/manual/en/function.is-readable.php) function in PHP returned `false` using the file path given in the error message. Check the permissions for the file and the directory in which the file is located.
113
+
114
+ If you get an error: `"%s" is not a valid image file.` means that the file is damaged in some way. Download the file to disk, save it again using any graphics program and add again to the page. If the error applies to individual images then you can ignore it - just the original images will load, not WebP.
115
+
116
+ If you get an error: `"%s" converted to WebP is larger than original and has been deleted.` means the original image weighed less than WebP. This happens when images have been compressed before. Disable the *"Automatic removal of WebP files larger than original"* option in plugin settings to force always using WebP.
117
+
118
+ In the case of the above problems, **contacting the support forum will be useless**. Unfortunately, we are unable to help you if your files are damaged. You have to fix it yourself. If you have previously used other tools that changed the original files and damaged them, you will do nothing more.
119
+
120
+ Remember that it happens that other plugins can cause problems with accessing files or the REST API. Please try to disable all other plugins and set the default theme to make sure that it is not one of them that causes these types of problems.
121
+
122
+ = What are requirements of plugin? =
123
+
124
+ Practically every hosting meets these requirements. You must use PHP at least 7.0 and have the `GD` or `Imagick` extension installed. **The extension must support `WebP format`.** If you have an error saying that the GD or Imagick library are not installed, but you have it installed then they are probably incorrectly configured and do not have WebP support.
125
+
126
+ They are required native PHP extensions, used among others by WordPress to generate thumbnails. Your server must also have the modules `mod_mime`, `mod_rewrite` and `mod_expires` enabled.
127
+
128
+ An example of the correct server configuration can be found [here](https://gbiorczyk.pl/webp-converter/serverinfo.png). Link to your current configuration can be found in the administration panel, on the management plugin page in the section **"We are waiting for your message"** *(or using the URL path: `/wp-admin/options-general.php?page=webpc_admin_page&action=server`)*.
129
+
130
+ **Note the items marked in red.** If the values marked in red do not appear in your case, it means that your server does not meet the technical requirements. Pay attention to the **WebP Support** value for the GD library and **WEBP in the list of supported extensions** for the Imagick library.
131
+
132
+ In a situation where your server does not meet the technical requirements, please contact your server Administrator. We are not able to help you. Please do not contact us about this matter, because this is a server configuration problem, not a plugin.
133
+
134
+ Also REST API must be enabled and work without additional restrictions. If you have a problem with it, please contact the Developer who created your website. He should easily find the issue with the REST API not working.
135
+
136
+ = How to check if plugin works? =
137
+
138
+ When you have installed plugin and converted all images, follow these steps:
139
+
140
+ 1. Run `Google Chrome` and enable `Dev Tools` *(F12)*.
141
+ 2. Go to the `Network` tab and select filtering for `Img` *(Images)*.
142
+ 3. Refresh your website page.
143
+ 4. Check list of loaded images. Note `Type` column.
144
+ 5. If value of `webp` is there, then everything works fine.
145
+ 6. Remember that this plugin does not change URLs. This means that e.g. link will have path to .jpg file, but `.jpg.webp file will be loaded instead of original .jpg`.
146
+ 7. In addition, you can check weight of website before and after using plugin. The difference will be huge!
147
+ 8. More information: [here](https://gbiorczyk.pl/webp-converter/check-devtools.png)
148
+
149
+ Please remember that in default loading mode *(via .htaccess)* URLs will remain unchanged. When you open the image in a new tab or look at its URL, you'll see the original URL. When you try to save the image to disk *(e.g. by clicking Save as...)* the original image will be saved.
150
+
151
+ WebP is only used when loading a image on a website. In default loading mode *(via .htaccess)* it is done by the rules from the .htaccess file, on the server side, without the visible URL change to the image. Yes, it can be called magic :)
152
+
153
+ That is why the plugin should be tested in Dev Tools. If the Type of file is `WebP`, then everything is working properly. You can also turn off the plugin for a moment and check the weight of your website, then turn it on and test again. The difference should be visible.
154
+
155
+ The operation of the plugin for non-advanced users may sometimes be less understood, but everything is fine. Thanks to this, regardless of whether your browser supports WebP or not, everything works without problems.
156
+
157
+ Only images from the `/uploads` directory are automatically converted. If you use other plugins that also save images in the `/uploads` directory then this may not work. Therefore, check the plugin settings and try converting all images again.
158
+
159
+ = Why are some images not in WebP? =
160
+
161
+ If the converted image in WebP format is larger than the original, the browser will use the original file. This converted file will be deleted. Therefore, you can also see files other than WebP on the list. When this happens, you will receive information in debug.log.
162
+
163
+ When such a situation occurs, a file in `.webp.deleted` format will be created. This avoids re-converting images that were larger than original after converting to WebP. If the option of forced conversion of all images is checked, this image will also be re-converted.
164
+
165
+ If you want to force the use of WebP files, uncheck the `Automatic removal of WebP files larger than original` option in the plugin settings. Then click on the `Regenerate All` button to convert all images again.
166
+
167
+ Remember that this plugin supports images from the `/wp-content` directory, e.g. files downloaded from the Media Library. Redirections will not work if your images are downloaded from another domain, i.e. from an external service.
168
+
169
+ When checking the operation of the plugin, e.g. in Dev Tools, pay attention to the path from which the files are downloaded and which directories you have enabled in the settings of plugin.
170
+
171
+ = How to change path to uploads? =
172
+
173
+ This is possible using the following types of filters to change default paths. It is a solution for advanced users. If you are not, please skip this question.
174
+
175
+ Path to the root installation directory of WordPress *(`ABSPATH` by default)*:
176
+
177
+ `add_filter( 'webpc_site_root', function( $path ) {
178
+ return ABSPATH;
179
+ } );`
180
+
181
+ Path to `/uploads` directory *(relative to the root directory)*:
182
+
183
+ `add_filter( 'webpc_dir_name', function( $path, $directory ) {
184
+ if ( $directory !== 'uploads' ) {
185
+ return $path;
186
+ }
187
+ return 'wp-content/uploads';
188
+ }, 10, 2 );`
189
+
190
+ Directory path with converted WebP files *(relative to the root directory)*:
191
+
192
+ `add_filter( 'webpc_dir_name', function( $path, $directory ) {
193
+ if ( $directory !== 'webp' ) {
194
+ return $path;
195
+ }
196
+ return 'wp-content/uploads-webpc';
197
+ }, 10, 2 );`
198
+
199
+ **Note that the `/uploads-webpc` directory must be at the same nesting level as the `/uploads`, `/plugins` and `/themes` directories.**
200
+
201
+ Prefix in URL of `/wp-content/` directory or equivalent *(used in .htaccess)*:
202
+
203
+ `add_filter( 'webpc_uploads_prefix', function( $prefix ) {
204
+ return '/';
205
+ } );`
206
+
207
+ For the following sample custom WordPress structure:
208
+
209
+ `...
210
+ ├── web
211
+ ...
212
+ ├── app
213
+ │ ├── mu-plugins
214
+ │ ├── plugins
215
+ │ ├── themes
216
+ │ └── uploads
217
+ ├── wp-config.php
218
+ ...`
219
+
220
+ Use the following filters:
221
+
222
+ `add_filter( 'webpc_site_root', function( $path ) {
223
+ return 'C:/WAMP/www/project/webp'; // your valid path to root
224
+ } );
225
+ add_filter( 'webpc_dir_name', function( $path, $directory ) {
226
+ if ( $directory !== 'uploads' ) {
227
+ return $path;
228
+ }
229
+ return 'app/uploads';
230
+ }, 10, 2 );
231
+ add_filter( 'webpc_dir_name', function( $path, $directory ) {
232
+ if ( $directory !== 'webp' ) {
233
+ return $path;
234
+ }
235
+ return 'app/uploads-webpc';
236
+ }, 10, 2 );`
237
+ `add_filter( 'webpc_uploads_prefix', function( $prefix ) {
238
+ return '/';
239
+ } );`
240
+
241
+ After setting the filters go to `Settings -> WebP Converter` in the admin panel and click the `Save Changes` button. `.htaccess` files with appropriate rules should be created in the directories `/uploads` and `/uploads-webpc`.
242
+
243
+ = How to run manually conversion? =
244
+
245
+ By default, all images are converted when you click on the `Regenerate All` button. In addition, conversion is automatic when you add new files to your Media Library.
246
+
247
+ Remember that our plugin takes into account images generated by WordPress. There are many plugins that generate, for example, images of a different size or in a different version.
248
+
249
+ If you would like to integrate with your plugin, which generates images by yourself, you can do it. Our plugin provides the possibility of this type of integration. This works for all images in the `/wp-content` directory.
250
+
251
+ It is a solution for advanced users. If you would like to integrate with another plugin, it's best to contact the author of that plugin and give him information about the actions available in our plugin. This will help you find a solution faster.
252
+
253
+ You can automatically run the option to regenerate all new images. This is useful when you use external plugins that generate images themselves. To do this, use the following code:
254
+
255
+ `do_action( 'webpc_regenerate_all', $paths );`
256
+
257
+ Below is an example of how to use this action to automatically regenerate images after changing the theme:
258
+
259
+ `add_action('init', function() {
260
+ do_action( 'webpc_regenerate_all' );
261
+ });`
262
+
263
+ To manually start converting selected files, you can use the action to which you will pass an array with a list of paths *(they must be absolute server paths)*:
264
+
265
+ `do_action( 'webpc_convert_paths', $paths );`
266
+
267
+ An alternative method is to manually start converting the selected attachment by passing the post ID from the Media Library. Remember to run this action after registering all image sizes *(i.e. after running the `add_image_size` function)*:
268
+
269
+ `do_action( 'webpc_convert_attachment', $post_id );`
270
+
271
+ In addition, you can edit the list of files that will be converted. For example, to add some to the exceptions. To do this, use the following filter, which by default returns a list of all paths:
272
+
273
+ `add_filter( 'webpc_files_paths', function( $paths, $skip_exists ) {
274
+ return $paths;
275
+ }, 10, 2 );`
276
+
277
+ Argument `$paths` is array of absolute server paths and `$skip_exists` means whether to skip converted images.
278
+
279
+ You can also modify the list of image paths for an attachment, e.g. to exclude one image size. To do this, use the following filter:
280
+
281
+ `add_filter( 'webpc_attachment_paths', function( $paths, $attachment_id ) {
282
+ return $paths;
283
+ }, 10, 2 );`
284
+
285
+ Argument `$paths` is array of absolute server paths and `$attachment_id` is the post ID of attachment, added to the Media Library.
286
+
287
+ To delete manually converted files, use the following action, providing as an argument an array of absolute server paths to the files *(this will delete manually converted files)*:
288
+
289
+ `do_action( 'webpc_delete_paths', $paths );`
290
+
291
+ = How to change .htaccess rules? =
292
+
293
+ Manually editing the rules in the .htaccess file is a task only for experienced developers. Remember that the wrong rules can cause your website to stop working.
294
+
295
+ Below is a list of filters that allow you to modify all rules. Remember that it's best to use your own rule set rather than edit parts of exists. This will ensure greater failure-free after plugin update.
296
+
297
+ Returning an empty string will delete these rules the next time you save the plugin settings. You must do this after each filter edit.
298
+
299
+ Rules for redirects: *(returns rules for `mod_rewrite` module)*:
300
+
301
+ `add_filter( 'webpc_htaccess_mod_rewrite', function( $rules, $path ) {
302
+ return '';
303
+ }, 10, 2 );`
304
+
305
+ Argument `$path` is absolute server path for `.htaccess` file *(`/wp-content/.htaccess` or `/wp-content/uploads/.htaccess`)*.
306
+
307
+ Rules for `image/webp` MIME type: *(returns rules for `mod_mime` module)*:
308
+
309
+ `add_filter( 'webpc_htaccess_mod_mime', function( $rules ) {
310
+ return '';
311
+ } );`
312
+
313
+ Rules for Browser Caching: *(returns rules for `mod_expires` module)*:
314
+
315
+ `add_filter( 'webpc_htaccess_mod_expires', function( $rules ) {
316
+ return '';
317
+ } );`
318
+
319
+ All rules from the files `/wp-content/.htaccess`, `/wp-content/uploads/.htaccess` and `/wp-content/uploads-webpc/.htaccess`: *(returns rules for modules: `mod_rewrite`, `mod_mime` and `mod_expires`)*:
320
+
321
+ `add_filter( 'webpc_htaccess_rules', function( $rules, $path ) {
322
+ return '';
323
+ }, 10, 2 );`
324
+
325
+ Argument `$path` is absolute server path for `.htaccess` file.
326
+
327
+ = Does plugin support CDN? =
328
+
329
+ Unfortunately not. This is due to the logic of the plugin's operation. Plugins that enable integration with the CDN servers modify the HTML of the website, changing URLs for media files. This plugin does not modify URLs. Replacing URLs in the HTML code is not an optimal solution.
330
+
331
+ The main problem when changing URLs is cache. When we modify the image URL for WebP supporting browser, then use the browser without WebP support, it will still have the URL address of an image in .webp format, because it will be in the cache.
332
+
333
+ While in the case of the `img` tag you can solve this problem, in the case of `background-image` it is possible. We wanted full support so that all images would be supported - no matter how they are displayed on the website.
334
+
335
+ Therefore in this plugin for browsers supporting the WebP format, only the source of the file is replaced by using the `mod_rewrite` module on the server. The URL for image remains the same. This solves the whole problem, but it is impossible to do when the files are stored on the CDN server.
336
+
337
+ If you are using a CDN server, find one that automatically converts images to WebP format and properly sends the correct image format to the browser.
338
+
339
+ = Configuration for Apache =
340
+
341
+ In the case of Apache, when saving the settings, .htaccess files will be generated automatically in the following locations:
342
+ - `/wp-content/.htaccess`
343
+ - `/wp-content/uploads/.htaccess`
344
+ - `/wp-content/uploads-webpc/.htaccess`
345
+
346
+ If these files are missing or empty, try disabling and re-enabling the plugin or saving the plugin settings again. Also check the write permissions of the directories where these files are located.
347
+
348
+ If your server is a combination of Apache and Nginx, remember that the image files must be supported by Apache. Only then will the redirections in the .htaccess file work properly. Alternatively, you can use the configuration for Nginx.
349
+
350
+ = Configuration for Nginx =
351
+
352
+ Please edit the configuration file:
353
+ - `/etc/nginx/mime.types`
354
+
355
+ and add this code line:
356
+
357
+ `types {`
358
+ ` # ...`
359
+ ` image/webp webp;`
360
+ `}`
361
+
362
+ Then find the configuration file in one of the paths *(remember to select configuration file used by your vhost)*:
363
+ - `/etc/nginx/sites-enabled/`
364
+ - `/etc/nginx/conf.d/`
365
+
366
+ and add below code in this file *(add these lines to very beginning of file if possible - if they will be at the bottom, other rules may block the rules for WebP from working)*:
367
+
368
+ `server {`
369
+ ` location ~ /wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif)$ {`
370
+ ` if ($http_accept !~* "image/webp") {`
371
+ ` break;`
372
+ ` }`
373
+ ` add_header Vary Accept;`
374
+ ` expires 365d;`
375
+ ` try_files /wp-content/uploads-webpc/$path.$ext.webp $uri =404;`
376
+ ` }`
377
+ ` # ...`
378
+ `}`
379
+
380
+ After making changes, remember to restart the machine: `systemctl restart nginx`.
381
+
382
+ = Configuration for Multisite Network =
383
+
384
+ Multisite Network mode works fine but requires adding configuration manually.
385
+
386
+ Please manually paste the following code **at the beginning of .htaccess file** in the `/wp-content` directory:
387
+
388
+ `# BEGIN WebP Converter`
389
+ `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
390
+ `<IfModule mod_rewrite.c>
391
+ RewriteEngine On
392
+ RewriteCond %{HTTP_ACCEPT} image/webp
393
+ RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpg.webp -f
394
+ RewriteRule (.+)\.jpg$ /wp-content/uploads-webpc/$1.jpg.webp [NC,T=image/webp,E=cache-control:no-cache,L]
395
+ RewriteCond %{HTTP_ACCEPT} image/webp
396
+ RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpeg.webp -f
397
+ RewriteRule (.+)\.jpeg$ /wp-content/uploads-webpc/$1.jpeg.webp [NC,T=image/webp,E=cache-control:no-cache,L]
398
+ RewriteCond %{HTTP_ACCEPT} image/webp
399
+ RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.png.webp -f
400
+ RewriteRule (.+)\.png$ /wp-content/uploads-webpc/$1.png.webp [NC,T=image/webp,E=cache-control:no-cache,L]
401
+ </IfModule>`
402
+ `# ! --- DO NOT EDIT NEXT LINE --- !`
403
+ `# END WebP Converter`
404
+
405
+ And the following code **at the beginning of .htaccess file** in the `/wp-content/uploads-webpc` directory:
406
+
407
+ `# BEGIN WebP Converter`
408
+ `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
409
+ `<IfModule mod_mime.c>
410
+ AddType image/webp .webp
411
+ </IfModule>
412
+ <IfModule mod_expires.c>
413
+ ExpiresActive On
414
+ ExpiresByType image/webp "access plus 1 year"
415
+ </IfModule>`
416
+ `# ! --- DO NOT EDIT NEXT LINE --- !`
417
+ `# END WebP Converter`
418
+
419
+ = Is the plugin completely free? =
420
+
421
+ Yes. The plugin is completely free.
422
+
423
+ However, working on plugins and technical support requires many hours of work. If you want to appreciate it, you can [provide us a coffee](https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=readme-faq). Thanks everyone!
424
+
425
+ Thank you for all the ratings and reviews.
426
+
427
+ If you are satisfied with this plugin, please recommend it to your friends. Every new person using our plugin is valuable to us.
428
+
429
+ This is all very important to us and allows us to do even better things for you!
430
+
431
+ == Screenshots ==
432
+
433
+ 1. How to start using plugin few moments?
434
+ 2. Screenshot of the options panel
435
+ 3. Screenshot when regenerating images
436
+
437
+ == Changelog ==
438
+
439
+ = 3.0.0 (2021-05-02) =
440
+ * `[Removed]` Filter `webpc_get_values`
441
+ * `[Removed]` Filter `webpc_get_options`
442
+ * `[Removed]` Filter `webpc_get_methods`
443
+ * `[Changed]` Error messages on plugin settings page
444
+ * `[Added]` Conversion of images to multiple output formats
445
+ * `[Added]` Compatibility with NextGEN Gallery plugin
446
+ * `[Added]` Data displayed on "Server configuration" tab on plugin settings page
447
+ * `[Added]` Changes to improve performance of plugin
448
+ * `[Added]` Changes to improve security of plugin
449
+
450
+ = 2.4.0 (2021-02-28) =
451
+ * `[Fixed]` Error detection of redirects without .png as supported file extension
452
+ * `[Fixed]` Pass Thru loading mode for servers not supporting `getallheaders()` function
453
+ * `[Changed]` Level of error for cached redirects of images to WebP files
454
+ * `[Added]` Skip re-converting images that were larger than original after converting to WebP
455
+
456
+ = 2.3.0 (2021-01-31) =
457
+ * `[Fixed]` Encoding paths to files
458
+ * `[Fixed]` Retaining PNG transparency using Gd method
459
+ * `[Added]` Cron to convert images uploaded to Media Library
460
+
461
+ = 2.2.0 (2021-01-13) =
462
+ * `[Added]` Support for WordPress Multisite
463
+
464
+ = 2.1.3 (2020-12-28) =
465
+ * `[Fixed]` Regex for Pass Thru loading mode
466
+
467
+ = 2.1.2 (2020-12-27) =
468
+ * `[Fixed]` Converting images using Imagick method
469
+
470
+ = 2.1.1 (2020-12-21) =
471
+ * `[Fixed]` Modal when deactivating plugin
472
+
473
+ = 2.1.0 (2020-12-21) =
474
+ * `[Changed]` Structure of conversion methods
475
+ * `[Changed]` Structure of error detection methods
476
+
477
+ = 2.0.1 (2020-12-16) =
478
+ * `[Fixed]` Actions initiated after plugin update
479
+
480
+ = 2.0.0 (2020-12-16) =
481
+ * `[Removed]` Filter `webpc_uploads_path`
482
+ * `[Removed]` Filter `webpc_uploads_webp`
483
+ * `[Removed]` Filter `webpc_uploads_dir`
484
+ * `[Removed]` Filter `webpc_uploads_root`
485
+ * `[Changed]` Error messages in administration panel
486
+ * `[Added]` Image loading mode: `Pass Thru` (without rewrites in .htacces files or Nginx configuration)
487
+ * `[Added]` Filter `webpc_dir_name` to change default directory paths
488
+ * `[Added]` Filter `webpc_site_root` to change path for root installation directory of WordPress
489
+ * `[Added]` Filter `webpc_site_url` to change Site URL of WordPress
490
+
491
+ = 1.6.0 (2020-12-12) =
492
+ * `[Added]` Escaping functions for translated phrases
493
+ * `[Added]` Error codes in error messages on plugin settings page
494
+ * `[Added]` Modal when deactivating plugin
495
+
496
+ = 1.5.1 (2020-11-02) =
497
+ * `[Changed]` Error messages related to non-working redirects from .htaccess file
498
+
499
+ = 1.5.0 (2020-10-28) =
500
+ * `[Added]` Filter `webpc_files_paths` to modify paths of images to be converted
501
+ * `[Added]` Filter `webpc_convert_error` to management of errors content displayed during conversion
502
+ * `[Added]` Filter `webpc_convert_errors` to management of errors displayed during conversion
503
+
504
+ = 1.4.6 (2020-10-23) =
505
+ * `[Fixed]` Error detection of non-working redirects without .png as supported file extension
506
+
507
+ = 1.4.5 (2020-10-19) =
508
+ * `[Fixed]` Content for translations
509
+
510
+ = 1.4.4 (2020-10-18) =
511
+ * `[Changed]` Information after conversion process is completed
512
+
513
+ = 1.4.3 (2020-09-30) =
514
+ * `[Changed]` Directory for error detection of non-working redirects of images to WebP files
515
+ * `[Changed]` Button for `Server configuration` tab
516
+ * `[Added]` Information about error detection in `Server configuration` tab
517
+
518
+ = 1.4.2 (2020-08-24) =
519
+ * `[Fixed]` Cache-Control for redirects of images to WebP files
520
+ * `[Added]` Error detection of cached redirects of images to WebP files
521
+
522
+ = 1.4.1 (2020-08-19) =
523
+ * `[Changed]` Error detection method on plugin settings page
524
+ * `[Added]` Error detection of non-working redirects of images to WebP files
525
+
526
+ = 1.4.0 (2020-08-13) =
527
+ * `[Removed]` Filter `webpc_notice_url`
528
+ * `[Changed]` Error messages for server requirements
529
+ * `[Changed]` Loading CSS and JS files only on plugin settings page
530
+ * `[Changed]` Minor changes for plugin settings page
531
+ * `[Changed]` Validation of saved settings values for security
532
+ * `[Added]` Blocking redirects to WebP when displaying images on other domains
533
+ * `[Added]` Cron to automatically regenerate new images outside of Media Library
534
+ * `[Added]` Filter `webpc_cron_interval` to change cron interval
535
+ * `[Added]` Error message for incorrect plugin settings
536
+ * `[Added]` Error when converting when WebP file is larger than original and has been deleted
537
+ * `[Added]` Notice after plugin installation with description of first steps
538
+ * `[Added]` Option to log errors while converting to debug.log file
539
+ * `[Added]` Option to preserve metadata for WebP files *(available for Imagick library)*
540
+ * `[Added]` Value of `ABSPATH` in `Server configuration` tab
541
+
542
+ = 1.3.1 (2020-07-03) =
543
+ * `[Fixed]` Text Domain for Internationalization
544
+
545
+ = 1.3.0 (2020-06-12) =
546
+ * `[Removed]` Ability to skip converting existing images when `Regenerate All`
547
+ * `[Fixed]` Creating `/uploads-webpc` directory webpc after re-activation plugin
548
+ * `[Fixed]` Error message about not supporting old PHP version
549
+ * `[Fixed]` Ignoring case sensitivity when verifying image extensions
550
+ * `[Changed]` Error messages when converting images
551
+ * `[Changed]` New argument for filter `webpc_htaccess_mod_rewrite` and support for multiple .htaccess files
552
+ * `[Added]` Converting all images from `/uploads` directory *(also other than from Media Library)*.
553
+ * `[Added]` Converting images from `/plugins` directory
554
+ * `[Added]` Converting images from `/themes` directory
555
+ * `[Added]` Information about used filters in `Server configuration` tab
556
+ * `[Added]` Option to force all images to be converted again when `Regenerate All`
557
+
558
+ = 1.2.7 (2020-06-11) =
559
+ * `[Changed]` Moving converted WebP files to `/uploads-webpc/uploads` directory from `/uploads-webpc` directory *(**required manual configuration change for Nginx and WordPress Multisite**)*
560
+ * `[Changed]` Validation when converting images
561
+
562
+ = 1.2.6 (2020-05-28) =
563
+ * `[Fixed]` Removal of WebP files larger than original during upload
564
+
565
+ = 1.2.5 (2020-05-10) =
566
+ * `[Removed]` Link to plugin settings on Network Admin Screen for WordPress Multisite
567
+ * `[Fixed]` Path in RewriteRule for WordPress Multisite
568
+ * `[Changed]` Error messages in administration panel
569
+ * `[Added]` Support for `disable_functions` setting for using `set_time_limit` function
570
+ * `[Added]` Support for blocked function `file_get_contents`
571
+
572
+ = 1.2.4 (2020-04-24) =
573
+ * `[Changed]` Error messages in administration panel
574
+ * `[Added]` Action `webpc_delete_paths` to delete images by paths
575
+
576
+ = 1.2.3 (2020-04-15) =
577
+ * `[Added]` Blocking server cache for rewrite rules
578
+ * `[Added]` Detecting whether requests to images are processed by server bypassing Apache
579
+
580
+ = 1.2.2 (2020-04-08) =
581
+ * `[Changed]` Moving rules for modules `mod_mime` and `mod_expires` to `/uploads-webpc/.htaccess` file
582
+ * `[Changed]` New argument for filter `webpc_htaccess_rules` with server path of file
583
+
584
+ = 1.2.1 (2020-04-07) =
585
+ * `[Removed]` Filter `webpc_option_disabled`
586
+ * `[Fixed]` Converting images multiple times when uploading to Media Library
587
+ * `[Added]` Action `webpc_convert_paths` to convert images by paths
588
+ * `[Added]` Action `webpc_convert_attachment` to convert images by Post ID
589
+
590
+ = 1.2.0 (2020-04-05) =
591
+ * `[Changed]` Moving rules from .htaccess file in root directory of WordPress to `/wp-content/uploads` directory
592
+ * `[Added]` Ability to disable automatic removal of WebP files larger than original
593
+ * `[Added]` Error validation for a non-writable .htaccess file
594
+ * `[Added]` Filter `webpc_uploads_root` to change path for root installation directory of WordPress
595
+
596
+ = 1.1.2 (2020-03-03) =
597
+ * `[Added]` Zero padding at end for odd-sized WebP files using `GD` library
598
+
599
+ = 1.1.1 (2020-02-13) =
600
+ * `[Changed]` Unknown error handling when converting images
601
+ * `[Added]` Ability to skip converting existing images when `Regenerate All`
602
+ * `[Added]` Button for simple checking of server configuration
603
+
604
+ = 1.1.0 (2020-02-10) =
605
+ * `[Fixed]` Support for WordPress installation in subdirectory
606
+ * `[Fixed]` Error detecting WebP support by Imagick
607
+
608
+ = 1.0.9 (2020-01-03) =
609
+ * `[Added]` Limit of maximum image resolution limit using `GD` library
610
+
611
+ = 1.0.8 (2019-12-19) =
612
+ * `[Fixed]` File deletion for custom paths with converted WebP files
613
+ * `[Changed]` Rules management in .htaccess file when activating or deactivating plugin
614
+ * `[Added]` Error detection system in server configuration
615
+ * `[Added]` Blocking image conversion when `GD` or `Imagick` libraries are unavailable
616
+
617
+ = 1.0.7 (2019-12-17) =
618
+ * `[Changed]` Rewrite rules in .htaccess file
619
+ * `[Added]` Custom path support for original uploads files
620
+ * `[Added]` Custom path support for saving converted WebP files
621
+ * `[Added]` Filter `webpc_uploads_path` to change path for original uploads files
622
+ * `[Added]` Filter `webpc_uploads_webp` to change path for saving converted WebP files
623
+
624
+ = 1.0.6 (2019-11-06) =
625
+ * `[Changed]` Way of generating file path _(without `ABSPATH`)_
626
+ * `[Added]` Automatic deletion of converted files larger than original
627
+
628
+ = 1.0.5 (2019-09-16) =
629
+ * `[Added]` Information on available FAQ
630
+
631
+ = 1.0.4 (2019-07-11) =
632
+ * `[Changed]` Limits of maximum execution time
633
+
634
+ = 1.0.3 (2019-06-26) =
635
+ * `[Added]` Additional security rules
636
+
637
+ = 1.0.2 (2019-06-25) =
638
+ * `[Changed]` Error messages
639
+ * `[Added]` Tab in Settings page about server configuration
640
+
641
+ = 1.0.1 (2019-06-23) =
642
+ * `[Changed]` Securing access to REST API
643
+ * `[Added]` Error handler for undefined `GD` extension
644
+
645
+ = 1.0.0 (2019-06-16) =
646
+ * The first stable release
647
+
648
+ == Upgrade Notice ==
649
+
650
+ None.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/errors/bypassing-apache.php DELETED
@@ -1,15 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('Requests to images are processed by your server bypassing Apache. When loading images, rules from the .htaccess file are not executed. Occasionally, this only applies to known file extensions: .jpg, .png, etc. and when e.g. .png2 extension is loaded, then the redirections from the .htaccess file work, because the server does not understand this format and does not treat it as image files. Check the redirects for %s.png file%s %s(for which the redirection does not work)%s and for %s.png2 file%s %s(for which the redirection works correctly)%s. %sChange the server settings to stop ignoring the rules from the .htaccess file. Please contact your server administrator.', 'webp-converter-for-media'),
4
- '<a href="' . WEBPC_URL . 'public/img/debug/icon-before.png" target="_blank">',
5
- '</a>',
6
- '<em>',
7
- '</em>',
8
- '<a href="' . WEBPC_URL . 'public/img/debug/icon-before.png2" target="_blank">',
9
- '</a>',
10
- '<em>',
11
- '</em>',
12
- '<br><br>'
13
- )); ?>
14
- </p>
15
- <?php require __DIR__ . '/passthru-info.php'; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/errors/libs-not-installed.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- ?>
6
- <p>
7
- <?= wp_kses_post(sprintf(
8
- __('On your server is not installed %sGD%s or %sImagick%s library. Please read %sthe plugin FAQ%s and check your server configuration %shere%s. Compare it with the configuration given in the requirements of plugin in the FAQ. Please contact your server administrator.', 'webp-converter-for-media'),
9
- '<strong>',
10
- '</strong>',
11
- '<strong>',
12
- '</strong>',
13
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
14
- '</a>',
15
- '<a href="' . sprintf('%s&action=server', Page::getSettingsPageUrl()) . '">',
16
- '</a>'
17
- )); ?>
18
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/errors/libs-without-webp-support.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- ?>
6
- <p>
7
- <?= wp_kses_post(sprintf(
8
- __('On your server installed GD or Imagick library %sdoes not support WebP format%s. Please read %sthe plugin FAQ%s and check your server configuration %shere%s. Compare it with the configuration given in the requirements of plugin in the FAQ. Please contact your server administrator.', 'webp-converter-for-media'),
9
- '<strong>',
10
- '</strong>',
11
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
12
- '</a>',
13
- '<a href="' . sprintf('%s&action=server', Page::getSettingsPageUrl()) . '">',
14
- '</a>'
15
- )); ?>
16
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/errors/passthru-execution.php DELETED
@@ -1,14 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Loader\Passthru;
4
-
5
- $url = Passthru::getLoaderUrl();
6
-
7
- ?>
8
- <p>
9
- <?= wp_kses_post(sprintf(
10
- __('Execution of the PHP file from path "%s" is blocked on your server, or access to this file is blocked. Add an exception and enable this file to be executed via HTTP request. To do this, check the security plugin settings (if you are using) or the security settings of your server.%sIn this case, please contact your server administrator.', 'webp-converter-for-media'),
11
- '<a href="' . $url . '" target="_blank">' . $url . '</a>',
12
- '<br><br>'
13
- )); ?>
14
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/errors/passthru-info.php DELETED
@@ -1,8 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('%sAlso try changing option "Image loading mode" to a different one.%s Issues about rewrites can often be resolved by setting this option to "%s". You can do this in plugin settings below. After changing settings, remember to flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media'),
4
- '<strong>',
5
- '</strong>',
6
- 'Pass Thru'
7
- )); ?>
8
- </p>
 
 
 
 
 
 
 
 
resources/components/errors/path-htaccess-not-writable.php DELETED
@@ -1,8 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('Unable to create or edit .htaccess file %s(function is_readable() or is_writable() returns false)%s. Change directory permissions. The current using path of file is: %s. Please contact your server administrator.', 'webp-converter-for-media'),
4
- '<em>',
5
- '</em>',
6
- '<strong>' . apply_filters('webpc_dir_path', '', 'uploads') . '/.htaccess</strong>'
7
- )); ?>
8
- </p>
 
 
 
 
 
 
 
 
resources/components/errors/path-uploads-unavailable.php DELETED
@@ -1,9 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('The path for /uploads files does not exist %s(function is_dir() returns false)%s. Use filter %s to set the correct path. The current using path is: %s. Please read the plugin FAQ to learn more.', 'webp-converter-for-media'),
4
- '<em>',
5
- '</em>',
6
- '<strong>webpc_dir_path</strong>',
7
- '<strong>' . apply_filters('webpc_dir_path', '', 'uploads') . '</strong>'
8
- )); ?>
9
- </p>
 
 
 
 
 
 
 
 
 
resources/components/errors/path-webp-duplicated.php DELETED
@@ -1,7 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('The paths for /uploads files and for saving converted WebP files are the same. Change them using filter %s. The current path for them is: %s.', 'webp-converter-for-media'),
4
- '<strong>webpc_dir_path</strong>',
5
- '<strong>' . apply_filters('webpc_dir_path', '', 'uploads') . '</strong>'
6
- )); ?>
7
- </p>
 
 
 
 
 
 
 
resources/components/errors/path-webp-not-writable.php DELETED
@@ -1,9 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('The path for saving converted WebP files does not exist and cannot be created %s(function is_writable() returns false)%s. Use filter %s to set the correct path. The current using path is: %s. Please read the plugin FAQ to learn more.', 'webp-converter-for-media'),
4
- '<em>',
5
- '</em>',
6
- '<strong>webpc_dir_path</strong>',
7
- '<strong>' . apply_filters('webpc_dir_path', '', 'webp') . '</strong>'
8
- )); ?>
9
- </p>
 
 
 
 
 
 
 
 
 
resources/components/errors/rest-api-disabled.php DELETED
@@ -1,8 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('The REST API on your website is not available. Please verify this and try again. Pay special attention to the filters: %s, %s and %s.', 'webp-converter-for-media'),
4
- '<a href="https://developer.wordpress.org/reference/hooks/rest_enabled/" target="_blank">rest_enabled</a>',
5
- '<a href="https://developer.wordpress.org/reference/hooks/rest_jsonp_enabled/" target="_blank">rest_jsonp_enabled</a>',
6
- '<a href="https://developer.wordpress.org/reference/hooks/rest_authentication_errors/" target="_blank">rest_authentication_errors</a>'
7
- )); ?>
8
- </p>
 
 
 
 
 
 
 
 
resources/components/errors/rewrites-cached.php DELETED
@@ -1,7 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('Your server uses the cache for HTTP requests. The rules from .htaccess file or from Nginx configuration are not executed every time when the image is loaded, but the last redirect from cache is performed. With each request to image, your server should execute the rules from .htaccess file or from Nginx configuration. Now it only does this the first time and then uses cache. This means that if your server redirected image to WebP format the first time, it does so on every request. It should check the rules from .htaccess file or from Nginx configuration each time during request to image and redirect only when the conditions are met. %sIf you have enabled caching HTTP reverse proxy or another HTTP caching, you must disable it. Otherwise the plugin cannot work properly. In this case, please contact your server administrator.', 'webp-converter-for-media'),
4
- '<br><br>'
5
- )); ?>
6
- </p>
7
- <?php require __DIR__ . '/passthru-info.php'; ?>
 
 
 
 
 
 
 
resources/components/errors/rewrites-not-working.php DELETED
@@ -1,9 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('Redirects on your server are not working. Check the correct configuration for you in %sthe plugin FAQ%s. If your configuration is correct, it means that your server does not support redirects from the .htaccess file or requests to images are processed by your server bypassing Apache. %sIn this case, please contact your server administrator.', 'webp-converter-for-media'),
4
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
5
- '</a>',
6
- '<br><br>'
7
- )); ?>
8
- </p>
9
- <?php require __DIR__ . '/passthru-info.php'; ?>
 
 
 
 
 
 
 
 
 
resources/components/errors/settings-incorrect.php DELETED
@@ -1,7 +0,0 @@
1
- <p>
2
- <?= wp_kses_post(sprintf(
3
- __('%sThe plugin settings are incorrect!%s Check them out and save them again. Please remember that you must have at least one supported files extension, at least one supported directory and selected conversion method and level of images quality.', 'webp-converter-for-media'),
4
- '<strong>',
5
- '</strong>'
6
- )); ?>
7
- </p>
 
 
 
 
 
 
 
resources/components/fields/checkbox.php DELETED
@@ -1,28 +0,0 @@
1
- <?php if ($option['info']) : ?>
2
- <p><?= wp_kses_post($option['info']); ?></p>
3
- <?php endif; ?>
4
- <table class="webpTable">
5
- <?php
6
- foreach ($option['values'] as $value => $label) :
7
- $isChecked = (isset($values[$option['name']]) && in_array($value, $values[$option['name']]));
8
- ?>
9
- <tr>
10
- <td>
11
- <input type="checkbox"
12
- name="<?= esc_attr($option['name']); ?>[]"
13
- value="<?= esc_attr($value); ?>"
14
- id="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
15
- class="webpCheckbox__input"
16
- <?= $isChecked ? 'checked' : ''; ?>
17
- <?= (in_array($value, $option['disabled'])) ? 'disabled' : ''; ?>>
18
- <label for="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"></label>
19
- </td>
20
- <td>
21
- <label for="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
22
- class="webpCheckbox__label">
23
- <?= wp_kses_post($label); ?>
24
- </label>
25
- </td>
26
- </tr>
27
- <?php endforeach; ?>
28
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/fields/quality.php DELETED
@@ -1,23 +0,0 @@
1
- <?php if ($option['info']) : ?>
2
- <p><?= wp_kses_post($option['info']); ?></p>
3
- <?php endif; ?>
4
- <div class="webpPage__quality">
5
- <?php
6
- foreach ($option['values'] as $value => $label) :
7
- $isChecked = (isset($values[$option['name']]) && ($value == $values[$option['name']]));
8
- ?>
9
- <div class="webpPage__qualityItem">
10
- <input type="radio"
11
- name="<?= esc_attr($option['name']); ?>"
12
- value="<?= esc_attr($value); ?>"
13
- id="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
14
- class="webpPage__qualityItemInput"
15
- <?= $isChecked ? 'checked' : ''; ?>
16
- <?= (in_array($value, $option['disabled'])) ? 'disabled' : ''; ?>>
17
- <label for="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
18
- class="webpPage__qualityItemLabel">
19
- <?= wp_kses_post($label); ?>
20
- </label>
21
- </div>
22
- <?php endforeach; ?>
23
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/fields/radio.php DELETED
@@ -1,28 +0,0 @@
1
- <?php if ($option['info']) : ?>
2
- <p><?= wp_kses_post($option['info']); ?></p>
3
- <?php endif; ?>
4
- <table class="webpTable">
5
- <?php
6
- foreach ($option['values'] as $value => $label) :
7
- $isChecked = (isset($values[$option['name']]) && ($value === $values[$option['name']]));
8
- ?>
9
- <tr>
10
- <td>
11
- <input type="radio"
12
- name="<?= esc_attr($option['name']); ?>"
13
- value="<?= esc_attr($value); ?>"
14
- id="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
15
- class="webpCheckbox__input"
16
- <?= $isChecked ? 'checked' : ''; ?>
17
- <?= (in_array($value, $option['disabled'])) ? 'disabled' : ''; ?>>
18
- <label for="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"></label>
19
- </td>
20
- <td>
21
- <label for="webpc-<?= esc_attr($index); ?>-<?= esc_attr($value); ?>"
22
- class="webpCheckbox__label">
23
- <?= wp_kses_post($label); ?>
24
- </label>
25
- </td>
26
- </tr>
27
- <?php endforeach; ?>
28
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/notices/thanks.php DELETED
@@ -1,32 +0,0 @@
1
- <div class="notice notice-success is-dismissible" data-notice="webp-converter" data-url="<?= admin_url('admin-ajax.php'); ?>">
2
- <div class="webpContent webpContent--notice">
3
- <h4>
4
- <?= esc_html(__('Thank you for using our plugin WebP Converter for Media!', 'webp-converter-for-media')); ?>
5
- </h4>
6
- <p>
7
- <?= wp_kses_post(sprintf(
8
- __('Please let us know what you think about our plugin. It is important that we can develop this tool. Thank you for all the ratings, reviews and donates. If you have a technical problem, please before you add a review %scheck our FAQ%s or contact us if you did not find help there. We will try to help you!', 'webp-converter-for-media'),
9
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
10
- '</a>'
11
- )); ?>
12
- </p>
13
- <div class="webpContent__buttons">
14
- <a href="https://wordpress.org/support/plugin/webp-converter-for-media/#new-post" target="_blank"
15
- class="webpContent__button webpButton webpButton--green">
16
- <?= esc_html(__('Get help', 'webp-converter-for-media')); ?>
17
- </a>
18
- <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/?rate=5#new-post" target="_blank"
19
- class="webpContent__button webpButton webpButton--green">
20
- <?= esc_html(__('Add review', 'webp-converter-for-media')); ?>
21
- </a>
22
- <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=notice-thanks" target="_blank"
23
- class="webpContent__button webpButton webpButton--green dashicons-heart">
24
- <?= esc_html(__('Provide us a coffee', 'webp-converter-for-media')); ?>
25
- </a>
26
- <a href="#" target="_blank" data-permanently
27
- class="webpContent__button webpButton webpButton--blue">
28
- <?= esc_html(__('I added review, do not show again', 'webp-converter-for-media')); ?>
29
- </a>
30
- </div>
31
- </div>
32
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/notices/welcome.php DELETED
@@ -1,25 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- ?>
6
- <div class="notice notice-success">
7
- <div class="webpContent webpContent--notice">
8
- <h4>
9
- <?= esc_html(__('Thank you for installing our plugin WebP Converter for Media!', 'webp-converter-for-media')); ?>
10
- </h4>
11
- <p>
12
- <?= wp_kses_post(sprintf(
13
- __('Would you like to speed up your website using our plugin? %sGo to plugin settings and convert all your images to WebP with one click! Thank you for being with us! %s', 'webp-converter-for-media'),
14
- '<br>',
15
- '<span class="dashicons dashicons-heart"></span>'
16
- )); ?>
17
- </p>
18
- <div class="webpContent__buttons">
19
- <a href="<?= esc_url(Page::getSettingsPageUrl()); ?>"
20
- class="webpContent__button webpButton webpButton--green">
21
- <?= esc_html(__('Speed up my website', 'webp-converter-for-media')); ?>
22
- </a>
23
- </div>
24
- </div>
25
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/about.php DELETED
@@ -1,28 +0,0 @@
1
- <div class="webpPage__widget">
2
- <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
- <?= __('How does this work?', 'webp-converter-for-media'); ?>
4
- </h3>
5
- <div class="webpContent">
6
- <p>
7
- <?= wp_kses_post(sprintf(
8
- __('By adding images to your media library, they are automatically converted and saved in a separate directory. Images are converted using %sGD%s or %sImagick%s native extension for PHP.', 'webp-converter-for-media'),
9
- '<strong>', '</strong>', '<strong>', '</strong>'
10
- )); ?>
11
- </p>
12
- <p>
13
- <?= wp_kses_post(sprintf(
14
- __('When the browser tries to download an image file, the server verifies if it supports image/webp files and if the file exists. If everything is OK, instead of the original image, the browser will receive its equivalent in WebP format.', 'webp-converter-for-media'),
15
- '<strong>', '</strong>'
16
- )); ?>
17
- </p>
18
- <p>
19
- <?= wp_kses_post(__('The plugin in default loading mode (via .htaccess) does not change file URLs, so there are no problems with saving the page to the cache and the page generation time does not increase.', 'webp-converter-for-media')); ?>
20
- </p>
21
- <p>
22
- <?= wp_kses_post(sprintf(
23
- __('Image URLs are modified using the module %smod_rewrite%s on the server, i.e. the same, thanks to which we can use friendly links in WordPress. Additionally, the MIME type of the sent file is modified to %simage/webp%s.', 'webp-converter-for-media'),
24
- '<strong>', '</strong>', '<strong>', '</strong>'
25
- )); ?>
26
- </p>
27
- </div>
28
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/donate.php DELETED
@@ -1,17 +0,0 @@
1
- <div class="webpPage__widget">
2
- <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
- <?= esc_html(__('We love what we do!', 'webp-converter-for-media')); ?>
4
- </h3>
5
- <div class="webpContent">
6
- <p>
7
- <?= wp_kses_post(__('However, working on plugins and technical support requires many hours of work. If you want to appreciate it, you can provide us a coffee. Thanks everyone!', 'webp-converter-for-media')); ?>
8
- </p>
9
- <p class="center">
10
- <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=widget-donate"
11
- target="_blank"
12
- class="webpButton webpButton--blue dashicons-heart">
13
- <?= esc_html(__('Provide us a coffee', 'webp-converter-for-media')); ?>
14
- </a>
15
- </p>
16
- </div>
17
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/errors.php DELETED
@@ -1,19 +0,0 @@
1
- <?php if ($errors = apply_filters('webpc_server_errors_messages', [], false, true)) : ?>
2
- <div class="webpPage__widget">
3
- <h3 class="webpPage__widgetTitle webpPage__widgetTitle--error">
4
- <?= esc_html(__('Server configuration error', 'webp-converter-for-media')); ?>
5
- </h3>
6
- <div class="webpContent webpContent--wide">
7
- <?= implode('<p>---</p>', $errors); ?>
8
- <p>---</p>
9
- <p>
10
- <?= sprintf(
11
- __('%sError codes:%s %s', 'webp-converter-for-media'),
12
- '<strong>',
13
- '</strong>',
14
- implode(', ', array_keys($errors))
15
- ); ?>
16
- </p>
17
- </div>
18
- </div>
19
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/options.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- ?>
6
- <div class="webpPage__widget">
7
- <h3 class="webpPage__widgetTitle">
8
- <?= esc_html(__('Settings', 'webp-converter-for-media')); ?>
9
- </h3>
10
- <div class="webpContent">
11
- <?php foreach ($options as $index => $option) : ?>
12
- <div class="webpPage__widgetRow">
13
- <h4><?= esc_html($option['label']); ?></h4>
14
- <?php include WEBPC_PATH . '/resources/components/fields/' . $option['type'] . '.php'; ?>
15
- </div>
16
- <?php endforeach; ?>
17
- <div class="webpPage__widgetRow">
18
- <button type="submit" name="webpc_save"
19
- class="webpButton webpButton--green">
20
- <?= esc_html(__('Save Changes', 'webp-converter-for-media')); ?>
21
- </button>
22
- </div>
23
- <div class="webpPage__widgetRow">
24
- <p>
25
- <?= wp_kses_post(sprintf(
26
- __('If you have a problem %scheck our FAQ%s first. If you did not find help there, please %scheck support forum%s for any similar problem or contact us. Before you contact us %scheck the configuration%s of your server.', 'webp-converter-for-media'),
27
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
28
- '</a>',
29
- '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
30
- '</a>',
31
- '<a href="' . sprintf('%s&action=server', Page::getSettingsPageUrl()) . '">',
32
- '</a>'
33
- )); ?>
34
- </p>
35
- </div>
36
- </div>
37
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/regenerate.php DELETED
@@ -1,96 +0,0 @@
1
- <?php
2
-
3
- $apiPaths = apply_filters('webpc_rest_api_paths', '');
4
- $apiRegenerate = apply_filters('webpc_rest_api_regenerate', '');
5
-
6
- ?>
7
- <div class="webpPage__widget">
8
- <h3 class="webpPage__widgetTitle">
9
- <?= esc_html(__('Regenerate images', 'webp-converter-for-media')); ?>
10
- </h3>
11
- <div class="webpLoader webpContent"
12
- data-api-paths="<?= esc_url($apiPaths); ?>"
13
- data-api-regenerate="<?= esc_url($apiRegenerate); ?>"
14
- data-api-error-message="<?= esc_attr(__('An unknown error occurred while converting the images: %s', 'webp-converter-for-media')); ?>">
15
- <div class="webpPage__widgetRow">
16
- <p>
17
- <?= wp_kses_post(__('Convert all existing images with just one click! This tool uses the WordPress REST API by downloading addresses of all images and converting all files gradually. This is a process that may take a few or more than ten minutes depending on the number of files. During this process, please do not close your browser window.', 'webp-converter-for-media')); ?>
18
- </p>
19
- <p>
20
- <?= wp_kses_post(__('This operation should be performed only once after installing the plugin. New images from the Media Library will be converted automatically. For other images, e.g. from the /themes or /uploads directory that are not from the Media Library, you must start manual conversion after adding new images.', 'webp-converter-for-media')); ?>
21
- </p>
22
- <div class="webpLoader__status" hidden>
23
- <div class="webpLoader__bar">
24
- <div class="webpLoader__barProgress" data-percent="0">
25
- <div class="webpLoader__barCount"></div>
26
- </div>
27
- <div class="webpLoader__size">
28
- <?= sprintf(
29
- wp_kses_post(__('Saving the weight of your images: %s', 'webp-converter-for-media')),
30
- '<span class="webpLoader__sizeProgress">0 kB</span>'
31
- ); ?>
32
- </div>
33
- </div>
34
- <div class="webpLoader__success" hidden>
35
- <div class="webpLoader__successContent">
36
- <?= wp_kses_post(__('The process was completed successfully. Your images have been converted!', 'webp-converter-for-media')); ?>
37
- <?= wp_kses_post(__('Please flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media')); ?>
38
- <br>
39
- <?= wp_kses_post(sprintf(
40
- __('Do you want to know how a plugin works and how to check if it is working properly? Read our %splugin FAQ%s.', 'webp-converter-for-media'),
41
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
42
- '</a>'
43
- )); ?>
44
- </div>
45
- </div>
46
- <div class="webpLoader__popup webpPopup" hidden>
47
- <div class="webpPopup__inner">
48
- <div class="webpPopup__image"></div>
49
- <div class="webpPopup__content">
50
- <p><?= wp_kses_post(__('Hi, I\'m Mateusz! I\'m glad you managed to reduce the weight of your website. If you would like to support me in developing this plugin, I will be very grateful to you!', 'webp-converter-for-media')); ?></p>
51
- <p>
52
- <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=notice-regenerate"
53
- target="_blank"
54
- class="webpButton webpButton--blue dashicons-coffee">
55
- <?= wp_kses_post(__('Provide me a coffee', 'webp-converter-for-media')); ?>
56
- </a>
57
- </p>
58
- </div>
59
- </div>
60
- </div>
61
- <div class="webpLoader__errors" hidden>
62
- <div class="webpLoader__errorsTitle">
63
- <?= esc_html(__('Additional informations about process:', 'webp-converter-for-media')); ?>
64
- </div>
65
- <div class="webpLoader__errorsContent">
66
- <div class="webpLoader__errorsContentList"></div>
67
- <div class="webpLoader__errorsContentMessage" hidden>
68
- <?= wp_kses_post(__('An error occurred while connecting to REST API. Please try again.', 'webp-converter-for-media')); ?>
69
- </div>
70
- </div>
71
- </div>
72
- </div>
73
- </div>
74
- <div class="webpPage__widgetRow">
75
- <table class="webpTable">
76
- <tr>
77
- <td>
78
- <input type="checkbox" name="regenerate_force" value="1"
79
- id="webpc-regenerate-force" class="webpCheckbox__input">
80
- <label for="webpc-regenerate-force"></label>
81
- </td>
82
- <td>
83
- <label for="webpc-regenerate-force" class="webpCheckbox__label">
84
- <?= __('Force convert all images again', 'webp-converter-for-media'); ?>
85
- </label>
86
- </td>
87
- </tr>
88
- </table>
89
- <button type="button" target="_blank"
90
- class="webpLoader__button webpButton webpButton--green"
91
- <?= (apply_filters('webpc_server_errors', [], true)) ? 'disabled' : ''; ?>>
92
- <?= esc_html(__('Regenerate All', 'webp-converter-for-media')); ?>
93
- </button>
94
- </div>
95
- </div>
96
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/server.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- $info = apply_filters('webpc_server_info', '');
6
-
7
- ?>
8
- <div class="webpPage__widget">
9
- <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
10
- <?= esc_html(__('Your server configuration', 'webp-converter-for-media')); ?>
11
- </h3>
12
- <div class="webpContent">
13
- <div class="webpPage__widgetRow">
14
- <p>
15
- <?= wp_kses_post(sprintf(__('Please compare your configuration with the configuration that is given in the technical requirements in %sthe plugin FAQ%s. If your server does not meet the technical requirements, please contact your server Administrator.', 'webp-converter-for-media'),
16
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
17
- '</a>'
18
- )); ?>
19
- </p>
20
- <a href="<?= esc_url(Page::getSettingsPageUrl()); ?>" class="webpLoader__button webpButton webpButton--blue">
21
- <?= esc_html(__('Back to settings', 'webp-converter-for-media')); ?>
22
- </a>
23
- </div>
24
- <div class="webpPage__widgetRow">
25
- <div class="webpServerInfo"><?= wp_kses_post($info); ?></div>
26
- </div>
27
- <div class="webpPage__widgetRow">
28
- <a href="<?= esc_url(Page::getSettingsPageUrl()); ?>" class="webpLoader__button webpButton webpButton--blue">
29
- <?= esc_html(__('Back to settings', 'webp-converter-for-media')); ?>
30
- </a>
31
- </div>
32
- </div>
33
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/components/widgets/support.php DELETED
@@ -1,41 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- ?>
6
- <div class="webpPage__widget">
7
- <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
8
- <?= esc_html(__('We are waiting for your message', 'webp-converter-for-media')); ?>
9
- </h3>
10
- <div class="webpContent">
11
- <p>
12
- <?= wp_kses_post(__('Do you have a technical problem? Please contact us. We will be happy to help you. Or maybe you have an idea for a new feature? Please let us know about it by filling the support form. We will try to add it!', 'webp-converter-for-media')); ?>
13
- </p>
14
- <p>
15
- <?= wp_kses_post(sprintf(
16
- __('Please %scheck our FAQ%s before adding a thread with technical problem. If you do not find help there, %scheck support forum%s for similar problems. Before you contact us check the configuration of your server and attach it in your message, e.g. as a screenshot.', 'webp-converter-for-media'),
17
- '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
18
- '</a>',
19
- '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
20
- '</a>'
21
- )); ?>
22
- </p>
23
- <p class="center">
24
- <a href="<?= esc_url(sprintf('%s&action=server', Page::getSettingsPageUrl())); ?>" class="webpButton webpButton--blue dashicons-admin-tools">
25
- <?= esc_html(__('Server configuration', 'webp-converter-for-media')); ?>
26
- </a>
27
- <br>
28
- <a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank" class="webpButton webpButton--blue">
29
- <?= esc_html(__('Get help', 'webp-converter-for-media')); ?>
30
- </a>
31
- </p>
32
- <p>
33
- <?= wp_kses_post(__('Do you like our plugin? Could you rate him? Please let us know what you think about our plugin. It is important that we can develop this tool. Thank you for all the ratings, reviews and donates.', 'webp-converter-for-media')); ?>
34
- </p>
35
- <p class="center">
36
- <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/?rate=5#new-post" target="_blank" class="webpButton webpButton--blue">
37
- <?= esc_html(__('Add review', 'webp-converter-for-media')); ?>
38
- </a>
39
- </p>
40
- </div>
41
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/views/deactivation-modal.php DELETED
@@ -1,86 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Errors;
4
-
5
- $errors = implode(', ', apply_filters('webpc_server_errors', []));
6
- $items = [
7
- [
8
- 'key' => 'server_config',
9
- 'label' => __('I have "Server configuration error" in plugin settings', 'webp-converter-for-media'),
10
- 'placeholder' => esc_attr(__('What is your error? Have you been looking for solution to this issue?', 'webp-converter-for-media')),
11
- ],
12
- [
13
- 'key' => 'website_broken',
14
- 'label' => __('This plugin broke my website', 'webp-converter-for-media'),
15
- 'placeholder' => esc_attr(__('What exactly happened?', 'webp-converter-for-media')),
16
- ],
17
- [
18
- 'key' => 'better_plugin',
19
- 'label' => __('I found a better plugin', 'webp-converter-for-media'),
20
- 'placeholder' => esc_attr(__('What is name of this plugin? Why is it better?', 'webp-converter-for-media')),
21
- ],
22
- [
23
- 'key' => 'misunderstanding',
24
- 'label' => __('I do not understand how the plugin works', 'webp-converter-for-media'),
25
- 'placeholder' => esc_attr(__('What is non-understandable to you? Did you search for this in plugin FAQ?', 'webp-converter-for-media')),
26
- ],
27
- [
28
- 'key' => 'temporary_deactivation',
29
- 'label' => __('This is a temporary deactivation', 'webp-converter-for-media'),
30
- 'placeholder' => '',
31
- ],
32
- [
33
- 'key' => 'other',
34
- 'label' => __('Other reason', 'webp-converter-for-media'),
35
- 'placeholder' => esc_attr(__('What is reason? What can we improve for you?', 'webp-converter-for-media')),
36
- ],
37
- ];
38
-
39
- ?>
40
- <div class="webpModal" hidden>
41
- <div class="webpModal__outer">
42
- <form action="https://feedback.gbiorczyk.pl/" method="POST" class="webpModal__form">
43
- <h2 class="webpModal__headline">
44
- <?= esc_html(__('We are sorry that you are leaving our plugin WebP Converter for Media', 'webp-converter-for-media')); ?>
45
- </h2>
46
- <div class="webpModal__desc">
47
- <?= esc_html(__('Can you please take a moment to tell us why you are deactivating this plugin (your answer is completely anonymous)?', 'webp-converter-for-media')); ?>
48
- </div>
49
- <table class="webpModal__table webpTable">
50
- <?php foreach ($items as $index => $item) : ?>
51
- <tr>
52
- <td>
53
- <input type="radio" name="webpc_reason" value="<?= esc_attr($item['key']); ?>"
54
- id="webpc-option<?= $index; ?>" class="webpCheckbox__input"
55
- data-placeholder="<?= esc_attr($item['placeholder']); ?>">
56
- <label for="webpc-option<?= $index; ?>"></label>
57
- </td>
58
- <td>
59
- <label for="webpc-option<?= $index; ?>"
60
- class="webpCheckbox__label"><?= esc_html($item['label']); ?></label>
61
- </td>
62
- </tr>
63
- <?php endforeach; ?>
64
- </table>
65
- <textarea class="webpModal__textarea" name="webpc_comment" rows="2"></textarea>
66
- <ul class="webpModal__buttons">
67
- <li class="webpModal__button">
68
- <button type="submit" class="webpModal__buttonInner webpButton webpButton--green">
69
- <?= esc_html(__('Submit and Deactivate', 'webp-converter-for-media')); ?>
70
- </button>
71
- </li>
72
- <li class="webpModal__button">
73
- <button type="button" class="webpModal__buttonInner webpButton webpButton--blue">
74
- <?= esc_html(__('Skip and Deactivate', 'webp-converter-for-media')); ?>
75
- </button>
76
- </li>
77
- </ul>
78
- <input type="hidden" name="webpc_error_codes"
79
- value="<?= esc_attr($errors); ?>">
80
- <input type="hidden" name="webpc_plugin_settings"
81
- value='<?= json_encode(apply_filters('webpc_get_values', [])); ?>'>
82
- <input type="hidden" name="webpc_plugin_version"
83
- value="<?= esc_attr(WEBPC_VERSION); ?>">
84
- </form>
85
- </div>
86
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/views/settings.php DELETED
@@ -1,42 +0,0 @@
1
- <?php
2
-
3
- use WebpConverter\Settings\Page;
4
-
5
- $path = sprintf('%s&_wpnonce=%s', Page::getSettingsPageUrl(), wp_create_nonce('webpc-save'));
6
- $options = apply_filters('webpc_get_options', []);
7
- $values = apply_filters('webpc_get_values', []);
8
-
9
- ?>
10
- <div class="wrap">
11
- <h1><?= esc_html(__('WebP Converter for Media', 'webp-converter-for-media')); ?></h1>
12
- <form method="post" action="<?= esc_url($path); ?>" class="webpPage">
13
- <div class="webpPage__inner">
14
- <ul class="webpPage__columns">
15
- <li class="webpPage__column webpPage__column--large">
16
- <?php if ($_POST) : ?>
17
- <div class="webpPage__alert">
18
- <?= esc_html(__('Changes were successfully saved!', 'webp-converter-for-media')); ?>
19
- <?= esc_html(__('Please flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media')); ?>
20
- </div>
21
- <?php endif; ?>
22
- <?php
23
- if (isset($_GET['action']) && ($_GET['action'] === 'server')) {
24
- include WEBPC_PATH . '/resources/components/widgets/server.php';
25
- } else {
26
- include WEBPC_PATH . '/resources/components/widgets/errors.php';
27
- include WEBPC_PATH . '/resources/components/widgets/options.php';
28
- include WEBPC_PATH . '/resources/components/widgets/regenerate.php';
29
- }
30
- ?>
31
- </li>
32
- <li class="webpPage__column webpPage__column--small">
33
- <?php
34
- include WEBPC_PATH . '/resources/components/widgets/about.php';
35
- include WEBPC_PATH . '/resources/components/widgets/support.php';
36
- include WEBPC_PATH . '/resources/components/widgets/donate.php';
37
- ?>
38
- </li>
39
- </ul>
40
- </div>
41
- </form>
42
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Action/ConvertAttachment.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Media\Attachment;
9
+
10
+ /**
11
+ * Initializes conversion of all image sizes for attachment.
12
+ */
13
+ class ConvertAttachment extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
14
+
15
+ /**
16
+ * Integrates with WordPress hooks.
17
+ *
18
+ * @return void
19
+ */
20
+ public function init_hooks() {
21
+ add_action( 'webpc_convert_attachment', [ $this, 'convert_files_by_attachment' ] );
22
+ }
23
+
24
+ /**
25
+ * Converts all sizes of attachment to output formats.
26
+ *
27
+ * @param int $post_id ID of attachment.
28
+ *
29
+ * @return void
30
+ * @internal
31
+ */
32
+ public function convert_files_by_attachment( int $post_id ) {
33
+ $attachment = new Attachment();
34
+ $attachment->set_plugin( $this->get_plugin() );
35
+
36
+ do_action( 'webpc_convert_paths', $attachment->get_attachment_paths( $post_id ) );
37
+ }
38
+ }
src/Action/ConvertDir.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\HookableInterface;
6
+
7
+ /**
8
+ * Initializes conversion of all image sizes in directory.
9
+ */
10
+ class ConvertDir implements HookableInterface {
11
+
12
+ /**
13
+ * Integrates with WordPress hooks.
14
+ *
15
+ * @return void
16
+ */
17
+ public function init_hooks() {
18
+ add_action( 'webpc_convert_dir', [ $this, 'convert_files_by_directory' ], 10, 2 );
19
+ }
20
+
21
+ /**
22
+ * Converts all images in directory to output formats.
23
+ *
24
+ * @param string $dir_path Server path of directory.
25
+ * @param bool $skip_exists Skip converted images?
26
+ *
27
+ * @return void
28
+ * @internal
29
+ */
30
+ public function convert_files_by_directory( string $dir_path, bool $skip_exists = true ) {
31
+ $paths = apply_filters( 'webpc_dir_filess', [], $dir_path, $skip_exists );
32
+ do_action( 'webpc_convert_paths', $paths );
33
+ }
34
+ }
src/Action/ConvertPaths.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Method\MethodIntegrator;
9
+
10
+ /**
11
+ * Initializes conversion of all images in list of paths.
12
+ */
13
+ class ConvertPaths extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
14
+
15
+ /**
16
+ * Integrates with WordPress hooks.
17
+ *
18
+ * @return void
19
+ */
20
+ public function init_hooks() {
21
+ add_action( 'webpc_convert_paths', [ $this, 'convert_files_by_paths' ] );
22
+ }
23
+
24
+ /**
25
+ * Converts all given images to output formats.
26
+ *
27
+ * @param string[] $paths Server paths of images.
28
+ *
29
+ * @return void
30
+ * @internal
31
+ */
32
+ public function convert_files_by_paths( array $paths ) {
33
+ $method_integrator = new MethodIntegrator();
34
+ $method_integrator->set_plugin( $this->get_plugin() );
35
+ $method_integrator->init_conversion( $paths );
36
+ }
37
+ }
src/Action/DeletePaths.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\Conversion\OutputPath;
7
+ use WebpConverter\Conversion\SkipLarger;
8
+
9
+ /**
10
+ * Deletes all images in list of paths.
11
+ */
12
+ class DeletePaths implements HookableInterface {
13
+
14
+ /**
15
+ * Integrates with WordPress hooks.
16
+ *
17
+ * @return void
18
+ */
19
+ public function init_hooks() {
20
+ add_action( 'webpc_delete_paths', [ $this, 'delete_files_by_paths' ] );
21
+ }
22
+
23
+ /**
24
+ * Deletes images from output directory.
25
+ *
26
+ * @param string[] $paths Server paths of output images.
27
+ *
28
+ * @return void
29
+ * @internal
30
+ */
31
+ public function delete_files_by_paths( array $paths ) {
32
+ foreach ( $paths as $path ) {
33
+ $this->delete_file_by_path( $path );
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Deletes image from output directory.
39
+ *
40
+ * @param string $path Server path of output image.
41
+ *
42
+ * @return void
43
+ */
44
+ private function delete_file_by_path( string $path ) {
45
+ if ( ! ( $source_paths = OutputPath::get_paths( $path ) ) ) {
46
+ return;
47
+ }
48
+
49
+ foreach ( $source_paths as $source_path ) {
50
+ if ( is_writable( $source_path ) ) {
51
+ unlink( $source_path );
52
+ } elseif ( is_writable( $source_path . '.' . SkipLarger::DELETED_FILE_EXTENSION ) ) {
53
+ unlink( $source_path . '.' . SkipLarger::DELETED_FILE_EXTENSION );
54
+ }
55
+ }
56
+ }
57
+ }
src/Action/RegenerateAll.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Endpoint\PathsEndpoint;
9
+
10
+ /**
11
+ * Initializes conversion of all image sizes in all directories.
12
+ */
13
+ class RegenerateAll extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
14
+
15
+ /**
16
+ * Integrates with WordPress hooks.
17
+ *
18
+ * @return void
19
+ */
20
+ public function init_hooks() {
21
+ add_action( 'webpc_regenerate_all', [ $this, 'regenerate_all_images' ] );
22
+ }
23
+
24
+ /**
25
+ * Converts all images in directories set in options to output formats.
26
+ *
27
+ * @return void
28
+ * @internal
29
+ */
30
+ public function regenerate_all_images() {
31
+ $paths_endpoint = new PathsEndpoint();
32
+ $paths_endpoint->set_plugin( $this->get_plugin() );
33
+
34
+ do_action( 'webpc_convert_paths', $paths_endpoint->get_paths( true ) );
35
+ }
36
+ }
src/Conversion/Cron/Event.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Cron;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Cron\Schedules;
9
+
10
+ /**
11
+ * Adds cron event that converts images.
12
+ */
13
+ class Event extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
14
+
15
+ const CRON_ACTION = 'webpc_regenerate_all';
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ add_action( 'init', [ $this, 'add_cron_event' ] );
24
+ }
25
+
26
+ /**
27
+ * Initializes cron event to convert all images.
28
+ *
29
+ * @return void
30
+ * @internal
31
+ */
32
+ public function add_cron_event() {
33
+ if ( wp_next_scheduled( self::CRON_ACTION )
34
+ || ! ( $settings = $this->get_plugin()->get_settings() )
35
+ || ! in_array( 'cron_enabled', $settings['features'] ) ) {
36
+ return;
37
+ }
38
+
39
+ wp_schedule_event( time(), Schedules::CRON_SCHEDULE, self::CRON_ACTION );
40
+ }
41
+ }
src/Conversion/Cron/Schedules.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Cron;
4
+
5
+ use WebpConverter\HookableInterface;
6
+
7
+ /**
8
+ * Adds time interval to cron event.
9
+ */
10
+ class Schedules implements HookableInterface {
11
+
12
+ const CRON_SCHEDULE = 'webpc_cron';
13
+
14
+ /**
15
+ * Integrates with WordPress hooks.
16
+ *
17
+ * @return void
18
+ */
19
+ public function init_hooks() {
20
+ add_filter( 'cron_schedules', [ $this, 'add_cron_interval' ] );
21
+ }
22
+
23
+ /**
24
+ * Adds new cron schedule.
25
+ *
26
+ * @param array[] $schedules Cron schedules.
27
+ *
28
+ * @return array[] Cron schedules.
29
+ * @internal
30
+ */
31
+ public function add_cron_interval( array $schedules ): array {
32
+ $schedules[ self::CRON_SCHEDULE ] = [
33
+ 'interval' => apply_filters( 'webpc_cron_interval', HOUR_IN_SECONDS ),
34
+ 'display' => 'WebP Converter for Media',
35
+ ];
36
+ return $schedules;
37
+ }
38
+ }
src/Conversion/Directories.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\Conversion\Directory\DirectoriesIntegration;
7
+ use WebpConverter\Conversion\Directory\UploadsDirectory;
8
+ use WebpConverter\Conversion\Directory\GalleryDirectory;
9
+ use WebpConverter\Conversion\Directory\UploadsWebpcDirectory;
10
+ use WebpConverter\Conversion\Directory\PluginsDirectory;
11
+ use WebpConverter\Conversion\Directory\ThemesDirectory;
12
+ use WebpConverter\Plugin\Uninstall\WebpFiles;
13
+
14
+ /**
15
+ * Initializes integration for all directories.
16
+ */
17
+ class Directories implements HookableInterface {
18
+
19
+ /**
20
+ * Objects of supported directories.
21
+ *
22
+ * @var DirectoriesIntegration
23
+ */
24
+ private $directories_integration;
25
+
26
+ /**
27
+ * Directories constructor.
28
+ */
29
+ public function __construct() {
30
+ $this->directories_integration = ( new DirectoriesIntegration() )
31
+ ->add_directory( new GalleryDirectory() )
32
+ ->add_directory( new PluginsDirectory() )
33
+ ->add_directory( new ThemesDirectory() )
34
+ ->add_directory( new UploadsDirectory() )
35
+ ->add_directory( new UploadsWebpcDirectory() );
36
+ }
37
+
38
+ /**
39
+ * Integrates with WordPress hooks.
40
+ *
41
+ * @return void
42
+ */
43
+ public function init_hooks() {
44
+ $this->directories_integration->init_hooks();
45
+ }
46
+
47
+ /**
48
+ * Returns list of source directories.
49
+ *
50
+ * @return string[] Types of directories with labels.
51
+ */
52
+ public function get_directories(): array {
53
+ return $this->directories_integration->get_input_directories();
54
+ }
55
+
56
+ /**
57
+ * Removes converted files from output directory.
58
+ *
59
+ * @param string[] $source_dirs Types of source directories.
60
+ *
61
+ * @return void
62
+ */
63
+ public function remove_unused_output_directories( array $source_dirs ) {
64
+ $all_dirs = $this->directories_integration->get_output_directories();
65
+ foreach ( $all_dirs as $output_dir => $output_path ) {
66
+ if ( in_array( $output_dir, $source_dirs ) ) {
67
+ continue;
68
+ }
69
+ WebpFiles::remove_webp_files( $output_path );
70
+ }
71
+ }
72
+ }
src/Conversion/Directory/DirectoriesIntegration.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
6
+ use WebpConverter\HookableInterface;
7
+ use WebpConverter\Conversion\OutputPath;
8
+
9
+ /**
10
+ * Returns various types of paths for directories.
11
+ */
12
+ class DirectoriesIntegration implements HookableInterface {
13
+
14
+ const DIRS_EXCLUDED = [ '.', '..', '.git', '.svn', 'node_modules' ];
15
+
16
+ /**
17
+ * Objects of supported directories.
18
+ *
19
+ * @var DirectoryInterface[]
20
+ */
21
+ private $directories = [];
22
+
23
+ /**
24
+ * Integrates with WordPress hooks.
25
+ *
26
+ * @return void
27
+ */
28
+ public function init_hooks() {
29
+ add_filter( 'webpc_dir_name', [ $this, 'get_dir_as_name' ], 0, 2 );
30
+ add_filter( 'webpc_dir_path', [ $this, 'get_dir_as_path' ], 0, 2 );
31
+ add_filter( 'webpc_dir_url', [ $this, 'get_dir_as_url' ], 0, 2 );
32
+ add_filter( 'webpc_uploads_prefix', [ $this, 'get_prefix_path' ], 0 );
33
+ add_filter( 'webpc_dir_excluded', [ $this, 'get_excluded_dirs' ], 0 );
34
+ }
35
+
36
+ /**
37
+ * Adds support of directory, if available.
38
+ *
39
+ * @param DirectoryInterface $directory .
40
+ *
41
+ * @return self
42
+ */
43
+ public function add_directory( DirectoryInterface $directory ): self {
44
+ if ( ! $directory->is_available() ) {
45
+ return $this;
46
+ }
47
+
48
+ $this->directories[ $directory->get_type() ] = $directory;
49
+ return $this;
50
+ }
51
+
52
+ /**
53
+ * Returns list of source directories.
54
+ *
55
+ * @return string[] Types of directories with labels.
56
+ */
57
+ public function get_input_directories(): array {
58
+ $values = [];
59
+ foreach ( $this->directories as $directory ) {
60
+ if ( ! $directory->is_output_directory() ) {
61
+ $values[ $directory->get_type() ] = $directory->get_label();
62
+ }
63
+ }
64
+ return $values;
65
+ }
66
+
67
+ /**
68
+ * Returns list of output directories.
69
+ *
70
+ * @return string[] Types of directories with labels.
71
+ */
72
+ public function get_output_directories(): array {
73
+ $values = [];
74
+ foreach ( $this->directories as $directory ) {
75
+ if ( ! $directory->is_output_directory()
76
+ && ( $output_path = OutputPath::get_directory_path( $directory->get_server_path() ) )
77
+ && ( $output_path !== $directory->get_server_path() ) ) {
78
+ $values[ $directory->get_type() ] = $output_path;
79
+ }
80
+ }
81
+ return $values;
82
+ }
83
+
84
+ /**
85
+ * Returns server path of directory relative to WordPress root directory.
86
+ *
87
+ * @param mixed $value Default value.
88
+ * @param string $directory_type Type of directory.
89
+ *
90
+ * @return string Relative server path of directory.
91
+ * @internal
92
+ */
93
+ public function get_dir_as_name( $value, string $directory_type ): string {
94
+ if ( isset( $this->directories[ $directory_type ] ) ) {
95
+ return $this->directories[ $directory_type ]->get_relative_path();
96
+ }
97
+ return $value;
98
+ }
99
+
100
+ /**
101
+ * Returns server path of directory.
102
+ *
103
+ * @param mixed $value Default value.
104
+ * @param string $directory_type Type of directory.
105
+ *
106
+ * @return string Server path of directory.
107
+ * @internal
108
+ */
109
+ public function get_dir_as_path( $value, string $directory_type ): string {
110
+ if ( isset( $this->directories[ $directory_type ] ) ) {
111
+ return $this->directories[ $directory_type ]->get_server_path();
112
+ } elseif ( ! ( $directory_name = apply_filters( 'webpc_dir_name', null, $directory_type ) ) ) {
113
+ return $value;
114
+ }
115
+
116
+ $source_path = apply_filters( 'webpc_site_root', realpath( ABSPATH ) );
117
+ return sprintf( '%1$s/%2$s', $source_path, $directory_name );
118
+ }
119
+
120
+ /**
121
+ * Returns URL of directory.
122
+ *
123
+ * @param mixed $value Default value.
124
+ * @param string $directory_type Type of directory.
125
+ *
126
+ * @return string URL of directory.
127
+ * @internal
128
+ */
129
+ public function get_dir_as_url( $value, string $directory_type ): string {
130
+ if ( isset( $this->directories[ $directory_type ] ) ) {
131
+ return $this->directories[ $directory_type ]->get_path_url();
132
+ } elseif ( ! ( $directory_name = apply_filters( 'webpc_dir_name', null, $directory_type ) ) ) {
133
+ return $value;
134
+ }
135
+
136
+ $source_url = apply_filters( 'webpc_site_url', get_site_url() );
137
+ return sprintf( '%1$s/%2$s', $source_url, $directory_name );
138
+ }
139
+
140
+ /**
141
+ * Returns prefix for wp-content directory for rules in .htaccess file.
142
+ *
143
+ * @return string Prefix for wp-content directory.
144
+ * @internal
145
+ */
146
+ public function get_prefix_path(): string {
147
+ $doc_dir = realpath( $_SERVER['DOCUMENT_ROOT'] ) ?: ''; // phpcs:ignore
148
+ $wp_rir = apply_filters( 'webpc_site_root', realpath( ABSPATH ) );
149
+ $diff_dir = trim( str_replace( $doc_dir, '', $wp_rir ), '\/' );
150
+ $diff_path = sprintf( '/%s/', $diff_dir );
151
+
152
+ return str_replace( '//', '/', $diff_path );
153
+ }
154
+
155
+ /**
156
+ * Returns list of directories excluded from source file search.
157
+ *
158
+ * @return string[] Relative paths of excluded directories.
159
+ * @internal
160
+ */
161
+ public function get_excluded_dirs(): array {
162
+ return self::DIRS_EXCLUDED;
163
+ }
164
+ }
src/Conversion/Directory/DirectoryAbstract.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
6
+
7
+ /**
8
+ * Abstract class for class that supports data about directory.
9
+ */
10
+ abstract class DirectoryAbstract implements DirectoryInterface {
11
+
12
+ /**
13
+ * Returns label of directory.
14
+ *
15
+ * @return string Directory label.
16
+ */
17
+ public function get_label(): string {
18
+ return '';
19
+ }
20
+
21
+ /**
22
+ * Returns status if directory is available.
23
+ *
24
+ * @return bool Directory is available?
25
+ */
26
+ public function is_available(): bool {
27
+ return ( file_exists( $this->get_server_path() ) );
28
+ }
29
+
30
+ /**
31
+ * Returns status if directory is destined for output.
32
+ *
33
+ * @return bool Directory for output?
34
+ */
35
+ public function is_output_directory(): bool {
36
+ return false;
37
+ }
38
+
39
+ /**
40
+ * Returns server path of directory.
41
+ *
42
+ * @return string Server path of directory.
43
+ */
44
+ public function get_server_path(): string {
45
+ $source_path = apply_filters( 'webpc_site_root', realpath( ABSPATH ) );
46
+ return sprintf( '%1$s/%2$s', $source_path, $this->get_relative_path() );
47
+ }
48
+
49
+ /**
50
+ * Returns URL of directory.
51
+ *
52
+ * @return string URL of directory.
53
+ */
54
+ public function get_path_url(): string {
55
+ $source_url = apply_filters( 'webpc_site_url', get_site_url() );
56
+ return sprintf( '%1$s/%2$s', $source_url, $this->get_relative_path() );
57
+ }
58
+ }
src/Conversion/Directory/DirectoryInterface.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ /**
6
+ * Interface for class that supports data about directory.
7
+ */
8
+ interface DirectoryInterface {
9
+
10
+ /**
11
+ * Returns type of directory.
12
+ *
13
+ * @return string Directory type.
14
+ */
15
+ public function get_type(): string;
16
+
17
+ /**
18
+ * Returns label of directory.
19
+ *
20
+ * @return string Directory label.
21
+ */
22
+ public function get_label(): string;
23
+
24
+ /**
25
+ * Returns status if directory is available.
26
+ *
27
+ * @return bool Directory is available?
28
+ */
29
+ public function is_available(): bool;
30
+
31
+ /**
32
+ * Returns status if directory is destined for output.
33
+ *
34
+ * @return bool Directory for output?
35
+ */
36
+ public function is_output_directory(): bool;
37
+
38
+ /**
39
+ * Returns relative path of directory.
40
+ *
41
+ * @return string Relative path of directory.
42
+ */
43
+ public function get_relative_path(): string;
44
+
45
+ /**
46
+ * Returns server path of directory.
47
+ *
48
+ * @return string Server path of directory.
49
+ */
50
+ public function get_server_path(): string;
51
+
52
+ /**
53
+ * Returns URL of directory.
54
+ *
55
+ * @return string URL of directory.
56
+ */
57
+ public function get_path_url(): string;
58
+ }
src/Conversion/Directory/GalleryDirectory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryAbstract;
6
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
7
+
8
+ /**
9
+ * Supports data about /gallery directory.
10
+ */
11
+ class GalleryDirectory extends DirectoryAbstract implements DirectoryInterface {
12
+
13
+ const DIRECTORY_TYPE = 'gallery';
14
+ const DIRECTORY_PATH = 'wp-content/gallery';
15
+
16
+ /**
17
+ * Returns type of directory.
18
+ *
19
+ * @return string Directory type.
20
+ */
21
+ public function get_type(): string {
22
+ return self::DIRECTORY_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns label of directory.
27
+ *
28
+ * @return string Directory label.
29
+ */
30
+ public function get_label(): string {
31
+ return '/' . self::DIRECTORY_TYPE;
32
+ }
33
+
34
+ /**
35
+ * Returns relative path of directory.
36
+ *
37
+ * @return string Relative path of directory.
38
+ */
39
+ public function get_relative_path(): string {
40
+ return self::DIRECTORY_PATH;
41
+ }
42
+ }
src/Conversion/Directory/PluginsDirectory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryAbstract;
6
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
7
+
8
+ /**
9
+ * Supports data about /plugins directory.
10
+ */
11
+ class PluginsDirectory extends DirectoryAbstract implements DirectoryInterface {
12
+
13
+ const DIRECTORY_TYPE = 'plugins';
14
+ const DIRECTORY_PATH = 'wp-content/plugins';
15
+
16
+ /**
17
+ * Returns type of directory.
18
+ *
19
+ * @return string Directory type.
20
+ */
21
+ public function get_type(): string {
22
+ return self::DIRECTORY_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns label of directory.
27
+ *
28
+ * @return string Directory label.
29
+ */
30
+ public function get_label(): string {
31
+ return '/' . self::DIRECTORY_TYPE;
32
+ }
33
+
34
+ /**
35
+ * Returns relative path of directory.
36
+ *
37
+ * @return string Relative path of directory.
38
+ */
39
+ public function get_relative_path(): string {
40
+ return self::DIRECTORY_PATH;
41
+ }
42
+ }
src/Conversion/Directory/ThemesDirectory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryAbstract;
6
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
7
+
8
+ /**
9
+ * Supports data about /themes directory.
10
+ */
11
+ class ThemesDirectory extends DirectoryAbstract implements DirectoryInterface {
12
+
13
+ const DIRECTORY_TYPE = 'themes';
14
+ const DIRECTORY_PATH = 'wp-content/themes';
15
+
16
+ /**
17
+ * Returns type of directory.
18
+ *
19
+ * @return string Directory type.
20
+ */
21
+ public function get_type(): string {
22
+ return self::DIRECTORY_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns label of directory.
27
+ *
28
+ * @return string Directory label.
29
+ */
30
+ public function get_label(): string {
31
+ return '/' . self::DIRECTORY_TYPE;
32
+ }
33
+
34
+ /**
35
+ * Returns relative path of directory.
36
+ *
37
+ * @return string Relative path of directory.
38
+ */
39
+ public function get_relative_path(): string {
40
+ return self::DIRECTORY_PATH;
41
+ }
42
+ }
src/Conversion/Directory/UploadsDirectory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryAbstract;
6
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
7
+
8
+ /**
9
+ * Supports data about /uploads directory.
10
+ */
11
+ class UploadsDirectory extends DirectoryAbstract implements DirectoryInterface {
12
+
13
+ const DIRECTORY_TYPE = 'uploads';
14
+ const DIRECTORY_PATH = 'wp-content/uploads';
15
+
16
+ /**
17
+ * Returns type of directory.
18
+ *
19
+ * @return string Directory type.
20
+ */
21
+ public function get_type(): string {
22
+ return self::DIRECTORY_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns label of directory.
27
+ *
28
+ * @return string Directory label.
29
+ */
30
+ public function get_label(): string {
31
+ return '/' . self::DIRECTORY_TYPE;
32
+ }
33
+
34
+ /**
35
+ * Returns relative path of directory.
36
+ *
37
+ * @return string Relative path of directory.
38
+ */
39
+ public function get_relative_path(): string {
40
+ return self::DIRECTORY_PATH;
41
+ }
42
+ }
src/Conversion/Directory/UploadsWebpcDirectory.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Directory;
4
+
5
+ use WebpConverter\Conversion\Directory\DirectoryAbstract;
6
+ use WebpConverter\Conversion\Directory\DirectoryInterface;
7
+
8
+ /**
9
+ * Supports data about /uploads-webpc directory.
10
+ */
11
+ class UploadsWebpcDirectory extends DirectoryAbstract implements DirectoryInterface {
12
+
13
+ const DIRECTORY_TYPE = 'webp';
14
+ const DIRECTORY_PATH = 'wp-content/uploads-webpc';
15
+
16
+ /**
17
+ * Returns type of directory.
18
+ *
19
+ * @return string Directory type.
20
+ */
21
+ public function get_type(): string {
22
+ return self::DIRECTORY_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns status if directory is available.
27
+ *
28
+ * @return bool Directory is available?
29
+ */
30
+ public function is_available(): bool {
31
+ return true;
32
+ }
33
+
34
+ /**
35
+ * Returns status if directory is destined for output.
36
+ *
37
+ * @return bool Directory for output?
38
+ */
39
+ public function is_output_directory(): bool {
40
+ return true;
41
+ }
42
+
43
+ /**
44
+ * Returns relative path of directory.
45
+ *
46
+ * @return string Relative path of directory.
47
+ */
48
+ public function get_relative_path(): string {
49
+ return self::DIRECTORY_PATH;
50
+ }
51
+ }
src/Conversion/DirectoryFiles.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+
9
+ /**
10
+ * Returns paths to files in given directory.
11
+ */
12
+ class DirectoryFiles extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
13
+
14
+ /**
15
+ * Integrates with WordPress hooks.
16
+ *
17
+ * @return void
18
+ */
19
+ public function init_hooks() {
20
+ add_filter( 'webpc_dir_files', [ $this, 'get_files_by_directory' ], 10, 3 );
21
+ }
22
+
23
+ /**
24
+ * Returns list of source images for directory.
25
+ *
26
+ * @param string[] $value Server paths of source images.
27
+ * @param string $dir_path Server path of source directory.
28
+ * @param bool $skip_exists Skip images already converted?
29
+ *
30
+ * @return string[] Server paths of source images.
31
+ * @internal
32
+ */
33
+ public function get_files_by_directory( array $value, string $dir_path, bool $skip_exists = false ): array {
34
+ if ( ! file_exists( $dir_path ) ) {
35
+ return $value;
36
+ }
37
+
38
+ $settings = $this->get_plugin()->get_settings();
39
+ $excluded = apply_filters( 'webpc_dir_excluded', [] );
40
+
41
+ $paths = $this->find_files_in_directory( $dir_path, $settings['extensions'], $excluded );
42
+ return apply_filters( 'webpc_files_paths', $paths, $skip_exists );
43
+ }
44
+
45
+ /**
46
+ * Returns list of source images for directory.
47
+ *
48
+ * @param string $dir_path Server path of source directory.
49
+ * @param string[] $allowed_exts File extensions to find.
50
+ * @param string[] $excluded_dirs Directories to ignore search.
51
+ *
52
+ * @return string[] Server paths of source images.
53
+ */
54
+ private function find_files_in_directory( string $dir_path, array $allowed_exts, array $excluded_dirs ): array {
55
+ $paths = scandir( $dir_path );
56
+ $list = [];
57
+ if ( ! is_array( $paths ) ) {
58
+ return $list;
59
+ }
60
+
61
+ foreach ( $paths as $path ) {
62
+ if ( in_array( $path, $excluded_dirs ) ) {
63
+ continue;
64
+ }
65
+
66
+ $current_path = $dir_path . '/' . urlencode( $path ); // phpcs:ignore
67
+ if ( is_dir( $current_path ) ) {
68
+ $list = array_merge( $list, $this->find_files_in_directory( $current_path, $allowed_exts, $excluded_dirs ) );
69
+ } elseif ( in_array( strtolower( pathinfo( $current_path, PATHINFO_EXTENSION ) ), $allowed_exts ) ) {
70
+ $list[] = $current_path;
71
+ }
72
+ }
73
+ return $list;
74
+ }
75
+ }
src/Conversion/Endpoint/EndpointAbstract.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Endpoint;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Conversion\Endpoint\EndpointInterface;
8
+
9
+ /**
10
+ * Abstract class for class that supports image conversion method.
11
+ */
12
+ abstract class EndpointAbstract extends PluginAccessAbstract implements PluginAccessInterface, EndpointInterface {
13
+
14
+ /**
15
+ * Returns list of params for endpoint.
16
+ *
17
+ * @return array[] Params of endpoint.
18
+ */
19
+ public function get_route_args(): array {
20
+ return [];
21
+ }
22
+
23
+ /**
24
+ * Returns URL of endpoint.
25
+ *
26
+ * @return string Endpoint URL.
27
+ */
28
+ public function get_route_url(): string {
29
+ return get_rest_url(
30
+ null,
31
+ sprintf(
32
+ '%1$s/%2$s?_wpnonce=%3$s',
33
+ EndpointIntegration::ROUTE_NAMESPACE,
34
+ $this->get_route_name(),
35
+ wp_create_nonce( 'wp_rest' )
36
+ )
37
+ );
38
+ }
39
+ }
src/Conversion/Endpoint/EndpointIntegration.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Endpoint;
4
+
5
+ use WebpConverter\Conversion\Endpoint\EndpointInterface;
6
+ use WebpConverter\HookableInterface;
7
+
8
+ /**
9
+ * Integrates endpoint class by registering REST API route.
10
+ */
11
+ class EndpointIntegration implements HookableInterface {
12
+
13
+ const ROUTE_NAMESPACE = 'webp-converter/v1';
14
+
15
+ /**
16
+ * Objects of supported REST API endpoints.
17
+ *
18
+ * @var EndpointInterface
19
+ */
20
+ private $endpoint_object;
21
+
22
+ /**
23
+ * EndpointIntegration constructor.
24
+ *
25
+ * @param EndpointInterface $endpoint_object .
26
+ */
27
+ public function __construct( EndpointInterface $endpoint_object ) {
28
+ $this->endpoint_object = $endpoint_object;
29
+ }
30
+
31
+ /**
32
+ * Integrates with WordPress hooks.
33
+ *
34
+ * @return void
35
+ */
36
+ public function init_hooks() {
37
+ add_action( 'rest_api_init', [ $this, 'register_rest_route' ] );
38
+ }
39
+
40
+ /**
41
+ * Registers new endpoint in REST API.
42
+ *
43
+ * @return void
44
+ * @internal
45
+ */
46
+ public function register_rest_route() {
47
+ register_rest_route(
48
+ self::ROUTE_NAMESPACE,
49
+ $this->endpoint_object->get_route_name(),
50
+ [
51
+ 'methods' => \WP_REST_Server::ALLMETHODS,
52
+ 'permission_callback' => function () {
53
+ return ( wp_verify_nonce( $_REQUEST['_wpnonce'] ?? '', 'wp_rest' ) // phpcs:ignore
54
+ && current_user_can( 'manage_options' ) );
55
+ },
56
+ 'callback' => [ $this->endpoint_object, 'get_route_response' ],
57
+ 'args' => $this->endpoint_object->get_route_args(),
58
+ ]
59
+ );
60
+ }
61
+ }
src/Conversion/Endpoint/EndpointInterface.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Endpoint;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+
7
+ /**
8
+ * Interface for class that supports endpoint.
9
+ */
10
+ interface EndpointInterface extends PluginAccessInterface {
11
+
12
+ /**
13
+ * Returns route of endpoint.
14
+ *
15
+ * @return string Endpoint route.
16
+ */
17
+ public function get_route_name(): string;
18
+
19
+ /**
20
+ * Returns list of params for endpoint.
21
+ *
22
+ * @return array[] Params of endpoint.
23
+ */
24
+ public function get_route_args(): array;
25
+
26
+ /**
27
+ * Returns URL of endpoint.
28
+ *
29
+ * @return string Endpoint URL.
30
+ */
31
+ public function get_route_url(): string;
32
+
33
+ /**
34
+ * Returns response to endpoint.
35
+ *
36
+ * @param \WP_REST_Request $request REST request object.
37
+ *
38
+ * @return \WP_REST_Response|\WP_Error REST response object or WordPress Error object.
39
+ * @internal
40
+ */
41
+ public function get_route_response( \WP_REST_Request $request );
42
+ }
src/Conversion/Endpoint/PathsEndpoint.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Endpoint;
4
+
5
+ use WebpConverter\Conversion\Endpoint\EndpointAbstract;
6
+ use WebpConverter\Conversion\Endpoint\EndpointInterface;
7
+ use WebpConverter\Conversion\Endpoint\EndpointIntegration;
8
+
9
+ /**
10
+ * Supports endpoint to get list of image paths to be converted.
11
+ */
12
+ class PathsEndpoint extends EndpointAbstract implements EndpointInterface {
13
+
14
+ const PATHS_PER_REQUEST = 10;
15
+
16
+ /**
17
+ * Returns route of endpoint.
18
+ *
19
+ * @return string Endpoint route.
20
+ */
21
+ public function get_route_name(): string {
22
+ return 'paths';
23
+ }
24
+
25
+ /**
26
+ * Returns list of params for endpoint.
27
+ *
28
+ * @return array[] Params of endpoint.
29
+ */
30
+ public function get_route_args(): array {
31
+ return [
32
+ 'regenerate_force' => [
33
+ 'description' => 'Option to force all images to be converted again (set `1` to enable)',
34
+ 'required' => false,
35
+ 'default' => false,
36
+ 'sanitize_callback' => function ( $value ) {
37
+ return ( $value === '1' );
38
+ },
39
+ ],
40
+ ];
41
+ }
42
+
43
+ /**
44
+ * Returns response to endpoint.
45
+ *
46
+ * @param \WP_REST_Request $request REST request object.
47
+ *
48
+ * @return \WP_REST_Response REST response object or WordPress Error object.
49
+ * @internal
50
+ */
51
+ public function get_route_response( \WP_REST_Request $request ) {
52
+ $params = $request->get_params();
53
+ $skip_exists = isset( $params['regenerate_force'] ) && ! $params['regenerate_force'];
54
+
55
+ $data = $this->get_paths( $skip_exists, self::PATHS_PER_REQUEST );
56
+ return new \WP_REST_Response(
57
+ $data,
58
+ 200
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Returns list of server paths of source images to be converted.
64
+ *
65
+ * @param bool $skip_exists Skip converted images?
66
+ * @param int $chunk_size Number of files per one conversion request.
67
+ *
68
+ * @return array[] Server paths of source images.
69
+ */
70
+ public function get_paths( bool $skip_exists = false, int $chunk_size = 0 ): array {
71
+ $settings = $this->get_plugin()->get_settings();
72
+ $dirs = array_filter(
73
+ array_map(
74
+ function ( $dir_name ) {
75
+ return apply_filters( 'webpc_dir_path', '', $dir_name );
76
+ },
77
+ $settings['dirs']
78
+ )
79
+ );
80
+
81
+ $list = [];
82
+ foreach ( $dirs as $dir_path ) {
83
+ $paths = apply_filters( 'webpc_dir_files', [], $dir_path, $skip_exists );
84
+ $list = array_merge( $list, $paths );
85
+ }
86
+
87
+ if ( $chunk_size === 0 ) {
88
+ return $list;
89
+ }
90
+ return array_chunk( $list, $chunk_size );
91
+ }
92
+ }
src/Conversion/Endpoint/RegenerateEndpoint.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Endpoint;
4
+
5
+ use WebpConverter\Conversion\Endpoint\EndpointAbstract;
6
+ use WebpConverter\Conversion\Endpoint\EndpointInterface;
7
+ use WebpConverter\Conversion\Method\MethodIntegrator;
8
+
9
+ /**
10
+ * Supports endpoint for converting list of paths to images.
11
+ */
12
+ class RegenerateEndpoint extends EndpointAbstract implements EndpointInterface {
13
+
14
+ /**
15
+ * Returns route of endpoint.
16
+ *
17
+ * @return string Endpoint route.
18
+ */
19
+ public function get_route_name(): string {
20
+ return 'regenerate';
21
+ }
22
+
23
+ /**
24
+ * Returns list of params for endpoint.
25
+ *
26
+ * @return array[] Params of endpoint.
27
+ */
28
+ public function get_route_args(): array {
29
+ return [
30
+ 'paths' => [
31
+ 'description' => 'Array of file paths (server paths)',
32
+ 'required' => true,
33
+ 'default' => [],
34
+ 'validate_callback' => function ( $value ) {
35
+ return ( is_array( $value ) && $value );
36
+ },
37
+ ],
38
+ ];
39
+ }
40
+
41
+ /**
42
+ * Returns response to endpoint.
43
+ *
44
+ * @param \WP_REST_Request $request REST request object.
45
+ *
46
+ * @return \WP_REST_Response|\WP_Error REST response object or WordPress Error object.
47
+ * @internal
48
+ */
49
+ public function get_route_response( \WP_REST_Request $request ) {
50
+ $params = $request->get_params();
51
+ $data = $this->convert_images( $params['paths'] );
52
+ if ( $data !== false ) {
53
+ return new \WP_REST_Response(
54
+ $data,
55
+ 200
56
+ );
57
+ } else {
58
+ return new \WP_Error(
59
+ 'webpc_rest_api_error',
60
+ '',
61
+ [
62
+ 'status' => 405,
63
+ ]
64
+ );
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Initializes image conversion to output formats.
70
+ *
71
+ * @param string[] $paths Server paths of source images.
72
+ *
73
+ * @return array[]|false Status of conversion.
74
+ */
75
+ public function convert_images( array $paths ) {
76
+ $method_integrator = new MethodIntegrator();
77
+ $method_integrator->set_plugin( $this->get_plugin() );
78
+
79
+ $response = $method_integrator->init_conversion( $paths );
80
+ if ( $response === null ) {
81
+ return false;
82
+ }
83
+ return $response;
84
+ }
85
+ }
src/Conversion/Endpoints.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Endpoint\EndpointInterface;
9
+ use WebpConverter\Conversion\Endpoint\EndpointIntegration;
10
+ use WebpConverter\Conversion\Endpoint\PathsEndpoint;
11
+ use WebpConverter\Conversion\Endpoint\RegenerateEndpoint;
12
+
13
+ /**
14
+ * Initializes integration for all endpoints.
15
+ */
16
+ class Endpoints extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
17
+
18
+ /**
19
+ * Integrates with WordPress hooks.
20
+ *
21
+ * @return void
22
+ */
23
+ public function init_hooks() {
24
+ $this->set_integration( new PathsEndpoint() );
25
+ $this->set_integration( new RegenerateEndpoint() );
26
+ }
27
+
28
+ /**
29
+ * Sets integration for endpoint.
30
+ *
31
+ * @param EndpointInterface $endpoint .
32
+ *
33
+ * @return void
34
+ */
35
+ private function set_integration( EndpointInterface $endpoint ) {
36
+ $endpoint->set_plugin( $this->get_plugin() );
37
+ ( new EndpointIntegration( $endpoint ) )->init_hooks();
38
+ }
39
+ }
src/Conversion/Exception/ConversionErrorException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "convert_error" exception when converting images.
10
+ */
11
+ class ConversionErrorException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Error occurred while converting image: "%s".';
14
+ const ERROR_CODE = 'convert_error';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ExceptionAbstract.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
6
+
7
+ /**
8
+ * Abstract class for class that supports exception when converting images.
9
+ */
10
+ abstract class ExceptionAbstract extends \Exception implements ExceptionInterface {
11
+
12
+ /**
13
+ * ExceptionInterface constructor.
14
+ *
15
+ * @param string[]|string $value Params of exception.
16
+ */
17
+ final public function __construct( $value = [] ) {
18
+ $this->code = $this->get_error_status();
19
+ parent::__construct( $this->get_error_message( (array) $value ) );
20
+ }
21
+ }
src/Conversion/Exception/ExceptionInterface.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ /**
6
+ * Interface for class that supports exception when converting images.
7
+ */
8
+ interface ExceptionInterface {
9
+
10
+ /**
11
+ * ExceptionInterface constructor.
12
+ *
13
+ * @param string[]|string $value Params of exception.
14
+ */
15
+ public function __construct( $value = [] );
16
+
17
+ /**
18
+ * Returns message of error.
19
+ *
20
+ * @param string[] $values Params from class constructor.
21
+ *
22
+ * @return string Error message.
23
+ */
24
+ public function get_error_message( array $values ): string;
25
+
26
+ /**
27
+ * Returns status of error.
28
+ *
29
+ * @return string Error status.
30
+ */
31
+ public function get_error_status(): string;
32
+ }
src/Conversion/Exception/ExtensionUnsupportedException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "unsupported_extension" exception when converting images.
10
+ */
11
+ class ExtensionUnsupportedException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Unsupported extension "%s" for file "%s".';
14
+ const ERROR_CODE = 'unsupported_extension';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0], $values[1] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/FunctionUnavailableException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "server_configuration" exception when converting images.
10
+ */
11
+ class FunctionUnavailableException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Server configuration: "%s" function is not available.';
14
+ const ERROR_CODE = 'server_configuration';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ImageInvalidException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "invalid_image" exception when converting images.
10
+ */
11
+ class ImageInvalidException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = '"%s" is not a valid image file.';
14
+ const ERROR_CODE = 'invalid_image';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ImagickNotSupportWebpException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "server_configuration" exception when converting images.
10
+ */
11
+ class ImagickNotSupportWebpException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Server configuration: Imagick does not support WebP format.';
14
+ const ERROR_CODE = 'server_configuration';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return self::ERROR_MESSAGE;
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ImagickUnavailableException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "server_configuration" exception when converting images.
10
+ */
11
+ class ImagickUnavailableException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Server configuration: Imagick module is not available with this PHP installation.';
14
+ const ERROR_CODE = 'server_configuration';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return self::ERROR_MESSAGE;
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/LargerThanOriginalException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "larger_than_original" exception when converting images.
10
+ */
11
+ class LargerThanOriginalException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Image "%s" converted to WebP is larger than original and has been deleted.';
14
+ const ERROR_CODE = 'larger_than_original';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/OutputPathException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "output_path" exception when converting images.
10
+ */
11
+ class OutputPathException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'An error occurred creating destination directory for "%s" file.';
14
+ const ERROR_CODE = 'output_path';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ResolutionOversizeException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "max_resolution" exception when converting images.
10
+ */
11
+ class ResolutionOversizeException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Image is larger than maximum 8K resolution: "%s".';
14
+ const ERROR_CODE = 'max_resolution';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/ServerConfigurationException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "server_configuration" exception when converting images.
10
+ */
11
+ class ServerConfigurationException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Server configuration: "%s" function is not available.';
14
+ const ERROR_CODE = 'server_configuration';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Exception/SourcePathException.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Exception;
4
+
5
+ use WebpConverter\Conversion\Exception\ExceptionAbstract;
6
+ use WebpConverter\Conversion\Exception\ExceptionInterface;
7
+
8
+ /**
9
+ * Handles "file_unreadable" exception when converting images.
10
+ */
11
+ class SourcePathException extends ExceptionAbstract implements ExceptionInterface {
12
+
13
+ const ERROR_MESSAGE = 'Source path "%s" for image does not exist or is unreadable.';
14
+ const ERROR_CODE = 'file_unreadable';
15
+
16
+ /**
17
+ * Returns message of error.
18
+ *
19
+ * @param string[] $values Params from class constructor.
20
+ *
21
+ * @return string Error message.
22
+ */
23
+ public function get_error_message( array $values ): string {
24
+ return sprintf( self::ERROR_MESSAGE, $values[0] );
25
+ }
26
+
27
+ /**
28
+ * Returns status of error.
29
+ *
30
+ * @return string Error status.
31
+ */
32
+ public function get_error_status(): string {
33
+ return self::ERROR_CODE;
34
+ }
35
+ }
src/Conversion/Format/AvifFormat.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Format;
4
+
5
+ use WebpConverter\Conversion\Format\FormatAbstract;
6
+ use WebpConverter\Conversion\Format\FormatInterface;
7
+
8
+ /**
9
+ * Supports AVIF as output format for images.
10
+ */
11
+ class AvifFormat extends FormatAbstract implements FormatInterface {
12
+
13
+ const FORMAT_EXTENSION = 'avif';
14
+
15
+ /**
16
+ * Returns extension of output format.
17
+ *
18
+ * @return string Format extension
19
+ */
20
+ public function get_extension(): string {
21
+ return self::FORMAT_EXTENSION;
22
+ }
23
+
24
+ /**
25
+ * Returns mime type of output format.
26
+ *
27
+ * @return string Format mime type
28
+ */
29
+ public function get_mime_type(): string {
30
+ return 'image/avif';
31
+ }
32
+
33
+ /**
34
+ * Returns label of output format.
35
+ *
36
+ * @return string Format label.
37
+ */
38
+ public function get_label(): string {
39
+ /* translators: %s format name */
40
+ return sprintf( __( '%s (planned soon)', 'webp-converter-for-media' ), 'AVIF' );
41
+ }
42
+
43
+ /**
44
+ * Returns status is output format available?
45
+ *
46
+ * @param string $conversion_method Type of conversion method.
47
+ *
48
+ * @return bool Is format available?
49
+ */
50
+ public function is_available( string $conversion_method ): bool {
51
+ return false;
52
+ }
53
+ }
src/Conversion/Format/FormatAbstract.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Format;
4
+
5
+ use WebpConverter\Conversion\Format\FormatInterface;
6
+ use WebpConverter\Conversion\Methods;
7
+
8
+ /**
9
+ * Abstract class for class that supports output format for images.
10
+ */
11
+ abstract class FormatAbstract implements FormatInterface {
12
+
13
+ /**
14
+ * Returns label of output format.
15
+ *
16
+ * @return string Format label.
17
+ */
18
+ public function get_label(): string {
19
+ return sprintf( '.%s', $this->get_extension() );
20
+ }
21
+
22
+ /**
23
+ * Returns status is output format available?
24
+ *
25
+ * @param string $conversion_method Type of conversion method.
26
+ *
27
+ * @return bool Is format available?
28
+ */
29
+ public function is_available( string $conversion_method ): bool {
30
+ return ( new Methods() )->is_method_available( $conversion_method, $this->get_extension() );
31
+ }
32
+ }
src/Conversion/Format/FormatInterface.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Format;
4
+
5
+ /**
6
+ * Interface for class that supports output format for images.
7
+ */
8
+ interface FormatInterface {
9
+
10
+ /**
11
+ * Returns extension of output format.
12
+ *
13
+ * @return string Format extension
14
+ */
15
+ public function get_extension(): string;
16
+
17
+ /**
18
+ * Returns mime type of output format.
19
+ *
20
+ * @return string Format mime type
21
+ */
22
+ public function get_mime_type(): string;
23
+
24
+ /**
25
+ * Returns label of output format.
26
+ *
27
+ * @return string Format label.
28
+ */
29
+ public function get_label(): string;
30
+
31
+ /**
32
+ * Returns status is output format available?
33
+ *
34
+ * @param string $conversion_method Type of conversion method.
35
+ *
36
+ * @return bool Is format available?
37
+ */
38
+ public function is_available( string $conversion_method ): bool;
39
+ }
src/Conversion/Format/WebpFormat.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Format;
4
+
5
+ use WebpConverter\Conversion\Format\FormatAbstract;
6
+ use WebpConverter\Conversion\Format\FormatInterface;
7
+
8
+ /**
9
+ * Supports WebP as output format for images.
10
+ */
11
+ class WebpFormat extends FormatAbstract implements FormatInterface {
12
+
13
+ const FORMAT_EXTENSION = 'webp';
14
+
15
+ /**
16
+ * Returns extension of output format.
17
+ *
18
+ * @return string Format extension
19
+ */
20
+ public function get_extension(): string {
21
+ return self::FORMAT_EXTENSION;
22
+ }
23
+
24
+ /**
25
+ * Returns mime type of output format.
26
+ *
27
+ * @return string Format mime type
28
+ */
29
+ public function get_mime_type(): string {
30
+ return 'image/webp';
31
+ }
32
+
33
+ /**
34
+ * Returns label of output format.
35
+ *
36
+ * @return string Format label.
37
+ */
38
+ public function get_label(): string {
39
+ return 'WebP';
40
+ }
41
+ }
src/Conversion/Formats.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\Conversion\Format\FormatInterface;
6
+ use WebpConverter\Conversion\Format\AvifFormat;
7
+ use WebpConverter\Conversion\Format\WebpFormat;
8
+
9
+ /**
10
+ * Adds support for all output formats and returns information about them.
11
+ */
12
+ class Formats {
13
+
14
+ /**
15
+ * Objects of supported output formats.
16
+ *
17
+ * @var FormatInterface[]
18
+ */
19
+ private $formats = [];
20
+
21
+ /**
22
+ * Formats constructor.
23
+ */
24
+ public function __construct() {
25
+ $this->formats[] = new AvifFormat();
26
+ $this->formats[] = new WebpFormat();
27
+ }
28
+
29
+ /**
30
+ * Returns list of output formats.
31
+ *
32
+ * @return string[] Extensions of output formats with labels.
33
+ */
34
+ public function get_formats(): array {
35
+ $values = [];
36
+ foreach ( $this->formats as $format ) {
37
+ $values[ $format->get_extension() ] = $format->get_label();
38
+ }
39
+ return $values;
40
+ }
41
+
42
+ /**
43
+ * Returns list of available output formats.
44
+ *
45
+ * @param string $conversion_method Name of conversion method.
46
+ *
47
+ * @return string[] Extensions of output formats with labels.
48
+ */
49
+ public function get_available_formats( string $conversion_method ): array {
50
+ $values = [];
51
+ foreach ( $this->formats as $format ) {
52
+ if ( ! $format->is_available( $conversion_method ) ) {
53
+ continue;
54
+ }
55
+ $values[ $format->get_extension() ] = $format->get_label();
56
+ }
57
+ return $values;
58
+ }
59
+
60
+ /**
61
+ * Returns extensions of output formats.
62
+ *
63
+ * @return string[] Extensions of output formats.
64
+ */
65
+ public function get_format_extensions(): array {
66
+ $values = [];
67
+ foreach ( $this->formats as $format ) {
68
+ $values[] = $format->get_extension();
69
+ }
70
+ return $values;
71
+ }
72
+
73
+ /**
74
+ * Returns mime types of output formats.
75
+ *
76
+ * @param string[] $output_formats Extensions of output formats.
77
+ *
78
+ * @return string[] Mime types of output formats.
79
+ */
80
+ public function get_mime_types( array $output_formats ): array {
81
+ $values = [];
82
+ foreach ( $this->formats as $format ) {
83
+ if ( ! in_array( $format->get_extension(), $output_formats ) ) {
84
+ continue;
85
+ }
86
+ $values[ $format->get_extension() ] = $format->get_mime_type();
87
+ }
88
+ return $values;
89
+ }
90
+ }
src/Conversion/Media/Attachment.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Media;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+
8
+ /**
9
+ * Returns all image paths for attachment.
10
+ */
11
+ class Attachment extends PluginAccessAbstract implements PluginAccessInterface {
12
+
13
+ /**
14
+ * Current upload directory path and URL.
15
+ *
16
+ * @var string[]
17
+ */
18
+ private $upload_dir;
19
+
20
+ /**
21
+ * Available intermediate image size names.
22
+ *
23
+ * @var string[]
24
+ */
25
+ private $image_sizes;
26
+
27
+ /**
28
+ * Attachment constructor.
29
+ */
30
+ public function __construct() {
31
+ $this->upload_dir = wp_upload_dir();
32
+ $this->image_sizes = get_intermediate_image_sizes();
33
+ }
34
+
35
+ /**
36
+ * Returns server paths to source images of attachment.
37
+ *
38
+ * @param int $attachment_id ID of attachment.
39
+ *
40
+ * @return string[] Server paths of source images.
41
+ */
42
+ public function get_attachment_paths( int $attachment_id ): array {
43
+ $settings = $this->get_plugin()->get_settings();
44
+ return $this->get_paths_by_attachment( $attachment_id, $settings );
45
+ }
46
+
47
+ /**
48
+ * Returns server paths to source images of attachment by file extensions.
49
+ *
50
+ * @param int $post_id ID of attachment.
51
+ * @param mixed[] $settings Plugin settings.
52
+ *
53
+ * @return string[] Server paths of source images.
54
+ */
55
+ private function get_paths_by_attachment( int $post_id, array $settings ): array {
56
+ $list = [];
57
+ $metadata = wp_get_attachment_metadata( $post_id );
58
+ if ( ! $metadata ) {
59
+ return $list;
60
+ }
61
+
62
+ $extension = strtolower( pathinfo( $metadata['file'], PATHINFO_EXTENSION ) );
63
+ if ( ! isset( $metadata['file'] )
64
+ || ! in_array( $extension, $settings['extensions'] ) ) {
65
+ return $list;
66
+ }
67
+
68
+ $paths = $this->get_paths_by_sizes( $post_id, $metadata['file'] );
69
+ $paths = apply_filters( 'webpc_attachment_paths', $paths, $post_id );
70
+ $paths = apply_filters( 'webpc_files_paths', $paths, false );
71
+ return $paths;
72
+ }
73
+
74
+ /**
75
+ * Returns unique server paths to source images of attachment.
76
+ *
77
+ * @param int $post_id ID of attachment.
78
+ * @param string $path Path of source image.
79
+ *
80
+ * @return string[] Server paths of source images.
81
+ */
82
+ private function get_paths_by_sizes( int $post_id, string $path ): array {
83
+ $list = [];
84
+ $list[] = str_replace( '\\', '/', implode( '/', [ $this->upload_dir['basedir'], $path ] ) );
85
+
86
+ foreach ( $this->image_sizes as $size ) {
87
+ $src = wp_get_attachment_image_src( $post_id, $size );
88
+ if ( ! is_array( $src ) || ! is_string( $src[0] ) ) {
89
+ continue;
90
+ }
91
+
92
+ $url = str_replace( $this->upload_dir['baseurl'], $this->upload_dir['basedir'], $src[0] );
93
+ $url = str_replace( '\\', '/', $url );
94
+ $list[] = $url;
95
+ }
96
+ return array_values( array_unique( $list ) );
97
+ }
98
+ }
src/Conversion/Media/Delete.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Media;
4
+
5
+ use WebpConverter\HookableInterface;
6
+
7
+ /**
8
+ * Removes image from its output format when removing image from media library.
9
+ */
10
+ class Delete implements HookableInterface {
11
+
12
+ /**
13
+ * Integrates with WordPress hooks.
14
+ *
15
+ * @return void
16
+ */
17
+ public function init_hooks() {
18
+ add_filter( 'wp_delete_file', [ $this, 'delete_attachment_file' ] );
19
+ }
20
+
21
+ /**
22
+ * Deletes output image based on server path of source image.
23
+ *
24
+ * @param string $path Server path of source image.
25
+ *
26
+ * @return string Server path of source image.
27
+ * @internal
28
+ */
29
+ public function delete_attachment_file( string $path ): string {
30
+ do_action( 'webpc_delete_paths', [ $path ] );
31
+ return $path;
32
+ }
33
+ }
src/Conversion/Media/Upload.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Media;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+
9
+ /**
10
+ * Initializes image conversion when uploading images to media library.
11
+ */
12
+ class Upload extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
13
+
14
+ /**
15
+ * Paths of converted images.
16
+ *
17
+ * @var string[]
18
+ */
19
+ private $converted_paths = [];
20
+
21
+ /**
22
+ * Integrates with WordPress hooks.
23
+ *
24
+ * @return void
25
+ */
26
+ public function init_hooks() {
27
+ add_filter( 'wp_update_attachment_metadata', [ $this, 'init_attachment_convert' ], 10, 2 );
28
+ }
29
+
30
+ /**
31
+ * Initializes converting attachment images while attachment is uploaded.
32
+ *
33
+ * @param mixed[] $data Updated attachment meta data.
34
+ * @param int $attachment_id ID of attachment.
35
+ *
36
+ * @return mixed[] Attachment meta data.
37
+ * @internal
38
+ */
39
+ public function init_attachment_convert( array $data, int $attachment_id ): array {
40
+ if ( ! $data || ! isset( $data['file'] ) || ! isset( $data['sizes'] ) ) {
41
+ return $data;
42
+ }
43
+
44
+ $paths = $this->get_sizes_paths( $data );
45
+ $paths = apply_filters( 'webpc_attachment_paths', $paths, $attachment_id );
46
+ $paths = apply_filters( 'webpc_files_paths', $paths, false );
47
+
48
+ $paths = array_diff( $paths, $this->converted_paths );
49
+ $this->converted_paths = array_merge( $this->converted_paths, $paths );
50
+ $this->init_conversion( $paths );
51
+
52
+ return $data;
53
+ }
54
+
55
+ /**
56
+ * Returns server paths of attachment image sizes.
57
+ *
58
+ * @param mixed[] $data Updated attachment meta data.
59
+ *
60
+ * @return string[] Server paths of source images.
61
+ */
62
+ private function get_sizes_paths( array $data ): array {
63
+ $directory = $this->get_attachment_directory( $data['file'] );
64
+ $list = [];
65
+
66
+ $list[] = $directory . basename( $data['file'] );
67
+ foreach ( $data['sizes'] as $size ) {
68
+ $path = $directory . $size['file'];
69
+ if ( ! in_array( $path, $list ) ) {
70
+ $list[] = $path;
71
+ }
72
+ }
73
+ return array_values( array_unique( $list ) );
74
+ }
75
+
76
+ /**
77
+ * Returns server path of source image.
78
+ *
79
+ * @param string $path Relative path of source image.
80
+ *
81
+ * @return string Server path of source image.
82
+ */
83
+ private function get_attachment_directory( string $path ): string {
84
+ $upload = wp_upload_dir();
85
+ $source = rtrim( $upload['basedir'], '/\\' ) . '/' . rtrim( dirname( $path ), '/\\' ) . '/';
86
+ $source = str_replace( '\\', '/', $source );
87
+ return $source;
88
+ }
89
+
90
+ /**
91
+ * Initializes conversion of attachment image sizes.
92
+ *
93
+ * @param string[] $paths Server paths of source images.
94
+ *
95
+ * @return void
96
+ */
97
+ private function init_conversion( array $paths ) {
98
+ $settings = $this->get_plugin()->get_settings();
99
+
100
+ if ( in_array( 'cron_conversion', $settings['features'] ) ) {
101
+ wp_schedule_single_event( ( time() + 1 ), 'webpc_convert_paths', [ $paths ] );
102
+ } else {
103
+ do_action( 'webpc_convert_paths', $paths );
104
+ }
105
+ }
106
+ }
src/Conversion/Method/GdMethod.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Method;
4
+
5
+ use WebpConverter\Conversion\Method\MethodAbstract;
6
+ use WebpConverter\Conversion\Method\MethodInterface;
7
+ use WebpConverter\Conversion\Format\WebpFormat;
8
+ use WebpConverter\Conversion\Format\AvifFormat;
9
+ use WebpConverter\Conversion\Exception;
10
+
11
+ /**
12
+ * Supports image conversion method using GD library.
13
+ */
14
+ class GdMethod extends MethodAbstract implements MethodInterface {
15
+
16
+ const METHOD_NAME = 'gd';
17
+
18
+ /**
19
+ * Returns name of conversion method.
20
+ *
21
+ * @return string Method name.
22
+ */
23
+ public function get_name(): string {
24
+ return self::METHOD_NAME;
25
+ }
26
+
27
+ /**
28
+ * Returns label of conversion method.
29
+ *
30
+ * @return string Method label.
31
+ */
32
+ public function get_label(): string {
33
+ /* translators: %s method name */
34
+ return sprintf( __( '%s (recommended)', 'webp-converter-for-media' ), 'GD' );
35
+ }
36
+
37
+ /**
38
+ * Returns status of whether method is installed.
39
+ *
40
+ * @return bool Is method installed?
41
+ */
42
+ public static function is_method_installed(): bool {
43
+ return ( extension_loaded( 'gd' ) );
44
+ }
45
+
46
+ /**
47
+ * Returns status of whether method is active.
48
+ *
49
+ * @param string $format Extension of output format.
50
+ *
51
+ * @return bool Is method active?
52
+ */
53
+ public static function is_method_active( string $format ): bool {
54
+ if ( ! self::is_method_installed() || ! ( $function = self::get_format_function( $format ) ) ) {
55
+ return false;
56
+ }
57
+ return function_exists( $function );
58
+ }
59
+
60
+ /**
61
+ * Returns name of function to convert source image to output image.
62
+ *
63
+ * @param string $format Extension of output format.
64
+ *
65
+ * @return string|null Function name using for conversion.
66
+ */
67
+ private static function get_format_function( string $format ) {
68
+ switch ( $format ) {
69
+ case WebpFormat::FORMAT_EXTENSION:
70
+ return 'imagewebp';
71
+ case AvifFormat::FORMAT_EXTENSION:
72
+ return 'imageavif';
73
+ default:
74
+ return null;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Creates image object based on source path.
80
+ *
81
+ * @param string $source_path Server path of source image.
82
+ *
83
+ * @return resource Image object.
84
+ * @throws Exception\ExtensionUnsupportedException
85
+ * @throws Exception\FunctionUnavailableException
86
+ * @throws Exception\ImageInvalidException
87
+ */
88
+ public function create_image_by_path( string $source_path ) {
89
+ $extension = strtolower( pathinfo( $source_path, PATHINFO_EXTENSION ) );
90
+ $methods = apply_filters(
91
+ 'webpc_gd_create_methods',
92
+ [
93
+ 'imagecreatefromjpeg' => [ 'jpg', 'jpeg' ],
94
+ 'imagecreatefrompng' => [ 'png' ],
95
+ 'imagecreatefromgif' => [ 'gif' ],
96
+ ]
97
+ );
98
+ $settings = $this->get_plugin()->get_settings();
99
+
100
+ foreach ( $methods as $method => $extensions ) {
101
+ if ( ! in_array( $extension, $settings['extensions'] ) || ! in_array( $extension, $extensions ) ) {
102
+ continue;
103
+ } elseif ( ! function_exists( $method ) ) {
104
+ throw new Exception\FunctionUnavailableException( $method );
105
+ } elseif ( ! $image = @$method( $source_path ) ) { // phpcs:ignore
106
+ throw new Exception\ImageInvalidException( $source_path );
107
+ }
108
+ }
109
+
110
+ if ( ! isset( $image ) ) {
111
+ throw new Exception\ExtensionUnsupportedException( [ $extension, $source_path ] );
112
+ }
113
+
114
+ return $this->update_image_resource( $image, $extension );
115
+ }
116
+
117
+ /**
118
+ * Updates image object before converting to output format.
119
+ *
120
+ * @param resource $image Image object.
121
+ * @param string $extension Extension of output format.
122
+ *
123
+ * @return resource Image object.
124
+ * @throws Exception\FunctionUnavailableException
125
+ */
126
+ private function update_image_resource( $image, string $extension ) {
127
+ if ( ! function_exists( 'imageistruecolor' ) ) {
128
+ throw new Exception\FunctionUnavailableException( 'imageistruecolor' );
129
+ }
130
+
131
+ if ( ! imageistruecolor( $image ) ) {
132
+ if ( ! function_exists( 'imagepalettetotruecolor' ) ) {
133
+ throw new Exception\FunctionUnavailableException( 'imagepalettetotruecolor' );
134
+ }
135
+ imagepalettetotruecolor( $image );
136
+ }
137
+
138
+ switch ( $extension ) {
139
+ case 'png':
140
+ if ( ! function_exists( 'imagealphablending' ) ) {
141
+ throw new Exception\FunctionUnavailableException( 'imagealphablending' );
142
+ }
143
+ imagealphablending( $image, false );
144
+
145
+ if ( ! function_exists( 'imagesavealpha' ) ) {
146
+ throw new Exception\FunctionUnavailableException( 'imagesavealpha' );
147
+ }
148
+ imagesavealpha( $image, true );
149
+ break;
150
+ }
151
+
152
+ return $image;
153
+ }
154
+
155
+ /**
156
+ * Converts image and saves to output location.
157
+ *
158
+ * @param resource $image Image object.
159
+ * @param string $source_path Server path of source image.
160
+ * @param string $output_path Server path for output image.
161
+ * @param string $format Extension of output format.
162
+ *
163
+ * @return void
164
+ * @throws Exception\ConversionErrorException
165
+ * @throws Exception\FunctionUnavailableException
166
+ * @throws Exception\ResolutionOversizeException
167
+ */
168
+ public function convert_image_to_output( $image, string $source_path, string $output_path, string $format ) {
169
+ $function = self::get_format_function( $format );
170
+ if ( $function === null ) {
171
+ return;
172
+ }
173
+
174
+ $image = apply_filters( 'webpc_gd_before_saving', $image, $source_path );
175
+ $settings = $this->get_plugin()->get_settings();
176
+
177
+ if ( ! function_exists( $function ) ) {
178
+ throw new Exception\FunctionUnavailableException( $function );
179
+ } elseif ( ( imagesx( $image ) > 8192 ) || ( imagesy( $image ) > 8192 ) ) {
180
+ throw new Exception\ResolutionOversizeException( $source_path );
181
+ } elseif ( is_callable( $function ) && ! $function( $image, $output_path, $settings['quality'] ) ) {
182
+ throw new Exception\ConversionErrorException( $source_path );
183
+ }
184
+
185
+ if ( filesize( $output_path ) % 2 === 1 ) {
186
+ file_put_contents( $output_path, "\0", FILE_APPEND );
187
+ }
188
+ }
189
+ }
src/Conversion/Method/ImagickMethod.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Method;
4
+
5
+ use WebpConverter\Conversion\Method\MethodAbstract;
6
+ use WebpConverter\Conversion\Method\MethodInterface;
7
+ use WebpConverter\Conversion\Format\WebpFormat;
8
+ use WebpConverter\Conversion\Format\AvifFormat;
9
+ use WebpConverter\Conversion\Exception;
10
+
11
+ /**
12
+ * Supports image conversion method using Imagick library.
13
+ */
14
+ class ImagickMethod extends MethodAbstract implements MethodInterface {
15
+
16
+ const METHOD_NAME = 'imagick';
17
+
18
+ /**
19
+ * Returns name of conversion method.
20
+ *
21
+ * @return string Method name.
22
+ */
23
+ public function get_name(): string {
24
+ return self::METHOD_NAME;
25
+ }
26
+
27
+ /**
28
+ * Returns label of conversion method.
29
+ *
30
+ * @return string Method label.
31
+ */
32
+ public function get_label(): string {
33
+ return 'Imagick';
34
+ }
35
+
36
+ /**
37
+ * Returns status of whether method is installed.
38
+ *
39
+ * @return bool Is method installed?
40
+ */
41
+ public static function is_method_installed(): bool {
42
+ return ( extension_loaded( 'imagick' ) && class_exists( '\Imagick' ) );
43
+ }
44
+
45
+ /**
46
+ * Returns status of whether method is active.
47
+ *
48
+ * @param string $format Extension of output format.
49
+ *
50
+ * @return bool Is method active?
51
+ */
52
+ public static function is_method_active( string $format ): bool {
53
+ if ( ! self::is_method_installed()
54
+ || ! ( $formats = ( new \Imagick() )->queryformats() )
55
+ || ! ( $extension = self::get_format_extension( $format ) ) ) {
56
+ return false;
57
+ }
58
+ return in_array( $extension, $formats );
59
+ }
60
+
61
+ /**
62
+ * Returns name of supported format to convert source image to output image.
63
+ *
64
+ * @param string $format Extension of output format.
65
+ *
66
+ * @return string|null Supported format using for conversion.
67
+ */
68
+ private static function get_format_extension( string $format ) {
69
+ switch ( $format ) {
70
+ case WebpFormat::FORMAT_EXTENSION:
71
+ return 'WEBP';
72
+ case AvifFormat::FORMAT_EXTENSION:
73
+ return 'AVIF';
74
+ default:
75
+ return null;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Creates image object based on source path.
81
+ *
82
+ * @param string $source_path Server path of source image.
83
+ *
84
+ * @return \Imagick Image object.
85
+ * @throws Exception\ImagickUnavailableException
86
+ * @throws Exception\ExtensionUnsupportedException
87
+ * @throws Exception\ImageInvalidException
88
+ */
89
+ public function create_image_by_path( string $source_path ) {
90
+ $extension = strtolower( pathinfo( $source_path, PATHINFO_EXTENSION ) );
91
+ $settings = $this->get_plugin()->get_settings();
92
+
93
+ if ( ! extension_loaded( 'imagick' ) || ! class_exists( 'Imagick' ) ) {
94
+ throw new Exception\ImagickUnavailableException();
95
+ } elseif ( ! in_array( $extension, $settings['extensions'] ) ) {
96
+ throw new Exception\ExtensionUnsupportedException( [ $extension, $source_path ] );
97
+ }
98
+
99
+ try {
100
+ return new \Imagick( $source_path );
101
+ } catch ( \ImagickException $e ) {
102
+ throw new Exception\ImageInvalidException( $source_path );
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Converts image and saves to output location.
108
+ *
109
+ * @param \Imagick $image Image object.
110
+ * @param string $source_path Server path of source image.
111
+ * @param string $output_path Server path for output image.
112
+ * @param string $format Extension of output format.
113
+ *
114
+ * @return void
115
+ * @throws Exception\ConversionErrorException
116
+ * @throws Exception\ImagickNotSupportWebpException
117
+ */
118
+ public function convert_image_to_output( $image, string $source_path, string $output_path, string $format ) {
119
+ $extension = self::get_format_extension( $format );
120
+ $image = apply_filters( 'webpc_imagick_before_saving', $image, $source_path );
121
+ $settings = $this->get_plugin()->get_settings();
122
+
123
+ if ( ! in_array( $extension, $image->queryFormats() ) ) {
124
+ throw new Exception\ImagickNotSupportWebpException();
125
+ }
126
+
127
+ $image->setImageFormat( $extension );
128
+ if ( ! in_array( 'keep_metadata', $settings['features'] ) ) {
129
+ $image->stripImage();
130
+ }
131
+ $image->setImageCompressionQuality( $settings['quality'] );
132
+ $blob = $image->getImageBlob();
133
+
134
+ if ( ! file_put_contents( $output_path, $blob ) ) {
135
+ throw new Exception\ConversionErrorException( $source_path );
136
+ }
137
+ }
138
+ }
src/Conversion/Method/MethodAbstract.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Method;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Conversion\Exception;
8
+ use WebpConverter\Conversion\Method\MethodInterface;
9
+ use WebpConverter\Conversion\OutputPath;
10
+ use WebpConverter\Conversion\SkipLarger;
11
+
12
+ /**
13
+ * Abstract class for class that supports endpoint.
14
+ */
15
+ abstract class MethodAbstract extends PluginAccessAbstract implements PluginAccessInterface, MethodInterface {
16
+
17
+ /**
18
+ * Messages of errors that occurred during conversion.
19
+ *
20
+ * @var string[]
21
+ */
22
+ private $errors = [];
23
+
24
+ /**
25
+ * Sum of size of source images before conversion.
26
+ *
27
+ * @var int
28
+ */
29
+ private $size_before = 0;
30
+
31
+ /**
32
+ * Sum of size of output images after conversion.
33
+ *
34
+ * @var int
35
+ */
36
+ private $size_after = 0;
37
+
38
+ /**
39
+ * Returns errors generated during image conversion.
40
+ *
41
+ * @return string[] Errors messages.
42
+ */
43
+ public function get_errors(): array {
44
+ return $this->errors;
45
+ }
46
+
47
+ /**
48
+ * Returns weight of source files before converting.
49
+ *
50
+ * @return int Source files weight.
51
+ */
52
+ public function get_size_before(): int {
53
+ return $this->size_before;
54
+ }
55
+
56
+ /**
57
+ * Returns weight of output files after converting.
58
+ *
59
+ * @return int Output files weight.
60
+ */
61
+ public function get_size_after(): int {
62
+ return $this->size_after;
63
+ }
64
+
65
+ /**
66
+ * Converts source paths to output formats.
67
+ *
68
+ * @param string[] $paths Server paths of source images.
69
+ *
70
+ * @return void
71
+ */
72
+ public function convert_paths( array $paths ) {
73
+ $output_formats = $this->get_plugin()->get_settings()['output_formats'];
74
+ foreach ( $output_formats as $output_format ) {
75
+ foreach ( $paths as $path ) {
76
+ try {
77
+ $response = $this->convert_path( $path, $output_format );
78
+
79
+ $this->size_before += $response['data']['size_before'];
80
+ $this->size_after += $response['data']['size_after'];
81
+ } catch ( \Exception $e ) {
82
+ $this->errors[] = $e->getMessage();
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Converts source path to output formats.
90
+ *
91
+ * @param string $path Server path of source image.
92
+ * @param string $format Extension of output format.
93
+ *
94
+ * @return mixed[] Results data of conversion.
95
+ * @throws Exception\SourcePathException
96
+ * @throws Exception\OutputPathException
97
+ */
98
+ public function convert_path( string $path, string $format ): array {
99
+ ini_set( 'memory_limit', '1G' ); // phpcs:ignore
100
+ if ( strpos( ini_get( 'disable_functions' ) ?: '', 'set_time_limit' ) === false ) {
101
+ set_time_limit( 120 );
102
+ }
103
+
104
+ try {
105
+ $source_path = $this->get_image_source_path( $path );
106
+ $image = $this->create_image_by_path( $source_path );
107
+ $output_path = $this->get_image_output_path( $source_path, $format );
108
+
109
+ if ( file_exists( $output_path . '.' . SkipLarger::DELETED_FILE_EXTENSION ) ) {
110
+ unlink( $output_path . '.' . SkipLarger::DELETED_FILE_EXTENSION );
111
+ }
112
+
113
+ $this->convert_image_to_output( $image, $source_path, $output_path, $format );
114
+ do_action( 'webpc_convert_after', $output_path, $source_path );
115
+
116
+ return [
117
+ 'success' => true,
118
+ 'message' => null,
119
+ 'data' => $this->get_conversion_stats( $source_path, $output_path ),
120
+ ];
121
+ } catch ( \Exception $e ) {
122
+ $features = $this->get_plugin()->get_settings()['features'] ?? [];
123
+ if ( in_array( 'debug_enabled', $features ) ) {
124
+ error_log( sprintf( 'WebP Converter for Media: %s', $e->getMessage() ) ); // phpcs:ignore
125
+ }
126
+
127
+ throw $e;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Checks server path of source image.
133
+ *
134
+ * @param string $source_path Server path of source image.
135
+ *
136
+ * @return string Server path of source image.
137
+ * @throws Exception\SourcePathException
138
+ */
139
+ public function get_image_source_path( string $source_path ): string {
140
+ $path = urldecode( $source_path );
141
+ if ( ! is_readable( $path ) ) {
142
+ throw new Exception\SourcePathException( $path );
143
+ }
144
+
145
+ return $path;
146
+ }
147
+
148
+ /**
149
+ * Returns server path for output image.
150
+ *
151
+ * @param string $source_path Server path of source image.
152
+ * @param string $format Extension of output format.
153
+ *
154
+ * @return string Server path of output image.
155
+ * @throws Exception\OutputPathException
156
+ */
157
+ public function get_image_output_path( string $source_path, string $format ): string {
158
+ if ( ! $output_path = OutputPath::get_path( $source_path, true, $format ) ) {
159
+ throw new Exception\OutputPathException( $source_path );
160
+ }
161
+
162
+ return $output_path;
163
+ }
164
+
165
+ /**
166
+ * Returns results data of conversion.
167
+ *
168
+ * @param string $source_path Server path of source image.
169
+ * @param string $output_path Server path of output image.
170
+ *
171
+ * @return int[] Results data of conversion.
172
+ */
173
+ public function get_conversion_stats( string $source_path, string $output_path ): array {
174
+ $size_before = filesize( $source_path );
175
+ $size_after = ( file_exists( $output_path ) ) ? filesize( $output_path ) : $size_before;
176
+
177
+ return [
178
+ 'size_before' => $size_before ?: 0,
179
+ 'size_after' => $size_after ?: 0,
180
+ ];
181
+ }
182
+ }
src/Conversion/Method/MethodIntegrator.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Method;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Conversion\Methods;
8
+ use WebpConverter\Conversion\Method\GdMethod;
9
+ use WebpConverter\Conversion\Method\ImagickMethod;
10
+ use WebpConverter\Conversion\Method\RemoteMethod;
11
+
12
+ /**
13
+ * Initializes image conversion using active image conversion method.
14
+ */
15
+ class MethodIntegrator extends PluginAccessAbstract implements PluginAccessInterface {
16
+
17
+ /**
18
+ * Initializes converting source images using active and set conversion method.
19
+ *
20
+ * @param string[] $paths Server paths for source images.
21
+ *
22
+ * @return array[]|null Results data of conversion.
23
+ */
24
+ public function init_conversion( array $paths ) {
25
+ if ( ! $method = $this->get_method_used() ) {
26
+ return null;
27
+ }
28
+
29
+ $method->convert_paths( $paths );
30
+ return [
31
+ 'errors' => apply_filters( 'webpc_convert_errors', $method->get_errors() ),
32
+ 'size' => [
33
+ 'before' => $method->get_size_before(),
34
+ 'after' => $method->get_size_after(),
35
+ ],
36
+ ];
37
+ }
38
+
39
+ /**
40
+ * Returns active and set conversion method.
41
+ *
42
+ * @return MethodInterface|null Object of conversion method.
43
+ */
44
+ private function get_method_used() {
45
+ if ( apply_filters( 'webpc_server_errors', [], true ) ) {
46
+ return null;
47
+ }
48
+
49
+ $method_key = $this->get_plugin()->get_settings()['method'] ?? '';
50
+ $methods = ( new Methods() )->get_methods_objects();
51
+ foreach ( $methods as $method_name => $method ) {
52
+ if ( $method_key === $method_name ) {
53
+ $method->set_plugin( $this->get_plugin() );
54
+ return $method;
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ }
src/Conversion/Method/MethodInterface.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion\Method;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+ use WebpConverter\Conversion\Exception;
7
+
8
+ /**
9
+ * Interface for class that supports image conversion method.
10
+ */
11
+ interface MethodInterface extends PluginAccessInterface {
12
+
13
+ /**
14
+ * Returns name of conversion method.
15
+ *
16
+ * @return string Method name.
17
+ */
18
+ public function get_name(): string;
19
+
20
+ /**
21
+ * Returns label of conversion method.
22
+ *
23
+ * @return string Method label.
24
+ */
25
+ public function get_label(): string;
26
+
27
+ /**
28
+ * Returns status of whether method is installed.
29
+ *
30
+ * @return bool Is method installed?
31
+ */
32
+ public static function is_method_installed(): bool;
33
+
34
+ /**
35
+ * Returns status of whether method is active.
36
+ *
37
+ * @param string $format Extension of output format.
38
+ *
39
+ * @return bool Is method active?
40
+ */
41
+ public static function is_method_active( string $format ): bool;
42
+
43
+ /**
44
+ * Returns errors generated during image conversion.
45
+ *
46
+ * @return string[] Errors messages.
47
+ */
48
+ public function get_errors(): array;
49
+
50
+ /**
51
+ * Returns weight of source files before converting.
52
+ *
53
+ * @return int Source files weight.
54
+ */
55
+ public function get_size_before(): int;
56
+
57
+ /**
58
+ * Returns weight of output files after converting.
59
+ *
60
+ * @return int Output files weight.
61
+ */
62
+ public function get_size_after(): int;
63
+
64
+ /**
65
+ * Converts source paths to output formats.
66
+ *
67
+ * @param string[] $paths Server paths of source images.
68
+ *
69
+ * @return void
70
+ */
71
+ public function convert_paths( array $paths );
72
+
73
+ /**
74
+ * Converts source path to output formats.
75
+ *
76
+ * @param string $path Server path of source image.
77
+ * @param string $format Extension of output format.
78
+ *
79
+ * @return mixed[] Results data of conversion.
80
+ * @throws Exception\OutputPathException
81
+ * @throws Exception\SourcePathException
82
+ */
83
+ public function convert_path( string $path, string $format ): array;
84
+
85
+ /**
86
+ * Checks server path of source image.
87
+ *
88
+ * @param string $source_path Server path of source image.
89
+ *
90
+ * @return string Server path of source image.
91
+ * @throws Exception\SourcePathException
92
+ */
93
+ public function get_image_source_path( string $source_path ): string;
94
+
95
+ /**
96
+ * Creates image object based on source path.
97
+ *
98
+ * @param string $source_path Server path of source image.
99
+ *
100
+ * @return mixed Image object.
101
+ * @throws Exception\ExtensionUnsupportedException
102
+ * @throws Exception\FunctionUnavailableException
103
+ * @throws Exception\ImageInvalidException
104
+ */
105
+ public function create_image_by_path( string $source_path );
106
+
107
+ /**
108
+ * Returns server path for output image.
109
+ *
110
+ * @param string $source_path Server path of source image.
111
+ * @param string $format Extension of output format.
112
+ *
113
+ * @return string Server path of output image.
114
+ * @throws Exception\OutputPathException
115
+ */
116
+ public function get_image_output_path( string $source_path, string $format ): string;
117
+
118
+ /**
119
+ * Converts image and saves to output location.
120
+ *
121
+ * @param mixed $image Image object.
122
+ * @param string $source_path Server path of source image.
123
+ * @param string $output_path Server path for output image.
124
+ * @param string $format Extension of output format.
125
+ *
126
+ * @return void
127
+ */
128
+ public function convert_image_to_output( $image, string $source_path, string $output_path, string $format );
129
+
130
+ /**
131
+ * Returns results data of conversion.
132
+ *
133
+ * @param string $source_path Server path of source image.
134
+ * @param string $output_path Server path of output image.
135
+ *
136
+ * @return int[] Results data of conversion.
137
+ */
138
+ public function get_conversion_stats( string $source_path, string $output_path ): array;
139
+ }
src/Conversion/Methods.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\Conversion\Method\MethodInterface;
6
+ use WebpConverter\Conversion\Method\GdMethod;
7
+ use WebpConverter\Conversion\Method\ImagickMethod;
8
+
9
+ /**
10
+ * Adds support for all conversion methods and returns information about them.
11
+ */
12
+ class Methods {
13
+
14
+ /**
15
+ * Objects of supported conversion methods.
16
+ *
17
+ * @var MethodInterface[]
18
+ */
19
+ private $methods = [];
20
+
21
+ /**
22
+ * Methods constructor.
23
+ */
24
+ public function __construct() {
25
+ $this->methods[ GdMethod::METHOD_NAME ] = new GdMethod();
26
+ $this->methods[ ImagickMethod::METHOD_NAME ] = new ImagickMethod();
27
+ }
28
+
29
+ /**
30
+ * Returns objects of conversion methods.
31
+ *
32
+ * @return MethodInterface[] .
33
+ */
34
+ public function get_methods_objects(): array {
35
+ $values = [];
36
+ foreach ( $this->methods as $method ) {
37
+ $values[ $method->get_name() ] = $method;
38
+ }
39
+ return $values;
40
+ }
41
+
42
+ /**
43
+ * Returns list of conversion methods.
44
+ *
45
+ * @return string[] Names of conversion methods with labels.
46
+ */
47
+ public function get_methods(): array {
48
+ $values = [];
49
+ foreach ( $this->get_methods_objects() as $method_name => $method ) {
50
+ $values[ $method_name ] = $method->get_label();
51
+ }
52
+ return $values;
53
+ }
54
+
55
+ /**
56
+ * Returns list of installed conversion methods.
57
+ *
58
+ * @return string[] Names of conversion methods with labels.
59
+ */
60
+ public function get_available_methods(): array {
61
+ $values = [];
62
+ foreach ( $this->get_methods_objects() as $method_name => $method ) {
63
+ if ( ! $method::is_method_installed() ) {
64
+ continue;
65
+ }
66
+ $values[ $method_name ] = $method->get_label();
67
+ }
68
+ return $values;
69
+ }
70
+
71
+ /**
72
+ * Returns status if conversion method is active.
73
+ *
74
+ * @param string $method_name Name of conversion method.
75
+ * @param string $output_format Extension of output format.
76
+ *
77
+ * @return bool Is method active?
78
+ */
79
+ public function is_method_available( string $method_name, string $output_format ): bool {
80
+ return ( isset( $this->methods[ $method_name ] )
81
+ && $this->methods[ $method_name ]->is_method_active( $output_format ) );
82
+ }
83
+ }
src/Conversion/OutputPath.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\Conversion\Formats;
6
+ use WebpConverter\Conversion\Format\WebpFormat;
7
+
8
+ /**
9
+ * Generates output paths from source paths.
10
+ */
11
+ class OutputPath {
12
+
13
+ /**
14
+ * Generates output path from path of source image.
15
+ *
16
+ * @param string $path Server path of source image.
17
+ * @param bool $create_dir Create output directory structure?
18
+ * @param string $file_extension Output format extension.
19
+ *
20
+ * @return string|null Server path for output image.
21
+ */
22
+ public static function get_path( string $path, bool $create_dir = false, string $file_extension = '' ) {
23
+ $paths = self::get_paths( $path, $create_dir, [ $file_extension ] );
24
+ return $paths[0] ?? null;
25
+ }
26
+
27
+ /**
28
+ * Generates output paths from paths of source image for all output formats.
29
+ * Creates directory structure of output path, if it does not exist.
30
+ *
31
+ * @param string $path Server path of source image.
32
+ * @param bool $create_dir Create output directory structure?
33
+ * @param string[] $file_extensions Output format extensions.
34
+ *
35
+ * @return string[] Server paths for output images.
36
+ */
37
+ public static function get_paths( string $path, bool $create_dir = false, array $file_extensions = [] ): array {
38
+ $new_path = self::get_directory_path( $path );
39
+ if ( $create_dir && ! self::make_directories( self::check_directories( $new_path ) ) ) {
40
+ return [];
41
+ }
42
+
43
+ $extensions = ( new Formats() )->get_format_extensions();
44
+ $paths = [];
45
+ foreach ( $extensions as $extension ) {
46
+ $output_path = sprintf( '%1$s.%2$s', $new_path, $extension );
47
+ if ( in_array( $extension, $file_extensions, true ) || file_exists( $output_path ) ) {
48
+ $paths[] = $output_path;
49
+ }
50
+ }
51
+ return $paths;
52
+ }
53
+
54
+ /**
55
+ * Generates output path from path of source directory.
56
+ *
57
+ * @param string $path Server path of source directory.
58
+ *
59
+ * @return string Server paths for output directory.
60
+ */
61
+ public static function get_directory_path( string $path ): string {
62
+ $webp_root = apply_filters( 'webpc_dir_path', '', 'webp' );
63
+ $uploads_root = dirname( $webp_root );
64
+ $output_path = str_replace( realpath( $uploads_root ) ?: '', '', realpath( $path ) ?: '' );
65
+ $output_path = trim( $output_path, '\/' );
66
+ return sprintf( '%1$s/%2$s', $webp_root, $output_path );
67
+ }
68
+
69
+ /**
70
+ * Checks if directories for output path exist.
71
+ *
72
+ * @param string $path Server path of output.
73
+ *
74
+ * @return string[] Directory paths to be created.
75
+ */
76
+ private static function check_directories( string $path ): array {
77
+ $current = dirname( $path );
78
+ $paths = [];
79
+ while ( ! file_exists( $current ) ) {
80
+ $paths[] = $current;
81
+ $current = dirname( $current );
82
+ }
83
+ return $paths;
84
+ }
85
+
86
+ /**
87
+ * Creates new directories.
88
+ *
89
+ * @param string[] $paths Output directory paths to be created.
90
+ *
91
+ * @return bool Paths created successfully?
92
+ */
93
+ private static function make_directories( array $paths ): bool {
94
+ $paths = array_reverse( $paths );
95
+ foreach ( $paths as $path ) {
96
+ if ( ! is_writable( dirname( $path ) ) ) {
97
+ return false;
98
+ }
99
+ mkdir( $path );
100
+ }
101
+ return true;
102
+ }
103
+ }
src/Conversion/SkipExists.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\OutputPath;
9
+ use WebpConverter\Conversion\SkipLarger;
10
+ use WebpConverter\Conversion\Formats;
11
+
12
+ /**
13
+ * Removes from list of source file paths those that have already been converted.
14
+ */
15
+ class SkipExists extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ add_filter( 'webpc_files_paths', [ $this, 'skip_exists_images' ], 10, 2 );
24
+ }
25
+
26
+ /**
27
+ * Removes from list of image paths those that have already been converted to output formats.
28
+ *
29
+ * @param string[] $paths Server paths of source images.
30
+ * @param bool $skip_exists Delete images already converted?
31
+ *
32
+ * @return string[] Server paths of source images.
33
+ * @internal
34
+ */
35
+ public function skip_exists_images( array $paths, bool $skip_exists = true ): array {
36
+ if ( ! $skip_exists ) {
37
+ return $paths;
38
+ }
39
+
40
+ $directory = new OutputPath();
41
+ $extensions = $this->get_output_extensions();
42
+ foreach ( $paths as $key => $path ) {
43
+ $output_paths = $directory->get_paths( urldecode( $path ), false, $extensions );
44
+ $is_exists = true;
45
+ foreach ( $output_paths as $output_path ) {
46
+ if ( ! file_exists( $output_path )
47
+ && ! file_exists( $output_path . '.' . SkipLarger::DELETED_FILE_EXTENSION ) ) {
48
+ $is_exists = false;
49
+ }
50
+ }
51
+
52
+ if ( $is_exists ) {
53
+ unset( $paths[ $key ] );
54
+ }
55
+ }
56
+ return $paths;
57
+ }
58
+
59
+ /**
60
+ * Returns list of file extensions in output directory.
61
+ *
62
+ * @return string[] Available output extensions.
63
+ */
64
+ private function get_output_extensions(): array {
65
+ $settings = $this->get_plugin()->get_settings();
66
+ $extensions = ( new Formats() )->get_available_formats( $settings['method'] );
67
+
68
+ $values = [];
69
+ foreach ( $extensions as $extension => $format_label ) {
70
+ $values[] = $extension;
71
+ }
72
+ return $values;
73
+ }
74
+ }
src/Conversion/SkipLarger.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Conversion;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Conversion\Exception;
9
+
10
+ /**
11
+ * Deletes output after conversion if it is larger than original.
12
+ */
13
+ class SkipLarger extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
14
+
15
+ const DELETED_FILE_EXTENSION = 'deleted';
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ add_action( 'webpc_convert_after', [ $this, 'remove_image_if_is_larger' ], 10, 2 );
24
+ }
25
+
26
+ /**
27
+ * Removes converted output image if it is larger than original image.
28
+ *
29
+ * @param string $webp_path Server path of output image.
30
+ * @param string $original_path Server path of source image.
31
+ *
32
+ * @return void
33
+ * @throws Exception\LargerThanOriginalException
34
+ * @internal
35
+ */
36
+ public function remove_image_if_is_larger( string $webp_path, string $original_path ) {
37
+ if ( ( ! $settings = $this->get_plugin()->get_settings() )
38
+ || ! in_array( 'only_smaller', $settings['features'] )
39
+ || ( ! file_exists( $webp_path ) || ! file_exists( $original_path ) )
40
+ || ( filesize( $webp_path ) < filesize( $original_path ) ) ) {
41
+ return;
42
+ }
43
+
44
+ $file = fopen( $webp_path . '.' . self::DELETED_FILE_EXTENSION, 'w' );
45
+ if ( $file !== false ) {
46
+ fclose( $file );
47
+ unlink( $webp_path );
48
+ }
49
+
50
+ throw new Exception\LargerThanOriginalException( $original_path );
51
+ }
52
+ }
src/Error/ErrorAbstract.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Error\ErrorInterface;
8
+
9
+ /**
10
+ * Abstract class for class that checks for configuration errors.
11
+ */
12
+ abstract class ErrorAbstract extends PluginAccessAbstract implements PluginAccessInterface, ErrorInterface {
13
+
14
+ /**
15
+ * Returns list of error codes.
16
+ *
17
+ * @return string[] Error codes.
18
+ */
19
+ public function get_error_codes(): array {
20
+ return [];
21
+ }
22
+ }
src/Error/ErrorInterface.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+
7
+ /**
8
+ * Interface for class that checks for configuration errors.
9
+ */
10
+ interface ErrorInterface extends PluginAccessInterface {
11
+
12
+ /**
13
+ * Returns list of error codes.
14
+ *
15
+ * @return string[] Error codes.
16
+ */
17
+ public function get_error_codes(): array;
18
+ }
src/Error/Errors.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Loader\PassthruLoader;
6
+ use WebpConverter\PluginAccessAbstract;
7
+ use WebpConverter\PluginAccessInterface;
8
+ use WebpConverter\HookableInterface;
9
+ use WebpConverter\Error\LibsInstalledError;
10
+ use WebpConverter\Error\LibsSupportWebpError;
11
+ use WebpConverter\Error\LibsSupportAvifError;
12
+ use WebpConverter\Error\PassthruError;
13
+ use WebpConverter\Error\PathsError;
14
+ use WebpConverter\Error\RestapiError;
15
+ use WebpConverter\Error\RewritesError;
16
+ use WebpConverter\Error\SettingsError;
17
+ use WebpConverter\Helper\ViewLoader;
18
+
19
+ /**
20
+ * Supports generating list of server configuration errors.
21
+ */
22
+ class Errors extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
23
+
24
+ const ERRORS_CACHE_OPTION = 'webpc_errors_cache';
25
+ const ALLOWED_ERROR_KEYS = [ 'rewrites_cached' ];
26
+ const ERROR_FILE_PATH = 'components/errors/%s.php';
27
+
28
+ /**
29
+ * List of error codes saved in cache.
30
+ *
31
+ * @var string[]
32
+ */
33
+ private $cache = [];
34
+
35
+ /**
36
+ * Integrates with WordPress hooks.
37
+ *
38
+ * @return void
39
+ */
40
+ public function init_hooks() {
41
+ add_filter( 'webpc_server_errors', [ $this, 'get_server_errors' ], 10, 3 );
42
+ add_filter( 'webpc_server_errors_messages', [ $this, 'get_server_errors_messages' ], 10, 3 );
43
+ }
44
+
45
+ /**
46
+ * Returns list of errors codes for server configuration.
47
+ * Uses cache for errors list.
48
+ *
49
+ * @param string[] $values Default value.
50
+ * @param bool $only_errors Only errors, no warnings?
51
+ * @param bool $is_force_refresh Force refresh error list?
52
+ *
53
+ * @return string[] Errors codes.
54
+ */
55
+ public function get_server_errors( array $values, bool $only_errors = false, bool $is_force_refresh = false ): array {
56
+ $errors = get_option( self::ERRORS_CACHE_OPTION, $this->cache );
57
+ if ( $is_force_refresh ) {
58
+ $errors = $this->get_errors_list();
59
+ }
60
+
61
+ return array_filter(
62
+ $errors,
63
+ function ( $error ) use ( $only_errors ) {
64
+ return ( ! $only_errors || ! in_array( $error, self::ALLOWED_ERROR_KEYS ) );
65
+ }
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Returns list of errors messages for server configuration.
71
+ * Uses cache for errors list.
72
+ *
73
+ * @param string[] $values Default value.
74
+ * @param bool $only_errors Only errors, no warnings?
75
+ * @param bool $is_force_refresh Force refresh error list?
76
+ *
77
+ * @return string[] Errors messages.
78
+ */
79
+ public function get_server_errors_messages( array $values, bool $only_errors = false, bool $is_force_refresh = false ): array {
80
+ $errors = $this->get_server_errors( $values, $only_errors, $is_force_refresh );
81
+ return $this->load_error_messages( $errors );
82
+ }
83
+
84
+ /**
85
+ * Returns list of errors messages loaded from templates files.
86
+ *
87
+ * @param string[] $errors Errors codes.
88
+ *
89
+ * @return string[] Errors messages.
90
+ */
91
+ private function load_error_messages( array $errors ): array {
92
+ $list = [];
93
+ foreach ( $errors as $error ) {
94
+ ob_start();
95
+ ViewLoader::load_view(
96
+ sprintf( self::ERROR_FILE_PATH, str_replace( '_', '-', $error ) ),
97
+ [
98
+ 'passthru_url' => PassthruLoader::get_loader_url(),
99
+ ]
100
+ );
101
+ $list[ $error ] = ob_get_clean();
102
+ }
103
+
104
+ return array_map( 'strval', $list );
105
+ }
106
+
107
+ /**
108
+ * Checks for configuration errors according to specified logic.
109
+ * Saves errors to cache.
110
+ *
111
+ * @return string[] Errors codes.
112
+ */
113
+ private function get_errors_list(): array {
114
+ $errors = [];
115
+
116
+ if ( $new_errors = $this->get_errors_by_detector( new LibsInstalledError() ) ) {
117
+ $errors = array_merge( $errors, $new_errors );
118
+ } elseif ( $new_errors = $this->get_errors_by_detector( new LibsSupportWebpError() ) ) {
119
+ $errors = array_merge( $errors, $new_errors );
120
+ } elseif ( $new_errors = $this->get_errors_by_detector( new LibsSupportAvifError() ) ) {
121
+ $errors = array_merge( $errors, $new_errors );
122
+ }
123
+
124
+ if ( $new_errors = $this->get_errors_by_detector( new RestapiError() ) ) {
125
+ $errors = array_merge( $errors, $new_errors );
126
+ }
127
+
128
+ if ( $new_errors = $this->get_errors_by_detector( new PathsError() ) ) {
129
+ $errors = array_merge( $errors, $new_errors );
130
+ }
131
+
132
+ if ( $new_errors = $this->get_errors_by_detector( new PassthruError() ) ) {
133
+ $errors = array_merge( $errors, $new_errors );
134
+ } elseif ( $new_errors = $this->get_errors_by_detector( new RewritesError() ) ) {
135
+ $errors = array_merge( $errors, $new_errors );
136
+ }
137
+
138
+ if ( ! $errors && ( $new_errors = $this->get_errors_by_detector( new SettingsError() ) ) ) {
139
+ $errors = array_merge( $errors, $new_errors );
140
+ }
141
+
142
+ $this->cache = $errors;
143
+ update_option( self::ERRORS_CACHE_OPTION, $errors );
144
+
145
+ return $errors;
146
+ }
147
+
148
+ /**
149
+ * Returns list of error codes for errors detector.
150
+ *
151
+ * @param ErrorInterface $error .
152
+ *
153
+ * @return string[] Error codes.
154
+ */
155
+ private function get_errors_by_detector( ErrorInterface $error ): array {
156
+ $error->set_plugin( $this->get_plugin() );
157
+ return $error->get_error_codes();
158
+ }
159
+ }
src/Error/LibsInstalledError.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+ use WebpConverter\Conversion\Method\GdMethod;
8
+ use WebpConverter\Conversion\Method\ImagickMethod;
9
+
10
+ /**
11
+ * Checks for configuration errors about non-installed methods for converting images.
12
+ */
13
+ class LibsInstalledError extends ErrorAbstract implements ErrorInterface {
14
+
15
+ /**
16
+ * Returns list of error codes.
17
+ *
18
+ * @return string[] Error codes.
19
+ */
20
+ public function get_error_codes(): array {
21
+ $errors = [];
22
+
23
+ if ( $this->if_libs_are_installed() !== true ) {
24
+ $errors[] = 'libs_not_installed';
25
+ }
26
+ return $errors;
27
+ }
28
+
29
+ /**
30
+ * Checks if any conversion method is installed.
31
+ *
32
+ * @return bool Verification status.
33
+ */
34
+ private function if_libs_are_installed(): bool {
35
+ return ( GdMethod::is_method_installed() || ImagickMethod::is_method_installed() );
36
+ }
37
+ }
src/Error/LibsSupportAvifError.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+ use WebpConverter\Conversion\Method\GdMethod;
8
+ use WebpConverter\Conversion\Method\ImagickMethod;
9
+ use WebpConverter\Conversion\Format\AvifFormat;
10
+
11
+ /**
12
+ * Checks for configuration errors about image conversion methods that do not support AVIF output format.
13
+ */
14
+ class LibsSupportAvifError extends ErrorAbstract implements ErrorInterface {
15
+
16
+ /**
17
+ * Returns list of error codes.
18
+ *
19
+ * @return string[] Error codes.
20
+ */
21
+ public function get_error_codes(): array {
22
+ $output_formats = $this->get_plugin()->get_settings()['output_formats'] ?? [];
23
+ $errors = [];
24
+
25
+ if ( in_array( AvifFormat::FORMAT_EXTENSION, $output_formats )
26
+ && ( $this->if_libs_support_avif() !== true ) ) {
27
+ $errors[] = 'libs_without_avif_support';
28
+ }
29
+ return $errors;
30
+ }
31
+
32
+ /**
33
+ * Checks if any conversion method supports converting to AVIF format.
34
+ *
35
+ * @return bool Verification status.
36
+ */
37
+ private function if_libs_support_avif(): bool {
38
+ return ( GdMethod::is_method_active( AvifFormat::FORMAT_EXTENSION )
39
+ || ImagickMethod::is_method_active( AvifFormat::FORMAT_EXTENSION ) );
40
+ }
41
+ }
src/Error/LibsSupportWebpError.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+ use WebpConverter\Conversion\Method\GdMethod;
8
+ use WebpConverter\Conversion\Method\ImagickMethod;
9
+ use WebpConverter\Conversion\Format\WebpFormat;
10
+ use WebpConverter\Conversion\Formats;
11
+
12
+ /**
13
+ * Checks for configuration errors about image conversion methods that do not support WebP output format.
14
+ */
15
+ class LibsSupportWebpError extends ErrorAbstract implements ErrorInterface {
16
+
17
+ /**
18
+ * Returns list of error codes.
19
+ *
20
+ * @return string[] Error codes.
21
+ */
22
+ public function get_error_codes(): array {
23
+ $errors = [];
24
+
25
+ if ( $this->if_libs_support_webp() !== true ) {
26
+ $errors[] = 'libs_without_webp_support';
27
+ }
28
+ return $errors;
29
+ }
30
+
31
+ /**
32
+ * Checks if any conversion method supports converting to WebP format.
33
+ *
34
+ * @return bool Verification status.
35
+ */
36
+ private function if_libs_support_webp(): bool {
37
+ return ( GdMethod::is_method_active( WebpFormat::FORMAT_EXTENSION )
38
+ || ImagickMethod::is_method_active( WebpFormat::FORMAT_EXTENSION ) );
39
+ }
40
+ }
src/Error/PassthruError.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+ use WebpConverter\Loader\LoaderAbstract;
8
+ use WebpConverter\Loader\PassthruLoader;
9
+
10
+ /**
11
+ * Checks for configuration errors about disabled file supports Pass Thru loader.
12
+ */
13
+ class PassthruError extends ErrorAbstract implements ErrorInterface {
14
+
15
+ /**
16
+ * Returns list of error codes.
17
+ *
18
+ * @return string[] Error codes.
19
+ */
20
+ public function get_error_codes(): array {
21
+ $errors = [];
22
+
23
+ do_action( LoaderAbstract::ACTION_NAME, true, true );
24
+
25
+ if ( $this->if_passthru_execution_allowed() !== true ) {
26
+ $errors[] = 'passthru_execution';
27
+ }
28
+
29
+ do_action( LoaderAbstract::ACTION_NAME, true );
30
+
31
+ return $errors;
32
+ }
33
+
34
+ /**
35
+ * Checks if PHP file required for Passthru loader is available.
36
+ *
37
+ * @return bool Verification status.
38
+ */
39
+ private function if_passthru_execution_allowed(): bool {
40
+ $loader = new PassthruLoader();
41
+ $loader->set_plugin( $this->get_plugin() );
42
+ if ( $loader->is_active_loader() !== true ) {
43
+ return true;
44
+ }
45
+
46
+ $url = $loader::get_loader_url() . '?nocache=1';
47
+ $ch = curl_init( $url );
48
+ if ( $ch === false ) {
49
+ return false;
50
+ }
51
+
52
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
53
+ curl_setopt( $ch, CURLOPT_NOBODY, 1 );
54
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
55
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
56
+ curl_setopt( $ch, CURLOPT_TIMEOUT, 3 );
57
+ curl_exec( $ch );
58
+ $code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
59
+ curl_close( $ch );
60
+
61
+ return ( $code === 200 );
62
+ }
63
+ }
src/Error/PathsError.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+
8
+ /**
9
+ * Checks for configuration errors about incorrect paths of directories.
10
+ */
11
+ class PathsError extends ErrorAbstract implements ErrorInterface {
12
+
13
+ /**
14
+ * Returns list of error codes.
15
+ *
16
+ * @return string[] Error codes.
17
+ */
18
+ public function get_error_codes(): array {
19
+ $errors = [];
20
+
21
+ if ( $this->if_uploads_path_exists() !== true ) {
22
+ $errors[] = 'path_uploads_unavailable';
23
+ } elseif ( $this->if_htaccess_is_writeable() !== true ) {
24
+ $errors[] = 'path_htaccess_not_writable';
25
+ }
26
+
27
+ if ( $this->if_paths_are_different() !== true ) {
28
+ $errors[] = 'path_webp_duplicated';
29
+ } elseif ( $this->if_webp_path_is_writeable() !== true ) {
30
+ $errors[] = 'path_webp_not_writable';
31
+ }
32
+
33
+ return $errors;
34
+ }
35
+
36
+ /**
37
+ * Checks if path of uploads directory is exists.
38
+ *
39
+ * @return bool Verification status.
40
+ */
41
+ private function if_uploads_path_exists(): bool {
42
+ $path = apply_filters( 'webpc_dir_path', '', 'uploads' );
43
+ return ( is_dir( $path ) && ( $path !== ABSPATH ) );
44
+ }
45
+
46
+ /**
47
+ * Checks if paths of wp-content and uploads directories are writable.
48
+ *
49
+ * @return bool Verification status.
50
+ */
51
+ private function if_htaccess_is_writeable(): bool {
52
+ $path_dir = apply_filters( 'webpc_dir_path', '', 'uploads' );
53
+ $path_file = $path_dir . '/.htaccess';
54
+ if ( file_exists( $path_file ) ) {
55
+ return ( is_readable( $path_file ) && is_writable( $path_file ) );
56
+ } else {
57
+ return is_writable( $path_dir );
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Checks if uploads directory path and output directory are different.
63
+ *
64
+ * @return bool Verification status.
65
+ */
66
+ private function if_paths_are_different(): bool {
67
+ $path_uploads = apply_filters( 'webpc_dir_path', '', 'uploads' );
68
+ $path_webp = apply_filters( 'webpc_dir_path', '', 'webp' );
69
+ return ( $path_uploads !== $path_webp );
70
+ }
71
+
72
+ /**
73
+ * Checks if path of output directory is writable.
74
+ *
75
+ * @return bool Verification status.
76
+ */
77
+ private function if_webp_path_is_writeable(): bool {
78
+ $path = apply_filters( 'webpc_dir_path', '', 'webp' );
79
+ return ( is_dir( $path ) || is_writable( dirname( $path ) ) );
80
+ }
81
+ }
src/Error/RestapiError.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+
8
+ /**
9
+ * Checks for configuration errors about disabled REST API.
10
+ */
11
+ class RestapiError extends ErrorAbstract implements ErrorInterface {
12
+
13
+ /**
14
+ * Returns list of error codes.
15
+ *
16
+ * @return string[] Error codes.
17
+ */
18
+ public function get_error_codes(): array {
19
+ $errors = [];
20
+
21
+ if ( $this->if_rest_api_is_enabled() !== true ) {
22
+ $errors[] = 'rest_api_disabled';
23
+ }
24
+ return $errors;
25
+ }
26
+
27
+ /**
28
+ * Checks if REST API is enabled.
29
+ *
30
+ * @return bool Verification status.
31
+ */
32
+ private function if_rest_api_is_enabled(): bool {
33
+ return ( ( apply_filters( 'rest_enabled', true ) === true )
34
+ && ( apply_filters( 'rest_jsonp_enabled', true ) === true )
35
+ && ( apply_filters( 'rest_authentication_errors', true ) === true ) );
36
+ }
37
+ }
src/Error/RewritesError.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\Error\ErrorAbstract;
6
+ use WebpConverter\Error\ErrorInterface;
7
+ use WebpConverter\Conversion\OutputPath;
8
+ use WebpConverter\Conversion\Format\WebpFormat;
9
+ use WebpConverter\Loader\LoaderAbstract;
10
+ use WebpConverter\Helper\FileLoader;
11
+
12
+ /**
13
+ * Checks for configuration errors about non-working HTTP rewrites.
14
+ */
15
+ class RewritesError extends ErrorAbstract implements ErrorInterface {
16
+
17
+ const PATH_SOURCE_FILE_PNG = '/assets/img/icon-test.png';
18
+ const PATH_SOURCE_FILE_WEBP = '/assets/img/icon-test.webp';
19
+ const PATH_OUTPUT_FILE_PNG = '/webp-converter-for-media-test.png';
20
+ const PATH_OUTPUT_FILE_PNG2 = '/webp-converter-for-media-test.png2';
21
+
22
+ /**
23
+ * Returns list of error codes.
24
+ *
25
+ * @return string[] Error codes.
26
+ */
27
+ public function get_error_codes(): array {
28
+ $settings = $this->get_plugin()->get_settings();
29
+ $errors = [];
30
+ if ( ! $settings['dirs'] || ! $settings['output_formats'] ) {
31
+ return $errors;
32
+ }
33
+
34
+ $this->convert_images_for_debug();
35
+ do_action( LoaderAbstract::ACTION_NAME, true, true );
36
+
37
+ if ( $this->if_redirects_are_works() !== true ) {
38
+ if ( $this->if_bypassing_apache_is_active() === true ) {
39
+ $errors[] = 'bypassing_apache';
40
+ } else {
41
+ $errors[] = 'rewrites_not_working';
42
+ }
43
+ } elseif ( $this->if_redirects_are_cached() === true ) {
44
+ $errors[] = 'rewrites_cached';
45
+ }
46
+
47
+ do_action( LoaderAbstract::ACTION_NAME, true );
48
+
49
+ return $errors;
50
+ }
51
+
52
+ /**
53
+ * Converts and saves files needed for testing.
54
+ *
55
+ * @return void
56
+ */
57
+ private function convert_images_for_debug() {
58
+ $uploads_dir = apply_filters( 'webpc_dir_path', '', 'uploads' );
59
+ $path_file_png = $uploads_dir . self::PATH_OUTPUT_FILE_PNG;
60
+ $path_file_png2 = $uploads_dir . self::PATH_OUTPUT_FILE_PNG2;
61
+ if ( ! is_writable( $uploads_dir ) ) {
62
+ return;
63
+ }
64
+
65
+ if ( ! file_exists( $path_file_png ) || ! file_exists( $path_file_png2 ) ) {
66
+ copy( WEBPC_PATH . self::PATH_SOURCE_FILE_PNG, $path_file_png );
67
+ copy( WEBPC_PATH . self::PATH_SOURCE_FILE_PNG, $path_file_png2 );
68
+ }
69
+
70
+ if ( ( $output_path = OutputPath::get_path( $path_file_png, true, WebpFormat::FORMAT_EXTENSION ) )
71
+ && ! file_exists( $output_path ) ) {
72
+ copy( WEBPC_PATH . self::PATH_SOURCE_FILE_WEBP, $output_path );
73
+ }
74
+ if ( ( $output_path = OutputPath::get_path( $path_file_png2, true, WebpFormat::FORMAT_EXTENSION ) )
75
+ && ! file_exists( $output_path ) ) {
76
+ copy( WEBPC_PATH . self::PATH_SOURCE_FILE_WEBP, $output_path );
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Checks if redirects to output images are works.
82
+ *
83
+ * @return bool Verification status.
84
+ */
85
+ private function if_redirects_are_works(): bool {
86
+ $uploads_dir = apply_filters( 'webpc_dir_path', '', 'uploads' );
87
+ $uploads_url = apply_filters( 'webpc_dir_url', '', 'uploads' );
88
+
89
+ $file_size = FileLoader::get_file_size_by_path(
90
+ $uploads_dir . self::PATH_OUTPUT_FILE_PNG
91
+ );
92
+ $file_webp = FileLoader::get_file_size_by_url(
93
+ $uploads_url . self::PATH_OUTPUT_FILE_PNG,
94
+ $this->get_plugin()
95
+ );
96
+
97
+ return ( $file_webp < $file_size );
98
+ }
99
+
100
+ /**
101
+ * Checks if bypassing of redirects to output images is exists.
102
+ *
103
+ * @return bool Verification status.
104
+ */
105
+ private function if_bypassing_apache_is_active(): bool {
106
+ $uploads_url = apply_filters( 'webpc_dir_url', '', 'uploads' );
107
+
108
+ $file_png = FileLoader::get_file_size_by_url(
109
+ $uploads_url . self::PATH_OUTPUT_FILE_PNG,
110
+ $this->get_plugin()
111
+ );
112
+ $file_png2 = FileLoader::get_file_size_by_url(
113
+ $uploads_url . self::PATH_OUTPUT_FILE_PNG2,
114
+ $this->get_plugin()
115
+ );
116
+
117
+ return ( $file_png > $file_png2 );
118
+ }
119
+
120
+ /**
121
+ * Checks if redirects to output images are cached.
122
+ *
123
+ * @return bool Verification status.
124
+ */
125
+ private function if_redirects_are_cached(): bool {
126
+ $uploads_url = apply_filters( 'webpc_dir_url', '', 'uploads' );
127
+
128
+ $file_webp = FileLoader::get_file_size_by_url(
129
+ $uploads_url . self::PATH_OUTPUT_FILE_PNG,
130
+ $this->get_plugin()
131
+ );
132
+ $file_original = FileLoader::get_file_size_by_url(
133
+ $uploads_url . self::PATH_OUTPUT_FILE_PNG,
134
+ $this->get_plugin(),
135
+ false
136
+ );
137
+
138
+ return ( ( $file_webp > 0 ) && ( $file_webp === $file_original ) );
139
+ }
140
+ }
src/Error/SettingsError.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Error;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+ use WebpConverter\Error\ErrorAbstract;
7
+ use WebpConverter\Error\ErrorInterface;
8
+
9
+ /**
10
+ * Checks for configuration errors about incorrectly saved plugin settings.
11
+ */
12
+ class SettingsError extends ErrorAbstract implements PluginAccessInterface, ErrorInterface {
13
+
14
+ /**
15
+ * Returns list of error codes.
16
+ *
17
+ * @return string[] Error codes.
18
+ */
19
+ public function get_error_codes(): array {
20
+ $errors = [];
21
+
22
+ if ( $this->if_settings_are_correct() !== true ) {
23
+ $errors[] = 'settings_incorrect';
24
+ }
25
+ return $errors;
26
+ }
27
+
28
+ /**
29
+ * Checks if plugin settings are correct.
30
+ *
31
+ * @return bool Verification status.
32
+ */
33
+ private function if_settings_are_correct(): bool {
34
+ $settings = $this->get_plugin()->get_settings();
35
+ if ( ( ! isset( $settings['extensions'] ) || ! $settings['extensions'] )
36
+ || ( ! isset( $settings['dirs'] ) || ! $settings['dirs'] )
37
+ || ( ! isset( $settings['method'] ) || ! $settings['method'] )
38
+ || ( ! isset( $settings['output_formats'] ) || ! $settings['output_formats'] )
39
+ || ( ! isset( $settings['quality'] ) || ! $settings['quality'] ) ) {
40
+ return false;
41
+ }
42
+
43
+ return true;
44
+ }
45
+ }
src/Helper/FileLoader.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Helper;
4
+
5
+ use WebpConverter\Loader\PassthruLoader;
6
+ use WebpConverter\WebpConverter;
7
+
8
+ /**
9
+ * Returns size of image downloaded based on server path or URL.
10
+ */
11
+ class FileLoader {
12
+
13
+ /**
14
+ * Checks size of file by sending request using active image loader.
15
+ *
16
+ * @param string $url URL of image.
17
+ * @param WebpConverter $plugin .
18
+ * @param bool $set_headers Whether to send headers to confirm that browser supports WebP?
19
+ *
20
+ * @return int Size of retrieved file.
21
+ */
22
+ public static function get_file_size_by_url( string $url, WebpConverter $plugin, bool $set_headers = true ): int {
23
+ $headers = [
24
+ 'Accept: image/webp',
25
+ 'Referer: ' . WEBPC_URL,
26
+ ];
27
+
28
+ $loader = new PassthruLoader();
29
+ $loader->set_plugin( $plugin );
30
+
31
+ $image_url = $loader->update_image_urls( $url, true );
32
+ return self::get_file_size_for_loaded_file( $image_url, ( $set_headers ) ? $headers : [] );
33
+ }
34
+
35
+ /**
36
+ * Returns size of file.
37
+ *
38
+ * @param string $path Server path of file.
39
+ *
40
+ * @return int Size of file.
41
+ */
42
+ public static function get_file_size_by_path( string $path ): int {
43
+ return ( file_exists( $path ) ) ? ( filesize( $path ) ?: 0 ) : 0;
44
+ }
45
+
46
+ /**
47
+ * Checks size of file by sending cURL request.
48
+ *
49
+ * @param string $url URL of image.
50
+ * @param string[] $headers Headers for cURL connection.
51
+ *
52
+ * @return int Size of retrieved file.
53
+ */
54
+ private static function get_file_size_for_loaded_file( string $url, array $headers ): int {
55
+ foreach ( wp_get_nocache_headers() as $header_key => $header_value ) {
56
+ $headers[] = sprintf( '%s: %s', $header_key, $header_value );
57
+ }
58
+
59
+ $ch = curl_init( $url );
60
+ if ( $ch === false ) {
61
+ return 0;
62
+ }
63
+
64
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
65
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
66
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
67
+ curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
68
+ curl_setopt( $ch, CURLOPT_FRESH_CONNECT, 1 );
69
+ curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
70
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
71
+ $response = curl_exec( $ch );
72
+ $code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
73
+ curl_close( $ch );
74
+
75
+ return ( $code === 200 )
76
+ ? strlen( is_string( $response ) ? $response : '' )
77
+ : 0;
78
+ }
79
+ }
src/Helper/ViewLoader.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Helper;
4
+
5
+ /**
6
+ * Supports loading views from /templates directory.
7
+ */
8
+ class ViewLoader {
9
+
10
+ const ROOT_DIRECTORY = WEBPC_PATH;
11
+
12
+ /**
13
+ * Loads view with given variables.
14
+ *
15
+ * @param string $path Server path relative to plugin root directory.
16
+ * @param mixed[] $params Variables for view.
17
+ *
18
+ * @return void
19
+ */
20
+ public static function load_view( string $path, array $params = [] ) {
21
+ extract( $params ); // phpcs:ignore
22
+ $view_path = sprintf( '%1$s/templates/%2$s', self::ROOT_DIRECTORY, $path );
23
+ if ( file_exists( $view_path ) ) {
24
+ /** @noinspection PhpIncludeInspection */ // phpcs:ignore
25
+ require_once $view_path;
26
+ }
27
+ }
28
+ }
src/HookableInterface.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter;
4
+
5
+ /**
6
+ * Interface for class which has action call to integrates with WordPress hooks.
7
+ */
8
+ interface HookableInterface {
9
+
10
+ /**
11
+ * Integrates with WordPress hooks.
12
+ *
13
+ * @return void
14
+ */
15
+ public function init_hooks();
16
+ }
src/Loader/HtaccessLoader.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\Loader\LoaderAbstract;
6
+ use WebpConverter\Loader\LoaderInterface;
7
+
8
+ /**
9
+ * Supports method of loading images using rewrites from .htaccess file.
10
+ */
11
+ class HtaccessLoader extends LoaderAbstract implements LoaderInterface {
12
+
13
+ const LOADER_TYPE = 'htaccess';
14
+
15
+ /**
16
+ * Returns status if loader is active.
17
+ *
18
+ * @return bool Is loader active?
19
+ */
20
+ public function is_active_loader(): bool {
21
+ $settings = $this->get_plugin()->get_settings();
22
+ return ( ! isset( $settings['loader_type'] ) || ( $settings['loader_type'] === self::LOADER_TYPE ) );
23
+ }
24
+
25
+ /**
26
+ * Initializes actions for activating loader.
27
+ *
28
+ * @param bool $is_debug Is debugging?
29
+ *
30
+ * @return void
31
+ */
32
+ public function activate_loader( bool $is_debug = false ) {
33
+ $settings = ( $is_debug ) ? $this->get_plugin()->get_settings_debug() : $this->get_plugin()->get_settings();
34
+
35
+ $this->add_rewrite_rules_to_wp_content( true, $settings );
36
+ $this->add_rewrite_rules_to_uploads( true, $settings );
37
+ $this->add_rewrite_rules_to_uploads_webp( true, $settings );
38
+ }
39
+
40
+ /**
41
+ * Initializes actions for deactivating loader.
42
+ *
43
+ * @return void
44
+ */
45
+ public function deactivate_loader() {
46
+ $settings = $this->get_plugin()->get_settings();
47
+
48
+ $this->add_rewrite_rules_to_wp_content( false, $settings );
49
+ $this->add_rewrite_rules_to_uploads( false, $settings );
50
+ $this->add_rewrite_rules_to_uploads_webp( false, $settings );
51
+ }
52
+
53
+ /**
54
+ * Saves rules to .htaccess file in /wp-content directory.
55
+ *
56
+ * @param bool $is_active Is loader active?
57
+ * @param mixed[] $settings Plugin settings.
58
+ *
59
+ * @return void
60
+ */
61
+ private function add_rewrite_rules_to_wp_content( bool $is_active, array $settings ) {
62
+ $path = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) );
63
+ if ( ! $is_active ) {
64
+ $this->save_rewrites_in_htaccesss( $path );
65
+ return;
66
+ }
67
+
68
+ $content = $this->add_comments_to_rules(
69
+ [
70
+ $this->get_mod_rewrite_rules( $settings ),
71
+ ]
72
+ );
73
+
74
+ $content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
75
+ $this->save_rewrites_in_htaccesss( $path, $content );
76
+ }
77
+
78
+ /**
79
+ * Saves rules to .htaccess file in /uploads directory.
80
+ *
81
+ * @param bool $is_active Is loader active?
82
+ * @param mixed[] $settings Plugin settings.
83
+ *
84
+ * @return void
85
+ */
86
+ private function add_rewrite_rules_to_uploads( bool $is_active, array $settings ) {
87
+ $path = apply_filters( 'webpc_dir_path', '', 'uploads' );
88
+ if ( ! $is_active ) {
89
+ $this->save_rewrites_in_htaccesss( $path );
90
+ return;
91
+ }
92
+
93
+ $path_parts = explode( '/', apply_filters( 'webpc_dir_name', '', 'uploads' ) );
94
+ $content = $this->add_comments_to_rules(
95
+ [
96
+ $this->get_mod_rewrite_rules( $settings, end( $path_parts ) ),
97
+ ]
98
+ );
99
+
100
+ $content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
101
+ $this->save_rewrites_in_htaccesss( $path, $content );
102
+ }
103
+
104
+ /**
105
+ * Saves rules to .htaccess file in /uploads-webpc directory.
106
+ *
107
+ * @param bool $is_active Is loader active?
108
+ * @param mixed[] $settings Plugin settings.
109
+ *
110
+ * @return void
111
+ */
112
+ private function add_rewrite_rules_to_uploads_webp( bool $is_active, array $settings ) {
113
+ $path = apply_filters( 'webpc_dir_path', '', 'webp' );
114
+ if ( ! $is_active ) {
115
+ $this->save_rewrites_in_htaccesss( $path );
116
+ return;
117
+ }
118
+
119
+ $content = $this->add_comments_to_rules(
120
+ [
121
+ $this->get_mod_mime_rules( $settings ),
122
+ $this->get_mod_expires_rules( $settings ),
123
+ ]
124
+ );
125
+
126
+ $content = apply_filters( 'webpc_htaccess_rules', $content, $path . '/.htaccess' );
127
+ $this->save_rewrites_in_htaccesss( $path, $content );
128
+ }
129
+
130
+ /**
131
+ * Generates rules for rewriting source images to output images.
132
+ *
133
+ * @param mixed[] $settings Plugin settings.
134
+ * @param string|null $output_path Location of .htaccess file.
135
+ *
136
+ * @return string Rules for .htaccess file.
137
+ */
138
+ private function get_mod_rewrite_rules( array $settings, $output_path = null ): string {
139
+ $content = '';
140
+ if ( ! $settings['extensions'] ) {
141
+ return $content;
142
+ }
143
+
144
+ $path = apply_filters( 'webpc_uploads_prefix', '/' ) . apply_filters( 'webpc_dir_name', '', 'webp' );
145
+ if ( $output_path !== null ) {
146
+ $path .= '/' . $output_path;
147
+ }
148
+
149
+ foreach ( $this->get_mime_types() as $format => $mime_type ) {
150
+ $content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
151
+ $content .= ' RewriteEngine On' . PHP_EOL;
152
+ foreach ( $settings['extensions'] as $ext ) {
153
+ $content .= " RewriteCond %{HTTP_ACCEPT} ${mime_type}" . PHP_EOL;
154
+ $content .= " RewriteCond %{DOCUMENT_ROOT}${path}/$1.${ext}.${format} -f" . PHP_EOL;
155
+ if ( ! in_array( 'referer_disabled', $settings['features'] ) ) {
156
+ $content .= " RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} ^([^@]*)@@https?://\\1/.*" . PHP_EOL;
157
+ }
158
+ $content .= " RewriteRule (.+)\.${ext}$ ${path}/$1.${ext}.${format} [NC,T=${mime_type},E=cache-control:no-cache,L]" . PHP_EOL;
159
+ }
160
+ $content .= '</IfModule>';
161
+ $content .= PHP_EOL;
162
+ }
163
+
164
+ return apply_filters( 'webpc_htaccess_mod_rewrite', trim( $content ), $path );
165
+ }
166
+
167
+ /**
168
+ * Generates rules for mod_expires.
169
+ *
170
+ * @param mixed[] $settings Plugin settings.
171
+ *
172
+ * @return string Rules for .htaccess file.
173
+ */
174
+ private function get_mod_expires_rules( array $settings ): string {
175
+ $content = '';
176
+ if ( ! in_array( 'mod_expires', $settings['features'] ) ) {
177
+ return $content;
178
+ }
179
+
180
+ $content .= '<IfModule mod_expires.c>' . PHP_EOL;
181
+ $content .= ' ExpiresActive On' . PHP_EOL;
182
+ $content .= ' ExpiresByType image/webp "access plus 1 year"' . PHP_EOL;
183
+ $content .= '</IfModule>';
184
+
185
+ return apply_filters( 'webpc_htaccess_mod_expires', $content );
186
+ }
187
+
188
+ /**
189
+ * Generates rules that add support for output formats.
190
+ *
191
+ * @param mixed[] $settings Plugin settings.
192
+ *
193
+ * @return string Rules for .htaccess file.
194
+ */
195
+ private function get_mod_mime_rules( array $settings ): string {
196
+ $content = '';
197
+ if ( ! $settings['extensions'] ) {
198
+ return $content;
199
+ }
200
+
201
+ foreach ( $this->get_mime_types() as $format => $mime_type ) {
202
+ $content .= '<IfModule mod_mime.c>' . PHP_EOL;
203
+ $content .= " AddType ${mime_type} .${format}" . PHP_EOL;
204
+ $content .= '</IfModule>';
205
+ }
206
+
207
+ return apply_filters( 'webpc_htaccess_mod_mime', $content );
208
+ }
209
+
210
+ /**
211
+ * Adds comments before and after rules for .htaccess file.
212
+ *
213
+ * @param string[] $rules Rules for .htaccess file.
214
+ *
215
+ * @return string Rules for .htaccess file.
216
+ */
217
+ private function add_comments_to_rules( array $rules ): string {
218
+ if ( ! $rules ) {
219
+ return '';
220
+ }
221
+
222
+ $rows = [];
223
+ $rows[] = '';
224
+ $rows[] = '# BEGIN WebP Converter';
225
+ $rows[] = '# ! --- DO NOT EDIT PREVIOUS LINE --- !';
226
+ $rows = array_merge( $rows, array_filter( $rules ) );
227
+ $rows[] = '# ! --- DO NOT EDIT NEXT LINE --- !';
228
+ $rows[] = '# END WebP Converter';
229
+ $rows[] = '';
230
+
231
+ return implode( PHP_EOL, $rows );
232
+ }
233
+
234
+ /**
235
+ * Saves rules to .htaccess file in selected location.
236
+ *
237
+ * @param string $path_dir Location of .htaccess file.
238
+ * @param string $rules Rules for .htaccess file.
239
+ *
240
+ * @return void
241
+ */
242
+ private function save_rewrites_in_htaccesss( string $path_dir, string $rules = '' ) {
243
+ $path_file = $path_dir . '/.htaccess';
244
+
245
+ $code = ( is_readable( $path_file ) ) ? file_get_contents( $path_file ) ?: '' : '';
246
+ $code = preg_replace( '/((:?[\r\n|\r|\n]?)# BEGIN WebP Converter(.*?)# END WebP Converter(:?(:?[\r\n|\r|\n]+)?))/s', '', $code );
247
+ if ( $rules && $code ) {
248
+ $code = PHP_EOL . $code;
249
+ }
250
+ $code = $rules . $code;
251
+
252
+ if ( is_writable( $path_dir ) ) {
253
+ file_put_contents( $path_file, $code );
254
+ }
255
+ }
256
+ }
src/Loader/LoaderAbstract.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Loader\LoaderInterface;
8
+ use WebpConverter\Conversion\Formats;
9
+
10
+ /**
11
+ * Abstract class for class that supports method of loading images.
12
+ */
13
+ abstract class LoaderAbstract extends PluginAccessAbstract implements PluginAccessInterface, LoaderInterface {
14
+
15
+ const ACTION_NAME = 'webpc_refresh_loader';
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ }
24
+
25
+ /**
26
+ * Returns mime types for loader.
27
+ *
28
+ * @return string[] Output formats with mime types.
29
+ */
30
+ public function get_mime_types(): array {
31
+ $settings = $this->get_plugin()->get_settings();
32
+ return ( new Formats() )->get_mime_types( $settings['output_formats'] );
33
+ }
34
+ }
src/Loader/LoaderIntegration.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Loader\LoaderInterface;
9
+ use WebpConverter\Loader\LoaderAbstract;
10
+
11
+ /**
12
+ * Adds integration with active method of loading images.
13
+ */
14
+ class LoaderIntegration extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
15
+
16
+ /**
17
+ * Object of image loader method.
18
+ *
19
+ * @var LoaderInterface
20
+ */
21
+ private $loader;
22
+
23
+ /**
24
+ * LoaderIntegration constructor.
25
+ *
26
+ * @param LoaderInterface $loader .
27
+ */
28
+ public function __construct( LoaderInterface $loader ) {
29
+ $this->loader = $loader;
30
+ }
31
+
32
+ /**
33
+ * Integrates with WordPress hooks.
34
+ *
35
+ * @return void
36
+ */
37
+ public function init_hooks() {
38
+ add_action( 'plugins_loaded', [ $this, 'load_loader_actions' ] );
39
+ add_action( LoaderAbstract::ACTION_NAME, [ $this, 'refresh_loader' ], 10, 2 );
40
+ }
41
+
42
+ /**
43
+ * Loads hooks for loader if loader is active.
44
+ *
45
+ * @return void
46
+ * @internal
47
+ */
48
+ public function load_loader_actions() {
49
+ if ( ! $this->loader->is_active_loader() || apply_filters( 'webpc_server_errors', [], true ) ) {
50
+ return;
51
+ }
52
+ $this->loader->init_hooks();
53
+ }
54
+
55
+ /**
56
+ * Activates or deactivates loader.
57
+ *
58
+ * @param bool $is_active Is active loader?
59
+ * @param bool $is_debug Is debugging?
60
+ *
61
+ * @return void
62
+ * @internal
63
+ */
64
+ public function refresh_loader( bool $is_active, bool $is_debug = false ) {
65
+ $has_errors = ( apply_filters( 'webpc_server_errors', [], true ) !== [] );
66
+
67
+ if ( ( ( $is_active && ! $has_errors ) || $is_debug ) && $this->loader->is_active_loader() ) {
68
+ $this->loader->activate_loader( $is_debug );
69
+ } else {
70
+ $this->loader->deactivate_loader();
71
+ }
72
+ }
73
+ }
src/Loader/LoaderInterface.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\PluginAccessInterface;
7
+
8
+ /**
9
+ * Interface for class that supports method of loading images.
10
+ */
11
+ interface LoaderInterface extends HookableInterface, PluginAccessInterface {
12
+
13
+ /**
14
+ * Returns mime types for loader.
15
+ *
16
+ * @return string[] Output formats with mime types.
17
+ */
18
+ public function get_mime_types(): array;
19
+
20
+ /**
21
+ * Returns status if loader is active.
22
+ *
23
+ * @return bool Is loader active?
24
+ */
25
+ public function is_active_loader(): bool;
26
+
27
+ /**
28
+ * Initializes actions for activating loader.
29
+ *
30
+ * @param bool $is_debug Is debugging?
31
+ *
32
+ * @return void
33
+ */
34
+ public function activate_loader( bool $is_debug = false );
35
+
36
+ /**
37
+ * Initializes actions for deactivating loader.
38
+ *
39
+ * @return void
40
+ */
41
+ public function deactivate_loader();
42
+ }
src/Loader/Loaders.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Loader\LoaderInterface;
9
+ use WebpConverter\Loader\LoaderIntegration;
10
+ use WebpConverter\Loader\HtaccessLoader;
11
+ use WebpConverter\Loader\PassthruLoader;
12
+
13
+ /**
14
+ * Adds integration with methods of loading images.
15
+ */
16
+ class Loaders extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
17
+
18
+ /**
19
+ * Integrates with WordPress hooks.
20
+ *
21
+ * @return void
22
+ */
23
+ public function init_hooks() {
24
+ $this->set_integration( new HtaccessLoader() );
25
+ $this->set_integration( new PassthruLoader() );
26
+ }
27
+
28
+ /**
29
+ * Sets integration for loader.
30
+ *
31
+ * @param LoaderInterface $loader .
32
+ *
33
+ * @return void
34
+ */
35
+ private function set_integration( LoaderInterface $loader ) {
36
+ $loader->set_plugin( $this->get_plugin() );
37
+ ( new LoaderIntegration( $loader ) )->set_plugin_hookable( $this->get_plugin() );
38
+ }
39
+ }
src/Loader/PassthruLoader.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Loader;
4
+
5
+ use WebpConverter\Loader\LoaderAbstract;
6
+ use WebpConverter\Loader\LoaderInterface;
7
+
8
+ /**
9
+ * Supports method of loading images using .php file as Pass Thru.
10
+ */
11
+ class PassthruLoader extends LoaderAbstract implements LoaderInterface {
12
+
13
+ const LOADER_TYPE = 'passthru';
14
+ const PATH_LOADER = '/webpc-passthru.php';
15
+ const LOADER_SOURCE = '/includes/passthru.php';
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ add_action( 'get_header', [ $this, 'start_buffer' ] );
24
+ }
25
+
26
+ /**
27
+ * Returns status if loader is active.
28
+ *
29
+ * @return bool Is loader active?
30
+ */
31
+ public function is_active_loader(): bool {
32
+ $settings = $this->get_plugin()->get_settings();
33
+ return ( isset( $settings['loader_type'] ) && ( $settings['loader_type'] === self::LOADER_TYPE ) );
34
+ }
35
+
36
+ /**
37
+ * Initializes actions for activating loader.
38
+ *
39
+ * @param bool $is_debug Is debugging?
40
+ *
41
+ * @return void
42
+ */
43
+ public function activate_loader( bool $is_debug = false ) {
44
+ $path_source = WEBPC_PATH . self::LOADER_SOURCE;
45
+ $source_code = ( is_readable( $path_source ) ) ? file_get_contents( $path_source ) ?: '' : '';
46
+ if ( ! $source_code ) {
47
+ return;
48
+ }
49
+
50
+ $path_dir_uploads = apply_filters( 'webpc_dir_name', '', 'uploads' );
51
+ $path_dir_webp = apply_filters( 'webpc_dir_name', '', 'webp' );
52
+ $upload_suffix = implode( '/', array_diff( explode( '/', $path_dir_uploads ), explode( '/', $path_dir_webp ) ) );
53
+
54
+ $source_code = preg_replace(
55
+ '/(PATH_UPLOADS(?:\s+)= \')(\')/',
56
+ '$1' . $path_dir_uploads . '$2',
57
+ $source_code
58
+ );
59
+ $source_code = preg_replace(
60
+ '/(PATH_UPLOADS_WEBP(?:\s+)= \')(\')/',
61
+ '$1' . $path_dir_webp . '/' . $upload_suffix . '$2',
62
+ $source_code ?: ''
63
+ );
64
+ $source_code = preg_replace(
65
+ '/(MIME_TYPES(?:\s+)= \')(\')/',
66
+ '$1' . json_encode( $this->get_mime_types() ) . '$2',
67
+ $source_code ?: ''
68
+ );
69
+
70
+ $dir_output = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) );
71
+ if ( is_writable( $dir_output ) ) {
72
+ file_put_contents( $dir_output . self::PATH_LOADER, $source_code );
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Initializes actions for deactivating loader.
78
+ *
79
+ * @return void
80
+ */
81
+ public function deactivate_loader() {
82
+ $dir_output = dirname( apply_filters( 'webpc_dir_path', '', 'uploads' ) ) . self::PATH_LOADER;
83
+ if ( is_writable( $dir_output ) ) {
84
+ unlink( $dir_output );
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Opens buffer in which all output is stored.
90
+ *
91
+ * @return void
92
+ * @internal
93
+ */
94
+ public function start_buffer() {
95
+ ob_start( [ $this, 'update_image_urls' ] );
96
+ }
97
+
98
+ /**
99
+ * Replaces URLs to source images in output buffer.
100
+ *
101
+ * @param string $buffer Contents of output buffer.
102
+ * @param bool $is_debug Is debugging?
103
+ *
104
+ * @return string Contents of output buffer.
105
+ * @internal
106
+ */
107
+ public function update_image_urls( string $buffer, bool $is_debug = false ): string {
108
+ if ( ! $this->is_active_loader() ) {
109
+ return $buffer;
110
+ }
111
+
112
+ $settings = ( ! $is_debug ) ? $this->get_plugin()->get_settings() : $this->get_plugin()->get_settings_debug();
113
+ $extensions = implode( '|', $settings['extensions'] ?? [] );
114
+ if ( ! $extensions || ( ! $source_dir = self::get_loader_url() )
115
+ || ( ! $allowed_dirs = $this->get_allowed_dirs( $settings ) ) ) {
116
+ return $buffer;
117
+ }
118
+
119
+ $dir_paths = str_replace( '/', '\\/', implode( '|', $allowed_dirs ) );
120
+ return preg_replace(
121
+ '/(https?:\/\/(?:[^\s()"\']+)(?:' . $dir_paths . ')(?:[^\s()"\']+)\.(?:' . $extensions . '))/',
122
+ $source_dir . '?src=$1&nocache=1',
123
+ $buffer
124
+ ) ?: '';
125
+ }
126
+
127
+ /**
128
+ * Returns URL for Passthru loader.
129
+ *
130
+ * @return string|null URL of source PHP file.
131
+ */
132
+ public static function get_loader_url() {
133
+ if ( ! $source_dir = dirname( apply_filters( 'webpc_dir_url', '', 'uploads' ) ) ) {
134
+ return null;
135
+ }
136
+ return $source_dir . self::PATH_LOADER;
137
+ }
138
+
139
+ /**
140
+ * Returns list of directories for which redirection from source images to output images.
141
+ *
142
+ * @param mixed[] $settings Plugin settings.
143
+ *
144
+ * @return string[] List of directories names.
145
+ */
146
+ private function get_allowed_dirs( array $settings ): array {
147
+ $dirs = [];
148
+ foreach ( $settings['dirs'] as $dir ) {
149
+ $dirs[] = apply_filters( 'webpc_dir_name', null, $dir );
150
+ }
151
+ return array_filter( $dirs );
152
+ }
153
+ }
src/Notice/NoticeAbstract.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ use WebpConverter\Notice\NoticeInterface;
6
+
7
+ /**
8
+ * Abstract class for class that supports data field in plugin settings.
9
+ */
10
+ abstract class NoticeAbstract implements NoticeInterface {
11
+
12
+ /**
13
+ * Returns name of action using in WP Ajax.
14
+ *
15
+ * @return string Name of ajax action.
16
+ */
17
+ public function get_ajax_action_to_disable(): string {
18
+ return '';
19
+ }
20
+
21
+ /**
22
+ * Returns variables with values using in view template.
23
+ *
24
+ * @return string[] Args extract in view template.
25
+ */
26
+ public function get_vars_for_view(): array {
27
+ return [];
28
+ }
29
+ }
src/Notice/NoticeIntegration.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ use WebpConverter\Notice\NoticeInterface;
6
+ use WebpConverter\HookableInterface;
7
+ use WebpConverter\Settings\AdminAssets;
8
+ use WebpConverter\Helper\ViewLoader;
9
+
10
+ /**
11
+ * Supports ability to display notice and its management.
12
+ */
13
+ class NoticeIntegration implements HookableInterface {
14
+
15
+ /**
16
+ * Object of notice.
17
+ *
18
+ * @var NoticeInterface
19
+ */
20
+ private $notice;
21
+
22
+ /**
23
+ * NoticeIntegration constructor.
24
+ *
25
+ * @param NoticeInterface $notice .
26
+ */
27
+ public function __construct( NoticeInterface $notice ) {
28
+ $this->notice = $notice;
29
+ }
30
+
31
+ /**
32
+ * Integrates with WordPress hooks.
33
+ *
34
+ * @return void
35
+ */
36
+ public function init_hooks() {
37
+ add_action( 'admin_init', [ $this, 'init_notice_hooks' ] );
38
+
39
+ if ( $ajax_action = $this->notice->get_ajax_action_to_disable() ) {
40
+ add_action( 'wp_ajax_' . $ajax_action, [ $this->notice, 'disable_notice' ] );
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Initializes displaying notice in administration panel.
46
+ *
47
+ * @return void
48
+ * @internal
49
+ */
50
+ public function init_notice_hooks() {
51
+ if ( ! $this->notice->is_available() ) {
52
+ return;
53
+ }
54
+
55
+ ( new AdminAssets() )->init_hooks();
56
+ add_action( 'admin_notices', [ $this, 'load_notice' ] );
57
+ add_action( 'network_admin_notices', [ $this, 'load_notice' ] );
58
+ }
59
+
60
+ /**
61
+ * Loads view template for notice.
62
+ *
63
+ * @return void
64
+ * @internal
65
+ */
66
+ public function load_notice() {
67
+ if ( ! $this->notice->is_available() ) {
68
+ return;
69
+ }
70
+
71
+ ViewLoader::load_view(
72
+ $this->notice->get_output_path(),
73
+ $this->notice->get_vars_for_view()
74
+ );
75
+ }
76
+
77
+ /**
78
+ * Sets value for option that specifies whether to display notice.
79
+ *
80
+ * @return void
81
+ */
82
+ public function set_default_value() {
83
+ if ( get_option( $this->notice->get_option_name(), null ) !== null ) {
84
+ return;
85
+ }
86
+ update_option( $this->notice->get_option_name(), $this->notice->get_default_value() );
87
+ }
88
+ }
src/Notice/NoticeInterface.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ /**
6
+ * Interface for class that supports notice displayed in admin panel.
7
+ */
8
+ interface NoticeInterface {
9
+
10
+ /**
11
+ * Returns name for option that specifies whether to display notice.
12
+ *
13
+ * @return string Option name.
14
+ */
15
+ public function get_option_name(): string;
16
+
17
+ /**
18
+ * Returns default value for option that specifies whether to display notice.
19
+ *
20
+ * @return string Default value.
21
+ */
22
+ public function get_default_value(): string;
23
+
24
+ /**
25
+ * Returns status if notice is active.
26
+ *
27
+ * @return bool Is notice available?
28
+ */
29
+ public function is_available(): bool;
30
+
31
+ /**
32
+ * Returns server path for view template.
33
+ *
34
+ * @return string Server path relative to plugin root.
35
+ */
36
+ public function get_output_path(): string;
37
+
38
+ /**
39
+ * Returns variables with values using in view template.
40
+ *
41
+ * @return string[] Args extract in view template.
42
+ */
43
+ public function get_vars_for_view(): array;
44
+
45
+ /**
46
+ * Returns name of action using in WP Ajax.
47
+ *
48
+ * @return string Name of ajax action.
49
+ */
50
+ public function get_ajax_action_to_disable(): string;
51
+
52
+ /**
53
+ * Sets options to disable notice.
54
+ *
55
+ * @return void
56
+ * @internal
57
+ */
58
+ public static function disable_notice();
59
+ }
src/Notice/Notices.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ use WebpConverter\Notice\NoticeIntegration;
6
+ use WebpConverter\Notice\ThanksNotice;
7
+ use WebpConverter\HookableInterface;
8
+
9
+ /**
10
+ * Adds integration for list of notices.
11
+ */
12
+ class Notices implements HookableInterface {
13
+
14
+ /**
15
+ * Integrates with WordPress hooks.
16
+ *
17
+ * @return void
18
+ */
19
+ public function init_hooks() {
20
+ ( new NoticeIntegration( new ThanksNotice() ) )->init_hooks();
21
+ ( new NoticeIntegration( new WelcomeNotice() ) )->init_hooks();
22
+ }
23
+ }
src/Notice/ThanksNotice.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ use WebpConverter\Notice\NoticeAbstract;
6
+ use WebpConverter\Notice\NoticeInterface;
7
+
8
+ /**
9
+ * Supports notice displayed as thank you for using plugin.
10
+ */
11
+ class ThanksNotice extends NoticeAbstract implements NoticeInterface {
12
+
13
+ const NOTICE_OPTION = 'webpc_notice_hidden';
14
+ const NOTICE_VIEW_PATH = 'components/notices/thanks.php';
15
+
16
+ /**
17
+ * Returns name for option that specifies whether to display notice.
18
+ *
19
+ * @return string Option name.
20
+ */
21
+ public function get_option_name(): string {
22
+ return self::NOTICE_OPTION;
23
+ }
24
+
25
+ /**
26
+ * Returns default value for option that specifies whether to display notice.
27
+ *
28
+ * @return string Default value.
29
+ */
30
+ public function get_default_value(): string {
31
+ return (string) strtotime( '+ 1 week' );
32
+ }
33
+
34
+ /**
35
+ * Returns status if notice is active.
36
+ *
37
+ * @return bool Is notice available?
38
+ */
39
+ public function is_available(): bool {
40
+ if ( basename( $_SERVER['PHP_SELF'] ) !== 'index.php' ) { // phpcs:ignore
41
+ return false;
42
+ }
43
+
44
+ $value = get_option( self::NOTICE_OPTION, 0 );
45
+ return ( $value < time() );
46
+ }
47
+
48
+ /**
49
+ * Returns server path for view template.
50
+ *
51
+ * @return string Server path relative to plugin root.
52
+ */
53
+ public function get_output_path(): string {
54
+ return self::NOTICE_VIEW_PATH;
55
+ }
56
+
57
+ /**
58
+ * Returns variables with values using in view template.
59
+ *
60
+ * @return string[] Args extract in view template.
61
+ */
62
+ public function get_vars_for_view(): array {
63
+ return [
64
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
65
+ ];
66
+ }
67
+
68
+ /**
69
+ * Returns name of action using in WP Ajax.
70
+ *
71
+ * @return string Name of ajax action.
72
+ */
73
+ public function get_ajax_action_to_disable(): string {
74
+ return 'webpc_notice';
75
+ }
76
+
77
+ /**
78
+ * Sets options to disable notice.
79
+ *
80
+ * @return void
81
+ * @internal
82
+ */
83
+ public static function disable_notice() {
84
+ $is_permanent = ( isset( $_POST['is_permanently'] ) && $_POST['is_permanently'] ); // phpcs:ignore
85
+ $expires_date = strtotime( ( $is_permanent ) ? '+10 years' : '+ 1 month' );
86
+
87
+ update_option( self::NOTICE_OPTION, $expires_date );
88
+ }
89
+ }
src/Notice/WelcomeNotice.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Notice;
4
+
5
+ use WebpConverter\Notice\NoticeAbstract;
6
+ use WebpConverter\Notice\NoticeInterface;
7
+ use WebpConverter\Settings\Pages;
8
+
9
+ /**
10
+ * Supports notice displayed after plugin installation.
11
+ */
12
+ class WelcomeNotice extends NoticeAbstract implements NoticeInterface {
13
+
14
+ const NOTICE_OPTION = 'webpc_is_new_installation';
15
+ const NOTICE_VIEW_PATH = 'components/notices/welcome.php';
16
+
17
+ /**
18
+ * Returns name for option that specifies whether to display notice.
19
+ *
20
+ * @return string Option name.
21
+ */
22
+ public function get_option_name(): string {
23
+ return self::NOTICE_OPTION;
24
+ }
25
+
26
+ /**
27
+ * Returns default value for option that specifies whether to display notice.
28
+ *
29
+ * @return string Default value.
30
+ */
31
+ public function get_default_value(): string {
32
+ return '1';
33
+ }
34
+
35
+ /**
36
+ * Returns status if notice is active.
37
+ *
38
+ * @return bool Is notice available?
39
+ */
40
+ public function is_available(): bool {
41
+ return ( get_option( self::NOTICE_OPTION, 0 ) === $this->get_default_value() );
42
+ }
43
+
44
+ /**
45
+ * Returns server path for view template.
46
+ *
47
+ * @return string Server path relative to plugin root.
48
+ */
49
+ public function get_output_path(): string {
50
+ return self::NOTICE_VIEW_PATH;
51
+ }
52
+
53
+ /**
54
+ * Returns variables with values using in view template.
55
+ *
56
+ * @return string[] Args extract in view template.
57
+ */
58
+ public function get_vars_for_view(): array {
59
+ return [
60
+ 'settings_url' => Pages::get_settings_page_url(),
61
+ ];
62
+ }
63
+
64
+ /**
65
+ * Sets options to disable notice.
66
+ *
67
+ * @return void
68
+ * @internal
69
+ */
70
+ public static function disable_notice() {
71
+ update_option( self::NOTICE_OPTION, '0' );
72
+ }
73
+ }
src/Plugin/Activation.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\Plugin\Activation\DefaultSettings;
7
+ use WebpConverter\Plugin\Activation\RefreshLoader;
8
+ use WebpConverter\Plugin\Activation\WebpDirectory;
9
+
10
+ /**
11
+ * Runs actions after plugin activation.
12
+ */
13
+ class Activation implements HookableInterface {
14
+
15
+ /**
16
+ * Integrates with WordPress hooks.
17
+ *
18
+ * @return void
19
+ */
20
+ public function init_hooks() {
21
+ register_activation_hook( WEBPC_FILE, [ $this, 'load_activation_actions' ] );
22
+ }
23
+
24
+ /**
25
+ * Initializes actions when plugin is activated.
26
+ *
27
+ * @return void
28
+ * @internal
29
+ */
30
+ public function load_activation_actions() {
31
+ ( new WebpDirectory() )->create_directory_for_uploads_webp();
32
+ ( new DefaultSettings() )->add_default_options();
33
+ ( new RefreshLoader() )->refresh_image_loader();
34
+ }
35
+ }
src/Plugin/Activation/DefaultSettings.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Activation;
4
+
5
+ use WebpConverter\Notice\NoticeIntegration;
6
+ use WebpConverter\Notice\ThanksNotice;
7
+ use WebpConverter\Notice\WelcomeNotice;
8
+
9
+ /**
10
+ * Adds default options for plugin settings.
11
+ */
12
+ class DefaultSettings {
13
+
14
+ /**
15
+ * Sets default value for admin notices.
16
+ *
17
+ * @return void
18
+ */
19
+ public function add_default_options() {
20
+ ( new NoticeIntegration( new ThanksNotice() ) )->set_default_value();
21
+ ( new NoticeIntegration( new WelcomeNotice() ) )->set_default_value();
22
+ }
23
+ }
src/Plugin/Activation/RefreshLoader.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Activation;
4
+
5
+ use WebpConverter\Loader\LoaderAbstract;
6
+
7
+ /**
8
+ * Initializes integration with image loading method to enable it.
9
+ */
10
+ class RefreshLoader {
11
+
12
+ /**
13
+ * Activates image loader if active.
14
+ *
15
+ * @return void
16
+ */
17
+ public function refresh_image_loader() {
18
+ do_action( LoaderAbstract::ACTION_NAME, true );
19
+ }
20
+ }
src/Plugin/Activation/WebpDirectory.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Activation;
4
+
5
+ /**
6
+ * Creates /upload-webpc directory for output files.
7
+ */
8
+ class WebpDirectory {
9
+
10
+ /**
11
+ * Creates directory for output images.
12
+ *
13
+ * @return void
14
+ */
15
+ public function create_directory_for_uploads_webp() {
16
+ $path = apply_filters( 'webpc_dir_path', '', 'webp' );
17
+ if ( ! file_exists( $path ) && is_writable( dirname( $path ) ) ) {
18
+ mkdir( $path );
19
+ }
20
+ }
21
+ }
src/Plugin/Deactivation.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Plugin\Deactivation\CronReset;
9
+ use WebpConverter\Plugin\Deactivation\Modal;
10
+ use WebpConverter\Plugin\Deactivation\RefreshLoader;
11
+
12
+ /**
13
+ * Runs actions after plugin deactivation.
14
+ */
15
+ class Deactivation extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
16
+
17
+ /**
18
+ * Integrates with WordPress hooks.
19
+ *
20
+ * @return void
21
+ */
22
+ public function init_hooks() {
23
+ register_deactivation_hook( WEBPC_FILE, [ $this, 'load_deactivation_actions' ] );
24
+
25
+ $modal = new Modal();
26
+ $modal->set_plugin( $this->get_plugin() );
27
+ $modal->show_deactivation_modal();
28
+ }
29
+
30
+ /**
31
+ * Initializes actions when plugin is deactivated.
32
+ *
33
+ * @return void
34
+ * @internal
35
+ */
36
+ public function load_deactivation_actions() {
37
+ ( new RefreshLoader() )->refresh_image_loader();
38
+ ( new CronReset() )->reset_cron_event();
39
+ }
40
+ }
src/Plugin/Deactivation/CronReset.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Deactivation;
4
+
5
+ use WebpConverter\Conversion\Cron\Event;
6
+
7
+ /**
8
+ * Removes cron event that starts converting all images.
9
+ */
10
+ class CronReset {
11
+
12
+ /**
13
+ * Resets cron event to regenerate all images.
14
+ *
15
+ * @return void
16
+ */
17
+ public function reset_cron_event() {
18
+ wp_clear_scheduled_hook( Event::CRON_ACTION );
19
+ }
20
+ }
src/Plugin/Deactivation/Modal.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Deactivation;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Settings\AdminAssets;
8
+ use WebpConverter\Helper\ViewLoader;
9
+
10
+ /**
11
+ * Displays modal with poll in list of plugins when you try to deactivate plugin.
12
+ */
13
+ class Modal extends PluginAccessAbstract implements PluginAccessInterface {
14
+
15
+ const FEEDBACK_API_URL = 'https://feedback.gbiorczyk.pl/';
16
+
17
+ /**
18
+ * Initializes display of poll modal with poll when plugin is deactivated.
19
+ *
20
+ * @return void
21
+ */
22
+ public function show_deactivation_modal() {
23
+ if ( basename( ( $_SERVER['SCRIPT_FILENAME'] ?? '' ), '.php' ) !== 'plugins' ) { // phpcs:ignore
24
+ return;
25
+ }
26
+
27
+ ( new AdminAssets() )->init_hooks();
28
+ add_action( 'admin_footer', [ $this, 'load_deactivation_modal' ] );
29
+ }
30
+
31
+ /**
32
+ * Loads modal with poll when plugin is deactivated.
33
+ *
34
+ * @return void
35
+ */
36
+ public function load_deactivation_modal() {
37
+ ViewLoader::load_view(
38
+ 'views/deactivation-modal.php',
39
+ [
40
+ 'errors' => apply_filters( 'webpc_server_errors', [] ),
41
+ 'reasons' => $this->get_reasons(),
42
+ 'settings' => $this->get_plugin()->get_settings(),
43
+ 'api_url' => self::FEEDBACK_API_URL,
44
+ ]
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Returns list of reasons for plugin deactivation.
50
+ *
51
+ * @return array[] Reasons for plugin deactivation.
52
+ */
53
+ private function get_reasons(): array {
54
+ return [
55
+ [
56
+ 'key' => 'server_config',
57
+ 'label' => __( 'I have "Server configuration error" in plugin settings', 'webp-converter-for-media' ),
58
+ 'placeholder' => esc_attr( __( 'What is your error? Have you been looking for solution to this issue?', 'webp-converter-for-media' ) ),
59
+ ],
60
+ [
61
+ 'key' => 'website_broken',
62
+ 'label' => __( 'This plugin broke my website', 'webp-converter-for-media' ),
63
+ 'placeholder' => esc_attr( __( 'What exactly happened?', 'webp-converter-for-media' ) ),
64
+ ],
65
+ [
66
+ 'key' => 'better_plugin',
67
+ 'label' => __( 'I found a better plugin', 'webp-converter-for-media' ),
68
+ 'placeholder' => esc_attr( __( 'What is name of this plugin? Why is it better?', 'webp-converter-for-media' ) ),
69
+ ],
70
+ [
71
+ 'key' => 'misunderstanding',
72
+ 'label' => __( 'I do not understand how the plugin works', 'webp-converter-for-media' ),
73
+ 'placeholder' => esc_attr( __( 'What is non-understandable to you? Did you search for this in plugin FAQ?', 'webp-converter-for-media' ) ),
74
+ ],
75
+ [
76
+ 'key' => 'temporary_deactivation',
77
+ 'label' => __( 'This is a temporary deactivation', 'webp-converter-for-media' ),
78
+ 'placeholder' => '',
79
+ ],
80
+ [
81
+ 'key' => 'other',
82
+ 'label' => __( 'Other reason', 'webp-converter-for-media' ),
83
+ 'placeholder' => esc_attr( __( 'What is reason? What can we improve for you?', 'webp-converter-for-media' ) ),
84
+ ],
85
+ ];
86
+ }
87
+ }
src/Plugin/Deactivation/RefreshLoader.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Deactivation;
4
+
5
+ use WebpConverter\Loader\LoaderAbstract;
6
+
7
+ /**
8
+ * Initializes integration with image loading method to disable it.
9
+ */
10
+ class RefreshLoader {
11
+
12
+ /**
13
+ * Deactivates image loader.
14
+ *
15
+ * @return void
16
+ */
17
+ public function refresh_image_loader() {
18
+ do_action( LoaderAbstract::ACTION_NAME, false );
19
+ }
20
+ }
src/Plugin/Links.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\Settings\Pages;
7
+
8
+ /**
9
+ * Adds links to plugin in list of plugins in panel.
10
+ */
11
+ class Links implements HookableInterface {
12
+
13
+ const DONATION_URL = 'https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=plugin-links';
14
+
15
+ /**
16
+ * Integrates with WordPress hooks.
17
+ *
18
+ * @return void
19
+ */
20
+ public function init_hooks() {
21
+ add_filter( 'plugin_action_links_' . WEBPC_NAME, [ $this, 'add_link_to_settings_for_admin' ] );
22
+ add_filter( 'network_admin_plugin_action_links_' . WEBPC_NAME, [ $this, 'add_link_to_settings_for_network' ] );
23
+ add_filter( 'plugin_action_links_' . WEBPC_NAME, [ $this, 'add_link_to_donate' ] );
24
+ add_filter( 'network_admin_plugin_action_links_' . WEBPC_NAME, [ $this, 'add_link_to_donate' ] );
25
+ }
26
+
27
+ /**
28
+ * Adds links to plugin for non-multisite websites.
29
+ *
30
+ * @param string[] $links Plugin action links.
31
+ *
32
+ * @return string[] Plugin action links.
33
+ * @internal
34
+ */
35
+ public function add_link_to_settings_for_admin( array $links ): array {
36
+ if ( is_multisite() ) {
37
+ return $links;
38
+ }
39
+ return $this->add_link_to_settings( $links );
40
+ }
41
+
42
+ /**
43
+ * Adds links to plugin for multisite websites.
44
+ *
45
+ * @param string[] $links Plugin action links.
46
+ *
47
+ * @return string[] Plugin action links.
48
+ * @internal
49
+ */
50
+ public function add_link_to_settings_for_network( array $links ): array {
51
+ return $this->add_link_to_settings( $links );
52
+ }
53
+
54
+ /**
55
+ * Adds link to plugin settings page.
56
+ *
57
+ * @param string[] $links Plugin action links.
58
+ *
59
+ * @return string[] Plugin action links.
60
+ */
61
+ private function add_link_to_settings( array $links ): array {
62
+ array_unshift(
63
+ $links,
64
+ sprintf(
65
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
66
+ esc_html( __( '%1$sSettings%2$s', 'webp-converter-for-media' ) ),
67
+ '<a href="' . Pages::get_settings_page_url() . '">',
68
+ '</a>'
69
+ )
70
+ );
71
+ return $links;
72
+ }
73
+
74
+ /**
75
+ * Adds link to donation.
76
+ *
77
+ * @param string[] $links Plugin action links.
78
+ *
79
+ * @return string[] Plugin action links.
80
+ * @internal
81
+ */
82
+ public function add_link_to_donate( array $links ): array {
83
+ $links[] = sprintf(
84
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
85
+ esc_html( __( '%1$sProvide us a coffee%2$s', 'webp-converter-for-media' ) ),
86
+ '<a href="' . self::DONATION_URL . '" target="_blank">',
87
+ '</a>'
88
+ );
89
+ return $links;
90
+ }
91
+ }
src/Plugin/Uninstall.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\HookableInterface;
6
+ use WebpConverter\Plugin\Uninstall\DebugFiles;
7
+ use WebpConverter\Plugin\Uninstall\HtaccessFile;
8
+ use WebpConverter\Plugin\Uninstall\PluginSettings;
9
+ use WebpConverter\Plugin\Uninstall\WebpFiles;
10
+
11
+ /**
12
+ * Runs actions before plugin uninstallation.
13
+ */
14
+ class Uninstall implements HookableInterface {
15
+
16
+ /**
17
+ * Integrates with WordPress hooks.
18
+ *
19
+ * @return void
20
+ */
21
+ public function init_hooks() {
22
+ register_uninstall_hook( WEBPC_FILE, [ 'WebpConverter\Plugin\Uninstall', 'load_uninstall_actions' ] );
23
+ }
24
+
25
+ /**
26
+ * Initializes actions when plugin is uninstalled.
27
+ *
28
+ * @return void
29
+ * @internal
30
+ */
31
+ public static function load_uninstall_actions() {
32
+ PluginSettings::remove_plugin_settings();
33
+ HtaccessFile::remove_htaccess_file();
34
+ WebpFiles::remove_webp_files();
35
+ DebugFiles::remove_debug_files();
36
+ }
37
+ }
src/Plugin/Uninstall/DebugFiles.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Uninstall;
4
+
5
+ use WebpConverter\Error\RewritesError;
6
+
7
+ /**
8
+ * Removes files needed for debugging from /uploads directory.
9
+ */
10
+ class DebugFiles {
11
+
12
+ /**
13
+ * Removes files used for debugging from /uploads directory.
14
+ *
15
+ * @return void
16
+ */
17
+ public static function remove_debug_files() {
18
+ $uploads_dir = apply_filters( 'webpc_dir_path', '', 'uploads' );
19
+
20
+ if ( is_writable( $uploads_dir . RewritesError::PATH_OUTPUT_FILE_PNG ) ) {
21
+ unlink( $uploads_dir . RewritesError::PATH_OUTPUT_FILE_PNG );
22
+ }
23
+ if ( is_writable( $uploads_dir . RewritesError::PATH_OUTPUT_FILE_PNG2 ) ) {
24
+ unlink( $uploads_dir . RewritesError::PATH_OUTPUT_FILE_PNG2 );
25
+ }
26
+ }
27
+ }
src/Plugin/Uninstall/HtaccessFile.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Uninstall;
4
+
5
+ /**
6
+ * Removes .htaccess file /uploads-webpc directory.
7
+ */
8
+ class HtaccessFile {
9
+
10
+ /**
11
+ * Removes .htaccess file from /uploads-webpc directory.
12
+ *
13
+ * @return void
14
+ */
15
+ public static function remove_htaccess_file() {
16
+ $path = sprintf( '%s/.htaccess', apply_filters( 'webpc_dir_path', '', 'webp' ) );
17
+ if ( is_writable( $path ) ) {
18
+ unlink( $path );
19
+ }
20
+ }
21
+ }
src/Plugin/Uninstall/PluginSettings.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Uninstall;
4
+
5
+ use WebpConverter\Error\Errors;
6
+ use WebpConverter\Notice\ThanksNotice;
7
+ use WebpConverter\Notice\WelcomeNotice;
8
+ use WebpConverter\Plugin\Update;
9
+ use WebpConverter\Settings\SettingsSave;
10
+
11
+ /**
12
+ * Removes options saved by plugin.
13
+ */
14
+ class PluginSettings {
15
+
16
+ /**
17
+ * Removes options from wp_options table.
18
+ *
19
+ * @return void
20
+ */
21
+ public static function remove_plugin_settings() {
22
+ delete_option( ThanksNotice::NOTICE_OPTION );
23
+ delete_option( WelcomeNotice::NOTICE_OPTION );
24
+ delete_option( Errors::ERRORS_CACHE_OPTION );
25
+ delete_option( SettingsSave::SETTINGS_OPTION );
26
+ delete_option( Update::VERSION_OPTION );
27
+ }
28
+ }
src/Plugin/Uninstall/WebpFiles.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin\Uninstall;
4
+
5
+ use WebpConverter\Conversion\SkipLarger;
6
+ use WebpConverter\Conversion\Formats;
7
+
8
+ /**
9
+ * Removes all output files /uploads-webpc directory.
10
+ */
11
+ class WebpFiles {
12
+
13
+ /**
14
+ * Removes output images from output directory.
15
+ *
16
+ * @param string|null $output_path Server path.
17
+ *
18
+ * @return void
19
+ */
20
+ public static function remove_webp_files( string $output_path = null ) {
21
+ $path = ( $output_path !== null ) ? $output_path : apply_filters( 'webpc_dir_path', '', 'webp' );
22
+ $paths = self::get_paths_from_location( $path );
23
+ $paths[] = $path;
24
+ self::remove_files( $paths );
25
+ }
26
+
27
+ /**
28
+ * Searches list of paths to remove from given directory.
29
+ *
30
+ * @param string $path Server path.
31
+ * @param string[] $paths Server paths already found.
32
+ *
33
+ * @return string[] Server paths.
34
+ */
35
+ private static function get_paths_from_location( string $path, array $paths = [] ): array {
36
+ if ( ! file_exists( $path ) ) {
37
+ return $paths;
38
+ }
39
+
40
+ $files = glob( $path . '/*' ) ?: [];
41
+ foreach ( $files as $file ) {
42
+ if ( is_dir( $file ) ) {
43
+ $paths = self::get_paths_from_location( $file, $paths );
44
+ }
45
+ $paths[] = $file;
46
+ }
47
+ return $paths;
48
+ }
49
+
50
+ /**
51
+ * Removes selected paths from disc.
52
+ *
53
+ * @param string[] $paths Server paths.
54
+ *
55
+ * @return void
56
+ */
57
+ private static function remove_files( array $paths ) {
58
+ if ( ! $paths ) {
59
+ return;
60
+ }
61
+
62
+ $extensions = ( new Formats() )->get_format_extensions();
63
+ $extensions[] = SkipLarger::DELETED_FILE_EXTENSION;
64
+
65
+ foreach ( $paths as $path ) {
66
+ if ( ! is_writable( $path ) || ! is_writable( dirname( $path ) ) ) {
67
+ continue;
68
+ }
69
+
70
+ $extension = pathinfo( $path, PATHINFO_EXTENSION );
71
+ if ( is_file( $path ) && in_array( $extension, $extensions ) ) {
72
+ unlink( $path );
73
+ } elseif ( is_dir( $path ) ) {
74
+ rmdir( $path );
75
+ }
76
+ }
77
+ }
78
+ }
src/Plugin/Update.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Loader\LoaderAbstract;
9
+ use WebpConverter\Plugin\Uninstall\WebpFiles;
10
+ use WebpConverter\Settings\SettingsSave;
11
+ use WebpConverter\Notice\WelcomeNotice;
12
+
13
+ /**
14
+ * Runs actions after plugin update to new version.
15
+ */
16
+ class Update extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
17
+
18
+ const VERSION_OPTION = 'webpc_latest_version';
19
+
20
+ /**
21
+ * Integrates with WordPress hooks.
22
+ *
23
+ * @return void
24
+ */
25
+ public function init_hooks() {
26
+ add_action( 'admin_init', [ $this, 'run_actions_after_update' ], 0 );
27
+ }
28
+
29
+ /**
30
+ * Initializes actions after updating plugin to different version.
31
+ *
32
+ * @return void
33
+ * @internal
34
+ */
35
+ public function run_actions_after_update() {
36
+ $version = get_option( self::VERSION_OPTION, null );
37
+ if ( $version === WEBPC_VERSION ) {
38
+ return;
39
+ }
40
+
41
+ if ( $version !== null ) {
42
+ WelcomeNotice::disable_notice();
43
+ }
44
+
45
+ do_action( LoaderAbstract::ACTION_NAME, true );
46
+ update_option( self::VERSION_OPTION, WEBPC_VERSION );
47
+ }
48
+ }
src/PluginAccessAbstract.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+ use WebpConverter\WebpConverter;
7
+ use WebpConverter\HookableInterface;
8
+
9
+ /**
10
+ * Allows class to access handle to main plugin class.
11
+ */
12
+ abstract class PluginAccessAbstract implements PluginAccessInterface {
13
+
14
+ /**
15
+ * Object of main plugin class.
16
+ *
17
+ * @var WebpConverter
18
+ */
19
+ private $plugin;
20
+
21
+ /**
22
+ * Saves handler for object of plugin main class.
23
+ *
24
+ * @param WebpConverter $plugin Main class of plugin.
25
+ *
26
+ * @return void
27
+ */
28
+ public function set_plugin( WebpConverter $plugin ) {
29
+ $this->plugin = $plugin;
30
+ }
31
+
32
+ /**
33
+ * Saves handler for object of plugin main class and initializes integration with WordPress hooks.
34
+ *
35
+ * @param WebpConverter $plugin Main class of plugin.
36
+ *
37
+ * @return void
38
+ */
39
+ public function set_plugin_hookable( WebpConverter $plugin ) {
40
+ $this->set_plugin( $plugin );
41
+ if ( $this instanceof HookableInterface ) {
42
+ $this->init_hooks();
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Returns handler for object of plugin main class.
48
+ *
49
+ * @return WebpConverter Main class of plugin.
50
+ */
51
+ public function get_plugin(): WebpConverter {
52
+ return $this->plugin;
53
+ }
54
+ }
src/PluginAccessInterface.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter;
4
+
5
+ use WebpConverter\WebpConverter;
6
+ use WebpConverter\PluginAccessAbstract;
7
+
8
+ /**
9
+ * Interface for class having access handle to main plugin class.
10
+ */
11
+ interface PluginAccessInterface {
12
+
13
+ /**
14
+ * Saves handler for object of plugin main class.
15
+ *
16
+ * @param WebpConverter $plugin Main class of plugin.
17
+ *
18
+ * @return void
19
+ */
20
+ public function set_plugin( WebpConverter $plugin );
21
+
22
+ /**
23
+ * Integrates with WordPress hooks.
24
+ *
25
+ * @param WebpConverter $plugin Main class of plugin.
26
+ *
27
+ * @return void
28
+ */
29
+ public function set_plugin_hookable( WebpConverter $plugin );
30
+
31
+ /**
32
+ * Returns handler for object of plugin main class.
33
+ *
34
+ * @return WebpConverter Main class of plugin.
35
+ */
36
+ public function get_plugin(): WebpConverter;
37
+ }
src/Settings/AdminAssets.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings;
4
+
5
+ use WebpConverter\HookableInterface;
6
+
7
+ /**
8
+ * Initializes loading of assets in admin panel.
9
+ */
10
+ class AdminAssets implements HookableInterface {
11
+
12
+ /**
13
+ * URL of CSS file.
14
+ *
15
+ * @var string
16
+ */
17
+ private $path_css = WEBPC_URL . 'assets/build/css/styles.css';
18
+
19
+ /**
20
+ * URL of JS file.
21
+ *
22
+ * @var string
23
+ */
24
+ private $path_js = WEBPC_URL . 'assets/build/js/scripts.js';
25
+
26
+ /**
27
+ * Integrates with WordPress hooks.
28
+ *
29
+ * @return void
30
+ */
31
+ public function init_hooks() {
32
+ add_filter( 'admin_enqueue_scripts', [ $this, 'load_styles' ] );
33
+ add_filter( 'admin_enqueue_scripts', [ $this, 'load_scripts' ] );
34
+ }
35
+
36
+ /**
37
+ * Loads CSS assets.
38
+ *
39
+ * @return void
40
+ * @internal
41
+ */
42
+ public function load_styles() {
43
+ wp_register_style( 'webp-converter', $this->path_css, [], WEBPC_VERSION );
44
+ wp_enqueue_style( 'webp-converter' );
45
+ }
46
+
47
+ /**
48
+ * Loads JavaScript assets.
49
+ *
50
+ * @return void
51
+ * @internal
52
+ */
53
+ public function load_scripts() {
54
+ wp_register_script( 'webp-converter', $this->path_js, [ 'jquery' ], WEBPC_VERSION, true );
55
+ wp_enqueue_script( 'webp-converter' );
56
+ }
57
+ }
src/Settings/Option/ConversionMethodOption.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+ use WebpConverter\Conversion\Methods;
8
+
9
+ /**
10
+ * Handles data about "Conversion method" field in plugin settings.
11
+ */
12
+ class ConversionMethodOption extends OptionAbstract implements OptionInterface {
13
+
14
+ const LOADER_TYPE = 'method';
15
+
16
+ /**
17
+ * Object of integration class supports all output formats.
18
+ *
19
+ * @var Methods
20
+ */
21
+ private $methods_integration;
22
+
23
+ /**
24
+ * ConversionMethodOption constructor.
25
+ */
26
+ public function __construct() {
27
+ $this->methods_integration = new Methods();
28
+ }
29
+
30
+ /**
31
+ * Returns name of option.
32
+ *
33
+ * @return string Option name.
34
+ */
35
+ public function get_name(): string {
36
+ return self::LOADER_TYPE;
37
+ }
38
+
39
+ /**
40
+ * Returns type of field.
41
+ *
42
+ * @return string Field type.
43
+ */
44
+ public function get_type(): string {
45
+ return OptionAbstract::OPTION_TYPE_RADIO;
46
+ }
47
+
48
+ /**
49
+ * Returns label of option.
50
+ *
51
+ * @return string Option label.
52
+ */
53
+ public function get_label(): string {
54
+ return __( 'Conversion method', 'webp-converter-for-media' );
55
+ }
56
+
57
+ /**
58
+ * Returns additional information of field.
59
+ *
60
+ * @return string Additional information.
61
+ */
62
+ public function get_info(): string {
63
+ return __( 'The configuration for advanced users.', 'webp-converter-for-media' );
64
+ }
65
+
66
+ /**
67
+ * Returns available values for field.
68
+ *
69
+ * @param mixed[] $settings Plugin settings.
70
+ *
71
+ * @return string[] Values for field.
72
+ */
73
+ public function get_values( array $settings ): array {
74
+ return $this->methods_integration->get_methods();
75
+ }
76
+
77
+ /**
78
+ * Returns unavailable values for field.
79
+ *
80
+ * @param mixed[] $settings Plugin settings.
81
+ *
82
+ * @return string[] Disabled values for field.
83
+ */
84
+ public function get_disabled_values( array $settings ): array {
85
+ $methods = $this->methods_integration->get_methods();
86
+ $methods_available = $this->methods_integration->get_available_methods();
87
+ return array_keys( array_diff( $methods, $methods_available ) );
88
+ }
89
+
90
+ /**
91
+ * Returns default value of field.
92
+ *
93
+ * @param mixed[]|null $settings Plugin settings.
94
+ *
95
+ * @return string Default value of field.
96
+ */
97
+ public function get_default_value( array $settings = null ): string {
98
+ return array_keys( $this->methods_integration->get_available_methods() )[0] ?? '';
99
+ }
100
+ }
src/Settings/Option/ExtraFeaturesOption.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+ use WebpConverter\Settings\Option\ConversionMethodOption;
8
+ use WebpConverter\Settings\Option\LoaderTypeOption;
9
+ use WebpConverter\Conversion\Method\ImagickMethod;
10
+ use WebpConverter\Loader\HtaccessLoader;
11
+
12
+ /**
13
+ * Handles data about "Extra features" field in plugin settings.
14
+ */
15
+ class ExtraFeaturesOption extends OptionAbstract implements OptionInterface {
16
+
17
+ const LOADER_TYPE = 'features';
18
+
19
+ /**
20
+ * Returns name of option.
21
+ *
22
+ * @return string Option name.
23
+ */
24
+ public function get_name(): string {
25
+ return self::LOADER_TYPE;
26
+ }
27
+
28
+ /**
29
+ * Returns type of field.
30
+ *
31
+ * @return string Field type.
32
+ */
33
+ public function get_type(): string {
34
+ return OptionAbstract::OPTION_TYPE_CHECKBOX;
35
+ }
36
+
37
+ /**
38
+ * Returns label of option.
39
+ *
40
+ * @return string Option label.
41
+ */
42
+ public function get_label(): string {
43
+ return __( 'Extra features', 'webp-converter-for-media' );
44
+ }
45
+
46
+ /**
47
+ * Returns additional information of field.
48
+ *
49
+ * @return string Additional information.
50
+ */
51
+ public function get_info(): string {
52
+ return __( 'Options allow you to enable new functionalities that will increase capabilities of plugin', 'webp-converter-for-media' );
53
+ }
54
+
55
+ /**
56
+ * Returns available values for field.
57
+ *
58
+ * @param mixed[] $settings Plugin settings.
59
+ *
60
+ * @return string[] Values for field.
61
+ */
62
+ public function get_values( array $settings ): array {
63
+ return [
64
+ 'only_smaller' => __(
65
+ 'Automatic removal of WebP files larger than original',
66
+ 'webp-converter-for-media'
67
+ ),
68
+ 'mod_expires' => __(
69
+ 'Browser Caching for WebP files (saving images in browser cache memory)',
70
+ 'webp-converter-for-media'
71
+ ),
72
+ 'keep_metadata' => __(
73
+ 'Keep images metadata stored in EXIF or XMP formats (only available for Imagick conversion method)',
74
+ 'webp-converter-for-media'
75
+ ),
76
+ 'cron_enabled' => __(
77
+ 'Enable cron to automatically convert images from outside Media Library (images from Media Library are converted immediately after upload)',
78
+ 'webp-converter-for-media'
79
+ ),
80
+ 'cron_conversion' => __(
81
+ 'Enable cron to convert images uploaded to Media Library to speed up process of adding images (deactivate this option if images added to Media Library are not automatically converted)',
82
+ 'webp-converter-for-media'
83
+ ),
84
+ 'referer_disabled' => __(
85
+ 'Force redirections to WebP for all domains (by default, images in WebP are loaded only in domain of your website - when image is displayed via URL on another domain that original file is loaded)',
86
+ 'webp-converter-for-media'
87
+ ),
88
+ 'debug_enabled' => __(
89
+ 'Log errors while converting to debug.log file (when debugging in WordPress is active)',
90
+ 'webp-converter-for-media'
91
+ ),
92
+ ];
93
+ }
94
+
95
+ /**
96
+ * Returns unavailable values for field.
97
+ *
98
+ * @param mixed[] $settings Plugin settings.
99
+ *
100
+ * @return string[] Disabled values for field.
101
+ */
102
+ public function get_disabled_values( array $settings ): array {
103
+ $values = [];
104
+ if ( ( $settings[ ConversionMethodOption::LOADER_TYPE ] ?? '' ) !== ImagickMethod::METHOD_NAME ) {
105
+ $values[] = 'keep_metadata';
106
+ }
107
+ if ( ( $settings[ LoaderTypeOption::LOADER_TYPE ] ?? '' ) !== HtaccessLoader::LOADER_TYPE ) {
108
+ $values[] = 'referer_disabled';
109
+ }
110
+ return $values;
111
+ }
112
+
113
+ /**
114
+ * Returns default value of field.
115
+ *
116
+ * @param mixed[]|null $settings Plugin settings.
117
+ *
118
+ * @return string[] Default value of field.
119
+ */
120
+ public function get_default_value( array $settings = null ): array {
121
+ return [
122
+ 'only_smaller',
123
+ 'mod_expires',
124
+ 'cron_conversion',
125
+ 'debug_enabled',
126
+ ];
127
+ }
128
+ }
src/Settings/Option/ImagesQualityOption.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+
8
+ /**
9
+ * Handles data about "Images quality" field in plugin settings.
10
+ */
11
+ class ImagesQualityOption extends OptionAbstract implements OptionInterface {
12
+
13
+ const LOADER_TYPE = 'quality';
14
+
15
+ /**
16
+ * Returns name of option.
17
+ *
18
+ * @return string Option name.
19
+ */
20
+ public function get_name(): string {
21
+ return self::LOADER_TYPE;
22
+ }
23
+
24
+ /**
25
+ * Returns type of field.
26
+ *
27
+ * @return string Field type.
28
+ */
29
+ public function get_type(): string {
30
+ return OptionAbstract::OPTION_TYPE_QUALITY;
31
+ }
32
+
33
+ /**
34
+ * Returns label of option.
35
+ *
36
+ * @return string Option label.
37
+ */
38
+ public function get_label(): string {
39
+ return __( 'Images quality', 'webp-converter-for-media' );
40
+ }
41
+
42
+ /**
43
+ * Returns additional information of field.
44
+ *
45
+ * @return string Additional information.
46
+ */
47
+ public function get_info(): string {
48
+ return __( 'Adjust the quality of the images being converted. Remember that higher quality also means larger file sizes. The recommended value is 85%.', 'webp-converter-for-media' );
49
+ }
50
+
51
+ /**
52
+ * Returns available values for field.
53
+ *
54
+ * @param mixed[] $settings Plugin settings.
55
+ *
56
+ * @return string[] Values for field.
57
+ */
58
+ public function get_values( array $settings ): array {
59
+ return [
60
+ '75' => '75%',
61
+ '80' => '80%',
62
+ '85' => '85%',
63
+ '90' => '90%',
64
+ '95' => '95%',
65
+ '100' => '100%',
66
+ ];
67
+ }
68
+
69
+ /**
70
+ * Returns default value of field.
71
+ *
72
+ * @param mixed[]|null $settings Plugin settings.
73
+ *
74
+ * @return string Default value of field.
75
+ */
76
+ public function get_default_value( array $settings = null ): string {
77
+ return '85';
78
+ }
79
+ }
src/Settings/Option/LoaderTypeOption.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+ use WebpConverter\Loader\HtaccessLoader;
8
+ use WebpConverter\Loader\PassthruLoader;
9
+
10
+ /**
11
+ * Handles data about "Image loading mode" field in plugin settings.
12
+ */
13
+ class LoaderTypeOption extends OptionAbstract implements OptionInterface {
14
+
15
+ const LOADER_TYPE = 'loader_type';
16
+
17
+ /**
18
+ * Returns name of option.
19
+ *
20
+ * @return string Option name.
21
+ */
22
+ public function get_name(): string {
23
+ return self::LOADER_TYPE;
24
+ }
25
+
26
+ /**
27
+ * Returns type of field.
28
+ *
29
+ * @return string Field type.
30
+ */
31
+ public function get_type(): string {
32
+ return OptionAbstract::OPTION_TYPE_RADIO;
33
+ }
34
+
35
+ /**
36
+ * Returns label of option.
37
+ *
38
+ * @return string Option label.
39
+ */
40
+ public function get_label(): string {
41
+ return __( 'Image loading mode', 'webp-converter-for-media' );
42
+ }
43
+
44
+ /**
45
+ * Returns additional information of field.
46
+ *
47
+ * @return string Additional information.
48
+ */
49
+ public function get_info(): string {
50
+ return __( 'By changing image loading mode it allows you to bypass some server configuration problems.', 'webp-converter-for-media' );
51
+ }
52
+
53
+ /**
54
+ * Returns available values for field.
55
+ *
56
+ * @param mixed[] $settings Plugin settings.
57
+ *
58
+ * @return string[] Values for field.
59
+ */
60
+ public function get_values( array $settings ): array {
61
+ return [
62
+ HtaccessLoader::LOADER_TYPE => sprintf(
63
+ /* translators: %s: loader type */
64
+ __( '%s (recommended)', 'webp-converter-for-media' ),
65
+ __( 'via .htaccess', 'webp-converter-for-media' )
66
+ ),
67
+ PassthruLoader::LOADER_TYPE => sprintf(
68
+ /* translators: %s: loader type */
69
+ __( '%s (without rewrites in .htaccess files or Nginx configuration)', 'webp-converter-for-media' ),
70
+ 'Pass Thru'
71
+ ),
72
+ ];
73
+ }
74
+
75
+ /**
76
+ * Returns default value of field.
77
+ *
78
+ * @param mixed[]|null $settings Plugin settings.
79
+ *
80
+ * @return string Default value of field.
81
+ */
82
+ public function get_default_value( array $settings = null ): string {
83
+ return HtaccessLoader::LOADER_TYPE;
84
+ }
85
+ }
src/Settings/Option/OptionAbstract.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionInterface;
6
+
7
+ /**
8
+ * Abstract class for class that supports notice displayed in admin panel.
9
+ */
10
+ abstract class OptionAbstract implements OptionInterface {
11
+
12
+ const OPTION_TYPE_CHECKBOX = 'checkbox';
13
+ const OPTION_TYPE_RADIO = 'radio';
14
+ const OPTION_TYPE_QUALITY = 'quality';
15
+
16
+ /**
17
+ * Returns additional information of field.
18
+ *
19
+ * @return string Additional information.
20
+ */
21
+ public function get_info(): string {
22
+ return '';
23
+ }
24
+
25
+ /**
26
+ * Returns unavailable values for field.
27
+ *
28
+ * @param mixed[] $settings Plugin settings.
29
+ *
30
+ * @return string[] Disabled values for field.
31
+ */
32
+ public function get_disabled_values( array $settings ): array {
33
+ return [];
34
+ }
35
+
36
+ /**
37
+ * Returns default value of field when debugging.
38
+ *
39
+ * @param mixed[] $settings Plugin settings.
40
+ *
41
+ * @return string|string[] Default value of field for debug.
42
+ */
43
+ public function get_value_for_debug( array $settings ) {
44
+ return $this->get_default_value( $settings );
45
+ }
46
+ }
src/Settings/Option/OptionIntegration.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionInterface;
6
+ use WebpConverter\Settings\Option\OptionAbstract;
7
+
8
+ /**
9
+ * Allows to integrate with field in plugin settings by specifying its settings and value.
10
+ */
11
+ class OptionIntegration {
12
+
13
+ /**
14
+ * Objects of supported settings options.
15
+ *
16
+ * @var OptionInterface
17
+ */
18
+ private $option;
19
+
20
+ /**
21
+ * OptionIntegration constructor.
22
+ *
23
+ * @param OptionInterface $option .
24
+ */
25
+ public function __construct( OptionInterface $option ) {
26
+ $this->option = $option;
27
+ }
28
+
29
+ /**
30
+ * Returns data of option based on plugin settings.
31
+ *
32
+ * @param mixed[] $settings Plugin settings.
33
+ * @param bool $is_debug Is debugging?
34
+ * @param bool $is_save Is saving?
35
+ *
36
+ * @return mixed[] Data of option.
37
+ */
38
+ public function get_option_data( array $settings, bool $is_debug, bool $is_save ): array {
39
+ $option_name = $this->option->get_name();
40
+ $option_type = $this->option->get_type();
41
+ $values = $this->option->get_values( $settings );
42
+ $disabled_values = $this->option->get_disabled_values( $settings );
43
+
44
+ if ( $is_debug ) {
45
+ $value = $this->option->get_value_for_debug( $settings );
46
+ } else {
47
+ $value = ( isset( $settings[ $option_name ] ) || $is_save )
48
+ ? $this->get_option_value( $settings[ $option_name ] ?? '', $option_type, $values, $disabled_values )
49
+ : $this->option->get_default_value( $settings );
50
+ }
51
+
52
+ return [
53
+ 'name' => $this->option->get_name(),
54
+ 'type' => $option_type,
55
+ 'label' => $this->option->get_label(),
56
+ 'info' => $this->option->get_info(),
57
+ 'values' => $values,
58
+ 'disabled' => $disabled_values,
59
+ 'value' => $value,
60
+ ];
61
+ }
62
+
63
+ /**
64
+ * Returns value of option based on plugin settings.
65
+ *
66
+ * @param mixed $current_value Value from plugin settings.
67
+ * @param string $option_type Key of option.
68
+ * @param string[] $values Values of option.
69
+ * @param string[] $disabled_values Disabled values of option.
70
+ *
71
+ * @return string[]|string Value of option.
72
+ */
73
+ private function get_option_value( $current_value, string $option_type, array $values, array $disabled_values ) {
74
+ $valid_values = [];
75
+ foreach ( (array) $current_value as $option_value ) {
76
+ if ( array_key_exists( $option_value, $values ) && ! in_array( $option_value, $disabled_values ) ) {
77
+ $valid_values[] = $option_value;
78
+ }
79
+ }
80
+
81
+ return ( in_array( $option_type, [ OptionAbstract::OPTION_TYPE_RADIO, OptionAbstract::OPTION_TYPE_QUALITY ] ) )
82
+ ? ( $valid_values[0] ?? '' )
83
+ : $valid_values;
84
+ }
85
+ }
src/Settings/Option/OptionInterface.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Loader\HtaccessLoader;
6
+ use WebpConverter\Loader\PassthruLoader;
7
+ use WebpConverter\Conversion\Method\GdMethod;
8
+ use WebpConverter\Conversion\Method\ImagickMethod;
9
+
10
+ /**
11
+ * Interface for class that supports data field in plugin settings.
12
+ */
13
+ interface OptionInterface {
14
+
15
+ /**
16
+ * Returns name of option.
17
+ *
18
+ * @return string Option name.
19
+ */
20
+ public function get_name(): string;
21
+
22
+ /**
23
+ * Returns type of field.
24
+ *
25
+ * @return string Field type.
26
+ */
27
+ public function get_type(): string;
28
+
29
+ /**
30
+ * Returns label of option.
31
+ *
32
+ * @return string Option label.
33
+ */
34
+ public function get_label(): string;
35
+
36
+ /**
37
+ * Returns additional information of field.
38
+ *
39
+ * @return string Additional information.
40
+ */
41
+ public function get_info(): string;
42
+
43
+ /**
44
+ * Returns available values for field.
45
+ *
46
+ * @param mixed[] $settings Plugin settings.
47
+ *
48
+ * @return string[] Values for field.
49
+ */
50
+ public function get_values( array $settings ): array;
51
+
52
+ /**
53
+ * Returns unavailable values for field.
54
+ *
55
+ * @param mixed[] $settings Plugin settings.
56
+ *
57
+ * @return string[] Disabled values for field.
58
+ */
59
+ public function get_disabled_values( array $settings ): array;
60
+
61
+ /**
62
+ * Returns default value of field.
63
+ *
64
+ * @param mixed[]|null $settings Plugin settings.
65
+ *
66
+ * @return string|string[] Default value of field.
67
+ */
68
+ public function get_default_value( array $settings = null );
69
+
70
+ /**
71
+ * Returns default value of field when debugging.
72
+ *
73
+ * @param mixed[] $settings Plugin settings.
74
+ *
75
+ * @return string|string[] Default value of field for debug.
76
+ */
77
+ public function get_value_for_debug( array $settings );
78
+ }
src/Settings/Option/OutputFormatsOption.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+ use WebpConverter\Settings\Option\ConversionMethodOption;
8
+ use WebpConverter\Conversion\Formats;
9
+ use WebpConverter\Conversion\Format\WebpFormat;
10
+
11
+ /**
12
+ * Handles data about "Supported output formats" field in plugin settings.
13
+ */
14
+ class OutputFormatsOption extends OptionAbstract implements OptionInterface {
15
+
16
+ const LOADER_TYPE = 'output_formats';
17
+
18
+ /**
19
+ * Object of integration class supports all conversion methods.
20
+ *
21
+ * @var Formats
22
+ */
23
+ private $formats_integration;
24
+
25
+ /**
26
+ * OutputFormatsOption constructor.
27
+ */
28
+ public function __construct() {
29
+ $this->formats_integration = new Formats();
30
+ }
31
+
32
+ /**
33
+ * Returns name of option.
34
+ *
35
+ * @return string Option name.
36
+ */
37
+ public function get_name(): string {
38
+ return self::LOADER_TYPE;
39
+ }
40
+
41
+ /**
42
+ * Returns type of field.
43
+ *
44
+ * @return string Field type.
45
+ */
46
+ public function get_type(): string {
47
+ return OptionAbstract::OPTION_TYPE_CHECKBOX;
48
+ }
49
+
50
+ /**
51
+ * Returns label of option.
52
+ *
53
+ * @return string Option label.
54
+ */
55
+ public function get_label(): string {
56
+ return __( 'List of supported output formats', 'webp-converter-for-media' );
57
+ }
58
+
59
+ /**
60
+ * Returns available values for field.
61
+ *
62
+ * @param mixed[] $settings Plugin settings.
63
+ *
64
+ * @return string[] Values for field.
65
+ */
66
+ public function get_values( array $settings ): array {
67
+ return $this->formats_integration->get_formats();
68
+ }
69
+
70
+ /**
71
+ * Returns default value of field.
72
+ *
73
+ * @param mixed[]|null $settings Plugin settings.
74
+ *
75
+ * @return string[] Default value of field.
76
+ */
77
+ public function get_default_value( array $settings = null ): array {
78
+ $method = $settings['method'] ?? ( new ConversionMethodOption() )->get_default_value();
79
+ $formats = array_keys( $this->formats_integration->get_available_formats( $method ) );
80
+
81
+ return ( in_array( WebpFormat::FORMAT_EXTENSION, $formats ) ) ? [ WebpFormat::FORMAT_EXTENSION ] : [];
82
+ }
83
+
84
+ /**
85
+ * Returns unavailable values for field.
86
+ *
87
+ * @param mixed[] $settings Plugin settings.
88
+ *
89
+ * @return string[] Disabled values for field.
90
+ */
91
+ public function get_disabled_values( array $settings ): array {
92
+ $method = $settings['method'] ?? ( new ConversionMethodOption() )->get_default_value();
93
+ $formats = $this->formats_integration->get_formats();
94
+ $formats_available = $this->formats_integration->get_available_formats( $method );
95
+ return array_keys( array_diff( $formats, $formats_available ) );
96
+ }
97
+ }
src/Settings/Option/SupportedDirectoriesOption.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+ use WebpConverter\Conversion\Directories;
8
+
9
+ /**
10
+ * Handles data about "Supported directories" field in plugin settings.
11
+ */
12
+ class SupportedDirectoriesOption extends OptionAbstract implements OptionInterface {
13
+
14
+ const LOADER_TYPE = 'dirs';
15
+
16
+ /**
17
+ * Returns name of option.
18
+ *
19
+ * @return string Option name.
20
+ */
21
+ public function get_name(): string {
22
+ return self::LOADER_TYPE;
23
+ }
24
+
25
+ /**
26
+ * Returns type of field.
27
+ *
28
+ * @return string Field type.
29
+ */
30
+ public function get_type(): string {
31
+ return OptionAbstract::OPTION_TYPE_CHECKBOX;
32
+ }
33
+
34
+ /**
35
+ * Returns label of option.
36
+ *
37
+ * @return string Option label.
38
+ */
39
+ public function get_label(): string {
40
+ return __( 'List of supported directories', 'webp-converter-for-media' );
41
+ }
42
+
43
+ /**
44
+ * Returns additional information of field.
45
+ *
46
+ * @return string Additional information.
47
+ */
48
+ public function get_info(): string {
49
+ return __( 'Files from these directories will be supported in output formats.', 'webp-converter-for-media' );
50
+ }
51
+
52
+ /**
53
+ * Returns available values for field.
54
+ *
55
+ * @param mixed[] $settings Plugin settings.
56
+ *
57
+ * @return string[] Values for field.
58
+ */
59
+ public function get_values( array $settings ): array {
60
+ return ( new Directories() )->get_directories();
61
+ }
62
+
63
+ /**
64
+ * Returns default value of field.
65
+ *
66
+ * @param mixed[]|null $settings Plugin settings.
67
+ *
68
+ * @return string[] Default value of field.
69
+ */
70
+ public function get_default_value( array $settings = null ): array {
71
+ return [ 'uploads' ];
72
+ }
73
+
74
+ /**
75
+ * Returns default value of field when debugging.
76
+ *
77
+ * @param mixed[] $settings Plugin settings.
78
+ *
79
+ * @return string[] Default value of field for debug.
80
+ */
81
+ public function get_value_for_debug( array $settings ): array {
82
+ return [ 'uploads' ];
83
+ }
84
+ }
src/Settings/Option/SupportedExtensionsOption.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Option;
4
+
5
+ use WebpConverter\Settings\Option\OptionAbstract;
6
+ use WebpConverter\Settings\Option\OptionInterface;
7
+
8
+ /**
9
+ * Handles data about "Supported files extensions" field in plugin settings.
10
+ */
11
+ class SupportedExtensionsOption extends OptionAbstract implements OptionInterface {
12
+
13
+ const LOADER_TYPE = 'extensions';
14
+
15
+ /**
16
+ * Returns name of option.
17
+ *
18
+ * @return string Option name.
19
+ */
20
+ public function get_name(): string {
21
+ return self::LOADER_TYPE;
22
+ }
23
+
24
+ /**
25
+ * Returns type of field.
26
+ *
27
+ * @return string Field type.
28
+ */
29
+ public function get_type(): string {
30
+ return OptionAbstract::OPTION_TYPE_CHECKBOX;
31
+ }
32
+
33
+ /**
34
+ * Returns label of option.
35
+ *
36
+ * @return string Option label.
37
+ */
38
+ public function get_label(): string {
39
+ return __( 'List of supported files extensions', 'webp-converter-for-media' );
40
+ }
41
+
42
+ /**
43
+ * Returns available values for field.
44
+ *
45
+ * @param mixed[] $settings Plugin settings.
46
+ *
47
+ * @return string[] Values for field.
48
+ */
49
+ public function get_values( array $settings ): array {
50
+ return [
51
+ 'jpg' => '.jpg',
52
+ 'jpeg' => '.jpeg',
53
+ 'png' => '.png',
54
+ 'gif' => '.gif',
55
+ ];
56
+ }
57
+
58
+ /**
59
+ * Returns default value of field.
60
+ *
61
+ * @param mixed[]|null $settings Plugin settings.
62
+ *
63
+ * @return string[] Default value of field.
64
+ */
65
+ public function get_default_value( array $settings = null ): array {
66
+ return [ 'jpg', 'jpeg', 'png' ];
67
+ }
68
+
69
+ /**
70
+ * Returns default value of field when debugging.
71
+ *
72
+ * @param mixed[] $settings Plugin settings.
73
+ *
74
+ * @return string[] Default value of field for debug.
75
+ */
76
+ public function get_value_for_debug( array $settings ): array {
77
+ return [ 'png2', 'png' ];
78
+ }
79
+ }
src/Settings/Options.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings;
4
+
5
+ use WebpConverter\Settings\Option\OptionInterface;
6
+ use WebpConverter\Settings\Option\OptionIntegration;
7
+ use WebpConverter\Settings\Option\LoaderTypeOption;
8
+ use WebpConverter\Settings\Option\OutputFormatsOption;
9
+ use WebpConverter\Settings\Option\SupportedExtensionsOption;
10
+ use WebpConverter\Settings\Option\SupportedDirectoriesOption;
11
+ use WebpConverter\Settings\Option\ConversionMethodOption;
12
+ use WebpConverter\Settings\Option\ImagesQualityOption;
13
+ use WebpConverter\Settings\Option\ExtraFeaturesOption;
14
+
15
+ /**
16
+ * Allows to integration with plugin settings by providing list of settings fields and saved values.
17
+ */
18
+ class Options {
19
+
20
+ /**
21
+ * Returns options of plugin settings.
22
+ *
23
+ * @param bool $is_debug Is debugging?
24
+ * @param array[]|null $posted_settings Settings submitted in form.
25
+ *
26
+ * @return array[] Options of plugin settings.
27
+ */
28
+ public function get_options( bool $is_debug = false, array $posted_settings = null ): array {
29
+ $is_save = ( $posted_settings !== null );
30
+ $settings = ( $is_save ) ? $posted_settings : get_option( SettingsSave::SETTINGS_OPTION, [] );
31
+
32
+ $options = [];
33
+ foreach ( $this->get_option_objects() as $option_object ) {
34
+ $options[] = ( new OptionIntegration( $option_object ) )->get_option_data( $settings, $is_debug, $is_save );
35
+ }
36
+ return $options;
37
+ }
38
+
39
+ /**
40
+ * Returns objects for options of plugin settings.
41
+ *
42
+ * @return OptionInterface[] .
43
+ */
44
+ private function get_option_objects(): array {
45
+ return [
46
+ new LoaderTypeOption(),
47
+ new SupportedExtensionsOption(),
48
+ new SupportedDirectoriesOption(),
49
+ new ConversionMethodOption(),
50
+ new OutputFormatsOption(),
51
+ new ImagesQualityOption(),
52
+ new ExtraFeaturesOption(),
53
+ ];
54
+ }
55
+
56
+ /**
57
+ * Returns values of plugin settings.
58
+ *
59
+ * @param bool $is_debug Is debugging?
60
+ * @param array[]|null $posted_settings Settings submitted in form.
61
+ *
62
+ * @return array[] Values of plugin settings.
63
+ */
64
+ public function get_values( bool $is_debug = false, array $posted_settings = null ): array {
65
+ $values = [];
66
+ foreach ( $this->get_options( $is_debug, $posted_settings ) as $option ) {
67
+ $values[ $option['name'] ] = $option['value'];
68
+ }
69
+ return $values;
70
+ }
71
+ }
src/Settings/Page/DebugPage.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace WebpConverter\Settings\Page;
5
+
6
+ use WebpConverter\Settings\Page\PageAbstract;
7
+ use WebpConverter\Settings\Page\PageInterface;
8
+ use WebpConverter\Loader\LoaderAbstract;
9
+ use WebpConverter\Settings\SettingsSave;
10
+ use WebpConverter\Helper\ViewLoader;
11
+ use WebpConverter\Helper\FileLoader;
12
+ use WebpConverter\Error\RewritesError;
13
+ use WebpConverter\Settings\Pages;
14
+
15
+ /**
16
+ * Supports debug tab in plugin settings page.
17
+ */
18
+ class DebugPage extends PageAbstract implements PageInterface {
19
+
20
+ const PAGE_VIEW_PATH = 'views/settings-debug.php';
21
+
22
+ /**
23
+ * Returns status if view is active.
24
+ *
25
+ * @return bool Is view active?
26
+ */
27
+ public function is_page_active(): bool {
28
+ return ( isset( $_GET['action'] ) && ( $_GET['action'] === 'server' ) ); // phpcs:ignore
29
+ }
30
+
31
+ /**
32
+ * Displays view for plugin settings page.
33
+ *
34
+ * @return void
35
+ */
36
+ public function show_page_view() {
37
+ $plugin = $this->get_plugin();
38
+ $uploads_url = apply_filters( 'webpc_dir_url', '', 'uploads' );
39
+ $uploads_path = apply_filters( 'webpc_dir_path', '', 'uploads' );
40
+
41
+ do_action( LoaderAbstract::ACTION_NAME, true, true );
42
+
43
+ ViewLoader::load_view(
44
+ self::PAGE_VIEW_PATH,
45
+ [
46
+ 'settings_url' => sprintf(
47
+ '%1$s&%2$s=%3$s',
48
+ Pages::get_settings_page_url(),
49
+ SettingsSave::NONCE_PARAM_KEY,
50
+ wp_create_nonce( SettingsSave::NONCE_PARAM_VALUE )
51
+ ),
52
+ 'settings_debug_url' => sprintf(
53
+ '%s&action=server',
54
+ Pages::get_settings_page_url()
55
+ ),
56
+ 'size_png_path' => FileLoader::get_file_size_by_path(
57
+ $uploads_path . RewritesError::PATH_OUTPUT_FILE_PNG
58
+ ),
59
+ 'size_png2_path' => FileLoader::get_file_size_by_path(
60
+ $uploads_path . RewritesError::PATH_OUTPUT_FILE_PNG2
61
+ ),
62
+ 'size_png_url' => FileLoader::get_file_size_by_url(
63
+ $uploads_url . RewritesError::PATH_OUTPUT_FILE_PNG,
64
+ $plugin,
65
+ false
66
+ ),
67
+ 'size_png2_url' => FileLoader::get_file_size_by_url(
68
+ $uploads_url . RewritesError::PATH_OUTPUT_FILE_PNG2,
69
+ $plugin,
70
+ false
71
+ ),
72
+ 'size_png_as_webp_url' => FileLoader::get_file_size_by_url(
73
+ $uploads_url . RewritesError::PATH_OUTPUT_FILE_PNG,
74
+ $plugin
75
+ ),
76
+ 'size_png2_as_webp_url' => FileLoader::get_file_size_by_url(
77
+ $uploads_url . RewritesError::PATH_OUTPUT_FILE_PNG2,
78
+ $plugin
79
+ ),
80
+ ]
81
+ );
82
+
83
+ do_action( LoaderAbstract::ACTION_NAME, true );
84
+ }
85
+ }
src/Settings/Page/PageAbstract.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Page;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Settings\Page\PageInterface;
8
+
9
+ /**
10
+ * Abstract class for class that supports tab in plugin settings page.
11
+ */
12
+ abstract class PageAbstract extends PluginAccessAbstract implements PluginAccessInterface, PageInterface {
13
+
14
+ /**
15
+ * Returns status if view is active.
16
+ *
17
+ * @return bool Is view active?
18
+ */
19
+ public function is_page_active(): bool {
20
+ return false;
21
+ }
22
+ }
src/Settings/Page/PageInterface.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings\Page;
4
+
5
+ use WebpConverter\PluginAccessInterface;
6
+
7
+ /**
8
+ * Interface for class that supports tab in plugin settings page.
9
+ */
10
+ interface PageInterface extends PluginAccessInterface {
11
+
12
+ /**
13
+ * Returns status if view is active.
14
+ *
15
+ * @return bool Is view active?
16
+ */
17
+ public function is_page_active(): bool;
18
+
19
+ /**
20
+ * Displays view for plugin settings page.
21
+ *
22
+ * @return void
23
+ */
24
+ public function show_page_view();
25
+ }
src/Settings/Page/SettingsPage.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace WebpConverter\Settings\Page;
5
+
6
+ use WebpConverter\Settings\Page\PageAbstract;
7
+ use WebpConverter\Settings\Page\PageInterface;
8
+ use WebpConverter\Conversion\Endpoint\PathsEndpoint;
9
+ use WebpConverter\Conversion\Endpoint\RegenerateEndpoint;
10
+ use WebpConverter\Helper\ViewLoader;
11
+ use WebpConverter\Loader\LoaderAbstract;
12
+ use WebpConverter\Settings\Options;
13
+ use WebpConverter\Settings\Pages;
14
+ use WebpConverter\Settings\SettingsSave;
15
+
16
+ /**
17
+ * Supports default tab in plugin settings page.
18
+ */
19
+ class SettingsPage extends PageAbstract implements PageInterface {
20
+
21
+ const PAGE_VIEW_PATH = 'views/settings.php';
22
+
23
+ /**
24
+ * Returns status if view is active.
25
+ *
26
+ * @return bool Is view active?
27
+ */
28
+ public function is_page_active(): bool {
29
+ return ( ! isset( $_GET['action'] ) || ( $_GET['action'] !== 'server' ) ); // phpcs:ignore
30
+ }
31
+
32
+ /**
33
+ * Displays view for plugin settings page.
34
+ *
35
+ * @return void
36
+ */
37
+ public function show_page_view() {
38
+ $settings_save = new SettingsSave();
39
+ $settings_save->set_plugin( $this->get_plugin() );
40
+ $settings_save->save_settings();
41
+
42
+ ViewLoader::load_view(
43
+ self::PAGE_VIEW_PATH,
44
+ [
45
+ 'errors' => apply_filters( 'webpc_server_errors_messages', [], false, true ),
46
+ 'options' => ( new Options() )->get_options(),
47
+ 'submit_value' => SettingsSave::SUBMIT_VALUE,
48
+ 'settings_url' => sprintf(
49
+ '%1$s&%2$s=%3$s',
50
+ Pages::get_settings_page_url(),
51
+ SettingsSave::NONCE_PARAM_KEY,
52
+ wp_create_nonce( SettingsSave::NONCE_PARAM_VALUE )
53
+ ),
54
+ 'settings_debug_url' => sprintf(
55
+ '%s&action=server',
56
+ Pages::get_settings_page_url()
57
+ ),
58
+ 'api_paths_url' => ( new PathsEndpoint() )->get_route_url(),
59
+ 'api_regenerate_url' => ( new RegenerateEndpoint() )->get_route_url(),
60
+ ]
61
+ );
62
+
63
+ do_action( LoaderAbstract::ACTION_NAME, true );
64
+ }
65
+ }
src/Settings/Pages.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\HookableInterface;
8
+ use WebpConverter\Notice\WelcomeNotice;
9
+ use WebpConverter\Settings\AdminAssets;
10
+ use WebpConverter\Settings\Page\DebugPage;
11
+ use WebpConverter\Settings\Page\PageInterface;
12
+ use WebpConverter\Settings\Page\SettingsPage;
13
+
14
+ /**
15
+ * Adds plugin settings page in admin panel.
16
+ */
17
+ class Pages extends PluginAccessAbstract implements PluginAccessInterface, HookableInterface {
18
+
19
+ const ADMIN_MENU_PAGE = 'webpc_admin_page';
20
+
21
+ /**
22
+ * Integrates with WordPress hooks.
23
+ *
24
+ * @return void
25
+ */
26
+ public function init_hooks() {
27
+ add_action( 'admin_menu', [ $this, 'add_settings_page_for_admin' ] );
28
+ add_action( 'network_admin_menu', [ $this, 'add_settings_page_for_network' ] );
29
+ }
30
+
31
+ /**
32
+ * Returns URL of plugin settings page.
33
+ *
34
+ * @return string
35
+ */
36
+ public static function get_settings_page_url(): string {
37
+ if ( ! is_multisite() ) {
38
+ return menu_page_url( self::ADMIN_MENU_PAGE, false );
39
+ } else {
40
+ return network_admin_url( 'settings.php?page=' . self::ADMIN_MENU_PAGE );
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Adds settings page to menu for non-multisite websites.
46
+ *
47
+ * @return void
48
+ * @internal
49
+ */
50
+ public function add_settings_page_for_admin() {
51
+ if ( is_multisite() ) {
52
+ return;
53
+ }
54
+ $this->add_settings_page( 'options-general.php' );
55
+ }
56
+
57
+ /**
58
+ * Adds settings page to menu for multisite websites.
59
+ *
60
+ * @return void
61
+ * @internal
62
+ */
63
+ public function add_settings_page_for_network() {
64
+ $this->add_settings_page( 'settings.php' );
65
+ }
66
+
67
+ /**
68
+ * Creates plugin settings page in WordPress Admin Dashboard.
69
+ *
70
+ * @param string $menu_page Parent menu page.
71
+ *
72
+ * @return void
73
+ */
74
+ private function add_settings_page( string $menu_page ) {
75
+ $page = add_submenu_page(
76
+ $menu_page,
77
+ 'WebP Converter for Media',
78
+ 'WebP Converter',
79
+ 'manage_options',
80
+ self::ADMIN_MENU_PAGE,
81
+ [ $this, 'load_settings_page' ]
82
+ );
83
+ add_action( 'load-' . $page, [ $this, 'load_scripts_for_page' ] );
84
+ }
85
+
86
+ /**
87
+ * Loads selected view on plugin settings page.
88
+ *
89
+ * @return void
90
+ * @internal
91
+ */
92
+ public function load_settings_page() {
93
+ $this->init_page_is_active( new DebugPage() );
94
+ $this->init_page_is_active( new SettingsPage() );
95
+ }
96
+
97
+ /**
98
+ * Initializes page loading if is active.
99
+ *
100
+ * @param PageInterface $page .
101
+ *
102
+ * @return void
103
+ */
104
+ private function init_page_is_active( PageInterface $page ) {
105
+ $page->set_plugin( $this->get_plugin() );
106
+ if ( $page->is_page_active() ) {
107
+ $page->show_page_view();
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Loads assets on plugin settings page.
113
+ *
114
+ * @return void
115
+ * @internal
116
+ */
117
+ public function load_scripts_for_page() {
118
+ WelcomeNotice::disable_notice();
119
+ ( new AdminAssets() )->init_hooks();
120
+ }
121
+ }
src/Settings/SettingsSave.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Settings;
4
+
5
+ use WebpConverter\PluginAccessAbstract;
6
+ use WebpConverter\PluginAccessInterface;
7
+ use WebpConverter\Conversion\Cron\Event;
8
+ use WebpConverter\Loader\LoaderAbstract;
9
+ use WebpConverter\Settings\Options;
10
+ use WebpConverter\Conversion\Directories;
11
+
12
+ /**
13
+ * Supports saving plugin settings on plugin settings page.
14
+ */
15
+ class SettingsSave extends PluginAccessAbstract implements PluginAccessInterface {
16
+
17
+ const SETTINGS_OPTION = 'webpc_settings';
18
+ const SUBMIT_VALUE = 'webpc_save';
19
+ const NONCE_PARAM_KEY = '_wpnonce';
20
+ const NONCE_PARAM_VALUE = 'webpc-save';
21
+
22
+ /**
23
+ * Saves plugin settings after submitting form on plugin settings page.
24
+ *
25
+ * @return void
26
+ */
27
+ public function save_settings() {
28
+ if ( ! isset( $_POST[ self::SUBMIT_VALUE ] )
29
+ || ! isset( $_REQUEST[ self::NONCE_PARAM_KEY ] )
30
+ || ! wp_verify_nonce( $_REQUEST[ self::NONCE_PARAM_KEY ], self::NONCE_PARAM_VALUE ) ) { // phpcs:ignore
31
+ return;
32
+ }
33
+
34
+ update_option( self::SETTINGS_OPTION, ( new Options() )->get_values( false, $_POST ) );
35
+ $settings = $this->get_plugin()->get_settings( true );
36
+ $this->get_plugin()->get_settings_debug( true );
37
+ $this->init_actions_after_save( $settings );
38
+ }
39
+
40
+ /**
41
+ * Runs actions needed after saving plugin settings.
42
+ *
43
+ * @param mixed[] $settings Plugin settings.
44
+ *
45
+ * @return void
46
+ */
47
+ private function init_actions_after_save( array $settings ) {
48
+ do_action( LoaderAbstract::ACTION_NAME, true );
49
+ wp_clear_scheduled_hook( Event::CRON_ACTION );
50
+ ( new Directories() )->remove_unused_output_directories( $settings['dirs'] );
51
+ }
52
+ }
src/WebpConverter.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter;
4
+
5
+ use WebpConverter\Action;
6
+ use WebpConverter\Conversion;
7
+ use WebpConverter\Conversion\Cron;
8
+ use WebpConverter\Error;
9
+ use WebpConverter\Conversion\Media;
10
+ use WebpConverter\Notice;
11
+ use WebpConverter\Plugin;
12
+ use WebpConverter\Settings;
13
+
14
+ /**
15
+ * Class initializes all plugin actions.
16
+ */
17
+ class WebpConverter {
18
+
19
+ /**
20
+ * Handler of class with plugin settings.
21
+ *
22
+ * @var Settings\Options
23
+ */
24
+ private $settings_object;
25
+
26
+ /**
27
+ * Cached settings of plugin.
28
+ *
29
+ * @var array[]
30
+ */
31
+ private $plugin_settings = null;
32
+
33
+ /**
34
+ * Cached settings of plugin for debugging.
35
+ *
36
+ * @var array[]
37
+ */
38
+ private $plugin_settings_debug = null;
39
+
40
+ /**
41
+ * WebpConverter constructor.
42
+ */
43
+ public function __construct() {
44
+ $this->settings_object = new Settings\Options();
45
+
46
+ ( new Action\ConvertAttachment() )->set_plugin_hookable( $this );
47
+ ( new Action\ConvertDir() )->init_hooks();
48
+ ( new Action\ConvertPaths() )->set_plugin_hookable( $this );
49
+ ( new Action\DeletePaths() )->init_hooks();
50
+ ( new Action\RegenerateAll() )->set_plugin_hookable( $this );
51
+ ( new Conversion\Directories() )->init_hooks();
52
+ ( new Conversion\DirectoryFiles() )->set_plugin_hookable( $this );
53
+ ( new Conversion\Endpoints() )->set_plugin_hookable( $this );
54
+ ( new Conversion\SkipExists() )->set_plugin_hookable( $this );
55
+ ( new Conversion\SkipLarger() )->set_plugin_hookable( $this );
56
+ ( new Cron\Event() )->set_plugin_hookable( $this );
57
+ ( new Cron\Schedules() )->init_hooks();
58
+ ( new Error\Errors() )->set_plugin_hookable( $this );
59
+ ( new Notice\Notices() )->init_hooks();
60
+ ( new Loader\Loaders() )->set_plugin_hookable( $this );
61
+ ( new Media\Delete() )->init_hooks();
62
+ ( new Media\Upload() )->set_plugin_hookable( $this );
63
+ ( new Plugin\Activation() )->init_hooks();
64
+ ( new Plugin\Deactivation() )->set_plugin_hookable( $this );
65
+ ( new Plugin\Links() )->init_hooks();
66
+ ( new Plugin\Uninstall() )->init_hooks();
67
+ ( new Plugin\Update() )->set_plugin_hookable( $this );
68
+ ( new Settings\Pages() )->set_plugin_hookable( $this );
69
+ }
70
+
71
+ /**
72
+ * Returns settings of plugin.
73
+ *
74
+ * @param bool $is_force_refresh Force refresh of current settings?
75
+ *
76
+ * @return mixed[] Settings of plugin.
77
+ */
78
+ public function get_settings( bool $is_force_refresh = false ): array {
79
+ if ( ( $this->plugin_settings === null ) || $is_force_refresh ) {
80
+ $this->plugin_settings = $this->settings_object->get_values();
81
+ }
82
+ return $this->plugin_settings;
83
+ }
84
+
85
+ /**
86
+ * Returns settings of plugin using for debugging.
87
+ *
88
+ * @param bool $is_force_refresh Force refresh of current settings?
89
+ *
90
+ * @return mixed[] Settings of plugin.
91
+ */
92
+ public function get_settings_debug( bool $is_force_refresh = false ): array {
93
+ if ( ( $this->plugin_settings_debug === null ) || $is_force_refresh ) {
94
+ $this->plugin_settings_debug = $this->settings_object->get_values( true );
95
+ }
96
+ return $this->plugin_settings_debug;
97
+ }
98
+ }
templates/components/errors/bypassing-apache.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag, %3$s: open anchor tag, %4$s: close anchor tag */
14
+ __( 'Requests to images are processed by your server bypassing Apache. When loading images, rules from the .htaccess file are not executed. Occasionally, this only applies to known file extensions: .jpg, .png, etc. and when e.g. .png2 extension is loaded, then the redirections from the .htaccess file work, because the server does not understand this format and does not treat it as image files. Check the redirects for %1$s.png file%2$s (for which the redirection does not work) and for %3$s.png2 file%4$s (for which the redirection works correctly). Change the server settings to stop ignoring the rules from the .htaccess file.', 'webp-converter-for-media' ),
15
+ '<a href="' . WEBPC_URL . 'assets/img/debug/icon-before.png" target="_blank">',
16
+ '</a>',
17
+ '<a href="' . WEBPC_URL . 'assets/img/debug/icon-before.png2" target="_blank">',
18
+ '</a>'
19
+ )
20
+ );
21
+ ?>
22
+ <br><br>
23
+ <?php
24
+ echo esc_html(
25
+ __( 'In this case, please contact your server administrator.', 'webp-converter-for-media' )
26
+ );
27
+ ?>
28
+ </p>
29
+ <?php require __DIR__ . '/passthru-info.php'; ?>
templates/components/errors/libs-not-installed.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
14
+ __( 'On your server is not installed GD or Imagick library. Please read %1$sthe plugin FAQ%2$s, specifically question about requirements of plugin. This issue is plugin-independent. Please contact your server administrator in this case.', 'webp-converter-for-media' ),
15
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
16
+ '</a>'
17
+ )
18
+ );
19
+ ?>
20
+ </p>
templates/components/errors/libs-without-avif-support.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ __( 'The selected option of "Conversion method" does not support AVIF format. This is a new format, so you will probably have to wait for its full support via PHP on your server. This issue is plugin-independent.', 'webp-converter-for-media' )
13
+ );
14
+ ?>
15
+ <br><br>
16
+ <?php
17
+ echo wp_kses_post(
18
+ __( 'Select a different method in the "Conversion method" option, if available. Or in the "List of supported output formats" option, select only the WebP format, because the selected conversion method does not yet allow converting to AVIF format.', 'webp-converter-for-media' )
19
+ );
20
+ ?>
21
+ </p>
templates/components/errors/libs-without-webp-support.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
14
+ __( 'The selected option of "Conversion method" does not support WebP format. Please read %1$sthe plugin FAQ%2$s, specifically question about requirements of plugin. GD or Imagick library is installed on your server, but it does not support the WebP format. This issue is plugin-independent.', 'webp-converter-for-media' ),
15
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
16
+ '</a>'
17
+ )
18
+ );
19
+ ?>
20
+ <br><br>
21
+ <?php
22
+ echo wp_kses_post(
23
+ __( 'Select a different method in the "Conversion method" option if available, or reconfigure the server so that the selected conversion method supports the WebP format. Please contact your server administrator in this case.', 'webp-converter-for-media' )
24
+ );
25
+ ?>
26
+ </p>
templates/components/errors/passthru-execution.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @var string $passthru_url URL of Pass Thru image loader.
6
+ * @package WebP Converter for Media
7
+ */
8
+
9
+ ?>
10
+ <p>
11
+ <?php
12
+ echo wp_kses_post(
13
+ sprintf(
14
+ /* translators: %s: anchor tag */
15
+ __( 'Execution of the PHP file from path "%s" is blocked on your server, or access to this file is blocked. Add an exception and enable this file to be executed via HTTP request. To do this, check the security plugin settings (if you are using) or the security settings of your server.', 'webp-converter-for-media' ),
16
+ '<a href="' . $passthru_url . '" target="_blank">' . $passthru_url . '</a>',
17
+ '<br><br>'
18
+ )
19
+ );
20
+ ?>
21
+ <br><br>
22
+ <?php
23
+ echo esc_html(
24
+ __( 'In this case, please contact your server administrator.', 'webp-converter-for-media' )
25
+ );
26
+ ?>
27
+ </p>
templates/components/errors/passthru-info.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: open strong tag, %2$s: close strong tag, %3$s: loader name */
14
+ __( '%1$sAlso try changing option "Image loading mode" to a different one.%2$s Issues about rewrites can often be resolved by setting this option to "%3$s". You can do this in plugin settings below. After changing settings, remember to flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media' ),
15
+ '<strong>',
16
+ '</strong>',
17
+ 'Pass Thru'
18
+ )
19
+ );
20
+ ?>
21
+ </p>
templates/components/errors/path-htaccess-not-writable.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: server path */
14
+ __( 'Unable to create or edit .htaccess file (function is_readable() or is_writable() returns false). Change directory permissions. The current using path of file is: %1$s. Please contact your server administrator.', 'webp-converter-for-media' ),
15
+ '<strong>' . apply_filters( 'webpc_dir_path', '', 'uploads' ) . '/.htaccess</strong>'
16
+ )
17
+ );
18
+ ?>
19
+ </p>
templates/components/errors/path-uploads-unavailable.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: filter name, %2$s: server path, %3$s: open anchor tag, %4$s: close anchor tag */
14
+ __( 'The path for /uploads files does not exist (function is_dir() returns false). Use filter %1$s to set the correct path. The current using path is: %2$s. Please read %3$sthe plugin FAQ%4$s to learn more.', 'webp-converter-for-media' ),
15
+ '<strong>webpc_dir_path</strong>',
16
+ '<strong>' . apply_filters( 'webpc_dir_path', '', 'uploads' ) . '</strong>',
17
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
18
+ '</a>'
19
+ )
20
+ );
21
+ ?>
22
+ </p>
templates/components/errors/path-webp-duplicated.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: filter name, %2$s: server path */
14
+ __( 'The paths for /uploads files and for saving converted WebP files are the same. Change them using filter %1$s. The current path for them is: %2$s.', 'webp-converter-for-media' ),
15
+ '<strong>webpc_dir_path</strong>',
16
+ '<strong>' . apply_filters( 'webpc_dir_path', '', 'uploads' ) . '</strong>'
17
+ )
18
+ );
19
+ ?>
20
+ </p>
templates/components/errors/path-webp-not-writable.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: filter name, %2$s: server path, %3$s: open anchor tag, %4$s: close anchor tag */
14
+ __( 'The path for saving converted WebP files does not exist and cannot be created (function is_writable() returns false). Use filter %1$s to set the correct path. The current using path is: %2$s. Please read %3$sthe plugin FAQ%4$s to learn more.', 'webp-converter-for-media' ),
15
+ '<strong>webpc_dir_path</strong>',
16
+ '<strong>' . apply_filters( 'webpc_dir_path', '', 'webp' ) . '</strong>',
17
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
18
+ '</a>'
19
+ )
20
+ );
21
+ ?>
22
+ </p>
templates/components/errors/rest-api-disabled.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: anchor tag, %2$s: anchor tag, %3$s: anchor tag */
14
+ __( 'The REST API on your website is not available. Please verify this and try again. Pay special attention to the filters: %1$s, %2$s and %3$s.', 'webp-converter-for-media' ),
15
+ '<a href="https://developer.wordpress.org/reference/hooks/rest_enabled/" target="_blank">rest_enabled</a>',
16
+ '<a href="https://developer.wordpress.org/reference/hooks/rest_jsonp_enabled/" target="_blank">rest_jsonp_enabled</a>',
17
+ '<a href="https://developer.wordpress.org/reference/hooks/rest_authentication_errors/" target="_blank">rest_authentication_errors</a>'
18
+ )
19
+ );
20
+ ?>
21
+ </p>
templates/components/errors/rewrites-cached.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: br tags, %2$s: open anchor tag, %3$s: close anchor tag */
14
+ __( 'Your server uses the cache for HTTP requests. The rules from .htaccess file or from Nginx configuration are not executed every time when the image is loaded, but the last redirect from cache is performed. With each request to image, your server should execute the rules from .htaccess file or from Nginx configuration. Now it only does this the first time and then uses cache. This means that if your server redirected image to WebP format the first time, it does so on every request. It should check the rules from .htaccess file or from Nginx configuration each time during request to image and redirect only when the conditions are met. %1$sIf you have enabled caching HTTP reverse proxy or another HTTP caching, you must disable it. Otherwise the plugin cannot work properly. Please read %2$sthe plugin FAQ%3$s to learn more (there you will find e.g. solution for Cloudflare servers).', 'webp-converter-for-media' ),
15
+ '<br><br>',
16
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
17
+ '</a>'
18
+ )
19
+ );
20
+ ?>
21
+ <br><br>
22
+ <?php
23
+ echo esc_html(
24
+ __( 'In this case, please contact your server administrator.', 'webp-converter-for-media' )
25
+ );
26
+ ?>
27
+ </p>
28
+ <?php require __DIR__ . '/passthru-info.php'; ?>
templates/components/errors/rewrites-not-working.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ sprintf(
13
+ /* translators: %1$s: open strong tag, %2$s: close strong tag */
14
+ __( 'Redirects on your server are not working. Check the correct configuration for you in %1$sthe plugin FAQ%2$s. If your configuration is correct, it means that your server does not support redirects from the .htaccess file or requests to images are processed by your server bypassing Apache.', 'webp-converter-for-media' ),
15
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
16
+ '</a>'
17
+ )
18
+ );
19
+ ?>
20
+ <br><br>
21
+ <?php
22
+ echo esc_html(
23
+ __( 'In this case, please contact your server administrator.', 'webp-converter-for-media' )
24
+ );
25
+ ?>
26
+ </p>
27
+ <?php require __DIR__ . '/passthru-info.php'; ?>
templates/components/errors/settings-incorrect.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Server configuration error displayed in errors section.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <p>
10
+ <?php
11
+ echo wp_kses_post(
12
+ __( 'The plugin settings are incorrect! Check them out and save them again. Please remember that you must have at least one option selected for each field.', 'webp-converter-for-media' )
13
+ );
14
+ ?>
15
+ </p>
templates/components/fields/checkbox.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Checkbox field displayed in plugin settings form.
4
+ *
5
+ * @var mixed[] $option Data of field.
6
+ * @var string $index Index of field.
7
+ * @package WebP Converter for Media
8
+ */
9
+
10
+ ?>
11
+ <?php if ( $option['info'] ) : ?>
12
+ <p><?php echo wp_kses_post( $option['info'] ); ?></p>
13
+ <?php endif; ?>
14
+ <table class="webpTable">
15
+ <?php foreach ( $option['values'] as $value => $label ) : ?>
16
+ <tr>
17
+ <td>
18
+ <input type="checkbox"
19
+ name="<?php echo esc_attr( $option['name'] ); ?>[]"
20
+ value="<?php echo esc_attr( $value ); ?>"
21
+ id="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
22
+ class="webpCheckbox__input"
23
+ <?php echo ( in_array( $value, $option['value'] ) ) ? 'checked' : ''; ?>
24
+ <?php echo ( in_array( $value, $option['disabled'] ) ) ? 'disabled' : ''; ?>>
25
+ <label for="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"></label>
26
+ </td>
27
+ <td>
28
+ <label for="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
29
+ class="webpCheckbox__label"
30
+ >
31
+ <?php echo wp_kses_post( $label ); ?>
32
+ </label>
33
+ </td>
34
+ </tr>
35
+ <?php endforeach; ?>
36
+ </table>
templates/components/fields/quality.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Quality steps field displayed in plugin settings form.
4
+ *
5
+ * @var mixed[] $option Data of field.
6
+ * @var string $index Index of field.
7
+ * @package WebP Converter for Media
8
+ */
9
+
10
+ ?>
11
+ <?php if ( $option['info'] ) : ?>
12
+ <p><?php echo wp_kses_post( $option['info'] ); ?></p>
13
+ <?php endif; ?>
14
+ <div class="webpPage__quality">
15
+ <?php foreach ( $option['values'] as $value => $label ) : ?>
16
+ <div class="webpPage__qualityItem">
17
+ <input type="radio"
18
+ name="<?php echo esc_attr( $option['name'] ); ?>"
19
+ value="<?php echo esc_attr( $value ); ?>"
20
+ id="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
21
+ class="webpPage__qualityItemInput"
22
+ <?php echo ( $value == $option['value'] ) ? 'checked' : ''; // phpcs:ignore ?>
23
+ <?php echo ( in_array( $value, $option['disabled'] ) ) ? 'disabled' : ''; ?>>
24
+ <label for="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
25
+ class="webpPage__qualityItemLabel"
26
+ >
27
+ <?php echo wp_kses_post( $label ); ?>
28
+ </label>
29
+ </div>
30
+ <?php endforeach; ?>
31
+ </div>
templates/components/fields/radio.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Radio field displayed in plugin settings form.
4
+ *
5
+ * @var mixed[] $option Data of field.
6
+ * @var string $index Index of field.
7
+ * @package WebP Converter for Media
8
+ */
9
+
10
+ ?>
11
+ <?php if ( $option['info'] ) : ?>
12
+ <p><?php echo wp_kses_post( $option['info'] ); ?></p>
13
+ <?php endif; ?>
14
+ <table class="webpTable">
15
+ <?php foreach ( $option['values'] as $value => $label ) : ?>
16
+ <tr>
17
+ <td>
18
+ <input type="radio"
19
+ name="<?php echo esc_attr( $option['name'] ); ?>"
20
+ value="<?php echo esc_attr( $value ); ?>"
21
+ id="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
22
+ class="webpCheckbox__input"
23
+ <?php echo ( $value == $option['value'] ) ? 'checked' : ''; // phpcs:ignore ?>
24
+ <?php echo ( in_array( $value, $option['disabled'] ) ) ? 'disabled' : ''; ?>>
25
+ <label for="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"></label>
26
+ </td>
27
+ <td>
28
+ <label for="webpc-<?php echo esc_attr( $index ); ?>-<?php echo esc_attr( $value ); ?>"
29
+ class="webpCheckbox__label"
30
+ >
31
+ <?php echo wp_kses_post( $label ); ?>
32
+ </label>
33
+ </td>
34
+ </tr>
35
+ <?php endforeach; ?>
36
+ </table>
templates/components/notices/thanks.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Notice displayed in admin panel.
4
+ *
5
+ * @var string $ajax_url URL of admin-ajax.
6
+ * @package WebP Converter for Media
7
+ */
8
+
9
+ ?>
10
+ <div class="notice notice-success is-dismissible" data-notice="webp-converter"
11
+ data-url="<?php echo esc_url( $ajax_url ); ?>"
12
+ >
13
+ <div class="webpContent webpContent--notice">
14
+ <h4>
15
+ <?php echo esc_html( __( 'Thank you for using our plugin WebP Converter for Media!', 'webp-converter-for-media' ) ); ?>
16
+ </h4>
17
+ <p>
18
+ <?php
19
+ echo wp_kses_post(
20
+ sprintf(
21
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
22
+ __( 'Please let us know what you think about our plugin. It is important that we can develop this tool. Thank you for all the ratings, reviews and donates. If you have a technical problem, please before you add a review %1$scheck our FAQ%2$s or contact us if you did not find help there. We will try to help you!', 'webp-converter-for-media' ),
23
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
24
+ '</a>'
25
+ )
26
+ );
27
+ ?>
28
+ </p>
29
+ <div class="webpContent__buttons">
30
+ <a href="https://wordpress.org/support/plugin/webp-converter-for-media/#new-post" target="_blank"
31
+ class="webpContent__button webpButton webpButton--green"
32
+ >
33
+ <?php echo esc_html( __( 'Get help', 'webp-converter-for-media' ) ); ?>
34
+ </a>
35
+ <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/?rate=5#new-post"
36
+ target="_blank"
37
+ class="webpContent__button webpButton webpButton--green"
38
+ >
39
+ <?php echo esc_html( __( 'Add review', 'webp-converter-for-media' ) ); ?>
40
+ </a>
41
+ <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=notice-thanks"
42
+ target="_blank"
43
+ class="webpContent__button webpButton webpButton--green dashicons-heart"
44
+ >
45
+ <?php echo esc_html( __( 'Provide us a coffee', 'webp-converter-for-media' ) ); ?>
46
+ </a>
47
+ <a href="#" target="_blank" data-permanently
48
+ class="webpContent__button webpButton webpButton--blue"
49
+ >
50
+ <?php echo esc_html( __( 'I added review, do not show again', 'webp-converter-for-media' ) ); ?>
51
+ </a>
52
+ </div>
53
+ </div>
54
+ </div>
templates/components/notices/welcome.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Notice displayed in admin panel.
4
+ *
5
+ * @var string $settings_url URL of plugin settings page (default view).
6
+ * @package WebP Converter for Media
7
+ */
8
+
9
+ ?>
10
+ <div class="notice notice-success">
11
+ <div class="webpContent webpContent--notice">
12
+ <h4>
13
+ <?php echo esc_html( __( 'Thank you for installing our plugin WebP Converter for Media!', 'webp-converter-for-media' ) ); ?>
14
+ </h4>
15
+ <p>
16
+ <?php
17
+ echo wp_kses_post(
18
+ sprintf(
19
+ /* translators: %1$s: br tag, %2$s: icon heart */
20
+ __( 'Would you like to speed up your website using our plugin? %1$sGo to plugin settings and convert all your images to WebP with one click! Thank you for being with us! %2$s', 'webp-converter-for-media' ),
21
+ '<br>',
22
+ '<span class="dashicons dashicons-heart"></span>'
23
+ )
24
+ );
25
+ ?>
26
+ </p>
27
+ <div class="webpContent__buttons">
28
+ <a href="<?php echo esc_url( $settings_url ); ?>"
29
+ class="webpContent__button webpButton webpButton--green"
30
+ >
31
+ <?php echo esc_html( __( 'Speed up my website', 'webp-converter-for-media' ) ); ?>
32
+ </a>
33
+ </div>
34
+ </div>
35
+ </div>
templates/components/server/debug.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Information about debugging displayed in server configuration widget.
4
+ *
5
+ * @var string $size_png_path Size of file.
6
+ * @var string $size_png2_path Size of file.
7
+ * @var string $size_png_url Size of file.
8
+ * @var string $size_png2_url Size of file.
9
+ * @var string $size_png_as_webp_url Size of file.
10
+ * @var string $size_png2_as_webp_url Size of file.
11
+ * @package WebP Converter for Media
12
+ */
13
+
14
+ ?>
15
+ <h4>Errors debug</h4>
16
+ <table>
17
+ <tbody>
18
+ <tr>
19
+ <td class="e">Size of PNG <em>(by server path )</em></td>
20
+ <td class="v">
21
+ <?php echo esc_html( $size_png_path ); ?>
22
+ </td>
23
+ </tr>
24
+ <tr>
25
+ <td class="e">Size of PNG2 <em>(by server path )</em></td>
26
+ <td class="v">
27
+ <?php echo esc_html( $size_png2_path ); ?>
28
+ </td>
29
+ </tr>
30
+ <tr>
31
+ <td class="e">Size of PNG as WEBP <em>(by URL)</em></td>
32
+ <td class="v">
33
+ <?php echo esc_html( $size_png_as_webp_url ); ?>
34
+ </td>
35
+ </tr>
36
+ <tr>
37
+ <td class="e">Size of PNG as PNG <em>(by URL)</em></td>
38
+ <td class="v">
39
+ <?php echo esc_html( $size_png_url ); ?>
40
+ </td>
41
+ </tr>
42
+ <tr>
43
+ <td class="e">Size of PNG2 as WEBP <em>(by URL)</em></td>
44
+ <td class="v">
45
+ <?php echo esc_html( $size_png2_as_webp_url ); ?>
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td class="e">Size of PNG2 as PNG2 <em>(by URL)</em></td>
50
+ <td class="v">
51
+ <?php echo esc_html( $size_png2_url ); ?>
52
+ </td>
53
+ </tr>
54
+ </tbody>
55
+ </table>
templates/components/server/filters.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Information about using filters displayed in server configuration widget.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <h4>Filters</h4>
10
+ <table>
11
+ <tbody>
12
+ <tr>
13
+ <td class="e">webpc_site_root</td>
14
+ <td class="v">
15
+ <?php echo esc_html( apply_filters( 'webpc_site_root', ABSPATH ) ); ?>
16
+ </td>
17
+ </tr>
18
+ <tr>
19
+ <td class="e">webpc_site_url</td>
20
+ <td class="v">
21
+ <?php echo esc_html( apply_filters( 'webpc_site_url', get_site_url() ) ); ?>
22
+ </td>
23
+ </tr>
24
+ <tr>
25
+ <td class="e">webpc_dir_path <em>(plugins )</em></td>
26
+ <td class="v">
27
+ <?php echo esc_html( apply_filters( 'webpc_dir_path', '', 'plugins' ) ); ?>
28
+ </td>
29
+ </tr>
30
+ <tr>
31
+ <td class="e">webpc_dir_path <em>(themes )</em></td>
32
+ <td class="v">
33
+ <?php echo esc_html( apply_filters( 'webpc_dir_path', '', 'themes' ) ); ?>
34
+ </td>
35
+ </tr>
36
+ <tr>
37
+ <td class="e">webpc_dir_path <em>(uploads )</em></td>
38
+ <td class="v">
39
+ <?php echo esc_html( apply_filters( 'webpc_dir_path', '', 'uploads' ) ); ?>
40
+ </td>
41
+ </tr>
42
+ <tr>
43
+ <td class="e">webpc_dir_path <em>(webp)</em></td>
44
+ <td class="v">
45
+ <?php echo esc_html( apply_filters( 'webpc_dir_path', '', 'webp' ) ); ?>
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td class="e">webpc_uploads_prefix</td>
50
+ <td class="v">
51
+ <?php echo esc_html( apply_filters( 'webpc_uploads_prefix', '/' ) ); ?>
52
+ </td>
53
+ </tr>
54
+ <tr>
55
+ <tr>
56
+ <td class="e">webpc_dir_excluded</td>
57
+ <td class="v">
58
+ <?php echo esc_html( implode( ' | ', apply_filters( 'webpc_dir_excluded', [] ) ) ); ?>
59
+ </td>
60
+ </tr>
61
+ </tbody>
62
+ </table>
templates/components/server/gd.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Information about GD library displayed in server configuration widget.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <h4>gd</h4>
10
+ <?php if ( ! extension_loaded( 'gd' ) ) : ?>
11
+ <p>-</p>
12
+ <?php else : ?>
13
+ <?php ( new \ReflectionExtension( 'gd' ) )->info(); ?>
14
+ <?php endif; ?>
templates/components/server/imagick.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Information about Imagick library displayed in server configuration widget.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <h4>imagick</h4>
10
+ <?php if ( ! extension_loaded( 'imagick' ) ) : ?>
11
+ <p>-</p>
12
+ <?php else : ?>
13
+ <?php ( new \ReflectionExtension( 'imagick' ) )->info(); ?>
14
+ <?php endif; ?>
templates/components/server/wordpress.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Information about WordPress config displayed in server configuration widget.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <h4>WordPress</h4>
10
+ <table>
11
+ <tbody>
12
+ <tr>
13
+ <td class="e">ABSPATH</td>
14
+ <td class="v">
15
+ <?php echo esc_html( ABSPATH ); ?>
16
+ </td>
17
+ </tr>
18
+ </tbody>
19
+ </table>
templates/components/widgets/about.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed information about plugin operation on plugin settings page.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <div class="webpPage__widget">
10
+ <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
11
+ <?php echo esc_html( __( 'How does this work?', 'webp-converter-for-media' ) ); ?>
12
+ </h3>
13
+ <div class="webpContent">
14
+ <p>
15
+ <?php
16
+ echo wp_kses_post(
17
+ __( 'By adding images to your media library, they are automatically converted and saved in a separate directory. Images are converted using GD or Imagick native extension for PHP.', 'webp-converter-for-media' )
18
+ );
19
+ ?>
20
+ </p>
21
+ <p>
22
+ <?php
23
+ echo wp_kses_post(
24
+ __( 'When the browser tries to download an image file, the server verifies if it supports image/webp files and if the file exists. If everything is OK, instead of the original image, the browser will receive its equivalent in WebP format.', 'webp-converter-for-media' )
25
+ );
26
+ ?>
27
+ </p>
28
+ <p>
29
+ <?php
30
+ echo wp_kses_post(
31
+ __( 'The plugin in default loading mode (via .htaccess) does not change file URLs, so there are no problems with saving the page to the cache and the page generation time does not increase.', 'webp-converter-for-media' )
32
+ );
33
+ ?>
34
+ </p>
35
+ <p>
36
+ <?php
37
+ echo wp_kses_post(
38
+ __( 'Image URLs are modified using the module mod_rewrite on the server, i.e. the same, thanks to which we can use friendly links in WordPress. Additionally, the MIME type of the sent file is modified to image/webp.', 'webp-converter-for-media' )
39
+ );
40
+ ?>
41
+ </p>
42
+ </div>
43
+ </div>
templates/components/widgets/donate.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed information about about donation on plugin settings page.
4
+ *
5
+ * @package WebP Converter for Media
6
+ */
7
+
8
+ ?>
9
+ <div class="webpPage__widget">
10
+ <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
11
+ <?php echo esc_html( __( 'I love what I do!', 'webp-converter-for-media' ) ); ?>
12
+ </h3>
13
+ <div class="webpContent">
14
+ <p>
15
+ <?php
16
+ echo wp_kses_post(
17
+ __( 'However, working on plugins and technical support requires many hours of work. If you want to appreciate it, you can provide me a coffee.', 'webp-converter-for-media' )
18
+ );
19
+ ?>
20
+ </p>
21
+ <p>
22
+ <?php
23
+ echo wp_kses_post(
24
+ __( 'If every plugin user did it, I could devote myself fully to working on this plugin. Thanks everyone!', 'webp-converter-for-media' )
25
+ );
26
+ ?>
27
+ </p>
28
+ <p class="center">
29
+ <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=widget-donate"
30
+ target="_blank"
31
+ class="webpButton webpButton--blue dashicons-heart"
32
+ >
33
+ <?php echo esc_html( __( 'Provide me a coffee', 'webp-converter-for-media' ) ); ?>
34
+ </a>
35
+ </p>
36
+ </div>
37
+ </div>
templates/components/widgets/errors.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed errors on plugin settings page.
4
+ *
5
+ * @var string[] $errors List of errors detected by plugin.
6
+ * @package WebP Converter for Media
7
+ */
8
+
9
+ ?>
10
+ <?php if ( $errors ) : ?>
11
+ <div class="webpPage__widget">
12
+ <h3 class="webpPage__widgetTitle webpPage__widgetTitle--error">
13
+ <?php echo esc_html( __( 'Server configuration error', 'webp-converter-for-media' ) ); ?>
14
+ </h3>
15
+ <div class="webpContent webpContent--wide">
16
+ <?php echo wp_kses_post( implode( '<p>---</p>', $errors ) ); ?>
17
+ <p>---</p>
18
+ <p>
19
+ <?php
20
+ echo wp_kses_post(
21
+ sprintf(
22
+ /* translators: %1$s: open strong tag, %2$s: close strong tag, %3$s: errors codes */
23
+ __( '%1$sError codes:%2$s %3$s', 'webp-converter-for-media' ),
24
+ '<strong>',
25
+ '</strong>',
26
+ implode( ', ', array_keys( $errors ) )
27
+ )
28
+ );
29
+ ?>
30
+ </p>
31
+ </div>
32
+ </div>
33
+ <?php endif; ?>
templates/components/widgets/options.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed settings form on plugin settings page.
4
+ *
5
+ * @var mixed[] $options Options of plugin settings.
6
+ * @var string $submit_value Value of submit button.
7
+ * @var string $settings_debug_url URL of plugin settings page (debug view).
8
+ * @package WebP Converter for Media
9
+ */
10
+
11
+ ?>
12
+ <div class="webpPage__widget">
13
+ <h3 class="webpPage__widgetTitle">
14
+ <?php echo esc_html( __( 'Settings', 'webp-converter-for-media' ) ); ?>
15
+ </h3>
16
+ <div class="webpContent">
17
+ <?php foreach ( $options as $index => $option ) : ?>
18
+ <div class="webpPage__widgetRow">
19
+ <h4><?php echo esc_html( $option['label'] ); ?></h4>
20
+ <?php include dirname( __DIR__ ) . '/fields/' . $option['type'] . '.php'; ?>
21
+ </div>
22
+ <?php endforeach; ?>
23
+ <div class="webpPage__widgetRow">
24
+ <button type="submit" name="<?php echo esc_attr( $submit_value ); ?>"
25
+ class="webpButton webpButton--green"
26
+ >
27
+ <?php echo esc_html( __( 'Save Changes', 'webp-converter-for-media' ) ); ?>
28
+ </button>
29
+ </div>
30
+ <div class="webpPage__widgetRow">
31
+ <p>
32
+ <?php
33
+ echo wp_kses_post(
34
+ sprintf(
35
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag, %3$s: open anchor tag, %4$s: close anchor tag, %5$s: open anchor tag, %6$s: close anchor tag */
36
+ __( 'If you have a problem %1$scheck our FAQ%2$s first. If you did not find help there, please %3$scheck support forum%2$s for any similar problem or contact us. Before you contact us, %5$scheck the configuration%6$s of your server.', 'webp-converter-for-media' ),
37
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
38
+ '</a>',
39
+ '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
40
+ '</a>',
41
+ '<a href="' . $settings_debug_url . '">',
42
+ '</a>'
43
+ )
44
+ );
45
+ ?>
46
+ </p>
47
+ </div>
48
+ </div>
49
+ </div>
templates/components/widgets/regenerate.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget allows regeneration images on plugin settings page.
4
+ *
5
+ * @var string $api_paths_url URL of REST API endpoint.
6
+ * @var string $api_regenerate_url URL of REST API endpoint.
7
+ * @package WebP Converter for Media
8
+ */
9
+
10
+ /* translators: %s error message */
11
+ $error_message = __( 'An unknown error occurred while converting the images: %s', 'webp-converter-for-media' );
12
+
13
+ ?>
14
+ <div class="webpPage__widget">
15
+ <h3 class="webpPage__widgetTitle">
16
+ <?php echo esc_html( __( 'Regenerate images', 'webp-converter-for-media' ) ); ?>
17
+ </h3>
18
+ <div class="webpLoader webpContent"
19
+ data-api-paths="<?php echo esc_url( $api_paths_url ); ?>"
20
+ data-api-regenerate="<?php echo esc_url( $api_regenerate_url ); ?>"
21
+ data-api-error-message="<?php echo esc_attr( $error_message ); ?>"
22
+ >
23
+ <div class="webpPage__widgetRow">
24
+ <p>
25
+ <?php echo wp_kses_post( __( 'Convert all existing images with just one click! This tool uses the WordPress REST API by downloading addresses of all images and converting all files gradually. This is a process that may take a few or more than ten minutes depending on the number of files. During this process, please do not close your browser window.', 'webp-converter-for-media' ) ); ?>
26
+ </p>
27
+ <p>
28
+ <?php echo wp_kses_post( __( 'This operation should be performed only once after installing the plugin. New images from the Media Library will be converted automatically. For other images, e.g. from the /themes or /uploads directory that are not from the Media Library, you must start manual conversion after adding new images.', 'webp-converter-for-media' ) ); ?>
29
+ </p>
30
+ <div class="webpLoader__status" hidden>
31
+ <div class="webpLoader__bar">
32
+ <div class="webpLoader__barProgress" data-percent="0">
33
+ <div class="webpLoader__barCount"></div>
34
+ </div>
35
+ <div class="webpLoader__size">
36
+ <?php
37
+ echo sprintf(
38
+ /* translators: %s progress value */
39
+ wp_kses_post( __( 'Saving the weight of your images: %s', 'webp-converter-for-media' ) ),
40
+ '<span class="webpLoader__sizeProgress">0 kB</span>'
41
+ );
42
+ ?>
43
+ </div>
44
+ </div>
45
+ <div class="webpLoader__success" hidden>
46
+ <div class="webpLoader__successContent">
47
+ <?php echo wp_kses_post( __( 'The process was completed successfully. Your images have been converted!', 'webp-converter-for-media' ) ); ?>
48
+ <?php echo wp_kses_post( __( 'Please flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media' ) ); ?>
49
+ <br>
50
+ <?php
51
+ echo wp_kses_post(
52
+ sprintf(
53
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
54
+ __( 'Do you want to know how a plugin works and how to check if it is working properly? Read our %1$splugin FAQ%2$s.', 'webp-converter-for-media' ),
55
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
56
+ '</a>'
57
+ )
58
+ );
59
+ ?>
60
+ </div>
61
+ </div>
62
+ <div class="webpLoader__popup webpPopup" hidden>
63
+ <div class="webpPopup__inner">
64
+ <div class="webpPopup__image"></div>
65
+ <div class="webpPopup__content">
66
+ <p>
67
+ <?php
68
+ echo wp_kses_post(
69
+ sprintf(
70
+ /* translators: %s break line tag */
71
+ __( 'Hello, my name is Mateusz! %sI am glad you managed to reduce the weight of your website. If you would like to support me in developing this plugin, I will be very grateful to you! If every plugin user did it, I could devote myself fully to working on this plugin.', 'webp-converter-for-media' ),
72
+ '<br>'
73
+ )
74
+ );
75
+ ?>
76
+ </p>
77
+ <p>
78
+ <a href="https://ko-fi.com/gbiorczyk/?utm_source=webp-converter-for-media&utm_medium=notice-regenerate"
79
+ target="_blank"
80
+ class="webpButton webpButton--blue dashicons-coffee"
81
+ >
82
+ <?php echo wp_kses_post( __( 'Provide me a coffee', 'webp-converter-for-media' ) ); ?>
83
+ </a>
84
+ </p>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ <div class="webpLoader__errors" hidden>
89
+ <div class="webpLoader__errorsTitle">
90
+ <?php echo esc_html( __( 'Additional informations about process:', 'webp-converter-for-media' ) ); ?>
91
+ </div>
92
+ <div class="webpLoader__errorsContent">
93
+ <div class="webpLoader__errorsContentList"></div>
94
+ <div class="webpLoader__errorsContentMessage" hidden>
95
+ <?php echo wp_kses_post( __( 'An error occurred while connecting to REST API. Please try again.', 'webp-converter-for-media' ) ); ?>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ <div class="webpPage__widgetRow">
102
+ <table class="webpTable">
103
+ <tr>
104
+ <td>
105
+ <input type="checkbox" name="regenerate_force" value="1"
106
+ id="webpc-regenerate-force" class="webpCheckbox__input"
107
+ >
108
+ <label for="webpc-regenerate-force"></label>
109
+ </td>
110
+ <td>
111
+ <label for="webpc-regenerate-force" class="webpCheckbox__label">
112
+ <?php echo esc_html( __( 'Force convert all images again', 'webp-converter-for-media' ) ); ?>
113
+ </label>
114
+ </td>
115
+ </tr>
116
+ </table>
117
+ <button type="button"
118
+ class="webpLoader__button webpButton webpButton--green"
119
+ <?php echo ( apply_filters( 'webpc_server_errors', [], true ) ) ? 'disabled' : ''; ?>>
120
+ <?php echo esc_html( __( 'Regenerate All', 'webp-converter-for-media' ) ); ?>
121
+ </button>
122
+ </div>
123
+ </div>
124
+ </div>
templates/components/widgets/server.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed server configuration on plugin settings page.
4
+ *
5
+ * @var string $settings_url URL of plugin settings page.
6
+ * @var string $size_png_path Size of file.
7
+ * @var string $size_png2_path Size of file.
8
+ * @var string $size_png_url Size of file.
9
+ * @var string $size_png2_url Size of file.
10
+ * @var string $size_png_as_webp_url Size of file.
11
+ * @var string $size_png2_as_webp_url Size of file.
12
+ * @package WebP Converter for Media
13
+ */
14
+
15
+ ?>
16
+ <div class="webpPage__widget">
17
+ <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
18
+ <?php echo esc_html( __( 'Your server configuration', 'webp-converter-for-media' ) ); ?>
19
+ </h3>
20
+ <div class="webpContent">
21
+ <div class="webpPage__widgetRow">
22
+ <p>
23
+ <?php
24
+ echo wp_kses_post(
25
+ sprintf(
26
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag */
27
+ __( 'Please compare your configuration with the configuration that is given in the technical requirements in %1$sthe plugin FAQ%2$s. If your server does not meet the technical requirements, please contact your server Administrator.', 'webp-converter-for-media' ),
28
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
29
+ '</a>'
30
+ )
31
+ );
32
+ ?>
33
+ </p>
34
+ <a href="<?php echo esc_url( $settings_url ); ?>"
35
+ class="webpLoader__button webpButton webpButton--blue"
36
+ >
37
+ <?php echo esc_html( __( 'Back to settings', 'webp-converter-for-media' ) ); ?>
38
+ </a>
39
+ </div>
40
+ <div class="webpPage__widgetRow">
41
+ <div class="webpServerInfo">
42
+ <?php
43
+ require_once dirname( __DIR__ ) . '/server/filters.php';
44
+ require_once dirname( __DIR__ ) . '/server/wordpress.php';
45
+ require_once dirname( __DIR__ ) . '/server/debug.php';
46
+ require_once dirname( __DIR__ ) . '/server/gd.php';
47
+ require_once dirname( __DIR__ ) . '/server/imagick.php';
48
+ ?>
49
+ </div>
50
+ </div>
51
+ <div class="webpPage__widgetRow">
52
+ <a href="<?php echo esc_url( $settings_url ); ?>"
53
+ class="webpLoader__button webpButton webpButton--blue"
54
+ >
55
+ <?php echo esc_html( __( 'Back to settings', 'webp-converter-for-media' ) ); ?>
56
+ </a>
57
+ </div>
58
+ </div>
59
+ </div>
templates/components/widgets/support.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget displayed information about support forum on plugin settings page.
4
+ *
5
+ * @var string $settings_debug_url URL of plugin settings page (debug view).
6
+ * @package WebP Converter for Media
7
+ */
8
+
9
+ ?>
10
+ <div class="webpPage__widget">
11
+ <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
12
+ <?php echo esc_html( __( 'We are waiting for your message', 'webp-converter-for-media' ) ); ?>
13
+ </h3>
14
+ <div class="webpContent">
15
+ <p>
16
+ <?php
17
+ echo wp_kses_post(
18
+ __( 'Do you have a technical problem? Please contact us. We will be happy to help you. Or maybe you have an idea for a new feature? Please let us know about it by filling the support form. We will try to add it!', 'webp-converter-for-media' )
19
+ );
20
+ ?>
21
+ </p>
22
+ <p>
23
+ <?php
24
+ echo wp_kses_post(
25
+ sprintf(
26
+ /* translators: %1$s: open anchor tag, %2$s: close anchor tag, %3$s: open anchor tag, %4$s: close anchor tag */
27
+ __( 'Please %1$scheck our FAQ%2$s before adding a thread with technical problem. If you do not find help there, %3$scheck support forum%4$s for similar problems. Before you contact us check the configuration of your server and attach it in your message, e.g. as a screenshot.', 'webp-converter-for-media' ),
28
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
29
+ '</a>',
30
+ '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
31
+ '</a>'
32
+ )
33
+ );
34
+ ?>
35
+ </p>
36
+ <p class="center">
37
+ <a href="<?php echo esc_url( $settings_debug_url ); ?>"
38
+ class="webpButton webpButton--blue dashicons-admin-tools"
39
+ >
40
+ <?php echo esc_html( __( 'Server configuration', 'webp-converter-for-media' ) ); ?>
41
+ </a>
42
+ <br>
43
+ <a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank"
44
+ class="webpButton webpButton--blue"
45
+ >
46
+ <?php echo esc_html( __( 'Get help', 'webp-converter-for-media' ) ); ?>
47
+ </a>
48
+ </p>
49
+ <p>
50
+ <?php
51
+ echo wp_kses_post(
52
+ __( 'Do you like our plugin? Could you rate him? Please let us know what you think about our plugin. It is important that we can develop this tool. Thank you for all the ratings, reviews and donates.', 'webp-converter-for-media' )
53
+ );
54
+ ?>
55
+ </p>
56
+ <p class="center">
57
+ <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/?rate=5#new-post"
58
+ target="_blank" class="webpButton webpButton--blue"
59
+ >
60
+ <?php echo esc_html( __( 'Add review', 'webp-converter-for-media' ) ); ?>
61
+ </a>
62
+ </p>
63
+ </div>
64
+ </div>
templates/views/deactivation-modal.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Modal with poll displayed in list of plugins.
4
+ *
5
+ * @var string[] $errors List of errors detected by plugin.
6
+ * @var mixed[] $reasons Reasons for plugin deactivation.
7
+ * @var mixed[] $settings Plugin settings.
8
+ * @var string $api_url URL of API for feedback request.
9
+ * @package WebP Converter for Media
10
+ */
11
+
12
+ ?>
13
+ <div class="webpModal" hidden>
14
+ <div class="webpModal__outer">
15
+ <form action="<?php echo esc_url( $api_url ); ?>" method="POST" class="webpModal__form">
16
+ <h2 class="webpModal__headline">
17
+ <?php echo esc_html( __( 'We are sorry that you are leaving our plugin WebP Converter for Media', 'webp-converter-for-media' ) ); ?>
18
+ </h2>
19
+ <div class="webpModal__desc">
20
+ <?php echo esc_html( __( 'Can you please take a moment to tell us why you are deactivating this plugin (your answer is completely anonymous)?', 'webp-converter-for-media' ) ); ?>
21
+ </div>
22
+ <table class="webpModal__table webpTable">
23
+ <?php foreach ( $reasons as $index => $reason ) : ?>
24
+ <tr>
25
+ <td>
26
+ <input type="radio" name="webpc_reason" value="<?php echo esc_attr( $reason['key'] ); ?>"
27
+ id="webpc-option-<?php echo esc_attr( $index ); ?>" class="webpCheckbox__input"
28
+ data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>"
29
+ >
30
+ <label for="webpc-option-<?php echo esc_attr( $index ); ?>"></label>
31
+ </td>
32
+ <td>
33
+ <label for="webpc-option-<?php echo esc_attr( $index ); ?>"
34
+ class="webpCheckbox__label"
35
+ ><?php echo esc_html( $reason['label'] ); ?></label>
36
+ </td>
37
+ </tr>
38
+ <?php endforeach; ?>
39
+ </table>
40
+ <textarea class="webpModal__textarea" name="webpc_comment" rows="2"></textarea>
41
+ <ul class="webpModal__buttons">
42
+ <li class="webpModal__button">
43
+ <button type="submit" class="webpModal__buttonInner webpButton webpButton--green">
44
+ <?php echo esc_html( __( 'Submit and Deactivate', 'webp-converter-for-media' ) ); ?>
45
+ </button>
46
+ </li>
47
+ <li class="webpModal__button">
48
+ <button type="button" class="webpModal__buttonInner webpButton webpButton--blue">
49
+ <?php echo esc_html( __( 'Skip and Deactivate', 'webp-converter-for-media' ) ); ?>
50
+ </button>
51
+ </li>
52
+ </ul>
53
+ <input type="hidden" name="webpc_error_codes"
54
+ value="<?php echo esc_attr( implode( ',', $errors ) ); ?>"
55
+ >
56
+ <input type="hidden" name="webpc_plugin_settings"
57
+ value='<?php echo json_encode( $settings ); ?>'
58
+ >
59
+ <input type="hidden" name="webpc_plugin_version"
60
+ value="<?php echo esc_attr( WEBPC_VERSION ); ?>"
61
+ >
62
+ </form>
63
+ </div>
64
+ </div>
templates/views/settings-debug.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Debug tab of plugin settings page.
4
+ *
5
+ * @var string $settings_url URL of plugin settings page (default view).
6
+ * @var string $size_png_path Size of file.
7
+ * @var string $size_png2_path Size of file.
8
+ * @var string $size_png_url Size of file.
9
+ * @var string $size_png2_url Size of file.
10
+ * @var string $size_png_as_webp_url Size of file.
11
+ * @var string $size_png2_as_webp_url Size of file.
12
+ * @package WebP Converter for Media
13
+ */
14
+
15
+ ?>
16
+ <div class="wrap">
17
+ <hr class="wp-header-end">
18
+ <div class="webpPage">
19
+ <h1 class="webpPage__headline"><?php echo esc_html( __( 'WebP Converter for Media', 'webp-converter-for-media' ) ); ?></h1>
20
+ <div class="webpPage__inner">
21
+ <ul class="webpPage__columns">
22
+ <li class="webpPage__column webpPage__column--large">
23
+ <?php
24
+ require_once dirname( __DIR__ ) . '/components/widgets/server.php';
25
+ ?>
26
+ </li>
27
+ <li class="webpPage__column webpPage__column--small">
28
+ <?php
29
+ require_once dirname( __DIR__ ) . '/components/widgets/about.php';
30
+ require_once dirname( __DIR__ ) . '/components/widgets/support.php';
31
+ require_once dirname( __DIR__ ) . '/components/widgets/donate.php';
32
+ ?>
33
+ </li>
34
+ </ul>
35
+ </div>
36
+ </div>
37
+ </div>
templates/views/settings.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Main tab of plugin settings page.
4
+ *
5
+ * @var string[] $errors List of errors detected by plugin.
6
+ * @var mixed[] $options Options of plugin settings.
7
+ * @var string $submit_value Value of submit button.
8
+ * @var string $settings_url URL of plugin settings page (default view).
9
+ * @var string $settings_debug_url URL of plugin settings page (debug view).
10
+ * @var string $api_paths_url URL of REST API endpoint.
11
+ * @var string $api_regenerate_url URL of REST API endpoint.
12
+ * @package WebP Converter for Media
13
+ */
14
+
15
+ ?>
16
+ <div class="wrap">
17
+ <hr class="wp-header-end">
18
+ <form method="post" action="<?php echo esc_url( $settings_url ); ?>" class="webpPage">
19
+ <h1 class="webpPage__headline"><?php echo esc_html( __( 'WebP Converter for Media', 'webp-converter-for-media' ) ); ?></h1>
20
+ <div class="webpPage__inner">
21
+ <ul class="webpPage__columns">
22
+ <li class="webpPage__column webpPage__column--large">
23
+ <?php if ( isset( $_POST[ $submit_value ] ) ) : // phpcs:ignore ?>
24
+ <div class="webpPage__alert">
25
+ <?php echo esc_html( __( 'Changes were successfully saved!', 'webp-converter-for-media' ) ); ?>
26
+ <?php echo esc_html( __( 'Please flush cache if you use caching plugin or caching via hosting.', 'webp-converter-for-media' ) ); ?>
27
+ </div>
28
+ <?php endif; ?>
29
+ <?php
30
+ require_once dirname( __DIR__ ) . '/components/widgets/errors.php';
31
+ require_once dirname( __DIR__ ) . '/components/widgets/options.php';
32
+ require_once dirname( __DIR__ ) . '/components/widgets/regenerate.php';
33
+ ?>
34
+ </li>
35
+ <li class="webpPage__column webpPage__column--small">
36
+ <?php
37
+ require_once dirname( __DIR__ ) . '/components/widgets/about.php';
38
+ require_once dirname( __DIR__ ) . '/components/widgets/support.php';
39
+ require_once dirname( __DIR__ ) . '/components/widgets/donate.php';
40
+ ?>
41
+ </li>
42
+ </ul>
43
+ </div>
44
+ </form>
45
+ </div>
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitbf2d1e8ab3a1950ed7aef886b373c248::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit9b97786baa18a2131b86fc40df508740::getLoader();
vendor/composer/autoload_psr4.php CHANGED
@@ -6,5 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
- 'WebpConverter\\' => array($baseDir . '/app'),
10
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'WebpConverter\\' => array($baseDir . '/src'),
10
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitbf2d1e8ab3a1950ed7aef886b373c248
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInitbf2d1e8ab3a1950ed7aef886b373c248
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInitbf2d1e8ab3a1950ed7aef886b373c248', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
- spl_autoload_unregister(array('ComposerAutoloaderInitbf2d1e8ab3a1950ed7aef886b373c248', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
- call_user_func(\Composer\Autoload\ComposerStaticInitbf2d1e8ab3a1950ed7aef886b373c248::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit9b97786baa18a2131b86fc40df508740
6
  {
7
  private static $loader;
8
 
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInit9b97786baa18a2131b86fc40df508740', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit9b97786baa18a2131b86fc40df508740', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit9b97786baa18a2131b86fc40df508740::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitbf2d1e8ab3a1950ed7aef886b373c248
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
@@ -16,15 +16,15 @@ class ComposerStaticInitbf2d1e8ab3a1950ed7aef886b373c248
16
  public static $prefixDirsPsr4 = array (
17
  'WebpConverter\\' =>
18
  array (
19
- 0 => __DIR__ . '/../..' . '/app',
20
  ),
21
  );
22
 
23
  public static function getInitializer(ClassLoader $loader)
24
  {
25
  return \Closure::bind(function () use ($loader) {
26
- $loader->prefixLengthsPsr4 = ComposerStaticInitbf2d1e8ab3a1950ed7aef886b373c248::$prefixLengthsPsr4;
27
- $loader->prefixDirsPsr4 = ComposerStaticInitbf2d1e8ab3a1950ed7aef886b373c248::$prefixDirsPsr4;
28
 
29
  }, null, ClassLoader::class);
30
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit9b97786baa18a2131b86fc40df508740
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
16
  public static $prefixDirsPsr4 = array (
17
  'WebpConverter\\' =>
18
  array (
19
+ 0 => __DIR__ . '/../..' . '/src',
20
  ),
21
  );
22
 
23
  public static function getInitializer(ClassLoader $loader)
24
  {
25
  return \Closure::bind(function () use ($loader) {
26
+ $loader->prefixLengthsPsr4 = ComposerStaticInit9b97786baa18a2131b86fc40df508740::$prefixLengthsPsr4;
27
+ $loader->prefixDirsPsr4 = ComposerStaticInit9b97786baa18a2131b86fc40df508740::$prefixDirsPsr4;
28
 
29
  }, null, ClassLoader::class);
30
  }
webp-converter-for-media.php CHANGED
@@ -1,20 +1,20 @@
1
- <?php
2
-
3
- /*
4
- Plugin Name: WebP Converter for Media
5
- Description: Speed up your website by serving WebP images instead of standard formats JPEG, PNG and GIF.
6
- Version: 2.4.0
7
- Author: Mateusz Gbiorczyk
8
- Author URI: https://gbiorczyk.pl/
9
- Text Domain: webp-converter-for-media
10
- Network: true
11
- */
12
-
13
- define('WEBPC_VERSION', '2.4.0');
14
- define('WEBPC_FILE', __FILE__);
15
- define('WEBPC_NAME', plugin_basename(__FILE__));
16
- define('WEBPC_PATH', plugin_dir_path(__FILE__));
17
- define('WEBPC_URL', plugin_dir_url(__FILE__));
18
-
19
- require_once __DIR__ . '/vendor/autoload.php';
20
- new WebpConverter\WebpConverter();
1
+ <?php
2
+
3
+ /**
4
+ * Plugin Name: WebP Converter for Media
5
+ * Description: Speed up your website by serving WebP images instead of standard formats JPEG, PNG and GIF.
6
+ * Version: 3.0.0
7
+ * Author: Mateusz Gbiorczyk
8
+ * Author URI: https://gbiorczyk.pl/
9
+ * Text Domain: webp-converter-for-media
10
+ * Network: true
11
+ */
12
+
13
+ define( 'WEBPC_VERSION', '3.0.0' );
14
+ define( 'WEBPC_FILE', __FILE__ );
15
+ define( 'WEBPC_NAME', plugin_basename( __FILE__ ) );
16
+ define( 'WEBPC_PATH', plugin_dir_path( __FILE__ ) );
17
+ define( 'WEBPC_URL', plugin_dir_url( __FILE__ ) );
18
+
19
+ require_once __DIR__ . '/vendor/autoload.php';
20
+ new WebpConverter\WebpConverter();