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

Version Description

(2020-08-13) = * [Removed] Filter webpc_notice_url * [Changed] Error messages for server requirements * [Changed] Loading CSS and JS files only on plugin settings page * [Changed] Minor changes for plugin settings page * [Changed] Validation of saved settings values for security * [Added] Blocking redirects to WebP when displaying images on other domains * [Added] Cron to automatically regenerate new images outside of Media Library * [Added] Filter webpc_cron_interval to change cron interval * [Added] Error message for incorrect plugin settings * [Added] Error when converting when WebP file is larger than original and has been deleted * [Added] Notice after plugin installation with description of first steps * [Added] Option to log errors while converting to debug.log file * [Added] Option to preserve metadata for WebP files (available for Imagick library) * [Added] Value of ABSPATH in Server configuration tab

Download this release

Release Info

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

Code changes from version 1.1.2 to 1.4.0

Files changed (75) hide show
  1. app/Action/Convert.php +47 -0
  2. app/Action/Cron.php +36 -0
  3. app/Action/Delete.php +30 -0
  4. app/Action/Regenerate.php +23 -0
  5. app/Action/_Core.php +14 -0
  6. app/Admin/Activation.php +0 -42
  7. app/Admin/Assets.php +5 -2
  8. app/Admin/Deactivation.php +0 -20
  9. app/Admin/Notice.php +26 -17
  10. app/Admin/Plugin.php +11 -5
  11. app/Admin/_Core.php +0 -4
  12. app/Convert/Dir.php +43 -0
  13. app/Convert/Directory.php +6 -3
  14. app/Convert/Paths.php +89 -0
  15. app/Convert/Server.php +26 -0
  16. app/Convert/Size.php +29 -0
  17. app/Convert/_Core.php +13 -0
  18. app/Media/Attachment.php +54 -0
  19. app/Media/Delete.php +1 -5
  20. app/Media/Htaccess.php +81 -34
  21. app/Media/Upload.php +21 -36
  22. app/{Convert → Method}/Gd.php +20 -16
  23. app/{Convert → Method}/Imagick.php +22 -16
  24. app/Plugin/Activation.php +56 -0
  25. app/Plugin/Deactivation.php +30 -0
  26. app/{Admin → Plugin}/Uninstall.php +17 -5
  27. app/Plugin/Update.php +78 -0
  28. app/Plugin/_Core.php +14 -0
  29. app/Regenerate/Endpoints.php +20 -14
  30. app/Regenerate/Paths.php +10 -46
  31. app/Regenerate/Regenerate.php +4 -12
  32. app/Regenerate/Skip.php +4 -3
  33. app/Regenerate/_Core.php +1 -0
  34. app/Settings/Errors.php +84 -15
  35. app/Settings/Methods.php +7 -4
  36. app/Settings/Options.php +45 -23
  37. app/Settings/Page.php +16 -2
  38. app/Settings/Paths.php +0 -35
  39. app/Settings/Save.php +17 -15
  40. app/Settings/Server.php +89 -0
  41. app/Settings/Values.php +9 -9
  42. app/Settings/_Core.php +0 -1
  43. app/WebpConverter.php +3 -0
  44. public/build/css/styles.css +1 -1
  45. public/build/js/scripts.js +1 -1
  46. public/img/.htaccess +6 -0
  47. public/img/icon-after.png +0 -0
  48. public/img/icon-after.png2 +0 -0
  49. public/img/icon-before.png +0 -0
  50. public/img/icon-before.png2 +0 -0
  51. readme.txt +324 -53
  52. resources/_dev/js/classes/Notice.js +1 -0
  53. resources/_dev/js/classes/Regenerate.js +21 -7
  54. resources/_dev/scss/components/webpLoader.scss +4 -0
  55. resources/_dev/scss/layout/webpPage.scss +2 -13
  56. resources/components/errors/bypassing-apache.php +13 -0
  57. resources/components/errors/libs-not-installed.php +13 -0
  58. resources/components/errors/libs-without-webp-support.php +11 -0
  59. resources/components/errors/path-htaccess-not-writable.php +8 -0
  60. resources/components/errors/path-uploads-unavailable.php +10 -0
  61. resources/components/errors/path-webp-duplicated.php +8 -0
  62. resources/components/errors/path-webp-not-writable.php +10 -0
  63. resources/components/errors/rest-api-disabled.php +8 -0
  64. resources/components/errors/settings-incorrect.php +7 -0
  65. resources/components/notices/thanks.php +7 -7
  66. resources/components/notices/welcome.php +20 -0
  67. resources/components/widgets/about.php +5 -5
  68. resources/components/widgets/donate.php +3 -3
  69. resources/components/widgets/errors.php +2 -38
  70. resources/components/widgets/options.php +3 -3
  71. resources/components/widgets/regenerate.php +20 -14
  72. resources/components/widgets/server.php +4 -4
  73. resources/components/widgets/support.php +7 -7
  74. resources/views/settings.php +30 -28
  75. webp-converter-for-media.php +3 -3
