Compress JPEG & PNG images - Version 1.6.0

Version Description

  • Improved compression status in the Media Library with new details window.
  • Show total compression savings on the Media Settings page with link to bulk compression page when no images have been compressed yet.
  • Moved Compress All Images from the Tools to the Media menu.
Download this release

Release Info

Developer TinyPNG
Plugin Icon 128x128 Compress JPEG & PNG images
Version 1.6.0
Comparing to
See all releases

Code changes from version 1.3.1 to 1.6.0

Files changed (56) hide show
  1. README.md +23 -8
  2. RELEASE +14 -11
  3. bin/docker-functions +2 -2
  4. bin/integration-tests +8 -2
  5. bin/restore-wordpress +11 -1
  6. bin/test-wordpress +12 -2
  7. composer.json +8 -1
  8. composer.lock +230 -139
  9. config/Dockerfile-phantomjs +2 -14
  10. config/Dockerfile-wordpress-37 +3 -3
  11. config/Dockerfile-wordpress-38 +3 -3
  12. config/Dockerfile-wordpress-39 +3 -3
  13. config/Dockerfile-wordpress-40 +3 -3
  14. config/Dockerfile-wordpress-41 +3 -3
  15. config/Dockerfile-wordpress-42 +3 -3
  16. config/Dockerfile-wordpress-43 +15 -0
  17. readme.txt +49 -21
  18. src/class-tiny-compress-curl.php +22 -11
  19. src/class-tiny-compress-fopen.php +34 -14
  20. src/class-tiny-compress.php +45 -9
  21. src/class-tiny-metadata.php +98 -18
  22. src/class-tiny-plugin.php +62 -44
  23. src/class-tiny-settings.php +180 -32
  24. src/class-tiny-wp-base.php +15 -2
  25. src/config/tiny-config.php +1 -0
  26. src/languages/tiny-compress-images-nl_NL.mo +0 -0
  27. src/languages/tiny-compress-images-nl_NL.po +135 -27
  28. src/languages/tiny-compress-images-ru_RU.mo +0 -0
  29. src/languages/tiny-compress-images-ru_RU.po +6 -12
  30. src/languages/tiny-compress-images-zh_TW.mo +0 -0
  31. src/languages/tiny-compress-images-zh_TW.po +205 -0
  32. src/scripts/admin.js +30 -1
  33. src/styles/admin.css +88 -3
  34. src/views/compress-details-processing.php +9 -0
  35. src/views/compress-details.php +119 -0
  36. test/fixtures/input-large.jpg +0 -0
  37. test/fixtures/json/wp_meta_default_sizes.json +27 -0
  38. test/fixtures/json/wp_meta_sizes_with_same_files.json +21 -0
  39. test/helpers/setup.php +11 -5
  40. test/helpers/wordpress.php +45 -2
  41. test/integration/BulkCompressIntegrationTest.php +2 -2
  42. test/integration/CompressIntegrationTest.php +70 -4
  43. test/integration/IntegrationTestCase.php +39 -0
  44. test/integration/PluginIntegrationTest.php +21 -0
  45. test/integration/SettingsIntegrationTest.php +85 -1
  46. test/mock-tinypng-webservice/common.php +45 -0
  47. test/mock-tinypng-webservice/output-resized.jpg +0 -0
  48. test/mock-tinypng-webservice/output.php +21 -1
  49. test/mock-tinypng-webservice/reset.php +2 -5
  50. test/mock-tinypng-webservice/shrink.php +22 -29
  51. test/unit/TinyMetadataTest.php +279 -0
  52. test/unit/TinyPluginTest.php +24 -11
  53. test/unit/TinySettingsTest.php +51 -2
  54. test/unit/TinyTestCase.php +9 -0
  55. tiny-compress-images.php +16 -16
  56. trunk/tmp/.gitkeep +0 -0