app/Action/Convert.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\Method;
6
+ use WebpConverter\Media\Attachment;
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
+ if ($settings['method'] === 'gd') $convert = new Method\Gd();
26
+ else if ($settings['method'] === 'imagick') $convert = new Method\Imagick();
27
+ if (!isset($convert)) return false;
28
+
29
+ foreach ($paths as $path) {
30
+ $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
31
+ if (!in_array($extension, $settings['extensions'])) continue;
32
+ $convert->convertImage($path, $settings);
33
+ }
34
+ }
35
+
36
+ public function convertFilesByAttachment($postId)
37
+ {
38
+ $paths = (new Attachment())->getAttachmentPaths($postId);
39
+ do_action('webpc_convert_paths', $paths);
40
+ }
41
+
42
+ public function convertFilesByDirectory($dirPath, $skipExists = true)
43
+ {
44
+ $paths = apply_filters('webpc_dir_files', [], $dirPath, $skipExists);
45
+ do_action('webpc_convert_paths', $paths);
46
+ }
47
+ }
app/Action/Cron.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Action;
4
+
5
+ use WebpConverter\Convert\Directory;
6
+
7
+ class Delete
8
+ {
9
+ public function __construct()
10
+ {
11
+ add_action('webpc_delete_paths', [$this, 'deleteFilesByPaths']);
12
+ }
13
+
14
+ /* ---
15
+ Functions
16
+ --- */
17
+
18
+ public function deleteFilesByPaths($paths)
19
+ {
20
+ foreach ($paths as $path) {
21
+ $this->deleteFileByPath($path);
22
+ }
23
+ }
24
+
25
+ private function deleteFileByPath($path)
26
+ {
27
+ $source = (new Directory())->getPath($path);
28
+ if (is_writable($source) && (pathinfo($source, PATHINFO_EXTENSION) === 'webp')) unlink($source);
29
+ }
30
+ }
app/Action/Regenerate.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/Activation.php DELETED
@@ -1,42 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- class Activation
6
- {
7
- public function __construct()
8
- {
9
- register_activation_hook(WEBPC_FILE, [$this, 'disablePluginForOldPhp']);
10
- register_activation_hook(WEBPC_FILE, [$this, 'addDefaultOptions']);
11
- register_activation_hook(WEBPC_FILE, [$this, 'refreshRewriteRules']);
12
- }
13
-
14
- /* ---
15
- Functions
16
- --- */
17
-
18
- public function disablePluginForOldPhp()
19
- {
20
- if (version_compare(PHP_VERSION, '5.6.12', '>=')) return;
21
-
22
- deactivate_plugins(basename(WEBPC_FILE));
23
- wp_die(sprintf(
24
- __('%sWebP Converter for Media%s plugin requires a minimum PHP %s version. Sorry about that!', 'webp-converter'),
25
- '<strong>',
26
- '</strong>',
27
- $this->version
28
- ));
29
- }
30
-
31
- public function addDefaultOptions()
32
- {
33
- if (get_option('webpc_notice_hidden', false) === false) {
34
- add_option('webpc_notice_hidden', strtotime('+ 1 week'));
35
- }
36
- }
37
-
38
- public function refreshRewriteRules()
39
- {
40
- flush_rewrite_rules(true);
41
- }
42
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Assets.php CHANGED
@@ -4,6 +4,9 @@
4
 
5
  class Assets
6
  {
 
 
 
7
  public function __construct()
8
  {
9
  add_filter('admin_enqueue_scripts', [$this, 'loadStyles']);
@@ -16,13 +19,13 @@
16
 
17
  public function loadStyles()
18
  {
19
- wp_register_style('webp-converter', WEBPC_URL . 'public/build/css/styles.css', '', WEBPC_VERSION);
20
  wp_enqueue_style('webp-converter');
21
  }
22
 
23
  public function loadScripts()
24
  {
25
- wp_register_script('webp-converter', WEBPC_URL . 'public/build/js/scripts.js', 'jquery', WEBPC_VERSION, true);
26
  wp_enqueue_script('webp-converter');
27
  }
28
  }
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']);
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/Deactivation.php DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Admin;
4
-
5
- class Deactivation
6
- {
7
- public function __construct()
8
- {
9
- register_deactivation_hook(WEBPC_FILE, [$this, 'refreshRewriteRules']);
10
- }
11
-
12
- /* ---
13
- Functions
14
- --- */
15
-
16
- public function refreshRewriteRules()
17
- {
18
- flush_rewrite_rules(true);
19
- }
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Admin/Notice.php CHANGED
@@ -2,46 +2,55 @@
2
 
3
  namespace WebpConverter\Admin;
4
 
 
 
5
  class Notice
6
  {
7
- private $option = 'webpc_notice_hidden';
8
 
9
  public function __construct()
10
  {
11
- add_filter('webpc_notice_url', [$this, 'showNoticeUrl']);
12
- add_action('admin_notices', [$this, 'showAdminNotice']);
13
- add_action('wp_ajax_webpc_notice', [$this, 'hideAdminNotice']);
14
  }
15
 
16
  /* ---
17
  Functions
18
  --- */
19
 
20
- public function showNoticeUrl()
 
 
 
 
 
 
 
 
21
  {
22
- $url = admin_url('admin-ajax.php?action=webpc_notice');
23
- return $url;
24
  }
25
 
26
- public function showAdminNotice()
27
  {
28
  if (($_SERVER['PHP_SELF'] !== '/wp-admin/index.php') ||
29
- (get_option($this->option, 0) >= time())) return;
30
 
 
 
 
 
 
 
31
  require_once WEBPC_PATH . 'resources/components/notices/thanks.php';
32
  }
33
 
34
- public function hideAdminNotice()
35
  {
36
  $isPermanent = isset($_POST['is_permanently']) && $_POST['is_permanently'];
37
  $expires = strtotime($isPermanent ? '+10 years' : '+ 1 month');
38
 
39
- $this->saveOption($expires);
40
- }
41
-
42
- public function saveOption($value)
43
- {
44
- if (get_option($this->option, false) !== false) update_option($this->option, $value);
45
- else add_option($this->option, $value);
46
  }
47
  }
2
 
3
  namespace WebpConverter\Admin;
4
 
5
+ use WebpConverter\Plugin\Activation;
6
+
7
  class Notice
8
  {
9
+ const NOTICE_THANKS_OPTION = 'webpc_notice_hidden';
10
 
11
  public function __construct()
12
  {
13
+ add_action('admin_init', [$this, 'showWelcomeNotice']);
14
+ add_action('admin_init', [$this, 'showThanksNotice']);
15
+ add_action('wp_ajax_webpc_notice', [$this, 'hideThanksNotice']);
16
  }
17
 
18
  /* ---
19
  Functions
20
  --- */
21
 
22
+ public function showWelcomeNotice()
23
+ {
24
+ if (get_option(Activation::NEW_INSTALLATION_OPTION) !== '1') return;
25
+
26
+ new Assets();
27
+ add_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
28
+ }
29
+
30
+ public static function loadWelcomeNotice()
31
  {
32
+ require_once WEBPC_PATH . 'resources/components/notices/welcome.php';
 
33
  }
34
 
35
+ public function showThanksNotice()
36
  {
37
  if (($_SERVER['PHP_SELF'] !== '/wp-admin/index.php') ||
38
+ (get_option(self::NOTICE_THANKS_OPTION, 0) >= time())) return;
39
 
40
+ new Assets();
41
+ add_action('admin_notices', [$this, 'loadThanksNotice']);
42
+ }
43
+
44
+ public function loadThanksNotice()
45
+ {
46
  require_once WEBPC_PATH . 'resources/components/notices/thanks.php';
47
  }
48
 
49
+ public function hideThanksNotice()
50
  {
51
  $isPermanent = isset($_POST['is_permanently']) && $_POST['is_permanently'];
52
  $expires = strtotime($isPermanent ? '+10 years' : '+ 1 month');
53
 
54
+ update_option(self::NOTICE_THANKS_OPTION, $expires);
 
 
 
 
 
 
55
  }
56
  }
app/Admin/Plugin.php CHANGED
@@ -6,23 +6,29 @@
6
  {
7
  public function __construct()
8
  {
9
- add_filter('network_admin_plugin_action_links_' . WEBPC_NAME, [$this, 'addPluginLinks']);
10
- add_filter('plugin_action_links_' . WEBPC_NAME, [$this, 'addPluginLinks']);
 
11
  }
12
 
13
  /* ---
14
  Functions
15
  --- */
16
 
17
- public function addPluginLinks($links)
18
  {
19
  array_unshift($links, sprintf(
20
- __('%sSettings%s', 'webp-converter'),
21
  '<a href="' . menu_page_url('webpc_admin_page', false) . '">',
22
  '</a>'
23
  ));
 
 
 
 
 
24
  $links[] = sprintf(
25
- __('%sProvide us a coffee%s', 'webp-converter'),
26
  '<a href="https://ko-fi.com/gbiorczyk/" target="_blank">',
27
  '</a>'
28
  );
6
  {
7
  public function __construct()
8
  {
9
+ add_filter('plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToSettings']);
10
+ add_filter('plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToDonate']);
11
+ add_filter('network_admin_plugin_action_links_' . WEBPC_NAME, [$this, 'addLinkToDonate']);
12
  }
13
 
14
  /* ---
15
  Functions
16
  --- */
17
 
18
+ public function addLinkToSettings($links)
19
  {
20
  array_unshift($links, sprintf(
21
+ __('%sSettings%s', 'webp-converter-for-media'),
22
  '<a href="' . menu_page_url('webpc_admin_page', false) . '">',
23
  '</a>'
24
  ));
25
+ return $links;
26
+ }
27
+
28
+ public function addLinkToDonate($links)
29
+ {
30
  $links[] = sprintf(
31
+ __('%sProvide us a coffee%s', 'webp-converter-for-media'),
32
  '<a href="https://ko-fi.com/gbiorczyk/" target="_blank">',
33
  '</a>'
34
  );
app/Admin/_Core.php CHANGED
@@ -6,11 +6,7 @@
6
  {
7
  public function __construct()
8
  {
9
- new Activation();
10
- new Assets();
11
- new Deactivation();
12
  new Notice();
13
  new Plugin();
14
- new Uninstall();
15
  }
16
  }
6
  {
7
  public function __construct()
8
  {
 
 
 
9
  new Notice();
10
  new Plugin();
 
11
  }
12
  }
app/Convert/Dir.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_attachment_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 . '/' . $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 CHANGED
@@ -10,9 +10,12 @@
10
 
11
  public function getPath($path, $createDirectory = false)
12
  {
13
- $pathSource = apply_filters('webpc_uploads_path', '');
14
- $pathOutput = apply_filters('webpc_uploads_webp', '');
15
- $newPath = str_replace("/${pathSource}/", "/${pathOutput}/", $path) . '.webp';
 
 
 
16
  if (!$createDirectory) return $newPath;
17
 
18
  if (!$paths = $this->checkDirectories($newPath)) return $newPath;
10
 
11
  public function getPath($path, $createDirectory = false)
12
  {
13
+ $webpRoot = apply_filters('webpc_uploads_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 = $this->checkDirectories($newPath)) return $newPath;
app/Convert/Paths.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Convert;
4
+
5
+ class Paths
6
+ {
7
+ const PATH_UPLOADS = 'wp-content/uploads';
8
+ const PATH_OUTPUT = 'wp-content/uploads-webpc';
9
+ const DIRS_EXCLUDED = ['.', '..', '.git', '.svn', 'node_modules'];
10
+
11
+ public function __construct()
12
+ {
13
+ add_filter('webpc_uploads_path', [$this, 'getUploadsPath'], 0, 2);
14
+ add_filter('webpc_uploads_webp', [$this, 'getOutputPath'], 0, 2);
15
+ add_filter('webpc_uploads_path', [$this, 'parsePath'], 100, 2);
16
+ add_filter('webpc_uploads_webp', [$this, 'parsePath'], 100, 2);
17
+ add_filter('webpc_uploads_prefix', [$this, 'getPrefixPath'], 0);
18
+ add_filter('webpc_uploads_dir', [$this, 'getUploadsDir'], 0);
19
+ add_filter('webpc_dir_path', [$this, 'getPathOfDir'], 0, 2);
20
+ add_filter('webpc_dir_excluded', [$this, 'getExcludedDirs'], 0);
21
+ }
22
+
23
+ /* ---
24
+ Functions
25
+ --- */
26
+
27
+ public function getUploadsPath($value, $skipRoot = false)
28
+ {
29
+ return self::PATH_UPLOADS;
30
+ }
31
+
32
+ public function getOutputPath($value, $skipRoot = false)
33
+ {
34
+ return self::PATH_OUTPUT;
35
+ }
36
+
37
+ public function parsePath($value, $skipRoot = false)
38
+ {
39
+ if ($skipRoot) return trim($value, '\/');
40
+
41
+ $path = apply_filters('webpc_uploads_root', ABSPATH);
42
+ return $path . '/' . trim($value, '\/');
43
+ }
44
+
45
+ public function getPrefixPath($value)
46
+ {
47
+ $docDir = realpath($_SERVER['DOCUMENT_ROOT']);
48
+ $wpDir = realpath(ABSPATH);
49
+ $diffDir = trim(str_replace($docDir, '', $wpDir), '\/');
50
+ $diffPath = sprintf('/%s/', $diffDir);
51
+
52
+ return str_replace('//', '/', $diffPath);
53
+ }
54
+
55
+ public function getUploadsDir($value)
56
+ {
57
+ $uploadsDir = apply_filters('webpc_uploads_path', '');
58
+ $uploadsParent = dirname($uploadsDir);
59
+ $webpParent = dirname(apply_filters('webpc_uploads_webp', ''));
60
+ if ((!$uploadsDir = realpath($uploadsDir)) || (!$uploadsParent = realpath($uploadsParent))
61
+ || ($uploadsParent !== realpath($webpParent))) {
62
+ return $value;
63
+ }
64
+
65
+ $path = str_replace($uploadsParent, '', $uploadsDir);
66
+ return trim($path, '\/');
67
+ }
68
+
69
+ public function getPathOfDir($value, $directory)
70
+ {
71
+ switch ($directory) {
72
+ case 'plugins':
73
+ return dirname(WEBPC_PATH);
74
+ break;
75
+ case 'themes':
76
+ return get_theme_root();
77
+ break;
78
+ case 'uploads':
79
+ return apply_filters('webpc_uploads_path', '');
80
+ break;
81
+ }
82
+ return null;
83
+ }
84
+
85
+ public function getExcludedDirs($value)
86
+ {
87
+ return self::DIRS_EXCLUDED;
88
+ }
89
+ }
app/Convert/Server.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Convert;
4
+
5
+ class Server
6
+ {
7
+ /* ---
8
+ Functions
9
+ --- */
10
+
11
+ public 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 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 ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Convert;
4
+
5
+ class Size
6
+ {
7
+ public function __construct()
8
+ {
9
+ add_action('webpc_convert_after', [$this, 'removeImageIfIsLarger'], 10, 2);
10
+ }
11
+
12
+ /* ---
13
+ Functions
14
+ --- */
15
+
16
+ public function removeImageIfIsLarger($webpPath, $originalPath)
17
+ {
18
+ if ((!$settings = apply_filters('webpc_get_values', []))
19
+ || !in_array('only_smaller', $settings['features'])
20
+ || (!file_exists($webpPath) || !file_exists($originalPath))
21
+ || (filesize($webpPath) < filesize($originalPath))) return;
22
+
23
+ unlink($webpPath);
24
+ throw new \Exception(sprintf(
25
+ 'Image "%s" converted to WebP is larger than original and has been deleted.',
26
+ $originalPath
27
+ ));
28
+ }
29
+ }
app/Convert/_Core.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
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/Media/Attachment.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ return $paths;
39
+ }
40
+
41
+ private function getPathsBySizes($postId, $path)
42
+ {
43
+ $list = [];
44
+ $list[] = str_replace('\\', '/', implode('/', [$this->uploadDir['basedir'], $path]));
45
+
46
+ foreach ($this->imageSizes as $size) {
47
+ $src = wp_get_attachment_image_src($postId, $size);
48
+ $url = str_replace($this->uploadDir['baseurl'], $this->uploadDir['basedir'], $src[0]);
49
+ $url = str_replace('\\', '/', $url);
50
+ $list[] = $url;
51
+ }
52
+ return array_values(array_unique($list));
53
+ }
54
+ }
app/Media/Delete.php CHANGED
@@ -2,8 +2,6 @@
2
 
3
  namespace WebpConverter\Media;
4
 
5
- use WebpConverter\Convert as Convert;
6
-
7
  class Delete
8
  {
9
  public function __construct()
@@ -17,9 +15,7 @@
17
 
18
  public function deleteAttachmentFile($path)
19
  {
20
- $directory = new Convert\Directory();
21
- $source = $directory->getPath($path);
22
- if (is_writable($source) && (pathinfo($source, PATHINFO_EXTENSION) === 'webp')) unlink($source);
23
  return $path;
24
  }
25
  }
2
 
3
  namespace WebpConverter\Media;
4
 
 
 
5
  class Delete
6
  {
7
  public function __construct()
15
 
16
  public function deleteAttachmentFile($path)
17
  {
18
+ do_action('webpc_delete_paths', [$path]);
 
 
19
  return $path;
20
  }
21
  }
app/Media/Htaccess.php CHANGED
@@ -4,64 +4,87 @@
4
 
5
  class Htaccess
6
  {
 
 
7
  public function __construct()
8
  {
9
- add_filter('mod_rewrite_rules', [$this, 'addRewriteRules']);
 
 
10
  }
11
 
12
  /* ---
13
  Functions
14
  --- */
15
 
16
- public function addRewriteRules($rules)
17
  {
18
- if (isset($_GET['plugin']) && ($_GET['plugin'] === 'webp-converter-for-media/webp-converter-for-media.php')
19
- && isset($_GET['action']) && ($_GET['action'] === 'deactivate')) return $rules;
20
 
21
- $values = apply_filters('webpc_get_values', []);
22
- $rows = [];
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- $rows[] = $this->getModMimeRules($values);
25
- $rows[] = $this->getModRewriteRules($values);
26
- $rows[] = $this->getModExpiresRules($values);
 
27
 
28
- $rows = array_filter($rows);
29
  $content = $this->addCommentsToRules($rows);
30
- return $content . $rules;
 
31
  }
32
 
33
- private function getModMimeRules($settings)
34
  {
35
- $content = '';
36
- if (!$settings['extensions']) return $content;
37
 
38
- $content .= '<IfModule mod_mime.c>' . PHP_EOL;
39
- $content .= ' AddType image/webp .webp' . PHP_EOL;
40
- $content .= '</IfModule>';
 
 
41
 
42
- $content = apply_filters('webpc_htaccess_mod_mime', $content);
43
- return $content;
 
44
  }
45
 
46
- private function getModRewriteRules($settings)
47
  {
48
  $content = '';
49
  if (!$settings['extensions']) return $content;
50
 
51
- $pathUrl = parse_url(site_url('/'), PHP_URL_PATH);
52
- $pathSource = apply_filters('webpc_uploads_path', '');
53
- $pathOutput = apply_filters('webpc_uploads_webp', '');
54
 
55
  $content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
56
  $content .= ' RewriteEngine On' . PHP_EOL;
57
  foreach ($settings['extensions'] as $ext) {
58
  $content .= ' RewriteCond %{HTTP_ACCEPT} image/webp' . PHP_EOL;
59
- $content .= " RewriteCond %{DOCUMENT_ROOT}${pathUrl}${pathOutput}/$1.${ext}.webp -f" . PHP_EOL;
60
- $content .= " RewriteRule ${pathSource}/(.+)\.${ext}$ ${pathOutput}/$1.${ext}.webp [T=image/webp]" . PHP_EOL;
 
 
 
61
  }
62
  $content .= '</IfModule>';
63
 
64
- $content = apply_filters('webpc_htaccess_mod_rewrite', $content);
65
  return $content;
66
  }
67
 
@@ -79,20 +102,44 @@
79
  return $content;
80
  }
81
 
82
- private function addCommentsToRules($rules)
83
  {
84
  $content = '';
85
- if (!$rules) return $content;
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  $rows = [];
88
- $rows[] = PHP_EOL;
89
  $rows[] = '# BEGIN WebP Converter';
90
- $rows = array_merge($rows, $rules);
 
 
91
  $rows[] = '# END WebP Converter';
92
- $rows[] = PHP_EOL;
93
 
94
- $content = implode(PHP_EOL, $rows);
95
- $content = apply_filters('webpc_htaccess_rules', $content);
96
- return $content;
 
 
 
 
 
 
 
 
 
 
97
  }
98
  }
4
 
5
  class Htaccess
6
  {
7
+ const ACTION_NAME = 'webpc_rewrite_htaccess';
8
+
9
  public function __construct()
10
  {
11
+ add_action(self::ACTION_NAME, [$this, 'addRewriteRulesToWpContent'], 10, 1);
12
+ add_action(self::ACTION_NAME, [$this, 'addRewriteRulesToUploads'], 10, 1);
13
+ add_action(self::ACTION_NAME, [$this, 'addRewriteRulesToUploadsWebp'], 10, 1);
14
  }
15
 
16
  /* ---
17
  Functions
18
  --- */
19
 
20
+ public function addRewriteRulesToWpContent($isActive)
21
  {
22
+ $path = dirname(apply_filters('webpc_uploads_path', ''));
23
+ if (!$isActive) return $this->saveRewritesInHtaccesss($path);
24
 
25
+ $settings = apply_filters('webpc_get_values', []);
26
+ $rows = [
27
+ $this->getModRewriteRules($settings),
28
+ ];
29
+
30
+ $content = $this->addCommentsToRules($rows);
31
+ $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
32
+ $this->saveRewritesInHtaccesss($path, $content);
33
+ }
34
+
35
+ public function addRewriteRulesToUploads($isActive)
36
+ {
37
+ $path = apply_filters('webpc_uploads_path', '');
38
+ if (!$isActive) return $this->saveRewritesInHtaccesss($path);
39
 
40
+ $settings = apply_filters('webpc_get_values', []);
41
+ $rows = [
42
+ $this->getModRewriteRules($settings, apply_filters('webpc_uploads_dir', '')),
43
+ ];
44
 
 
45
  $content = $this->addCommentsToRules($rows);
46
+ $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
47
+ $this->saveRewritesInHtaccesss($path, $content);
48
  }
49
 
50
+ public function addRewriteRulesToUploadsWebp($isActive)
51
  {
52
+ $path = apply_filters('webpc_uploads_webp', '');
53
+ if (!$isActive) return $this->saveRewritesInHtaccesss($path);
54
 
55
+ $values = apply_filters('webpc_get_values', []);
56
+ $rows = [
57
+ $this->getModMimeRules($values),
58
+ $this->getModExpiresRules($values),
59
+ ];
60
 
61
+ $content = $this->addCommentsToRules($rows);
62
+ $content = apply_filters('webpc_htaccess_rules', $content, $path . '/.htaccess');
63
+ $this->saveRewritesInHtaccesss($path, $content);
64
  }
65
 
66
+ private function getModRewriteRules($settings, $outputPath = null)
67
  {
68
  $content = '';
69
  if (!$settings['extensions']) return $content;
70
 
71
+ $path = apply_filters('webpc_uploads_prefix', '/');
72
+ $path .= apply_filters('webpc_uploads_webp', '', true);
73
+ if ($outputPath !== null) $path .= '/' . $outputPath;
74
 
75
  $content .= '<IfModule mod_rewrite.c>' . PHP_EOL;
76
  $content .= ' RewriteEngine On' . PHP_EOL;
77
  foreach ($settings['extensions'] as $ext) {
78
  $content .= ' RewriteCond %{HTTP_ACCEPT} image/webp' . PHP_EOL;
79
+ $content .= " RewriteCond %{DOCUMENT_ROOT}${path}/$1.${ext}.webp -f" . PHP_EOL;
80
+ if (!in_array('referer_disabled', $settings['features'])) {
81
+ $content .= " RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} ^([^@]*)@@https?://\\1/.*" . PHP_EOL;
82
+ }
83
+ $content .= " RewriteRule (.+)\.${ext}$ ${path}/$1.${ext}.webp [NC,T=image/webp,E=cache-control:private,L]" . PHP_EOL;
84
  }
85
  $content .= '</IfModule>';
86
 
87
+ $content = apply_filters('webpc_htaccess_mod_rewrite', $content, $path);
88
  return $content;
89
  }
90
 
102
  return $content;
103
  }
104
 
105
+ private function getModMimeRules($settings)
106
  {
107
  $content = '';
108
+ if (!$settings['extensions']) return $content;
109
+
110
+ $content .= '<IfModule mod_mime.c>' . PHP_EOL;
111
+ $content .= ' AddType image/webp .webp' . PHP_EOL;
112
+ $content .= '</IfModule>';
113
+
114
+ $content = apply_filters('webpc_htaccess_mod_mime', $content);
115
+ return $content;
116
+ }
117
+
118
+ private function addCommentsToRules($rules)
119
+ {
120
+ if (!$rules) return '';
121
 
122
  $rows = [];
123
+ $rows[] = '';
124
  $rows[] = '# BEGIN WebP Converter';
125
+ $rows[] = '# ! --- DO NOT EDIT PREVIOUS LINE --- !';
126
+ $rows = array_merge($rows, array_filter($rules));
127
+ $rows[] = '# ! --- DO NOT EDIT NEXT LINE --- !';
128
  $rows[] = '# END WebP Converter';
129
+ $rows[] = '';
130
 
131
+ return implode(PHP_EOL, $rows);
132
+ }
133
+
134
+ private function saveRewritesInHtaccesss($pathDir, $rules = '')
135
+ {
136
+ $pathFile = $pathDir . '/.htaccess';
137
+
138
+ $code = (is_readable($pathFile)) ? file_get_contents($pathFile) : '';
139
+ $code = preg_replace('/((:?[\r\n|\r|\n]?)# BEGIN WebP Converter(.*?)# END WebP Converter(:?(:?[\r\n|\r|\n]+)?))/s', '', $code);
140
+ if ($rules && $code) $code = PHP_EOL . $code;
141
+ $code = $rules . $code;
142
+
143
+ if (is_writable($pathDir)) file_put_contents($pathFile, $code);
144
  }
145
  }
app/Media/Upload.php CHANGED
@@ -2,10 +2,10 @@
2
 
3
  namespace WebpConverter\Media;
4
 
5
- use WebpConverter\Convert as Convert;
6
-
7
  class Upload
8
  {
 
 
9
  public function __construct()
10
  {
11
  add_filter('wp_update_attachment_metadata', [$this, 'initAttachmentConvert'], 10, 2);
@@ -18,50 +18,35 @@
18
  public function initAttachmentConvert($data, $attachmentId)
19
  {
20
  if (!$data || !isset($data['file']) || !isset($data['sizes'])) return $data;
21
- $path = $this->getAttachmentDirectory($data['file']);
22
- $sizes = [];
23
 
24
- $sizes['_source'] = $path . basename($data['file']);
25
- foreach ($data['sizes'] as $key => $size) {
26
- $url = $path . $size['file'];
27
- if (in_array($url, $sizes)) continue;
28
- $sizes[$key] = $url;
29
- }
30
 
31
- $sizes = apply_filters('webpc_attachment_paths', $sizes, $attachmentId);
32
- $this->convertSizes($sizes);
33
- return $data;
34
- }
35
 
36
- private function getAttachmentDirectory($path)
37
- {
38
- $upload = wp_upload_dir();
39
- $source = rtrim($upload['basedir'], '/\\') . '/' . rtrim(dirname($path), '/\\') . '/';
40
- $source = str_replace('\\', '/', $source);
41
- return $source;
42
  }
43
 
44
- private function convertSizes($paths)
45
  {
46
- $settings = apply_filters('webpc_get_values', []);
47
-
48
- if ($settings['method'] === 'gd') $convert = new Convert\Gd();
49
- else if ($settings['method'] === 'imagick') $convert = new Convert\Imagick();
50
- if (!isset($convert)) return false;
51
 
52
- foreach ($paths as $path) {
53
- if (!in_array(pathinfo($path, PATHINFO_EXTENSION), $settings['extensions'])) continue;
54
-
55
- $response = $convert->convertImage($path, $settings['quality']);
56
- if (!$response['success']) $this->addErrorToLog($response['message']);
57
  }
 
58
  }
59
 
60
- private function addErrorToLog($message)
61
  {
62
- error_log(sprintf(
63
- 'WebP Converter: %s',
64
- $message
65
- ));
66
  }
67
  }
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);
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
 
25
+ $paths = array_diff($paths, $this->convertedPaths);
26
+ $this->convertedPaths = array_merge($this->convertedPaths, $paths);
 
 
27
 
28
+ do_action('webpc_convert_paths', $paths);
29
+ return $data;
 
 
 
 
30
  }
31
 
32
+ private function getSizesPaths($data)
33
  {
34
+ $directory = $this->getAttachmentDirectory($data['file']);
35
+ $list = [];
 
 
 
36
 
37
+ $list[] = $directory . basename($data['file']);
38
+ foreach ($data['sizes'] as $key => $size) {
39
+ $path = $directory . $size['file'];
40
+ if (!in_array($path, $list)) $list[] = $path;
 
41
  }
42
+ return array_values(array_unique($list));
43
  }
44
 
45
+ private function getAttachmentDirectory($path)
46
  {
47
+ $upload = wp_upload_dir();
48
+ $source = rtrim($upload['basedir'], '/\\') . '/' . rtrim(dirname($path), '/\\') . '/';
49
+ $source = str_replace('\\', '/', $source);
50
+ return $source;
51
  }
52
  }
app/{Convert → Method}/Gd.php RENAMED
@@ -1,6 +1,9 @@
1
  <?php
2
 
3
- namespace WebpConverter\Convert;
 
 
 
4
 
5
  class Gd
6
  {
@@ -8,15 +11,13 @@
8
  Functions
9
  --- */
10
 
11
- public function convertImage($path, $quality)
12
  {
13
- ini_set('memory_limit', '1G');
14
- set_time_limit(120);
15
 
16
  try {
17
- if (!is_writable($path)) {
18
- throw new \Exception(sprintf('File "%s" does not exist.', $path));
19
- }
20
 
21
  $response = $this->createImage($path);
22
  if (!$response['success']) throw new \Exception($response['message']);
@@ -27,13 +28,17 @@
27
  else $image = $response['data'];
28
 
29
  $image = apply_filters('webpc_gd_before_saving', $image, $path);
30
- $response = $this->convertToWebp($image, $path, $quality);
31
  if (!$response['success']) throw new \Exception($response['message']);
32
  else return [
33
  'success' => true,
34
  'data' => $response['data'],
35
  ];
36
  } catch (\Exception $e) {
 
 
 
 
37
  return [
38
  'success' => false,
39
  'message' => $e->getMessage(),
@@ -43,7 +48,7 @@
43
 
44
  private function createImage($path)
45
  {
46
- $extension = pathinfo($path, PATHINFO_EXTENSION);
47
  $methods = apply_filters('webpc_gd_create_methods', [
48
  'imagecreatefromjpeg' => ['jpg', 'jpeg'],
49
  'imagecreatefrompng' => ['png'],
@@ -99,30 +104,29 @@
99
  }
100
  }
101
 
102
- private function convertToWebp($image, $path, $quality)
103
  {
104
  try {
105
- $directory = new Directory();
106
- $output = $directory->getPath($path, true);
107
-
108
  if (!$output) {
109
  throw new \Exception(sprintf('An error occurred creating destination directory for "%s" file.', $path));
110
  } else if (!function_exists('imagewebp')) {
111
  throw new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagewebp'));
112
  } else if ((imagesx($image) > 8192) || (imagesy($image) > 8192)) {
113
  throw new \Exception(sprintf('Image is larger than maximum 8K resolution: "%s".', $path));
114
- } else if (!$success = imagewebp($image, $output, $quality)) {
115
  throw new \Exception(sprintf('Error occurred while converting image: "%s".', $path));
116
  }
117
 
118
  if (filesize($output) % 2 === 1) file_put_contents($output, "\0", FILE_APPEND);
 
 
119
  return [
120
  'success' => true,
121
  'data' => [
122
- 'path' => $output,
123
  'size' => [
124
  'before' => filesize($path),
125
- 'after' => filesize($output),
126
  ],
127
  ],
128
  ];
1
  <?php
2
 
3
+ namespace WebpConverter\Method;
4
+
5
+ use WebpConverter\Convert\Directory;
6
+ use WebpConverter\Convert\Server;
7
 
8
  class Gd
9
  {
11
  Functions
12
  --- */
13
 
14
+ public function convertImage($path, $settings)
15
  {
16
+ (new Server())->setSettings();
 
17
 
18
  try {
19
+ $status = (new Server())->checkIfFileExists($path);
20
+ if ($status !== true) throw new \Exception($status);
 
21
 
22
  $response = $this->createImage($path);
23
  if (!$response['success']) throw new \Exception($response['message']);
28
  else $image = $response['data'];
29
 
30
  $image = apply_filters('webpc_gd_before_saving', $image, $path);
31
+ $response = $this->convertToWebp($image, $path, $settings);
32
  if (!$response['success']) throw new \Exception($response['message']);
33
  else return [
34
  'success' => true,
35
  'data' => $response['data'],
36
  ];
37
  } catch (\Exception $e) {
38
+ if (in_array('debug_enabled', $settings['features'])) {
39
+ error_log(sprintf('WebP Converter for Media: %s', $e->getMessage()));
40
+ }
41
+
42
  return [
43
  'success' => false,
44
  'message' => $e->getMessage(),
48
 
49
  private function createImage($path)
50
  {
51
+ $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
52
  $methods = apply_filters('webpc_gd_create_methods', [
53
  'imagecreatefromjpeg' => ['jpg', 'jpeg'],
54
  'imagecreatefrompng' => ['png'],
104
  }
105
  }
106
 
107
+ private function convertToWebp($image, $path, $settings)
108
  {
109
  try {
110
+ $output = (new Directory())->getPath($path, true);
 
 
111
  if (!$output) {
112
  throw new \Exception(sprintf('An error occurred creating destination directory for "%s" file.', $path));
113
  } else if (!function_exists('imagewebp')) {
114
  throw new \Exception(sprintf('Server configuration: "%s" function is not available.', 'imagewebp'));
115
  } else if ((imagesx($image) > 8192) || (imagesy($image) > 8192)) {
116
  throw new \Exception(sprintf('Image is larger than maximum 8K resolution: "%s".', $path));
117
+ } else if (!$success = imagewebp($image, $output, $settings['quality'])) {
118
  throw new \Exception(sprintf('Error occurred while converting image: "%s".', $path));
119
  }
120
 
121
  if (filesize($output) % 2 === 1) file_put_contents($output, "\0", FILE_APPEND);
122
+ do_action('webpc_convert_after', $output, $path);
123
+
124
  return [
125
  'success' => true,
126
  'data' => [
 
127
  'size' => [
128
  'before' => filesize($path),
129
+ 'after' => filesize((file_exists($output)) ? $output : $path),
130
  ],
131
  ],
132
  ];
app/{Convert → Method}/Imagick.php RENAMED
@@ -1,6 +1,9 @@
1
  <?php
2
 
3
- namespace WebpConverter\Convert;
 
 
 
4
 
5
  class Imagick
6
  {
@@ -8,28 +11,30 @@
8
  Functions
9
  --- */
10
 
11
- public function convertImage($path, $quality)
12
  {
13
- ini_set('memory_limit', '1G');
14
- set_time_limit(120);
15
 
16
  try {
17
- if (!is_writable($path)) {
18
- throw new \Exception(sprintf('File "%s" does not exist.', $path));
19
- }
20
 
21
  $response = $this->createImage($path);
22
  if (!$response['success']) throw new \Exception($response['message']);
23
  else $image = $response['data'];
24
 
25
  $image = apply_filters('webpc_imagick_before_saving', $image, $path);
26
- $response = $this->convertToWebp($image, $path, $quality);
27
  if (!$response['success']) throw new \Exception($response['message']);
28
  else return [
29
  'success' => true,
30
  'data' => $response['data'],
31
  ];
32
  } catch (\Exception $e) {
 
 
 
 
33
  return [
34
  'success' => false,
35
  'message' => $e->getMessage(),
@@ -39,7 +44,7 @@
39
 
40
  private function createImage($path)
41
  {
42
- $extension = pathinfo($path, PATHINFO_EXTENSION);
43
  try {
44
  if (!extension_loaded('imagick') || !class_exists('Imagick')) {
45
  throw new \Exception('Server configuration: Imagick module is not available with this PHP installation.');
@@ -62,11 +67,10 @@
62
  }
63
  }
64
 
65
- private function convertToWebp($image, $path, $quality)
66
  {
67
  try {
68
- $directory = new Directory();
69
- $output = $directory->getPath($path, true);
70
  if (!$output) {
71
  throw new \Exception(sprintf('An error occurred creating destination directory for "%s" file.', $path));
72
  } else if (!in_array('WEBP', $image->queryFormats())) {
@@ -74,22 +78,24 @@
74
  }
75
 
76
  $image->setImageFormat('WEBP');
77
- $image->stripImage();
78
- $image->setImageCompressionQuality($quality);
 
 
79
  $blob = $image->getImageBlob();
80
 
81
  $success = file_put_contents($output, $blob);
82
  if (!$success) {
83
  throw new \Exception('Error occurred while converting image.');
84
  }
 
85
 
86
  return [
87
  'success' => true,
88
  'data' => [
89
- 'path' => $output,
90
  'size' => [
91
  'before' => filesize($path),
92
- 'after' => filesize($output),
93
  ],
94
  ],
95
  ];
1
  <?php
2
 
3
+ namespace WebpConverter\Method;
4
+
5
+ use WebpConverter\Convert\Directory;
6
+ use WebpConverter\Convert\Server;
7
 
8
  class Imagick
9
  {
11
  Functions
12
  --- */
13
 
14
+ public function convertImage($path, $settings)
15
  {
16
+ (new Server())->setSettings();
 
17
 
18
  try {
19
+ $status = (new Server())->checkIfFileExists($path);
20
+ if ($status !== true) throw new \Exception($status);
 
21
 
22
  $response = $this->createImage($path);
23
  if (!$response['success']) throw new \Exception($response['message']);
24
  else $image = $response['data'];
25
 
26
  $image = apply_filters('webpc_imagick_before_saving', $image, $path);
27
+ $response = $this->convertToWebp($image, $path, $settings);
28
  if (!$response['success']) throw new \Exception($response['message']);
29
  else return [
30
  'success' => true,
31
  'data' => $response['data'],
32
  ];
33
  } catch (\Exception $e) {
34
+ if (in_array('debug_enabled', $settings['features'])) {
35
+ error_log(sprintf('WebP Converter for Media: %s', $e->getMessage()));
36
+ }
37
+
38
  return [
39
  'success' => false,
40
  'message' => $e->getMessage(),
44
 
45
  private function createImage($path)
46
  {
47
+ $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
48
  try {
49
  if (!extension_loaded('imagick') || !class_exists('Imagick')) {
50
  throw new \Exception('Server configuration: Imagick module is not available with this PHP installation.');
67
  }
68
  }
69
 
70
+ private function convertToWebp($image, $path, $settings)
71
  {
72
  try {
73
+ $output = (new Directory())->getPath($path, true);
 
74
  if (!$output) {
75
  throw new \Exception(sprintf('An error occurred creating destination directory for "%s" file.', $path));
76
  } else if (!in_array('WEBP', $image->queryFormats())) {
78
  }
79
 
80
  $image->setImageFormat('WEBP');
81
+ if (!in_array('keep_metadata', $settings['features'])) {
82
+ $image->stripImage();
83
+ }
84
+ $image->setImageCompressionQuality($settings['quality']);
85
  $blob = $image->getImageBlob();
86
 
87
  $success = file_put_contents($output, $blob);
88
  if (!$success) {
89
  throw new \Exception('Error occurred while converting image.');
90
  }
91
+ do_action('webpc_convert_after', $output, $path);
92
 
93
  return [
94
  'success' => true,
95
  'data' => [
 
96
  'size' => [
97
  'before' => filesize($path),
98
+ 'after' => filesize((file_exists($output)) ? $output : $path),
99
  ],
100
  ],
101
  ];
app/Plugin/Activation.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\Action\Cron;
6
+ use WebpConverter\Admin\Notice;
7
+ use WebpConverter\Media\Htaccess;
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_uploads_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(Htaccess::ACTION_NAME, true);
54
+ flush_rewrite_rules(true);
55
+ }
56
+ }
app/Plugin/Deactivation.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\Action\Cron;
6
+ use WebpConverter\Media\Htaccess;
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(Htaccess::ACTION_NAME, false);
23
+ flush_rewrite_rules(true);
24
+ }
25
+
26
+ public function resetCronEvent()
27
+ {
28
+ wp_clear_scheduled_hook(Cron::CRON_ACTION);
29
+ }
30
+ }
app/{Admin → Plugin}/Uninstall.php RENAMED
@@ -1,12 +1,15 @@
1
  <?php
2
 
3
- namespace WebpConverter\Admin;
 
 
 
4
 
5
  class Uninstall
6
  {
7
  public function __construct()
8
  {
9
- register_uninstall_hook(WEBPC_FILE, ['WebpConverter\Admin\Uninstall', 'removePluginSettings']);
10
  }
11
 
12
  /* ---
@@ -15,15 +18,24 @@
15
 
16
  public static function removePluginSettings()
17
  {
18
- delete_option('webpc_settings');
19
- delete_option('webpc_notice_hidden');
 
 
20
 
 
21
  self::removeWebpFiles();
22
  }
23
 
 
 
 
 
 
 
24
  public static function removeWebpFiles()
25
  {
26
- $path = ABSPATH . apply_filters('webpc_uploads_webp', 'wp-content/uploads-webpc');
27
  $paths = self::getPathsFromLocation($path);
28
  $paths[] = $path;
29
  self::removeFiles($paths);
1
  <?php
2
 
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\Admin\Notice;
6
+ use WebpConverter\Settings\Save;
7
 
8
  class Uninstall
9
  {
10
  public function __construct()
11
  {
12
+ register_uninstall_hook(WEBPC_FILE, ['WebpConverter\Plugin\Uninstall', 'removePluginSettings']);
13
  }
14
 
15
  /* ---
18
 
19
  public static function removePluginSettings()
20
  {
21
+ delete_option(Activation::NEW_INSTALLATION_OPTION);
22
+ delete_option(Save::SETTINGS_OPTION);
23
+ delete_option(Notice::NOTICE_THANKS_OPTION);
24
+ delete_option(Update::VERSION_OPTION);
25
 
26
+ self::removeHtaccessFile();
27
  self::removeWebpFiles();
28
  }
29
 
30
+ private static function removeHtaccessFile()
31
+ {
32
+ $path = sprintf('%s/.htaccess', apply_filters('webpc_uploads_webp', ''));
33
+ if (is_writable($path)) unlink($path);
34
+ }
35
+
36
  public static function removeWebpFiles()
37
  {
38
+ $path = apply_filters('webpc_uploads_webp', '');
39
  $paths = self::getPathsFromLocation($path);
40
  $paths[] = $path;
41
  self::removeFiles($paths);
app/Plugin/Update.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WebpConverter\Plugin;
4
+
5
+ use WebpConverter\Media\Htaccess;
6
+ use WebpConverter\Settings\Save;
7
+
8
+ class Update
9
+ {
10
+ const VERSION_OPTION = 'webpc_latest_version';
11
+
12
+ public function __construct()
13
+ {
14
+ add_action('admin_init', [$this, 'runActionsAfterUpdate']);
15
+ }
16
+
17
+ /* ---
18
+ Functions
19
+ --- */
20
+
21
+ public function runActionsAfterUpdate()
22
+ {
23
+ $version = get_option(self::VERSION_OPTION, null);
24
+ if ($version === WEBPC_VERSION) return;
25
+
26
+ if ($version !== null) {
27
+ update_option(Save::SETTINGS_OPTION, $this->updateSettingsForOldVersions($version));
28
+ $this->moveFilesToUploadsSubdirectory(self::VERSION_OPTION);
29
+
30
+ update_option(Activation::NEW_INSTALLATION_OPTION, '0');
31
+ remove_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
32
+ }
33
+
34
+ do_action(Htaccess::ACTION_NAME, true);
35
+ flush_rewrite_rules(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
+ $settings['features'] = array_unique($settings['features']);
56
+ return $settings;
57
+ }
58
+
59
+ private function moveFilesToUploadsSubdirectory($version)
60
+ {
61
+ if (version_compare($version, '1.2.7', '>')) return;
62
+
63
+ $webpRoot = apply_filters('webpc_uploads_webp', '');
64
+ if (!is_writable($webpRoot)) return;
65
+
66
+ $pathParts = explode('/', apply_filters('webpc_uploads_dir', ''));
67
+ $oldPaths = scandir(apply_filters('webpc_uploads_webp', ''));
68
+ for ($i = 1; $i <= count($pathParts); $i++) {
69
+ $dirPath = $webpRoot . '/' . implode('/', array_slice($pathParts, 0, $i));
70
+ if (!file_exists($dirPath)) mkdir($dirPath);
71
+ }
72
+
73
+ foreach ($oldPaths as $path) {
74
+ if (in_array($path, ['.', '..', '.htaccess', $pathParts[0]])) continue;
75
+ rename($webpRoot . '/'. $path, $dirPath . '/'. $path);
76
+ }
77
+ }
78
+ }
app/Plugin/_Core.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 CHANGED
@@ -2,11 +2,10 @@
2
 
3
  namespace WebpConverter\Regenerate;
4
 
5
- use WebpConverter\Convert as Convert;
6
-
7
  class Endpoints
8
  {
9
- public $namespace = 'webp-converter/v1';
 
10
 
11
  public function __construct()
12
  {
@@ -22,7 +21,7 @@
22
  public function restApiEndpoints()
23
  {
24
  register_rest_route(
25
- $this->namespace,
26
  'paths',
27
  [
28
  'methods' => \WP_REST_Server::ALLMETHODS,
@@ -31,12 +30,21 @@
31
  && current_user_can('manage_options'));
32
  },
33
  'callback' => [$this, 'getPaths'],
34
- 'args' => [],
 
 
 
 
 
 
 
 
 
35
  ]
36
  );
37
 
38
  register_rest_route(
39
- $this->namespace,
40
  'regenerate',
41
  [
42
  'methods' => \WP_REST_Server::ALLMETHODS,
@@ -61,11 +69,10 @@
61
 
62
  public function getPaths($request)
63
  {
64
- $params = $request->get_params();
65
- if (isset($params['skip']) && $params['skip']) new Skip();
66
 
67
- $api = new Paths();
68
- $data = $api->getPaths();
69
  if ($data !== false) return new \WP_REST_Response($data, 200);
70
  else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
71
  }
@@ -73,8 +80,7 @@
73
  public function convertImages($request)
74
  {
75
  $params = $request->get_params();
76
- $api = new Regenerate();
77
- $data = $api->convertImages($params['paths']);
78
  if ($data !== false) return new \WP_REST_Response($data, 200);
79
  else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
80
  }
@@ -82,14 +88,14 @@
82
  public function showApiPathsUrl()
83
  {
84
  $nonce = wp_create_nonce('wp_rest');
85
- $url = get_rest_url(null, $this->namespace . '/paths?_wpnonce=' . $nonce);
86
  return $url;
87
  }
88
 
89
  public function showApiRegenerateUrl()
90
  {
91
  $nonce = wp_create_nonce('wp_rest');
92
- $url = get_rest_url(null, $this->namespace . '/regenerate?_wpnonce=' . $nonce);
93
  return $url;
94
  }
95
  }
2
 
3
  namespace WebpConverter\Regenerate;
4
 
 
 
5
  class Endpoints
6
  {
7
+ const ROUTE_NAMESPACE = 'webp-converter/v1';
8
+ const PATHS_PER_REQUEST = 10;
9
 
10
  public function __construct()
11
  {
21
  public function restApiEndpoints()
22
  {
23
  register_rest_route(
24
+ self::ROUTE_NAMESPACE,
25
  'paths',
26
  [
27
  'methods' => \WP_REST_Server::ALLMETHODS,
30
  && current_user_can('manage_options'));
31
  },
32
  'callback' => [$this, 'getPaths'],
33
+ 'args' => [
34
+ 'regenerate_force' => [
35
+ 'description' => 'Option to force all images to be converted again (set `1` to enable)',
36
+ 'required' => false,
37
+ 'default' => false,
38
+ 'sanitize_callback' => function($value, $request, $param) {
39
+ return ($value === '1') ? true : false;
40
+ }
41
+ ],
42
+ ],
43
  ]
44
  );
45
 
46
  register_rest_route(
47
+ self::ROUTE_NAMESPACE,
48
  'regenerate',
49
  [
50
  'methods' => \WP_REST_Server::ALLMETHODS,
69
 
70
  public function getPaths($request)
71
  {
72
+ $params = $request->get_params();
73
+ $skipExists = (!$params['regenerate_force']) ? true : false;
74
 
75
+ $data = (new Paths())->getPaths($skipExists, self::PATHS_PER_REQUEST);
 
76
  if ($data !== false) return new \WP_REST_Response($data, 200);
77
  else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
78
  }
80
  public function convertImages($request)
81
  {
82
  $params = $request->get_params();
83
+ $data = (new Regenerate())->convertImages($params['paths']);
 
84
  if ($data !== false) return new \WP_REST_Response($data, 200);
85
  else return new \WP_Error('webpc_rest_api_error', null, ['status' => 405]);
86
  }
88
  public function showApiPathsUrl()
89
  {
90
  $nonce = wp_create_nonce('wp_rest');
91
+ $url = get_rest_url(null, self::ROUTE_NAMESPACE . '/paths?_wpnonce=' . $nonce);
92
  return $url;
93
  }
94
 
95
  public function showApiRegenerateUrl()
96
  {
97
  $nonce = wp_create_nonce('wp_rest');
98
+ $url = get_rest_url(null, self::ROUTE_NAMESPACE . '/regenerate?_wpnonce=' . $nonce);
99
  return $url;
100
  }
101
  }
app/Regenerate/Paths.php CHANGED
@@ -8,56 +8,20 @@
8
  Functions
9
  --- */
10
 
11
- public function getPaths()
12
- {
13
- $sizes = get_intermediate_image_sizes();
14
- $posts = get_posts([
15
- 'post_type' => 'attachment',
16
- 'post_mime_type' => 'image',
17
- 'post_status' => 'any',
18
- 'posts_per_page' => -1,
19
- 'fields' => 'ids',
20
- ]);
21
-
22
- $list = $this->parseImages($posts, $sizes);
23
- wp_send_json_success($list);
24
- }
25
-
26
- private function parseImages($posts, $sizes)
27
  {
28
  $settings = apply_filters('webpc_get_values', []);
29
- $upload = wp_upload_dir();
30
- $list = [];
31
- if (!$posts) return $list;
32
 
33
- foreach ($posts as $postId) {
34
- $metadata = wp_get_attachment_metadata($postId);
35
- if (!isset($metadata['file'])
36
- || !in_array(pathinfo($metadata['file'], PATHINFO_EXTENSION), $settings['extensions'])) continue;
37
-
38
- $paths = $this->parseImageSizes($postId, $metadata['file'], $sizes, $upload);
39
- $paths = apply_filters('webpc_attachment_paths', $paths, $postId);
40
-
41
- if (!$paths) continue;
42
- $list[] = $paths;
43
- }
44
-
45
- $list = array_filter($list);
46
- return $list;
47
- }
48
-
49
- private function parseImageSizes($postId, $path, $sizes, $upload)
50
- {
51
  $list = [];
52
- $list['_source'] = str_replace('\\', '/', implode('/', [$upload['basedir'], $path]));
53
- foreach ($sizes as $size) {
54
- $src = wp_get_attachment_image_src($postId, $size);
55
- $url = str_replace($upload['baseurl'], $upload['basedir'], $src[0]);
56
- $url = str_replace('\\', '/', $url);
57
-
58
- if (in_array($url, $list)) continue;
59
- $list[$size] = $url;
60
  }
61
- return $list;
 
 
62
  }
63
  }
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 CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace WebpConverter\Regenerate;
4
 
5
- use WebpConverter\Convert as Convert;
6
 
7
  class Regenerate
8
  {
@@ -17,13 +17,12 @@
17
  $sizeBefore = 0;
18
  $sizeAfter = 0;
19
 
20
- if ($settings['method'] === 'gd') $convert = new Convert\Gd();
21
- else if ($settings['method'] === 'imagick') $convert = new Convert\Imagick();
22
  if (!isset($convert)) return false;
23
 
24
  foreach ($paths as $path) {
25
- $response = $convert->convertImage($path, $settings['quality']);
26
- if ($response['success'] && !$this->checkFileSize($response['data'])) continue;
27
 
28
  if ($response['success'] !== true) {
29
  $errors[] = $response['message'];
@@ -41,11 +40,4 @@
41
  ],
42
  ];
43
  }
44
-
45
- private function checkFileSize($data)
46
- {
47
- if ($data['size']['after'] < $data['size']['before']) return true;
48
- unlink($data['path']);
49
- return false;
50
- }
51
  }
2
 
3
  namespace WebpConverter\Regenerate;
4
 
5
+ use WebpConverter\Method;
6
 
7
  class Regenerate
8
  {
17
  $sizeBefore = 0;
18
  $sizeAfter = 0;
19
 
20
+ if ($settings['method'] === 'gd') $convert = new Method\Gd();
21
+ else if ($settings['method'] === 'imagick') $convert = new Method\Imagick();
22
  if (!isset($convert)) return false;
23
 
24
  foreach ($paths as $path) {
25
+ $response = $convert->convertImage($path, $settings);
 
26
 
27
  if ($response['success'] !== true) {
28
  $errors[] = $response['message'];
40
  ],
41
  ];
42
  }
 
 
 
 
 
 
 
43
  }
app/Regenerate/Skip.php CHANGED
@@ -8,17 +8,18 @@
8
  {
9
  public function __construct()
10
  {
11
- add_filter('webpc_attachment_paths', [$this, 'skipExistsImages']);
12
  }
13
 
14
  /* ---
15
  Functions
16
  --- */
17
 
18
- public function skipExistsImages($paths)
19
  {
20
- $directory = new Directory();
21
 
 
22
  foreach ($paths as $key => $path) {
23
  $output = $directory->getPath($path, false);
24
  if (file_exists($output)) unset($paths[$key]);
8
  {
9
  public function __construct()
10
  {
11
+ add_filter('webpc_attachment_paths', [$this, 'skipExistsImages'], 10, 2);
12
  }
13
 
14
  /* ---
15
  Functions
16
  --- */
17
 
18
+ public function skipExistsImages($paths, $skipExists = false)
19
  {
20
+ if (!$skipExists) return $paths;
21
 
22
+ $directory = new Directory();
23
  foreach ($paths as $key => $path) {
24
  $output = $directory->getPath($path, false);
25
  if (file_exists($output)) unset($paths[$key]);
app/Regenerate/_Core.php CHANGED
@@ -7,5 +7,6 @@
7
  public function __construct()
8
  {
9
  new Endpoints();
 
10
  }
11
  }
7
  public function __construct()
8
  {
9
  new Endpoints();
10
+ new Skip();
11
  }
12
  }
app/Settings/Errors.php CHANGED
@@ -4,6 +4,9 @@
4
 
5
  class Errors
6
  {
 
 
 
7
  public function __construct()
8
  {
9
  add_filter('webpc_server_errors', [$this, 'getServerErrors']);
@@ -15,38 +18,104 @@
15
 
16
  public function getServerErrors()
17
  {
18
- $list = [
19
- 'path_uploads' => ($this->ifUploadsPathExists() !== true),
20
- 'path_webp' => ($this->ifWebpPathExists() !== true),
21
- 'rest_api' => ($this->ifRestApiEnabled() !== true),
22
- 'methods' => ($this->ifMethodsAvailable() !== true),
23
- ];
24
- return array_keys(array_filter($list));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
27
  private function ifUploadsPathExists()
28
  {
29
- $path = ABSPATH . apply_filters('webpc_uploads_path', '');
30
  return (is_dir($path) && ($path !== ABSPATH));
31
  }
32
 
33
- private function ifWebpPathExists()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  {
35
- $path = ABSPATH . apply_filters('webpc_uploads_webp', '');
36
- return ((is_dir($path) || is_writable(dirname($path))) && ($path !== ABSPATH));
 
37
  }
38
 
39
- private function ifRestApiEnabled()
40
  {
41
  return ((apply_filters('rest_enabled', true) === true)
42
  && (apply_filters('rest_jsonp_enabled', true) === true)
43
  && (apply_filters('rest_authentication_errors', true) === true));
44
  }
45
 
46
- private function ifMethodsAvailable()
 
 
 
 
 
47
  {
48
- $config = apply_filters('webpc_get_values', []);
49
  $methods = apply_filters('webpc_get_methods', []);
50
- return (isset($config['method']) && in_array($config['method'], $methods));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
  }
4
 
5
  class Errors
6
  {
7
+ private $cache = null;
8
+ private $filePath = WEBPC_PATH . '/resources/components/errors/%s.php';
9
+
10
  public function __construct()
11
  {
12
  add_filter('webpc_server_errors', [$this, 'getServerErrors']);
18
 
19
  public function getServerErrors()
20
  {
21
+ if ($this->cache !== null) return $this->cache;
22
+
23
+ $this->cache = $this->loadErrorMessages([
24
+ 'path_uploads_unavailable' => ($this->ifUploadsPathExists() !== true),
25
+ 'path_htaccess_not_writable' => ($this->ifHtaccessIsWriteable() !== true),
26
+ 'path_webp_not_writable' => ($this->ifWebpPathIsWriteable() !== true),
27
+ 'path_webp_duplicated' => ($this->ifPathsAreDifferent() !== true),
28
+ 'rest_api_disabled' => ($this->ifRestApiIsEnabled() !== true),
29
+ 'libs_not_installed' => ($this->ifLibsAreInstalled() !== true),
30
+ 'libs_without_webp_support' => ($this->ifLibsSupportWebp() !== true),
31
+ 'bypassing_apache' => ($this->ifBypassingApacheIsActive() === true),
32
+ 'settings_incorrect' => ($this->ifSettingsAreCorrect() !== true),
33
+ ]);
34
+ return $this->cache;
35
+ }
36
+
37
+ private function loadErrorMessages($errors)
38
+ {
39
+ $list = [];
40
+ foreach ($errors as $error => $status) {
41
+ if ($status !== true) continue;
42
+ ob_start();
43
+ include sprintf($this->filePath, str_replace('_', '-', $error));
44
+ $list[$error] = ob_get_contents();
45
+ ob_end_clean();
46
+ }
47
+ return $list;
48
  }
49
 
50
  private function ifUploadsPathExists()
51
  {
52
+ $path = apply_filters('webpc_uploads_path', '');
53
  return (is_dir($path) && ($path !== ABSPATH));
54
  }
55
 
56
+ private function ifHtaccessIsWriteable()
57
+ {
58
+ $pathDir = apply_filters('webpc_uploads_path', '');
59
+ $pathFile = $pathDir . '/.htaccess';
60
+ if (file_exists($pathFile)) return (is_readable($pathFile) && is_writable($pathFile));
61
+ else return is_writable($pathDir);
62
+ }
63
+
64
+ private function ifWebpPathIsWriteable()
65
+ {
66
+ $path = apply_filters('webpc_uploads_webp', '');
67
+ return (is_dir($path) || is_writable(dirname($path)));
68
+ }
69
+
70
+ private function ifPathsAreDifferent()
71
  {
72
+ $pathUploads = apply_filters('webpc_uploads_path', '');
73
+ $pathWebp = apply_filters('webpc_uploads_webp', '');
74
+ return ($pathUploads !== $pathWebp);
75
  }
76
 
77
+ private function ifRestApiIsEnabled()
78
  {
79
  return ((apply_filters('rest_enabled', true) === true)
80
  && (apply_filters('rest_jsonp_enabled', true) === true)
81
  && (apply_filters('rest_authentication_errors', true) === true));
82
  }
83
 
84
+ private function ifLibsAreInstalled()
85
+ {
86
+ return (extension_loaded('gd') || (extension_loaded('imagick') && class_exists('\Imagick')));
87
+ }
88
+
89
+ private function ifLibsSupportWebp()
90
  {
 
91
  $methods = apply_filters('webpc_get_methods', []);
92
+ return (($this->ifLibsAreInstalled() !== true) || (count($methods) > 0));
93
+ }
94
+
95
+ private function ifBypassingApacheIsActive()
96
+ {
97
+ $ctx = stream_context_create([
98
+ 'http' => [
99
+ 'timeout' => 1,
100
+ ],
101
+ ]);
102
+ $filePng = @file_get_contents(WEBPC_URL . 'public/img/icon-before.png', false, $ctx);
103
+ if ($filePng === false) return false;
104
+
105
+ $filePng2 = @file_get_contents(WEBPC_URL . 'public/img/icon-before.png2', false, $ctx);
106
+ if ($filePng2 === false) return false;
107
+
108
+ return (strlen($filePng) < strlen($filePng2));
109
+ }
110
+
111
+ private function ifSettingsAreCorrect()
112
+ {
113
+ $settings = apply_filters('webpc_get_values', [], true);
114
+ if ((!isset($settings['extensions']) || !$settings['extensions'])
115
+ || (!isset($settings['dirs']) || !$settings['dirs'])
116
+ || (!isset($settings['method']) || !$settings['method'])
117
+ || (!isset($settings['quality']) || !$settings['quality'])) return false;
118
+
119
+ return true;
120
  }
121
  }
app/Settings/Methods.php CHANGED
@@ -4,6 +4,8 @@
4
 
5
  class Methods
6
  {
 
 
7
  public function __construct()
8
  {
9
  add_filter('webpc_get_methods', [$this, 'getAvaiableMethods']);
@@ -15,15 +17,16 @@
15
 
16
  public function getAvaiableMethods()
17
  {
18
- $list = [];
19
 
 
20
  if (extension_loaded('gd') && function_exists('imagewebp')) {
21
- $list[] = 'gd';
22
  }
23
  if (extension_loaded('imagick') && class_exists('\Imagick')) {
24
  $formats = (new \Imagick)->queryformats();
25
- if (in_array('WEBP', $formats)) $list[] = 'imagick';
26
  }
27
- return $list;
28
  }
29
  }
4
 
5
  class Methods
6
  {
7
+ private $cache = null;
8
+
9
  public function __construct()
10
  {
11
  add_filter('webpc_get_methods', [$this, 'getAvaiableMethods']);
17
 
18
  public function getAvaiableMethods()
19
  {
20
+ if ($this->cache !== null) return $this->cache;
21
 
22
+ $this->cache = [];
23
  if (extension_loaded('gd') && function_exists('imagewebp')) {
24
+ $this->cache[] = 'gd';
25
  }
26
  if (extension_loaded('imagick') && class_exists('\Imagick')) {
27
  $formats = (new \Imagick)->queryformats();
28
+ if (in_array('WEBP', $formats)) $this->cache[] = 'imagick';
29
  }
30
+ return $this->cache;
31
  }
32
  }
app/Settings/Options.php CHANGED
@@ -6,21 +6,20 @@
6
  {
7
  public function __construct()
8
  {
9
- add_filter('webpc_get_options', [$this, 'getOptions']);
10
- add_filter('webpc_option_disabled', [$this, 'setDisabledValues'], 10, 2);
11
  }
12
 
13
  /* ---
14
  Functions
15
  --- */
16
 
17
- public function getOptions()
18
  {
19
  return [
20
  [
21
  'name' => 'extensions',
22
  'type' => 'checkbox',
23
- 'label' => __('List of supported files extensions', 'webp-converter'),
24
  'info' => '',
25
  'values' => [
26
  'jpg' => '.jpg',
@@ -28,34 +27,36 @@
28
  'png' => '.png',
29
  'gif' => '.gif',
30
  ],
31
- 'disabled' => apply_filters('webpc_option_disabled', [], 'extensions'),
32
  ],
33
  [
34
- 'name' => 'method',
35
- 'type' => 'radio',
36
- 'label' => __('Conversion method', 'webp-converter'),
37
- 'info' => __('The configuration for advanced users.', 'webp-converter'),
38
  'values' => [
39
- 'gd' => sprintf(__('%s (recommended)', 'webp-converter'), 'GD'),
40
- 'imagick' => 'Imagick',
 
41
  ],
42
- 'disabled' => apply_filters('webpc_option_disabled', [], 'method'),
43
  ],
44
  [
45
- 'name' => 'features',
46
- 'type' => 'checkbox',
47
- 'label' => __('Extra features', 'webp-converter'),
48
- 'info' => __('The options allow you to enable new functionalities that will additionally speed up your website.', 'webp-converter'),
49
  'values' => [
50
- 'mod_expires' => 'Browser Caching for .webp files (saving images in browser cache memory)',
 
51
  ],
52
- 'disabled' => apply_filters('webpc_option_disabled', [], 'features'),
53
  ],
54
  [
55
  'name' => 'quality',
56
  'type' => 'quality',
57
- 'label' => __('Images quality', 'webp-converter'),
58
- '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'),
59
  'values' => [
60
  '75' => '75%',
61
  '80' => '80%',
@@ -64,18 +65,39 @@
64
  '95' => '95%',
65
  '100' => '100%',
66
  ],
67
- 'disabled' => apply_filters('webpc_option_disabled', [], 'quality'),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  ],
69
  ];
70
  }
71
 
72
- public function setDisabledValues($list, $name)
73
  {
74
- switch ($name) {
 
75
  case 'method':
76
  $methods = apply_filters('webpc_get_methods', []);
77
  if (!in_array('gd', $methods)) $list[] = 'gd';
78
  if (!in_array('imagick', $methods)) $list[] = 'imagick';
 
 
 
 
 
79
  }
80
  return $list;
81
  }
6
  {
7
  public function __construct()
8
  {
9
+ add_filter('webpc_get_options', [$this, 'getOptions']);
 
10
  }
11
 
12
  /* ---
13
  Functions
14
  --- */
15
 
16
+ public function getOptions($options)
17
  {
18
  return [
19
  [
20
  'name' => 'extensions',
21
  'type' => 'checkbox',
22
+ 'label' => __('List of supported files extensions', 'webp-converter-for-media'),
23
  'info' => '',
24
  'values' => [
25
  'jpg' => '.jpg',
27
  'png' => '.png',
28
  'gif' => '.gif',
29
  ],
30
+ 'disabled' => $this->getDisabledValues('extensions'),
31
  ],
32
  [
33
+ 'name' => 'dirs',
34
+ 'type' => 'checkbox',
35
+ 'label' => __('List of supported directories', 'webp-converter-for-media'),
36
+ 'info' => __('Files from these directories will be supported in WebP format.', 'webp-converter-for-media'),
37
  'values' => [
38
+ 'plugins' => '/plugins',
39
+ 'themes' => '/themes',
40
+ 'uploads' => '/uploads',
41
  ],
42
+ 'disabled' => $this->getDisabledValues('dirs'),
43
  ],
44
  [
45
+ 'name' => 'method',
46
+ 'type' => 'radio',
47
+ 'label' => __('Conversion method', 'webp-converter-for-media'),
48
+ 'info' => __('The configuration for advanced users.', 'webp-converter-for-media'),
49
  'values' => [
50
+ 'gd' => sprintf(__('%s (recommended)', 'webp-converter-for-media'), 'GD'),
51
+ 'imagick' => 'Imagick',
52
  ],
53
+ 'disabled' => $this->getDisabledValues('method'),
54
  ],
55
  [
56
  'name' => 'quality',
57
  'type' => 'quality',
58
+ 'label' => __('Images quality', 'webp-converter-for-media'),
59
+ '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'),
60
  'values' => [
61
  '75' => '75%',
62
  '80' => '80%',
65
  '95' => '95%',
66
  '100' => '100%',
67
  ],
68
+ 'disabled' => $this->getDisabledValues('quality'),
69
+ ],
70
+ [
71
+ 'name' => 'features',
72
+ 'type' => 'checkbox',
73
+ 'label' => __('Extra features', 'webp-converter-for-media'),
74
+ 'info' => __('Options allow you to enable new functionalities that will increase capabilities of plugin.', 'webp-converter-for-media'),
75
+ 'values' => [
76
+ 'only_smaller' => __('Automatic removal of WebP files larger than original', 'webp-converter-for-media'),
77
+ 'mod_expires' => __('Browser Caching for WebP files (saving images in browser cache memory)', 'webp-converter-for-media'),
78
+ 'keep_metadata' => __('Keep images metadata stored in EXIF or XMP formats (only available for Imagick conversion method)', 'webp-converter-for-media'),
79
+ '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'),
80
+ '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'),
81
+ 'debug_enabled' => __('Log errors while converting to debug.log file (when debugging in WordPress is active)', 'webp-converter-for-media'),
82
+ ],
83
+ 'disabled' => $this->getDisabledValues('features'),
84
  ],
85
  ];
86
  }
87
 
88
+ private function getDisabledValues($optionName)
89
  {
90
+ $list = [];
91
+ switch ($optionName) {
92
  case 'method':
93
  $methods = apply_filters('webpc_get_methods', []);
94
  if (!in_array('gd', $methods)) $list[] = 'gd';
95
  if (!in_array('imagick', $methods)) $list[] = 'imagick';
96
+ break;
97
+ case 'features':
98
+ $settings = apply_filters('webpc_get_values', []);
99
+ if ($settings['method'] !== 'imagick') $list[] = 'keep_metadata';
100
+ break;
101
  }
102
  return $list;
103
  }
app/Settings/Page.php CHANGED
@@ -2,8 +2,13 @@
2
 
3
  namespace WebpConverter\Settings;
4
 
 
 
 
5
  class Page
6
  {
 
 
7
  public function __construct()
8
  {
9
  add_action('admin_menu', [$this, 'addSettingsPage']);
@@ -17,7 +22,7 @@
17
  {
18
  if (is_network_admin()) return;
19
 
20
- add_submenu_page(
21
  'options-general.php',
22
  'WebP Converter for Media',
23
  'WebP Converter',
@@ -25,11 +30,20 @@
25
  'webpc_admin_page',
26
  [$this, 'showSettingsPage']
27
  );
 
28
  }
29
 
30
  public function showSettingsPage()
31
  {
32
  new Save();
33
- require_once WEBPC_PATH . 'resources/views/settings.php';
 
 
 
 
 
 
 
 
34
  }
35
  }
2
 
3
  namespace WebpConverter\Settings;
4
 
5
+ use WebpConverter\Admin\Assets;
6
+ use WebpConverter\Plugin\Activation;
7
+
8
  class Page
9
  {
10
+ private $filePath = WEBPC_PATH . '/resources/views/settings.php';
11
+
12
  public function __construct()
13
  {
14
  add_action('admin_menu', [$this, 'addSettingsPage']);
22
  {
23
  if (is_network_admin()) return;
24
 
25
+ $page = add_submenu_page(
26
  'options-general.php',
27
  'WebP Converter for Media',
28
  'WebP Converter',
30
  'webpc_admin_page',
31
  [$this, 'showSettingsPage']
32
  );
33
+ add_action('load-' . $page, [$this, 'loadScriptsForPage']);
34
  }
35
 
36
  public function showSettingsPage()
37
  {
38
  new Save();
39
+ require_once $this->filePath;
40
+ }
41
+
42
+ public function loadScriptsForPage()
43
+ {
44
+ update_option(Activation::NEW_INSTALLATION_OPTION, '0');
45
+ remove_action('admin_notices', ['WebpConverter\Admin\Notice', 'loadWelcomeNotice']);
46
+
47
+ new Assets();
48
  }
49
  }
app/Settings/Paths.php DELETED
@@ -1,35 +0,0 @@
1
- <?php
2
-
3
- namespace WebpConverter\Settings;
4
-
5
- class Paths
6
- {
7
- private $source = 'wp-content/uploads', $output = 'wp-content/uploads-webpc';
8
-
9
- public function __construct()
10
- {
11
- add_filter('webpc_uploads_path', [$this, 'getSourcePath'], 0);
12
- add_filter('webpc_uploads_webp', [$this, 'getOutputPath'], 0);
13
- add_filter('webpc_uploads_path', [$this, 'parsePath'], 100);
14
- add_filter('webpc_uploads_webp', [$this, 'parsePath'], 100);
15
- }
16
-
17
- /* ---
18
- Functions
19
- --- */
20
-
21
- public function getSourcePath($value)
22
- {
23
- return $this->source;
24
- }
25
-
26
- public function getOutputPath($value)
27
- {
28
- return $this->output;
29
- }
30
-
31
- public function parsePath($value)
32
- {
33
- return trim($value, '\/');
34
- }
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Settings/Save.php CHANGED
@@ -2,8 +2,13 @@
2
 
3
  namespace WebpConverter\Settings;
4
 
 
 
 
5
  class Save
6
  {
 
 
7
  public function __construct()
8
  {
9
  $this->saveConfig();
@@ -19,8 +24,11 @@
19
  || !wp_verify_nonce($_REQUEST['_wpnonce'], 'webpc-save')) return;
20
 
21
  $values = $this->getValues();
22
- $this->saveOption('webpc_settings', $values);
23
- flush_rewrite_rules(true);
 
 
 
24
  }
25
 
26
  private function getValues()
@@ -29,24 +37,18 @@
29
  $values = [];
30
  foreach ($options as $key => $option) {
31
  $name = $option['name'];
32
- $values[$name] = isset($_POST[$name]) ? $_POST[$name] : (($option['type'] === 'checkbox') ? [] : null);
 
 
33
  }
34
- $values = $this->sanitizeValues($values);
35
- return $values;
36
- }
37
 
38
- private function sanitizeValues($values)
39
- {
40
- foreach ($values as $index => $value) {
41
- if (is_array($value)) $values[$index] = array_map('sanitize_text_field', $value);
42
- else $values[$index] = sanitize_text_field($value);
43
- }
44
  return $values;
45
  }
46
 
47
- private function saveOption($key, $value)
48
  {
49
- if (get_option($key, false) !== false) update_option($key, $value);
50
- else add_option($key, $value);
 
51
  }
52
  }
2
 
3
  namespace WebpConverter\Settings;
4
 
5
+ use WebpConverter\Action\Cron;
6
+ use WebpConverter\Media\Htaccess;
7
+
8
  class Save
9
  {
10
+ const SETTINGS_OPTION = 'webpc_settings';
11
+
12
  public function __construct()
13
  {
14
  $this->saveConfig();
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(Htaccess::ACTION_NAME, true);
31
+ wp_clear_scheduled_hook(Cron::CRON_ACTION);
32
  }
33
 
34
  private function getValues()
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 CHANGED
@@ -19,6 +19,7 @@
19
  {
20
  ob_start();
21
 
 
22
  foreach ($this->extensions as $extension) {
23
  $this->getExtensionInfo($extension);
24
  }
@@ -42,4 +43,92 @@
42
  $ext->info();
43
  endif;
44
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
19
  {
20
  ob_start();
21
 
22
+ echo $this->getFiltersInfo();
23
  foreach ($this->extensions as $extension) {
24
  $this->getExtensionInfo($extension);
25
  }
43
  $ext->info();
44
  endif;
45
  }
46
+
47
+ private function getFiltersInfo()
48
+ {
49
+ ob_start();
50
+
51
+ ?>
52
+ <h4>apply_filters</h4>
53
+ <table>
54
+ <tbody>
55
+ <tr>
56
+ <td class="e">webpc_get_values</td>
57
+ <td class="v">
58
+ <?= json_encode(apply_filters('webpc_get_values', [], null)); ?>
59
+ </td>
60
+ </tr>
61
+ <tr>
62
+ <td class="e">webpc_get_methods</td>
63
+ <td class="v">
64
+ <?= implode(' | ', apply_filters('webpc_get_methods', [])); ?>
65
+ </td>
66
+ </tr>
67
+ <tr>
68
+ <td class="e">webpc_uploads_root</td>
69
+ <td class="v">
70
+ <?= apply_filters('webpc_uploads_root', ABSPATH); ?>
71
+ </td>
72
+ </tr>
73
+ <tr>
74
+ <td class="e">webpc_uploads_prefix</td>
75
+ <td class="v">
76
+ <?= apply_filters('webpc_uploads_prefix', '/'); ?>
77
+ </td>
78
+ </tr>
79
+ <tr>
80
+ <td class="e">webpc_uploads_path</td>
81
+ <td class="v">
82
+ <?= apply_filters('webpc_uploads_path', '', false); ?>
83
+ </td>
84
+ </tr>
85
+ <tr>
86
+ <td class="e">webpc_uploads_webp</td>
87
+ <td class="v">
88
+ <?= apply_filters('webpc_uploads_webp', '', false); ?>
89
+ </td>
90
+ </tr>
91
+ <tr>
92
+ <td class="e">webpc_dir_path <em>(plugins)</em></td>
93
+ <td class="v">
94
+ <?= apply_filters('webpc_dir_path', '', 'plugins'); ?>
95
+ </td>
96
+ </tr>
97
+ <tr>
98
+ <td class="e">webpc_dir_path <em>(themes)</em></td>
99
+ <td class="v">
100
+ <?= apply_filters('webpc_dir_path', '', 'themes'); ?>
101
+ </td>
102
+ </tr>
103
+ <tr>
104
+ <td class="e">webpc_dir_path <em>(uploads)</em></td>
105
+ <td class="v">
106
+ <?= apply_filters('webpc_dir_path', '', 'uploads'); ?>
107
+ </td>
108
+ </tr>
109
+ <tr>
110
+ <td class="e">webpc_dir_excluded</td>
111
+ <td class="v">
112
+ <?= implode(' | ', apply_filters('webpc_dir_excluded', [])); ?>
113
+ </td>
114
+ </tr>
115
+ </tbody>
116
+ </table>
117
+ <h4>WordPress</h4>
118
+ <table>
119
+ <tbody>
120
+ <tr>
121
+ <td class="e">ABSPATH</td>
122
+ <td class="v">
123
+ <?= ABSPATH; ?>
124
+ </td>
125
+ </tr>
126
+ </tbody>
127
+ </table>
128
+ <?php
129
+
130
+ $content = ob_get_contents();
131
+ ob_end_clean();
132
+ return $content;
133
+ }
134
  }
app/Settings/Values.php CHANGED
@@ -4,29 +4,29 @@
4
 
5
  class Values
6
  {
7
- private $config;
8
 
9
  public function __construct()
10
  {
11
- add_filter('webpc_get_values', [$this, 'getValues']);
12
  }
13
 
14
  /* ---
15
  Functions
16
  --- */
17
 
18
- public function getValues()
19
  {
20
- if ($this->config) return $this->config;
21
 
22
- $methods = apply_filters('webpc_get_methods', []);
23
- $value = get_option('webpc_settings', [
24
  'extensions' => ['jpg', 'jpeg', 'png'],
 
25
  'method' => ($methods) ? $methods[0] : '',
26
- 'features' => ['mod_expires'],
27
  'quality' => 85,
28
  ]);
29
- $this->config = $value;
30
- return $value;
31
  }
32
  }
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
  'extensions' => ['jpg', 'jpeg', 'png'],
25
+ 'dirs' => ['uploads'],
26
  'method' => ($methods) ? $methods[0] : '',
27
+ 'features' => ['only_smaller', 'mod_expires', 'debug_enabled'],
28
  'quality' => 85,
29
  ]);
30
+ return $this->cache;
 
31
  }
32
  }
app/Settings/_Core.php CHANGED
@@ -10,7 +10,6 @@
10
  new Methods();
11
  new Options();
12
  new Page();
13
- new Paths();
14
  new Server();
15
  new Values();
16
  }
10
  new Methods();
11
  new Options();
12
  new Page();
 
13
  new Server();
14
  new Values();
15
  }
app/WebpConverter.php CHANGED
@@ -6,8 +6,11 @@
6
  {
7
  public function __construct()
8
  {
 
9
  new Admin\_Core();
 
10
  new Media\_Core();
 
11
  new Regenerate\_Core();
12
  new Settings\_Core();
13
  }
6
  {
7
  public function __construct()
8
  {
9
+ new Action\_Core();
10
  new Admin\_Core();
11
+ new Convert\_Core();
12
  new Media\_Core();
13
+ new Plugin\_Core();
14
  new Regenerate\_Core();
15
  new Settings\_Core();
16
  }
public/build/css/styles.css CHANGED
@@ -1 +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"}.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__headline{padding:32px 0;font-weight:400;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__widgetTable{width:100%;margin:5px 0;border-spacing:0}.webpPage__widgetTable td{padding:5px 0;vertical-align:top}.webpPage__widgetTable td:first-child{width:22px;padding-right:30px}.webpPage__widgetRow{padding-bottom:10px}.webpPage__widgetRow:last-child{padding-bottom:0}.webpPage__widgetRow .webpButton{margin:10px 0}.webpPage__checkbox{display:none!important}.webpPage__checkbox[type=checkbox]+label:after{content:"\F147"}.webpPage__checkbox[type=radio]+label:after{content:"\F335"}.webpPage__checkbox+label{position:relative;display:inline-block}.webpPage__checkbox+label:after,.webpPage__checkbox+label:before{content:"";display:flex;align-items:center;justify-content:center;width:22px;height:22px}.webpPage__checkbox+label:before{border:1px solid #b4b9be}.webpPage__checkbox+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}.webpPage__checkbox[disabled]+label{opacity:.25;pointer-events:none}.webpPage__checkbox:checked+label:after{transform:scale(1)}.webpPage__checkboxLabel{display:inline-block;max-width:600px;font-size:14px;line-height:1.64}.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}.webpContent{font-family:Exo\ 2,sans-serif;padding:20px 30px}.webpContent p{max-width:800px;font-size:14px;line-height:1.64}.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--lastCenter>p:last-child{text-align:center}.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{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{margin-top:20px;padding:4px 0 4px 20px;font-weight:500;font-size:14px;line-height:1.64;color:#46b450;border-left:2px solid #46b450}.webpLoader__errors{margin-top:20px;border-left:2px solid #dc3232}.webpLoader__errorsTitle{display:inline-block;padding:4px 22px;font-size:14px;line-height:1.64;color:#fff;background-color:#dc3232}.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}.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}@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){.webpPage{padding-right:10px}}@media screen and (max-width:768px){.webpPage__quality{display:block}.webpPage__qualityItem{border-left:0}.webpPage__qualityItem+.webpPage__qualityItem{border-top:1px solid #a0a5aa}}
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"}.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__widgetTable{width:100%;margin:5px 0;border-spacing:0}.webpPage__widgetTable td{padding:5px 0;vertical-align:top}.webpPage__widgetTable td:first-child{width:22px;padding-right:30px}.webpPage__widgetRow{padding-bottom:10px}.webpPage__widgetRow:last-child{padding-bottom:0}.webpPage__widgetRow .webpButton{margin:10px 0}.webpPage__checkbox{display:none!important}.webpPage__checkbox[type=checkbox]+label:after{content:"\F147"}.webpPage__checkbox[type=radio]+label:after{content:"\F335"}.webpPage__checkbox+label{position:relative;display:inline-block}.webpPage__checkbox+label:after,.webpPage__checkbox+label:before{content:"";display:flex;align-items:center;justify-content:center;width:22px;height:22px}.webpPage__checkbox+label:before{border:1px solid #b4b9be}.webpPage__checkbox+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}.webpPage__checkbox[disabled]+label{opacity:.25;pointer-events:none}.webpPage__checkbox:checked+label:after{transform:scale(1)}.webpPage__checkboxLabel{display:inline-block;max-width:650px;font-size:14px;line-height:1.64}.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}.webpContent{font-family:Exo\ 2,sans-serif;padding:20px 30px}.webpContent p{max-width:800px;font-size:14px;line-height:1.64}.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--lastCenter>p:last-child{text-align:center}.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{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{margin-top:20px;padding:4px 0 4px 20px;font-weight:500;font-size:14px;line-height:1.64;color:#46b450;border-left:2px solid #46b450}.webpLoader__success a{color:inherit}.webpLoader__errors{margin-top:20px;border-left:2px solid #dc3232}.webpLoader__errorsTitle{display:inline-block;padding:4px 22px;font-size:14px;line-height:1.64;color:#fff;background-color:#dc3232}.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}.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}@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){.webpPage{padding-right:10px}}@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/build/js/scripts.js CHANGED
@@ -1 +1 @@
1
- !function(e){var t={};function r(s){if(t[s])return t[s].exports;var i=t[s]={i:s,l:!1,exports:{}};return e[s].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=e,r.c=t,r.d=function(e,t,s){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(r.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(s,i,function(t){return e[t]}.bind(null,i));return s},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/",r(r.s=0)}([function(e,t,r){r(1),e.exports=r(2)},function(e,t,r){"use strict";function s(e,t){for(var r=0;r<t.length;r++){var s=t[r];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(e,s.key,s)}}r.r(t);var i=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.setVars()&&this.setEvents()}var t,r,i;return t=e,(r=[{key:"setVars",value:function(){if(this.notice=document.querySelector(".notice[data-notice=webp-converter]"),this.notice)return this.settings={isHidden:!1,ajaxUrl:this.notice.getAttribute("data-url")},!0}},{key:"setEvents",value:function(){window.addEventListener("load",this.getButtons.bind(this))}},{key:"getButtons",value:function(){this.buttonClose=this.notice.querySelector(".notice-dismiss"),this.buttonPermanently=this.notice.querySelector("[data-permanently]"),this.setButtonsEvents()}},{key:"setButtonsEvents",value:function(){var e=this;this.buttonClose.addEventListener("click",(function(){e.hideNotice(!1)})),this.buttonPermanently.addEventListener("click",(function(t){t.preventDefault(),e.hideNotice(!0)}))}},{key:"hideNotice",value:function(e){this.settings.isHidden||(this.settings.isHidden=!0,jQuery.ajax(this.settings.ajaxUrl,{type:"POST",data:{is_permanently:e?1:0}}),this.buttonClose.click())}}])&&s(t.prototype,r),i&&s(t,i),e}();function n(e,t){for(var r=0;r<t.length;r++){var s=t[r];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(e,s.key,s)}}var a=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.setVars()&&this.setEvents()}var t,r,s;return t=e,(r=[{key:"setVars",value:function(){if(this.section=document.querySelector(".webpLoader"),this.section)return this.wrapper=this.section.querySelector(".webpLoader__status"),this.progress=this.wrapper.querySelector(".webpLoader__barProgress"),this.progressSize=this.section.querySelector(".webpLoader__sizeProgress"),this.errors=this.section.querySelector(".webpLoader__errors"),this.errorsInner=this.errors.querySelector(".webpLoader__errorsContentList"),this.errorsMessage=this.errors.querySelector(".webpLoader__errorsContentMessage"),this.success=this.section.querySelector(".webpLoader__success"),this.skipOption=this.section.querySelector('input[name="regenerate_skip"]'),this.button=this.section.querySelector(".webpLoader__button"),this.data={count:0,max:0,items:[],size:{before:0,after:0},errors:[]},this.settings={isDisabled:!1,ajax:{urlPaths:this.section.getAttribute("data-api-paths"),urlRegenerate:this.section.getAttribute("data-api-regenerate"),errorMessage:this.section.getAttribute("data-api-error-message")},units:["kB","MB","GB"]},this.atts={progress:"data-percent"},this.classes={progressError:"webpLoader__barProgress--error",buttonDisabled:"webpLoader__button--disabled"},!0}},{key:"setEvents",value:function(){this.button.addEventListener("click",this.initRegenerate.bind(this))}},{key:"initRegenerate",value:function(e){e.preventDefault(),this.settings.isDisabled||(this.settings.isDisabled=!0,this.skipOption.setAttribute("disabled",!0),this.button.classList.add(this.classes.buttonDisabled),this.wrapper.removeAttribute("hidden"),this.getImagesList())}},{key:"getImagesList",value:function(){var e=this;jQuery.ajax(this.settings.ajax.urlPaths,{type:"POST",data:{skip:this.skipOption.checked?1:0}}).done((function(t){e.data.items=t.data,e.data.max=t.data.length,e.regenerateNextImages()})).fail((function(){e.progress.classList.add(e.classes.progressError),e.errorsMessage.removeAttribute("hidden"),e.errors.removeAttribute("hidden")}))}},{key:"regenerateNextImages",value:function(){if(0===this.data.max&&this.updateProgress(),!(this.data.count>=this.data.max)){var e=this.data.items[this.data.count];this.data.count++,this.sendRequest(e)}}},{key:"sendRequest",value:function(e){var t=this;jQuery.ajax(this.settings.ajax.urlRegenerate,{type:"POST",data:{paths:e}}).done((function(e){t.updateErrors(e.errors),t.updateSize(e),t.updateProgress(),t.regenerateNextImages()})).fail((function(){var r=JSON.stringify(e),s=t.settings.ajax.errorMessage.replace("%s","<code>".concat(r,"</code>"));t.updateErrors([s]),t.regenerateNextImages()}))}},{key:"updateErrors",value:function(e){0!==e.length&&(this.data.errors=this.data.errors.concat(e),this.errorsInner.innerHTML=this.data.errors.join("<br>"),this.errors.removeAttribute("hidden"))}},{key:"updateSize",value:function(e){var t=this.data.size;t.before+=e.size.before,t.after+=e.size.after;var r=t.before-t.after;if(r<0&&(r=0),0!==r){var s=Math.round(100*(1-t.after/t.before));s<0&&(s=0);var i=-1;do{i++,r/=1024}while(r>1024);var n=r.toFixed(2),a=this.settings.units[i],o="".concat(n," ").concat(a," (").concat(s,"%)");this.progressSize.innerHTML=o}}},{key:"updateProgress",value:function(){var e=this.data.max>0?Math.floor(this.data.count/this.data.max*100):100;e>100&&(e=100),100===e&&this.success.removeAttribute("hidden"),this.progress.setAttribute(this.atts.progress,e)}}])&&n(t.prototype,r),s&&n(t,s),e}();new function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),new i,new a}},function(e,t){}]);
1
+ !function(e){var t={};function r(s){if(t[s])return t[s].exports;var i=t[s]={i:s,l:!1,exports:{}};return e[s].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=e,r.c=t,r.d=function(e,t,s){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(r.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(s,i,function(t){return e[t]}.bind(null,i));return s},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/",r(r.s=0)}([function(e,t,r){r(1),e.exports=r(2)},function(e,t,r){"use strict";function s(e,t){for(var r=0;r<t.length;r++){var s=t[r];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(e,s.key,s)}}r.r(t);var i=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.setVars()&&this.setEvents()}var t,r,i;return t=e,(r=[{key:"setVars",value:function(){if(this.notice=document.querySelector(".notice[data-notice=webp-converter]"),this.notice)return this.settings={isHidden:!1,ajaxUrl:this.notice.getAttribute("data-url")},!0}},{key:"setEvents",value:function(){window.addEventListener("load",this.getButtons.bind(this))}},{key:"getButtons",value:function(){this.buttonClose=this.notice.querySelector(".notice-dismiss"),this.buttonPermanently=this.notice.querySelector("[data-permanently]"),this.setButtonsEvents()}},{key:"setButtonsEvents",value:function(){var e=this;this.buttonClose.addEventListener("click",(function(){e.hideNotice(!1)})),this.buttonPermanently.addEventListener("click",(function(t){t.preventDefault(),e.hideNotice(!0)}))}},{key:"hideNotice",value:function(e){this.settings.isHidden||(this.settings.isHidden=!0,jQuery.ajax(this.settings.ajaxUrl,{type:"POST",data:{action:"webpc_notice",is_permanently:e?1:0}}),this.buttonClose.click())}}])&&s(t.prototype,r),i&&s(t,i),e}();function n(e,t){for(var r=0;r<t.length;r++){var s=t[r];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(e,s.key,s)}}var a=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.setVars()&&this.setEvents()}var t,r,s;return t=e,(r=[{key:"setVars",value:function(){if(this.section=document.querySelector(".webpLoader"),this.section)return this.wrapper=this.section.querySelector(".webpLoader__status"),this.progress=this.wrapper.querySelector(".webpLoader__barProgress"),this.progressSize=this.section.querySelector(".webpLoader__sizeProgress"),this.errors=this.section.querySelector(".webpLoader__errors"),this.errorsInner=this.errors.querySelector(".webpLoader__errorsContentList"),this.errorsMessage=this.errors.querySelector(".webpLoader__errorsContentMessage"),this.success=this.section.querySelector(".webpLoader__success"),this.inputOptions=this.section.querySelectorAll('input[type="checkbox"]'),this.button=this.section.querySelector(".webpLoader__button"),this.data={count:0,max:0,items:[],size:{before:0,after:0},errors:[]},this.settings={isDisabled:!1,ajax:{urlPaths:this.section.getAttribute("data-api-paths"),urlRegenerate:this.section.getAttribute("data-api-regenerate"),errorMessage:this.section.getAttribute("data-api-error-message")},units:["kB","MB","GB"]},this.atts={progress:"data-percent"},this.classes={progressError:"webpLoader__barProgress--error",buttonDisabled:"webpLoader__button--disabled"},!0}},{key:"setEvents",value:function(){this.button.addEventListener("click",this.initRegenerate.bind(this))}},{key:"initRegenerate",value:function(e){if(e.preventDefault(),!this.settings.isDisabled){this.settings.isDisabled=!0,this.button.classList.add(this.classes.buttonDisabled);for(var t=this.inputOptions.length,r=0;r<t;r++)this.inputOptions[r].setAttribute("disabled",!0);this.wrapper.removeAttribute("hidden"),this.getImagesList()}}},{key:"getImagesList",value:function(){var e=this;jQuery.ajax(this.settings.ajax.urlPaths,{type:"POST",data:this.getDataForPathsRequest()}).done((function(t){e.data.items=t,e.data.max=t.length,e.regenerateNextImages()})).fail((function(){e.progress.classList.add(e.classes.progressError),e.errorsMessage.removeAttribute("hidden"),e.errors.removeAttribute("hidden")}))}},{key:"getDataForPathsRequest",value:function(){for(var e={},t=this.inputOptions.length,r=0;r<t;r++)e[this.inputOptions[r].getAttribute("name")]=this.inputOptions[r].checked?1:0;return e}},{key:"regenerateNextImages",value:function(){if(0===this.data.max&&this.updateProgress(),!(this.data.count>=this.data.max)){var e=this.data.items[this.data.count];this.data.count++,this.sendRequest(e)}}},{key:"sendRequest",value:function(e){var t=this;jQuery.ajax(this.settings.ajax.urlRegenerate,{type:"POST",data:{paths:e}}).done((function(e){t.updateErrors(e.errors),t.updateSize(e),t.updateProgress(),t.regenerateNextImages()})).fail((function(){var r=JSON.stringify(e),s=t.settings.ajax.errorMessage.replace("%s","<code>".concat(r,"</code>"));t.updateErrors([s]),t.regenerateNextImages()}))}},{key:"updateErrors",value:function(e){0!==e.length&&(this.data.errors=this.data.errors.concat(e),this.errorsInner.innerHTML=this.data.errors.join("<br>"),this.errors.removeAttribute("hidden"))}},{key:"updateSize",value:function(e){var t=this.data.size;t.before+=e.size.before,t.after+=e.size.after;var r=t.before-t.after;if(r<0&&(r=0),0!==r){var s=Math.round(100*(1-t.after/t.before));s<0&&(s=0);var i=-1;do{i++,r/=1024}while(r>1024);var n=r.toFixed(2),a=this.settings.units[i],o="".concat(n," ").concat(a," (").concat(s,"%)");this.progressSize.innerHTML=o}}},{key:"updateProgress",value:function(){var e=this.data.max>0?Math.floor(this.data.count/this.data.max*100):100;e>100&&(e=100),100===e&&this.success.removeAttribute("hidden"),this.progress.setAttribute(this.atts.progress,e)}}])&&n(t.prototype,r),s&&n(t,s),e}();new function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),new i,new a}},function(e,t){}]);
public/img/.htaccess ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # BEGIN WebP Converter
2
+ <IfModule mod_rewrite.c>
3
+ RewriteEngine On
4
+ RewriteRule icon-before\.(.+)$ ./icon-after.$1 [NC,E=cache-control:private,L]
5
+ </IfModule>
6
+ # END WebP Converter
public/img/icon-after.png ADDED
Binary file
public/img/icon-after.png2 ADDED
Binary file
public/img/icon-before.png ADDED
Binary file
public/img/icon-before.png2 ADDED
Binary file
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === WebP Converter for Media ===
2
  Contributors: mateuszgbiorczyk
3
  Donate link: https://ko-fi.com/gbiorczyk/
4
- Tags: webp, images, performance, compress, optimize
5
  Requires at least: 5.0
6
- Tested up to: 5.3
7
  Requires PHP: 7.0
8
  Stable tag: trunk
9
  License: GPLv2 or later
@@ -21,26 +21,43 @@ As of today, nearly 80% of users use browsers that support the WebP format. The
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
  #### How does this work?
25
 
26
- - By adding images to your media library, they are automatically converted and saved in a separate directory.
27
  - If you have just installed the plugin, you can convert all existing images with one click.
 
28
  - Images are converted using PHP `GD` or `Imagick` extension *(you can modify the compression level)*.
29
  - When the browser tries to download an image file, the server verifies if it supports `image/webp` files and if the file exists.
30
  - If everything is OK, instead of the original image, the browser will receive its equivalent in WebP format.
31
  - **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!
 
32
  - 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`.
 
33
  - The final result is that your users download less than half of the data, and the website itself loads faster!
34
 
 
 
 
 
35
  #### WebP images are the future!
36
 
37
  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.
38
 
 
 
 
 
 
 
39
  #### Please also read the FAQ below. Thank you for being with us!
40
 
41
  == Installation ==
42
 
43
- 1. Upload the plugin files to `/wp-content/plugins/webp-converter-for-media/` directory, or install plugin through the WordPress plugins screen directly.
44
  2. Activate plugin through `Plugins` screen in WordPress Admin Panel.
45
  3. Use `Settings -> Settings -> WebP Converter` screen to configure the plugin.
46
  4. Click on the button `Regenerate All`.
@@ -52,23 +69,19 @@ That's all! Your website is already loading faster!
52
 
53
  = How to get technical support? (before you ask for help) =
54
 
55
- We are happy to help you with any problem. Contact us about this matter.
56
-
57
  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.
58
 
59
- This will save time repeating the same issues many times and solving the same problems.
60
-
61
- If you do not find anything and you still have a problem, then contact us. So that we can better help you need additional information.
62
-
63
  When adding a thread, follow these steps and reply to each of them:
64
 
65
- **1.** Does your server meet the technical requirements described in the FAQ?
66
 
67
- **2.** Do you use CDN? If so, please see the question **"Does the plugin support CDN?"** in plugin FAQ.
68
 
69
- **3.** Do you use other plugins to optimize images? Please disable them and check this plugin without them. Remember not to combine several optimization plugins because they can be mutually exclusive.
70
 
71
- **4.** Check if in `/wp-content/uploads-webpc/` directory are all files that should be converted.
 
 
72
 
73
  If not, please enable `WP_DEBUG_LOG` in your `wp-config.php` *(more about debugging: [https://codex.wordpress.org/WP_DEBUG](https://codex.wordpress.org/WP_DEBUG))*. That's what you should have in this file:
74
 
@@ -88,33 +101,59 @@ Then follow these steps:
88
 
89
  Send a screenshot from console if an error occurred while converting images. Of you have errors in `/wp-content/debug.log` send their?
90
 
91
- **5.** URL of your website. If your site is not publicly available, add it to test environment.
 
 
 
 
92
 
93
- **6.** 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.
94
 
95
- Directly the URL path: `/wp-admin/options-general.php?page=webpc_admin_page&action=server`
96
 
97
- **7.** Content of your `.htaccess` file.
98
 
99
- **8.** What plugin version are you using? If it is not the latest then update and check everything again. Please also provide the version of WordPress and the list of plugins you use.
100
 
101
- Please remember to include the answers for all 8 questions by adding a thread. It is much easier and accelerate the solution of your problem.
102
 
103
- And most importantly - **do not leave the thread unanswered**. If you add a thread, follow when you get a reply. Then let us know if we have helped you or not. This helps us improve technical support.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  = What are requirements of plugin? =
106
 
107
- 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`.**
108
 
109
  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.
110
 
111
- Also REST API must be enabled and work without additional restrictions.
112
-
113
  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`)*.
114
 
115
- **Note the items marked in red.** If your server does not meet the technical requirements, please contact your server Administrator.
116
 
117
- He is the most competent to solve such problems. Due to the huge amount of possible server environments, we are not able to help you with its configuration. Surely the server Administrator will be able to do it best.
 
 
118
 
119
  = What are restrictions? =
120
 
@@ -124,13 +163,29 @@ Please remember that **Safari and Internet Explorer do not support the WebP form
124
 
125
  You can find more about WebP support by browsers [here](https://caniuse.com/#feat=webp).
126
 
127
- = How can I convert existing images after installing? =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  In the WordPress admin panel, on the `Settings -> WebP Converter` subpage there is a module that allows you to process all your images.
130
 
131
  It uses the WordPress REST API by downloading addresses of all images and converting all files gradually.
132
 
133
- This process may take few or more than ten minutes depending on the number of files. **It should be done once after installing the plugin.** Then all added images will be automatically regerated.
 
 
134
 
135
  = How to check if plugin works? =
136
 
@@ -145,41 +200,178 @@ When you have installed plugin and converted all images, follow these steps:
145
  7. In addition, you can check weight of website before and after using plugin. The difference will be huge!
146
  8. More information: [here](https://gbiorczyk.pl/webp-converter/check-devtools.png)
147
 
148
- Please remember that if the converted image in WebP format is larger than the original, the browser will use the original file. Therefore, you can also see files other than WebP on the list.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
  = Where are converted images stored? =
151
 
152
- All WebP images are stored in the `/wp-content/uploads-webpc/` directory. Inside the directory there is the same structure as in the original `uploads` directory. The files have original extensions in the name along with the new `.webp`.
 
 
153
 
154
- 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/2019/06/example.jpg.webp`.
155
 
156
- Original images are not changed.
157
 
158
  = How to change path to uploads? =
159
 
160
- This is possible using two filters. You can change the path of the default uploads directory and directory in which WebP files will be stored.
161
 
162
- Remember that this is the relative path of the domain. You can not change the domain there.
163
 
164
- Here is an example using default paths:
 
 
 
 
165
 
166
  `add_filter('webpc_uploads_path', function($path) {
167
  return 'wp-content/uploads';
168
  });`
169
 
 
 
170
  `add_filter('webpc_uploads_webp', function($path) {
171
  return 'wp-content/uploads-webpc';
172
  });`
173
 
174
- Filter `webpc_uploads_path` modifies the default path to the original uploads files. And filter `webpc_uploads_webp` changes the path where WebP files will be saved.
175
 
176
- Then go to `Settings -> WebP Converter` in the admin panel and click the `Save Changes` button. Also remember to regenerate all images using the `Regenerate All` button.
177
 
178
- = Can I enable browser caching for WebP images? =
 
 
179
 
180
- Yes of course. The plugin allows this by using the module `mod_expires`. Thanks to this, we can even speed up page loading time for returning users because they do not need to re-download files from the server.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
182
- If you do not want to use this functionality, you can turn it off at any time.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
  = Does plugin support CDN? =
185
 
@@ -187,7 +379,7 @@ Unfortunately not. This is due to the logic of the plugin's operation. Plugins t
187
 
188
  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.
189
 
190
- 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 added to the media library would be supported - no matter how they are displayed on the website.
191
 
192
  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.
193
 
@@ -216,42 +408,51 @@ and add below code in this file:
216
  `server {`
217
  ` # ...
218
 
219
- location ~ (?<root>.+)/uploads/(?<path>.+)\.(?<ext>jp?g|png|gif)$ {
220
  if ($http_accept !~* "image/webp") {
221
  break;
222
  }
223
  add_header Vary Accept;
224
  expires 365d;
225
- try_files $root/uploads-webpc/$path.$ext.webp $uri =404;
226
  }
227
  }`
228
 
229
  = Configuration for Multisite Network =
230
 
231
- Yes, with one exception. In this mode it is not possible to automatically generate the contents of .htaccess file.
232
 
233
- Please manually paste the following code **at the beginning of .htaccess file**:
234
 
235
  `# BEGIN WebP Converter`
236
- `<IfModule mod_mime.c>
237
- AddType image/webp .webp
238
- </IfModule>
239
- <IfModule mod_rewrite.c>
240
  RewriteEngine On
241
  RewriteCond %{HTTP_ACCEPT} image/webp
242
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpg.webp -f
243
- RewriteRule wp-content/uploads/(.+)\.jpg$ wp-content/uploads-webpc/$1.jpg.webp [T=image/webp]
244
  RewriteCond %{HTTP_ACCEPT} image/webp
245
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpeg.webp -f
246
- RewriteRule wp-content/uploads/(.+)\.jpeg$ wp-content/uploads-webpc/$1.jpeg.webp [T=image/webp]
247
  RewriteCond %{HTTP_ACCEPT} image/webp
248
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.png.webp -f
249
- RewriteRule wp-content/uploads/(.+)\.png$ wp-content/uploads-webpc/$1.png.webp [T=image/webp]
 
 
 
 
 
 
 
 
 
 
250
  </IfModule>
251
  <IfModule mod_expires.c>
252
  ExpiresActive On
253
  ExpiresByType image/webp "access plus 1 year"
254
  </IfModule>`
 
255
  `# END WebP Converter`
256
 
257
  = Is the plugin completely free? =
@@ -273,6 +474,76 @@ This is all very important to us and allows us to do even better things for you!
273
 
274
  == Changelog ==
275
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  = 1.1.2 (2020-03-03) =
277
  * `[Added]` Zero padding at end for odd-sized WebP files using `GD` library
278
 
@@ -290,7 +561,7 @@ This is all very important to us and allows us to do even better things for you!
290
 
291
  = 1.0.8 (2019-12-19) =
292
  * `[Fixed]` File deletion for custom paths with converted WebP files
293
- * `[Changed]` Rules management in .htaccess file when activating/deactivating plugin
294
  * `[Added]` Error detection system in server configuration
295
  * `[Added]` Blocking image conversion when `GD` or `Imagick` libraries are unavailable
296
 
1
  === WebP Converter for Media ===
2
  Contributors: mateuszgbiorczyk
3
  Donate link: https://ko-fi.com/gbiorczyk/
4
+ Tags: convert webp, webp, optimize images, images, webp converter, performance, optimisation
5
  Requires at least: 5.0
6
+ Tested up to: 5.5
7
  Requires PHP: 7.0
8
  Stable tag: trunk
9
  License: GPLv2 or later
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
+ #### New feature
25
+
26
+ Now you can also convert files from the `/uploads` directory into WebP and generated by other plugins! It 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
  - **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
+ - When you try to save the image to disk *(e.g. by clicking Save as...)* the original image will be saved. WebP is only used for browser loading.
40
  - The final result is that your users download less than half of the data, and the website itself loads faster!
41
 
42
+ #### Support for additional directories
43
+
44
+ You can also manually convert images from the `/plugins` and `/themes` directories, as well as other images from the `/uploads` directory that are not in the Media Library *(which are e.g. generated by other plugins)*. It allows full integration with the WebP format and maximum acceleration of your website.
45
+
46
  #### WebP images are the future!
47
 
48
  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.
49
 
50
+ #### Support to the development of plugin
51
+
52
+ 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.
53
+
54
+ If you would like to appreciate it, you can [provide us a coffee](https://ko-fi.com/gbiorczyk/). **If every user bought at least one, we could work on the plugin 24 hours a day!**
55
+
56
  #### Please also read the FAQ below. Thank you for being with us!
57
 
58
  == Installation ==
59
 
60
+ 1. Upload the plugin files to `/wp-content/plugins/webp-converter-for-media` directory, or install plugin through the WordPress plugins screen directly.
61
  2. Activate plugin through `Plugins` screen in WordPress Admin Panel.
62
  3. Use `Settings -> Settings -> WebP Converter` screen to configure the plugin.
63
  4. Click on the button `Regenerate All`.
69
 
70
  = How to get technical support? (before you ask for help) =
71
 
 
 
72
  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.
73
 
 
 
 
 
74
  When adding a thread, follow these steps and reply to each of them:
75
 
76
+ **1.** Do you have any error on the plugin settings page? If so, which one? Have you consulted your server administrator or developer? If not, please do it first.
77
 
78
+ **2.** URL of your website. If your site is not publicly available, add it to test environment.
79
 
80
+ **3.** Does your server meet the technical requirements described in the FAQ? Please send 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.
81
 
82
+ **4.** Do you use CDN? If so, please see the question **"Does the plugin support CDN?"** in plugin FAQ.
83
+
84
+ **5.** Check if in `/wp-content/uploads-webpc` directory are all files that should be converted.
85
 
86
  If not, please enable `WP_DEBUG_LOG` in your `wp-config.php` *(more about debugging: [https://codex.wordpress.org/WP_DEBUG](https://codex.wordpress.org/WP_DEBUG))*. That's what you should have in this file:
87
 
101
 
102
  Send a screenshot from console if an error occurred while converting images. Of you have errors in `/wp-content/debug.log` send their?
103
 
104
+ **6.** If in the previous step it turned out that you have files, 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.
105
+
106
+ **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)*.
107
+
108
+ **8.** Do you use any plugin filters or actions from this FAQ? If so, list them all.
109
 
110
+ **9.** What plugin version are you using? If it is not the latest then update and check everything again.
111
 
112
+ **10.** Used Wordpress version.
113
 
114
+ **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.**
115
 
116
+ 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.
117
 
118
+ = Error on plugin settings screen? =
119
 
120
+ 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.
121
+
122
+ 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.
123
+
124
+ When contacting the administrator, give him all the information available in the message. If you still cannot solve the problem, please contact us.
125
+
126
+ 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.
127
+
128
+ = Error while converting? =
129
+
130
+ 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.
131
+
132
+ 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.
133
+
134
+ 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.
135
+
136
+ 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.
137
+
138
+ 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.
139
+
140
+ 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.
141
+
142
+ 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.
143
 
144
  = What are requirements of plugin? =
145
 
146
+ 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.
147
 
148
  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.
149
 
 
 
150
  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`)*.
151
 
152
+ **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.
153
 
154
+ 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.
155
+
156
+ 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.
157
 
158
  = What are restrictions? =
159
 
163
 
164
  You can find more about WebP support by browsers [here](https://caniuse.com/#feat=webp).
165
 
166
+ = Damaged images on iOS or other browsers =
167
+
168
+ The plugin uses rules in the .htaccess file to redirect from the original image to an image in WebP format. Verifies whether the WebP file exists and whether your browser supports the WebP format. It does this every time you try to load an image.
169
+
170
+ When you enter from a WebP supporting device, it will redirect. However, when someone uses a browser that does not support WebP, the redirection will not work and you get the original file.
171
+
172
+ However, if you see corrupted images on browsers that do not support WebP, it means that your server uses cache for rewrites from the .htaccess file. Then the plugin will not work properly because the server instead of reading the rules from the .htaccess file every time uses its cache and does the redirection automatically.
173
+
174
+ How can you check it? When you turn off the plugin, the rewrites from the .htaccess file are removed, which means you should see the original images on every browser. If this is not the case and you see forced redirects to WebP files, it means that your server remembers the redirects you made earlier and uses cache.
175
+
176
+ In this situation, please contact your server administrator. Each configuration is different. It can be e.g. module `mod_pagespeed` or other similar. This functionality must be turned off so that the server reads and executes the rules from the .htaccess file each time the images are loaded. This cannot be ignored because it will cause problems.
177
+
178
+ = What to do after installing plugin? =
179
+
180
+ After installing the plugin, you should convert all existing images.
181
 
182
  In the WordPress admin panel, on the `Settings -> WebP Converter` subpage there is a module that allows you to process all your images.
183
 
184
  It uses the WordPress REST API by downloading addresses of all images and converting all files gradually.
185
 
186
+ This process may take few or more than ten minutes depending on the number of files.
187
+
188
+ **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.
189
 
190
  = How to check if plugin works? =
191
 
200
  7. In addition, you can check weight of website before and after using plugin. The difference will be huge!
201
  8. More information: [here](https://gbiorczyk.pl/webp-converter/check-devtools.png)
202
 
203
+ Please remember that 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.
204
+
205
+ WebP is only used when loading a image on a website. This 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 :)
206
+
207
+ 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.
208
+
209
+ 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.
210
+
211
+ 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.
212
+
213
+ = Why are some images not in WebP? =
214
+
215
+ 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.
216
+
217
+ 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.
218
+
219
+ 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.
220
+
221
+ 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.
222
 
223
  = Where are converted images stored? =
224
 
225
+ 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`.
226
+
227
+ 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`.
228
 
229
+ 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`.
230
 
231
+ Original images are not changed. If you remove plugins, only WebP files will be deleted. Your images are not changed in any way.
232
 
233
  = How to change path to uploads? =
234
 
235
+ 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.
236
 
237
+ Path to the root installation directory of WordPress *(`ABSPATH` by default)*:
238
 
239
+ `add_filter('webpc_uploads_root', function($path) {
240
+ return ABSPATH;
241
+ });`
242
+
243
+ Path to `/uploads` directory *(relative to the root directory)*:
244
 
245
  `add_filter('webpc_uploads_path', function($path) {
246
  return 'wp-content/uploads';
247
  });`
248
 
249
+ Directory path with converted WebP files *(relative to the root directory)*:
250
+
251
  `add_filter('webpc_uploads_webp', function($path) {
252
  return 'wp-content/uploads-webpc';
253
  });`
254
 
255
+ **Note that the `/uploads-webpc` directory must be at the same nesting level as the `/uploads`, `/plugins` and `/themes` directories.**
256
 
257
+ Prefix in URL of `/wp-content/` directory or equivalent *(used in .htaccess)*:
258
 
259
+ `add_filter('webpc_uploads_prefix', function($prefix) {
260
+ return '/';
261
+ });`
262
 
263
+ For the following sample custom WordPress structure:
264
+
265
+ `...
266
+ ├── web
267
+ ...
268
+ ├── app
269
+ │ ├── mu-plugins
270
+ │ ├── plugins
271
+ │ ├── themes
272
+ │ └── uploads
273
+ ├── wp-config.php
274
+ ...`
275
+
276
+ Use the following filters:
277
+
278
+ `add_filter('webpc_uploads_root', function($path) {
279
+ return 'C:/WAMP/www/project/webp'; // your valid path
280
+ });
281
+ add_filter('webpc_uploads_path', function($path) {
282
+ return 'app/uploads';
283
+ });
284
+ add_filter('webpc_uploads_webp', function($path) {
285
+ return 'app/uploads-webpc';
286
+ });`
287
+ `add_filter('webpc_uploads_prefix', function($prefix) {
288
+ return '/';
289
+ });`
290
 
291
+ 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`.
292
+
293
+ = How to run manually conversion? =
294
+
295
+ 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.
296
+
297
+ 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.
298
+
299
+ 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.
300
+
301
+ 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.
302
+
303
+ 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:
304
+
305
+ `do_action('webpc_regenerate_all', $paths);`
306
+
307
+ Below is an example of how to use this action to automatically regenerate images after changing the theme:
308
+
309
+ `add_action('init', function()
310
+ {
311
+ do_action('webpc_regenerate_all');
312
+ });`
313
+
314
+ 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)*:
315
+
316
+ `do_action('webpc_convert_paths', $paths);`
317
+
318
+ 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)*:
319
+
320
+ `do_action('webpc_convert_attachment', $postId);`
321
+
322
+ 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:
323
+
324
+ `add_filter('webpc_attachment_paths', function($paths, $attachmentId) {
325
+ return $paths;
326
+ }, 10, 2);`
327
+
328
+ Argument `$paths` is array of absolute server paths and `$attachmentId` is the post ID of attachment, added to the Media Library.
329
+
330
+ 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)*:
331
+
332
+ `do_action('webpc_delete_paths', $paths);`
333
+
334
+ = How to change .htaccess rules? =
335
+
336
+ 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.
337
+
338
+ 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.
339
+
340
+ Returning an empty string will delete these rules the next time you save the plugin settings. You must do this after each filter edit.
341
+
342
+ Rules for redirects: *(returns rules for `mod_rewrite` module)*:
343
+
344
+ `add_filter('webpc_htaccess_mod_rewrite', function($rules, $path) {
345
+ return '';
346
+ }, 10, 2);`
347
+
348
+ Argument `$path` is absolute server path for `.htaccess` file *(`/wp-content/.htaccess` or `/wp-content/uploads/.htaccess`)*.
349
+
350
+ Rules for `image/webp` MIME type: *(returns rules for `mod_mime` module)*:
351
+
352
+ `add_filter('webpc_htaccess_mod_mime', function($rules) {
353
+ return '';
354
+ });`
355
+
356
+ Rules for Browser Caching: *(returns rules for `mod_expires` module)*:
357
+
358
+ `add_filter('webpc_htaccess_mod_expires', function($rules) {
359
+ return '';
360
+ });`
361
+
362
+ 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`)*:
363
+
364
+ `add_filter('webpc_htaccess_rules', function($rules, $path) {
365
+ return '';
366
+ }, 10, 2);`
367
+
368
+ Argument `$path` is absolute server path for `.htaccess` file.
369
+
370
+ = What is Browser Caching? =
371
+
372
+ This option allows you to speed up page loading time for returning users because they do not need to re-download files from the server. The plugin allows this by using the module `mod_expires`.
373
+
374
+ It is enabled by default. If you do not want to use this functionality, you can turn it off at any time.
375
 
376
  = Does plugin support CDN? =
377
 
379
 
380
  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.
381
 
382
+ 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.
383
 
384
  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.
385
 
408
  `server {`
409
  ` # ...
410
 
411
+ location ~ /wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif)$ {
412
  if ($http_accept !~* "image/webp") {
413
  break;
414
  }
415
  add_header Vary Accept;
416
  expires 365d;
417
+ try_files /wp-content/uploads-webpc/$path.$ext.webp $uri =404;
418
  }
419
  }`
420
 
421
  = Configuration for Multisite Network =
422
 
423
+ Yes, with one exception. In this mode it is not possible to automatically generate the contents of .htaccess files.
424
 
425
+ Please manually paste the following code **at the beginning of .htaccess file** in the `/wp-content` directory:
426
 
427
  `# BEGIN WebP Converter`
428
+ `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
429
+ `<IfModule mod_rewrite.c>
 
 
430
  RewriteEngine On
431
  RewriteCond %{HTTP_ACCEPT} image/webp
432
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpg.webp -f
433
+ RewriteRule (.+)\.jpg$ /wp-content/uploads-webpc/$1.jpg.webp [NC,T=image/webp,E=cache-control:private,L]
434
  RewriteCond %{HTTP_ACCEPT} image/webp
435
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.jpeg.webp -f
436
+ RewriteRule (.+)\.jpeg$ /wp-content/uploads-webpc/$1.jpeg.webp [NC,T=image/webp,E=cache-control:private,Lp]
437
  RewriteCond %{HTTP_ACCEPT} image/webp
438
  RewriteCond %{DOCUMENT_ROOT}/wp-content/uploads-webpc/$1.png.webp -f
439
+ RewriteRule (.+)\.png$ /wp-content/uploads-webpc/$1.png.webp [NC,T=image/webp,E=cache-control:private,L]
440
+ </IfModule>`
441
+ `# ! --- DO NOT EDIT NEXT LINE --- !`
442
+ `# END WebP Converter`
443
+
444
+ And the following code **at the beginning of .htaccess file** in the `/wp-content/uploads-webpc` directory:
445
+
446
+ `# BEGIN WebP Converter`
447
+ `# ! --- DO NOT EDIT PREVIOUS LINE --- !`
448
+ `<IfModule mod_mime.c>
449
+ AddType image/webp .webp
450
  </IfModule>
451
  <IfModule mod_expires.c>
452
  ExpiresActive On
453
  ExpiresByType image/webp "access plus 1 year"
454
  </IfModule>`
455
+ `# ! --- DO NOT EDIT NEXT LINE --- !`
456
  `# END WebP Converter`
457
 
458
  = Is the plugin completely free? =
474
 
475
  == Changelog ==
476
 
477
+ = 1.4.0 (2020-08-13) =
478
+ * `[Removed]` Filter `webpc_notice_url`
479
+ * `[Changed]` Error messages for server requirements
480
+ * `[Changed]` Loading CSS and JS files only on plugin settings page
481
+ * `[Changed]` Minor changes for plugin settings page
482
+ * `[Changed]` Validation of saved settings values for security
483
+ * `[Added]` Blocking redirects to WebP when displaying images on other domains
484
+ * `[Added]` Cron to automatically regenerate new images outside of Media Library
485
+ * `[Added]` Filter `webpc_cron_interval` to change cron interval
486
+ * `[Added]` Error message for incorrect plugin settings
487
+ * `[Added]` Error when converting when WebP file is larger than original and has been deleted
488
+ * `[Added]` Notice after plugin installation with description of first steps
489
+ * `[Added]` Option to log errors while converting to debug.log file
490
+ * `[Added]` Option to preserve metadata for WebP files *(available for Imagick library)*
491
+ * `[Added]` Value of `ABSPATH` in `Server configuration` tab
492
+
493
+ = 1.3.1 (2020-07-03) =
494
+ * `[Fixed]` Text Domain for Internationalization
495
+
496
+ = 1.3.0 (2020-06-12) =
497
+ * `[Removed]` Ability to skip converting existing images when `Regenerate All`
498
+ * `[Fixed]` Creating `/uploads-webpc` directory webpc after re-activation plugin
499
+ * `[Fixed]` Error message about not supporting old PHP version
500
+ * `[Fixed]` Ignoring case sensitivity when verifying image extensions
501
+ * `[Changed]` Error messages when converting images
502
+ * `[Changed]` New argument for filter `webpc_htaccess_mod_rewrite` and support for multiple .htaccess files
503
+ * `[Added]` Converting all images from `/uploads` directory *(also other than from Media Library)*.
504
+ * `[Added]` Converting images from `/plugins` directory
505
+ * `[Added]` Converting images from `/themes` directory
506
+ * `[Added]` Information about used filters in `Server configuration` tab
507
+ * `[Added]` Option to force all images to be converted again when `Regenerate All`
508
+
509
+ = 1.2.7 (2020-06-11) =
510
+ * `[Changed]` Moving converted WebP files to `/uploads-webpc/uploads` directory from `/uploads-webpc` directory *(**required manual configuration change for Nginx and WordPress Multisite**)*
511
+ * `[Changed]` Validation when converting images
512
+
513
+ = 1.2.6 (2020-05-28) =
514
+ * `[Fixed]` Removal of WebP files larger than original during upload
515
+
516
+ = 1.2.5 (2020-05-10) =
517
+ * `[Removed]` Link to plugin settings on Network Admin Screen for WordPress Multisite
518
+ * `[Fixed]` Path in RewriteRule for WordPress Multisite
519
+ * `[Changed]` Error messages in administration panel
520
+ * `[Added]` Support for `disable_functions` setting for using `set_time_limit` function
521
+ * `[Added]` Support for blocked function `file_get_contents`
522
+
523
+ = 1.2.4 (2020-04-24) =
524
+ * `[Changed]` Error messages in administration panel
525
+ * `[Added]` Action `webpc_delete_paths` to delete images by paths
526
+
527
+ = 1.2.3 (2020-04-15) =
528
+ * `[Added]` Blocking server cache for rewrite rules
529
+ * `[Added]` Detecting whether requests to images are processed by server bypassing Apache
530
+
531
+ = 1.2.2 (2020-04-08) =
532
+ * `[Changed]` Moving rules for modules `mod_mime` and `mod_expires` to `/uploads-webpc/.htaccess` file
533
+ * `[Changed]` New argument for filter `webpc_htaccess_rules` with server path of file
534
+
535
+ = 1.2.1 (2020-04-07) =
536
+ * `[Removed]` Filter `webpc_option_disabled`
537
+ * `[Fixed]` Converting images multiple times when uploading to Media Library
538
+ * `[Added]` Action `webpc_convert_paths` to convert images by paths
539
+ * `[Added]` Action `webpc_convert_attachment` to convert images by Post ID
540
+
541
+ = 1.2.0 (2020-04-05) =
542
+ * `[Changed]` Moving rules from .htaccess file in root directory of WordPress to `/wp-content/uploads` directory
543
+ * `[Added]` Ability to disable automatic removal of WebP files larger than original
544
+ * `[Added]` Error validation for a non-writable .htaccess file
545
+ * `[Added]` Filter `webpc_uploads_root` to change path for root installation directory of WordPress
546
+
547
  = 1.1.2 (2020-03-03) =
548
  * `[Added]` Zero padding at end for odd-sized WebP files using `GD` library
549
 
561
 
562
  = 1.0.8 (2019-12-19) =
563
  * `[Fixed]` File deletion for custom paths with converted WebP files
564
+ * `[Changed]` Rules management in .htaccess file when activating or deactivating plugin
565
  * `[Added]` Error detection system in server configuration
566
  * `[Added]` Blocking image conversion when `GD` or `Imagick` libraries are unavailable
567
 
resources/_dev/js/classes/Notice.js CHANGED
@@ -51,6 +51,7 @@ export default class Notice
51
  jQuery.ajax(this.settings.ajaxUrl, {
52
  type: 'POST',
53
  data: {
 
54
  is_permanently: isPermanently ? 1 : 0,
55
  },
56
  });
51
  jQuery.ajax(this.settings.ajaxUrl, {
52
  type: 'POST',
53
  data: {
54
+ action: 'webpc_notice',
55
  is_permanently: isPermanently ? 1 : 0,
56
  },
57
  });
resources/_dev/js/classes/Regenerate.js CHANGED
@@ -19,7 +19,7 @@ export default class Regenerate
19
  this.errorsInner = this.errors.querySelector('.webpLoader__errorsContentList');
20
  this.errorsMessage = this.errors.querySelector('.webpLoader__errorsContentMessage');
21
  this.success = this.section.querySelector('.webpLoader__success');
22
- this.skipOption = this.section.querySelector('input[name="regenerate_skip"]');
23
  this.button = this.section.querySelector('.webpLoader__button');
24
  this.data = {
25
  count: 0,
@@ -63,10 +63,15 @@ export default class Regenerate
63
  {
64
  e.preventDefault();
65
  if (this.settings.isDisabled) return;
 
66
  this.settings.isDisabled = true;
67
- this.skipOption.setAttribute('disabled', true);
68
  this.button.classList.add(this.classes.buttonDisabled);
69
 
 
 
 
 
 
70
  this.wrapper.removeAttribute('hidden');
71
  this.getImagesList();
72
  }
@@ -75,12 +80,10 @@ export default class Regenerate
75
  {
76
  jQuery.ajax(this.settings.ajax.urlPaths, {
77
  type: 'POST',
78
- data: {
79
- skip: this.skipOption.checked ? 1 : 0,
80
- },
81
  }).done((response) => {
82
- this.data.items = response.data;
83
- this.data.max = response.data.length;
84
  this.regenerateNextImages();
85
  }).fail(() => {
86
  this.progress.classList.add(this.classes.progressError);
@@ -89,6 +92,17 @@ export default class Regenerate
89
  });
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
 
92
  /* ---
93
  Regenerate request
94
  --- */
19
  this.errorsInner = this.errors.querySelector('.webpLoader__errorsContentList');
20
  this.errorsMessage = this.errors.querySelector('.webpLoader__errorsContentMessage');
21
  this.success = this.section.querySelector('.webpLoader__success');
22
+ this.inputOptions = this.section.querySelectorAll('input[type="checkbox"]');
23
  this.button = this.section.querySelector('.webpLoader__button');
24
  this.data = {
25
  count: 0,
63
  {
64
  e.preventDefault();
65
  if (this.settings.isDisabled) return;
66
+
67
  this.settings.isDisabled = true;
 
68
  this.button.classList.add(this.classes.buttonDisabled);
69
 
70
+ const { length } = this.inputOptions;
71
+ for (let i = 0; i < length; i++) {
72
+ this.inputOptions[i].setAttribute('disabled', true);
73
+ }
74
+
75
  this.wrapper.removeAttribute('hidden');
76
  this.getImagesList();
77
  }
80
  {
81
  jQuery.ajax(this.settings.ajax.urlPaths, {
82
  type: 'POST',
83
+ data: this.getDataForPathsRequest(),
 
 
84
  }).done((response) => {
85
+ this.data.items = response;
86
+ this.data.max = response.length;
87
  this.regenerateNextImages();
88
  }).fail(() => {
89
  this.progress.classList.add(this.classes.progressError);
92
  });
93
  }
94
 
95
+ getDataForPathsRequest()
96
+ {
97
+ const options = {};
98
+ const { length } = this.inputOptions;
99
+ for (let i = 0; i < length; i++) {
100
+ const name = this.inputOptions[i].getAttribute('name');
101
+ options[name] = (this.inputOptions[i].checked) ? 1 : 0;
102
+ }
103
+ return options;
104
+ }
105
+
106
  /* ---
107
  Regenerate request
108
  --- */
resources/_dev/scss/components/webpLoader.scss CHANGED
@@ -107,6 +107,10 @@
107
  line-height: 1.64;
108
  color: $c-green-01;
109
  border-left: 2px solid $c-green-01;
 
 
 
 
110
  }
111
 
112
  /* ---
107
  line-height: 1.64;
108
  color: $c-green-01;
109
  border-left: 2px solid $c-green-01;
110
+
111
+ a {
112
+ color: inherit;
113
+ }
114
  }
115
 
116
  /* ---
resources/_dev/scss/layout/webpPage.scss CHANGED
@@ -1,5 +1,5 @@
1
  .webpPage {
2
- margin: 0;
3
  padding: 0 20px 0 0;
4
  font-family: $f-main;
5
  color: $c-gray-07;
@@ -25,17 +25,6 @@
25
  display: none !important;
26
  }
27
 
28
- /* ---
29
- Headline
30
- --- */
31
-
32
- &__headline {
33
- padding: 32px 0;
34
- font-weight: 400;
35
- font-size: 24px;
36
- line-height: 1.25;
37
- }
38
-
39
  /* ---
40
  Alert
41
  --- */
@@ -208,7 +197,7 @@
208
 
209
  &__checkboxLabel {
210
  display: inline-block;
211
- max-width: 600px;
212
  font-size: 14px;
213
  line-height: 1.64;
214
  }
1
  .webpPage {
2
+ margin: 20px 0 0 0;
3
  padding: 0 20px 0 0;
4
  font-family: $f-main;
5
  color: $c-gray-07;
25
  display: none !important;
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
 
28
  /* ---
29
  Alert
30
  --- */
197
 
198
  &__checkboxLabel {
199
  display: inline-block;
200
+ max-width: 650px;
201
  font-size: 14px;
202
  line-height: 1.64;
203
  }
resources/components/errors/bypassing-apache.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('Requests to images are processed by your server bypassing Apache. When loading images, rules from the .htaccess file are not executed. 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. Change the server settings to stop ignoring the rules in the .htaccess file. Please contact your server administrator.', 'webp-converter-for-media'),
4
+ '<a href="' . WEBPC_URL . 'public/img/icon-before.png" target="_blank">',
5
+ '</a>',
6
+ '<em>',
7
+ '</em>',
8
+ '<a href="' . WEBPC_URL . 'public/img/icon-before.png2" target="_blank">',
9
+ '</a>',
10
+ '<em>',
11
+ '</em>'
12
+ ); ?>
13
+ </p>
resources/components/errors/libs-not-installed.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('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'),
4
+ '<strong>',
5
+ '</strong>',
6
+ '<strong>',
7
+ '</strong>',
8
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
9
+ '</a>',
10
+ '<a href="' . sprintf('%s&action=server', menu_page_url('webpc_admin_page', false)) . '">',
11
+ '</a>'
12
+ ); ?>
13
+ </p>
resources/components/errors/libs-without-webp-support.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('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'),
4
+ '<strong>',
5
+ '</strong>',
6
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
7
+ '</a>',
8
+ '<a href="' . sprintf('%s&action=server', menu_page_url('webpc_admin_page', false)) . '">',
9
+ '</a>'
10
+ ); ?>
11
+ </p>
resources/components/errors/path-htaccess-not-writable.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= 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_uploads_path', '') . '/.htaccess</strong>'
7
+ ); ?>
8
+ </p>
resources/components/errors/path-uploads-unavailable.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('The path for /uploads files does not exist %s(function is_dir() returns false)%s. Use filters %s or %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_uploads_root</strong>',
7
+ '<strong>webpc_uploads_path</strong>',
8
+ '<strong>' . apply_filters('webpc_uploads_path', '') . '</strong>'
9
+ ); ?>
10
+ </p>
resources/components/errors/path-webp-duplicated.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('The paths for /uploads files and for saving converted WebP files are the same. Change them using filters %s or %s. The current path for them is: %s.', 'webp-converter-for-media'),
4
+ '<strong>webpc_uploads_path</strong>',
5
+ '<strong>webpc_uploads_webp</strong>',
6
+ '<strong>' . apply_filters('webpc_uploads_path', '') . '</strong>'
7
+ ); ?>
8
+ </p>
resources/components/errors/path-webp-not-writable.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= sprintf(
3
+ __('The path for saving converted WebP files does not exist and cannot be created %s(function is_writable() returns false)%s. Use filters %s or %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_uploads_root</strong>',
7
+ '<strong>webpc_uploads_webp</strong>',
8
+ '<strong>' . apply_filters('webpc_uploads_webp', '') . '</strong>'
9
+ ); ?>
10
+ </p>
resources/components/errors/rest-api-disabled.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= 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/settings-incorrect.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <p>
2
+ <?= 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/notices/thanks.php CHANGED
@@ -1,11 +1,11 @@
1
- <div class="notice notice-success is-dismissible" data-notice="webp-converter" data-url="<?= apply_filters('webpc_notice_url', ''); ?>">
2
  <div class="webpContent webpContent--notice">
3
  <h4>
4
- <?= __('Thank you for using our plugin WebP Converter for Media!', 'webp-converter'); ?>
5
  </h4>
6
  <p>
7
  <?= 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'),
9
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
10
  '</a>'
11
  ); ?>
@@ -13,19 +13,19 @@
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
- <?= __('Get help', 'webp-converter'); ?>
17
  </a>
18
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/#new-post" target="_blank"
19
  class="webpContent__button webpButton webpButton--green">
20
- <?= __('Add review', 'webp-converter'); ?>
21
  </a>
22
  <a href="https://ko-fi.com/gbiorczyk/" target="_blank"
23
  class="webpContent__button webpButton webpButton--green dashicons-heart">
24
- <?= __('Provide us a coffee', 'webp-converter'); ?>
25
  </a>
26
  <a href="#" target="_blank" data-permanently
27
  class="webpContent__button webpButton webpButton--blue">
28
- <?= __('I added review, do not show again', 'webp-converter'); ?>
29
  </a>
30
  </div>
31
  </div>
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
+ <?= __('Thank you for using our plugin WebP Converter for Media!', 'webp-converter-for-media'); ?>
5
  </h4>
6
  <p>
7
  <?= 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
  ); ?>
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
+ <?= __('Get help', 'webp-converter-for-media'); ?>
17
  </a>
18
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/#new-post" target="_blank"
19
  class="webpContent__button webpButton webpButton--green">
20
+ <?= __('Add review', 'webp-converter-for-media'); ?>
21
  </a>
22
  <a href="https://ko-fi.com/gbiorczyk/" target="_blank"
23
  class="webpContent__button webpButton webpButton--green dashicons-heart">
24
+ <?= __('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
+ <?= __('I added review, do not show again', 'webp-converter-for-media'); ?>
29
  </a>
30
  </div>
31
  </div>
resources/components/notices/welcome.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="notice notice-success">
2
+ <div class="webpContent webpContent--notice">
3
+ <h4>
4
+ <?= __('Thank you for installing our plugin WebP Converter for Media!', 'webp-converter-for-media'); ?>
5
+ </h4>
6
+ <p>
7
+ <?= sprintf(
8
+ __('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'),
9
+ '<br>',
10
+ '<span class="dashicons dashicons-heart"></span>'
11
+ ); ?>
12
+ </p>
13
+ <div class="webpContent__buttons">
14
+ <a href="<?= menu_page_url('webpc_admin_page', false); ?>"
15
+ class="webpContent__button webpButton webpButton--green">
16
+ <?= __('Speed up my website', 'webp-converter-for-media'); ?>
17
+ </a>
18
+ </div>
19
+ </div>
20
+ </div>
resources/components/widgets/about.php CHANGED
@@ -1,26 +1,26 @@
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
- <?= __('How does this work?', 'webp-converter'); ?>
4
  </h3>
5
  <div class="webpContent">
6
  <p>
7
  <?= 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'),
9
  '<strong>', '</strong>', '<strong>', '</strong>'
10
  ); ?>
11
  </p>
12
  <p>
13
  <?= 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'),
15
  '<strong>', '</strong>'
16
  ); ?>
17
  </p>
18
  <p>
19
- <?= __('The plugin 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'); ?>
20
  </p>
21
  <p>
22
  <?= 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'),
24
  '<strong>', '</strong>', '<strong>', '</strong>'
25
  ); ?>
26
  </p>
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
  <?= 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
  <?= 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
+ <?= __('The plugin 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
  <?= 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>
resources/components/widgets/donate.php CHANGED
@@ -1,14 +1,14 @@
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
- <?= __('We love what we do!', 'webp-converter'); ?>
4
  </h3>
5
  <div class="webpContent webpContent--lastCenter">
6
  <p>
7
- <?= __('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'); ?>
8
  </p>
9
  <p>
10
  <a href="https://ko-fi.com/gbiorczyk/" target="_blank" class="webpButton webpButton--blue dashicons-heart">
11
- <?= __('Provide us a coffee', 'webp-converter'); ?>
12
  </a>
13
  </p>
14
  </div>
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
+ <?= __('We love what we do!', 'webp-converter-for-media'); ?>
4
  </h3>
5
  <div class="webpContent webpContent--lastCenter">
6
  <p>
7
+ <?= __('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>
10
  <a href="https://ko-fi.com/gbiorczyk/" target="_blank" class="webpButton webpButton--blue dashicons-heart">
11
+ <?= __('Provide us a coffee', 'webp-converter-for-media'); ?>
12
  </a>
13
  </p>
14
  </div>
resources/components/widgets/errors.php CHANGED
@@ -1,44 +1,8 @@
1
  <?php if ($errors = apply_filters('webpc_server_errors', [])) : ?>
2
  <div class="webpPage__widget">
3
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--error">
4
- <?= __('Server configuration error', 'webp-converter'); ?>
5
  </h3>
6
- <div class="webpContent">
7
- <?php if (in_array('path_uploads', $errors)) : ?>
8
- <p>
9
- <?= sprintf(
10
- __('The path for uploads files does not exist. Please use the %s filter to set the correct path. The default path is: %s.', 'webp-converter'),
11
- '<strong>webpc_uploads_path</strong>',
12
- '<strong>' . ABSPATH . 'wp-content/uploads/</strong>'
13
- ); ?>
14
- </p>
15
- <?php endif; ?>
16
- <?php if (in_array('path_webp', $errors)) : ?>
17
- <p>
18
- <?= sprintf(
19
- __('The path for saving converted WebP files does not exist and cannot be created. Please check your server configuration and try again. The default path is: %s.', 'webp-converter'),
20
- '<strong>' . ABSPATH . 'wp-content/uploads-webpc/</strong>'
21
- ); ?>
22
- </p>
23
- <?php endif; ?>
24
- <?php if (in_array('rest_api', $errors)) : ?>
25
- <p>
26
- <?= sprintf(
27
- __('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'),
28
- '<a href="https://developer.wordpress.org/reference/hooks/rest_enabled/" target="_blank">rest_enabled</a>',
29
- '<a href="https://developer.wordpress.org/reference/hooks/rest_jsonp_enabled/" target="_blank">rest_jsonp_enabled</a>',
30
- '<a href="https://developer.wordpress.org/reference/hooks/rest_authentication_errors/" target="_blank">rest_authentication_errors</a>'
31
- ); ?>
32
- </p>
33
- <?php endif; ?>
34
- <?php if (in_array('methods', $errors)) : ?>
35
- <p>
36
- <?= sprintf(
37
- __('On your server is not installed %sGD%s or %sImagick%s library, or installed extension does not support WebP format. Please check your server configuration and try again.', 'webp-converter'),
38
- '<strong>', '</strong>', '<strong>', '</strong>'
39
- ); ?>
40
- </p>
41
- <?php endif; ?>
42
- </div>
43
  </div>
44
  <?php endif; ?>
1
  <?php if ($errors = apply_filters('webpc_server_errors', [])) : ?>
2
  <div class="webpPage__widget">
3
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--error">
4
+ <?= __('Server configuration error', 'webp-converter-for-media'); ?>
5
  </h3>
6
+ <div class="webpContent"><?= implode(PHP_EOL, $errors); ?></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  </div>
8
  <?php endif; ?>
resources/components/widgets/options.php CHANGED
@@ -1,6 +1,6 @@
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle">
3
- <?= __('Settings', 'webp-converter'); ?>
4
  </h3>
5
  <div class="webpContent">
6
  <?php foreach ($options as $index => $option) : ?>
@@ -11,12 +11,12 @@
11
  <?php endforeach; ?>
12
  <div class="webpPage__widgetRow">
13
  <button type="submit" name="webpc_save"
14
- class="webpButton webpButton--green"><?= __('Save Changes', 'webp-converter'); ?></button>
15
  </div>
16
  <div class="webpPage__widgetRow">
17
  <p>
18
  <?= sprintf(
19
- __('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'),
20
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
21
  '</a>',
22
  '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle">
3
+ <?= __('Settings', 'webp-converter-for-media'); ?>
4
  </h3>
5
  <div class="webpContent">
6
  <?php foreach ($options as $index => $option) : ?>
11
  <?php endforeach; ?>
12
  <div class="webpPage__widgetRow">
13
  <button type="submit" name="webpc_save"
14
+ class="webpButton webpButton--green"><?= __('Save Changes', 'webp-converter-for-media'); ?></button>
15
  </div>
16
  <div class="webpPage__widgetRow">
17
  <p>
18
  <?= sprintf(
19
+ __('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'),
20
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
21
  '</a>',
22
  '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
resources/components/widgets/regenerate.php CHANGED
@@ -4,18 +4,18 @@
4
  ?>
5
  <div class="webpPage__widget">
6
  <h3 class="webpPage__widgetTitle">
7
- <?= __('Regenerate images', 'webp-converter'); ?>
8
  </h3>
9
  <div class="webpLoader webpContent"
10
  data-api-paths="<?= $apiPaths; ?>"
11
  data-api-regenerate="<?= $apiRegenerate; ?>"
12
- data-api-error-message="<?= __('An unknown error occurred while converting the images: %s', 'webp-converter'); ?>">
13
  <div class="webpPage__widgetRow">
14
  <p>
15
- <?= __('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'); ?>
16
  </p>
17
  <p>
18
- <?= __('This operation should be performed only once after installing the plugin. New images will be converted automatically.', 'webp-converter'); ?>
19
  </p>
20
  <div class="webpLoader__status" hidden>
21
  <div class="webpLoader__bar">
@@ -24,20 +24,26 @@
24
  </div>
25
  <div class="webpLoader__size">
26
  <?= sprintf(
27
- __('Saving the weight of your images: %s', 'webp-converter'),
28
  '<span class="webpLoader__sizeProgress">0 kB</span>'
29
  ); ?>
30
  </div>
31
  </div>
32
  <div class="webpLoader__success" hidden>
33
- <?= __('The process was completed successfully. Your images have been converted!', 'webp-converter'); ?>
 
 
 
 
 
 
34
  </div>
35
  <div class="webpLoader__errors" hidden>
36
- <div class="webpLoader__errorsTitle"><?= __('List of errors', 'webp-converter'); ?></div>
37
  <div class="webpLoader__errorsContent">
38
  <div class="webpLoader__errorsContentList"></div>
39
  <div class="webpLoader__errorsContentMessage" hidden>
40
- <?= __('An error occurred while connecting to REST API. Please try again.', 'webp-converter'); ?>
41
  </div>
42
  </div>
43
  </div>
@@ -47,13 +53,13 @@
47
  <table class="webpPage__widgetTable">
48
  <tr>
49
  <td>
50
- <input type="checkbox" name="regenerate_skip" value="1"
51
- id="webpc-regenerate-skip" class="webpPage__checkbox">
52
- <label for="webpc-regenerate-skip"></label>
53
  </td>
54
  <td>
55
- <label for="webpc-regenerate-skip" class="webpPage__checkboxLabel">
56
- <?= __('Skip converted images', 'webp-converter'); ?>
57
  </label>
58
  </td>
59
  </tr>
@@ -61,7 +67,7 @@
61
  <button type="button" target="_blank"
62
  class="webpLoader__button webpButton webpButton--green"
63
  <?= (apply_filters('webpc_server_errors', [])) ? 'disabled' : ''; ?>>
64
- <?= __('Regenerate All', 'webp-converter'); ?>
65
  </button>
66
  </div>
67
  </div>
4
  ?>
5
  <div class="webpPage__widget">
6
  <h3 class="webpPage__widgetTitle">
7
+ <?= __('Regenerate images', 'webp-converter-for-media'); ?>
8
  </h3>
9
  <div class="webpLoader webpContent"
10
  data-api-paths="<?= $apiPaths; ?>"
11
  data-api-regenerate="<?= $apiRegenerate; ?>"
12
+ data-api-error-message="<?= __('An unknown error occurred while converting the images: %s', 'webp-converter-for-media'); ?>">
13
  <div class="webpPage__widgetRow">
14
  <p>
15
+ <?= __('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'); ?>
16
  </p>
17
  <p>
18
+ <?= __('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'); ?>
19
  </p>
20
  <div class="webpLoader__status" hidden>
21
  <div class="webpLoader__bar">
24
  </div>
25
  <div class="webpLoader__size">
26
  <?= sprintf(
27
+ __('Saving the weight of your images: %s', 'webp-converter-for-media'),
28
  '<span class="webpLoader__sizeProgress">0 kB</span>'
29
  ); ?>
30
  </div>
31
  </div>
32
  <div class="webpLoader__success" hidden>
33
+ <?= __('The process was completed successfully. Your images have been converted!', 'webp-converter-for-media'); ?>
34
+ <br>
35
+ <?= sprintf(
36
+ __('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'),
37
+ '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
38
+ '</a>'
39
+ ); ?>
40
  </div>
41
  <div class="webpLoader__errors" hidden>
42
+ <div class="webpLoader__errorsTitle"><?= __('List of errors', 'webp-converter-for-media'); ?></div>
43
  <div class="webpLoader__errorsContent">
44
  <div class="webpLoader__errorsContentList"></div>
45
  <div class="webpLoader__errorsContentMessage" hidden>
46
+ <?= __('An error occurred while connecting to REST API. Please try again.', 'webp-converter-for-media'); ?>
47
  </div>
48
  </div>
49
  </div>
53
  <table class="webpPage__widgetTable">
54
  <tr>
55
  <td>
56
+ <input type="checkbox" name="regenerate_force" value="1"
57
+ id="webpc-regenerate-force" class="webpPage__checkbox">
58
+ <label for="webpc-regenerate-force"></label>
59
  </td>
60
  <td>
61
+ <label for="webpc-regenerate-force" class="webpPage__checkboxLabel">
62
+ <?= __('Force convert all images again', 'webp-converter-for-media'); ?>
63
  </label>
64
  </td>
65
  </tr>
67
  <button type="button" target="_blank"
68
  class="webpLoader__button webpButton webpButton--green"
69
  <?= (apply_filters('webpc_server_errors', [])) ? 'disabled' : ''; ?>>
70
+ <?= __('Regenerate All', 'webp-converter-for-media'); ?>
71
  </button>
72
  </div>
73
  </div>
resources/components/widgets/server.php CHANGED
@@ -4,18 +4,18 @@
4
  ?>
5
  <div class="webpPage__widget">
6
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
7
- <?= __('Your server configuration', 'webp-converter'); ?>
8
  </h3>
9
  <div class="webpContent">
10
  <div class="webpPage__widgetRow">
11
  <p>
12
- <?= 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'),
13
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
14
  '</a>'
15
  ); ?>
16
  </p>
17
  <a href="<?= $pageUrl; ?>" class="webpLoader__button webpButton webpButton--blue">
18
- <?= __('Back to settings', 'webp-converter'); ?>
19
  </a>
20
  </div>
21
  <div class="webpPage__widgetRow">
@@ -23,7 +23,7 @@
23
  </div>
24
  <div class="webpPage__widgetRow">
25
  <a href="<?= $pageUrl; ?>" class="webpLoader__button webpButton webpButton--blue">
26
- <?= __('Back to settings', 'webp-converter'); ?>
27
  </a>
28
  </div>
29
  </div>
4
  ?>
5
  <div class="webpPage__widget">
6
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
7
+ <?= __('Your server configuration', 'webp-converter-for-media'); ?>
8
  </h3>
9
  <div class="webpContent">
10
  <div class="webpPage__widgetRow">
11
  <p>
12
+ <?= 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'),
13
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
14
  '</a>'
15
  ); ?>
16
  </p>
17
  <a href="<?= $pageUrl; ?>" class="webpLoader__button webpButton webpButton--blue">
18
+ <?= __('Back to settings', 'webp-converter-for-media'); ?>
19
  </a>
20
  </div>
21
  <div class="webpPage__widgetRow">
23
  </div>
24
  <div class="webpPage__widgetRow">
25
  <a href="<?= $pageUrl; ?>" class="webpLoader__button webpButton webpButton--blue">
26
+ <?= __('Back to settings', 'webp-converter-for-media'); ?>
27
  </a>
28
  </div>
29
  </div>
resources/components/widgets/support.php CHANGED
@@ -1,14 +1,14 @@
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
- <?= __('We are waiting for your message', 'webp-converter'); ?>
4
  </h3>
5
  <div class="webpContent">
6
  <p>
7
- <?= __('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'); ?>
8
  </p>
9
  <p>
10
  <?= sprintf(
11
- __('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'),
12
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
13
  '</a>',
14
  '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
@@ -17,18 +17,18 @@
17
  </p>
18
  <p>
19
  <a href="<?= sprintf('%s&action=server', menu_page_url('webpc_admin_page', false)); ?>" class="webpButton webpButton--blue">
20
- <?= __('Server configuration', 'webp-converter'); ?>
21
  </a>
22
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank" class="webpButton webpButton--blue">
23
- <?= __('Get help', 'webp-converter'); ?>
24
  </a>
25
  </p>
26
  <p>
27
- <?= __('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'); ?>
28
  </p>
29
  <p>
30
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/#new-post" target="_blank" class="webpButton webpButton--blue">
31
- <?= __('Add review', 'webp-converter'); ?>
32
  </a>
33
  </p>
34
  </div>
1
  <div class="webpPage__widget">
2
  <h3 class="webpPage__widgetTitle webpPage__widgetTitle--second">
3
+ <?= __('We are waiting for your message', 'webp-converter-for-media'); ?>
4
  </h3>
5
  <div class="webpContent">
6
  <p>
7
+ <?= __('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'); ?>
8
  </p>
9
  <p>
10
  <?= sprintf(
11
+ __('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'),
12
  '<a href="https://wordpress.org/plugins/webp-converter-for-media/#faq" target="_blank">',
13
  '</a>',
14
  '<a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank">',
17
  </p>
18
  <p>
19
  <a href="<?= sprintf('%s&action=server', menu_page_url('webpc_admin_page', false)); ?>" class="webpButton webpButton--blue">
20
+ <?= __('Server configuration', 'webp-converter-for-media'); ?>
21
  </a>
22
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/" target="_blank" class="webpButton webpButton--blue">
23
+ <?= __('Get help', 'webp-converter-for-media'); ?>
24
  </a>
25
  </p>
26
  <p>
27
+ <?= __('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'); ?>
28
  </p>
29
  <p>
30
  <a href="https://wordpress.org/support/plugin/webp-converter-for-media/reviews/#new-post" target="_blank" class="webpButton webpButton--blue">
31
+ <?= __('Add review', 'webp-converter-for-media'); ?>
32
  </a>
33
  </p>
34
  </div>
resources/views/settings.php CHANGED
@@ -3,31 +3,33 @@
3
  $options = apply_filters('webpc_get_options', []);
4
  $values = apply_filters('webpc_get_values', []);
5
  ?>
6
- <form method="post" action="<?= $path; ?>" class="webpPage">
7
- <div class="webpPage__inner">
8
- <h1 class="webpPage__headline"><?= __('WebP Converter for Media', 'webp-converter'); ?></h1>
9
- <ul class="webpPage__columns">
10
- <li class="webpPage__column webpPage__column--large">
11
- <?php if ($_POST) : ?>
12
- <div class="webpPage__alert"><?= __('Changes were successfully saved!', 'webp-converter'); ?></div>
13
- <?php endif; ?>
14
- <?php
15
- if (isset($_GET['action']) && ($_GET['action'] === 'server')) {
16
- include WEBPC_PATH . '/resources/components/widgets/server.php';
17
- } else {
18
- include WEBPC_PATH . '/resources/components/widgets/errors.php';
19
- include WEBPC_PATH . '/resources/components/widgets/options.php';
20
- include WEBPC_PATH . '/resources/components/widgets/regenerate.php';
21
- }
22
- ?>
23
- </li>
24
- <li class="webpPage__column webpPage__column--small">
25
- <?php
26
- include WEBPC_PATH . '/resources/components/widgets/about.php';
27
- include WEBPC_PATH . '/resources/components/widgets/support.php';
28
- include WEBPC_PATH . '/resources/components/widgets/donate.php';
29
- ?>
30
- </li>
31
- </ul>
32
- </div>
33
- </form>
 
 
3
  $options = apply_filters('webpc_get_options', []);
4
  $values = apply_filters('webpc_get_values', []);
5
  ?>
6
+ <div class="wrap">
7
+ <h1><?= __('WebP Converter for Media', 'webp-converter-for-media'); ?></h1>
8
+ <form method="post" action="<?= $path; ?>" class="webpPage">
9
+ <div class="webpPage__inner">
10
+ <ul class="webpPage__columns">
11
+ <li class="webpPage__column webpPage__column--large">
12
+ <?php if ($_POST) : ?>
13
+ <div class="webpPage__alert"><?= __('Changes were successfully saved!', 'webp-converter-for-media'); ?></div>
14
+ <?php endif; ?>
15
+ <?php
16
+ if (isset($_GET['action']) && ($_GET['action'] === 'server')) {
17
+ include WEBPC_PATH . '/resources/components/widgets/server.php';
18
+ } else {
19
+ include WEBPC_PATH . '/resources/components/widgets/errors.php';
20
+ include WEBPC_PATH . '/resources/components/widgets/options.php';
21
+ include WEBPC_PATH . '/resources/components/widgets/regenerate.php';
22
+ }
23
+ ?>
24
+ </li>
25
+ <li class="webpPage__column webpPage__column--small">
26
+ <?php
27
+ include WEBPC_PATH . '/resources/components/widgets/about.php';
28
+ include WEBPC_PATH . '/resources/components/widgets/support.php';
29
+ include WEBPC_PATH . '/resources/components/widgets/donate.php';
30
+ ?>
31
+ </li>
32
+ </ul>
33
+ </div>
34
+ </form>
35
+ </div>
webp-converter-for-media.php CHANGED
@@ -3,13 +3,13 @@
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: 1.1.2
7
  Author: Mateusz Gbiorczyk
8
  Author URI: https://gbiorczyk.pl/
9
- Text Domain: webp-converter
10
  */
11
 
12
- define('WEBPC_VERSION', '1.1.2');
13
  define('WEBPC_FILE', __FILE__);
14
  define('WEBPC_NAME', plugin_basename(__FILE__));
15
  define('WEBPC_PATH', plugin_dir_path(__FILE__));
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: 1.4.0
7
  Author: Mateusz Gbiorczyk
8
  Author URI: https://gbiorczyk.pl/
9
+ Text Domain: webp-converter-for-media
10
  */
11
 
12
+ define('WEBPC_VERSION', '1.4.0');
13
  define('WEBPC_FILE', __FILE__);
14
  define('WEBPC_NAME', plugin_basename(__FILE__));
15
  define('WEBPC_PATH', plugin_dir_path(__FILE__));