README.md CHANGED
@@ -1,25 +1,29 @@
1
  [<img src="https://travis-ci.org/tinify/wordpress-plugin.svg?branch=master" alt="Build Status">](https://travis-ci.org/tinify/wordpress-plugin)
2
 
3
- # TinyPNG image compression for WordPress
 
4
  Make your website faster by compressing your JPEG and PNG images.
5
 
6
- This plugin automatically optimizes your images by integrating with the popular image compression services TinyJPG and TinyPNG. You can download the plugin from https://wordpress.org/plugins/tiny-compress-images/.
 
 
7
 
8
- Learn more about TinyPNG at https://tinypng.com.
9
 
10
  ## Contact us
 
11
  Got questions or feedback? Let us know! Contact us at support@tinypng.com.
12
 
13
  ## Information for plugin contributors
14
 
15
  ### Prerequisites
16
- * A working docker installation (https://docs.docker.com/installation/).
17
  * Composer (https://getcomposer.org/download/).
18
  * Selenium Server (http://www.seleniumhq.org/download/).
19
- * Mysql client and admin tools.
20
  * Java runtime.
21
 
22
- ### Running the plugin in Wordpress
23
  1. Run `bin/run-wordpress <version>`. E.g. `bin/run-wordpress 41`.
24
  2. Use `docker ps` to check which port to use to connect to WordPress.
25
 
@@ -28,11 +32,22 @@ Got questions or feedback? Let us know! Contact us at support@tinypng.com.
28
 
29
  ### Running the integration tests
30
  1. Start Selenium server: `java -jar selenium-server-standalone-2.44.0.jar`.
31
- 2. Run `bin/integration-tests $version [$to_version]`. E.g. `bin/run-wordpress 41` or `bin/integration-tests 40 42`.
 
 
 
 
32
 
33
- Note that when testing a different WordPress version, `bin/run-wordpress <version>` has to be run first.
 
 
 
 
 
 
34
 
35
  ## License
 
36
  Copyright (C) 2015 Voormedia B.V.
37
 
38
  This program is free software; you can redistribute it and/or modify
1
  [<img src="https://travis-ci.org/tinify/wordpress-plugin.svg?branch=master" alt="Build Status">](https://travis-ci.org/tinify/wordpress-plugin)
2
 
3
+ # Compress JPEG & PNG images for WordPress
4
+
5
  Make your website faster by compressing your JPEG and PNG images.
6
 
7
+ This plugin automatically optimizes your images by integrating with the
8
+ popular image compression services TinyJPG and TinyPNG. You can download the
9
+ plugin from https://wordpress.org/plugins/tiny-compress-images/.
10
 
11
+ Learn more about TinyJPG and TinyPNG at https://tinypng.com/.
12
 
13
  ## Contact us
14
+
15
  Got questions or feedback? Let us know! Contact us at support@tinypng.com.
16
 
17
  ## Information for plugin contributors
18
 
19
  ### Prerequisites
20
+ * A working Docker installation (https://docs.docker.com/installation/).
21
  * Composer (https://getcomposer.org/download/).
22
  * Selenium Server (http://www.seleniumhq.org/download/).
23
+ * MySQL client and admin tools.
24
  * Java runtime.
25
 
26
+ ### Running the plugin in WordPress
27
  1. Run `bin/run-wordpress <version>`. E.g. `bin/run-wordpress 41`.
28
  2. Use `docker ps` to check which port to use to connect to WordPress.
29
 
32
 
33
  ### Running the integration tests
34
  1. Start Selenium server: `java -jar selenium-server-standalone-2.44.0.jar`.
35
+ 2. Run `bin/integration-tests $version [$to_version]` (When $to_version is
36
+ added, all versions between $version and $to_version are tested). E.g.
37
+ `bin/integration-tests 41` or `bin/integration-tests 40 42`.
38
+
39
+ ### Create language files
40
 
41
+ WordPress requires both .po and .mo files for each language. The .mo files
42
+ can be generated with [gettext](https://www.gnu.org/software/gettext/) that
43
+ needs to be installed first.
44
+
45
+ 1. Install gettext for example run `brew install gettext`.
46
+ 2. Add a link msgfmt `ln -s /usr/local/Cellar/gettext/0.19.6/bin/msgfmt ~/.bin`.
47
+ 3. Generate the .mo files `bin/format-language-files`.
48
 
49
  ## License
50
+
51
  Copyright (C) 2015 Voormedia B.V.
52
 
53
  This program is free software; you can redistribute it and/or modify
RELEASE CHANGED
@@ -2,14 +2,17 @@ In order to release a new version of the plugin to wordpress.org, perform the fo
2
 
3
  1. Update the version in tiny-compress-images.php
4
  2. Change the 'Stable tag' in readme.txt to the new release number.
5
- 3. Commit and push to GitHub.
6
- 4. Create a new release in GitHub and pull it in.
7
- 5. Locally, checkout the new tag: `git checkout <tagged version>`.
8
- 6. If not already done so, checkout the plugin's Subversion repository: `svn co http://plugins.svn.wordpress.org/tiny-compress-images`.
9
- 7. Update svn:ignore property of trunk when .gitignore is updated: `svn propedit svn:ignore trunk`.
10
- 8. Delete everything in trunk `rm -rf <path-to-local-svn-repo/trunk/*`.
11
- 9. Manually copy the Git release to the local Subversion repo: `git ls-files | xargs tar c | tar x -C <path-to-local-svn-repo>/trunk/`.
12
- 10. Add new files `svn st | awk '/^\?/ { print $2; }' | xargs svn add`.
13
- 11. Delete deleted files: `svn st | awk '/^!/ { print $2; }' | xargs svn rm`.
14
- 12. Commit the trunk to Subversion: `svn ci -m "<message>"`.
15
- 13. Tag the new release in Subversion and commit: `svn cp trunk tags/<version> && svn ci -m "<message>"`.
 
 
 
2
 
3
  1. Update the version in tiny-compress-images.php
4
  2. Change the 'Stable tag' in readme.txt to the new release number.
5
+ 3. Add release notes to readme.txt.
6
+ 4. If you've changed the plugin to work with newer version of WordPress add that to the readme.txt as well.
7
+ 5. Commit and push to GitHub.
8
+ 6. Create a new release in GitHub and pull it in.
9
+ 7. Locally, checkout the new tag: `git checkout <tagged version>`.
10
+ 8. If not already done so, checkout the plugin's Subversion repository: `svn co http://plugins.svn.wordpress.org/tiny-compress-images`.
11
+ 9. Run `svn update` when the Subversion repository already existed.
12
+ 10. Update svn:ignore property of trunk when .gitignore is updated: `svn propedit svn:ignore trunk`.
13
+ 11. Delete everything in trunk `rm -rf <path-to-local-svn-repo/trunk/*`.
14
+ 12. Manually copy the Git release to the local Subversion repo: `git ls-files | xargs tar c | tar x -C <path-to-local-svn-repo>/trunk/`.
15
+ 13. Add new files `svn st | awk '/^\?/ { print $2; }' | xargs svn add`.
16
+ 14. Delete deleted files: `svn st | awk '/^!/ { print $2; }' | xargs svn rm`.
17
+ 15. Commit the trunk to Subversion: `svn ci -m "<message>"`.
18
+ 16. Tag the new release in Subversion and commit: `svn cp trunk tags/<version> && svn ci -m "<message>"`.
bin/docker-functions CHANGED
@@ -21,7 +21,7 @@ run_phantomjs() {
21
  echo "Starting PhantomJS container..."
22
  docker run --name phantomjs \
23
  --link "wordpress$version":wordpress \
24
- -d phantomjs
25
  }
26
 
27
  run_wordpress() {
@@ -50,7 +50,7 @@ run_mysql() {
50
  then
51
  docker start "mysql-wordpress"
52
  else
53
- docker run --name mysql-wordpress -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql
54
  fi
55
  fi
56
  }
21
  echo "Starting PhantomJS container..."
22
  docker run --name phantomjs \
23
  --link "wordpress$version":wordpress \
24
+ --detach=false phantomjs
25
  }
26
 
27
  run_wordpress() {
50
  then
51
  docker start "mysql-wordpress"
52
  else
53
+ docker run --name mysql-wordpress -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql:5.5
54
  fi
55
  fi
56
  }
bin/integration-tests CHANGED
@@ -7,7 +7,13 @@ use IO::Socket;
7
  use Time::HiRes qw(usleep);
8
 
9
  my $dir = dirname($0);
10
- my $hostip = `boot2docker ip`;
 
 
 
 
 
 
11
 
12
  sub check_port {
13
  my ($ip, $port, $times, $sleep) = @_;
@@ -28,7 +34,7 @@ my $from = $ARGV[0] || 42;
28
  my $to = $ARGV[1] || $from;
29
 
30
  for (my $version = $from; $version <= $to; $version++) {
31
- printf("==================== Wordpress %d ====================\n", $version);
32
  print(" - Running\n");
33
  my $ret = system("$dir/run-wordpress $version > /dev/null 2>&1");
34
  if ($ret) {
7
  use Time::HiRes qw(usleep);
8
 
9
  my $dir = dirname($0);
10
+
11
+ my $hostip;
12
+ if (`which docker-machine`) {
13
+ $hostip = `docker-machine ip $ENV{'DOCKER_MACHINE_NAME'}`;
14
+ } else {
15
+ $hostip = `boot2docker ip`;
16
+ }
17
 
18
  sub check_port {
19
  my ($ip, $port, $times, $sleep) = @_;
34
  my $to = $ARGV[1] || $from;
35
 
36
  for (my $version = $from; $version <= $to; $version++) {
37
+ printf("==================== WordPress %d ====================\n", $version);
38
  print(" - Running\n");
39
  my $ret = system("$dir/run-wordpress $version > /dev/null 2>&1");
40
  if ($ret) {
bin/restore-wordpress CHANGED
@@ -19,7 +19,17 @@ source $DIR/docker-functions
19
  export WORDPRESS_VERSION=$version
20
  export WORDPRESS_DATABASE=wordpress_$version
21
  export MYSQL_ROOT_PASSWORD=root
22
- export HOST_IP=$(boot2docker ip)
 
 
 
 
 
 
 
 
 
 
23
  export MYSQL_DUMP_FILE=tmp/mysqldump_wordpress_$version.sql.gz
24
 
25
  gunzip -c < $MYSQL_DUMP_FILE | mysql -h $HOST_IP -u root "-p$MYSQL_ROOT_PASSWORD" $WORDPRESS_DATABASE
19
  export WORDPRESS_VERSION=$version
20
  export WORDPRESS_DATABASE=wordpress_$version
21
  export MYSQL_ROOT_PASSWORD=root
22
+
23
+ if hash docker-machine 2>/dev/null; then
24
+ export HOST_IP=$(docker-machine ip $DOCKER_MACHINE_NAME)
25
+ else
26
+ export HOST_IP=$(boot2docker ip)
27
+ fi
28
+ if [ -z "$HOST_IP" ]; then
29
+ echo "Could not find docker machine ip"
30
+ exit 2
31
+ fi
32
+
33
  export MYSQL_DUMP_FILE=tmp/mysqldump_wordpress_$version.sql.gz
34
 
35
  gunzip -c < $MYSQL_DUMP_FILE | mysql -h $HOST_IP -u root "-p$MYSQL_ROOT_PASSWORD" $WORDPRESS_DATABASE
bin/test-wordpress CHANGED
@@ -26,7 +26,17 @@ fi
26
  export WORDPRESS_VERSION=$version
27
  export WORDPRESS_DATABASE=wordpress_$version
28
  export MYSQL_ROOT_PASSWORD=root
29
- export HOST_IP=$(boot2docker ip)
 
 
 
 
 
 
 
 
 
 
30
  export HOST_PORT=80$version
31
- export WORDPRESS_URL=http://$(boot2docker ip):$HOST_PORT
32
  vendor/bin/phpunit "$PHPUNIT_ARG"
26
  export WORDPRESS_VERSION=$version
27
  export WORDPRESS_DATABASE=wordpress_$version
28
  export MYSQL_ROOT_PASSWORD=root
29
+
30
+ if hash docker-machine 2>/dev/null; then
31
+ export HOST_IP=$(docker-machine ip $DOCKER_MACHINE_NAME)
32
+ else
33
+ export HOST_IP=$(boot2docker ip)
34
+ fi
35
+ if [ -z "$HOST_IP" ]; then
36
+ echo "Could not find docker machine ip"
37
+ exit 2
38
+ fi
39
+
40
  export HOST_PORT=80$version
41
+ export WORDPRESS_URL=http://$HOST_IP:$HOST_PORT
42
  vendor/bin/phpunit "$PHPUNIT_ARG"
composer.json CHANGED
@@ -1,8 +1,15 @@
1
  {
 
 
 
 
 
2
  "require": {
3
- "facebook/webdriver": "0.5.*"
 
4
  },
5
  "require-dev": {
 
6
  "phpunit/phpunit": "~4.6",
7
  "mikey179/vfsStream": "~1.5",
8
  "mockery/mockery": "~0.9"
1
  {
2
+ "name": "tinify/wordpress-plugin",
3
+ "description": "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG.",
4
+ "license": "GPL-2.0+",
5
+ "type": "wordpress-plugin",
6
+ "keywords": ["plugin"],
7
  "require": {
8
+ "php": ">=5.3.0",
9
+ "composer/installers": "~1.0"
10
  },
11
  "require-dev": {
12
+ "facebook/webdriver": "0.5.*",
13
  "phpunit/phpunit": "~4.6",
14
  "mikey179/vfsStream": "~1.5",
15
  "mockery/mockery": "~0.9"
composer.lock CHANGED
@@ -4,63 +4,120 @@
4
  "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
  "This file is @generated automatically"
6
  ],
7
- "hash": "14e67ae14aec130373c8ff715c963454",
8
  "packages": [
9
  {
10
- "name": "facebook/webdriver",
11
- "version": "v0.5.1",
12
  "source": {
13
  "type": "git",
14
- "url": "https://github.com/facebook/php-webdriver.git",
15
- "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509"
16
  },
17
  "dist": {
18
  "type": "zip",
19
- "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bbcb697efb394d17bd9ec3d467e7da847cde4509",
20
- "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509",
21
  "shasum": ""
22
  },
23
  "require": {
24
- "php": ">=5.3.19"
 
 
 
 
25
  },
26
  "require-dev": {
27
- "phpdocumentor/phpdocumentor": "2.*",
28
- "phpunit/phpunit": "3.7.*"
 
 
 
 
 
 
 
29
  },
30
- "type": "library",
31
  "autoload": {
32
- "classmap": [
33
- "lib/"
34
- ]
35
  },
36
  "notification-url": "https://packagist.org/downloads/",
37
  "license": [
38
- "Apache-2.0"
39
  ],
40
- "description": "A php client for WebDriver",
41
- "homepage": "https://github.com/facebook/php-webdriver",
 
 
 
 
 
 
 
42
  "keywords": [
43
- "facebook",
44
- "php",
45
- "selenium",
46
- "webdriver"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  ],
48
- "time": "2014-11-05 20:53:09"
49
  }
50
  ],
51
  "packages-dev": [
52
  {
53
  "name": "doctrine/instantiator",
54
- "version": "1.0.4",
55
  "source": {
56
  "type": "git",
57
  "url": "https://github.com/doctrine/instantiator.git",
58
- "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
59
  },
60
  "dist": {
61
  "type": "zip",
62
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
63
- "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
64
  "shasum": ""
65
  },
66
  "require": {
@@ -71,7 +128,7 @@
71
  "ext-pdo": "*",
72
  "ext-phar": "*",
73
  "phpunit/phpunit": "~4.0",
74
- "squizlabs/php_codesniffer": "2.0.*@ALPHA"
75
  },
76
  "type": "library",
77
  "extra": {
@@ -80,8 +137,8 @@
80
  }
81
  },
82
  "autoload": {
83
- "psr-0": {
84
- "Doctrine\\Instantiator\\": "src"
85
  }
86
  },
87
  "notification-url": "https://packagist.org/downloads/",
@@ -101,7 +158,48 @@
101
  "constructor",
102
  "instantiate"
103
  ],
104
- "time": "2014-10-13 12:58:55"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  },
106
  {
107
  "name": "hamcrest/hamcrest-php",
@@ -150,16 +248,16 @@
150
  },
151
  {
152
  "name": "mikey179/vfsStream",
153
- "version": "v1.5.0",
154
  "source": {
155
  "type": "git",
156
  "url": "https://github.com/mikey179/vfsStream.git",
157
- "reference": "4dc0d2f622412f561f5b242b19b98068bbbc883a"
158
  },
159
  "dist": {
160
  "type": "zip",
161
- "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/4dc0d2f622412f561f5b242b19b98068bbbc883a",
162
- "reference": "4dc0d2f622412f561f5b242b19b98068bbbc883a",
163
  "shasum": ""
164
  },
165
  "require": {
@@ -171,7 +269,7 @@
171
  "type": "library",
172
  "extra": {
173
  "branch-alias": {
174
- "dev-master": "1.5.x-dev"
175
  }
176
  },
177
  "autoload": {
@@ -192,7 +290,7 @@
192
  ],
193
  "description": "Virtual file system to mock the real file system in unit tests.",
194
  "homepage": "http://vfs.bovigo.org/",
195
- "time": "2015-03-29 11:19:49"
196
  },
197
  {
198
  "name": "mockery/mockery",
@@ -310,16 +408,16 @@
310
  },
311
  {
312
  "name": "phpspec/prophecy",
313
- "version": "v1.4.1",
314
  "source": {
315
  "type": "git",
316
  "url": "https://github.com/phpspec/prophecy.git",
317
- "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
318
  },
319
  "dist": {
320
  "type": "zip",
321
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
322
- "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
323
  "shasum": ""
324
  },
325
  "require": {
@@ -366,20 +464,20 @@
366
  "spy",
367
  "stub"
368
  ],
369
- "time": "2015-04-27 22:15:08"
370
  },
371
  {
372
  "name": "phpunit/php-code-coverage",
373
- "version": "2.0.16",
374
  "source": {
375
  "type": "git",
376
  "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
377
- "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c"
378
  },
379
  "dist": {
380
  "type": "zip",
381
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c",
382
- "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c",
383
  "shasum": ""
384
  },
385
  "require": {
@@ -387,7 +485,7 @@
387
  "phpunit/php-file-iterator": "~1.3",
388
  "phpunit/php-text-template": "~1.2",
389
  "phpunit/php-token-stream": "~1.3",
390
- "sebastian/environment": "~1.0",
391
  "sebastian/version": "~1.0"
392
  },
393
  "require-dev": {
@@ -402,7 +500,7 @@
402
  "type": "library",
403
  "extra": {
404
  "branch-alias": {
405
- "dev-master": "2.0.x-dev"
406
  }
407
  },
408
  "autoload": {
@@ -428,20 +526,20 @@
428
  "testing",
429
  "xunit"
430
  ],
431
- "time": "2015-04-11 04:35:00"
432
  },
433
  {
434
  "name": "phpunit/php-file-iterator",
435
- "version": "1.4.0",
436
  "source": {
437
  "type": "git",
438
  "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
439
- "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
440
  },
441
  "dist": {
442
  "type": "zip",
443
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
444
- "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
445
  "shasum": ""
446
  },
447
  "require": {
@@ -475,20 +573,20 @@
475
  "filesystem",
476
  "iterator"
477
  ],
478
- "time": "2015-04-02 05:19:05"
479
  },
480
  {
481
  "name": "phpunit/php-text-template",
482
- "version": "1.2.0",
483
  "source": {
484
  "type": "git",
485
  "url": "https://github.com/sebastianbergmann/php-text-template.git",
486
- "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
487
  },
488
  "dist": {
489
  "type": "zip",
490
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
491
- "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
492
  "shasum": ""
493
  },
494
  "require": {
@@ -497,20 +595,17 @@
497
  "type": "library",
498
  "autoload": {
499
  "classmap": [
500
- "Text/"
501
  ]
502
  },
503
  "notification-url": "https://packagist.org/downloads/",
504
- "include-path": [
505
- ""
506
- ],
507
  "license": [
508
  "BSD-3-Clause"
509
  ],
510
  "authors": [
511
  {
512
  "name": "Sebastian Bergmann",
513
- "email": "sb@sebastian-bergmann.de",
514
  "role": "lead"
515
  }
516
  ],
@@ -519,20 +614,20 @@
519
  "keywords": [
520
  "template"
521
  ],
522
- "time": "2014-01-30 17:20:04"
523
  },
524
  {
525
  "name": "phpunit/php-timer",
526
- "version": "1.0.5",
527
  "source": {
528
  "type": "git",
529
  "url": "https://github.com/sebastianbergmann/php-timer.git",
530
- "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
531
  },
532
  "dist": {
533
  "type": "zip",
534
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
535
- "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
536
  "shasum": ""
537
  },
538
  "require": {
@@ -541,13 +636,10 @@
541
  "type": "library",
542
  "autoload": {
543
  "classmap": [
544
- "PHP/"
545
  ]
546
  },
547
  "notification-url": "https://packagist.org/downloads/",
548
- "include-path": [
549
- ""
550
- ],
551
  "license": [
552
  "BSD-3-Clause"
553
  ],
@@ -563,20 +655,20 @@
563
  "keywords": [
564
  "timer"
565
  ],
566
- "time": "2013-08-02 07:42:54"
567
  },
568
  {
569
  "name": "phpunit/php-token-stream",
570
- "version": "1.4.1",
571
  "source": {
572
  "type": "git",
573
  "url": "https://github.com/sebastianbergmann/php-token-stream.git",
574
- "reference": "eab81d02569310739373308137284e0158424330"
575
  },
576
  "dist": {
577
  "type": "zip",
578
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
579
- "reference": "eab81d02569310739373308137284e0158424330",
580
  "shasum": ""
581
  },
582
  "require": {
@@ -612,20 +704,20 @@
612
  "keywords": [
613
  "tokenizer"
614
  ],
615
- "time": "2015-04-08 04:46:07"
616
  },
617
  {
618
  "name": "phpunit/phpunit",
619
- "version": "4.6.6",
620
  "source": {
621
  "type": "git",
622
  "url": "https://github.com/sebastianbergmann/phpunit.git",
623
- "reference": "3afe303d873a4d64c62ef84de491b97b006fbdac"
624
  },
625
  "dist": {
626
  "type": "zip",
627
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3afe303d873a4d64c62ef84de491b97b006fbdac",
628
- "reference": "3afe303d873a4d64c62ef84de491b97b006fbdac",
629
  "shasum": ""
630
  },
631
  "require": {
@@ -635,15 +727,15 @@
635
  "ext-reflection": "*",
636
  "ext-spl": "*",
637
  "php": ">=5.3.3",
638
- "phpspec/prophecy": "~1.3,>=1.3.1",
639
- "phpunit/php-code-coverage": "~2.0,>=2.0.11",
640
  "phpunit/php-file-iterator": "~1.4",
641
  "phpunit/php-text-template": "~1.2",
642
- "phpunit/php-timer": "~1.0",
643
  "phpunit/phpunit-mock-objects": "~2.3",
644
  "sebastian/comparator": "~1.1",
645
  "sebastian/diff": "~1.2",
646
- "sebastian/environment": "~1.2",
647
  "sebastian/exporter": "~1.2",
648
  "sebastian/global-state": "~1.0",
649
  "sebastian/version": "~1.0",
@@ -658,7 +750,7 @@
658
  "type": "library",
659
  "extra": {
660
  "branch-alias": {
661
- "dev-master": "4.6.x-dev"
662
  }
663
  },
664
  "autoload": {
@@ -684,26 +776,27 @@
684
  "testing",
685
  "xunit"
686
  ],
687
- "time": "2015-04-29 15:18:52"
688
  },
689
  {
690
  "name": "phpunit/phpunit-mock-objects",
691
- "version": "2.3.1",
692
  "source": {
693
  "type": "git",
694
  "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
695
- "reference": "74ffb87f527f24616f72460e54b595f508dccb5c"
696
  },
697
  "dist": {
698
  "type": "zip",
699
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/74ffb87f527f24616f72460e54b595f508dccb5c",
700
- "reference": "74ffb87f527f24616f72460e54b595f508dccb5c",
701
  "shasum": ""
702
  },
703
  "require": {
704
- "doctrine/instantiator": "~1.0,>=1.0.2",
705
  "php": ">=5.3.3",
706
- "phpunit/php-text-template": "~1.2"
 
707
  },
708
  "require-dev": {
709
  "phpunit/phpunit": "~4.4"
@@ -739,20 +832,20 @@
739
  "mock",
740
  "xunit"
741
  ],
742
- "time": "2015-04-02 05:36:41"
743
  },
744
  {
745
  "name": "sebastian/comparator",
746
- "version": "1.1.1",
747
  "source": {
748
  "type": "git",
749
  "url": "https://github.com/sebastianbergmann/comparator.git",
750
- "reference": "1dd8869519a225f7f2b9eb663e225298fade819e"
751
  },
752
  "dist": {
753
  "type": "zip",
754
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e",
755
- "reference": "1dd8869519a225f7f2b9eb663e225298fade819e",
756
  "shasum": ""
757
  },
758
  "require": {
@@ -766,7 +859,7 @@
766
  "type": "library",
767
  "extra": {
768
  "branch-alias": {
769
- "dev-master": "1.1.x-dev"
770
  }
771
  },
772
  "autoload": {
@@ -803,7 +896,7 @@
803
  "compare",
804
  "equality"
805
  ],
806
- "time": "2015-01-29 16:28:08"
807
  },
808
  {
809
  "name": "sebastian/diff",
@@ -859,16 +952,16 @@
859
  },
860
  {
861
  "name": "sebastian/environment",
862
- "version": "1.2.2",
863
  "source": {
864
  "type": "git",
865
  "url": "https://github.com/sebastianbergmann/environment.git",
866
- "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
867
  },
868
  "dist": {
869
  "type": "zip",
870
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
871
- "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
872
  "shasum": ""
873
  },
874
  "require": {
@@ -905,20 +998,20 @@
905
  "environment",
906
  "hhvm"
907
  ],
908
- "time": "2015-01-01 10:01:08"
909
  },
910
  {
911
  "name": "sebastian/exporter",
912
- "version": "1.2.0",
913
  "source": {
914
  "type": "git",
915
  "url": "https://github.com/sebastianbergmann/exporter.git",
916
- "reference": "84839970d05254c73cde183a721c7af13aede943"
917
  },
918
  "dist": {
919
  "type": "zip",
920
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943",
921
- "reference": "84839970d05254c73cde183a721c7af13aede943",
922
  "shasum": ""
923
  },
924
  "require": {
@@ -971,20 +1064,20 @@
971
  "export",
972
  "exporter"
973
  ],
974
- "time": "2015-01-27 07:23:06"
975
  },
976
  {
977
  "name": "sebastian/global-state",
978
- "version": "1.0.0",
979
  "source": {
980
  "type": "git",
981
  "url": "https://github.com/sebastianbergmann/global-state.git",
982
- "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01"
983
  },
984
  "dist": {
985
  "type": "zip",
986
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
987
- "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
988
  "shasum": ""
989
  },
990
  "require": {
@@ -1022,20 +1115,20 @@
1022
  "keywords": [
1023
  "global state"
1024
  ],
1025
- "time": "2014-10-06 09:23:50"
1026
  },
1027
  {
1028
  "name": "sebastian/recursion-context",
1029
- "version": "1.0.0",
1030
  "source": {
1031
  "type": "git",
1032
  "url": "https://github.com/sebastianbergmann/recursion-context.git",
1033
- "reference": "3989662bbb30a29d20d9faa04a846af79b276252"
1034
  },
1035
  "dist": {
1036
  "type": "zip",
1037
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252",
1038
- "reference": "3989662bbb30a29d20d9faa04a846af79b276252",
1039
  "shasum": ""
1040
  },
1041
  "require": {
@@ -1075,20 +1168,20 @@
1075
  ],
1076
  "description": "Provides functionality to recursively process PHP variables",
1077
  "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1078
- "time": "2015-01-24 09:48:32"
1079
  },
1080
  {
1081
  "name": "sebastian/version",
1082
- "version": "1.0.5",
1083
  "source": {
1084
  "type": "git",
1085
  "url": "https://github.com/sebastianbergmann/version.git",
1086
- "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
1087
  },
1088
  "dist": {
1089
  "type": "zip",
1090
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
1091
- "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
1092
  "shasum": ""
1093
  },
1094
  "type": "library",
@@ -1110,37 +1203,33 @@
1110
  ],
1111
  "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1112
  "homepage": "https://github.com/sebastianbergmann/version",
1113
- "time": "2015-02-24 06:35:25"
1114
  },
1115
  {
1116
  "name": "symfony/yaml",
1117
- "version": "v2.6.7",
1118
- "target-dir": "Symfony/Component/Yaml",
1119
  "source": {
1120
  "type": "git",
1121
- "url": "https://github.com/symfony/Yaml.git",
1122
- "reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2"
1123
  },
1124
  "dist": {
1125
  "type": "zip",
1126
- "url": "https://api.github.com/repos/symfony/Yaml/zipball/f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
1127
- "reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
1128
  "shasum": ""
1129
  },
1130
  "require": {
1131
- "php": ">=5.3.3"
1132
- },
1133
- "require-dev": {
1134
- "symfony/phpunit-bridge": "~2.7"
1135
  },
1136
  "type": "library",
1137
  "extra": {
1138
  "branch-alias": {
1139
- "dev-master": "2.6-dev"
1140
  }
1141
  },
1142
  "autoload": {
1143
- "psr-0": {
1144
  "Symfony\\Component\\Yaml\\": ""
1145
  }
1146
  },
@@ -1160,7 +1249,7 @@
1160
  ],
1161
  "description": "Symfony Yaml Component",
1162
  "homepage": "https://symfony.com",
1163
- "time": "2015-05-02 15:18:45"
1164
  }
1165
  ],
1166
  "aliases": [],
@@ -1168,6 +1257,8 @@
1168
  "stability-flags": [],
1169
  "prefer-stable": false,
1170
  "prefer-lowest": false,
1171
- "platform": [],
 
 
1172
  "platform-dev": []
1173
  }
4
  "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
  "This file is @generated automatically"
6
  ],
7
+ "hash": "ae7fd61a1dd5aff668e00bbc8cc907ae",
8
  "packages": [
9
  {
10
+ "name": "composer/installers",
11
+ "version": "v1.0.22",
12
  "source": {
13
  "type": "git",
14
+ "url": "https://github.com/composer/installers.git",
15
+ "reference": "bd9b14f094c89c8b5804a4e41edeb7853bb85046"
16
  },
17
  "dist": {
18
  "type": "zip",
19
+ "url": "https://api.github.com/repos/composer/installers/zipball/bd9b14f094c89c8b5804a4e41edeb7853bb85046",
20
+ "reference": "bd9b14f094c89c8b5804a4e41edeb7853bb85046",
21
  "shasum": ""
22
  },
23
  "require": {
24
+ "composer-plugin-api": "1.0.0"
25
+ },
26
+ "replace": {
27
+ "roundcube/plugin-installer": "*",
28
+ "shama/baton": "*"
29
  },
30
  "require-dev": {
31
+ "composer/composer": "1.0.*@dev",
32
+ "phpunit/phpunit": "4.1.*"
33
+ },
34
+ "type": "composer-plugin",
35
+ "extra": {
36
+ "class": "Composer\\Installers\\Plugin",
37
+ "branch-alias": {
38
+ "dev-master": "1.0-dev"
39
+ }
40
  },
 
41
  "autoload": {
42
+ "psr-0": {
43
+ "Composer\\Installers\\": "src/"
44
+ }
45
  },
46
  "notification-url": "https://packagist.org/downloads/",
47
  "license": [
48
+ "MIT"
49
  ],
50
+ "authors": [
51
+ {
52
+ "name": "Kyle Robinson Young",
53
+ "email": "kyle@dontkry.com",
54
+ "homepage": "https://github.com/shama"
55
+ }
56
+ ],
57
+ "description": "A multi-framework Composer library installer",
58
+ "homepage": "http://composer.github.com/installers/",
59
  "keywords": [
60
+ "Craft",
61
+ "Dolibarr",
62
+ "Hurad",
63
+ "MODX Evo",
64
+ "OXID",
65
+ "SMF",
66
+ "Thelia",
67
+ "WolfCMS",
68
+ "agl",
69
+ "aimeos",
70
+ "annotatecms",
71
+ "bitrix",
72
+ "cakephp",
73
+ "chef",
74
+ "codeigniter",
75
+ "concrete5",
76
+ "croogo",
77
+ "dokuwiki",
78
+ "drupal",
79
+ "elgg",
80
+ "fuelphp",
81
+ "grav",
82
+ "installer",
83
+ "joomla",
84
+ "kohana",
85
+ "laravel",
86
+ "lithium",
87
+ "magento",
88
+ "mako",
89
+ "mediawiki",
90
+ "modulework",
91
+ "moodle",
92
+ "phpbb",
93
+ "piwik",
94
+ "ppi",
95
+ "puppet",
96
+ "roundcube",
97
+ "shopware",
98
+ "silverstripe",
99
+ "symfony",
100
+ "typo3",
101
+ "wordpress",
102
+ "zend",
103
+ "zikula"
104
  ],
105
+ "time": "2015-10-29 23:28:48"
106
  }
107
  ],
108
  "packages-dev": [
109
  {
110
  "name": "doctrine/instantiator",
111
+ "version": "1.0.5",
112
  "source": {
113
  "type": "git",
114
  "url": "https://github.com/doctrine/instantiator.git",
115
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
116
  },
117
  "dist": {
118
  "type": "zip",
119
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
120
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
121
  "shasum": ""
122
  },
123
  "require": {
128
  "ext-pdo": "*",
129
  "ext-phar": "*",
130
  "phpunit/phpunit": "~4.0",
131
+ "squizlabs/php_codesniffer": "~2.0"
132
  },
133
  "type": "library",
134
  "extra": {
137
  }
138
  },
139
  "autoload": {
140
+ "psr-4": {
141
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
142
  }
143
  },
144
  "notification-url": "https://packagist.org/downloads/",
158
  "constructor",
159
  "instantiate"
160
  ],
161
+ "time": "2015-06-14 21:17:01"
162
+ },
163
+ {
164
+ "name": "facebook/webdriver",
165
+ "version": "v0.5.1",
166
+ "source": {
167
+ "type": "git",
168
+ "url": "https://github.com/facebook/php-webdriver.git",
169
+ "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509"
170
+ },
171
+ "dist": {
172
+ "type": "zip",
173
+ "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bbcb697efb394d17bd9ec3d467e7da847cde4509",
174
+ "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509",
175
+ "shasum": ""
176
+ },
177
+ "require": {
178
+ "php": ">=5.3.19"
179
+ },
180
+ "require-dev": {
181
+ "phpdocumentor/phpdocumentor": "2.*",
182
+ "phpunit/phpunit": "3.7.*"
183
+ },
184
+ "type": "library",
185
+ "autoload": {
186
+ "classmap": [
187
+ "lib/"
188
+ ]
189
+ },
190
+ "notification-url": "https://packagist.org/downloads/",
191
+ "license": [
192
+ "Apache-2.0"
193
+ ],
194
+ "description": "A php client for WebDriver",
195
+ "homepage": "https://github.com/facebook/php-webdriver",
196
+ "keywords": [
197
+ "facebook",
198
+ "php",
199
+ "selenium",
200
+ "webdriver"
201
+ ],
202
+ "time": "2014-11-05 20:53:09"
203
  },
204
  {
205
  "name": "hamcrest/hamcrest-php",
248
  },
249
  {
250
  "name": "mikey179/vfsStream",
251
+ "version": "v1.6.0",
252
  "source": {
253
  "type": "git",
254
  "url": "https://github.com/mikey179/vfsStream.git",
255
+ "reference": "73bcb605b741a7d5044b47592338c633788b0eb7"
256
  },
257
  "dist": {
258
  "type": "zip",
259
+ "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/73bcb605b741a7d5044b47592338c633788b0eb7",
260
+ "reference": "73bcb605b741a7d5044b47592338c633788b0eb7",
261
  "shasum": ""
262
  },
263
  "require": {
269
  "type": "library",
270
  "extra": {
271
  "branch-alias": {
272
+ "dev-master": "1.6.x-dev"
273
  }
274
  },
275
  "autoload": {
290
  ],
291
  "description": "Virtual file system to mock the real file system in unit tests.",
292
  "homepage": "http://vfs.bovigo.org/",
293
+ "time": "2015-10-06 16:59:57"
294
  },
295
  {
296
  "name": "mockery/mockery",
408
  },
409
  {
410
  "name": "phpspec/prophecy",
411
+ "version": "v1.5.0",
412
  "source": {
413
  "type": "git",
414
  "url": "https://github.com/phpspec/prophecy.git",
415
+ "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
416
  },
417
  "dist": {
418
  "type": "zip",
419
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
420
+ "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
421
  "shasum": ""
422
  },
423
  "require": {
464
  "spy",
465
  "stub"
466
  ],
467
+ "time": "2015-08-13 10:07:40"
468
  },
469
  {
470
  "name": "phpunit/php-code-coverage",
471
+ "version": "2.2.4",
472
  "source": {
473
  "type": "git",
474
  "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
475
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
476
  },
477
  "dist": {
478
  "type": "zip",
479
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
480
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
481
  "shasum": ""
482
  },
483
  "require": {
485
  "phpunit/php-file-iterator": "~1.3",
486
  "phpunit/php-text-template": "~1.2",
487
  "phpunit/php-token-stream": "~1.3",
488
+ "sebastian/environment": "^1.3.2",
489
  "sebastian/version": "~1.0"
490
  },
491
  "require-dev": {
500
  "type": "library",
501
  "extra": {
502
  "branch-alias": {
503
+ "dev-master": "2.2.x-dev"
504
  }
505
  },
506
  "autoload": {
526
  "testing",
527
  "xunit"
528
  ],
529
+ "time": "2015-10-06 15:47:00"
530
  },
531
  {
532
  "name": "phpunit/php-file-iterator",
533
+ "version": "1.4.1",
534
  "source": {
535
  "type": "git",
536
  "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
537
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
538
  },
539
  "dist": {
540
  "type": "zip",
541
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
542
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
543
  "shasum": ""
544
  },
545
  "require": {
573
  "filesystem",
574
  "iterator"
575
  ],
576
+ "time": "2015-06-21 13:08:43"
577
  },
578
  {
579
  "name": "phpunit/php-text-template",
580
+ "version": "1.2.1",
581
  "source": {
582
  "type": "git",
583
  "url": "https://github.com/sebastianbergmann/php-text-template.git",
584
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
585
  },
586
  "dist": {
587
  "type": "zip",
588
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
589
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
590
  "shasum": ""
591
  },
592
  "require": {
595
  "type": "library",
596
  "autoload": {
597
  "classmap": [
598
+ "src/"
599
  ]
600
  },
601
  "notification-url": "https://packagist.org/downloads/",
 
 
 
602
  "license": [
603
  "BSD-3-Clause"
604
  ],
605
  "authors": [
606
  {
607
  "name": "Sebastian Bergmann",
608
+ "email": "sebastian@phpunit.de",
609
  "role": "lead"
610
  }
611
  ],
614
  "keywords": [
615
  "template"
616
  ],
617
+ "time": "2015-06-21 13:50:34"
618
  },
619
  {
620
  "name": "phpunit/php-timer",
621
+ "version": "1.0.7",
622
  "source": {
623
  "type": "git",
624
  "url": "https://github.com/sebastianbergmann/php-timer.git",
625
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
626
  },
627
  "dist": {
628
  "type": "zip",
629
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
630
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
631
  "shasum": ""
632
  },
633
  "require": {
636
  "type": "library",
637
  "autoload": {
638
  "classmap": [
639
+ "src/"
640
  ]
641
  },
642
  "notification-url": "https://packagist.org/downloads/",
 
 
 
643
  "license": [
644
  "BSD-3-Clause"
645
  ],
655
  "keywords": [
656
  "timer"
657
  ],
658
+ "time": "2015-06-21 08:01:12"
659
  },
660
  {
661
  "name": "phpunit/php-token-stream",
662
+ "version": "1.4.8",
663
  "source": {
664
  "type": "git",
665
  "url": "https://github.com/sebastianbergmann/php-token-stream.git",
666
+ "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
667
  },
668
  "dist": {
669
  "type": "zip",
670
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
671
+ "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
672
  "shasum": ""
673
  },
674
  "require": {
704
  "keywords": [
705
  "tokenizer"
706
  ],
707
+ "time": "2015-09-15 10:49:45"
708
  },
709
  {
710
  "name": "phpunit/phpunit",
711
+ "version": "4.8.18",
712
  "source": {
713
  "type": "git",
714
  "url": "https://github.com/sebastianbergmann/phpunit.git",
715
+ "reference": "fa33d4ad96481b91df343d83e8c8aabed6b1dfd3"
716
  },
717
  "dist": {
718
  "type": "zip",
719
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fa33d4ad96481b91df343d83e8c8aabed6b1dfd3",
720
+ "reference": "fa33d4ad96481b91df343d83e8c8aabed6b1dfd3",
721
  "shasum": ""
722
  },
723
  "require": {
727
  "ext-reflection": "*",
728
  "ext-spl": "*",
729
  "php": ">=5.3.3",
730
+ "phpspec/prophecy": "^1.3.1",
731
+ "phpunit/php-code-coverage": "~2.1",
732
  "phpunit/php-file-iterator": "~1.4",
733
  "phpunit/php-text-template": "~1.2",
734
+ "phpunit/php-timer": ">=1.0.6",
735
  "phpunit/phpunit-mock-objects": "~2.3",
736
  "sebastian/comparator": "~1.1",
737
  "sebastian/diff": "~1.2",
738
+ "sebastian/environment": "~1.3",
739
  "sebastian/exporter": "~1.2",
740
  "sebastian/global-state": "~1.0",
741
  "sebastian/version": "~1.0",
750
  "type": "library",
751
  "extra": {
752
  "branch-alias": {
753
+ "dev-master": "4.8.x-dev"
754
  }
755
  },
756
  "autoload": {
776
  "testing",
777
  "xunit"
778
  ],
779
+ "time": "2015-11-11 11:32:49"
780
  },
781
  {
782
  "name": "phpunit/phpunit-mock-objects",
783
+ "version": "2.3.8",
784
  "source": {
785
  "type": "git",
786
  "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
787
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
788
  },
789
  "dist": {
790
  "type": "zip",
791
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
792
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
793
  "shasum": ""
794
  },
795
  "require": {
796
+ "doctrine/instantiator": "^1.0.2",
797
  "php": ">=5.3.3",
798
+ "phpunit/php-text-template": "~1.2",
799
+ "sebastian/exporter": "~1.2"
800
  },
801
  "require-dev": {
802
  "phpunit/phpunit": "~4.4"
832
  "mock",
833
  "xunit"
834
  ],
835
+ "time": "2015-10-02 06:51:40"
836
  },
837
  {
838
  "name": "sebastian/comparator",
839
+ "version": "1.2.0",
840
  "source": {
841
  "type": "git",
842
  "url": "https://github.com/sebastianbergmann/comparator.git",
843
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
844
  },
845
  "dist": {
846
  "type": "zip",
847
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
848
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
849
  "shasum": ""
850
  },
851
  "require": {
859
  "type": "library",
860
  "extra": {
861
  "branch-alias": {
862
+ "dev-master": "1.2.x-dev"
863
  }
864
  },
865
  "autoload": {
896
  "compare",
897
  "equality"
898
  ],
899
+ "time": "2015-07-26 15:48:44"
900
  },
901
  {
902
  "name": "sebastian/diff",
952
  },
953
  {
954
  "name": "sebastian/environment",
955
+ "version": "1.3.2",
956
  "source": {
957
  "type": "git",
958
  "url": "https://github.com/sebastianbergmann/environment.git",
959
+ "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44"
960
  },
961
  "dist": {
962
  "type": "zip",
963
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44",
964
+ "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44",
965
  "shasum": ""
966
  },
967
  "require": {
998
  "environment",
999
  "hhvm"
1000
  ],
1001
+ "time": "2015-08-03 06:14:51"
1002
  },
1003
  {
1004
  "name": "sebastian/exporter",
1005
+ "version": "1.2.1",
1006
  "source": {
1007
  "type": "git",
1008
  "url": "https://github.com/sebastianbergmann/exporter.git",
1009
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
1010
  },
1011
  "dist": {
1012
  "type": "zip",
1013
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
1014
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
1015
  "shasum": ""
1016
  },
1017
  "require": {
1064
  "export",
1065
  "exporter"
1066
  ],
1067
+ "time": "2015-06-21 07:55:53"
1068
  },
1069
  {
1070
  "name": "sebastian/global-state",
1071
+ "version": "1.1.1",
1072
  "source": {
1073
  "type": "git",
1074
  "url": "https://github.com/sebastianbergmann/global-state.git",
1075
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
1076
  },
1077
  "dist": {
1078
  "type": "zip",
1079
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
1080
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
1081
  "shasum": ""
1082
  },
1083
  "require": {
1115
  "keywords": [
1116
  "global state"
1117
  ],
1118
+ "time": "2015-10-12 03:26:01"
1119
  },
1120
  {
1121
  "name": "sebastian/recursion-context",
1122
+ "version": "1.0.1",
1123
  "source": {
1124
  "type": "git",
1125
  "url": "https://github.com/sebastianbergmann/recursion-context.git",
1126
+ "reference": "994d4a811bafe801fb06dccbee797863ba2792ba"
1127
  },
1128
  "dist": {
1129
  "type": "zip",
1130
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/994d4a811bafe801fb06dccbee797863ba2792ba",
1131
+ "reference": "994d4a811bafe801fb06dccbee797863ba2792ba",
1132
  "shasum": ""
1133
  },
1134
  "require": {
1168
  ],
1169
  "description": "Provides functionality to recursively process PHP variables",
1170
  "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1171
+ "time": "2015-06-21 08:04:50"
1172
  },
1173
  {
1174
  "name": "sebastian/version",
1175
+ "version": "1.0.6",
1176
  "source": {
1177
  "type": "git",
1178
  "url": "https://github.com/sebastianbergmann/version.git",
1179
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
1180
  },
1181
  "dist": {
1182
  "type": "zip",
1183
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1184
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1185
  "shasum": ""
1186
  },
1187
  "type": "library",
1203
  ],
1204
  "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1205
  "homepage": "https://github.com/sebastianbergmann/version",
1206
+ "time": "2015-06-21 13:59:46"
1207
  },
1208
  {
1209
  "name": "symfony/yaml",
1210
+ "version": "v2.7.6",
 
1211
  "source": {
1212
  "type": "git",
1213
+ "url": "https://github.com/symfony/yaml.git",
1214
+ "reference": "eca9019c88fbe250164affd107bc8057771f3f4d"
1215
  },
1216
  "dist": {
1217
  "type": "zip",
1218
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/eca9019c88fbe250164affd107bc8057771f3f4d",
1219
+ "reference": "eca9019c88fbe250164affd107bc8057771f3f4d",
1220
  "shasum": ""
1221
  },
1222
  "require": {
1223
+ "php": ">=5.3.9"
 
 
 
1224
  },
1225
  "type": "library",
1226
  "extra": {
1227
  "branch-alias": {
1228
+ "dev-master": "2.7-dev"
1229
  }
1230
  },
1231
  "autoload": {
1232
+ "psr-4": {
1233
  "Symfony\\Component\\Yaml\\": ""
1234
  }
1235
  },
1249
  ],
1250
  "description": "Symfony Yaml Component",
1251
  "homepage": "https://symfony.com",
1252
+ "time": "2015-10-11 09:39:48"
1253
  }
1254
  ],
1255
  "aliases": [],
1257
  "stability-flags": [],
1258
  "prefer-stable": false,
1259
  "prefer-lowest": false,
1260
+ "platform": {
1261
+ "php": ">=5.3.0"
1262
+ },
1263
  "platform-dev": []
1264
  }
config/Dockerfile-phantomjs CHANGED
@@ -1,17 +1,5 @@
1
- FROM ubuntu:14.04
2
 
3
  EXPOSE 8910
4
 
5
- ENV PHANTOM_JS_VERSION 1.9.7-linux-x86_64
6
-
7
- RUN apt-get update
8
- RUN apt-get install -yqq curl libfreetype6 libfontconfig
9
- # make ruby python git g++ flex bison gperf perl \
10
- # libfontconfig1-dev libicu-dev libfreetype6 \
11
- # libssl-dev libpng-dev libjpeg-dev
12
- # RUN git clone git://github.com/ariya/phantomjs.git && cd phantomjs && ./build.sh && send "y\n"
13
-
14
- RUN curl -sSL https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$PHANTOM_JS_VERSION.tar.bz2 | tar xjC /
15
- RUN ln -s phantomjs-$PHANTOM_JS_VERSION /phantomjs
16
-
17
- CMD ["/phantomjs/bin/phantomjs", "--webdriver=8910"]
1
+ FROM servebox/phantomjs:latest
2
 
3
  EXPOSE 8910
4
 
5
+ CMD ["phantomjs", "--webdriver=8910"]
 
 
 
 
 
 
 
 
 
 
 
 
config/Dockerfile-wordpress-37 CHANGED
@@ -2,9 +2,9 @@ FROM wordpress:4
2
 
3
  RUN docker-php-ext-install mysql
4
 
5
- ENV WORDPRESS_VERSION 3.7.8
6
- ENV WORDPRESS_UPSTREAM_VERSION 3.7.8
7
- ENV WORDPRESS_SHA1 f6a326bc7fe8805a142d3c3e5db7857c336d8a75
8
 
9
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
10
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
2
 
3
  RUN docker-php-ext-install mysql
4
 
5
+ ENV WORDPRESS_VERSION 3.7.11
6
+ ENV WORDPRESS_UPSTREAM_VERSION 3.7.11
7
+ ENV WORDPRESS_SHA1 7b331b23756520beee83fa1530a1e43bf510b5c5
8
 
9
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
10
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-38 CHANGED
@@ -2,9 +2,9 @@ FROM wordpress:4
2
 
3
  RUN docker-php-ext-install mysql
4
 
5
- ENV WORDPRESS_VERSION 3.8.8
6
- ENV WORDPRESS_UPSTREAM_VERSION 3.8.8
7
- ENV WORDPRESS_SHA1 8c5875ae76cdc9fb545e9e30591c67021bb1fafd
8
 
9
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
10
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
2
 
3
  RUN docker-php-ext-install mysql
4
 
5
+ ENV WORDPRESS_VERSION 3.8.11
6
+ ENV WORDPRESS_UPSTREAM_VERSION 3.8.11
7
+ ENV WORDPRESS_SHA1 d58349c2aea01aa97ce4452bfe62347a9b82d28a
8
 
9
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
10
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-39 CHANGED
@@ -1,8 +1,8 @@
1
  FROM wordpress:4
2
 
3
- ENV WORDPRESS_VERSION 3.9.6
4
- ENV WORDPRESS_UPSTREAM_VERSION 3.9.6
5
- ENV WORDPRESS_SHA1 373c185080d0e3b2cd748277d013894e8a3af0d9
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
1
  FROM wordpress:4
2
 
3
+ ENV WORDPRESS_VERSION 3.9.9
4
+ ENV WORDPRESS_UPSTREAM_VERSION 3.9.9
5
+ ENV WORDPRESS_SHA1 559edda1c178879d73ad234b098b8080506fbd71
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-40 CHANGED
@@ -1,8 +1,8 @@
1
  FROM wordpress:4
2
 
3
- ENV WORDPRESS_VERSION 4.0.5
4
- ENV WORDPRESS_UPSTREAM_VERSION 4.0.5
5
- ENV WORDPRESS_SHA1 23de8e24ea68a19723b6ebc95f44c8d32df97a8e
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
1
  FROM wordpress:4
2
 
3
+ ENV WORDPRESS_VERSION 4.0.8
4
+ ENV WORDPRESS_UPSTREAM_VERSION 4.0.8
5
+ ENV WORDPRESS_SHA1 6a3511025d9b9ccfec45efdad27d67a85ecce595
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-41 CHANGED
@@ -1,8 +1,8 @@
1
  FROM wordpress:4
2
 
3
- ENV WORDPRESS_VERSION 4.1.5
4
- ENV WORDPRESS_UPSTREAM_VERSION 4.1.5
5
- ENV WORDPRESS_SHA1 85bc3f20d0ee8c98f9eabeba48eb37fe732eab33
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
1
  FROM wordpress:4
2
 
3
+ ENV WORDPRESS_VERSION 4.1.8
4
+ ENV WORDPRESS_UPSTREAM_VERSION 4.1.8
5
+ ENV WORDPRESS_SHA1 f3dc8f554312eeee5145c7eaaf85506e01a3d738
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-42 CHANGED
@@ -1,8 +1,8 @@
1
  FROM wordpress:4
2
 
3
- ENV WORDPRESS_VERSION 4.2.2
4
- ENV WORDPRESS_UPSTREAM_VERSION 4.2.2
5
- ENV WORDPRESS_SHA1 d3a70d0f116e6afea5b850f793a81a97d2115039
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
1
  FROM wordpress:4
2
 
3
+ ENV WORDPRESS_VERSION 4.2.5
4
+ ENV WORDPRESS_UPSTREAM_VERSION 4.2.5
5
+ ENV WORDPRESS_SHA1 a8944f75f51b4687648a9a272e15dc17b9e25577
6
 
7
  # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
  RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
config/Dockerfile-wordpress-43 ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM wordpress:4
2
+
3
+ ENV WORDPRESS_VERSION 4.3.1
4
+ ENV WORDPRESS_UPSTREAM_VERSION 4.3.1
5
+ ENV WORDPRESS_SHA1 b2e5652a6d2333cabe7b37459362a3e5b8b66221
6
+
7
+ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
8
+ RUN curl -o wordpress.tar.gz -sSL https://wordpress.org/wordpress-${WORDPRESS_UPSTREAM_VERSION}.tar.gz \
9
+ && echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c - \
10
+ && tar -xzf wordpress.tar.gz -C /usr/src/ \
11
+ && rm wordpress.tar.gz \
12
+ && chown -R www-data:www-data /usr/src/wordpress
13
+
14
+ ENTRYPOINT ["/entrypoint.sh"]
15
+ CMD ["apache2-foreground"]
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Compress JPEG & PNG images ===
2
  Contributors: TinyPNG
3
  Donate link: https://tinypng.com/
4
- Tags: compress, optimize, shrink, improve, images, tinypng, tinyjpg, jpeg, jpg, png, lossy, jpegmini, crunch, minify, smush, save, bandwidth, website, speed, faster, performance, panda
5
  Requires at least: 3.0.6
6
- Tested up to: 4.2
7
- Stable tag: 1.3.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -16,14 +16,17 @@ Make your website faster by compressing your JPEG and PNG images. This plugin au
16
 
17
  = Features =
18
 
19
- * Automatically compress new images.
20
- * Easy bulk compression of your existing media library.
21
  * Compress individual images already in your media library.
 
 
 
22
  * Multisite support with a single API key.
 
23
  * See your usage directly from the media settings and during bulk compression.
24
- * Select which thumbnail sizes of an image may be compressed.
25
- * Automatic detection of images that can be recompressed.
26
- * No file size limit.
27
 
28
  = How does it work? =
29
 
@@ -31,7 +34,7 @@ After you upload an image to your WordPress site, each resized image is uploaded
31
 
32
  = Getting started =
33
 
34
- Install this plugin and obtain your free API key from https://tinypng.com/developers. The first 500 compressions per month are completely free, so roughly 100 images can be uploaded to WordPress for free, no strings attached! You can also change which of the generated thumbnail sizes should be compressed, because each one of them counts as a compression. And if you’re a heavy user, you can compress more than 500 images per month for a small additional fee per image.
35
 
36
  = Multisite support =
37
 
@@ -79,40 +82,65 @@ The API key can also be configured in wp-config.php. You can add a TINY_API_KEY
79
 
80
  == Frequently Asked Questions ==
81
 
82
- = Q: I don't recall uploading 500 photos this month but my limit is already reached. How is this number calculated? =
83
- A: When you upload an image to your website, Wordpress will create different sized versions of it (see Settings > Media). The plugin will compress each of these sizes, so when you have 100 images and 5 different sizes you will do 500 compressions.
84
 
85
  = Q: What happens to the compressed images when I uninstall the plugin? =
86
  A: When you remove the TinyPNG plugin all your compressed images will remain compressed.
87
 
 
 
 
88
  = Q: Is there a file size limit? =
89
  A: No. There are no limitations on the size of the images you want to compress.
90
 
91
  = Q: What happens when I reach my monthly compression limit? =
92
  A: Everything will keep on working, but newly uploaded images will not be compressed. Of course we encourage everyone to sign up for a full subscription.
93
 
 
 
 
94
  == Changelog ==
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  = 1.3.1 =
97
- * Media library now shows when files are in the process of being compressed.
98
 
99
  = 1.3.0 =
100
- * Improved bulk compressions from media library. You can now also bulk compress your whole media library in one step.
101
- * Intelligent detection if file is already compressed or was altered by another plugin and should be recompressed.
 
102
 
103
  = 1.2.1 =
104
- * Bugfix that prevents recompressing the original when no additional image sizes can be found in the metadata. (introduced in 1.2.0)
105
 
106
  = 1.2.0 =
107
- * Display connection status and number of compressions this month on the settings page. This also allows you to check if you entered a valid API key.
108
- * Show a notice to administrators when reaching the monthly compression limit (in case you're on a fixed or free plan).
109
- * The plugin will now work when php's parse_ini_file is disabled on your host.
110
- * Bugfix that avoids a warning when no additional image sizes can be found in the metadata.
 
111
 
112
  = 1.1.0 =
113
  * The API key can now be set with the TINY_API_KEY constant in wp-config.php. This will work for normal and multisite WordPress installations.
114
- * You can now enable or disable compression of the original uploaded image. If you upgrade the plugin from version 1.0 you may need to go to media settings to include it for compression.
115
- * Improved display of original sizes and compressed sizes showing the total size of all compressed images in media library list view.
116
 
117
  = 1.0.0 =
118
  * Initial version.
1
  === Compress JPEG & PNG images ===
2
  Contributors: TinyPNG
3
  Donate link: https://tinypng.com/
4
+ Tags: compress, optimize, shrink, resize, fit, scale, improve, images, tinypng, tinyjpg, jpeg, jpg, png, lossy, jpegmini, crunch, minify, smush, save, bandwidth, website, speed, faster, performance, panda, wordpress app
5
  Requires at least: 3.0.6
6
+ Tested up to: 4.4
7
+ Stable tag: 1.6.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
16
 
17
  = Features =
18
 
19
+ * Automatically compress new images on upload.
 
20
  * Compress individual images already in your media library.
21
+ * Easy bulk compression of your existing media library.
22
+ * Resize large original images by setting a maximum width and/or height.
23
+ * Select which thumbnail sizes of an image may be compressed.
24
  * Multisite support with a single API key.
25
+ * Color profiles are translated to the standard RGB color space.
26
  * See your usage directly from the media settings and during bulk compression.
27
+ * Convert CMYK to RGB to save more space and maximize compatibility.
28
+ * Compress and resize uploads with the WordPress mobile app.
29
+ * No file size limits.
30
 
31
  = How does it work? =
32
 
34
 
35
  = Getting started =
36
 
37
+ Install this plugin and obtain your free API key from https://tinypng.com/developers. With a free account you can compress **roughly 100 images each month** (based on a regular WordPress installation). The exact number depends on the number of thumbnail sizes you use. You can change which of the generated thumbnail sizes should be compressed, because each one of them counts as a compression. And if you’re a heavy user, you can compress more images for a small additional fee per image.
38
 
39
  = Multisite support =
40
 
82
 
83
  == Frequently Asked Questions ==
84
 
85
+ = Q: How many images can I compress for free? =
86
+ In a default Wordpress installation you can compress around 100 images for free each month. WordPress creates different sized versions of your images which all have to be compressed. Some plugins even add more sizes, so take a look at the Settings > Media page before you start compressing.
87
 
88
  = Q: What happens to the compressed images when I uninstall the plugin? =
89
  A: When you remove the TinyPNG plugin all your compressed images will remain compressed.
90
 
91
+ = Q: I don't recall uploading 500 photos this month but my limit is already reached. How is this number calculated? =
92
+ A: When you upload an image to your website, WordPress will create different sized versions of it (see Settings > Media). The plugin will compress each of these sizes, so when you have 100 images and 5 different sizes you will do 500 compressions.
93
+
94
  = Q: Is there a file size limit? =
95
  A: No. There are no limitations on the size of the images you want to compress.
96
 
97
  = Q: What happens when I reach my monthly compression limit? =
98
  A: Everything will keep on working, but newly uploaded images will not be compressed. Of course we encourage everyone to sign up for a full subscription.
99
 
100
+ = Q: Can I compress all existing images in my media library? =
101
+ A: Yes! After installing the plugin, go to Media > Compress All Images, and click on the button to compress all uncompressed images in your media library.
102
+
103
  == Changelog ==
104
 
105
+ = 1.6.0 =
106
+ * Improved compression status in the Media Library with new details window.
107
+ * Show total compression savings on the Media Settings page with link to bulk compression page when no images have been compressed yet.
108
+ * Moved Compress All Images from the Tools to the Media menu.
109
+
110
+ = 1.5.0 =
111
+ * Resize original images by specifying a maximum width and/or height. During compression your original images will also be scaled down if they are bigger.
112
+ * Support for the mobile WordPress app (thanks to David Goodwin).
113
+
114
+ = 1.4.0 =
115
+ * Indication of the number of images you can compress for free each month.
116
+ * Link to the Media Settings page from the plugin listing.
117
+ * Clarification that original images will be overwritten when compressed.
118
+
119
+ = 1.3.2 =
120
+ * Detect different thumbnail sizes with the same dimensions so they will not be compressed again.
121
+
122
  = 1.3.1 =
123
+ * Media library shows files that are in the process of compression.
124
 
125
  = 1.3.0 =
126
+ * Improved bulk compression from media library. Bulk compress your whole media library in one step.
127
+ * Better indication of image sizes that have been compressed.
128
+ * Detection of image sizes modified after compression by other plugins.
129
 
130
  = 1.2.1 =
131
+ * Prevent compressing the original image if it is the only selected image size.
132
 
133
  = 1.2.0 =
134
+ * Show if you entered a valid API key.
135
+ * Display connection status and number of compressions this month.
136
+ * Show a notice to administrators when the free compression limit is reached.
137
+ * The plugin now works when php's parse_ini_file is disabled on your host.
138
+ * Avoid warnings when no image thumbnail sizes have been selected.
139
 
140
  = 1.1.0 =
141
  * The API key can now be set with the TINY_API_KEY constant in wp-config.php. This will work for normal and multisite WordPress installations.
142
+ * Enable or disable compression of the original uploaded image.
143
+ * Improved display of original sizes and compressed sizes showing the total compression size in the Media Library list view.
144
 
145
  = 1.0.0 =
146
  * Initial version.
src/class-tiny-compress-curl.php CHANGED
@@ -45,39 +45,50 @@ class Tiny_Compress_Curl extends Tiny_Compress {
45
  $request = curl_init();
46
  curl_setopt_array($request, $this->shrink_options($input));
47
 
48
- $output_url = null;
49
  $response = curl_exec($request);
50
- if ($response === false) {
51
  return array(array(
52
  'error' => 'CurlError',
53
- 'message' => sprintf("%s [%d]", curl_error($request), curl_errno($request))
54
- ), null
55
  );
56
  }
57
 
58
  $header_size = curl_getinfo($request, CURLINFO_HEADER_SIZE);
 
59
  $headers = self::parse_headers(substr($response, 0, $header_size));
60
  curl_close($request);
61
 
62
- return array(self::decode(substr($response, $header_size)), $headers);
63
  }
64
 
65
- protected function output_options($url) {
66
- return array(
67
  CURLOPT_URL => $url,
68
  CURLOPT_RETURNTRANSFER => true,
 
69
  CURLOPT_CAINFO => self::get_ca_file(),
70
- CURLOPT_SSL_VERIFYPEER => true
 
71
  );
 
 
 
 
 
 
72
  }
73
 
74
- protected function output($url) {
75
  $request = curl_init();
76
- curl_setopt_array($request, $this->output_options($url));
 
77
 
78
  $response = curl_exec($request);
 
 
79
  curl_close($request);
80
 
81
- return $response;
82
  }
83
  }
45
  $request = curl_init();
46
  curl_setopt_array($request, $this->shrink_options($input));
47
 
 
48
  $response = curl_exec($request);
49
+ if ($response === false || $response === null) {
50
  return array(array(
51
  'error' => 'CurlError',
52
+ 'message' => sprintf("cURL: %s [%d]", curl_error($request), curl_errno($request))
53
+ ), null, null
54
  );
55
  }
56
 
57
  $header_size = curl_getinfo($request, CURLINFO_HEADER_SIZE);
58
+ $status_code = curl_getinfo($request, CURLINFO_HTTP_CODE);
59
  $headers = self::parse_headers(substr($response, 0, $header_size));
60
  curl_close($request);
61
 
62
+ return array(self::decode(substr($response, $header_size)), $headers, $status_code);
63
  }
64
 
65
+ protected function output_options($url, $resize) {
66
+ $options = array(
67
  CURLOPT_URL => $url,
68
  CURLOPT_RETURNTRANSFER => true,
69
+ CURLOPT_HEADER => true,
70
  CURLOPT_CAINFO => self::get_ca_file(),
71
+ CURLOPT_SSL_VERIFYPEER => true,
72
+ CURLOPT_USERAGENT => Tiny_WP_Base::plugin_identification() . ' cURL'
73
  );
74
+ if ($resize) {
75
+ $options[CURLOPT_USERPWD] = 'api:' . $this->api_key;
76
+ $options[CURLOPT_HTTPHEADER] = array('Content-Type: application/json');
77
+ $options[CURLOPT_POSTFIELDS] = json_encode(array('resize' => $resize));
78
+ }
79
+ return $options;
80
  }
81
 
82
+ protected function output($url, $resize) {
83
  $request = curl_init();
84
+ $options = $this->output_options($url, $resize);
85
+ curl_setopt_array($request, $options);
86
 
87
  $response = curl_exec($request);
88
+ $header_size = curl_getinfo($request, CURLINFO_HEADER_SIZE);
89
+ $headers = self::parse_headers(substr($response, 0, $header_size));
90
  curl_close($request);
91
 
92
+ return array(substr($response, $header_size), $headers);
93
  }
94
  }
src/class-tiny-compress-fopen.php CHANGED
@@ -28,7 +28,10 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
28
  'Authorization: Basic ' . base64_encode('api:' . $this->api_key),
29
  'User-Agent: ' . Tiny_WP_Base::plugin_identification() . ' fopen',
30
  ),
31
- 'content' => $input
 
 
 
32
  ),
33
  'ssl' => array(
34
  'cafile' => self::get_ca_file(),
@@ -41,11 +44,21 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
41
  $context = stream_context_create($this->shrink_options($input));
42
  $request = @fopen(Tiny_Config::URL, 'r', false, $context);
43
 
 
 
 
 
 
 
 
 
44
  if (!$request) {
 
 
45
  return array(array(
46
  'error' => 'FopenError',
47
- 'message' => 'Could not compress, enable cURL for detailed error'
48
- ), null
49
  );
50
  }
51
 
@@ -54,11 +67,11 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
54
  $headers = self::parse_headers($meta_data['wrapper_data']);
55
  fclose($request);
56
 
57
- return array(self::decode($response), $headers);
58
  }
59
 
60
- protected function output_options() {
61
- return array(
62
  'http' => array(
63
  'method' => 'GET',
64
  ),
@@ -67,23 +80,30 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
67
  'verify_peer' => true
68
  )
69
  );
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
- protected function output($url) {
73
- $context = stream_context_create($this->output_options());
74
  $request = @fopen($url, 'rb', false, $context);
75
 
76
  if ($request) {
77
  $response = stream_get_contents($request);
 
 
78
  fclose($request);
79
  } else {
80
  $response = '';
 
81
  }
82
-
83
- return $response;
84
- }
85
-
86
- public function get_status(&$details) {
87
- return null;
88
  }
89
  }
28
  'Authorization: Basic ' . base64_encode('api:' . $this->api_key),
29
  'User-Agent: ' . Tiny_WP_Base::plugin_identification() . ' fopen',
30
  ),
31
+ 'content' => $input,
32
+ 'follow_location' => 0,
33
+ 'max_redirects' => 1, // Necessary for PHP 5.2
34
+ 'ignore_errors' => true // Apparently, a 201 is a failure
35
  ),
36
  'ssl' => array(
37
  'cafile' => self::get_ca_file(),
44
  $context = stream_context_create($this->shrink_options($input));
45
  $request = @fopen(Tiny_Config::URL, 'r', false, $context);
46
 
47
+ $status_code = null;
48
+ if ($http_response_header && count($http_response_header) > 0) {
49
+ $http_code_values = explode(' ', $http_response_header[0]);
50
+ if (count($http_code_values) > 1) {
51
+ $status_code = intval($http_code_values[1]);
52
+ }
53
+ }
54
+
55
  if (!$request) {
56
+ $headers = self::parse_headers($http_response_header);
57
+
58
  return array(array(
59
  'error' => 'FopenError',
60
+ 'message' => 'Could not compress, enable cURL for detailed error',
61
+ ), $headers, $status_code
62
  );
63
  }
64
 
67
  $headers = self::parse_headers($meta_data['wrapper_data']);
68
  fclose($request);
69
 
70
+ return array(self::decode($response), $headers, $status_code);
71
  }
72
 
73
+ protected function output_options($resize) {
74
+ $options = array(
75
  'http' => array(
76
  'method' => 'GET',
77
  ),
80
  'verify_peer' => true
81
  )
82
  );
83
+ if ($resize) {
84
+ $options['http']['header'] = array(
85
+ 'Authorization: Basic ' . base64_encode('api:' . $this->api_key),
86
+ 'Content-Type: application/json',
87
+ 'User-Agent: ' . Tiny_WP_Base::plugin_identification() . ' fopen'
88
+ );
89
+ $options['http']['content'] = json_encode(array('resize' => $resize));
90
+ }
91
+ return $options;
92
  }
93
 
94
+ protected function output($url, $resize) {
95
+ $context = stream_context_create($this->output_options($resize));
96
  $request = @fopen($url, 'rb', false, $context);
97
 
98
  if ($request) {
99
  $response = stream_get_contents($request);
100
+ $meta_data = stream_get_meta_data($request);
101
+ $headers = self::parse_headers($meta_data['wrapper_data']);
102
  fclose($request);
103
  } else {
104
  $response = '';
105
+ $headers = array();
106
  }
107
+ return array($response, $headers);
 
 
 
 
 
108
  }
109
  }
src/class-tiny-compress.php CHANGED
@@ -41,20 +41,20 @@ abstract class Tiny_Compress {
41
  }
42
 
43
  abstract protected function shrink($input);
44
- abstract protected function output($url);
45
 
46
  public function get_status(&$details) {
47
- list($details, $headers) = $this->shrink(null);
48
 
49
  $this->call_after_compress_callback($details, $headers);
50
- if (!isset($details['error']) || $details["error"] == 'InputMissing' || $details["error"] == 'TooManyRequests') {
51
  return true;
52
  } else {
53
  return false;
54
  }
55
  }
56
 
57
- public function compress($input) {
58
  list($details, $headers) = $this->shrink($input);
59
  $this->call_after_compress_callback($details, $headers);
60
  $outputUrl = isset($headers['location']) ? $headers['location'] : null;
@@ -63,19 +63,31 @@ abstract class Tiny_Compress {
63
  } else if ($outputUrl === null) {
64
  throw new Tiny_Exception('Could not find output url', 'OutputNotFound');
65
  }
66
- $output = $this->output($outputUrl);
 
67
  if (strlen($output) == 0) {
68
  throw new Tiny_Exception('Could not download output', 'OutputError');
69
  }
 
70
  return array($output, $details);
71
  }
72
 
73
- public function compress_file($file) {
74
  if (!file_exists($file)) {
75
- throw new Tiny_Exception('File does not exists', 'FileError');
 
 
 
 
76
  }
77
- list($output, $details) = $this->compress(file_get_contents($file));
 
78
  file_put_contents($file, $output);
 
 
 
 
 
79
  return $details;
80
  }
81
 
@@ -102,9 +114,33 @@ abstract class Tiny_Compress {
102
  protected static function decode($text) {
103
  $result = json_decode($text, true);
104
  if ($result === null) {
105
- throw new Tiny_Exception('Could not decode JSON', 'JsonError');
 
 
 
106
  }
107
  return $result;
108
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
41
  }
42
 
43
  abstract protected function shrink($input);
44
+ abstract protected function output($url, $resize);
45
 
46
  public function get_status(&$details) {
47
+ list($details, $headers, $status_code) = $this->shrink(null);
48
 
49
  $this->call_after_compress_callback($details, $headers);
50
+ if ($status_code >= 400 && $status_code < 500 && $status_code != 401) {
51
  return true;
52
  } else {
53
  return false;
54
  }
55
  }
56
 
57
+ public function compress($input, $resize_options) {
58
  list($details, $headers) = $this->shrink($input);
59
  $this->call_after_compress_callback($details, $headers);
60
  $outputUrl = isset($headers['location']) ? $headers['location'] : null;
63
  } else if ($outputUrl === null) {
64
  throw new Tiny_Exception('Could not find output url', 'OutputNotFound');
65
  }
66
+ list($output, $headers) = $this->output($outputUrl, $resize_options);
67
+ $this->call_after_compress_callback(null, $headers);
68
  if (strlen($output) == 0) {
69
  throw new Tiny_Exception('Could not download output', 'OutputError');
70
  }
71
+
72
  return array($output, $details);
73
  }
74
 
75
+ public function compress_file($file, $resize_options) {
76
  if (!file_exists($file)) {
77
+ throw new Tiny_Exception('File does not exist', 'FileError');
78
+ }
79
+
80
+ if (!self::needs_resize($file, $resize_options)) {
81
+ $resize_options = false;
82
  }
83
+
84
+ list($output, $details) = $this->compress(file_get_contents($file), $resize_options);
85
  file_put_contents($file, $output);
86
+
87
+ if ($resize_options) {
88
+ $details['output'] = self::update_details($file, $details) + $details['output'];
89
+ }
90
+
91
  return $details;
92
  }
93
 
114
  protected static function decode($text) {
115
  $result = json_decode($text, true);
116
  if ($result === null) {
117
+ throw new Tiny_Exception(sprintf('JSON: %s [%d]',
118
+ PHP_VERSION_ID >= 50500 ? json_last_error_msg() : 'Unknown error',
119
+ PHP_VERSION_ID >= 50300 ? json_last_error() : 'Error'),
120
+ 'JsonError');
121
  }
122
  return $result;
123
  }
124
+
125
+ protected static function needs_resize($file, $resize_options) {
126
+ if (!$resize_options) {
127
+ return false;
128
+ }
129
+
130
+ list($width, $height) = getimagesize($file);
131
+ return $width > $resize_options['width'] || $height > $resize_options['height'];
132
+ }
133
+
134
+ protected static function update_details($file, $details) {
135
+ $size = filesize($file);
136
+ list($width, $height) = getimagesize($file);
137
+ return array(
138
+ 'size' => $size,
139
+ 'width' => $width,
140
+ 'height' => $height,
141
+ 'ratio' => round($size / $details['input']['size'], 4),
142
+ 'resized' => true
143
+ );
144
+ }
145
  }
146
 
src/class-tiny-metadata.php CHANGED
@@ -23,6 +23,7 @@ class Tiny_Metadata {
23
  const ORIGINAL = 0;
24
 
25
  private $id;
 
26
  private $values;
27
  private $filenames;
28
  private $urls;
@@ -34,7 +35,7 @@ class Tiny_Metadata {
34
  $wp_metadata = wp_get_attachment_metadata($id);
35
  }
36
  $this->parse_wp_metadata($wp_metadata);
37
- $this->values = get_post_meta($id, self::META_KEY, true);
38
  if (!is_array($this->values)) {
39
  $this->values = array();
40
  }
@@ -56,27 +57,36 @@ class Tiny_Metadata {
56
  $url_prefix .= $path_info['dirname'] .'/';
57
  }
58
 
 
 
59
  $this->filenames[self::ORIGINAL] = "$path_prefix${path_info['basename']}";
60
  $this->urls[self::ORIGINAL] = "$url_prefix${path_info['basename']}";
 
 
61
  if (isset($wp_metadata['sizes']) && is_array($wp_metadata['sizes'])) {
62
  foreach ($wp_metadata['sizes'] as $size => $info) {
63
- $this->filenames[$size] = "$path_prefix${info['file']}";
64
- $this->urls[$size] = "$url_prefix${info['file']}";
 
 
 
 
 
65
  }
66
  }
67
  }
68
 
69
- public function update() {
70
- update_post_meta($this->id, self::META_KEY, $this->values);
 
 
 
 
 
71
  }
72
 
73
- public function add_response($response, $size=self::ORIGINAL) {
74
- $data = array(
75
- 'input' => array('size' => $response['input']['size']),
76
- 'output' => array('size' => $response['output']['size']),
77
- 'end' => time()
78
- );
79
- $this->values[$size] = array_merge($this->values[$size], $data);
80
  }
81
 
82
  public function add_request($size=self::ORIGINAL) {
@@ -85,6 +95,11 @@ class Tiny_Metadata {
85
  );
86
  }
87
 
 
 
 
 
 
88
  public function add_exception($exception, $size=self::ORIGINAL) {
89
  $this->values[$size] = array(
90
  'error' => $exception->get_error(),
@@ -97,6 +112,10 @@ class Tiny_Metadata {
97
  return $this->id;
98
  }
99
 
 
 
 
 
100
  public function get_filename($size=self::ORIGINAL) {
101
  return isset($this->filenames[$size]) ? $this->filenames[$size] : null;
102
  }
@@ -109,10 +128,30 @@ class Tiny_Metadata {
109
  return isset($this->values[$size]) ? $this->values[$size] : null;
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  public function is_compressed($size=self::ORIGINAL) {
113
- $filename = $this->get_filename($size);
114
- return isset($this->values[$size]) && isset($this->values[$size]['output'])
115
- && file_exists($filename) && filesize($filename) == $this->values[$size]['output']['size'];
116
  }
117
 
118
  public function is_compressing($size=self::ORIGINAL) {
@@ -120,23 +159,60 @@ class Tiny_Metadata {
120
  return isset($meta) && isset($meta['start']) && !isset($meta['output']);
121
  }
122
 
 
 
 
 
 
 
123
  public function get_sizes() {
124
  return array_keys($this->filenames);
125
  }
126
 
 
 
 
 
127
  public function get_success_sizes() {
128
  return array_filter(array_keys($this->values), array($this, 'is_compressed'));
129
  }
130
 
131
- public function get_missing_sizes($tinify_sizes) {
132
- $sizes = array_intersect($this->get_sizes(), $tinify_sizes);
133
- return array_diff($sizes, $this->get_success_sizes());
 
 
 
 
 
 
134
  }
135
 
136
  public function get_in_progress_sizes() {
137
  return array_filter(array_keys($this->values), array($this, 'is_compressing'));
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  public function get_latest_error() {
141
  $last_time = null;
142
  $message = null;
@@ -164,4 +240,8 @@ class Tiny_Metadata {
164
  }
165
  return $result;
166
  }
 
 
 
 
167
  }
23
  const ORIGINAL = 0;
24
 
25
  private $id;
26
+ private $name;
27
  private $values;
28
  private $filenames;
29
  private $urls;
35
  $wp_metadata = wp_get_attachment_metadata($id);
36
  }
37
  $this->parse_wp_metadata($wp_metadata);
38
+ $this->values = get_post_meta($this->id, self::META_KEY, true);
39
  if (!is_array($this->values)) {
40
  $this->values = array();
41
  }
57
  $url_prefix .= $path_info['dirname'] .'/';
58
  }
59
 
60
+ $this->name = $path_info['basename'];
61
+
62
  $this->filenames[self::ORIGINAL] = "$path_prefix${path_info['basename']}";
63
  $this->urls[self::ORIGINAL] = "$url_prefix${path_info['basename']}";
64
+
65
+ $unique_sizes = array();
66
  if (isset($wp_metadata['sizes']) && is_array($wp_metadata['sizes'])) {
67
  foreach ($wp_metadata['sizes'] as $size => $info) {
68
+ $filename = $info['file'];
69
+
70
+ if (!isset($unique_sizes[$filename])) {
71
+ $this->filenames[$size] = "$path_prefix$filename";
72
+ $this->urls[$size] = "$url_prefix$filename";
73
+ $unique_sizes[$filename] = true;
74
+ }
75
  }
76
  }
77
  }
78
 
79
+ public function update_wp_metadata($wp_metadata) {
80
+ $tiny_metadata = $this->get_value();
81
+ if (isset($tiny_metadata) && isset($tiny_metadata['output']) && isset($tiny_metadata['output']['width']) && isset($tiny_metadata['output']['height'])) {
82
+ $wp_metadata['width'] = $tiny_metadata['output']['width'];
83
+ $wp_metadata['height'] = $tiny_metadata['output']['height'];
84
+ }
85
+ return $wp_metadata;
86
  }
87
 
88
+ public function update() {
89
+ update_post_meta($this->id, self::META_KEY, $this->values);
 
 
 
 
 
90
  }
91
 
92
  public function add_request($size=self::ORIGINAL) {
95
  );
96
  }
97
 
98
+ public function add_response($response, $size=self::ORIGINAL) {
99
+ $response['end'] = time();
100
+ $this->values[$size] = array_merge($this->values[$size], $response);
101
+ }
102
+
103
  public function add_exception($exception, $size=self::ORIGINAL) {
104
  $this->values[$size] = array(
105
  'error' => $exception->get_error(),
112
  return $this->id;
113
  }
114
 
115
+ public function get_name() {
116
+ return $this->name;
117
+ }
118
+
119
  public function get_filename($size=self::ORIGINAL) {
120
  return isset($this->filenames[$size]) ? $this->filenames[$size] : null;
121
  }
128
  return isset($this->values[$size]) ? $this->values[$size] : null;
129
  }
130
 
131
+ public function get_end_time($size=self::ORIGINAL) {
132
+ $value = $this->get_value($size);
133
+ if (array_key_exists("end", $value)) {
134
+ return $value["end"];
135
+ } else if (array_key_exists("timestamp", $value)) {
136
+ return $value["timestamp"];
137
+ }
138
+ }
139
+
140
+ public function has_been_compressed($size=self::ORIGINAL) {
141
+ return isset($this->values[$size]) && isset($this->values[$size]['output']);
142
+ }
143
+
144
+ public function exists($size=self::ORIGINAL) {
145
+ return file_exists($this->get_filename($size));
146
+ }
147
+
148
+ public function still_exists($size=self::ORIGINAL) {
149
+ return $this->has_been_compressed($size) && file_exists($this->get_filename($size));
150
+ }
151
+
152
  public function is_compressed($size=self::ORIGINAL) {
153
+ return $this->has_been_compressed($size) && $this->still_exists($size)
154
+ && filesize($this->get_filename($size)) == $this->values[$size]['output']['size'];
 
155
  }
156
 
157
  public function is_compressing($size=self::ORIGINAL) {
159
  return isset($meta) && isset($meta['start']) && !isset($meta['output']);
160
  }
161
 
162
+ public function is_resized($size=self::ORIGINAL) {
163
+ $meta = $this->values[$size];
164
+ return isset($meta) && isset($meta['output']) && isset($meta['output']['resized'])
165
+ && $meta['output']['resized'];
166
+ }
167
+
168
  public function get_sizes() {
169
  return array_keys($this->filenames);
170
  }
171
 
172
+ public function get_compressed_sizes() {
173
+ return array_filter(array_keys($this->values), array($this, 'has_been_compressed'));
174
+ }
175
+
176
  public function get_success_sizes() {
177
  return array_filter(array_keys($this->values), array($this, 'is_compressed'));
178
  }
179
 
180
+ public function get_uncompressed_sizes($active_tinify_sizes) {
181
+ $sizes = array_intersect($this->get_sizes(), $active_tinify_sizes);
182
+ $uncompressed = array_diff($sizes, $this->get_success_sizes());
183
+ return array_filter($uncompressed, array($this, 'exists'));
184
+ }
185
+
186
+ public function get_not_compressed_active_sizes($active_tinify_sizes) {
187
+ $sizes = array_intersect($this->get_sizes(), $active_tinify_sizes);
188
+ return array_diff($sizes, $this->get_compressed_sizes());
189
  }
190
 
191
  public function get_in_progress_sizes() {
192
  return array_filter(array_keys($this->values), array($this, 'is_compressing'));
193
  }
194
 
195
+ public function get_success_count() {
196
+ return count($this->get_success_sizes());
197
+ }
198
+
199
+ public function get_in_progress_count() {
200
+ return count($this->get_in_progress_sizes());
201
+ }
202
+
203
+ public function get_compressed_count() {
204
+ return count($this->get_compressed_sizes());
205
+ }
206
+
207
+ public function get_missing_count() {
208
+ return count($this->get_compressed_sizes()) -
209
+ count(array_filter($this->get_compressed_sizes(), array($this, 'still_exists')));
210
+ }
211
+
212
+ public function get_modified_count() {
213
+ return count($this->get_compressed_sizes()) - $this->get_success_count() - $this->get_missing_count();
214
+ }
215
+
216
  public function get_latest_error() {
217
  $last_time = null;
218
  $message = null;
240
  }
241
  return $result;
242
  }
243
+
244
+ public function is_resizable($size) {
245
+ return $size === self::ORIGINAL;
246
+ }
247
  }
src/class-tiny-plugin.php CHANGED
@@ -21,8 +21,10 @@
21
  class Tiny_Plugin extends Tiny_WP_Base {
22
  const MEDIA_COLUMN = self::NAME;
23
  const MEDIA_COLUMN_HEADER = 'Compression';
 
24
 
25
  private $settings;
 
26
 
27
  public static function jpeg_quality() {
28
  return 95;
@@ -54,14 +56,22 @@ class Tiny_Plugin extends Tiny_WP_Base {
54
  add_action('wp_ajax_tiny_compress_image', $this->get_method('compress_image'));
55
  add_action('admin_action_tiny_bulk_compress', $this->get_method('bulk_compress'));
56
  add_action('admin_enqueue_scripts', $this->get_method('enqueue_scripts'));
 
 
 
57
  }
58
 
59
  public function admin_menu() {
60
- add_management_page(
61
  self::translate('Compress JPEG & PNG Images'), self::translate('Compress All Images'),
62
  'upload_files', 'tiny-bulk-compress', $this->get_method('bulk_compress_page')
63
  );
 
64
 
 
 
 
 
65
  }
66
 
67
  public function enqueue_scripts($hook) {
@@ -72,7 +82,7 @@ class Tiny_Plugin extends Tiny_WP_Base {
72
  wp_register_script($handle, plugins_url('/scripts/admin.js', __FILE__),
73
  array(), self::plugin_version(), true);
74
 
75
- // Wordpress < 3.3 does not handle multi dimensional arrays
76
  wp_localize_script($handle, 'tinyCompress', array(
77
  'nonce' => wp_create_nonce('tiny-compress'),
78
  'wpVersion' => self::wp_version(),
@@ -94,36 +104,42 @@ class Tiny_Plugin extends Tiny_WP_Base {
94
  $tiny_metadata = new Tiny_Metadata($attachment_id, $metadata);
95
 
96
  if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) {
97
- return $metadata;
98
  }
99
 
100
  $success = 0;
101
  $failed = 0;
102
 
103
  $compressor = $this->settings->get_compressor();
104
- $sizes = $this->settings->get_tinify_sizes();
105
- $missing = $tiny_metadata->get_missing_sizes($sizes);
106
- foreach ($missing as $size) {
 
107
  try {
108
- $tiny_metadata->add_request($size);
109
  $tiny_metadata->update();
110
 
111
- $response = $compressor->compress_file($tiny_metadata->get_filename($size));
112
- $tiny_metadata->add_response($response, $size);
 
 
 
113
  $success++;
114
  } catch (Tiny_Exception $e) {
115
- $tiny_metadata->add_exception($e, $size);
 
116
  $failed++;
117
  }
118
  }
119
- $tiny_metadata->update();
120
 
121
  return array($tiny_metadata, array('success' => $success, 'failed' => $failed));
122
  }
123
 
124
  public function compress_attachment($metadata, $attachment_id) {
125
- $this->compress($metadata, $attachment_id);
126
- return $metadata;
 
 
127
  }
128
 
129
  public function compress_image() {
@@ -150,6 +166,8 @@ class Tiny_Plugin extends Tiny_WP_Base {
150
  }
151
 
152
  list($tiny_metadata, $result) = $this->compress($metadata, $id);
 
 
153
  if ($json) {
154
  $result['message'] = $tiny_metadata->get_latest_error();
155
  $result['status'] = $this->settings->get_status();
@@ -173,7 +191,7 @@ class Tiny_Plugin extends Tiny_WP_Base {
173
  wp_redirect(add_query_arg(
174
  '_wpnonce',
175
  wp_create_nonce('tiny-bulk-compress'),
176
- admin_url("tools.php?page=tiny-bulk-compress&ids=$ids")
177
  ));
178
  exit();
179
  }
@@ -190,30 +208,19 @@ class Tiny_Plugin extends Tiny_WP_Base {
190
  }
191
 
192
  private function render_compress_details($tiny_metadata) {
193
- $missing = $tiny_metadata->get_missing_sizes($this->settings->get_tinify_sizes());
194
- $success = count($tiny_metadata->get_success_sizes());
195
- $total = count($missing) + $success;
196
- $progress = count($tiny_metadata->get_in_progress_sizes());
197
-
198
- if (count($missing) > 0) {
199
- printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total);
200
- echo '<br/>';
201
- if (($error = $tiny_metadata->get_latest_error())) {
202
- echo '<span class="error">' . self::translate_escape('Latest error') . ': '. self::translate_escape($error) .'</span><br/>';
203
- }
204
- echo '<button type="button" class="tiny-compress" data-id="' . $tiny_metadata->get_id() . '">' .
205
- self::translate_escape('Compress') . '</button>';
206
- echo '<div class="spinner hidden"></div>';
207
- } elseif ($progress > 0) {
208
- printf(self::translate_escape('Compressing %d sizes...'), count($this->settings->get_tinify_sizes()));
209
  } else {
210
- printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total);
211
- $savings = $tiny_metadata->get_savings();
212
- if ($savings['count'] > 0) {
213
- echo '<br/>';
214
- echo self::translate_escape('Total size') . ': ' . size_format($savings['input']) . '<br/>';
215
- echo self::translate_escape('Compressed size') . ': ' . size_format($savings['output']);
216
- }
217
  }
218
  }
219
 
@@ -224,18 +231,29 @@ class Tiny_Plugin extends Tiny_WP_Base {
224
  echo '<h2>' . self::translate('Compress JPEG & PNG Images') . '</h2>';
225
  if (empty($_POST['tiny-bulk-compress']) && empty($_REQUEST['ids'])) {
226
  $result = $wpdb->get_results("SELECT COUNT(*) AS `count` FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A);
227
- $count = $result[0]['count'];
 
228
 
229
- echo '<p>' . self::translate_escape("Use this tool to compress all images in your media library") . '. ';
230
- echo self::translate_escape("Only images that have not been compressed will be compressed") . '.</p>';
231
- echo '<p>' . sprintf(self::translate_escape("We have found %d images in your media library"), $count) . '. ';
232
- echo self::translate_escape("To begin, just press the button below") . '.</p>';
 
 
 
 
 
 
 
233
 
234
  echo '<form method="POST" action="?page=tiny-bulk-compress">';
235
  echo '<input type="hidden" name="_wpnonce" value="' . wp_create_nonce('tiny-bulk-compress') . '">';
236
  echo '<input type="hidden" name="tiny-bulk-compress" value="1">';
237
- echo '<p><button class="button button-primary button-large" type="submit">' .
238
- self::translate_escape('Compress All Images') . '</p>';
 
 
 
239
  echo '</form>';
240
  } else {
241
  check_admin_referer('tiny-bulk-compress');
21
  class Tiny_Plugin extends Tiny_WP_Base {
22
  const MEDIA_COLUMN = self::NAME;
23
  const MEDIA_COLUMN_HEADER = 'Compression';
24
+ const DATETIME_FORMAT = 'Y-m-d G:i:s';
25
 
26
  private $settings;
27
+ private $twig;
28
 
29
  public static function jpeg_quality() {
30
  return 95;
56
  add_action('wp_ajax_tiny_compress_image', $this->get_method('compress_image'));
57
  add_action('admin_action_tiny_bulk_compress', $this->get_method('bulk_compress'));
58
  add_action('admin_enqueue_scripts', $this->get_method('enqueue_scripts'));
59
+ $plugin = plugin_basename(dirname(dirname(__FILE__)) . '/tiny-compress-images.php');
60
+ add_filter("plugin_action_links_$plugin", $this->get_method('add_plugin_links'));
61
+ add_thickbox();
62
  }
63
 
64
  public function admin_menu() {
65
+ add_media_page(
66
  self::translate('Compress JPEG & PNG Images'), self::translate('Compress All Images'),
67
  'upload_files', 'tiny-bulk-compress', $this->get_method('bulk_compress_page')
68
  );
69
+ }
70
 
71
+ public function add_plugin_links($current_links) {
72
+ $additional[] = sprintf('<a href="options-media.php#%s">%s</a>', self::NAME,
73
+ self::translate_escape('Settings'));
74
+ return array_merge($additional, $current_links);
75
  }
76
 
77
  public function enqueue_scripts($hook) {
82
  wp_register_script($handle, plugins_url('/scripts/admin.js', __FILE__),
83
  array(), self::plugin_version(), true);
84
 
85
+ // WordPress < 3.3 does not handle multidimensional arrays
86
  wp_localize_script($handle, 'tinyCompress', array(
87
  'nonce' => wp_create_nonce('tiny-compress'),
88
  'wpVersion' => self::wp_version(),
104
  $tiny_metadata = new Tiny_Metadata($attachment_id, $metadata);
105
 
106
  if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) {
107
+ return array($tiny_metadata, null);
108
  }
109
 
110
  $success = 0;
111
  $failed = 0;
112
 
113
  $compressor = $this->settings->get_compressor();
114
+ $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
115
+ $uncompressed_sizes = $tiny_metadata->get_uncompressed_sizes($active_tinify_sizes);
116
+
117
+ foreach ($uncompressed_sizes as $uncompressed_size) {
118
  try {
119
+ $tiny_metadata->add_request($uncompressed_size);
120
  $tiny_metadata->update();
121
 
122
+ $resize = $tiny_metadata->is_resizable($uncompressed_size) ? $this->settings->get_resize_options() : false;
123
+ $response = $compressor->compress_file($tiny_metadata->get_filename($uncompressed_size), $resize);
124
+
125
+ $tiny_metadata->add_response($response, $uncompressed_size);
126
+ $tiny_metadata->update();
127
  $success++;
128
  } catch (Tiny_Exception $e) {
129
+ $tiny_metadata->add_exception($e, $uncompressed_size);
130
+ $tiny_metadata->update();
131
  $failed++;
132
  }
133
  }
 
134
 
135
  return array($tiny_metadata, array('success' => $success, 'failed' => $failed));
136
  }
137
 
138
  public function compress_attachment($metadata, $attachment_id) {
139
+ if (!empty($metadata)) {
140
+ list($tiny_metadata, $result) = $this->compress($metadata, $attachment_id);
141
+ return $tiny_metadata->update_wp_metadata($metadata);
142
+ }
143
  }
144
 
145
  public function compress_image() {
166
  }
167
 
168
  list($tiny_metadata, $result) = $this->compress($metadata, $id);
169
+ wp_update_attachment_metadata($id, $tiny_metadata->update_wp_metadata($metadata));
170
+
171
  if ($json) {
172
  $result['message'] = $tiny_metadata->get_latest_error();
173
  $result['status'] = $this->settings->get_status();
191
  wp_redirect(add_query_arg(
192
  '_wpnonce',
193
  wp_create_nonce('tiny-bulk-compress'),
194
+ admin_url("upload.php?page=tiny-bulk-compress&ids=$ids")
195
  ));
196
  exit();
197
  }
208
  }
209
 
210
  private function render_compress_details($tiny_metadata) {
211
+ $active = $this->settings->get_active_tinify_sizes();
212
+ $uncompressed = $tiny_metadata->get_uncompressed_sizes($active);
213
+ $not_compressed_active = count($tiny_metadata->get_not_compressed_active_sizes($active));
214
+ $savings = $tiny_metadata->get_savings();
215
+ $error = $tiny_metadata->get_latest_error();
216
+ $missing = $tiny_metadata->get_missing_count();
217
+ $modified = $tiny_metadata->get_modified_count();
218
+ $compressing = (count($uncompressed) > 0) ? count($uncompressed) : count($active);
219
+
220
+ if ($tiny_metadata->get_in_progress_count() > 0) {
221
+ include(dirname(__FILE__) . '/views/compress-details-processing.php');
 
 
 
 
 
222
  } else {
223
+ include(dirname(__FILE__) . '/views/compress-details.php');
 
 
 
 
 
 
224
  }
225
  }
226
 
231
  echo '<h2>' . self::translate('Compress JPEG & PNG Images') . '</h2>';
232
  if (empty($_POST['tiny-bulk-compress']) && empty($_REQUEST['ids'])) {
233
  $result = $wpdb->get_results("SELECT COUNT(*) AS `count` FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A);
234
+ $image_count = $result[0]['count'];
235
+ $sizes_count = count($this->settings->get_active_tinify_sizes());
236
 
237
+ echo '<p>';
238
+ echo self::translate_escape("Use this tool to compress all images in your media library") . '. ';
239
+ echo self::translate_escape("Only images that have not been compressed will be compressed") . '. ';
240
+ echo '</p>';
241
+ echo '<p>';
242
+ echo sprintf(self::translate_escape("We have found %d images in your media library and for each image %d sizes will be compressed"), $image_count, $sizes_count) . '. ';
243
+ echo sprintf(self::translate_escape('This results in %d compressions at most'), $image_count*$sizes_count) . '. ';
244
+ echo '</p>';
245
+ echo '<p>';
246
+ echo self::translate_escape("To begin, just press the button below") . '. ';
247
+ echo '</p>';
248
 
249
  echo '<form method="POST" action="?page=tiny-bulk-compress">';
250
  echo '<input type="hidden" name="_wpnonce" value="' . wp_create_nonce('tiny-bulk-compress') . '">';
251
  echo '<input type="hidden" name="tiny-bulk-compress" value="1">';
252
+ echo '<p>';
253
+ echo '<button class="button button-primary button-large" type="submit">';
254
+ echo self::translate_escape('Compress All Images');
255
+ echo '</button>';
256
+ echo '</p>';
257
  echo '</form>';
258
  } else {
259
  check_admin_referer('tiny-bulk-compress');
src/class-tiny-settings.php CHANGED
@@ -31,14 +31,25 @@ class Tiny_Settings extends Tiny_WP_Base {
31
  $this->notices = new Tiny_Notices();
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
34
  public function admin_init() {
35
  if (current_user_can('manage_options') && !$this->get_api_key()) {
36
  $link = sprintf('<a href="options-media.php#%s">%s</a>', self::NAME,
37
  self::translate_escape('Please fill in an API key to start compressing images'));
38
  $this->notices->show('setting', $link, 'error', false);
39
  }
40
- try {
41
- $this->compressor = Tiny_Compress::get_compressor($this->get_api_key(), $this->get_method('after_compress_callback'));
42
  } catch (Tiny_Exception $e) {
43
  $this->notices->show('compressor_exception', self::translate_escape($e->getMessage()), 'error', false);
44
  }
@@ -54,11 +65,26 @@ class Tiny_Settings extends Tiny_WP_Base {
54
  register_setting('media', $field);
55
  add_settings_field($field, self::translate('File compression'), $this->get_method('render_sizes'), 'media', $section);
56
 
 
 
 
 
57
  $field = self::get_prefixed_name('status');
58
  register_setting('media', $field);
59
  add_settings_field($field, self::translate('Connection status'), $this->get_method('render_pending_status'), 'media', $section);
60
 
 
 
 
 
 
61
  add_action('wp_ajax_tiny_compress_status', $this->get_method('connection_status'));
 
 
 
 
 
 
62
  }
63
 
64
  public function connection_status() {
@@ -66,6 +92,11 @@ class Tiny_Settings extends Tiny_WP_Base {
66
  exit();
67
  }
68
 
 
 
 
 
 
69
  public function get_compressor() {
70
  return $this->compressor;
71
  }
@@ -134,7 +165,7 @@ class Tiny_Settings extends Tiny_WP_Base {
134
  return $this->sizes;
135
  }
136
 
137
- public function get_tinify_sizes() {
138
  if (is_array($this->tinify_sizes)) {
139
  return $this->tinify_sizes;
140
  }
@@ -148,6 +179,32 @@ class Tiny_Settings extends Tiny_WP_Base {
148
  return $this->tinify_sizes;
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  public function render_section() {
152
  echo '<span id="' . self::NAME . '"></span>';
153
  }
@@ -166,32 +223,114 @@ class Tiny_Settings extends Tiny_WP_Base {
166
  if (empty($key)) {
167
  printf(self::translate_escape('Visit %s to get an API key') . '.', $link);
168
  } else {
169
- printf(self::translate_escape('Visit %s to view your usage or upgrade your account') . '.', $link);
170
  }
171
  echo '</p>';
172
  }
173
 
174
  public function render_sizes() {
175
- echo '<p>' . self::translate_escape('You can choose to compress different image sizes created by WordPress here') . '.<br/>';
176
- echo self::translate_escape('Remember each additional image size will affect your TinyPNG monthly usage') . "!";?>
177
- <input type="hidden" name="<?php echo self::get_prefixed_name('sizes[' . self::DUMMY_SIZE .']'); ?>" value="on"/></p>
178
- <?php
 
179
  foreach ($this->get_sizes() as $size => $option) {
180
  $this->render_size_checkbox($size, $option);
181
  }
 
 
 
 
182
  }
183
 
184
  private function render_size_checkbox($size, $option) {
185
  $id = self::get_prefixed_name("sizes_$size");
186
- $field = self::get_prefixed_name("sizes[$size]");
 
187
  if ($size === Tiny_Metadata::ORIGINAL) {
188
- $label = self::translate_escape("original");
189
  } else {
190
- $label = $size . " - ${option['width']}x${option['height']}";
191
- }?>
192
- <p><input type="checkbox" id="<?php echo $id; ?>" name="<?php echo $field ?>" value="on" <?php if ($option['tinify']) { echo ' checked="checked"'; } ?>/>
193
- <label for="<?php echo $id; ?>"><?php echo $label; ?></label></p>
194
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
196
 
197
  public function get_compression_count() {
@@ -224,35 +363,44 @@ class Tiny_Settings extends Tiny_WP_Base {
224
  $status = false;
225
  $details = array('message' => $e->getMessage());
226
  }
 
 
227
  if ($status) {
228
- echo '<p><img src="images/yes.png"> ' . self::translate_escape('API connection successful') . '</p>';
 
229
  } else {
 
230
  if ($status === false) {
231
- echo '<p><img src="images/no.png"> ' . self::translate_escape('API connection unsuccessful') . '</p>';
232
  if (isset($details['message'])) {
233
- echo '<p>'. self::translate_escape('Error') . ': ' . self::translate_escape($details['message']) . '</p>';
234
  }
235
  } else {
236
- echo '<p>' . self::translate_escape('API status could not be checked, enable cURL for more information') . '.</p>';
237
  }
238
- return;
239
- }
240
-
241
- $compressions = self::get_compression_count();
242
- echo '<p>';
243
- // We currently have no way to check if a user is free or flexible.
244
- if ($compressions == 500) {
245
- $link = '<a href="https://tinypng.com/developers" target="_blank">' . self::translate_escape('TinyPNG API account') . '</a>';
246
- printf(self::translate_escape('You have reached your limit of %s compressions this month') . '.', $compressions);
247
- echo '<br>';
248
- printf(self::translate_escape('If you need to compress more images you can change your %s') . '.', $link);
249
- } else {
250
- printf(self::translate_escape('You have made %s compressions this month') . '.', self::get_compression_count());
251
  }
252
  echo '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
 
255
  public function render_pending_status() {
256
  echo '<div id="tiny-compress-status"><div class="spinner"></div></div>';
257
  }
 
 
 
 
258
  }
31
  $this->notices = new Tiny_Notices();
32
  }
33
 
34
+ private function init_compressor() {
35
+ $this->compressor = Tiny_Compress::get_compressor($this->get_api_key(), $this->get_method('after_compress_callback'));
36
+ }
37
+
38
+ public function xmlrpc_init() {
39
+ try {
40
+ $this->init_compressor();
41
+ } catch (Tiny_Exception $e) {
42
+ }
43
+ }
44
+
45
  public function admin_init() {
46
  if (current_user_can('manage_options') && !$this->get_api_key()) {
47
  $link = sprintf('<a href="options-media.php#%s">%s</a>', self::NAME,
48
  self::translate_escape('Please fill in an API key to start compressing images'));
49
  $this->notices->show('setting', $link, 'error', false);
50
  }
51
+ try {
52
+ $this->init_compressor();
53
  } catch (Tiny_Exception $e) {
54
  $this->notices->show('compressor_exception', self::translate_escape($e->getMessage()), 'error', false);
55
  }
65
  register_setting('media', $field);
66
  add_settings_field($field, self::translate('File compression'), $this->get_method('render_sizes'), 'media', $section);
67
 
68
+ $field = self::get_prefixed_name('resize_original');
69
+ register_setting('media', $field);
70
+ add_settings_field($field, self::translate('Resize original'), $this->get_method('render_resize'), 'media', $section);
71
+
72
  $field = self::get_prefixed_name('status');
73
  register_setting('media', $field);
74
  add_settings_field($field, self::translate('Connection status'), $this->get_method('render_pending_status'), 'media', $section);
75
 
76
+ $field = self::get_prefixed_name('savings');
77
+ register_setting('media', $field);
78
+ add_settings_field($field, self::translate('Savings'), $this->get_method('render_pending_savings'), 'media', $section);
79
+
80
+ add_action('wp_ajax_tiny_image_sizes_notice', $this->get_method('image_sizes_notice'));
81
  add_action('wp_ajax_tiny_compress_status', $this->get_method('connection_status'));
82
+ add_action('wp_ajax_tiny_compress_savings', $this->get_method('total_savings_status'));
83
+ }
84
+
85
+ public function image_sizes_notice() {
86
+ $this->render_image_sizes_notice($_GET["image_sizes_selected"], isset($_GET["resize_original"]));
87
+ exit();
88
  }
89
 
90
  public function connection_status() {
92
  exit();
93
  }
94
 
95
+ public function total_savings_status() {
96
+ $this->render_total_savings();
97
+ exit();
98
+ }
99
+
100
  public function get_compressor() {
101
  return $this->compressor;
102
  }
165
  return $this->sizes;
166
  }
167
 
168
+ public function get_active_tinify_sizes() {
169
  if (is_array($this->tinify_sizes)) {
170
  return $this->tinify_sizes;
171
  }
179
  return $this->tinify_sizes;
180
  }
181
 
182
+ public function get_resize_enabled() {
183
+ $setting = get_option(self::get_prefixed_name('resize_original'));
184
+ return isset($setting['enabled']) && $setting['enabled'] === 'on';
185
+ }
186
+
187
+ public function get_resize_options() {
188
+ $setting = get_option(self::get_prefixed_name('resize_original'));
189
+ if (!$this->get_resize_enabled()) {
190
+ return false;
191
+ }
192
+
193
+ $width = intval($setting['width']);
194
+ $height = intval($setting['height']);
195
+ $method = $width > 0 && $height > 0 ? 'fit' : 'scale';
196
+
197
+ $options['method'] = $method;
198
+ if ($width > 0) {
199
+ $options['width'] = $width;
200
+ }
201
+ if ($height > 0) {
202
+ $options['height'] = $height;
203
+ }
204
+
205
+ return sizeof($options) >= 2 ? $options : false;
206
+ }
207
+
208
  public function render_section() {
209
  echo '<span id="' . self::NAME . '"></span>';
210
  }
223
  if (empty($key)) {
224
  printf(self::translate_escape('Visit %s to get an API key') . '.', $link);
225
  } else {
226
+ printf(self::translate_escape('Visit %s to view or upgrade your account') . '.', $link);
227
  }
228
  echo '</p>';
229
  }
230
 
231
  public function render_sizes() {
232
+ echo '<p>';
233
+ echo self::translate_escape('Choose sizes to compress') . '. ';
234
+ echo self::translate_escape('Remember each selected size counts as a compression') . '. ';
235
+ echo '</p>';
236
+ echo '<input type="hidden" name="' . self::get_prefixed_name('sizes[' . self::DUMMY_SIZE . ']') . '" value="on"/>';
237
  foreach ($this->get_sizes() as $size => $option) {
238
  $this->render_size_checkbox($size, $option);
239
  }
240
+ echo '<br>';
241
+ echo '<div id="tiny-image-sizes-notice">';
242
+ $this->render_image_sizes_notice(count(self::get_active_tinify_sizes()), self::get_resize_enabled());
243
+ echo '</div>';
244
  }
245
 
246
  private function render_size_checkbox($size, $option) {
247
  $id = self::get_prefixed_name("sizes_$size");
248
+ $name = self::get_prefixed_name("sizes[$size]");
249
+ $checked = ( $option['tinify'] ? ' checked="checked"' : '' );
250
  if ($size === Tiny_Metadata::ORIGINAL) {
251
+ $label = self::translate_escape("original") . ' (' . self::translate_escape('overwritten by compressed image') . ')';
252
  } else {
253
+ $label = $size . ' - ' . $option['width'] . 'x' . $option['height'];
254
+ }
255
+ echo '<p>';
256
+ echo '<input type="checkbox" id="' . $id . '" name="' . $name . '" value="on" ' . $checked . '/>';
257
+ echo '<label for="' . $id . '">' . $label . '</label>';
258
+ echo '</p>';
259
+ }
260
+
261
+ public function render_image_sizes_notice($active_image_sizes_count, $resize_original_enabled) {
262
+ echo '<p>';
263
+ if ($resize_original_enabled) {
264
+ $active_image_sizes_count++;
265
+ }
266
+ if ($active_image_sizes_count < 1) {
267
+ echo self::translate_escape('With these settings no images will be compressed') . '.';
268
+ } else {
269
+ $free_images_per_month = floor( Tiny_Config::MONTHLY_FREE_COMPRESSIONS / $active_image_sizes_count );
270
+ echo self::translate_escape('With these settings you can compress');
271
+ echo ' <strong>';
272
+ printf(self::translate_escape('at least %s images'), $free_images_per_month);
273
+ echo '</strong> ';
274
+ echo self::translate_escape('for free each month') . '.';
275
+ }
276
+ echo '</p>';
277
+ }
278
+
279
+ public function render_total_savings() {
280
+ global $wpdb;
281
+
282
+ $total_savings = 0;
283
+ $result = $wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A);
284
+ for ($i = 0; $i < sizeof($result); $i++) {
285
+ $tiny_metadata = new Tiny_Metadata($result[$i]["ID"]);
286
+ $savings = $tiny_metadata->get_savings();
287
+ $total_savings += ($savings['input'] - $savings['output']);
288
+ }
289
+
290
+ echo '<p>';
291
+ if ($total_savings > 0) {
292
+ printf( self::translate_escape( "You have saved a total of %s on images") . '!', '<strong>' . size_format( $total_savings ) . '</strong>' );
293
+ } else {
294
+ $link = '<a href="upload.php?page=tiny-bulk-compress">' . self::translate_escape('Compress All Images') . '</a>';
295
+ printf(self::translate_escape('No images compressed yet. Use %s to compress existing images') . '.', $link);
296
+ }
297
+ echo '</p>';
298
+ }
299
+
300
+ public function render_resize() {
301
+ echo '<p class="tiny-resize-unavailable" style="display: none">';
302
+ echo self::translate_escape("Enable the compression of the original image size to configure resizing") . '.';
303
+ echo '</p>';
304
+
305
+ $id = self::get_prefixed_name("resize_original_enabled");
306
+ $name = self::get_prefixed_name("resize_original[enabled]");
307
+ $checked = ( $this->get_resize_enabled() ? ' checked="checked"' : '' );
308
+ $label = self::translate_escape('Resize and compress the orginal image');
309
+
310
+ echo '<p class="tiny-resize-available">';
311
+ echo '<input type="checkbox" id="' . $id . '" name="' . $name . '" value="on" '. $checked . '/>';
312
+ echo '<label for="' . $id . '">' . $label . '</label>';
313
+ echo '<br>';
314
+ echo '</p>';
315
+
316
+ echo '<p class="tiny-resize-available tiny-resize-resolution">';
317
+ printf("%s: ", self::translate_escape('Max Width'));
318
+ $this->render_resize_input('width');
319
+ printf("%s: ", self::translate_escape('Max Height'));
320
+ $this->render_resize_input('height');
321
+ echo '</p>';
322
+
323
+ echo '<p class="tiny-resize-available">';
324
+ echo sprintf(self::translate_escape("Resizing takes %s for each image that is larger"), self::translate_escape('1 additional compression')) . '.';
325
+ echo '</p>';
326
+ }
327
+
328
+ public function render_resize_input($name) {
329
+ $id = sprintf(self::get_prefixed_name('resize_original_%s'), $name);
330
+ $field = sprintf(self::get_prefixed_name('resize_original[%s]'), $name);
331
+ $settings = get_option(self::get_prefixed_name('resize_original'));
332
+ $value = isset($settings[$name]) ? $settings[$name] : "2048";
333
+ echo '<input type="number" id="'. $id .'" name="' . $field . '" value="' . $value . '" size="5" />';
334
  }
335
 
336
  public function get_compression_count() {
363
  $status = false;
364
  $details = array('message' => $e->getMessage());
365
  }
366
+
367
+ echo '<p>';
368
  if ($status) {
369
+ echo '<img src="images/yes.png"> ';
370
+ echo self::translate_escape('API connection successful');
371
  } else {
372
+ echo '<img src="images/no.png"> ';
373
  if ($status === false) {
374
+ echo self::translate_escape('API connection unsuccessful') . '<br>';
375
  if (isset($details['message'])) {
376
+ echo self::translate_escape('Error') . ': ' . self::translate_escape($details['message']);
377
  }
378
  } else {
379
+ echo self::translate_escape('API status could not be checked, enable cURL for more information');
380
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  }
382
  echo '</p>';
383
+ if ($status) {
384
+ $compressions = self::get_compression_count();
385
+ echo '<p>';
386
+ // It is not possible to check if a subscription is free or flexible.
387
+ if ( $compressions == Tiny_Config::MONTHLY_FREE_COMPRESSIONS ) {
388
+ $link = '<a href="https://tinypng.com/developers" target="_blank">' . self::translate_escape('TinyPNG API account') . '</a>';
389
+ printf(self::translate_escape('You have reached your limit of %s compressions this month') . '.', $compressions);
390
+ echo '<br>';
391
+ printf(self::translate_escape('If you need to compress more images you can change your %s') . '.', $link);
392
+ } else {
393
+ printf(self::translate_escape('You have made %s compressions this month') . '.', self::get_compression_count());
394
+ }
395
+ echo '</p>';
396
+ }
397
  }
398
 
399
  public function render_pending_status() {
400
  echo '<div id="tiny-compress-status"><div class="spinner"></div></div>';
401
  }
402
+
403
+ public function render_pending_savings() {
404
+ echo '<div id="tiny-compress-savings"><div class="spinner"></div></div>';
405
+ }
406
  }
src/class-tiny-wp-base.php CHANGED
@@ -42,6 +42,10 @@ abstract class Tiny_WP_Base {
42
  return floatval(self::wp_version()) >= $version;
43
  }
44
 
 
 
 
 
45
  public static function plugin_version() {
46
  if (is_null(self::$plugin_version)) {
47
  $plugin_data = get_plugin_data(dirname(__FILE__) . '/../tiny-compress-images.php');
@@ -51,7 +55,7 @@ abstract class Tiny_WP_Base {
51
  }
52
 
53
  public static function plugin_identification() {
54
- return 'Wordpress/' . self::wp_version() . ' Tiny/' . self::plugin_version();
55
  }
56
 
57
  protected static function get_prefixed_name($name) {
@@ -66,9 +70,15 @@ abstract class Tiny_WP_Base {
66
  return htmlspecialchars(translate($phrase, self::NAME));
67
  }
68
 
 
 
 
 
69
  public function __construct() {
70
  add_action('init', $this->get_method('init'));
71
- if (is_admin()) {
 
 
72
  add_action('admin_init', $this->get_method('admin_init'));
73
  }
74
  }
@@ -92,6 +102,9 @@ abstract class Tiny_WP_Base {
92
  public function init() {
93
  }
94
 
 
 
 
95
  public function admin_init() {
96
  }
97
  }
42
  return floatval(self::wp_version()) >= $version;
43
  }
44
 
45
+ protected function is_xmlrpc_request() {
46
+ return defined('XMLRPC_REQUEST') && XMLRPC_REQUEST;
47
+ }
48
+
49
  public static function plugin_version() {
50
  if (is_null(self::$plugin_version)) {
51
  $plugin_data = get_plugin_data(dirname(__FILE__) . '/../tiny-compress-images.php');
55
  }
56
 
57
  public static function plugin_identification() {
58
+ return 'WordPress/' . self::wp_version() . ' PHP/' . PHP_VERSION . ' Tiny/' . self::plugin_version();
59
  }
60
 
61
  protected static function get_prefixed_name($name) {
70
  return htmlspecialchars(translate($phrase, self::NAME));
71
  }
72
 
73
+ protected static function ntranslate_escape($single, $plural, $amount) {
74
+ return htmlspecialchars(_n($single, $plural, $amount, self::NAME));
75
+ }
76
+
77
  public function __construct() {
78
  add_action('init', $this->get_method('init'));
79
+ if (self::is_xmlrpc_request()) {
80
+ add_action('init', $this->get_method('xmlrpc_init'));
81
+ } elseif (is_admin()) {
82
  add_action('admin_init', $this->get_method('admin_init'));
83
  }
84
  }
102
  public function init() {
103
  }
104
 
105
+ public function xmlrpc_init() {
106
+ }
107
+
108
  public function admin_init() {
109
  }
110
  }
src/config/tiny-config.php CHANGED
@@ -2,4 +2,5 @@
2
 
3
  class Tiny_Config {
4
  const URL = 'https://api.tinify.com/shrink';
 
5
  }
2
 
3
  class Tiny_Config {
4
  const URL = 'https://api.tinify.com/shrink';
5
+ const MONTHLY_FREE_COMPRESSIONS = 500;
6
  }
src/languages/tiny-compress-images-nl_NL.mo CHANGED
Binary file
src/languages/tiny-compress-images-nl_NL.po CHANGED
@@ -1,14 +1,14 @@
 
 
 
1
  msgid "PNG and JPEG compression"
2
  msgstr "PNG- en JPEG-compressie"
3
 
4
- msgid "Multisite PNG and JPEG compression"
5
- msgstr "Multisite PNG- en JPEG-compressie"
6
-
7
  msgid "Visit %s to get an API key"
8
- msgstr "Bezoek de %s om een API-sleutel te krijgen"
9
 
10
- msgid "Visit %s to view your usage or upgrade your account"
11
- msgstr "Bezoek de %s om je verbruik te bekijken of je account aan te passen"
12
 
13
  msgid "TinyPNG Developer section"
14
  msgstr "TinyPNG Developer pagina"
@@ -16,20 +16,17 @@ msgstr "TinyPNG Developer pagina"
16
  msgid "TinyPNG API key"
17
  msgstr "TinyPNG API-sleutel"
18
 
19
- msgid "Multisite API key"
20
- msgstr "Multisite API-sleutel"
21
-
22
  msgid "File compression"
23
  msgstr "Bestandscompressie"
24
 
25
  msgid "original"
26
  msgstr "origineel"
27
 
28
- msgid "You can choose to compress different image sizes created by WordPress here"
29
- msgstr "Je kunt hier kiezen welke afmetingen je wilt comprimeren van de afbeeldingen"
30
 
31
- msgid "Remember each additional image size will affect your TinyPNG monthly usage"
32
- msgstr "Elke afmetingen zal apart worden gecomprimeerd en telt mee voor je verbruik"
33
 
34
  msgid "Compression"
35
  msgstr "Compressie"
@@ -40,17 +37,77 @@ msgstr "Comprimeer"
40
  msgid "Compress Images"
41
  msgstr "Comprimeer Afbeeldingen"
42
 
43
- msgid "Compressed %d out of %d sizes"
44
- msgstr "%d van de %d afmetingen zijn gecomprimeerd"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- msgid "Compressing %d sizes..."
47
- msgstr "%d afmetingen worden gecomprimeerd..."
 
 
 
48
 
49
  msgid "Total size"
50
  msgstr "Totale grootte"
51
 
52
- msgid "Compressed size"
53
- msgstr "Gecomprimeerde grootte"
 
 
 
54
 
55
  msgid "Latest error"
56
  msgstr "Laatste fout"
@@ -91,12 +148,9 @@ msgstr "Kon geen outputlocatie vinden"
91
  msgid "Could not download output"
92
  msgstr "Kon output niet downloaden"
93
 
94
- msgid "File does not exists"
95
  msgstr "Bestand bestaat niet"
96
 
97
- msgid "Could not decode JSON"
98
- msgstr "Kon JSON niet decoderen"
99
-
100
  msgid "Could not compress, enable cURL for detailed error"
101
  msgstr "Kon niet comprimeren, schakel cURL in voor een preciezere foutmelding"
102
 
@@ -142,11 +196,35 @@ msgstr "Als je meer afbeeldingen wilt comprimeren kun je je %s aanpassen"
142
  msgid "Upgrade your %s if you like to compress more images"
143
  msgstr "Upgrade je %s als je meer afbeeldingen wilt comprimeren"
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  msgid "Please fill in an API key to start compressing images"
146
  msgstr "Vul een API-sleutel in om te starten met comprimeren"
147
 
148
  msgid "Compress All Images"
149
- msgstr "Comprimeer Alle Afbeeldingen"
150
 
151
  msgid "Compress JPEG & PNG Images"
152
  msgstr "Comprimeer JPEG & PNG afbeeldingen"
@@ -173,13 +251,16 @@ msgid "out of"
173
  msgstr "van de"
174
 
175
  msgid "Use this tool to compress all images in your media library"
176
- msgstr "Deze tool comprimeert alle afbeeldingen in je media-bibliotheek"
177
 
178
  msgid "Only images that have not been compressed will be compressed"
179
  msgstr "Dit geldt alleen voor de afbeeldingen die nog niet zijn gecomprimeerd"
180
 
181
- msgid "We have found %d images in your media library"
182
- msgstr "We hebben %d afbeeldingen in de media-bibliotheek gevonden"
 
 
 
183
 
184
  msgid "To begin, just press the button below"
185
  msgstr "Druk op de knop om te starten"
@@ -195,3 +276,30 @@ msgstr "Navigeer niet van deze pagina want daardoor stopt het proces"
195
 
196
  msgid "You will be notified via this page when the processing is done"
197
  msgstr "Je wordt genotificeerd op deze pagina bij voltooing"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG."
2
+ msgstr "Maak je website sneller. Optimaliseer alle JPEG en PNG afbeeldingen automatisch met TinyPNG."
3
+
4
  msgid "PNG and JPEG compression"
5
  msgstr "PNG- en JPEG-compressie"
6
 
 
 
 
7
  msgid "Visit %s to get an API key"
8
+ msgstr "Bezoek de %s om een API-sleutel te verkrijgen"
9
 
10
+ msgid "Visit %s to view or upgrade your account"
11
+ msgstr "Bezoek de %s om je account te bekijken of aan te passen"
12
 
13
  msgid "TinyPNG Developer section"
14
  msgstr "TinyPNG Developer pagina"
16
  msgid "TinyPNG API key"
17
  msgstr "TinyPNG API-sleutel"
18
 
 
 
 
19
  msgid "File compression"
20
  msgstr "Bestandscompressie"
21
 
22
  msgid "original"
23
  msgstr "origineel"
24
 
25
+ msgid "Choose sizes to compress"
26
+ msgstr "Kies afmetingen om te comprimeren"
27
 
28
+ msgid "Remember each selected size counts as a compression"
29
+ msgstr "Elke geselecteerde afmeting telt als een compressie"
30
 
31
  msgid "Compression"
32
  msgstr "Compressie"
37
  msgid "Compress Images"
38
  msgstr "Comprimeer Afbeeldingen"
39
 
40
+ msgid "size compressed"
41
+ msgstr "afmeting gecomprimeerd"
42
+
43
+ msgid "sizes compressed"
44
+ msgstr "afmetingen gecomprimeerd"
45
+
46
+ msgid "%d size not compressed"
47
+ msgstr "%d afmeting niet gecomprimeerd"
48
+
49
+ msgid "%d sizes not compressed"
50
+ msgstr "%d afmetingen niet gecomprimeerd"
51
+
52
+ msgid "%d file removed"
53
+ msgstr "%d bestand verwijderd"
54
+
55
+ msgid "%d files removed"
56
+ msgstr "%d bestanden verwijderd"
57
+
58
+ msgid "%d file missing"
59
+ msgstr "%d bestand bestaat niet"
60
+
61
+ msgid "%d files missing"
62
+ msgstr "%d bestanden bestaan niet"
63
+
64
+ msgid "%d file modified after compression"
65
+ msgstr "%d bestand veranderd na comprimeren"
66
+
67
+ msgid "%d files modified after compression"
68
+ msgstr "%d bestanden veranderd na comprimeren"
69
+
70
+ msgid "Compression details for %s"
71
+ msgstr "Compressie details voor %s"
72
+
73
+ msgid "Size"
74
+ msgstr "Afmeting"
75
+
76
+ msgid "Date"
77
+ msgstr "Datum"
78
+
79
+ msgid "(resized to %dx%d)"
80
+ msgstr "(verkleind naar %dx%d)"
81
+
82
+ msgid "(modified after compression)"
83
+ msgstr "(veranderd na compressie)"
84
+
85
+ msgid "(file removed)"
86
+ msgstr "(bestand ontbreekt)"
87
+
88
+ msgid "ago"
89
+ msgstr "geleden"
90
+
91
+ msgid "Combined"
92
+ msgstr "Gecombineerd"
93
+
94
+ msgid "Total savings %s"
95
+ msgstr "Totaal bespaard %s"
96
 
97
+ msgid "size being compressed"
98
+ msgstr "afmeting wordt gecomprimeerd"
99
+
100
+ msgid "sizes being compressed"
101
+ msgstr "afmetingen worden gecomprimeerd"
102
 
103
  msgid "Total size"
104
  msgstr "Totale grootte"
105
 
106
+ msgid "Original"
107
+ msgstr "Origineel"
108
+
109
+ msgid "Compressed"
110
+ msgstr "Gecomprimeerd"
111
 
112
  msgid "Latest error"
113
  msgstr "Laatste fout"
148
  msgid "Could not download output"
149
  msgstr "Kon output niet downloaden"
150
 
151
+ msgid "File does not exist"
152
  msgstr "Bestand bestaat niet"
153
 
 
 
 
154
  msgid "Could not compress, enable cURL for detailed error"
155
  msgstr "Kon niet comprimeren, schakel cURL in voor een preciezere foutmelding"
156
 
196
  msgid "Upgrade your %s if you like to compress more images"
197
  msgstr "Upgrade je %s als je meer afbeeldingen wilt comprimeren"
198
 
199
+ msgid "Savings"
200
+ msgstr "Besparingen"
201
+
202
+ msgid "You have saved a total of %s on images"
203
+ msgstr "Je hebt in totaal %s bespaard op afbeeldingen"
204
+
205
+ msgid "No images compressed yet. Use %s to compress existing images"
206
+ msgstr "Nog geen gecomprimeerde afbeeldingen. Gebruik %s om bestaande afbeeldingen te comprimeren"
207
+
208
+ msgid "With these settings you can compress"
209
+ msgstr "Met deze instellingen kan je elke maand"
210
+
211
+ msgid "at least %s images"
212
+ msgstr "minstens %s afbeeldingen"
213
+
214
+ msgid "for free each month"
215
+ msgstr "gratis comprimeren"
216
+
217
+ msgid "With these settings no images will be compressed"
218
+ msgstr "Met deze instellingen worden geen afbeeldingen gecomprimeerd"
219
+
220
+ msgid "overwritten by compressed image"
221
+ msgstr "overschreven door gecomprimeerde afbeelding"
222
+
223
  msgid "Please fill in an API key to start compressing images"
224
  msgstr "Vul een API-sleutel in om te starten met comprimeren"
225
 
226
  msgid "Compress All Images"
227
+ msgstr "Comprimeer alle afbeeldingen"
228
 
229
  msgid "Compress JPEG & PNG Images"
230
  msgstr "Comprimeer JPEG & PNG afbeeldingen"
251
  msgstr "van de"
252
 
253
  msgid "Use this tool to compress all images in your media library"
254
+ msgstr "Deze tool comprimeert alle afbeeldingen in je mediabibliotheek"
255
 
256
  msgid "Only images that have not been compressed will be compressed"
257
  msgstr "Dit geldt alleen voor de afbeeldingen die nog niet zijn gecomprimeerd"
258
 
259
+ msgid "We have found %d images in your media library and for each image %d sizes will be compressed"
260
+ msgstr "We hebben %d afbeeldingen in de mediabibliotheek gevonden en voor elke afbeelding worden %d afmetingen gecomprimeerd"
261
+
262
+ msgid "This results in %d compressions at most"
263
+ msgstr "Dit resulteert in een maximaal verbruik van %d compressies"
264
 
265
  msgid "To begin, just press the button below"
266
  msgstr "Druk op de knop om te starten"
276
 
277
  msgid "You will be notified via this page when the processing is done"
278
  msgstr "Je wordt genotificeerd op deze pagina bij voltooing"
279
+
280
+ msgid "Settings"
281
+ msgstr "Instellingen"
282
+
283
+ msgid "Resize original"
284
+ msgstr "Orgineel verkleinen"
285
+
286
+ msgid "Enable the compression of the original image size to configure resizing"
287
+ msgstr "Schakel compressie van de originele afbeelding in om te kunnen verkleinen"
288
+
289
+ msgid "Resize and compress the orginal image"
290
+ msgstr "Verklein en comprimeer de originele afbeelding"
291
+
292
+ msgid "Resizing takes %s for each image that is larger"
293
+ msgstr "Verkleinen gebruikt %s voor elke afbeelding die groter is dan de vermelde afmetingen"
294
+
295
+ msgid "1 additional compression"
296
+ msgstr "1 extra compressie"
297
+
298
+ msgid "Resized original to %dx%d"
299
+ msgstr "Origineel verkleind tot %dx%d"
300
+
301
+ msgid "Max Width"
302
+ msgstr "Maximale breedte"
303
+
304
+ msgid "Max Height"
305
+ msgstr "Maximale hoogte"
src/languages/tiny-compress-images-ru_RU.mo CHANGED
Binary file
src/languages/tiny-compress-images-ru_RU.po CHANGED
@@ -13,16 +13,16 @@ msgstr ""
13
  "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
14
  "Language: ru_RU\n"
15
 
 
 
 
16
  msgid "PNG and JPEG compression"
17
  msgstr "Сжатие PNG и JPEG"
18
 
19
- msgid "Multisite PNG and JPEG compression"
20
- msgstr "PNG и JPEG сжатие для Multisite"
21
-
22
  msgid "Visit %s to get an API key"
23
  msgstr "Посетите %s, чтобы получить API ключ"
24
 
25
- msgid "Visit %s to view your usage or upgrade your account"
26
  msgstr "Посетите %s, чтобы посмотреть свою статистику использования сервиса и повысить статус аккаунта"
27
 
28
  msgid "TinyPNG Developer section"
@@ -31,9 +31,6 @@ msgstr "раздел TinyPNG для разработчиков"
31
  msgid "TinyPNG API key"
32
  msgstr "TinyPNG API ключ"
33
 
34
- msgid "Multisite API key"
35
- msgstr "Multisite API ключ"
36
-
37
  msgid "File compression"
38
  msgstr "Сжатие файлов"
39
 
@@ -43,7 +40,7 @@ msgstr "оригинальное изображение"
43
  msgid "You can choose to compress different image sizes created by WordPress here"
44
  msgstr "Здесь вы можете выбрать, какие размеры изображений сжимать"
45
 
46
- msgid "Remember each additional image size will affect your TinyPNG monthly usage"
47
  msgstr "Помните, каждый дополнительный типоразмер влияет на месячное использование сервиса TinyPNG"
48
 
49
  msgid "Compression"
@@ -103,12 +100,9 @@ msgstr "Не могу найти url результата"
103
  msgid "Could not download output"
104
  msgstr "Не могу загрузить результат"
105
 
106
- msgid "File does not exists"
107
  msgstr "Файл не существует или не найден плагином"
108
 
109
- msgid "Could not decode JSON"
110
- msgstr "Не могу раскодировать JSON"
111
-
112
  msgid "Could not compress, enable cURL for detailed error"
113
  msgstr "Не могу сжать. Подключите cURL для деталей"
114
 
13
  "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
14
  "Language: ru_RU\n"
15
 
16
+ msgid "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG."
17
+ msgstr "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG."
18
+
19
  msgid "PNG and JPEG compression"
20
  msgstr "Сжатие PNG и JPEG"
21
 
 
 
 
22
  msgid "Visit %s to get an API key"
23
  msgstr "Посетите %s, чтобы получить API ключ"
24
 
25
+ msgid "Visit %s to view or upgrade your account"
26
  msgstr "Посетите %s, чтобы посмотреть свою статистику использования сервиса и повысить статус аккаунта"
27
 
28
  msgid "TinyPNG Developer section"
31
  msgid "TinyPNG API key"
32
  msgstr "TinyPNG API ключ"
33
 
 
 
 
34
  msgid "File compression"
35
  msgstr "Сжатие файлов"
36
 
40
  msgid "You can choose to compress different image sizes created by WordPress here"
41
  msgstr "Здесь вы можете выбрать, какие размеры изображений сжимать"
42
 
43
+ msgid "Remember each selected size counts as a compression"
44
  msgstr "Помните, каждый дополнительный типоразмер влияет на месячное использование сервиса TinyPNG"
45
 
46
  msgid "Compression"
100
  msgid "Could not download output"
101
  msgstr "Не могу загрузить результат"
102
 
103
+ msgid "File does not exist"
104
  msgstr "Файл не существует или не найден плагином"
105
 
 
 
 
106
  msgid "Could not compress, enable cURL for detailed error"
107
  msgstr "Не могу сжать. Подключите cURL для деталей"
108
 
src/languages/tiny-compress-images-zh_TW.mo ADDED
Binary file
src/languages/tiny-compress-images-zh_TW.po ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "POT-Creation-Date: \n"
5
+ "PO-Revision-Date: \n"
6
+ "Language-Team: \n"
7
+ "MIME-Version: 1.0\n"
8
+ "Content-Type: text/plain; charset=UTF-8\n"
9
+ "Content-Transfer-Encoding: 8bit\n"
10
+ "X-Generator: Poedit 1.8.4\n"
11
+ "Last-Translator: Pseric <pserics@gmail.com>\n"
12
+ "Plural-Forms: nplurals=1; plural=0;\n"
13
+ "Language: zh_TW\n"
14
+
15
+ msgid "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG."
16
+ msgstr "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG."
17
+
18
+ msgid "PNG and JPEG compression"
19
+ msgstr "PNG 和 JPEG 壓縮"
20
+
21
+ msgid "Visit %s to get an API key"
22
+ msgstr "訪問 %s 取得一個 API 金鑰"
23
+
24
+ msgid "Visit %s to view or upgrade your account"
25
+ msgstr "訪問 %s 檢視你的使用量或升級你的帳號"
26
+
27
+ msgid "TinyPNG Developer section"
28
+ msgstr "TinyPNG 開發者功能"
29
+
30
+ msgid "TinyPNG API key"
31
+ msgstr "TinyPNG API 金鑰"
32
+
33
+ msgid "File compression"
34
+ msgstr "檔案壓縮"
35
+
36
+ msgid "original"
37
+ msgstr "原始大小"
38
+
39
+ msgid "You can choose to compress different image sizes created by WordPress here"
40
+ msgstr "你可以在這裡選擇要壓縮的圖片大小,由 WordPress 建立"
41
+
42
+ msgid "Remember each selected size counts as a compression"
43
+ msgstr "請記住,每個額外圖片尺寸都會影響你的 TinyPNG 每月使用量"
44
+
45
+ msgid "Compression"
46
+ msgstr "壓縮"
47
+
48
+ msgid "Compress"
49
+ msgstr "壓縮"
50
+
51
+ msgid "Compress Images"
52
+ msgstr "壓縮圖片"
53
+
54
+ msgid "Compressed %d out of %d sizes"
55
+ msgstr "已壓縮 %d/%d 個尺寸"
56
+
57
+ msgid "Compressing %d sizes..."
58
+ msgstr "壓縮 %d 個尺寸..."
59
+
60
+ msgid "Total size"
61
+ msgstr "總共大小"
62
+
63
+ msgid "Compressed size"
64
+ msgstr "已壓縮尺寸"
65
+
66
+ msgid "Latest error"
67
+ msgstr "最近錯誤"
68
+
69
+ msgid "Error"
70
+ msgstr "錯誤"
71
+
72
+ msgid "Internal error"
73
+ msgstr "內部錯誤"
74
+
75
+ msgid "Credentials are invalid"
76
+ msgstr "憑證無效"
77
+
78
+ msgid "Your monthly limit has been exceeded"
79
+ msgstr "你的每月限額已經超過"
80
+
81
+ msgid "File is empty"
82
+ msgstr "檔案是空的"
83
+
84
+ msgid "Does not appear to be a PNG or JPEG file"
85
+ msgstr "似乎不是一個 PNG 或 JPEG 檔案"
86
+
87
+ msgid "CMYK color space is not supported"
88
+ msgstr "不支援 CMYK 色彩空間"
89
+
90
+ msgid "Image appears corrupt"
91
+ msgstr "圖片似乎已經損壞"
92
+
93
+ msgid "Compression failed"
94
+ msgstr "壓縮失敗"
95
+
96
+ msgid "No HTTP client is available (cURL or fopen)"
97
+ msgstr "沒有 HTTP 客戶端可用(cURL 或 fopen)"
98
+
99
+ msgid "Could not find output url"
100
+ msgstr "找不到輸出網址"
101
+
102
+ msgid "Could not download output"
103
+ msgstr "無法下載輸出"
104
+
105
+ msgid "File does not exist"
106
+ msgstr "檔案不存在"
107
+
108
+ msgid "Could not compress, enable cURL for detailed error"
109
+ msgstr "無法壓縮,啟用 cURL 取得詳細錯誤資訊"
110
+
111
+ msgid "You don't have permission to work with uploaded files"
112
+ msgstr "你沒有權限來處理上傳的檔案"
113
+
114
+ msgid "Not a valid media file"
115
+ msgstr "不是一個有效的媒體檔案"
116
+
117
+ msgid "Could not find metadata of media file"
118
+ msgstr "找不到媒體檔案的 metadata"
119
+
120
+ msgid "The API key has been configured in %s"
121
+ msgstr "這個 API 金鑰已經設定在 %s"
122
+
123
+ msgid "Connection status"
124
+ msgstr "連線狀態"
125
+
126
+ msgid "Dismiss"
127
+ msgstr "拒絕"
128
+
129
+ msgid "TinyPNG API account"
130
+ msgstr "TinyPNG API 帳號"
131
+
132
+ msgid "API connection successful"
133
+ msgstr "API 連線成功"
134
+
135
+ msgid "API connection unsuccessful"
136
+ msgstr "API 連線不成功"
137
+
138
+ msgid "API status could not be checked, enable cURL for more information"
139
+ msgstr "無法檢查 API 狀態,啟用 cURL 取得更多資訊"
140
+
141
+ msgid "You have made %s compressions this month"
142
+ msgstr "本月你已經壓縮 %s 張圖片"
143
+
144
+ msgid "You have reached your limit of %s compressions this month"
145
+ msgstr "本月你已經到達你的壓縮限制 %s 張圖片"
146
+
147
+ msgid "If you need to compress more images you can change your %s"
148
+ msgstr "如果你需要壓縮更多圖片,你可以變更你的 %s"
149
+
150
+ msgid "Upgrade your %s if you like to compress more images"
151
+ msgstr "如果你想壓縮更多圖片,升級你的 %s"
152
+
153
+ msgid "Please fill in an API key to start compressing images"
154
+ msgstr "請填入一個 API 金鑰來開始壓縮圖片"
155
+
156
+ msgid "Compress All Images"
157
+ msgstr "壓縮所有圖片"
158
+
159
+ msgid "Compress JPEG & PNG Images"
160
+ msgstr "壓縮 JPEG & PNG 圖片"
161
+
162
+ msgid "All images are processed"
163
+ msgstr "所有圖片皆處理完成"
164
+
165
+ msgid "Compressions this month"
166
+ msgstr "本月壓縮"
167
+
168
+ msgid "Processing"
169
+ msgstr "處理中"
170
+
171
+ msgid "Waiting"
172
+ msgstr "等待中"
173
+
174
+ msgid "Compressing"
175
+ msgstr "壓縮中"
176
+
177
+ msgid "compressions"
178
+ msgstr "壓縮"
179
+
180
+ msgid "out of"
181
+ msgstr "以外"
182
+
183
+ msgid "Use this tool to compress all images in your media library"
184
+ msgstr "使用這個工具來壓縮你媒體庫的所有圖片"
185
+
186
+ msgid "Only images that have not been compressed will be compressed"
187
+ msgstr "只有沒被壓縮過的圖片才會壓縮"
188
+
189
+ msgid "We have found %d images in your media library"
190
+ msgstr "我們在你的媒體庫找到 %d 張圖片"
191
+
192
+ msgid "To begin, just press the button below"
193
+ msgstr "如要開始,只要點選下方案扭"
194
+
195
+ msgid "Please be patient while the images are being compressed"
196
+ msgstr "相片壓縮時請耐心等待"
197
+
198
+ msgid "This can take a while if you have many images"
199
+ msgstr "如果你有許多圖片,這可能需要一段時間"
200
+
201
+ msgid "Do not navigate away from this page because it will stop the process"
202
+ msgstr "請不要離開此頁面,因為它會停止壓縮程序"
203
+
204
+ msgid "You will be notified via this page when the processing is done"
205
+ msgstr "當處理完成後,你將透過此頁面取得通知"
src/scripts/admin.js CHANGED
@@ -8,6 +8,7 @@
8
  var element = jQuery(event.target)
9
  element.attr('disabled', 'disabled')
10
  element.closest('td').find('.spinner').removeClass('hidden')
 
11
  jQuery.ajax({
12
  url: ajaxurl,
13
  type: "POST",
@@ -155,6 +156,34 @@
155
 
156
  if (adminpage === "options-media-php") {
157
  jQuery('#tiny-compress-status').load(ajaxurl + '?action=tiny_compress_status')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
159
 
160
  jQuery('.tiny-notice a.tiny-dismiss').click(dismiss_notice)
@@ -163,4 +192,4 @@
163
  })
164
 
165
  window.tinyBulkCompress = bulk_compress
166
- }).call()
8
  var element = jQuery(event.target)
9
  element.attr('disabled', 'disabled')
10
  element.closest('td').find('.spinner').removeClass('hidden')
11
+ element.closest('td').find('span.dashicons').addClass('hidden')
12
  jQuery.ajax({
13
  url: ajaxurl,
14
  type: "POST",
156
 
157
  if (adminpage === "options-media-php") {
158
  jQuery('#tiny-compress-status').load(ajaxurl + '?action=tiny_compress_status')
159
+ jQuery('#tiny-compress-savings').load(ajaxurl + '?action=tiny_compress_savings')
160
+
161
+ jQuery('input[name*="tinypng_sizes"], input#tinypng_resize_original_enabled').on("click", function() {
162
+ // Unfortunately, we need some additional information to display the correct notice.
163
+ totalSelectedSizes = jQuery('input[name*="tinypng_sizes"]:checked').length
164
+ var image_count_url = ajaxurl + '?action=tiny_image_sizes_notice&image_sizes_selected=' + totalSelectedSizes
165
+ if (jQuery('input#tinypng_resize_original_enabled').prop('checked') && jQuery('input#tinypng_sizes_0').prop('checked')) {
166
+ image_count_url += '&resize_original=true'
167
+ }
168
+ jQuery('#tiny-image-sizes-notice').load(image_count_url)
169
+ })
170
+
171
+ function update_resize_settings() {
172
+ if (jQuery('#tinypng_sizes_0').prop('checked')) {
173
+ jQuery('.tiny-resize-available').show()
174
+ jQuery('.tiny-resize-unavailable').hide()
175
+ } else {
176
+ jQuery('.tiny-resize-available').hide()
177
+ jQuery('.tiny-resize-unavailable').show()
178
+ }
179
+
180
+ var elements = jQuery('#tinypng_resize_original_width, #tinypng_resize_original_height')
181
+ for (var i = 0; i < elements.length; i++) {
182
+ elements[i].disabled = !jQuery('#tinypng_resize_original_enabled').prop('checked')
183
+ }
184
+ }
185
+ update_resize_settings()
186
+ jQuery('#tinypng_sizes_0, #tinypng_resize_original_enabled').click(update_resize_settings)
187
  }
188
 
189
  jQuery('.tiny-notice a.tiny-dismiss').click(dismiss_notice)
192
  })
193
 
194
  window.tinyBulkCompress = bulk_compress
195
+ }).call()
src/styles/admin.css CHANGED
@@ -5,20 +5,93 @@
5
  margin-top: 0;
6
  }
7
 
8
- .tiny-compress-images .spinner {
9
  display: inline-block;
 
 
 
 
 
 
10
  visibility: visible;
11
  float: none;
12
- margin-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
- #tiny-compress-status .spinner {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  display: inline;
17
  visibility: visible;
18
  float: left;
19
  margin: 0;
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  #tiny-bulk-compress #media-items .bar.failed {
23
  background-color: #DD3D36;
24
  }
@@ -51,3 +124,15 @@
51
  box-shadow: 0px 1px 0px #DFDFDF;
52
  padding: 5px;
53
  }
 
 
 
 
 
 
 
 
 
 
 
 
5
  margin-top: 0;
6
  }
7
 
8
+ .tiny-compress-images div.spinner {
9
  display: inline-block;
10
+ visibility: visible;
11
+ float: right;
12
+ margin-top: 4px;
13
+ }
14
+
15
+ .tiny-compress-images span.spinner {
16
  visibility: visible;
17
  float: none;
18
+ margin: 0;
19
+ }
20
+
21
+ .tiny-compress-images .details-container {
22
+ overflow: auto;
23
+ }
24
+
25
+ .tiny-compress-images .details-container button {
26
+ display: block;
27
+ margin: 5px 0 10px 24px;
28
+ }
29
+
30
+ .tiny-compress-images .details-container span.icon {
31
+ position: absolute;
32
  }
33
 
34
+ .tiny-compress-images .details-container .message {
35
+ display: inline-block;
36
+ margin-left: 24px;
37
+ }
38
+
39
+ .tiny-compress-images .details-container span.success {
40
+ color: #0EE00E;
41
+ }
42
+
43
+ .tiny-compress-images .details-container span.error {
44
+ color: #D54E21;
45
+ }
46
+
47
+ .tiny-compress-images .details-container span.alert {
48
+ color: gray;
49
+ }
50
+
51
+ #tiny-compress-status .spinner, #tiny-compress-savings .spinner {
52
  display: inline;
53
  visibility: visible;
54
  float: left;
55
  margin: 0;
56
  }
57
 
58
+ .tiny-compression-details {
59
+ padding: 10px;
60
+ }
61
+
62
+ .tiny-compression-details table {
63
+ border: 1px solid #E5E5E5;
64
+ border-collapse: collapse;
65
+ white-space: nowrap;
66
+ width: 100%;
67
+ }
68
+
69
+ .tiny-compression-details table tr.even {
70
+ background-color: #F9F9F9;
71
+ }
72
+
73
+ .tiny-compression-details table td {
74
+ padding: 6px 10px;
75
+ }
76
+
77
+ .tiny-compression-details table th {
78
+ padding: 8px 10px;
79
+ border-bottom: 1px solid #E5E5E5;
80
+ font-size: 14px;
81
+ }
82
+
83
+ .tiny-compression-details table tfoot {
84
+ border-top: 1px solid #E5E5E5;
85
+ }
86
+
87
+ .tiny-compression-details table tfoot td {
88
+ padding: 8px 10px;
89
+ }
90
+
91
+ .tiny-compress-images .modal {
92
+ display: none;
93
+ }
94
+
95
  #tiny-bulk-compress #media-items .bar.failed {
96
  background-color: #DD3D36;
97
  }
124
  box-shadow: 0px 1px 0px #DFDFDF;
125
  padding: 5px;
126
  }
127
+
128
+ p.tiny-resize-resolution {
129
+ margin-left: 24px;
130
+ }
131
+
132
+ p.tiny-resize-resolution input {
133
+ margin-right: 6px;
134
+ }
135
+
136
+ input[type=number][name*="tinypng_resize_original"] {
137
+ width: 65px;
138
+ }
src/views/compress-details-processing.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <div class="details-container">
2
+ <div class="details">
3
+ <span class="icon spinner"></span>
4
+ <span class="message">
5
+ <strong><?php echo $compressing ?></strong>
6
+ <span><?php printf(self::ntranslate_escape('size being compressed', 'sizes being compressed', $compressing)) ?></span>
7
+ </span>
8
+ </div>
9
+ </div>
src/views/compress-details.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="details-container">
2
+ <div class="details">
3
+ <?php if ($error) { ?>
4
+ <span class="icon dashicons dashicons-warning error"></span>
5
+ <?php } else if ($missing > 0 || $modified > 0) { ?>
6
+ <span class="icon dashicons dashicons-yes alert"></span>
7
+ <?php } else if ($tiny_metadata->get_success_count() > 0 && count($uncompressed) > 0) { ?>
8
+ <span class="icon dashicons dashicons-yes alert"></span>
9
+ <?php } else if ($tiny_metadata->get_success_count() > 0) { ?>
10
+ <span class="icon dashicons dashicons-yes success"></span>
11
+ <?php } ?>
12
+ <span class="icon spinner hidden"></span>
13
+
14
+ <?php if ($tiny_metadata->get_compressed_count() > 0 || ($tiny_metadata->get_compressed_count() == 0 && count($uncompressed) == 0)) { ?>
15
+ <span class="message">
16
+ <strong><?php echo $tiny_metadata->get_compressed_count() ?></strong>
17
+ <span><?php printf(self::ntranslate_escape('size compressed', 'sizes compressed', $tiny_metadata->get_compressed_count())) ?></span>
18
+ </span>
19
+ <br/>
20
+ <?php } ?>
21
+
22
+ <?php if ($not_compressed_active > 0) { ?>
23
+ <span class="message">
24
+ <?php printf(self::ntranslate_escape('%d size not compressed', '%d sizes not compressed', $not_compressed_active), $not_compressed_active) ?>
25
+ </span>
26
+ <br />
27
+ <?php } ?>
28
+
29
+ <?php if ($missing > 0) { ?>
30
+ <span class="message">
31
+ <?php printf(self::ntranslate_escape('%d file removed', '%d files removed', $missing), $missing) ?>
32
+ </span>
33
+ <br />
34
+ <?php } ?>
35
+
36
+ <?php if ($modified > 0) { ?>
37
+ <span class="message">
38
+ <?php printf(self::ntranslate_escape('%d file modified after compression', '%d files modified after compression', $modified), $modified) ?>
39
+ </span>
40
+ <br />
41
+ <?php } ?>
42
+
43
+ <?php if ($savings["input"] - $savings["output"]) { ?>
44
+ <span class="message">
45
+ <?php printf(self::translate_escape('Total savings %s' ), str_replace( " ", "&nbsp;", size_format($savings["input"] - $savings["output"], 1))) ?>
46
+ </span>
47
+ <br />
48
+ <?php } ?>
49
+
50
+ <?php if ($error) { ?>
51
+ <span class="message error_message">
52
+ <?php echo self::translate_escape('Latest error') . ': '. self::translate_escape($error) ?>
53
+ </span>
54
+ <br/>
55
+ <?php } ?>
56
+
57
+ <?php if ($tiny_metadata->get_compressed_count() > 0) { ?>
58
+ <a class="thickbox message" href="#TB_inline?width=700&amp;height=500&amp;inlineId=modal_<?php echo $tiny_metadata->get_id() ?>">Details</a>
59
+ <?php } ?>
60
+ </div>
61
+
62
+ <?php if (count($uncompressed) > 0) { ?>
63
+ <button type="button" class="tiny-compress button button-small button-primary" data-id="<?php echo $tiny_metadata->get_id() ?>">
64
+ <?php echo self::translate_escape('Compress') ?>
65
+ </button>
66
+ <?php } ?>
67
+ </div>
68
+ <?php if ($tiny_metadata->get_compressed_count() > 0) { ?>
69
+ <div class="modal" id="modal_<?php echo $tiny_metadata->get_id() ?>">
70
+ <div class="tiny-compression-details">
71
+ <h3><?php printf(self::translate_escape('Compression details for %s'), $tiny_metadata->get_name()) ?></h3>
72
+ <table>
73
+ <tr>
74
+ <th><?php echo self::translate_escape('Size') ?></th>
75
+ <th><?php echo self::translate_escape('Original') ?></th>
76
+ <th><?php echo self::translate_escape('Compressed') ?></th>
77
+ <th><?php echo self::translate_escape('Date') ?></th>
78
+ </tr>
79
+ <?php $i = 0; ?>
80
+ <?php foreach ($tiny_metadata->get_compressed_sizes() as $size) { ?>
81
+ <?php $meta = $tiny_metadata->get_value($size); ?>
82
+ <tr class="<?php echo ($i % 2 == 0) ? 'even' : 'odd' ?>">
83
+ <td>
84
+ <?php
85
+ echo ($size == "0" ? self::translate_escape('original') : $size ) . ' ';
86
+ if ($tiny_metadata->still_exists($size)) {
87
+ if ($tiny_metadata->is_compressed($size)) {
88
+ if ($tiny_metadata->is_resized($size)) {
89
+ printf('<em>' . self::translate_escape('(resized to %dx%d)') . '</em>', $meta['output']['width'], $meta['output']['height']);
90
+ }
91
+ } else {
92
+ echo '<em>' . self::translate_escape('(modified after compression)') . '</em>';
93
+ }
94
+ } else {
95
+ echo '<em>' . self::translate_escape('(file removed)') . '</em>';
96
+ }
97
+ ?>
98
+ </td>
99
+ <td><?php echo size_format($meta["input"]["size"], 1) ?></td>
100
+ <td><?php echo size_format($meta["output"]["size"], 1) ?></td>
101
+ <td><?php echo human_time_diff($tiny_metadata->get_end_time($size)) . ' ' . self::translate_escape('ago') ?></td>
102
+ </tr>
103
+ <?php $i++; ?>
104
+ <?php } ?>
105
+ <?php if ($savings['count'] > 0) { ?>
106
+ <tfoot>
107
+ <tr>
108
+ <td><?php echo self::translate_escape('Combined') ?></td>
109
+ <td><?php echo size_format($savings['input'], 1) ?></td>
110
+ <td><?php echo size_format($savings['output'], 1) ?></td>
111
+ <td></td>
112
+ </tr>
113
+ </tfoot>
114
+ <?php } ?>
115
+ </table>
116
+ <p><strong><?php printf( self::translate_escape( 'Total savings %s' ), size_format($savings["input"] - $savings["output"], 1)) ?></strong></p>
117
+ </div>
118
+ </div>
119
+ <?php } ?>
test/fixtures/input-large.jpg ADDED
Binary file
test/fixtures/json/wp_meta_default_sizes.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "width": 1256,
3
+ "height": 1256,
4
+ "file": "2015/09/tinypng_gravatar.png",
5
+ "sizes": {
6
+ "thumbnail": {
7
+ "file": "tinypng_gravatar-150x150.png",
8
+ "width": 150,
9
+ "height": 150,
10
+ "mime-type": "image/png"
11
+ },
12
+ "medium": {
13
+ "file": "tinypng_gravatar-300x300.png",
14
+ "width": 300,
15
+ "height": 300,
16
+ "mime-type": "image/png"
17
+ },
18
+ "large": {
19
+ "file": "tinypng_gravatar-600x600.png",
20
+ "width": 600,
21
+ "height": 600,
22
+ "mime-type": "image/png"
23
+ }
24
+ },
25
+ "image_meta": {
26
+ }
27
+ }
test/fixtures/json/wp_meta_sizes_with_same_files.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "width": 1080,
3
+ "height": 720,
4
+ "file": "2015/09/panda.png",
5
+ "sizes": {
6
+ "custom-size": {
7
+ "file": "panda-150x150.png",
8
+ "width": 150,
9
+ "height": 150,
10
+ "mime-type": "image/png"
11
+ },
12
+ "custom-size-2": {
13
+ "file": "panda-150x150.png",
14
+ "width": 150,
15
+ "height": 150,
16
+ "mime-type": "image/png"
17
+ }
18
+ },
19
+ "image_meta": {
20
+ }
21
+ }
test/helpers/setup.php CHANGED
@@ -103,8 +103,12 @@ function setup_wordpress_site($driver) {
103
  }
104
  $driver->findElement(WebDriverBy::name('weblog_title'))->sendKeys('Wordpress test');
105
  $driver->findElement(WebDriverBy::name('user_name'))->clear()->sendKeys('admin');
106
- $driver->findElement(WebDriverBy::name('admin_password'))->sendKeys('admin');
107
- $driver->findElement(WebDriverBy::name('admin_password2'))->sendKeys('admin');
 
 
 
 
108
  $driver->findElement(WebDriverBy::name('admin_email'))->sendKeys('developers@voormedia.com');
109
  $driver->findElement(WebDriverBy::tagName('form'))->submit();
110
  $h1s = $driver->findElements(WebDriverBy::tagName('h1'));
@@ -118,13 +122,16 @@ function setup_wordpress_site($driver) {
118
  }
119
 
120
  function login($driver) {
 
121
  $driver->get(wordpress('/wp-login.php'));
122
  $driver->findElement(WebDriverBy::tagName('body'))->click();
123
  $driver->findElement(WebDriverBy::name('log'))->clear()->click()->sendKeys('admin');
124
  $driver->findElement(WebDriverBy::name('pwd'))->clear()->click()->sendKeys('admin');
125
  $driver->findElement(WebDriverBy::tagName('form'))->submit();
126
- if ($driver->findElement(WebDriverBy::tagName('h2'))->getText() == 'Dashboard') {
127
- print "Successfully logged into WordPress.\n";
 
 
128
  } else {
129
  var_dump($driver->getPageSource());
130
  throw new UnexpectedValueException('Login failed.');
@@ -157,7 +164,6 @@ function reset_webservice() {
157
  curl_setopt_array($request, array(
158
  CURLOPT_URL => 'http://' . getenv('HOST_IP') .':8080/reset',
159
  ));
160
-
161
  $response = curl_exec($request);
162
  curl_close($request);
163
  }
103
  }
104
  $driver->findElement(WebDriverBy::name('weblog_title'))->sendKeys('Wordpress test');
105
  $driver->findElement(WebDriverBy::name('user_name'))->clear()->sendKeys('admin');
106
+ if (wordpress_version() > 42) {
107
+ $driver->findElement(WebDriverBy::id('pass1-text'))->clear()->sendKeys('a')->sendKeys('dmin');
108
+ } else {
109
+ $driver->findElement(WebDriverBy::name('admin_password'))->sendKeys('admin');
110
+ $driver->findElement(WebDriverBy::name('admin_password2'))->sendKeys('admin');
111
+ }
112
  $driver->findElement(WebDriverBy::name('admin_email'))->sendKeys('developers@voormedia.com');
113
  $driver->findElement(WebDriverBy::tagName('form'))->submit();
114
  $h1s = $driver->findElements(WebDriverBy::tagName('h1'));
122
  }
123
 
124
  function login($driver) {
125
+ print "Logging in to WordPress... ";
126
  $driver->get(wordpress('/wp-login.php'));
127
  $driver->findElement(WebDriverBy::tagName('body'))->click();
128
  $driver->findElement(WebDriverBy::name('log'))->clear()->click()->sendKeys('admin');
129
  $driver->findElement(WebDriverBy::name('pwd'))->clear()->click()->sendKeys('admin');
130
  $driver->findElement(WebDriverBy::tagName('form'))->submit();
131
+
132
+ $dashboardHeading = $driver->findElement(WebDriverBy::xpath("//html/body//div[@class='wrap']/*[self::h1 or self::h2]"));
133
+ if ($dashboardHeading->getText() == 'Dashboard') {
134
+ print "success!\n";
135
  } else {
136
  var_dump($driver->getPageSource());
137
  throw new UnexpectedValueException('Login failed.');
164
  curl_setopt_array($request, array(
165
  CURLOPT_URL => 'http://' . getenv('HOST_IP') .':8080/reset',
166
  ));
 
167
  $response = curl_exec($request);
168
  curl_close($request);
169
  }
test/helpers/wordpress.php CHANGED
@@ -136,6 +136,10 @@ class WordPressStubs {
136
  $this->metadata[$id][$key] = $values;
137
  }
138
 
 
 
 
 
139
  public function getCalls($method) {
140
  return $this->calls[$method];
141
  }
@@ -156,9 +160,20 @@ class WordPressStubs {
156
  $this->stubs[$method] = $func;
157
  }
158
 
 
 
 
 
 
 
 
 
 
 
 
159
  public function createImages($sizes=null, $original_size=12345, $path='14/01', $name='test') {
160
  vfsStream::newDirectory(self::UPLOAD_DIR . "/$path")->at($this->vfs);
161
- $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/$path");
162
 
163
  vfsStream::newFile("$name.png")
164
  ->withContent(new LargeFileContent($original_size))
@@ -175,8 +190,36 @@ class WordPressStubs {
175
  }
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  public function getTestMetadata($path='14/01', $name='test') {
179
- $metadata = array('file' => "$path/$name.png", 'sizes' => array());
 
 
 
 
 
180
 
181
  $regex = '#^' . preg_quote($name) .'-([^.]+)[.](png|jpe?g)$#';
182
  $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/$path");
136
  $this->metadata[$id][$key] = $values;
137
  }
138
 
139
+ public function setMetadata($id, $values) {
140
+ $this->metadata[$id] = $values;
141
+ }
142
+
143
  public function getCalls($method) {
144
  return $this->calls[$method];
145
  }
160
  $this->stubs[$method] = $func;
161
  }
162
 
163
+ public function createImage($file_size, $path, $name) {
164
+ if (!$this->vfs->hasChild(self::UPLOAD_DIR . "/$path")) {
165
+ vfsStream::newDirectory(self::UPLOAD_DIR . "/$path")->at($this->vfs);
166
+ }
167
+ $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/$path");
168
+
169
+ vfsStream::newFile($name)
170
+ ->withContent(new LargeFileContent($file_size))
171
+ ->at($dir);
172
+ }
173
+
174
  public function createImages($sizes=null, $original_size=12345, $path='14/01', $name='test') {
175
  vfsStream::newDirectory(self::UPLOAD_DIR . "/$path")->at($this->vfs);
176
+ $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/" . $path);
177
 
178
  vfsStream::newFile("$name.png")
179
  ->withContent(new LargeFileContent($original_size))
190
  }
191
  }
192
 
193
+ public function createImagesFromMeta($wp_meta, $tiny_meta, $original_size = 1234567) {
194
+ $parts = explode("/", $wp_meta["file"]);
195
+ $file = array_pop($parts);
196
+ $path = implode("/", $parts);
197
+
198
+ vfsStream::newDirectory(self::UPLOAD_DIR . "/$path")->at($this->vfs);
199
+ $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/" . $path);
200
+
201
+ vfsStream::newFile($file)
202
+ ->withContent(new LargeFileContent($original_size))
203
+ ->at($dir);
204
+
205
+ foreach ($wp_meta["sizes"] as $image_size => $values) {
206
+ if (isset($tiny_meta[Tiny_Metadata::META_KEY][$image_size])) {
207
+ $file_size = $tiny_meta[Tiny_Metadata::META_KEY][$image_size]["output"]["size"];
208
+ vfsStream::newFile($values["file"])
209
+ ->withContent(new LargeFileContent($file_size))
210
+ ->at($dir);
211
+ }
212
+ }
213
+
214
+ }
215
+
216
  public function getTestMetadata($path='14/01', $name='test') {
217
+ $metadata = array(
218
+ 'file' => "$path/$name.png",
219
+ 'width' => 4000,
220
+ 'height' => 3000,
221
+ 'sizes' => array()
222
+ );
223
 
224
  $regex = '#^' . preg_quote($name) .'-([^.]+)[.](png|jpe?g)$#';
225
  $dir = $this->vfs->getChild(self::UPLOAD_DIR . "/$path");
test/integration/BulkCompressIntegrationTest.php CHANGED
@@ -35,7 +35,7 @@ class BulkCompressIntegrationTest extends IntegrationTestCase {
35
  $this->enable_compression_sizes(array('thumbnail', 'medium', 'large'));
36
  }
37
 
38
- public function testBulkCompressShouldFromMediaShouldOnlyCompressSelected() {
39
  $this->prepare(1, 2);
40
 
41
  self::$driver->get(wordpress('/wp-admin/upload.php?orderby=title&order=asc'));
@@ -55,7 +55,7 @@ class BulkCompressIntegrationTest extends IntegrationTestCase {
55
  public function testBulkCompressShouldCompressAll() {
56
  $this->prepare(1, 1);
57
 
58
- self::$driver->get(wordpress('/wp-admin/tools.php?page=tiny-bulk-compress.php'));
59
  $elements = self::$driver->findElements(WebDriverBy::cssSelector('#tiny-bulk-compress p'));
60
  $this->assertContains('2 images', $elements[1]->getText());
61
 
35
  $this->enable_compression_sizes(array('thumbnail', 'medium', 'large'));
36
  }
37
 
38
+ public function testBulkCompressFromMediaShouldOnlyCompressSelected() {
39
  $this->prepare(1, 2);
40
 
41
  self::$driver->get(wordpress('/wp-admin/upload.php?orderby=title&order=asc'));
55
  public function testBulkCompressShouldCompressAll() {
56
  $this->prepare(1, 1);
57
 
58
+ self::$driver->get(wordpress('/wp-admin/upload.php?page=tiny-bulk-compress.php'));
59
  $elements = self::$driver->findElements(WebDriverBy::cssSelector('#tiny-bulk-compress p'));
60
  $this->assertContains('2 images', $elements[1]->getText());
61
 
test/integration/CompressIntegrationTest.php CHANGED
@@ -26,13 +26,13 @@ class CompressIntegrationTest extends IntegrationTestCase {
26
  $this->set_api_key('1234');
27
  $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
28
  $this->assertContains('Latest error: Credentials are invalid',
29
- self::$driver->findElement(WebDriverBy::cssSelector('span.error'))->getText());
30
  }
31
 
32
  public function testShrink() {
33
  $this->set_api_key('PNG123');
34
  $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
35
- $this->assertContains('Compressed size',
36
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
37
  }
38
 
@@ -43,11 +43,13 @@ class CompressIntegrationTest extends IntegrationTestCase {
43
  $this->enable_compression_sizes(array('medium', 'large'));
44
 
45
  self::$driver->get(wordpress('/wp-admin/upload.php'));
46
- $this->assertContains('Compressed 1 out of 2 sizes',
 
 
47
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
48
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images button'))->click();
49
  self::$driver->wait(2)->until(WebDriverExpectedCondition::textToBePresentInElement(
50
- WebDriverBy::cssSelector('td.tiny-compress-images'), 'Compressed 2 out of 2 sizes'));
51
  }
52
 
53
  public function testLimitReached() {
@@ -67,4 +69,68 @@ class CompressIntegrationTest extends IntegrationTestCase {
67
  self::$driver->get(wordpress('/wp-admin/options-media.php'));
68
  $this->assertEquals(0, count(self::$driver->findElements(WebDriverBy::cssSelector('div.error p'))));
69
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
26
  $this->set_api_key('1234');
27
  $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
28
  $this->assertContains('Latest error: Credentials are invalid',
29
+ self::$driver->findElement(WebDriverBy::cssSelector('span.details'))->getText());
30
  }
31
 
32
  public function testShrink() {
33
  $this->set_api_key('PNG123');
34
  $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
35
+ $this->assertContains('sizes compressed',
36
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
37
  }
38
 
43
  $this->enable_compression_sizes(array('medium', 'large'));
44
 
45
  self::$driver->get(wordpress('/wp-admin/upload.php'));
46
+ $this->assertContains('1 size compressed',
47
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
48
+ $this->assertContains('1 size not compressed',
49
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
50
  self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images button'))->click();
51
  self::$driver->wait(2)->until(WebDriverExpectedCondition::textToBePresentInElement(
52
+ WebDriverBy::cssSelector('td.tiny-compress-images'), '2 sizes compressed'));
53
  }
54
 
55
  public function testLimitReached() {
69
  self::$driver->get(wordpress('/wp-admin/options-media.php'));
70
  $this->assertEquals(0, count(self::$driver->findElements(WebDriverBy::cssSelector('div.error p'))));
71
  }
72
+
73
+ public function testIncorrectJsonButton() {
74
+ $this->enable_compression_sizes(array());
75
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
76
+ $this->enable_compression_sizes(array('medium', 'large'));
77
+
78
+ $this->set_api_key('JSON1234');
79
+ self::$driver->get(wordpress('/wp-admin/upload.php'));
80
+
81
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images button'))->click();
82
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::textToBePresentInElement(
83
+ WebDriverBy::cssSelector('td.tiny-compress-images'), 'JSON: Syntax error [4]'));
84
+ }
85
+
86
+ public function testResizeFit() {
87
+ $this->set_api_key('JPG123');
88
+ $this->enable_resize(300, 200);
89
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-large.png');
90
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images a.thickbox'))->click();
91
+ $this->assertContains('resized to 300x200',
92
+ self::$driver->findElement(WebDriverBy::cssSelector('div.tiny-compression-details'))->getText());
93
+ $this->view_edit_image();
94
+ $this->assertContains('Dimensions: 300 × 200',
95
+ self::$driver->findElement(WebDriverBy::cssSelector('div.misc-pub-dimensions'))->getText());
96
+ }
97
+
98
+ public function testResizeScale() {
99
+ $this->set_api_key('JPG123');
100
+ $this->enable_resize(0, 200);
101
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-large.jpg');
102
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images a.thickbox'))->click();
103
+ $this->assertContains('resized to 300x200', self::$driver->findElement(
104
+ WebDriverBy::cssSelector('div.tiny-compression-details'))->getText());
105
+ $this->view_edit_image();
106
+ $this->assertContains('Dimensions: 300 × 200',
107
+ self::$driver->findElement(WebDriverBy::cssSelector('div.misc-pub-dimensions'))->getText());
108
+ }
109
+
110
+ public function testResizeNotNeeded()
111
+ {
112
+ $this->set_api_key('JPG123');
113
+ $this->enable_resize(30000, 20000);
114
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-large.jpg');
115
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images a.thickbox'))->click();
116
+ $this->assertNotContains('resized',
117
+ self::$driver->findElement(WebDriverBy::cssSelector('div.tiny-compression-details'))->getText());
118
+ $this->view_edit_image();
119
+ $this->assertContains('Dimensions: 1080 × 330',
120
+ self::$driver->findElement(WebDriverBy::cssSelector('div.misc-pub-dimensions'))->getText());
121
+ }
122
+
123
+ public function testResizeDisabled()
124
+ {
125
+ $this->set_api_key('JPG123');
126
+ $this->enable_resize(300, 200);
127
+ $this->disable_resize();
128
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-large.jpg');
129
+ self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images a.thickbox'))->click();
130
+ $this->assertNotContains('resized',
131
+ self::$driver->findElement(WebDriverBy::cssSelector('div.tiny-compression-details'))->getText());
132
+ $this->view_edit_image();
133
+ $this->assertContains('Dimensions: 1080 × 330',
134
+ self::$driver->findElement(WebDriverBy::cssSelector('div.misc-pub-dimensions'))->getText());
135
+ }
136
  }
test/integration/IntegrationTestCase.php CHANGED
@@ -62,4 +62,43 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase {
62
  }
63
  self::$driver->findElement(WebDriverBy::tagName('form'))->submit();
64
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
62
  }
63
  self::$driver->findElement(WebDriverBy::tagName('form'))->submit();
64
  }
65
+
66
+ protected function enable_resize($width, $height) {
67
+ $url = wordpress('/wp-admin/options-media.php');
68
+ if (self::$driver->getCurrentUrl() != $url) {
69
+ self::$driver->get($url);
70
+ }
71
+ $element = self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_enabled'));
72
+ if (!$element->getAttribute('checked')) {
73
+ $element->click();
74
+ }
75
+ self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_width'))->clear()->sendKeys($width);
76
+ self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_height'))->clear()->sendKeys($height);
77
+ self::$driver->findElement(WebDriverBy::tagName('form'))->submit();
78
+ }
79
+
80
+ protected function disable_resize() {
81
+ $url = wordpress('/wp-admin/options-media.php');
82
+ if (self::$driver->getCurrentUrl() != $url) {
83
+ self::$driver->get($url);
84
+ }
85
+ $element = self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_enabled'));
86
+ if ($element->getAttribute('checked')) {
87
+ $element->click();
88
+ }
89
+ self::$driver->findElement(WebDriverBy::tagName('form'))->submit();
90
+ }
91
+
92
+ protected function view_edit_image($image_title = 'input-large') {
93
+ $url = wordpress('/wp-admin/upload.php');
94
+ if (self::$driver->getCurrentUrl() != $url) {
95
+ self::$driver->get($url);
96
+ }
97
+ if (wordpress_version() >= 43) {
98
+ $selector = "//span[text()='" . $image_title . "']";
99
+ } else {
100
+ $selector = "//a[contains(text(),'" . $image_title . "')]";
101
+ }
102
+ self::$driver->findElement(WebDriverBy::xpath($selector))->click();
103
+ }
104
  }
test/integration/PluginIntegrationTest.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . "/IntegrationTestCase.php");
4
+
5
+ class PluginIntegrationTest extends IntegrationTestCase {
6
+
7
+ public function setUp() {
8
+ parent::setUp();
9
+ self::$driver->get(wordpress('/wp-admin/plugins.php'));
10
+ }
11
+
12
+ public function tearDown() {
13
+ clear_settings();
14
+ }
15
+
16
+ public function testTitlePresence()
17
+ {
18
+ $element = self::$driver->findElements(WebDriverBy::xpath('//*[@id="compress-jpeg-png-images"]//a[text()="Settings"]'));
19
+ $this->assertStringEndsWith('options-media.php#tiny-compress-images', $element[0]->getAttribute('href'));
20
+ }
21
+ }
test/integration/SettingsIntegrationTest.php CHANGED
@@ -86,9 +86,73 @@ class SettingsIntegrationTest extends IntegrationTestCase {
86
  $this->assertEquals(0, count(array_map('elementName', $elements)));
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  public function testStatusPresenceOK() {
90
  reset_webservice();
91
  $this->set_api_key('PNG123');
 
92
  $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-status'))->findElements(WebDriverBy::tagName('p'));
93
  $statuses = array_map('innerText', $elements);
94
  $this->assertContains('API connection successful', $statuses);
@@ -97,8 +161,28 @@ class SettingsIntegrationTest extends IntegrationTestCase {
97
 
98
  public function testStatusPresenseFail() {
99
  $this->set_api_key('INVALID123');
 
100
  $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-status'))->findElements(WebDriverBy::tagName('p'));
101
  $statuses = array_map('innerText', $elements);
102
- $this->assertContains('API connection unsuccessful', $statuses);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
  }
86
  $this->assertEquals(0, count(array_map('elementName', $elements)));
87
  }
88
 
89
+ public function testShouldShowTotalImagesInfo() {
90
+ $elements = self::$driver->findElement(WebDriverBy::id('tiny-image-sizes-notice'))->findElements(WebDriverBy::tagName('p'));
91
+ $statuses = array_map('innerText', $elements);
92
+ $this->assertContains('With these settings you can compress at least 100 images for free each month.', $statuses);
93
+ }
94
+
95
+ public function testShouldUpdateTotalImagesInfo() {
96
+ $element = self::$driver->findElement(
97
+ WebDriverBy::xpath('//input[@type="checkbox" and @name="tinypng_sizes[0]" and @checked="checked"]'));
98
+ $element->click();
99
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::textToBePresentInElement(
100
+ WebDriverBy::cssSelector('#tiny-image-sizes-notice'), 'With these settings you can compress at least 125 images for free each month.'));
101
+ // Not really necessary anymore to assert this.
102
+ $elements = self::$driver->findElement(WebDriverBy::id('tiny-image-sizes-notice'))->findElements(WebDriverBy::tagName('p'));
103
+ $statuses = array_map('innerText', $elements);
104
+ $this->assertContains('With these settings you can compress at least 125 images for free each month.', $statuses);
105
+ }
106
+
107
+ public function testShouldShowCorrectNoImageSizesInfo() {
108
+ $elements = self::$driver->findElements(
109
+ WebDriverBy::xpath('//input[@type="checkbox" and starts-with(@name, "tinypng_sizes") and @checked="checked"]'));
110
+ foreach ($elements as $element) {
111
+ $element->click();
112
+ }
113
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::textToBePresentInElement(
114
+ WebDriverBy::cssSelector('#tiny-image-sizes-notice'), 'With these settings no images will be compressed.'));
115
+ // Not really necessary anymore to assert this.
116
+ $elements = self::$driver->findElement(WebDriverBy::id('tiny-image-sizes-notice'))->findElements(WebDriverBy::tagName('p'));
117
+ $statuses = array_map('innerText', $elements);
118
+ $this->assertContains('With these settings no images will be compressed.', $statuses);
119
+ }
120
+
121
+ public function testShouldShowResizingWhenOriginalEnabled() {
122
+ $element = self::$driver->findElement(WebDriverBy::id('tinypng_sizes_0'));
123
+ if (!$element->getAttribute('checked')) {
124
+ $element->click();
125
+ }
126
+ $labels = self::$driver->findElements(WebDriverBy::tagName('label'));
127
+ $texts = array_map('innerText', $labels);
128
+ $this->assertContains('Resize and compress orginal images to fit within:', $texts);
129
+ $paragraphs = self::$driver->findElements(WebDriverBy::tagName('p'));
130
+ $texts = array_map('innerText', $paragraphs);
131
+ $this->assertNotContains('Enable the compression of the original image size to configure resizing.', $texts);
132
+ }
133
+
134
+ public function testShouldNotShowResizingWhenOriginalDisabled() {
135
+ $element = self::$driver->findElement(WebDriverBy::id('tinypng_sizes_0'));
136
+ if ($element->getAttribute('checked')) {
137
+ $element->click();
138
+ }
139
+ self::$driver->wait(1)->until(WebDriverExpectedCondition::textToBePresentInElement(
140
+ WebDriverBy::cssSelector('p.tiny-resize-unavailable'), 'Enable the compression of the original image size to configure resizing.'));
141
+ $labels = self::$driver->findElements(WebDriverBy::tagName('label'));
142
+ $texts = array_map('innerText', $labels);
143
+ $this->assertNotContains('Resize and compress orginal images to fit within:', $texts);
144
+ }
145
+
146
+ public function testShouldPersistResizingSettings() {
147
+ $this->enable_resize(123, 456);
148
+ $this->assertEquals('123', self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_width'))->getAttribute('value'));
149
+ $this->assertEquals('456', self::$driver->findElement(WebDriverBy::id('tinypng_resize_original_height'))->getAttribute('value'));
150
+ }
151
+
152
  public function testStatusPresenceOK() {
153
  reset_webservice();
154
  $this->set_api_key('PNG123');
155
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('#tiny-compress-status p')));
156
  $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-status'))->findElements(WebDriverBy::tagName('p'));
157
  $statuses = array_map('innerText', $elements);
158
  $this->assertContains('API connection successful', $statuses);
161
 
162
  public function testStatusPresenseFail() {
163
  $this->set_api_key('INVALID123');
164
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('#tiny-compress-status p')));
165
  $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-status'))->findElements(WebDriverBy::tagName('p'));
166
  $statuses = array_map('innerText', $elements);
167
+ $this->assertContains('API connection unsuccessful', $statuses[0]);
168
+ }
169
+
170
+ public function testShouldShowBulkCompressionLink() {
171
+ reset_webservice();
172
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('#tiny-compress-savings p')));
173
+ $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-savings'))->findElements(WebDriverBy::tagName('p'));
174
+ $statuses = array_map('innerText', $elements);
175
+ $this->assertContains('No images compressed yet. Use Compress All Images to compress existing images.', $statuses);
176
+ }
177
+
178
+ public function testShouldShowSavings() {
179
+ reset_webservice();
180
+ $this->set_api_key('PNG123');
181
+ $this->upload_image(dirname(__FILE__) . '/../fixtures/input-example.png');
182
+ self::$driver->get(wordpress('/wp-admin/options-media.php'));
183
+ self::$driver->wait(2)->until(WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('#tiny-compress-savings p')));
184
+ $elements = self::$driver->findElement(WebDriverBy::id('tiny-compress-savings'))->findElements(WebDriverBy::tagName('p'));
185
+ $statuses = array_map('innerText', $elements);
186
+ $this->assertContains('You have saved a total of 53.0 kB on images!', $statuses);
187
  }
188
  }
test/mock-tinypng-webservice/common.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('SESSION_FILE', '/tmp/session.dat');
4
+
5
+ if (file_exists(SESSION_FILE)) {
6
+ $session = unserialize(file_get_contents(SESSION_FILE));
7
+ } else {
8
+ $session = array('Compression-Count' => 0);
9
+ }
10
+
11
+ function save_session() {
12
+ global $session;
13
+ if ($session) {
14
+ file_put_contents(SESSION_FILE, serialize($session));
15
+ } elseif (file_exists(SESSION_FILE)) {
16
+ unlink(SESSION_FILE);
17
+ }
18
+ }
19
+ register_shutdown_function('save_session');
20
+
21
+ function get_api_key() {
22
+ $request_headers = apache_request_headers();
23
+ if (!isset($request_headers['Authorization'])) {
24
+ return null;
25
+ }
26
+ $basic_auth = base64_decode(str_replace('Basic ', '', $request_headers['Authorization']));
27
+ return next(explode(':', $basic_auth));
28
+ }
29
+
30
+ function get_json_body() {
31
+ return json_decode(file_get_contents("php://input"));
32
+ }
33
+
34
+ function mock_invalid_response() {
35
+ global $session;
36
+
37
+ header('HTTP/1.1 401 Unauthorized');
38
+ header("Content-Type: application/json; charset=utf-8");
39
+
40
+ $response = array(
41
+ "error" => "Unauthorized",
42
+ "message" => "Credentials are invalid"
43
+ );
44
+ return json_encode($response);
45
+ }
test/mock-tinypng-webservice/output-resized.jpg ADDED
Binary file
test/mock-tinypng-webservice/output.php CHANGED
@@ -1,13 +1,33 @@
1
  <?php
2
  ob_start();
3
 
 
 
4
  if (preg_match('#output/.+[.](png|jpg)$#', $_SERVER['REQUEST_URI'], $match)) {
5
  $file = str_replace('/', '-', $match[0]);
 
6
  $mime = $match[1] == 'jpg' ? 'image/jpeg' : "image/$ext";
7
  } else {
8
  $file = null;
9
  }
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  if ($file && file_exists($file)) {
12
  header("Content-Type: $mime");
13
  header('Content-Disposition: attachment');
@@ -16,4 +36,4 @@ if ($file && file_exists($file)) {
16
  header("HTTP/1.1 404 Not Found");
17
  }
18
 
19
- ob_end_flush();
1
  <?php
2
  ob_start();
3
 
4
+ require_once('common.php');
5
+
6
  if (preg_match('#output/.+[.](png|jpg)$#', $_SERVER['REQUEST_URI'], $match)) {
7
  $file = str_replace('/', '-', $match[0]);
8
+ $ext = $match[1];
9
  $mime = $match[1] == 'jpg' ? 'image/jpeg' : "image/$ext";
10
  } else {
11
  $file = null;
12
  }
13
 
14
+ $api_key = get_api_key();
15
+ if (!is_null($api_key)) {
16
+ $data = get_json_body();
17
+ if (is_null($data) || $api_key != 'JPG123') {
18
+ mock_invalid_response();
19
+ ob_end_flush();
20
+ exit();
21
+ }
22
+
23
+ $resize = $data->resize;
24
+ if ($resize->method) {
25
+ $file = "output-resized.$ext";
26
+ header("Image-Width: {$resize->width}");
27
+ header("Image-Height: {$resize->height}");
28
+ }
29
+ }
30
+
31
  if ($file && file_exists($file)) {
32
  header("Content-Type: $mime");
33
  header('Content-Disposition: attachment');
36
  header("HTTP/1.1 404 Not Found");
37
  }
38
 
39
+ ob_end_flush();
test/mock-tinypng-webservice/reset.php CHANGED
@@ -1,7 +1,4 @@
1
  <?php
2
 
3
- define('SESSION_FILE', '/tmp/session.dat');
4
-
5
- if (file_exists(SESSION_FILE)) {
6
- unlink(SESSION_FILE);
7
- }
1
  <?php
2
 
3
+ require('common.php');
4
+ $session = null;
 
 
 
test/mock-tinypng-webservice/shrink.php CHANGED
@@ -1,13 +1,7 @@
1
  <?php
2
  ob_start();
3
 
4
- define('SESSION_FILE', '/tmp/session.dat');
5
-
6
- if (file_exists(SESSION_FILE)) {
7
- $session = unserialize(file_get_contents(SESSION_FILE));
8
- } else {
9
- $session = array('Compression-Count' => 0);
10
- }
11
 
12
  function mock_png_response() {
13
  global $session;
@@ -15,10 +9,11 @@ function mock_png_response() {
15
  $session['Compression-Count'] += 1;
16
  header('HTTP/1.1 201 Created');
17
  header("Location: http://webservice/output/example.png");
 
18
  header("Compression-Count: {$session['Compression-Count']}");
19
  $response = array(
20
  "input" => array("size" => 161885, "type" => "image/png"),
21
- "output" => array("size" => 151021, "type" => "image.png", "ratio" => 0.933)
22
  );
23
  return json_encode($response);
24
  }
@@ -29,6 +24,7 @@ function mock_jpg_response() {
29
  $session['Compression-Count'] += 1;
30
  header('HTTP/1.1 201 Created');
31
  header("Location: http://webservice/output/example.jpg");
 
32
  header("Compression-Count: {$session['Compression-Count']}");
33
 
34
  $response = array(
@@ -44,6 +40,7 @@ function mock_large_response() {
44
  $session['Compression-Count'] += 1;
45
  header('HTTP/1.1 201 Created');
46
  header("Location: http://webservice/output/large.png");
 
47
  header("Compression-Count: {$session['Compression-Count']}");
48
 
49
  $response = array(
@@ -53,19 +50,6 @@ function mock_large_response() {
53
  return json_encode($response);
54
  }
55
 
56
- function mock_invalid_response() {
57
- global $session;
58
-
59
- header('HTTP/1.1 401 Unauthorized');
60
- header("Content-Type: application/json; charset=utf-8");
61
-
62
- $response = array(
63
- "error" => "Unauthorized",
64
- "message" => "Credentials are invalid"
65
- );
66
- return json_encode($response);
67
- }
68
-
69
  function mock_empty_response() {
70
  global $session;
71
 
@@ -94,13 +78,18 @@ function mock_limit_reached_response() {
94
  return json_encode($response);
95
  }
96
 
97
- $request_headers = apache_request_headers();
98
- $basic_auth = base64_decode(str_replace('Basic ', '', $request_headers['Authorization']));
99
- $api_key_elements = explode(':', $basic_auth);
100
- $api_key = $api_key_elements[1];
101
 
102
- header("Content-Type: application/json; charset=utf-8");
 
 
 
 
 
 
103
 
 
104
  if ($api_key == 'PNG123') {
105
  if (intval($_SERVER['CONTENT_LENGTH']) == 0) {
106
  echo mock_empty_response();
@@ -113,12 +102,16 @@ if ($api_key == 'PNG123') {
113
  } else {
114
  echo mock_jpg_response();
115
  }
 
 
 
 
 
 
116
  } else if ($api_key == 'LIMIT123') {
117
  echo mock_limit_reached_response();
118
  } else {
119
  echo mock_invalid_response();
120
  }
121
 
122
- file_put_contents(SESSION_FILE, serialize($session));
123
-
124
- ob_end_flush();
1
  <?php
2
  ob_start();
3
 
4
+ require_once('common.php');
 
 
 
 
 
 
5
 
6
  function mock_png_response() {
7
  global $session;
9
  $session['Compression-Count'] += 1;
10
  header('HTTP/1.1 201 Created');
11
  header("Location: http://webservice/output/example.png");
12
+ header("Content-Type: application/json; charset=utf-8");
13
  header("Compression-Count: {$session['Compression-Count']}");
14
  $response = array(
15
  "input" => array("size" => 161885, "type" => "image/png"),
16
+ "output" => array("size" => 151021, "type" => "image/png", "ratio" => 0.933)
17
  );
18
  return json_encode($response);
19
  }
24
  $session['Compression-Count'] += 1;
25
  header('HTTP/1.1 201 Created');
26
  header("Location: http://webservice/output/example.jpg");
27
+ header("Content-Type: application/json; charset=utf-8");
28
  header("Compression-Count: {$session['Compression-Count']}");
29
 
30
  $response = array(
40
  $session['Compression-Count'] += 1;
41
  header('HTTP/1.1 201 Created');
42
  header("Location: http://webservice/output/large.png");
43
+ header("Content-Type: application/json; charset=utf-8");
44
  header("Compression-Count: {$session['Compression-Count']}");
45
 
46
  $response = array(
50
  return json_encode($response);
51
  }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  function mock_empty_response() {
54
  global $session;
55
 
78
  return json_encode($response);
79
  }
80
 
81
+ function mock_invalid_json_response() {
82
+ global $session;
 
 
83
 
84
+ $session['Compression-Count'] += 1;
85
+ header('HTTP/1.1 201 Created');
86
+ header("Location: http://webservice/output/example.png");
87
+ header("Content-Type: application/json; charset=utf-8");
88
+ header("Compression-Count: {$session['Compression-Count']}");
89
+ return '{invalid: json}';
90
+ }
91
 
92
+ $api_key = get_api_key();
93
  if ($api_key == 'PNG123') {
94
  if (intval($_SERVER['CONTENT_LENGTH']) == 0) {
95
  echo mock_empty_response();
102
  } else {
103
  echo mock_jpg_response();
104
  }
105
+ } else if ($api_key == 'JSON1234') {
106
+ if (intval($_SERVER['CONTENT_LENGTH']) == 0) {
107
+ echo mock_empty_response();
108
+ } else {
109
+ echo mock_invalid_json_response();
110
+ }
111
  } else if ($api_key == 'LIMIT123') {
112
  echo mock_limit_reached_response();
113
  } else {
114
  echo mock_invalid_response();
115
  }
116
 
117
+ ob_end_flush();
 
 
test/unit/TinyMetadataTest.php ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . "/TinyTestCase.php");
4
+
5
+ class Tiny_Metadata_Test extends TinyTestCase {
6
+ public function setUp() {
7
+ parent::setUp();
8
+
9
+ $this->wp->addOption("tinypng_api_key", "test123");
10
+ $this->wp->addOption("tinypng_sizes[0]", "on");
11
+
12
+ $meta = array(Tiny_Metadata::META_KEY => array(
13
+ Tiny_Metadata::ORIGINAL => array(
14
+ "input" => array("size" => 146480),
15
+ "output" => array("size" => 137856)),
16
+ "thumbnail" => array(
17
+ "input" => array("size" => 46480),
18
+ "output" => array("size" => 37856)),
19
+ "medium" => array(
20
+ "input" => array("size" => 66480),
21
+ "output" => array("size" => 57856))
22
+ ));
23
+ $this->wp->setMetadata(1, $meta);
24
+ $this->wp->createImagesFromMeta($this->json("wp_meta_default_sizes"), $meta, 137856);
25
+ $this->subject = new Tiny_Metadata(1, $this->json("wp_meta_default_sizes"));
26
+ }
27
+
28
+ public function testUpdateWpMetadataShouldNotUpdateWithNoResizedOriginal() {
29
+ $tiny_meta = new Tiny_Metadata(150, $this->json("wp_meta_sizes_with_same_files"));
30
+ $wp_metadata = array(
31
+ 'width' => 2000,
32
+ 'height' => 1000
33
+ );
34
+ $this->assertEquals(array('width' => 2000, 'height' => 1000), $tiny_meta->update_wp_metadata($wp_metadata));
35
+ }
36
+
37
+ public function testUpdateWpMetadataShouldUpdateWithResizedOriginal() {
38
+ $tiny_meta = new Tiny_Metadata(150, $this->json("wp_meta_sizes_with_same_files"));
39
+ $wp_metadata = array(
40
+ 'width' => 2000,
41
+ 'height' => 1000
42
+ );
43
+ $tiny_meta->add_request();
44
+ $tiny_meta->add_response(array('output' => array('width' => 200, 'height' => 100)));
45
+ $this->assertEquals(array('width' => 200, 'height' => 100), $tiny_meta->update_wp_metadata($wp_metadata));
46
+ }
47
+
48
+ public function testAddRequestShouldIncreaseProccessingCount() {
49
+ $processing_count = $this->subject->get_in_progress_count();
50
+ $this->subject->add_request("large");
51
+ $this->assertEquals($processing_count + 1, $this->subject->get_in_progress_count());
52
+ }
53
+
54
+ public function testAddRequestShouldIncreaseProccessingCountEvenIfAlreadyCompressed() {
55
+ $processing_count = $this->subject->get_in_progress_count();
56
+ $this->subject->add_request("thumbnail");
57
+ $this->assertEquals($processing_count + 1, $this->subject->get_in_progress_count());
58
+ }
59
+
60
+ public function testAddRequestShouldNotIncreaseSuccessCount() {
61
+ $success_count = $this->subject->get_success_count();
62
+ $this->subject->add_request("large");
63
+ $this->assertEquals($success_count, $this->subject->get_success_count());
64
+ }
65
+
66
+ public function testAddResponseShouldIncreaseSuccessCountForCompression() {
67
+ $success_count = $this->subject->get_success_count();
68
+ $this->subject->add_request("large");
69
+ $this->subject->add_response(array("output" => array("size" => 137857)), "large");
70
+ $this->wp->createImage(137857, "2015/09", "tinypng_gravatar-600x600.png");
71
+ $this->assertEquals($success_count + 1, $this->subject->get_success_count());
72
+ }
73
+
74
+ public function testAddResponseShouldNotIncreaseSuccessCountIfPhysicalFileIsMissing() {
75
+ $success_count = $this->subject->get_success_count();
76
+ $this->subject->add_request("large");
77
+ $this->subject->add_response(array("output" => array("size" => 137857)), "large");
78
+ $this->assertEquals($success_count, $this->subject->get_success_count());
79
+ }
80
+
81
+ public function testAddResponseShouldIncreaseCompressedCount() {
82
+ $compressed_count = count($this->subject->get_compressed_sizes());
83
+ $this->subject->add_request("large");
84
+ $this->subject->add_response(array("output" => array("size" => 137857)), "large");
85
+ $this->wp->createImage(137857, "2015/09", "tinypng_gravatar-600x600.png");
86
+ $this->assertEquals($compressed_count + 1, count($this->subject->get_compressed_sizes()));
87
+ }
88
+
89
+ public function testAddResponseShouldIncreaseCompressedCountIfPhysicalFileIsMissing() {
90
+ $compressed_count = count($this->subject->get_compressed_sizes());
91
+ $this->subject->add_request("large");
92
+ $this->subject->add_response(array("output" => array("size" => 137857)), "large");
93
+ $this->assertEquals($compressed_count + 1, count($this->subject->get_compressed_sizes()));
94
+ }
95
+
96
+ public function testAddResponseShouldNotIncreaseProcessingCount() {
97
+ $processing_count = $this->subject->get_in_progress_count();
98
+ $this->subject->add_request("large");
99
+ $this->subject->add_response(array("output" => array("size" => 137857)), "large");
100
+ $this->wp->createImage(137857, "2015/09", "tinypng_gravatar-600x600.png");
101
+ $this->assertEquals($processing_count, $this->subject->get_in_progress_count());
102
+ }
103
+
104
+ public function testAddExceptionShouldNotIncreaseSuccessCount() {
105
+ $success_count = $this->subject->get_success_count();
106
+ $this->subject->add_request("large");
107
+ $this->subject->add_exception(new Tiny_Exception('Could not download output', 'OutputError'), "large");
108
+ $this->assertEquals($success_count, $this->subject->get_success_count());
109
+ }
110
+
111
+ public function testAddExceptionShouldNotIncreaseProcessingCount() {
112
+ $processing_count = $this->subject->get_in_progress_count();
113
+ $this->subject->add_request("large");
114
+ $this->subject->add_exception(new Tiny_Exception('Could not download output', 'OutputError'), "large");
115
+ $this->assertEquals($processing_count, $this->subject->get_in_progress_count());
116
+ }
117
+
118
+ public function testIsCompressedShouldReturnTrueForOriginal() {
119
+ $this->assertTrue($this->subject->is_compressed(Tiny_Metadata::ORIGINAL));
120
+ }
121
+
122
+ public function testIsCompressedShouldReturnTrueForCompressedSize() {
123
+ $this->assertTrue($this->subject->is_compressed("thumbnail"));
124
+ }
125
+
126
+ public function testIsCompressedShouldReturnFalseForUncompressedSize() {
127
+ $this->assertFalse($this->subject->is_compressed("large"));
128
+ }
129
+
130
+ public function testIsCompressedShouldReturnFalseWhenFilesizeOnFilesystemDoesNotMatchMeta() {
131
+ $meta = array(Tiny_Metadata::META_KEY => array(
132
+ "thumbnail" => array(
133
+ "input" => array("size" => 46480),
134
+ "output" => array("size" => 37856))
135
+ ));
136
+ $this->wp->setMetadata(2, $meta);
137
+ $this->wp->createImage(37857, "2015/09", "tinypng_gravatar-150x150.png");
138
+ $tiny_meta = new Tiny_Metadata(2, $this->json("wp_meta_default_sizes"));
139
+ $this->assertFalse($tiny_meta->is_compressed("thumbnail"));
140
+ }
141
+
142
+ public function testIsCompressedShouldReturnFalseWhenFileDoesNotExist() {
143
+ $meta = array(Tiny_Metadata::META_KEY => array(
144
+ "no_file" => array(
145
+ "input" => array("size" => 46480),
146
+ "output" => array("size" => 37856))
147
+ ));
148
+ $this->wp->setMetadata(3, $meta);
149
+ $tiny_meta = new Tiny_Metadata(3, $this->json("wp_meta_default_sizes"));
150
+ $this->assertFalse($tiny_meta->is_compressed("no_file"));
151
+ }
152
+
153
+ public function testIsCompressedShouldReturnFalseWhenNoMetadata() {
154
+ $this->wp->createImage(37856, "2015/09", "tinypng_gravatar-150x150.png");
155
+ $tiny_meta = new Tiny_Metadata(4, $this->json("wp_meta_default_sizes"));
156
+ $this->assertFalse($tiny_meta->is_compressed("thumbnail"));
157
+ }
158
+
159
+ public function testIsCompressingShouldReturnTrue() {
160
+ $meta = array(Tiny_Metadata::META_KEY => array(
161
+ "thumbnail" => array(
162
+ "start" => 1447925134,
163
+ "input" => array("size" => 46480))
164
+ ));
165
+ $this->wp->setMetadata(5, $meta);
166
+ $this->wp->createImage(46480, "2015/09", "tinypng_gravatar-150x150.png");
167
+ $tiny_meta = new Tiny_Metadata(5, $this->json("wp_meta_default_sizes"));
168
+ $this->assertTrue($tiny_meta->is_compressing("thumbnail"));
169
+ }
170
+
171
+ public function testIsCompressingShouldReturnFalse() {
172
+ $this->assertFalse($this->subject->is_compressing("thumbnail"));
173
+ }
174
+
175
+ public function testIsResizedShouldReturnTrueForResizedImage() {
176
+ $meta = array(Tiny_Metadata::META_KEY => array(
177
+ Tiny_Metadata::ORIGINAL => array(
178
+ "output" => array("size" => 46480, "resized" => true))
179
+ ));
180
+ $this->wp->setMetadata(7, $meta);
181
+ $tiny_meta = new Tiny_Metadata(7, $this->json("wp_meta_default_sizes"));
182
+ $this->assertTrue($tiny_meta->is_resized());
183
+ }
184
+
185
+ public function testIsResizedShouldReturnFalseForNotResizedSize() {
186
+ $this->assertFalse($this->subject->is_resized("thumbnail"));
187
+ }
188
+
189
+ public function testGetSizes() {
190
+ $this->assertEquals(
191
+ array(Tiny_Metadata::ORIGINAL, "thumbnail", "medium", "large"),
192
+ $this->subject->get_sizes());
193
+ }
194
+
195
+ public function testGetSizesWithDuplicates() {
196
+ $tiny_meta = new Tiny_Metadata(150, $this->json("wp_meta_sizes_with_same_files"));
197
+ $this->assertEquals(
198
+ array(Tiny_Metadata::ORIGINAL, "custom-size"),
199
+ $tiny_meta->get_sizes());
200
+ }
201
+
202
+ public function testGetSuccessSizes() {
203
+ $this->assertEquals(array(0, "thumbnail", "medium"), $this->subject->get_success_sizes());
204
+ }
205
+
206
+ public function testGetSuccessSizesShouldNotIncludeSizeIfNotOnFileSystem() {
207
+ $meta = array(Tiny_Metadata::META_KEY => array(
208
+ "additional_size" => array(
209
+ "start" => 1447925134,
210
+ "end" => 1447925138,
211
+ "input" => array("size" => 46480),
212
+ "output" => array("size" => 37856))
213
+ ));
214
+ $this->wp->setMetadata(6, $meta);
215
+ $tiny_meta = new Tiny_Metadata(6, $this->json("wp_meta_default_sizes"));
216
+ $this->assertEquals(array(), $tiny_meta->get_success_sizes());
217
+ }
218
+
219
+ public function testGetCompressedSizes() {
220
+ $this->assertEquals(array(0, "thumbnail", "medium"), $this->subject->get_compressed_sizes());
221
+ }
222
+
223
+ public function testGetCompressedSizesShouldIncludeSizeEvenIfNotOnFileSystem() {
224
+ $meta = array(Tiny_Metadata::META_KEY => array(
225
+ "additional_size" => array(
226
+ "start" => 1447925134,
227
+ "end" => 1447925138,
228
+ "input" => array("size" => 46480),
229
+ "output" => array("size" => 37856))
230
+ ));
231
+ $this->wp->setMetadata(6, $meta);
232
+ $tiny_meta = new Tiny_Metadata(6, $this->json("wp_meta_default_sizes"));
233
+ $this->assertEquals(array("additional_size"), $tiny_meta->get_compressed_sizes());
234
+ }
235
+
236
+ public function testGetUncompressedSizes() {
237
+ $this->wp->createImage(137857, "2015/09", "tinypng_gravatar-600x600.png");
238
+ $tinify_sizes = array(Tiny_Metadata::ORIGINAL, "thumbnail", "medium", "large");
239
+ $this->assertEquals(
240
+ array_values(array("large")),
241
+ array_values($this->subject->get_uncompressed_sizes($tinify_sizes)));
242
+ }
243
+
244
+ public function testGetUncompressedSizesShouldReturnOnlyUniqueSizes() {
245
+ $this->wp->addOption("tinypng_sizes[custom-size]", "on");
246
+ $this->wp->addOption("tinypng_sizes[custom-size-2]", "on");
247
+ $this->wp->addImageSize('custom-size', array('width' => 150, 'height' => 150));
248
+ $this->wp->addImageSize('custom-size-2', array('width' => 150, 'height' => 150));
249
+ $this->wp->createImages(array("150x150" => 37856), 146480, "2015/09", "panda");
250
+
251
+ $tiny_meta = new Tiny_Metadata(155, $this->json("wp_meta_sizes_with_same_files"));
252
+
253
+ $tinify_sizes = array(Tiny_Metadata::ORIGINAL, "custom-size", "custom-size-2");
254
+ $uncompressed_sizes = array(Tiny_Metadata::ORIGINAL, "custom-size");
255
+ $this->assertEquals($uncompressed_sizes, $tiny_meta->get_uncompressed_sizes($tinify_sizes));
256
+ }
257
+
258
+ public function testGetInProgressSizesShouldReturnEmptyArray() {
259
+ $this->assertEquals(array(), $this->subject->get_in_progress_sizes());
260
+ }
261
+
262
+ public function testGetInProgressSizesShouldReturnSizeBeingCompressed() {
263
+ $meta = array(Tiny_Metadata::META_KEY => array(
264
+ "thumbnail" => array(
265
+ "start" => 1447925134,
266
+ "input" => array("size" => 46480))
267
+ ));
268
+ $this->wp->setMetadata(5, $meta);
269
+ $tiny_meta = new Tiny_Metadata(5, $this->json("wp_meta_default_sizes"));
270
+ $this->assertEquals(array("thumbnail"), $tiny_meta->get_in_progress_sizes());
271
+ }
272
+
273
+ public function testGetLatestErrorShouldReturnMessage() {
274
+ $processing_count = $this->subject->get_in_progress_count();
275
+ $this->subject->add_request("large");
276
+ $this->subject->add_exception(new Tiny_Exception('Could not download output', 'OutputError'), "large");
277
+ $this->assertEquals("Could not download output", $this->subject->get_latest_error());
278
+ }
279
+ }
test/unit/TinyPluginTest.php CHANGED
@@ -34,19 +34,32 @@ class Tiny_Plugin_Test extends TinyTestCase {
34
  $input = filesize($file);
35
  switch ($key) {
36
  case "thumbnail":
37
- $output = 81; break;
 
 
 
38
  case "medium":
39
- $output = 768; break;
 
 
 
40
  case "large":
41
- $output = 6789; break;
 
 
 
42
  case "post-thumbnail":
43
- $output = 1000; break;
 
 
 
44
  default:
45
  $output = 10000;
 
 
46
  }
47
  $this->vfs->getChild(vfsStream::path($file))->truncate($output);
48
- return array('input' => array('size' => $input), 'output' => array('size' => $output));
49
-
50
  }
51
 
52
  public function testInitShouldAddFilters() {
@@ -115,14 +128,14 @@ class Tiny_Plugin_Test extends TinyTestCase {
115
 
116
  $metadata = $this->wp->getMetadata(1, 'tiny_compress_images', true);
117
  foreach ($metadata as $key => $values) {
118
- $this->assertEquals(time(), $values['end'], 2);
119
  unset($metadata[$key]['end']);
120
  unset($metadata[$key]['start']);
121
  }
122
  $this->assertEquals(array(
123
- 0 => array('input' => array('size' => 12345), 'output' => array('size' => 10000)),
124
- 'large' => array('input' => array('size' => 10000), 'output' => array('size' => 6789)),
125
- 'post-thumbnail' => array('input' => array('size' => 1234), 'output' => array('size' => 1000)),
126
  ), $metadata);
127
  }
128
 
@@ -186,4 +199,4 @@ class Tiny_Plugin_Test extends TinyTestCase {
186
  $this->subject->compress_attachment($testmeta, 1);
187
  $this->assertEquals(2, count($this->wp->getCalls('update_post_meta')));
188
  }
189
- }
34
  $input = filesize($file);
35
  switch ($key) {
36
  case "thumbnail":
37
+ $output = 81;
38
+ $width = '150';
39
+ $height = '150';
40
+ break;
41
  case "medium":
42
+ $output = 768;
43
+ $width = '300';
44
+ $height = '300';
45
+ break;
46
  case "large":
47
+ $output = 6789;
48
+ $width = '1024';
49
+ $height = '1024';
50
+ break;
51
  case "post-thumbnail":
52
+ $output = 1000;
53
+ $width = '800';
54
+ $height = '500';
55
+ break;
56
  default:
57
  $output = 10000;
58
+ $width = '4000';
59
+ $height = '3000';
60
  }
61
  $this->vfs->getChild(vfsStream::path($file))->truncate($output);
62
+ return array('input' => array('size' => $input), 'output' => array('size' => $output, 'width' => $width, 'height' => $height));
 
63
  }
64
 
65
  public function testInitShouldAddFilters() {
128
 
129
  $metadata = $this->wp->getMetadata(1, 'tiny_compress_images', true);
130
  foreach ($metadata as $key => $values) {
131
+ $this->assertBetween(-1, +1, $values['end'] - time());
132
  unset($metadata[$key]['end']);
133
  unset($metadata[$key]['start']);
134
  }
135
  $this->assertEquals(array(
136
+ 0 => array('input' => array('size' => 12345), 'output' => array('size' => 10000, 'width' => 4000, 'height' => 3000)),
137
+ 'large' => array('input' => array('size' => 10000), 'output' => array('size' => 6789, 'width' => 1024, 'height' => 1024)),
138
+ 'post-thumbnail' => array('input' => array('size' => 1234), 'output' => array('size' => 1000, 'width' => 800, 'height' => 500)),
139
  ), $metadata);
140
  }
141
 
199
  $this->subject->compress_attachment($testmeta, 1);
200
  $this->assertEquals(2, count($this->wp->getCalls('update_post_meta')));
201
  }
202
+ }
test/unit/TinySettingsTest.php CHANGED
@@ -14,7 +14,9 @@ class Tiny_Settings_Test extends TinyTestCase {
14
  $this->assertEquals(array(
15
  array('media', 'tinypng_api_key'),
16
  array('media', 'tinypng_sizes'),
17
- array('media', 'tinypng_status')
 
 
18
  ), $this->wp->getCalls('register_setting'));
19
  }
20
 
@@ -28,7 +30,9 @@ class Tiny_Settings_Test extends TinyTestCase {
28
  $this->assertEquals(array(
29
  array('tinypng_api_key', 'TinyPNG API key', array($this->subject, 'render_api_key'), 'media', 'tinypng_settings', array('label_for' => 'tinypng_api_key')),
30
  array('tinypng_sizes', 'File compression', array($this->subject, 'render_sizes'), 'media', 'tinypng_settings'),
31
- array('tinypng_status', 'Connection status', array($this->subject, 'render_pending_status'), 'media', 'tinypng_settings')
 
 
32
  ), $this->wp->getCalls('add_settings_field'));
33
  }
34
 
@@ -99,4 +103,49 @@ class Tiny_Settings_Test extends TinyTestCase {
99
  array('width' => 0, 'height' => 888, 'tinify' => true),
100
  $sizes["additional_size_no_width"]);
101
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
14
  $this->assertEquals(array(
15
  array('media', 'tinypng_api_key'),
16
  array('media', 'tinypng_sizes'),
17
+ array('media', 'tinypng_resize_original'),
18
+ array('media', 'tinypng_status'),
19
+ array('media', 'tinypng_savings')
20
  ), $this->wp->getCalls('register_setting'));
21
  }
22
 
30
  $this->assertEquals(array(
31
  array('tinypng_api_key', 'TinyPNG API key', array($this->subject, 'render_api_key'), 'media', 'tinypng_settings', array('label_for' => 'tinypng_api_key')),
32
  array('tinypng_sizes', 'File compression', array($this->subject, 'render_sizes'), 'media', 'tinypng_settings'),
33
+ array('tinypng_resize_original', 'Resize original', array($this->subject, 'render_resize'), 'media', 'tinypng_settings'),
34
+ array('tinypng_status', 'Connection status', array($this->subject, 'render_pending_status'), 'media', 'tinypng_settings'),
35
+ array('tinypng_savings', 'Savings', array($this->subject, 'render_pending_savings'), 'media', 'tinypng_settings')
36
  ), $this->wp->getCalls('add_settings_field'));
37
  }
38
 
103
  array('width' => 0, 'height' => 888, 'tinify' => true),
104
  $sizes["additional_size_no_width"]);
105
  }
106
+
107
+ public function testShouldReturnResizeEnabled() {
108
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on'));
109
+ $this->assertEquals(true, $this->subject->get_resize_enabled());
110
+ }
111
+
112
+ public function testShouldReturnResizeNotEnabledWithoutConfiguration() {
113
+ $this->wp->addOption("tinypng_resize_original", array());
114
+ $this->assertEquals(false, $this->subject->get_resize_enabled());
115
+ }
116
+
117
+ public function testShouldReturnResizeOptionsWithWidthAndHeight() {
118
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '800', 'height' => '600'));
119
+ $this->assertEquals(array('method' => 'fit', 'width' => 800, 'height' => 600), $this->subject->get_resize_options());
120
+ }
121
+
122
+ public function testShouldReturnResizeOptionsWithoutWidth() {
123
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '', 'height' => '600'));
124
+ $this->assertEquals(array('method' => 'scale', 'height' => 600), $this->subject->get_resize_options());
125
+ }
126
+
127
+ public function testShouldReturnResizeOptionsWithoutHeight() {
128
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '800', 'height' => '',));
129
+ $this->assertEquals(array('method' => 'scale', 'width' => 800), $this->subject->get_resize_options());
130
+ }
131
+
132
+ public function testShouldReturnResizeOptionsWithInvaledWidth() {
133
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '-1', 'height' => '600'));
134
+ $this->assertEquals(array('method' => 'scale', 'height' => 600), $this->subject->get_resize_options());
135
+ }
136
+
137
+ public function testShouldReturnResizeOptionsWithInvaledHeight() {
138
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '800', 'height' => '-1'));
139
+ $this->assertEquals(array('method' => 'scale', 'width' => 800), $this->subject->get_resize_options());
140
+ }
141
+
142
+ public function testShouldNotReturnResizeOptionsWithoutWithAndHeight() {
143
+ $this->wp->addOption("tinypng_resize_original", array('enabled' => 'on', 'width' => '', 'height' => ''));
144
+ $this->assertEquals(false, $this->subject->get_resize_options());
145
+ }
146
+
147
+ public function testShouldNotReturnResizeOptionsWhenNotEnabled() {
148
+ $this->wp->addOption("tinypng_resize_original", array('width' => '800', 'height' => '600'));
149
+ $this->assertEquals(false, $this->subject->get_resize_options());
150
+ }
151
  }
test/unit/TinyTestCase.php CHANGED
@@ -27,4 +27,13 @@ abstract class TinyTestCase extends PHPUnit_Framework_TestCase {
27
 
28
  protected function tearDown() {
29
  }
 
 
 
 
 
 
 
 
 
30
  }
27
 
28
  protected function tearDown() {
29
  }
30
+
31
+ protected function assertBetween($lower_bound, $upper_bound, $actual, $message='') {
32
+ $this->assertGreaterThanOrEqual($lower_bound, $actual, $message);
33
+ $this->assertLessThanOrEqual($upper_bound, $actual, $message);
34
+ }
35
+
36
+ protected function json($file_name) {
37
+ return json_decode(file_get_contents(dirname(__FILE__) . "/../fixtures/json/" . $file_name . ".json"), true);
38
+ }
39
  }
tiny-compress-images.php CHANGED
@@ -2,27 +2,27 @@
2
  /**
3
  * Plugin Name: Compress JPEG & PNG images
4
  * Description: Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG.
5
- * Version: 1.3.1
6
  * Author: TinyPNG
7
  * Author URI: https://tinypng.com
 
8
  * License: GPLv2 or later
9
  */
10
 
11
-
12
- require (dirname(__FILE__) . '/src/config/tiny-config.php');
13
- require (dirname(__FILE__) . '/src/class-tiny-php.php');
14
- require (dirname(__FILE__) . '/src/class-tiny-wp-base.php');
15
- require (dirname(__FILE__) . '/src/class-tiny-exception.php');
16
- require (dirname(__FILE__) . '/src/class-tiny-compress.php');
17
- require (dirname(__FILE__) . '/src/class-tiny-compress-curl.php');
18
- require (dirname(__FILE__) . '/src/class-tiny-compress-fopen.php');
19
- require (dirname(__FILE__) . '/src/class-tiny-metadata.php');
20
- require (dirname(__FILE__) . '/src/class-tiny-settings.php');
21
- require (dirname(__FILE__) . '/src/class-tiny-plugin.php');
22
- require (dirname(__FILE__) . '/src/class-tiny-notices.php');
23
 
24
  $tiny_plugin = new Tiny_Plugin();
25
 
26
- if (!defined('TINY_DEBUG')) {
27
- define('TINY_DEBUG', null);
28
- }
2
  /**
3
  * Plugin Name: Compress JPEG & PNG images
4
  * Description: Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG.
5
+ * Version: 1.6.0
6
  * Author: TinyPNG
7
  * Author URI: https://tinypng.com
8
+ * Text Domain: tiny-compress-images
9
  * License: GPLv2 or later
10
  */
11
 
12
+ require dirname(__FILE__) . '/src/config/tiny-config.php';
13
+ require dirname(__FILE__) . '/src/class-tiny-php.php';
14
+ require dirname(__FILE__) . '/src/class-tiny-wp-base.php';
15
+ require dirname(__FILE__) . '/src/class-tiny-exception.php';
16
+ require dirname(__FILE__) . '/src/class-tiny-compress.php';
17
+ require dirname(__FILE__) . '/src/class-tiny-compress-curl.php';
18
+ require dirname(__FILE__) . '/src/class-tiny-compress-fopen.php';
19
+ require dirname(__FILE__) . '/src/class-tiny-metadata.php';
20
+ require dirname(__FILE__) . '/src/class-tiny-settings.php';
21
+ require dirname(__FILE__) . '/src/class-tiny-plugin.php';
22
+ require dirname(__FILE__) . '/src/class-tiny-notices.php';
 
23
 
24
  $tiny_plugin = new Tiny_Plugin();
25
 
26
+ if ( !defined( 'TINY_DEBUG' ) ) {
27
+ define( 'TINY_DEBUG', null );
28
+ }
trunk/tmp/.gitkeep DELETED
File without changes