Compress JPEG & PNG images - Version 3.0.0

Version Description

  • Compress new images in the background to speed up your workflow.
  • Turbo-charged Bulk Optimization page with simultaneous image compression.
  • Improved memory usage for installations with extreme media libraries.
  • Detection of incompatible plugins.
  • Fallback to fopen whenever the curl_exec function is disabled.
  • Additional notices for WP Offload S3 users.
  • Several minor fixes and tweaks.
Download this release

Release Info

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

Code changes from version 2.2.6 to 3.0.0

.travis.yml CHANGED
@@ -1,15 +1,22 @@
1
  language: php
2
  php:
3
- - 5.3
4
  - 5.4
5
  - 5.5
6
  - 5.6
7
  - 7.0
8
  - 7.1
 
9
  matrix:
10
  include:
 
 
 
11
  - dist: trusty
12
  php: hhvm
 
 
 
 
13
  - dist: trusty
14
  php: 7.0
15
  env: WORDPRESS_VERSION=48 INTEGRATION_TESTS=true
@@ -70,24 +77,12 @@ matrix:
70
  php: 7.0
71
  env: WORDPRESS_VERSION=34 INTEGRATION_TESTS=true
72
  script: bin/integration-tests
73
- - dist: trusty
74
- php: 7.0
75
- env: WORDPRESS_VERSION=33 INTEGRATION_TESTS=true
76
- script: bin/integration-tests
77
- - dist: trusty
78
- php: 7.0
79
- env: WORDPRESS_VERSION=32 INTEGRATION_TESTS=true
80
- script: bin/integration-tests
81
- - dist: trusty
82
- php: 7.0
83
- env: WORDPRESS_VERSION=31 INTEGRATION_TESTS=true
84
- script: bin/integration-tests
85
  install:
86
  - composer install
87
  - if [[ "$INTEGRATION_TESTS" == "true" ]]; then sudo service mysql stop; sudo bin/install-docker; fi
88
  script:
89
  - bin/unit-tests
90
- - bin/check-style --warning-severity=0 src
91
  notifications:
92
  email: false
93
  slack:
1
  language: php
2
  php:
 
3
  - 5.4
4
  - 5.5
5
  - 5.6
6
  - 7.0
7
  - 7.1
8
+ - 7.2
9
  matrix:
10
  include:
11
+ - dist: precise
12
+ php: 5.3
13
+ script: bin/unit-tests
14
  - dist: trusty
15
  php: hhvm
16
+ - dist: trusty
17
+ php: 7.0
18
+ env: WORDPRESS_VERSION=49 INTEGRATION_TESTS=true
19
+ script: bin/integration-tests
20
  - dist: trusty
21
  php: 7.0
22
  env: WORDPRESS_VERSION=48 INTEGRATION_TESTS=true
77
  php: 7.0
78
  env: WORDPRESS_VERSION=34 INTEGRATION_TESTS=true
79
  script: bin/integration-tests
 
 
 
 
 
 
 
 
 
 
 
 
80
  install:
81
  - composer install
82
  - if [[ "$INTEGRATION_TESTS" == "true" ]]; then sudo service mysql stop; sudo bin/install-docker; fi
83
  script:
84
  - bin/unit-tests
85
+ - bin/check-style
86
  notifications:
87
  email: false
88
  slack:
bin/install-docker CHANGED
@@ -15,7 +15,7 @@ rm -f $(which docker)
15
  rm -f $(which docker-compose)
16
 
17
  set -e
18
- apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
19
  echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | tee /etc/apt/sources.list.d/docker.list
20
  echo "deb https://apt.dockerproject.org/repo ubuntu-trusty testing" | tee -a /etc/apt/sources.list.d/docker.list
21
  apt-get update
15
  rm -f $(which docker-compose)
16
 
17
  set -e
18
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
19
  echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | tee /etc/apt/sources.list.d/docker.list
20
  echo "deb https://apt.dockerproject.org/repo ubuntu-trusty testing" | tee -a /etc/apt/sources.list.d/docker.list
21
  apt-get update
composer.json CHANGED
@@ -1,5 +1,5 @@
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",
1
  {
2
+ "name": "tinify/tiny-compress-images",
3
  "description": "Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG.",
4
  "license": "GPL-2.0+",
5
  "type": "wordpress-plugin",
composer.lock CHANGED
@@ -8,16 +8,16 @@
8
  "packages": [
9
  {
10
  "name": "composer/installers",
11
- "version": "v1.3.0",
12
  "source": {
13
  "type": "git",
14
  "url": "https://github.com/composer/installers.git",
15
- "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045"
16
  },
17
  "dist": {
18
  "type": "zip",
19
- "url": "https://api.github.com/repos/composer/installers/zipball/79ad876c7498c0bbfe7eed065b8651c93bfd6045",
20
- "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045",
21
  "shasum": ""
22
  },
23
  "require": {
@@ -29,7 +29,7 @@
29
  },
30
  "require-dev": {
31
  "composer/composer": "1.0.*@dev",
32
- "phpunit/phpunit": "4.1.*"
33
  },
34
  "type": "composer-plugin",
35
  "extra": {
@@ -63,6 +63,7 @@
63
  "Hurad",
64
  "ImageCMS",
65
  "Kanboard",
 
66
  "MODX Evo",
67
  "Mautic",
68
  "Maya",
@@ -86,6 +87,7 @@
86
  "croogo",
87
  "dokuwiki",
88
  "drupal",
 
89
  "elgg",
90
  "expressionengine",
91
  "fuelphp",
@@ -98,14 +100,18 @@
98
  "lavalite",
99
  "lithium",
100
  "magento",
 
101
  "mako",
102
  "mediawiki",
103
  "modulework",
 
104
  "moodle",
 
105
  "phpbb",
106
  "piwik",
107
  "ppi",
108
  "puppet",
 
109
  "reindex",
110
  "roundcube",
111
  "shopware",
@@ -118,7 +124,7 @@
118
  "zend",
119
  "zikula"
120
  ],
121
- "time": "2017-04-24T06:37:16+00:00"
122
  }
123
  ],
124
  "packages-dev": [
@@ -269,16 +275,16 @@
269
  },
270
  {
271
  "name": "mikey179/vfsStream",
272
- "version": "v1.6.4",
273
  "source": {
274
  "type": "git",
275
  "url": "https://github.com/mikey179/vfsStream.git",
276
- "reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592"
277
  },
278
  "dist": {
279
  "type": "zip",
280
- "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/0247f57b2245e8ad2e689d7cee754b45fbabd592",
281
- "reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592",
282
  "shasum": ""
283
  },
284
  "require": {
@@ -311,7 +317,7 @@
311
  ],
312
  "description": "Virtual file system to mock the real file system in unit tests.",
313
  "homepage": "http://vfs.bovigo.org/",
314
- "time": "2016-07-18T14:02:57+00:00"
315
  },
316
  {
317
  "name": "mockery/mockery",
@@ -429,33 +435,33 @@
429
  },
430
  {
431
  "name": "phpspec/prophecy",
432
- "version": "v1.7.0",
433
  "source": {
434
  "type": "git",
435
  "url": "https://github.com/phpspec/prophecy.git",
436
- "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
437
  },
438
  "dist": {
439
  "type": "zip",
440
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
441
- "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
442
  "shasum": ""
443
  },
444
  "require": {
445
  "doctrine/instantiator": "^1.0.2",
446
  "php": "^5.3|^7.0",
447
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
448
- "sebastian/comparator": "^1.1|^2.0",
449
  "sebastian/recursion-context": "^1.0|^2.0|^3.0"
450
  },
451
  "require-dev": {
452
  "phpspec/phpspec": "^2.5|^3.2",
453
- "phpunit/phpunit": "^4.8 || ^5.6.5"
454
  },
455
  "type": "library",
456
  "extra": {
457
  "branch-alias": {
458
- "dev-master": "1.6.x-dev"
459
  }
460
  },
461
  "autoload": {
@@ -488,7 +494,7 @@
488
  "spy",
489
  "stub"
490
  ],
491
- "time": "2017-03-02T20:05:34+00:00"
492
  },
493
  {
494
  "name": "phpunit/php-code-coverage",
@@ -554,16 +560,16 @@
554
  },
555
  {
556
  "name": "phpunit/php-file-iterator",
557
- "version": "1.4.2",
558
  "source": {
559
  "type": "git",
560
  "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
561
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
562
  },
563
  "dist": {
564
  "type": "zip",
565
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
566
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
567
  "shasum": ""
568
  },
569
  "require": {
@@ -597,7 +603,7 @@
597
  "filesystem",
598
  "iterator"
599
  ],
600
- "time": "2016-10-03T07:40:28+00:00"
601
  },
602
  {
603
  "name": "phpunit/php-text-template",
@@ -691,16 +697,16 @@
691
  },
692
  {
693
  "name": "phpunit/php-token-stream",
694
- "version": "1.4.11",
695
  "source": {
696
  "type": "git",
697
  "url": "https://github.com/sebastianbergmann/php-token-stream.git",
698
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
699
  },
700
  "dist": {
701
  "type": "zip",
702
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
703
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
704
  "shasum": ""
705
  },
706
  "require": {
@@ -736,20 +742,20 @@
736
  "keywords": [
737
  "tokenizer"
738
  ],
739
- "time": "2017-02-27T10:12:30+00:00"
740
  },
741
  {
742
  "name": "phpunit/phpunit",
743
- "version": "4.8.35",
744
  "source": {
745
  "type": "git",
746
  "url": "https://github.com/sebastianbergmann/phpunit.git",
747
- "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87"
748
  },
749
  "dist": {
750
  "type": "zip",
751
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87",
752
- "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87",
753
  "shasum": ""
754
  },
755
  "require": {
@@ -808,7 +814,7 @@
808
  "testing",
809
  "xunit"
810
  ],
811
- "time": "2017-02-06T05:18:07+00:00"
812
  },
813
  {
814
  "name": "phpunit/phpunit-mock-objects",
@@ -1316,22 +1322,78 @@
1316
  ],
1317
  "time": "2017-05-22T02:43:20+00:00"
1318
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1319
  {
1320
  "name": "symfony/yaml",
1321
- "version": "v2.8.22",
1322
  "source": {
1323
  "type": "git",
1324
  "url": "https://github.com/symfony/yaml.git",
1325
- "reference": "4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5"
1326
  },
1327
  "dist": {
1328
  "type": "zip",
1329
- "url": "https://api.github.com/repos/symfony/yaml/zipball/4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5",
1330
- "reference": "4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5",
1331
  "shasum": ""
1332
  },
1333
  "require": {
1334
- "php": ">=5.3.9"
 
1335
  },
1336
  "type": "library",
1337
  "extra": {
@@ -1363,7 +1425,7 @@
1363
  ],
1364
  "description": "Symfony Yaml Component",
1365
  "homepage": "https://symfony.com",
1366
- "time": "2017-06-01T20:52:29+00:00"
1367
  },
1368
  {
1369
  "name": "tinify/tinify",
@@ -1371,12 +1433,12 @@
1371
  "source": {
1372
  "type": "git",
1373
  "url": "https://github.com/tinify/tinify-php.git",
1374
- "reference": "45e79fee561f6264dfa10f423a121a1a5293089a"
1375
  },
1376
  "dist": {
1377
  "type": "zip",
1378
- "url": "https://api.github.com/repos/tinify/tinify-php/zipball/45e79fee561f6264dfa10f423a121a1a5293089a",
1379
- "reference": "45e79fee561f6264dfa10f423a121a1a5293089a",
1380
  "shasum": ""
1381
  },
1382
  "require": {
@@ -1423,7 +1485,7 @@
1423
  "source": "https://github.com/tinify/tinify-php/tree/create-key",
1424
  "issues": "https://github.com/tinify/tinify-php/issues"
1425
  },
1426
- "time": "2017-02-24 09:07:29"
1427
  },
1428
  {
1429
  "name": "wp-coding-standards/wpcs",
8
  "packages": [
9
  {
10
  "name": "composer/installers",
11
+ "version": "v1.5.0",
12
  "source": {
13
  "type": "git",
14
  "url": "https://github.com/composer/installers.git",
15
+ "reference": "049797d727261bf27f2690430d935067710049c2"
16
  },
17
  "dist": {
18
  "type": "zip",
19
+ "url": "https://api.github.com/repos/composer/installers/zipball/049797d727261bf27f2690430d935067710049c2",
20
+ "reference": "049797d727261bf27f2690430d935067710049c2",
21
  "shasum": ""
22
  },
23
  "require": {
29
  },
30
  "require-dev": {
31
  "composer/composer": "1.0.*@dev",
32
+ "phpunit/phpunit": "^4.8.36"
33
  },
34
  "type": "composer-plugin",
35
  "extra": {
63
  "Hurad",
64
  "ImageCMS",
65
  "Kanboard",
66
+ "Lan Management System",
67
  "MODX Evo",
68
  "Mautic",
69
  "Maya",
87
  "croogo",
88
  "dokuwiki",
89
  "drupal",
90
+ "eZ Platform",
91
  "elgg",
92
  "expressionengine",
93
  "fuelphp",
100
  "lavalite",
101
  "lithium",
102
  "magento",
103
+ "majima",
104
  "mako",
105
  "mediawiki",
106
  "modulework",
107
+ "modx",
108
  "moodle",
109
+ "osclass",
110
  "phpbb",
111
  "piwik",
112
  "ppi",
113
  "puppet",
114
+ "pxcms",
115
  "reindex",
116
  "roundcube",
117
  "shopware",
124
  "zend",
125
  "zikula"
126
  ],
127
+ "time": "2017-12-29T09:13:20+00:00"
128
  }
129
  ],
130
  "packages-dev": [
275
  },
276
  {
277
  "name": "mikey179/vfsStream",
278
+ "version": "v1.6.5",
279
  "source": {
280
  "type": "git",
281
  "url": "https://github.com/mikey179/vfsStream.git",
282
+ "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
283
  },
284
  "dist": {
285
  "type": "zip",
286
+ "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
287
+ "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
288
  "shasum": ""
289
  },
290
  "require": {
317
  ],
318
  "description": "Virtual file system to mock the real file system in unit tests.",
319
  "homepage": "http://vfs.bovigo.org/",
320
+ "time": "2017-08-01T08:02:14+00:00"
321
  },
322
  {
323
  "name": "mockery/mockery",
435
  },
436
  {
437
  "name": "phpspec/prophecy",
438
+ "version": "1.7.6",
439
  "source": {
440
  "type": "git",
441
  "url": "https://github.com/phpspec/prophecy.git",
442
+ "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
443
  },
444
  "dist": {
445
  "type": "zip",
446
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
447
+ "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
448
  "shasum": ""
449
  },
450
  "require": {
451
  "doctrine/instantiator": "^1.0.2",
452
  "php": "^5.3|^7.0",
453
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
454
+ "sebastian/comparator": "^1.1|^2.0|^3.0",
455
  "sebastian/recursion-context": "^1.0|^2.0|^3.0"
456
  },
457
  "require-dev": {
458
  "phpspec/phpspec": "^2.5|^3.2",
459
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
460
  },
461
  "type": "library",
462
  "extra": {
463
  "branch-alias": {
464
+ "dev-master": "1.7.x-dev"
465
  }
466
  },
467
  "autoload": {
494
  "spy",
495
  "stub"
496
  ],
497
+ "time": "2018-04-18T13:57:24+00:00"
498
  },
499
  {
500
  "name": "phpunit/php-code-coverage",
560
  },
561
  {
562
  "name": "phpunit/php-file-iterator",
563
+ "version": "1.4.5",
564
  "source": {
565
  "type": "git",
566
  "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
567
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
568
  },
569
  "dist": {
570
  "type": "zip",
571
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
572
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
573
  "shasum": ""
574
  },
575
  "require": {
603
  "filesystem",
604
  "iterator"
605
  ],
606
+ "time": "2017-11-27T13:52:08+00:00"
607
  },
608
  {
609
  "name": "phpunit/php-text-template",
697
  },
698
  {
699
  "name": "phpunit/php-token-stream",
700
+ "version": "1.4.12",
701
  "source": {
702
  "type": "git",
703
  "url": "https://github.com/sebastianbergmann/php-token-stream.git",
704
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
705
  },
706
  "dist": {
707
  "type": "zip",
708
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
709
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
710
  "shasum": ""
711
  },
712
  "require": {
742
  "keywords": [
743
  "tokenizer"
744
  ],
745
+ "time": "2017-12-04T08:55:13+00:00"
746
  },
747
  {
748
  "name": "phpunit/phpunit",
749
+ "version": "4.8.36",
750
  "source": {
751
  "type": "git",
752
  "url": "https://github.com/sebastianbergmann/phpunit.git",
753
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
754
  },
755
  "dist": {
756
  "type": "zip",
757
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
758
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
759
  "shasum": ""
760
  },
761
  "require": {
814
  "testing",
815
  "xunit"
816
  ],
817
+ "time": "2017-06-21T08:07:12+00:00"
818
  },
819
  {
820
  "name": "phpunit/phpunit-mock-objects",
1322
  ],
1323
  "time": "2017-05-22T02:43:20+00:00"
1324
  },
1325
+ {
1326
+ "name": "symfony/polyfill-ctype",
1327
+ "version": "v1.8.0",
1328
+ "source": {
1329
+ "type": "git",
1330
+ "url": "https://github.com/symfony/polyfill-ctype.git",
1331
+ "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae"
1332
+ },
1333
+ "dist": {
1334
+ "type": "zip",
1335
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
1336
+ "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
1337
+ "shasum": ""
1338
+ },
1339
+ "require": {
1340
+ "php": ">=5.3.3"
1341
+ },
1342
+ "type": "library",
1343
+ "extra": {
1344
+ "branch-alias": {
1345
+ "dev-master": "1.8-dev"
1346
+ }
1347
+ },
1348
+ "autoload": {
1349
+ "psr-4": {
1350
+ "Symfony\\Polyfill\\Ctype\\": ""
1351
+ },
1352
+ "files": [
1353
+ "bootstrap.php"
1354
+ ]
1355
+ },
1356
+ "notification-url": "https://packagist.org/downloads/",
1357
+ "license": [
1358
+ "MIT"
1359
+ ],
1360
+ "authors": [
1361
+ {
1362
+ "name": "Symfony Community",
1363
+ "homepage": "https://symfony.com/contributors"
1364
+ },
1365
+ {
1366
+ "name": "Gert de Pagter",
1367
+ "email": "BackEndTea@gmail.com"
1368
+ }
1369
+ ],
1370
+ "description": "Symfony polyfill for ctype functions",
1371
+ "homepage": "https://symfony.com",
1372
+ "keywords": [
1373
+ "compatibility",
1374
+ "ctype",
1375
+ "polyfill",
1376
+ "portable"
1377
+ ],
1378
+ "time": "2018-04-30T19:57:29+00:00"
1379
+ },
1380
  {
1381
  "name": "symfony/yaml",
1382
+ "version": "v2.8.43",
1383
  "source": {
1384
  "type": "git",
1385
  "url": "https://github.com/symfony/yaml.git",
1386
+ "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff"
1387
  },
1388
  "dist": {
1389
  "type": "zip",
1390
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff",
1391
+ "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff",
1392
  "shasum": ""
1393
  },
1394
  "require": {
1395
+ "php": ">=5.3.9",
1396
+ "symfony/polyfill-ctype": "~1.8"
1397
  },
1398
  "type": "library",
1399
  "extra": {
1425
  ],
1426
  "description": "Symfony Yaml Component",
1427
  "homepage": "https://symfony.com",
1428
+ "time": "2018-05-01T22:52:40+00:00"
1429
  },
1430
  {
1431
  "name": "tinify/tinify",
1433
  "source": {
1434
  "type": "git",
1435
  "url": "https://github.com/tinify/tinify-php.git",
1436
+ "reference": "ce0b3fe4b7490604604294992f41d8ccd91f6cf6"
1437
  },
1438
  "dist": {
1439
  "type": "zip",
1440
+ "url": "https://api.github.com/repos/tinify/tinify-php/zipball/ce0b3fe4b7490604604294992f41d8ccd91f6cf6",
1441
+ "reference": "ce0b3fe4b7490604604294992f41d8ccd91f6cf6",
1442
  "shasum": ""
1443
  },
1444
  "require": {
1485
  "source": "https://github.com/tinify/tinify-php/tree/create-key",
1486
  "issues": "https://github.com/tinify/tinify-php/issues"
1487
  },
1488
+ "time": "2017-07-19 12:34:08"
1489
  },
1490
  {
1491
  "name": "wp-coding-standards/wpcs",
phpcs.xml CHANGED
@@ -21,5 +21,5 @@
21
  <exclude-pattern>src/data</exclude-pattern>
22
  <exclude-pattern>src/js</exclude-pattern>
23
  <exclude-pattern>src/vendor</exclude-pattern>
24
- <exclude-pattern>test/mock-tinypng-webservice</exclude-pattern>
25
  </ruleset>
21
  <exclude-pattern>src/data</exclude-pattern>
22
  <exclude-pattern>src/js</exclude-pattern>
23
  <exclude-pattern>src/vendor</exclude-pattern>
24
+ <exclude-pattern>test/</exclude-pattern>
25
  </ruleset>
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Compress JPEG & PNG images ===
2
  Contributors: TinyPNG
3
  Donate link: https://tinypng.com/
4
- Tags: optimize, compress, shrink, resize, faster, fit, scale, improve, images, tinypng, tinyjpg, jpeg, jpg, png, lossy, jpegmini, crunch, minify, smush, save, bandwidth, website, speed, performance, panda, wordpress app
5
- Requires at least: 3.0.6
6
  Tested up to: 4.9
7
- Stable tag: 2.2.6
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -17,9 +17,11 @@ Make your website faster by optimizing your JPEG and PNG images. This plugin aut
17
  = Features =
18
 
19
  * Automatically optimize new images on upload.
 
20
  * Optimize individual images already in your media library.
21
  * Easy bulk optimization of your existing media library.
22
  * Resize large original images by setting a maximum width and/or height.
 
23
  * Preserve copyright metadata, creation date and GPS location in the original images.
24
  * Supports compression of animated PNG.
25
  * Select which thumbnail sizes of an image may be optimized.
@@ -40,7 +42,7 @@ After you upload an image to your WordPress site, each resized image is uploaded
40
 
41
  = Getting started =
42
 
43
- Install this plugin and follow the instructions to set up your account. With a regular WordPress installation you can optimize **roughly 100 images each month** for free. The exact total depends on the number of thumbnail sizes that are in use in your WordPress installation. You can change which of the generated thumbnail sizes should be optimized in the *Settings > Media* page. Once installed you can also switch to a [paid account](https://tinypng.com/dashboard/developers) to remove the limits and optimize as many images as you like.
44
 
45
  = Optimizing all your images =
46
 
@@ -65,7 +67,7 @@ Want to contribute? Check out the [Tinify Wordpress plugin on GitHub](https://gi
65
  1. Visit *Plugins > Add New*.
66
  2. Search for 'tinypng' and press the 'Install Now' button for the plugin named 'Compress JPEG & PNG images' by 'TinyPNG'.
67
  3. Activate the plugin from your *Plugins* page.
68
- 4. Go to the *Settings > Media* page and register a new account.
69
  5. Or enter the API key you got from https://tinypng.com/developers.
70
  6. Go to *Media > Bulk Optimization* and optimize all your images!
71
 
@@ -74,7 +76,7 @@ Want to contribute? Check out the [Tinify Wordpress plugin on GitHub](https://gi
74
  1. Download the plugin named 'Compress JPEG & PNG images' by 'TinyPNG'.
75
  2. Upload the `tiny-compress-images` directory to your `/wp-content/plugins/` directory, using your favorite method (ftp, sftp, scp, etc...)
76
  3. Activate the plugin from your Plugins page.
77
- 4. Go to the *Settings > Media* page and register a new account.
78
  5. Or enter the API key you got from https://tinypng.com/developers.
79
  6. Go to *Media > Bulk Optimization* and optimize all your images!
80
 
@@ -84,7 +86,7 @@ The API key can also be configured in your *wp-config.php* file. To do this you
84
 
85
  `define( 'TINY_API_KEY', 'YOUR_API_KEY_HERE' );`
86
 
87
- Once set up you will see a message on the *Settings > Media* page. This will work for normal and multisite WordPress installations.
88
 
89
  == Screenshots ==
90
 
@@ -96,16 +98,16 @@ Once set up you will see a message on the *Settings > Media* page. This will wor
96
  == Frequently Asked Questions ==
97
 
98
  = Q: How many images can I optimize for free? =
99
- A: In a default WordPress installation you can optimize around 100 images for free each month. WordPress creates different thumbnails 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 optimization.
100
 
101
  = Q: How can I remove the 500 limit? =
102
- A: Just add your *Payment details* on your [account dashboard](https://tinypng.com/dashboard/developers) to remove the limit. For a small fee the additional compressions above 500 will then be charged to your account at the end of each month.
103
 
104
  = Q: What happens to the optimized images when I uninstall the plugin? =
105
  A: When you remove the plugin all your optimized images will remain optimized.
106
 
107
  = Q: I don't recall uploading 500 photos this month but my limit is already reached. How is this number calculated? =
108
- 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.
109
 
110
  = Q: Is there a file size limit? =
111
  A: No. There are no limitations on the size of the images you want to compress.
@@ -117,23 +119,32 @@ A: Yes, there are no limitations. You can add the same key everywhere.
117
  A: Yes, you can hide your API key from the admin so other admin users will not be able to see it. To do this you should define the API key in your *wp-config.php* file. See the installation instructions for more information.
118
 
119
  = Q: What happens when I reach my monthly limit? =
120
- A: Everything will keep on working, but newly uploaded images will not be optimized. Of course we encourage everyone to [switch](https://tinypng.com/dashboard/developers) to a paid account to cover the hosting and development costs of the service.
121
 
122
  = Q: Can I optimize all existing images in my media library? =
123
  A: Yes! After installing the plugin, go to *Media > Bulk Optimization*, and click on the start button to optimize all unoptimized images in your media library.
124
 
125
  = Q: How do I switch to a paid account? =
126
- A: You can upgrade to a paid account by adding your *Payment details* on your [account dashboard](https://tinypng.com/dashboard/developers). Additional compressions above 500 will then be charged at the end of each month as a one-time fee.
127
 
128
  == Changelog ==
 
 
 
 
 
 
 
 
 
129
  = 2.2.6 =
130
  * Fixed bug in compression of file types other than JPEG and PNG that have a thumbnail generated automatically.
131
 
132
  = 2.2.5 =
133
- * Fixed bug in bulk optimization page that could sometimes cause it to stop.
134
  * Fixed a problem that would prevent dashboard widget from loading.
135
  * Tweaked styling of the dashboard widget for the latest version of WordPress.
136
- * Fixed a warning that sometimes occurred in the media library when certain plugins are used.
137
 
138
  = 2.2.4 =
139
  * Fixed bug with drop-down menu in the Media Library.
@@ -234,3 +245,5 @@ A: You can upgrade to a paid account by adding your *Payment details* on your [a
234
 
235
  = 1.0.0 =
236
  * Initial version.
 
 
1
  === Compress JPEG & PNG images ===
2
  Contributors: TinyPNG
3
  Donate link: https://tinypng.com/
4
+ Tags: optimize, compress, shrink, resize, faster, fit, scale, improve, images, picture, pictures, photo, photos, image, tinypng, tinyjpg, jpeg, jpg, png, lossy, jpegmini, crunch, minify, smush, save, bandwidth, website, speed, performance, panda, george, wordpress app, SEO, lossy, wp compress, sitespeed, shortpixel, kraken, PageRank, cheetaho, s3
5
+ Requires at least: 3.4
6
  Tested up to: 4.9
7
+ Stable tag: 3.0.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
17
  = Features =
18
 
19
  * Automatically optimize new images on upload.
20
+ * Advanced background optimization to speed up your workflow.
21
  * Optimize individual images already in your media library.
22
  * Easy bulk optimization of your existing media library.
23
  * Resize large original images by setting a maximum width and/or height.
24
+ * Display JPEG images more quickly with progressive JPEG encoding.
25
  * Preserve copyright metadata, creation date and GPS location in the original images.
26
  * Supports compression of animated PNG.
27
  * Select which thumbnail sizes of an image may be optimized.
42
 
43
  = Getting started =
44
 
45
+ Install this plugin and follow the instructions to set up your account. With a regular WordPress installation you can optimize **roughly 100 images each month** for free. The exact total depends on the number of thumbnail sizes that are in use in your WordPress installation. You can change which of the generated thumbnail sizes should be optimized in the *Settings > Compress JPEG & PNG images* page. Once installed you can also switch to a [paid account](https://tinypng.com/dashboard/api) to remove the limits and optimize as many images as you like.
46
 
47
  = Optimizing all your images =
48
 
67
  1. Visit *Plugins > Add New*.
68
  2. Search for 'tinypng' and press the 'Install Now' button for the plugin named 'Compress JPEG & PNG images' by 'TinyPNG'.
69
  3. Activate the plugin from your *Plugins* page.
70
+ 4. Go to the *Settings > Compress JPEG & PNG images* page and register a new account.
71
  5. Or enter the API key you got from https://tinypng.com/developers.
72
  6. Go to *Media > Bulk Optimization* and optimize all your images!
73
 
76
  1. Download the plugin named 'Compress JPEG & PNG images' by 'TinyPNG'.
77
  2. Upload the `tiny-compress-images` directory to your `/wp-content/plugins/` directory, using your favorite method (ftp, sftp, scp, etc...)
78
  3. Activate the plugin from your Plugins page.
79
+ 4. Go to the *Settings > Compress JPEG & PNG images* page and register a new account.
80
  5. Or enter the API key you got from https://tinypng.com/developers.
81
  6. Go to *Media > Bulk Optimization* and optimize all your images!
82
 
86
 
87
  `define( 'TINY_API_KEY', 'YOUR_API_KEY_HERE' );`
88
 
89
+ Once set up you will see a message on the *Settings > Compress JPEG & PNG images* page. This will work for normal and multisite WordPress installations.
90
 
91
  == Screenshots ==
92
 
98
  == Frequently Asked Questions ==
99
 
100
  = Q: How many images can I optimize for free? =
101
+ A: In a default WordPress installation you can optimize around 100 images for free each month. WordPress creates different thumbnails of your images which all have to be compressed. Some plugins even add more sizes, so take a look at the *Settings > Compress JPEG & PNG images* page before you start optimization.
102
 
103
  = Q: How can I remove the 500 limit? =
104
+ A: Just add your *Payment details* on your [account dashboard](https://tinypng.com/dashboard/api) to remove the limit. For a small fee the additional compressions above 500 will then be charged to your account at the end of each month.
105
 
106
  = Q: What happens to the optimized images when I uninstall the plugin? =
107
  A: When you remove the plugin all your optimized images will remain optimized.
108
 
109
  = Q: I don't recall uploading 500 photos this month but my limit is already reached. How is this number calculated? =
110
+ A: When you upload an image to your website, WordPress will create different sized versions of it (see *Settings > Compress JPEG & PNG images*). The plugin will compress each of these sizes, so when you have 100 images and 5 different sizes you will do 500 compressions.
111
 
112
  = Q: Is there a file size limit? =
113
  A: No. There are no limitations on the size of the images you want to compress.
119
  A: Yes, you can hide your API key from the admin so other admin users will not be able to see it. To do this you should define the API key in your *wp-config.php* file. See the installation instructions for more information.
120
 
121
  = Q: What happens when I reach my monthly limit? =
122
+ A: Everything will keep on working, but newly uploaded images will not be optimized. Of course we encourage everyone to [switch](https://tinypng.com/dashboard/api) to a paid account to cover the hosting and development costs of the service.
123
 
124
  = Q: Can I optimize all existing images in my media library? =
125
  A: Yes! After installing the plugin, go to *Media > Bulk Optimization*, and click on the start button to optimize all unoptimized images in your media library.
126
 
127
  = Q: How do I switch to a paid account? =
128
+ A: You can upgrade to a paid account by adding your *Payment details* on your [account dashboard](https://tinypng.com/dashboard/api). Additional compressions above 500 will then be charged at the end of each month as a one-time fee.
129
 
130
  == Changelog ==
131
+ = 3.0.0 =
132
+ * Compress new images in the background to speed up your workflow.
133
+ * Turbo-charged Bulk Optimization page with simultaneous image compression.
134
+ * Improved memory usage for installations with extreme media libraries.
135
+ * Detection of incompatible plugins.
136
+ * Fallback to fopen whenever the curl_exec function is disabled.
137
+ * Additional notices for WP Offload S3 users.
138
+ * Several minor fixes and tweaks.
139
+
140
  = 2.2.6 =
141
  * Fixed bug in compression of file types other than JPEG and PNG that have a thumbnail generated automatically.
142
 
143
  = 2.2.5 =
144
+ * Fixed bug in the Bulk Optimization page that sometimes caused it to stop.
145
  * Fixed a problem that would prevent dashboard widget from loading.
146
  * Tweaked styling of the dashboard widget for the latest version of WordPress.
147
+ * Fixed a warning in the media library when certain plugins are used.
148
 
149
  = 2.2.4 =
150
  * Fixed bug with drop-down menu in the Media Library.
245
 
246
  = 1.0.0 =
247
  * Initial version.
248
+
249
+ :)
src/class-tiny-bulk-optimization.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
+ *
6
+ * This program is free software; you can redistribute it and/or modify it
7
+ * under the terms of the GNU General Public License as published by the Free
8
+ * Software Foundation; either version 2 of the License, or (at your option)
9
+ * any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful, but WITHOUT
12
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
+ * more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License along
17
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
18
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+ class Tiny_Bulk_Optimization {
22
+ // Page the retrieved database results for memory purposes
23
+ // in case the media library is extremely big.
24
+ const PAGING_SIZE = 25000;
25
+
26
+ public static function get_optimization_statistics( $settings, $result = null ) {
27
+ $stats = array();
28
+ $stats['uploaded-images'] = 0;
29
+ $stats['optimized-image-sizes'] = 0;
30
+ $stats['available-unoptimised-sizes'] = 0;
31
+ $stats['optimized-library-size'] = 0;
32
+ $stats['unoptimized-library-size'] = 0;
33
+ $stats['available-for-optimization'] = array();
34
+
35
+ if ( is_null( $result ) ) {
36
+ $last_image_id = null;
37
+ do {
38
+ $result = self::wpdb_retrieve_images_and_metadata( $last_image_id );
39
+ $stats = self::populate_optimization_statistics( $settings, $result, $stats );
40
+ $last_image = end( $result );
41
+ $last_image_id = $last_image['ID'];
42
+ } while ( sizeof( $result ) == self::PAGING_SIZE );
43
+ } else {
44
+ $stats = self::populate_optimization_statistics( $settings, $result, $stats );
45
+ }
46
+ unset( $result );
47
+
48
+ if ( 0 != $stats['unoptimized-library-size'] ) {
49
+ $stats['display-percentage'] = round(
50
+ 100 -
51
+ ( $stats['optimized-library-size'] / $stats['unoptimized-library-size'] * 100 ), 1
52
+ );
53
+ } else {
54
+ $stats['display-percentage'] = 0;
55
+ }
56
+ return $stats;
57
+ }
58
+
59
+ private static function wpdb_retrieve_images_and_metadata( $start_id ) {
60
+ global $wpdb;
61
+
62
+ // Retrieve posts that have "_wp_attachment_metadata" image metadata
63
+ // and optionally contain "tiny_compress_images" metadata.
64
+ $sql_start_id = ( $start_id ? " $wpdb->posts.ID < $start_id AND " : '' );
65
+ $query =
66
+ "SELECT
67
+ $wpdb->posts.ID,
68
+ $wpdb->posts.post_title,
69
+ $wpdb->postmeta.meta_value,
70
+ wp_postmeta_file.meta_value AS unique_attachment_name,
71
+ wp_postmeta_tiny.meta_value AS tiny_meta_value
72
+ FROM $wpdb->posts
73
+ LEFT JOIN $wpdb->postmeta
74
+ ON $wpdb->posts.ID = $wpdb->postmeta.post_id
75
+ LEFT JOIN $wpdb->postmeta AS wp_postmeta_file
76
+ ON $wpdb->posts.ID = wp_postmeta_file.post_id
77
+ AND wp_postmeta_file.meta_key = '_wp_attached_file'
78
+ LEFT JOIN $wpdb->postmeta AS wp_postmeta_tiny
79
+ ON $wpdb->posts.ID = wp_postmeta_tiny.post_id
80
+ AND wp_postmeta_tiny.meta_key = '" . Tiny_Config::META_KEY . "'
81
+ WHERE
82
+ $sql_start_id
83
+ $wpdb->posts.post_type = 'attachment'
84
+ AND (
85
+ $wpdb->posts.post_mime_type = 'image/jpeg' OR
86
+ $wpdb->posts.post_mime_type = 'image/png'
87
+ )
88
+ AND $wpdb->postmeta.meta_key = '_wp_attachment_metadata'
89
+ GROUP BY unique_attachment_name
90
+ ORDER BY ID DESC
91
+ LIMIT " . self::PAGING_SIZE;
92
+
93
+ return $wpdb->get_results( $query, ARRAY_A ); // WPCS: unprepared SQL OK.
94
+ }
95
+
96
+ private static function populate_optimization_statistics( $settings, $result, $stats ) {
97
+ $active_sizes = $settings->get_sizes();
98
+ $active_tinify_sizes = $settings->get_active_tinify_sizes();
99
+ for ( $i = 0; $i < sizeof( $result ); $i++ ) {
100
+ $wp_metadata = unserialize( $result[ $i ]['meta_value'] );
101
+ $tiny_metadata = unserialize( $result[ $i ]['tiny_meta_value'] );
102
+ if ( ! is_array( $tiny_metadata ) ) {
103
+ $tiny_metadata = array();
104
+ }
105
+ $tiny_image = new Tiny_Image(
106
+ $settings,
107
+ $result[ $i ]['ID'],
108
+ $wp_metadata,
109
+ $tiny_metadata,
110
+ $active_sizes,
111
+ $active_tinify_sizes
112
+ );
113
+ $image_stats = $tiny_image->get_statistics( $active_sizes, $active_tinify_sizes );
114
+ $stats['uploaded-images']++;
115
+ $stats['available-unoptimised-sizes'] += $image_stats['available_unoptimized_sizes'];
116
+ $stats['optimized-image-sizes'] += $image_stats['image_sizes_optimized'];
117
+ $stats['optimized-library-size'] += $image_stats['optimized_total_size'];
118
+ $stats['unoptimized-library-size'] += $image_stats['initial_total_size'];
119
+ if ( $image_stats['available_unoptimized_sizes'] > 0 ) {
120
+ $stats['available-for-optimization'][] = array(
121
+ 'ID' => $result[ $i ]['ID'],
122
+ 'post_title' => $result[ $i ]['post_title'],
123
+ );
124
+ }
125
+ }
126
+ return $stats;
127
+ }
128
+ }
src/class-tiny-compress-client.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
src/class-tiny-compress-fopen.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -141,7 +141,7 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
141
 
142
  if ( ! $request ) {
143
  throw new Tiny_Exception(
144
- 'Could not execute request, enable cURL for detailed errors',
145
  'Tinify\FopenError'
146
  );
147
  }
@@ -200,6 +200,7 @@ class Tiny_Compress_Fopen extends Tiny_Compress {
200
  'header' => array_merge( $headers, array(
201
  'Authorization: Basic ' . base64_encode( 'api:' . $this->api_key ),
202
  'User-Agent: ' . self::identifier(),
 
203
  ) ),
204
  'content' => $body,
205
  'follow_location' => 0,
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
141
 
142
  if ( ! $request ) {
143
  throw new Tiny_Exception(
144
+ 'Could not execute fopen request',
145
  'Tinify\FopenError'
146
  );
147
  }
200
  'header' => array_merge( $headers, array(
201
  'Authorization: Basic ' . base64_encode( 'api:' . $this->api_key ),
202
  'User-Agent: ' . self::identifier(),
203
+ 'Content-Type: multipart/form-data',
204
  ) ),
205
  'content' => $body,
206
  'follow_location' => 0,
src/class-tiny-compress.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
src/class-tiny-exception.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
src/class-tiny-image-size.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
src/class-tiny-image.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -19,7 +19,6 @@
19
  */
20
 
21
  class Tiny_Image {
22
- const META_KEY = 'tiny_compress_images';
23
  const ORIGINAL = 0;
24
 
25
  private $settings;
@@ -29,13 +28,20 @@ class Tiny_Image {
29
  private $sizes = array();
30
  private $statistics = array();
31
 
32
- public function __construct( $settings, $id, $wp_metadata = null, $tiny_metadata = null ) {
 
 
 
 
 
 
 
33
  $this->settings = $settings;
34
  $this->id = $id;
35
  $this->wp_metadata = $wp_metadata;
36
  $this->parse_wp_metadata();
37
  $this->parse_tiny_metadata( $tiny_metadata );
38
- $this->detect_duplicates();
39
  }
40
 
41
  private function parse_wp_metadata() {
@@ -70,7 +76,7 @@ class Tiny_Image {
70
  }
71
  }
72
 
73
- private function detect_duplicates() {
74
  $filenames = array();
75
 
76
  if ( is_array( $this->wp_metadata )
@@ -78,8 +84,12 @@ class Tiny_Image {
78
  && isset( $this->wp_metadata['sizes'] )
79
  && is_array( $this->wp_metadata['sizes'] ) ) {
80
 
81
- $active_sizes = $this->settings->get_sizes();
82
- $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
 
 
 
 
83
 
84
  foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
85
  if ( $this->sizes[ $size_name ]->has_been_compressed()
@@ -116,7 +126,7 @@ class Tiny_Image {
116
 
117
  private function parse_tiny_metadata( $tiny_metadata ) {
118
  if ( is_null( $tiny_metadata ) ) {
119
- $tiny_metadata = get_post_meta( $this->id, self::META_KEY, true );
120
  }
121
  if ( $tiny_metadata ) {
122
  foreach ( $tiny_metadata as $size => $meta ) {
@@ -155,11 +165,39 @@ class Tiny_Image {
155
  return get_post_mime_type( $this->id );
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  public function compress() {
159
  if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
160
  return;
161
  }
162
 
 
 
 
 
 
163
  $success = 0;
164
  $failed = 0;
165
 
@@ -245,7 +283,7 @@ class Tiny_Image {
245
  foreach ( $this->sizes as $size_name => $size ) {
246
  $tiny_metadata[ $size_name ] = $size->meta;
247
  }
248
- update_post_meta( $this->id, self::META_KEY, $tiny_metadata );
249
  }
250
 
251
  public function get_image_sizes() {
@@ -347,7 +385,7 @@ class Tiny_Image {
347
  return '' . number_format( $savings, 1 );
348
  }
349
 
350
- public function get_statistics() {
351
  if ( $this->statistics ) {
352
  error_log( 'Strangely the image statistics are asked for again.' );
353
  return $this->statistics;
@@ -358,16 +396,12 @@ class Tiny_Image {
358
  $this->statistics['image_sizes_optimized'] = 0;
359
  $this->statistics['available_unoptimized_sizes'] = 0;
360
 
361
- $active_sizes = $this->settings->get_sizes();
362
- $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
363
-
364
  foreach ( $this->sizes as $size_name => $size ) {
365
  if ( ! $size->is_duplicate() ) {
366
  if ( array_key_exists( $size_name, $active_sizes ) ) {
367
  if ( isset( $size->meta['input'] ) ) {
368
  $input = $size->meta['input'];
369
  $this->statistics['initial_total_size'] += intval( $input['size'] );
370
-
371
  if ( isset( $size->meta['output'] ) ) {
372
  $output = $size->meta['output'];
373
  if ( $size->modified() ) {
@@ -392,88 +426,27 @@ class Tiny_Image {
392
  }
393
  }
394
  }
395
- }
396
-
397
- return $this->statistics;
398
- }
399
-
400
- public static function get_optimization_statistics( $settings, $result = null ) {
401
- global $wpdb;
402
-
403
- if ( is_null( $result ) ) {
404
- // Select posts that have "_wp_attachment_metadata" image metadata
405
- // and optionally contain "tiny_compress_images" metadata.
406
- $query =
407
- "SELECT
408
- $wpdb->posts.ID,
409
- $wpdb->posts.post_title,
410
- $wpdb->postmeta.meta_value,
411
- wp_postmeta_file.meta_value AS unique_attachment_name,
412
- wp_postmeta_tiny.meta_value AS tiny_meta_value
413
- FROM $wpdb->posts
414
- LEFT JOIN $wpdb->postmeta
415
- ON $wpdb->posts.ID = $wpdb->postmeta.post_id
416
- LEFT JOIN $wpdb->postmeta AS wp_postmeta_file
417
- ON $wpdb->posts.ID = wp_postmeta_file.post_id
418
- AND wp_postmeta_file.meta_key = '_wp_attached_file'
419
- LEFT JOIN $wpdb->postmeta AS wp_postmeta_tiny
420
- ON $wpdb->posts.ID = wp_postmeta_tiny.post_id
421
- AND wp_postmeta_tiny.meta_key = '" . self::META_KEY . "'
422
- WHERE $wpdb->posts.post_type = 'attachment'
423
- AND (
424
- $wpdb->posts.post_mime_type = 'image/jpeg' OR
425
- $wpdb->posts.post_mime_type = 'image/png'
426
- )
427
- AND $wpdb->postmeta.meta_key = '_wp_attachment_metadata'
428
- GROUP BY unique_attachment_name
429
- ORDER BY ID DESC";
430
-
431
- $result = $wpdb->get_results( $query, ARRAY_A ); // WPCS: unprepared SQL OK.
432
- }
433
-
434
- $stats = array();
435
- $stats['uploaded-images'] = 0;
436
- $stats['optimized-image-sizes'] = 0;
437
- $stats['available-unoptimised-sizes'] = 0;
438
- $stats['optimized-library-size'] = 0;
439
- $stats['unoptimized-library-size'] = 0;
440
- $stats['available-for-optimization'] = array();
441
-
442
- for ( $i = 0; $i < sizeof( $result ); $i++ ) {
443
- $wp_metadata = unserialize( $result[ $i ]['meta_value'] );
444
- $tiny_metadata = unserialize( $result[ $i ]['tiny_meta_value'] );
445
- if ( ! is_array( $tiny_metadata ) ) {
446
- $tiny_metadata = array();
447
- }
448
- $tiny_image = new Tiny_Image(
449
- $settings,
450
- $result[ $i ]['ID'],
451
- $wp_metadata,
452
- $tiny_metadata
453
- );
454
- $image_stats = $tiny_image->get_statistics();
455
- $stats['uploaded-images']++;
456
- $stats['available-unoptimised-sizes'] += $image_stats['available_unoptimized_sizes'];
457
- $stats['optimized-image-sizes'] += $image_stats['image_sizes_optimized'];
458
- $stats['optimized-library-size'] += $image_stats['optimized_total_size'];
459
- $stats['unoptimized-library-size'] += $image_stats['initial_total_size'];
460
- if ( $image_stats['available_unoptimized_sizes'] > 0 ) {
461
- $stats['available-for-optimization'][] = array(
462
- 'ID' => $result[ $i ]['ID'],
463
- 'post_title' => $result[ $i ]['post_title'],
464
- );
465
  }
466
  }
 
467
 
468
- if ( 0 != $stats['unoptimized-library-size'] ) {
469
- $stats['display-percentage'] = round(
470
- 100 -
471
- ( $stats['optimized-library-size'] / $stats['unoptimized-library-size'] * 100 ), 1
472
- );
473
- } else {
474
- $stats['display-percentage'] = 0;
475
- }
476
- return $stats;
477
  }
478
 
479
  public static function is_original( $size ) {
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
19
  */
20
 
21
  class Tiny_Image {
 
22
  const ORIGINAL = 0;
23
 
24
  private $settings;
28
  private $sizes = array();
29
  private $statistics = array();
30
 
31
+ public function __construct(
32
+ $settings,
33
+ $id,
34
+ $wp_metadata = null,
35
+ $tiny_metadata = null,
36
+ $active_sizes = null,
37
+ $active_tinify_sizes = null
38
+ ) {
39
  $this->settings = $settings;
40
  $this->id = $id;
41
  $this->wp_metadata = $wp_metadata;
42
  $this->parse_wp_metadata();
43
  $this->parse_tiny_metadata( $tiny_metadata );
44
+ $this->detect_duplicates( $active_sizes, $active_tinify_sizes );
45
  }
46
 
47
  private function parse_wp_metadata() {
76
  }
77
  }
78
 
79
+ private function detect_duplicates( $active_sizes, $active_tinify_sizes ) {
80
  $filenames = array();
81
 
82
  if ( is_array( $this->wp_metadata )
84
  && isset( $this->wp_metadata['sizes'] )
85
  && is_array( $this->wp_metadata['sizes'] ) ) {
86
 
87
+ if ( null == $active_sizes ) {
88
+ $active_sizes = $this->settings->get_sizes();
89
+ }
90
+ if ( null == $active_tinify_sizes ) {
91
+ $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
92
+ }
93
 
94
  foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
95
  if ( $this->sizes[ $size_name ]->has_been_compressed()
126
 
127
  private function parse_tiny_metadata( $tiny_metadata ) {
128
  if ( is_null( $tiny_metadata ) ) {
129
+ $tiny_metadata = get_post_meta( $this->id, Tiny_Config::META_KEY, true );
130
  }
131
  if ( $tiny_metadata ) {
132
  foreach ( $tiny_metadata as $size => $meta ) {
165
  return get_post_mime_type( $this->id );
166
  }
167
 
168
+ public function download_missing_image_sizes() {
169
+ global $as3cf;
170
+
171
+ if ( ! $as3cf || ! $as3cf->is_plugin_setup() ) {
172
+ error_log( 'offload s3 plugin not configured..' );
173
+ return;
174
+ }
175
+
176
+ $s3_data = get_post_meta( $this->id, 'amazonS3_info', true );
177
+ if ( ! $s3_data ) {
178
+ return;
179
+ }
180
+
181
+ $path = dirname( $s3_data['key'] );
182
+
183
+ foreach ( $this->sizes as $size_name => $size ) {
184
+ $local_file_path = get_home_path() . $s3_data['key'];
185
+
186
+ $s3_data['key'] = wp_normalize_path( $path . '/' . basename( $size->filename ) );
187
+ $as3cf->plugin_compat->copy_s3_file_to_server( $s3_data, $size->filename );
188
+ }
189
+ }
190
+
191
  public function compress() {
192
  if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
193
  return;
194
  }
195
 
196
+ /* Integration tests need to be written before this can be enabled. */
197
+ // if ( $this->settings->has_offload_s3_installed() ) {
198
+ // $this->download_missing_image_sizes();
199
+ // }
200
+
201
  $success = 0;
202
  $failed = 0;
203
 
283
  foreach ( $this->sizes as $size_name => $size ) {
284
  $tiny_metadata[ $size_name ] = $size->meta;
285
  }
286
+ update_post_meta( $this->id, Tiny_Config::META_KEY, $tiny_metadata );
287
  }
288
 
289
  public function get_image_sizes() {
385
  return '' . number_format( $savings, 1 );
386
  }
387
 
388
+ public function get_statistics( $active_sizes, $active_tinify_sizes ) {
389
  if ( $this->statistics ) {
390
  error_log( 'Strangely the image statistics are asked for again.' );
391
  return $this->statistics;
396
  $this->statistics['image_sizes_optimized'] = 0;
397
  $this->statistics['available_unoptimized_sizes'] = 0;
398
 
 
 
 
399
  foreach ( $this->sizes as $size_name => $size ) {
400
  if ( ! $size->is_duplicate() ) {
401
  if ( array_key_exists( $size_name, $active_sizes ) ) {
402
  if ( isset( $size->meta['input'] ) ) {
403
  $input = $size->meta['input'];
404
  $this->statistics['initial_total_size'] += intval( $input['size'] );
 
405
  if ( isset( $size->meta['output'] ) ) {
406
  $output = $size->meta['output'];
407
  if ( $size->modified() ) {
426
  }
427
  }
428
  }
429
+ }// End foreach().
430
+
431
+ /*
432
+ When an image hasn't yet been optimized but only exists on S3, we still need to
433
+ know the total size of the image sizes for the bulk optimization tool.
434
+ TODO: First write integration tests before enabling this again.
435
+
436
+ if (
437
+ 0 === $this->statistics['initial_total_size'] &&
438
+ 0 === $this->statistics['optimized_total_size'] &&
439
+ $this->settings->has_offload_s3_installed()
440
+ ) {
441
+ $s3_data = get_post_meta( $this->id, 'wpos3_filesize_total', true );
442
+ if ( $s3_data ) {
443
+ $this->statistics['initial_total_size'] = $s3_data;
444
+ $this->statistics['optimized_total_size'] = $s3_data;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  }
446
  }
447
+ */
448
 
449
+ return $this->statistics;
 
 
 
 
 
 
 
 
450
  }
451
 
452
  public static function is_original( $size ) {
src/class-tiny-notices.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -138,4 +138,38 @@ class Tiny_Notices extends Tiny_WP_Base {
138
  )
139
  );
140
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
138
  )
139
  );
140
  }
141
+
142
+ public function show_incompatible_plugins( $incompatible_plugins ) {
143
+ $notice = '<div class="error notice tiny-notice incompatible-plugins">';
144
+ $notice .= '<h3>';
145
+ $notice .= esc_html__( 'Compress JPEG & PNG images', 'tiny-compress-images' );
146
+ $notice .= '</h3>';
147
+ $notice .= '<p>';
148
+ $notice .= esc_html__(
149
+ 'These plugins are incompatible and may cause unexpected results:',
150
+ 'tiny-compress-images'
151
+ );
152
+ $notice .= '</p>';
153
+ $notice .= '<table>';
154
+ foreach ( $incompatible_plugins as $name => $file ) {
155
+ $notice .= '<tr><td class="bullet">•</td><td class="name">';
156
+ $notice .= $name;
157
+ $notice .= '</td><td>';
158
+ $nonce = wp_create_nonce( 'deactivate-plugin_' . $file );
159
+ $query_string = 'action=deactivate&plugin=' . $file . '&_wpnonce=' . $nonce;
160
+ $url = admin_url( 'plugins.php?' . $query_string );
161
+ $notice .= '<a class="button button-primary" href="' . $url . '">';
162
+ $notice .= esc_html__( 'Deactivate' );
163
+ $notice .= '</a></td></tr>';
164
+ }
165
+ $notice .= '</table>';
166
+ $notice .= '</div>';
167
+
168
+ add_action( 'admin_notices',
169
+ create_function(
170
+ '',
171
+ "echo '$notice';"
172
+ )
173
+ );
174
+ }
175
  }
src/class-tiny-php.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -19,11 +19,26 @@
19
  */
20
 
21
  class Tiny_PHP {
 
 
 
 
 
 
 
 
22
  public static function fopen_available() {
23
  return ini_get( 'allow_url_fopen' );
24
  }
25
 
 
 
 
 
 
26
  public static function client_supported() {
27
- return version_compare( PHP_VERSION, '5.3', '>' ) && extension_loaded( 'curl' );
 
 
28
  }
29
  }
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
19
  */
20
 
21
  class Tiny_PHP {
22
+ public static function has_fully_supported_php() {
23
+ return version_compare( PHP_VERSION, '5.3', '>' );
24
+ }
25
+
26
+ public static function curl_available() {
27
+ return extension_loaded( 'curl' );
28
+ }
29
+
30
  public static function fopen_available() {
31
  return ini_get( 'allow_url_fopen' );
32
  }
33
 
34
+ public static function curl_exec_disabled() {
35
+ $disabled_functions = explode( ',', ini_get( 'disable_functions' ) );
36
+ return in_array( 'curl_exec', $disabled_functions );
37
+ }
38
+
39
  public static function client_supported() {
40
+ return Tiny_PHP::has_fully_supported_php() &&
41
+ Tiny_PHP::curl_available() &&
42
+ ! Tiny_PHP::curl_exec_disabled();
43
  }
44
  }
src/class-tiny-plugin.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -18,7 +18,7 @@
18
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
  */
20
  class Tiny_Plugin extends Tiny_WP_Base {
21
- const VERSION = '2.2.6';
22
  const MEDIA_COLUMN = self::NAME;
23
  const DATETIME_FORMAT = 'Y-m-d G:i:s';
24
 
@@ -57,10 +57,14 @@ class Tiny_Plugin extends Tiny_WP_Base {
57
  );
58
 
59
  add_filter( 'wp_generate_attachment_metadata',
60
- $this->get_method( 'compress_on_upload' ),
61
  10, 2
62
  );
63
 
 
 
 
 
64
  load_plugin_textdomain( self::NAME, false,
65
  dirname( plugin_basename( __FILE__ ) ) . '/languages'
66
  );
@@ -96,6 +100,10 @@ class Tiny_Plugin extends Tiny_WP_Base {
96
  $this->get_method( 'show_media_info' )
97
  );
98
 
 
 
 
 
99
  add_action( 'wp_ajax_tiny_compress_image_from_library',
100
  $this->get_method( 'compress_image_from_library' )
101
  );
@@ -108,6 +116,10 @@ class Tiny_Plugin extends Tiny_WP_Base {
108
  $this->get_method( 'ajax_optimization_statistics' )
109
  );
110
 
 
 
 
 
111
  $plugin = plugin_basename(
112
  dirname( dirname( __FILE__ ) ) . '/tiny-compress-images.php'
113
  );
@@ -142,8 +154,7 @@ class Tiny_Plugin extends Tiny_WP_Base {
142
  public function add_plugin_links( $current_links ) {
143
  $additional = array(
144
  'settings' => sprintf(
145
- '<a href="options-media.php#%s">%s</a>',
146
- self::NAME,
147
  esc_html__( 'Settings', 'tiny-compress-images' )
148
  ),
149
  'bulk' => sprintf(
@@ -229,10 +240,24 @@ class Tiny_Plugin extends Tiny_WP_Base {
229
 
230
  wp_enqueue_script( self::NAME . '_tiny_bulk_optimization' );
231
  }
 
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  }
234
 
235
- public function compress_on_upload( $metadata, $attachment_id ) {
236
  if ( ! empty( $metadata ) ) {
237
  $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata );
238
  $result = $tiny_image->compress( $this->settings );
@@ -242,6 +267,97 @@ class Tiny_Plugin extends Tiny_WP_Base {
242
  }
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  public function compress_image_from_library() {
246
  if ( ! $this->check_ajax_referer() ) {
247
  exit();
@@ -325,12 +441,18 @@ class Tiny_Plugin extends Tiny_WP_Base {
325
  }
326
 
327
  $tiny_image_before = new Tiny_Image( $this->settings, $id, $metadata );
328
- $image_statistics_before = $tiny_image_before->get_statistics();
 
 
 
329
  $size_before = $image_statistics_before['optimized_total_size'];
330
 
331
  $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
332
  $result = $tiny_image->compress( $this->settings );
333
- $image_statistics = $tiny_image->get_statistics();
 
 
 
334
  wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() );
335
 
336
  $current_library_size = intval( $_POST['current_size'] );
@@ -368,30 +490,67 @@ class Tiny_Plugin extends Tiny_WP_Base {
368
  if ( ! $this->check_ajax_referer() ) {
369
  exit();
370
  }
371
- $stats = Tiny_Image::get_optimization_statistics( $this->settings );
372
  echo json_encode( $stats );
373
  exit();
374
  }
375
 
376
- public function media_library_bulk_action() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
 
 
378
  if ( empty( $_REQUEST['action'] ) || (
379
  'tiny_bulk_action' != $_REQUEST['action'] &&
380
  'tiny_bulk_action' != $_REQUEST['action2'] ) ) {
381
  return;
382
  }
383
-
384
  if ( empty( $_REQUEST['media'] ) || ( ! $_REQUEST['media'] ) ) {
 
385
  return;
386
  }
387
-
388
  check_admin_referer( 'bulk-media' );
389
  $ids = implode( '-', array_map( 'intval', $_REQUEST['media'] ) );
390
- wp_redirect(add_query_arg(
391
- '_wpnonce',
392
- wp_create_nonce( 'tiny-bulk-optimization' ),
393
- admin_url( "upload.php?page=tiny-bulk-optimization&ids=$ids" )
394
- ));
 
 
 
 
 
 
 
 
395
  exit();
396
  }
397
 
@@ -436,7 +595,7 @@ class Tiny_Plugin extends Tiny_WP_Base {
436
  }
437
 
438
  public function render_bulk_optimization_page() {
439
- $stats = Tiny_Image::get_optimization_statistics( $this->settings );
440
  $estimated_costs = Tiny_Compress::estimate_cost(
441
  $stats['available-unoptimised-sizes'],
442
  $this->settings->get_compression_count()
@@ -445,8 +604,6 @@ class Tiny_Plugin extends Tiny_WP_Base {
445
 
446
  $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
447
 
448
- $auto_start_bulk = isset( $_REQUEST['ids'] );
449
-
450
  include( dirname( __FILE__ ) . '/views/bulk-optimization.php' );
451
  }
452
 
@@ -519,20 +676,4 @@ class Tiny_Plugin extends Tiny_WP_Base {
519
  $name = ucfirst( empty( $user->first_name ) ? $user->display_name : $user->first_name );
520
  return $name;
521
  }
522
-
523
- private function get_ids_to_compress() {
524
- if ( empty( $_REQUEST['ids'] ) ) {
525
- return array();
526
- }
527
-
528
- $ids = implode( ',', array_map( 'intval', explode( '-', $_REQUEST['ids'] ) ) );
529
- $condition = "AND ID IN($ids)";
530
-
531
- global $wpdb;
532
- return $wpdb->get_results( // WPCS: unprepared SQL OK.
533
- "SELECT ID, post_title FROM $wpdb->posts
534
- WHERE post_type = 'attachment' $condition
535
- AND (post_mime_type = 'image/jpeg' OR post_mime_type = 'image/png')
536
- ORDER BY ID DESC", ARRAY_A);
537
- }
538
  }
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
18
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
  */
20
  class Tiny_Plugin extends Tiny_WP_Base {
21
+ const VERSION = '3.0.0';
22
  const MEDIA_COLUMN = self::NAME;
23
  const DATETIME_FORMAT = 'Y-m-d G:i:s';
24
 
57
  );
58
 
59
  add_filter( 'wp_generate_attachment_metadata',
60
+ $this->get_method( 'process_attachment' ),
61
  10, 2
62
  );
63
 
64
+ add_filter( 'wp_ajax_nopriv_tiny_rpc',
65
+ $this->get_method( 'process_rpc_request' )
66
+ );
67
+
68
  load_plugin_textdomain( self::NAME, false,
69
  dirname( plugin_basename( __FILE__ ) ) . '/languages'
70
  );
100
  $this->get_method( 'show_media_info' )
101
  );
102
 
103
+ add_filter( 'wp_ajax_tiny_async_optimize_upload_new_media',
104
+ $this->get_method( 'compress_on_upload' )
105
+ );
106
+
107
  add_action( 'wp_ajax_tiny_compress_image_from_library',
108
  $this->get_method( 'compress_image_from_library' )
109
  );
116
  $this->get_method( 'ajax_optimization_statistics' )
117
  );
118
 
119
+ add_action( 'wp_ajax_tiny_get_compression_status',
120
+ $this->get_method( 'ajax_compression_status' )
121
+ );
122
+
123
  $plugin = plugin_basename(
124
  dirname( dirname( __FILE__ ) ) . '/tiny-compress-images.php'
125
  );
154
  public function add_plugin_links( $current_links ) {
155
  $additional = array(
156
  'settings' => sprintf(
157
+ '<a href="options-general.php?page=tinify">%s</a>',
 
158
  esc_html__( 'Settings', 'tiny-compress-images' )
159
  ),
160
  'bulk' => sprintf(
240
 
241
  wp_enqueue_script( self::NAME . '_tiny_bulk_optimization' );
242
  }
243
+ }
244
 
245
+ public function process_attachment( $metadata, $attachment_id ) {
246
+ if ( $this->settings->auto_compress_enabled() ) {
247
+ if (
248
+ $this->settings->background_compress_enabled() &&
249
+ ! $this->settings->remove_local_files_setting_enabled()
250
+ ) {
251
+ $this->async_compress_on_upload( $metadata, $attachment_id );
252
+ } else {
253
+ return $this->blocking_compress_on_upload( $metadata, $attachment_id );
254
+ }
255
+ }
256
+
257
+ return $metadata;
258
  }
259
 
260
+ public function blocking_compress_on_upload( $metadata, $attachment_id ) {
261
  if ( ! empty( $metadata ) ) {
262
  $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata );
263
  $result = $tiny_image->compress( $this->settings );
267
  }
268
  }
269
 
270
+ public function async_compress_on_upload( $metadata, $attachment_id ) {
271
+ $context = 'wp';
272
+ $action = 'tiny_async_optimize_upload_new_media';
273
+ $_ajax_nonce = wp_create_nonce( 'new_media-' . $attachment_id );
274
+ $body = compact( 'action', '_ajax_nonce', 'metadata', 'attachment_id', 'context' );
275
+
276
+ $args = array(
277
+ 'timeout' => 0.01,
278
+ 'blocking' => false,
279
+ 'body' => $body,
280
+ 'cookies' => isset( $_COOKIE ) && is_array( $_COOKIE ) ? $_COOKIE : array(),
281
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
282
+ );
283
+
284
+ if ( defined( 'XMLRPC_REQUEST' ) && get_current_user_id() ) {
285
+ /* We generate a hash to be used for the transient we use to store the current user. */
286
+ $rpc_hash = md5( maybe_serialize( $body ) );
287
+
288
+ $args['body']['tiny_rpc_action'] = $args['body']['action'];
289
+ /* We set a different action to make sure that all RPC requests are first validated. */
290
+ $args['body']['action'] = 'tiny_rpc';
291
+ $args['body']['tiny_rpc_hash'] = $rpc_hash;
292
+ $args['body']['tiny_rpc_nonce'] = wp_create_nonce( 'tiny_rpc_' . $rpc_hash );
293
+
294
+ /*
295
+ We can't use cookies here, so we save the user id in a transient
296
+ so that we can retrieve it again when processing the RPC request.
297
+ We should be able to use a relatively short timeout, as the request
298
+ should be processed directly afterwards.
299
+ */
300
+ set_transient( 'tiny_rpc_' . $rpc_hash, get_current_user_id(), 10 );
301
+ }
302
+
303
+ if ( getenv( 'WORDPRESS_HOST' ) !== false ) {
304
+ wp_remote_post( getenv( 'WORDPRESS_HOST' ) . '/wp-admin/admin-ajax.php', $args );
305
+ } else {
306
+ wp_remote_post( admin_url( 'admin-ajax.php' ), $args );
307
+ }
308
+ }
309
+
310
+ public function process_rpc_request() {
311
+ if (
312
+ empty( $_POST['tiny_rpc_action'] ) ||
313
+ empty( $_POST['tiny_rpc_hash'] ) ||
314
+ 32 !== strlen( $_POST['tiny_rpc_hash'] )
315
+ ) {
316
+ exit();
317
+ }
318
+
319
+ $rpc_hash = sanitize_key( $_POST['tiny_rpc_hash'] );
320
+ $user_id = absint( get_transient( 'tiny_rpc_' . $rpc_hash ) );
321
+ $user = $user_id ? get_userdata( $user_id ) : false;
322
+
323
+ /* We no longer need the transient. */
324
+ delete_transient( 'tiny_rpc_' . $rpc_hash );
325
+
326
+ if ( ! $user || ! $user->exists() ) {
327
+ exit();
328
+ }
329
+ wp_set_current_user( $user_id );
330
+
331
+ if ( ! check_ajax_referer( 'tiny_rpc_' . $rpc_hash, 'tiny_rpc_nonce', false ) ) {
332
+ exit();
333
+ }
334
+
335
+ /* Now that everything is checked, perform the actual action. */
336
+ $action = $_POST['tiny_rpc_action'];
337
+ unset(
338
+ $_POST['action'],
339
+ $_POST['tiny_rpc_action'],
340
+ $_POST['tiny_rpc_id'],
341
+ $_POST['tiny_rpc_nonce']
342
+ );
343
+ do_action( 'wp_ajax_' . $action );
344
+ }
345
+
346
+ public function compress_on_upload() {
347
+ $attachment_id = intval( $_POST['attachment_id'] );
348
+ $metadata = $_POST['metadata'];
349
+ if ( is_array( $metadata ) ) {
350
+ $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata );
351
+ $result = $tiny_image->compress( $this->settings );
352
+ // The wp_update_attachment_metadata call is thrown because the
353
+ // dimensions of the original image can change. This will then
354
+ // trigger other plugins and can result in unexpected behaviour and
355
+ // further changes to the image. This may require another approach.
356
+ wp_update_attachment_metadata( $attachment_id, $tiny_image->get_wp_metadata() );
357
+ }
358
+ exit();
359
+ }
360
+
361
  public function compress_image_from_library() {
362
  if ( ! $this->check_ajax_referer() ) {
363
  exit();
441
  }
442
 
443
  $tiny_image_before = new Tiny_Image( $this->settings, $id, $metadata );
444
+ $image_statistics_before = $tiny_image_before->get_statistics(
445
+ $this->settings->get_sizes(),
446
+ $this->settings->get_active_tinify_sizes()
447
+ );
448
  $size_before = $image_statistics_before['optimized_total_size'];
449
 
450
  $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
451
  $result = $tiny_image->compress( $this->settings );
452
+ $image_statistics = $tiny_image->get_statistics(
453
+ $this->settings->get_sizes(),
454
+ $this->settings->get_active_tinify_sizes()
455
+ );
456
  wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() );
457
 
458
  $current_library_size = intval( $_POST['current_size'] );
490
  if ( ! $this->check_ajax_referer() ) {
491
  exit();
492
  }
493
+ $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings );
494
  echo json_encode( $stats );
495
  exit();
496
  }
497
 
498
+ public function ajax_compression_status() {
499
+ if ( ! $this->check_ajax_referer() ) {
500
+ exit();
501
+ }
502
+
503
+ if ( empty( $_POST['id'] ) ) {
504
+ $message = esc_html__(
505
+ 'Not a valid media file.',
506
+ 'tiny-compress-images'
507
+ );
508
+ echo $message;
509
+ exit();
510
+ }
511
+ $id = intval( $_POST['id'] );
512
+ $metadata = wp_get_attachment_metadata( $id );
513
+ if ( ! is_array( $metadata ) ) {
514
+ $message = esc_html__(
515
+ 'Could not find metadata of media file.',
516
+ 'tiny-compress-images'
517
+ );
518
+ echo $message;
519
+ exit;
520
+ }
521
+
522
+ $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
523
+
524
+ echo $this->render_compress_details( $tiny_image );
525
+
526
+ exit();
527
+ }
528
 
529
+ public function media_library_bulk_action() {
530
  if ( empty( $_REQUEST['action'] ) || (
531
  'tiny_bulk_action' != $_REQUEST['action'] &&
532
  'tiny_bulk_action' != $_REQUEST['action2'] ) ) {
533
  return;
534
  }
 
535
  if ( empty( $_REQUEST['media'] ) || ( ! $_REQUEST['media'] ) ) {
536
+ $_REQUEST['action'] = '';
537
  return;
538
  }
 
539
  check_admin_referer( 'bulk-media' );
540
  $ids = implode( '-', array_map( 'intval', $_REQUEST['media'] ) );
541
+ $location = 'upload.php?mode=list&ids=' . $ids;
542
+
543
+ if ( ! empty( $_REQUEST['paged'] ) ) {
544
+ $location = add_query_arg( 'paged', absint( $_REQUEST['paged'] ), $location );
545
+ }
546
+ if ( ! empty( $_REQUEST['s'] ) ) {
547
+ $location = add_query_arg( 's', $_REQUEST['s'], $location );
548
+ }
549
+ if ( ! empty( $_REQUEST['m'] ) ) {
550
+ $location = add_query_arg( 'm', $_REQUEST['m'], $location );
551
+ }
552
+
553
+ wp_redirect( admin_url( $location ) );
554
  exit();
555
  }
556
 
595
  }
596
 
597
  public function render_bulk_optimization_page() {
598
+ $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings );
599
  $estimated_costs = Tiny_Compress::estimate_cost(
600
  $stats['available-unoptimised-sizes'],
601
  $this->settings->get_compression_count()
604
 
605
  $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
606
 
 
 
607
  include( dirname( __FILE__ ) . '/views/bulk-optimization.php' );
608
  }
609
 
676
  $name = ucfirst( empty( $user->first_name ) ? $user->display_name : $user->first_name );
677
  return $name;
678
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
src/class-tiny-settings.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
@@ -25,9 +25,22 @@ class Tiny_Settings extends Tiny_WP_Base {
25
  private $compressor;
26
  private $notices;
27
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  public function __construct() {
29
  parent::__construct();
30
  $this->notices = new Tiny_Notices();
 
31
  }
32
 
33
  private function init_compressor() {
@@ -38,7 +51,7 @@ class Tiny_Settings extends Tiny_WP_Base {
38
  }
39
 
40
  public function get_absolute_url() {
41
- return get_admin_url( null, 'options-media.php#' . self::NAME );
42
  }
43
 
44
  public function xmlrpc_init() {
@@ -48,46 +61,20 @@ class Tiny_Settings extends Tiny_WP_Base {
48
  }
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
51
  public function admin_init() {
52
  if ( current_user_can( 'manage_options' ) ) {
53
- if ( ! $this->get_api_key() ) {
54
- $notice_class = 'error';
55
- $notice = esc_html__(
56
- 'Please register or provide an API key to start compressing images',
57
- 'tiny-compress-images'
58
- );
59
- } elseif ( $this->get_api_key_pending() ) {
60
- $notice_class = 'notice-warning';
61
- $notice = esc_html__(
62
- 'Please activate your account to start compressing images',
63
- 'tiny-compress-images'
64
- );
65
- }
66
-
67
- if ( isset( $notice ) && $notice ) {
68
- $link = sprintf(
69
- '<a href="options-media.php#%s">%s</a>', self::NAME, $notice
70
- );
71
- $this->notices->show( 'setting', $link, $notice_class, false );
72
- }
73
-
74
- if ( ! Tiny_PHP::client_supported() ) {
75
- $details = 'PHP ' . PHP_VERSION;
76
- if ( extension_loaded( 'curl' ) ) {
77
- $curlinfo = curl_version();
78
- $details .= ' with curl ' . $curlinfo['version'];
79
- } else {
80
- $details .= ' without curl';
81
- }
82
- $message = sprintf(
83
- esc_html__(
84
- 'You are using an outdated platform (%s) – some features are disabled',
85
- 'tiny-compress-images'
86
- ), $details
87
- );
88
- $this->notices->show( 'deprecated', $message, 'notice-warning', false );
89
- }
90
- }// End if().
91
 
92
  try {
93
  $this->init_compressor();
@@ -99,50 +86,29 @@ class Tiny_Settings extends Tiny_WP_Base {
99
  );
100
  }
101
 
102
- $section = self::get_prefixed_name( 'settings' );
103
- add_settings_section( $section,
104
- esc_html__( 'JPEG and PNG optimization', 'tiny-compress-images' ),
105
- $this->get_method( 'render_section' ),
106
  'media'
107
  );
108
 
109
  $field = self::get_prefixed_name( 'api_key' );
110
- register_setting( 'media', $field );
111
- add_settings_field( $field,
112
- esc_html__( 'TinyPNG account', 'tiny-compress-images' ),
113
- $this->get_method( 'render_pending_status' ),
114
- 'media',
115
- $section
116
- );
117
 
118
  $field = self::get_prefixed_name( 'api_key_pending' );
119
- register_setting( 'media', $field );
 
 
 
120
 
121
  $field = self::get_prefixed_name( 'sizes' );
122
- register_setting( 'media', $field );
123
- add_settings_field( $field,
124
- esc_html__( 'File compression', 'tiny-compress-images' ),
125
- $this->get_method( 'render_sizes' ),
126
- 'media',
127
- $section
128
- );
129
 
130
  $field = self::get_prefixed_name( 'resize_original' );
131
- register_setting( 'media', $field );
132
- add_settings_field( $field,
133
- esc_html__( 'Original image', 'tiny-compress-images' ),
134
- $this->get_method( 'render_resize' ),
135
- 'media',
136
- $section
137
- );
138
 
139
  $field = self::get_prefixed_name( 'preserve_data' );
140
- register_setting( 'media', $field );
141
-
142
- add_settings_section( 'section_end', '',
143
- $this->get_method( 'render_section_end' ),
144
- 'media'
145
- );
146
 
147
  add_action(
148
  'wp_ajax_tiny_image_sizes_notice',
@@ -165,6 +131,10 @@ class Tiny_Settings extends Tiny_WP_Base {
165
  );
166
  }
167
 
 
 
 
 
168
  public function image_sizes_notice() {
169
  $this->render_image_sizes_notice(
170
  $_GET['image_sizes_selected'],
@@ -191,6 +161,20 @@ class Tiny_Settings extends Tiny_WP_Base {
191
  return intval( get_option( self::get_prefixed_name( 'status' ) ) );
192
  }
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  protected function get_api_key() {
195
  if ( defined( 'TINY_API_KEY' ) ) {
196
  return TINY_API_KEY;
@@ -284,6 +268,12 @@ class Tiny_Settings extends Tiny_WP_Base {
284
  return $this->tinify_sizes;
285
  }
286
 
 
 
 
 
 
 
287
  public function get_resize_enabled() {
288
  /* This only applies if the original is being resized. */
289
  $sizes = $this->get_sizes();
@@ -295,6 +285,79 @@ class Tiny_Settings extends Tiny_WP_Base {
295
  return isset( $setting['enabled'] ) && 'on' === $setting['enabled'];
296
  }
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  public function get_preserve_enabled( $name ) {
299
  $setting = get_option( self::get_prefixed_name( 'preserve_data' ) );
300
  return isset( $setting[ $name ] ) && 'on' === $setting[ $name ];
@@ -338,22 +401,205 @@ class Tiny_Settings extends Tiny_WP_Base {
338
  return sizeof( $options ) >= 2 ? $options : false;
339
  }
340
 
341
- public function render_section_end() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  echo '</div>';
343
  }
344
 
345
- public function render_section() {
346
- echo '<div class="' . self::NAME . '">';
347
- echo '<span id="' . self::NAME . '"></span>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
349
 
350
- public function render_sizes() {
351
- echo '<p>';
352
- esc_html_e(
353
- 'Choose sizes to compress. Remember each selected size counts as a compression.',
354
  'tiny-compress-images'
355
  );
356
- echo '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  echo '<input type="hidden" name="' .
358
  self::get_prefixed_name( 'sizes[' . self::DUMMY_SIZE . ']' ) . '" value="on"/>';
359
 
@@ -381,7 +627,10 @@ class Tiny_Settings extends Tiny_WP_Base {
381
  $checked = ( $option['tinify'] ? ' checked="checked"' : '' );
382
  if ( Tiny_Image::is_original( $size ) ) {
383
  $label = esc_html__( 'Original image', 'tiny-compress-images' ) . ' (' .
384
- esc_html__( 'overwritten by compressed image', 'tiny-compress-images' ) . ')';
 
 
 
385
  } elseif ( Tiny_Image::is_retina( $size ) ) {
386
  $label = esc_html__( 'WP Retina 2x sizes', 'tiny-compress-images' );
387
  } else {
@@ -408,6 +657,12 @@ class Tiny_Settings extends Tiny_WP_Base {
408
  public function render_image_sizes_notice(
409
  $active_sizes_count, $resize_original_enabled, $compress_wr2x ) {
410
  echo '<p>';
 
 
 
 
 
 
411
  if ( $resize_original_enabled ) {
412
  $active_sizes_count++;
413
  }
@@ -429,10 +684,11 @@ class Tiny_Settings extends Tiny_WP_Base {
429
  'strong' => array(),
430
  );
431
 
 
432
  printf( wp_kses( __(
433
- 'With these settings you can compress <strong>at least %1$s images</strong> %2$s',
434
  'tiny-compress-images'
435
- ), $strong ), $free_images_per_month, 'for free each month.' );
436
 
437
  if ( self::wr2x_active() ) {
438
  echo '</p>';
@@ -447,11 +703,15 @@ class Tiny_Settings extends Tiny_WP_Base {
447
  'tiny-compress-images'
448
  );
449
  }
450
- }
451
  echo '</p>';
452
  }
453
 
454
  public function render_resize() {
 
 
 
 
455
  echo '<p class="tiny-resize-unavailable" style="display: none">';
456
  esc_html_e(
457
  'Enable compression of the original image size for more options.',
@@ -464,40 +724,34 @@ class Tiny_Settings extends Tiny_WP_Base {
464
  $checked = ( $this->get_resize_enabled() ? ' checked="checked"' : '' );
465
 
466
  $label = esc_html__(
467
- 'Resize and compress the original image',
468
  'tiny-compress-images'
469
  );
470
 
471
- echo '<p class="tiny-resize-available">';
472
  echo '<input type="checkbox" id="' . $id . '" name="' . $name .
473
  '" value="on" ' . $checked . '/>';
474
- echo '<label for="' . $id . '">' . $label . '</label>';
475
- echo '<br>';
476
- echo '</p>';
477
 
478
- echo '<p class="tiny-resize-available tiny-resize-resolution">';
479
- printf( '%s ', esc_html__( 'Max Width' ) );
 
 
 
 
 
 
480
  $this->render_resize_input( 'width' );
481
- printf( '%s ', esc_html__( 'Max Height' ) );
482
  $this->render_resize_input( 'height' );
483
- echo '</p>';
484
-
485
- echo '<p class="tiny-resize-available tiny-resize-resolution">';
486
-
487
- esc_html_e(
488
- 'Resizing takes 1 additional compression for each image that is larger.',
489
- 'tiny-compress-images'
490
- );
491
-
492
- echo '</p><br>';
493
 
494
  $this->render_preserve_input(
495
  'creation',
496
  esc_html__(
497
  'Preserve creation date and time in the original image',
498
  'tiny-compress-images'
499
- ) . ' ' .
500
- esc_html__( '(JPEG only)', 'tiny-compress-images' )
501
  );
502
 
503
  $this->render_preserve_input(
@@ -518,6 +772,46 @@ class Tiny_Settings extends Tiny_WP_Base {
518
  );
519
  }
520
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  public function render_preserve_input( $name, $description ) {
522
  echo '<p class="tiny-preserve">';
523
  $id = sprintf( self::get_prefixed_name( 'preserve_data_%s' ), $name );
@@ -545,6 +839,11 @@ class Tiny_Settings extends Tiny_WP_Base {
545
  return get_option( $field );
546
  }
547
 
 
 
 
 
 
548
  public function after_compress_callback( $compressor ) {
549
  $count = $compressor->get_compression_count();
550
  if ( ! is_null( $count ) ) {
@@ -552,18 +851,16 @@ class Tiny_Settings extends Tiny_WP_Base {
552
  update_option( $field, $count );
553
  }
554
  if ( $compressor->limit_reached() ) {
555
- $link = '<a href="https://tinypng.com/dashboard/developers" target="_blank">' .
556
  esc_html__( 'TinyPNG API account', 'tiny-compress-images' ) . '</a>';
557
 
558
  $this->notices->add('limit-reached',
 
 
 
 
559
  sprintf(
560
- esc_html__(
561
- 'You have reached your limit of %s compressions this month.',
562
- 'tiny-compress-images'
563
- ),
564
- $count
565
- ) .
566
- sprintf(
567
  esc_html__(
568
  'Upgrade your %s if you like to compress more images.',
569
  'tiny-compress-images'
@@ -651,7 +948,7 @@ class Tiny_Settings extends Tiny_WP_Base {
651
  $compressor->create_key( $_POST['email'], array(
652
  'name' => $_POST['name'],
653
  'identifier' => $identifier,
654
- 'link' => $link,
655
  ) );
656
 
657
  update_option( self::get_prefixed_name( 'api_key_pending' ), true );
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
25
  private $compressor;
26
  private $notices;
27
 
28
+ protected static $incompatible_plugins = array(
29
+ 'CheetahO Image Optimizer' => 'cheetaho-image-optimizer/cheetaho.php',
30
+ 'EWWW Image Optimizer' => 'ewww-image-optimizer/ewww-image-optimizer.php',
31
+ 'Imagify' => 'imagify/imagify.php',
32
+ 'Kraken Image Optimizer' => 'kraken-image-optimizer/kraken.php',
33
+ 'ShortPixel Image Optimizer' => 'shortpixel-image-optimiser/wp-shortpixel.php',
34
+ 'WP Smush' => 'wp-smushit/wp-smush.php',
35
+ 'WP Smush Pro' => 'wp-smush-pro/wp-smush.php',
36
+ );
37
+
38
+ protected static $offload_s3_plugin = 'amazon-s3-and-cloudfront/wordpress-s3.php';
39
+
40
  public function __construct() {
41
  parent::__construct();
42
  $this->notices = new Tiny_Notices();
43
+ add_action( 'admin_menu', array( $this, 'add_menu' ) );
44
  }
45
 
46
  private function init_compressor() {
51
  }
52
 
53
  public function get_absolute_url() {
54
+ return get_admin_url( null, 'options-general.php?page=tinify' );
55
  }
56
 
57
  public function xmlrpc_init() {
61
  }
62
  }
63
 
64
+ public function add_menu() {
65
+ add_options_page(
66
+ __( 'Compress JPEG & PNG images', 'tiny-compress-images' ),
67
+ esc_html__( 'Compress JPEG & PNG images', 'tiny-compress-images' ),
68
+ 'manage_options',
69
+ 'tinify',
70
+ array( $this, 'add_options_to_page' )
71
+ );
72
+ }
73
+
74
  public function admin_init() {
75
  if ( current_user_can( 'manage_options' ) ) {
76
+ $this->render_notices();
77
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  try {
80
  $this->init_compressor();
86
  );
87
  }
88
 
89
+ /* Create link to new settings page from media settings page. */
90
+ add_settings_section( 'section_end', '',
91
+ $this->get_method( 'render_settings_link' ),
 
92
  'media'
93
  );
94
 
95
  $field = self::get_prefixed_name( 'api_key' );
96
+ register_setting( 'tinify', $field );
 
 
 
 
 
 
97
 
98
  $field = self::get_prefixed_name( 'api_key_pending' );
99
+ register_setting( 'tinify', $field );
100
+
101
+ $field = self::get_prefixed_name( 'compression_timing' );
102
+ register_setting( 'tinify', $field );
103
 
104
  $field = self::get_prefixed_name( 'sizes' );
105
+ register_setting( 'tinify', $field );
 
 
 
 
 
 
106
 
107
  $field = self::get_prefixed_name( 'resize_original' );
108
+ register_setting( 'tinify', $field );
 
 
 
 
 
 
109
 
110
  $field = self::get_prefixed_name( 'preserve_data' );
111
+ register_setting( 'tinify', $field );
 
 
 
 
 
112
 
113
  add_action(
114
  'wp_ajax_tiny_image_sizes_notice',
131
  );
132
  }
133
 
134
+ public function add_options_to_page() {
135
+ include( dirname( __FILE__ ) . '/views/settings.php' );
136
+ }
137
+
138
  public function image_sizes_notice() {
139
  $this->render_image_sizes_notice(
140
  $_GET['image_sizes_selected'],
161
  return intval( get_option( self::get_prefixed_name( 'status' ) ) );
162
  }
163
 
164
+ public function disabled_required_functions() {
165
+ $required_functions = array( 'curl_exec' );
166
+ $disabled_required_functions = array();
167
+ $disabled_functions = explode( ',', ini_get( 'disable_functions' ) );
168
+
169
+ foreach ( $required_functions as $required_function ) {
170
+ if ( in_array( $required_function, $disabled_functions ) ) {
171
+ array_push( $disabled_required_functions, $required_function );
172
+ }
173
+ }
174
+
175
+ return $disabled_required_functions;
176
+ }
177
+
178
  protected function get_api_key() {
179
  if ( defined( 'TINY_API_KEY' ) ) {
180
  return TINY_API_KEY;
268
  return $this->tinify_sizes;
269
  }
270
 
271
+ public function new_plugin_install() {
272
+ /* We merely have to check whether a newly added setting is already stored. */
273
+ $compression_timing = get_option( self::get_prefixed_name( 'compression_timing' ) );
274
+ return ! $compression_timing;
275
+ }
276
+
277
  public function get_resize_enabled() {
278
  /* This only applies if the original is being resized. */
279
  $sizes = $this->get_sizes();
285
  return isset( $setting['enabled'] ) && 'on' === $setting['enabled'];
286
  }
287
 
288
+ public function get_compression_timing() {
289
+ $setting = get_option( self::get_prefixed_name( 'compression_timing' ) );
290
+ if ( isset( $setting ) && $setting ) {
291
+ return $setting;
292
+ } elseif ( $this->new_plugin_install() ) {
293
+ update_option( self::get_prefixed_name( 'compression_timing' ), 'background' );
294
+ return 'background';
295
+ } else {
296
+ update_option( self::get_prefixed_name( 'compression_timing' ), 'auto' );
297
+ return 'auto';
298
+ }
299
+ }
300
+
301
+ public function auto_compress_enabled() {
302
+ return $this->get_compression_timing() === 'auto' ||
303
+ $this->get_compression_timing() === 'background';
304
+ }
305
+
306
+ public function background_compress_enabled() {
307
+ return $this->get_compression_timing() === 'background';
308
+ }
309
+
310
+ public function has_offload_s3_installed() {
311
+ if (
312
+ ! function_exists( 'is_plugin_active' ) ||
313
+ ! is_plugin_active( self::$offload_s3_plugin )
314
+ ) {
315
+ return false;
316
+ }
317
+ $setting = get_option( 'tantan_wordpress_s3' );
318
+ if ( ! is_array( $setting ) ) {
319
+ return false;
320
+ }
321
+
322
+ return true;
323
+ }
324
+
325
+ public function old_offload_s3_version_installed() {
326
+ if (
327
+ function_exists( 'is_plugin_active' ) &&
328
+ is_plugin_active( self::$offload_s3_plugin ) &&
329
+ function_exists( 'get_plugin_data' )
330
+ ) {
331
+ $metadata = get_plugin_data( WP_PLUGIN_DIR . '/' . self::$offload_s3_plugin );
332
+ $offload_s3_version_parts = explode( '.', $metadata['Version'] );
333
+ $major_version = intval( $offload_s3_version_parts[0] );
334
+ $minor_version = intval( $offload_s3_version_parts[1] );
335
+ if ( 0 === $major_version && $minor_version < 7 ) {
336
+ return true;
337
+ }
338
+ }
339
+
340
+ return false;
341
+ }
342
+
343
+ public function remove_local_files_setting_enabled() {
344
+ /* Check if Offload S3 plugin is installed. */
345
+ if (
346
+ ! function_exists( 'is_plugin_active' ) ||
347
+ ! is_plugin_active( self::$offload_s3_plugin )
348
+ ) {
349
+ return false;
350
+ }
351
+ $setting = get_option( 'tantan_wordpress_s3' );
352
+ if ( ! is_array( $setting ) ) {
353
+ return false;
354
+ }
355
+ /* Check if Offload S3 is configured to remove local files. */
356
+ return ( $this->has_offload_s3_installed() &&
357
+ array_key_exists( 'remove-local-file', $setting ) &&
358
+ '1' === $setting['remove-local-file'] );
359
+ }
360
+
361
  public function get_preserve_enabled( $name ) {
362
  $setting = get_option( self::get_prefixed_name( 'preserve_data' ) );
363
  return isset( $setting[ $name ] ) && 'on' === $setting[ $name ];
401
  return sizeof( $options ) >= 2 ? $options : false;
402
  }
403
 
404
+ public function render_notices() {
405
+ $this->render_setup_incomplete_notice();
406
+ $this->render_outdated_platform_notice();
407
+ $this->render_incompatible_plugins_notice();
408
+ $this->render_offload_s3_notices();
409
+ }
410
+
411
+ public function render_setup_incomplete_notice() {
412
+ if ( ! $this->get_api_key() ) {
413
+ $notice_class = 'error';
414
+ $notice = esc_html__(
415
+ 'Please register or provide an API key to start compressing images.',
416
+ 'tiny-compress-images'
417
+ );
418
+ } elseif ( $this->get_api_key_pending() ) {
419
+ $notice_class = 'notice-warning';
420
+ $notice = esc_html__(
421
+ 'Please activate your account to start compressing images.',
422
+ 'tiny-compress-images'
423
+ );
424
+ }
425
+
426
+ if ( isset( $notice ) && $notice ) {
427
+ $link = sprintf(
428
+ '<a href="options-general.php?page=tinify">%s</a>', $notice
429
+ );
430
+ $this->notices->show( 'setting', $link, $notice_class, false );
431
+ }
432
+ }
433
+
434
+ public function render_outdated_platform_notice() {
435
+ if ( ! Tiny_PHP::client_supported() ) {
436
+ if ( ! Tiny_PHP::has_fully_supported_php() ) {
437
+ $details = 'PHP ' . PHP_VERSION;
438
+ if ( Tiny_PHP::curl_available() ) {
439
+ $curlinfo = curl_version();
440
+ $details .= ' ' . sprintf(
441
+ /* translators: %s: curl version */
442
+ esc_html__( 'with curl %s', 'tiny-compress-images' ), $curlinfo['version']
443
+ );
444
+ } else {
445
+ $details .= ' ' . esc_html__( 'without curl', 'tiny-compress-images' );
446
+ }
447
+ if ( Tiny_PHP::curl_exec_disabled() ) {
448
+ $details .= ' ' .
449
+ esc_html__( 'and curl_exec disabled', 'tiny-compress-images' );
450
+ }
451
+ $message = sprintf(
452
+ /* translators: %s: details of outdated platform */
453
+ esc_html__(
454
+ 'You are using an outdated platform (%s).',
455
+ 'tiny-compress-images'
456
+ ), $details
457
+ );
458
+ } elseif ( ! Tiny_PHP::curl_available() ) {
459
+ $message = esc_html__(
460
+ 'We noticed that cURL is not available. For the best experience we recommend to make sure cURL is available.', // WPCS: Needed for proper translation.
461
+ 'tiny-compress-images'
462
+ );
463
+ } elseif ( Tiny_PHP::curl_exec_disabled() ) {
464
+ $message = esc_html__(
465
+ 'We noticed that curl_exec is disabled in your PHP configuration. Please update this setting for the best experience.', // WPCS: Needed for proper translation.
466
+ 'tiny-compress-images'
467
+ );
468
+ }
469
+ $this->notices->show( 'deprecated', $message, 'notice-warning', false );
470
+ } // End if().
471
+ }
472
+
473
+ public function render_incompatible_plugins_notice() {
474
+ $incompatible_plugins = array_filter( self::$incompatible_plugins, 'is_plugin_active' );
475
+ if ( count( $incompatible_plugins ) > 0 ) {
476
+ $this->notices->show_incompatible_plugins( $incompatible_plugins );
477
+ }
478
+ }
479
+
480
+ public function render_settings_link() {
481
+ echo '<div class="tinify-settings"><h3>';
482
+ esc_html_e( 'Compress JPEG & PNG images', 'tiny-compress-images' );
483
+ echo '</h3>';
484
+ $url = admin_url( 'options-general.php?page=tinify' );
485
+ $link = "<a href='" . $url . "'>";
486
+ $link .= esc_html__( 'settings', 'tiny-compress-images' );
487
+ $link .= '</a>';
488
+ printf(
489
+ wp_kses(
490
+ /* translators: %s: link saying settings */
491
+ __( 'The %s have moved.', 'tiny-compress-images' ),
492
+ array(
493
+ 'a' => array(
494
+ 'href' => array(),
495
+ ),
496
+ )
497
+ ),
498
+ $link
499
+ );
500
  echo '</div>';
501
  }
502
 
503
+ public function render_offload_s3_notices() {
504
+ if ( $this->remove_local_files_setting_enabled() &&
505
+ 'background' === $this->get_compression_timing() ) {
506
+ $message = esc_html__(
507
+ 'Removing files from the server is incompatible with background compressions. Images will still be automatically compressed, but no longer in the background.', // WPCS: Needed for proper translation.
508
+ 'tiny-compress-images'
509
+ );
510
+ $this->notices->show( 'offload-s3', $message, 'notice-error', false );
511
+ update_option( self::get_prefixed_name( 'compression_timing' ), 'auto' );
512
+ }
513
+
514
+ if ( $this->old_offload_s3_version_installed() &&
515
+ 'background' === $this->get_compression_timing() ) {
516
+ $message = esc_html__(
517
+ 'Background compressions are not compatible with the version of WP Offload S3 you have installed. Please update to version 0.7.2 at least.', // WPCS: Needed for proper translation.
518
+ 'tiny-compress-images'
519
+ );
520
+ $this->notices->show( 'old-offload-s3-version', $message, 'notice-error', false );
521
+ update_option( self::get_prefixed_name( 'compression_timing' ), 'auto' );
522
+ }
523
  }
524
 
525
+ public function render_compression_timing_settings() {
526
+ $heading = esc_html__(
527
+ 'When should new images be compressed?',
 
528
  'tiny-compress-images'
529
  );
530
+ echo '<h4>' . $heading . '</h4>';
531
+ echo '<div class="optimization-options">';
532
+
533
+ $name = self::get_prefixed_name( 'compression_timing' );
534
+ $compression_timing = $this->get_compression_timing();
535
+
536
+ $id = self::get_prefixed_name( 'background_compress_enabled' );
537
+ $checked = ( 'background' === $compression_timing ? ' checked="checked"' : '' );
538
+
539
+ $label = esc_html__(
540
+ 'Compress new images in the background (Recommended)',
541
+ 'tiny-compress-images'
542
+ );
543
+ $description = esc_html__(
544
+ 'This is the fastest method, but can cause issues with some image related plugins.',
545
+ 'tiny-compress-images'
546
+ );
547
+
548
+ $this->render_compression_timing_radiobutton(
549
+ $name,
550
+ $label,
551
+ $description,
552
+ 'background',
553
+ $checked,
554
+ $this->remove_local_files_setting_enabled() || $this->old_offload_s3_version_installed()
555
+ );
556
+
557
+ $id = self::get_prefixed_name( 'auto_compress_enabled' );
558
+ $checked = ( 'auto' === $compression_timing ? ' checked="checked"' : '' );
559
+
560
+ $label = esc_html__(
561
+ 'Compress new images during upload',
562
+ 'tiny-compress-images'
563
+ );
564
+ $description = esc_html__(
565
+ 'Uploads will take longer, but provides higher compatibility with other plugins.',
566
+ 'tiny-compress-images'
567
+ );
568
+
569
+ $this->render_compression_timing_radiobutton(
570
+ $name,
571
+ $label,
572
+ $description,
573
+ 'auto',
574
+ $checked,
575
+ false
576
+ );
577
+
578
+ $id = self::get_prefixed_name( 'auto_compress_disabled' );
579
+ $checked = ( 'manual' === $compression_timing ? ' checked="checked"' : '' );
580
+
581
+ $label = esc_html__(
582
+ 'Do not compress new images automatically',
583
+ 'tiny-compress-images'
584
+ );
585
+ $description = esc_html__(
586
+ 'Manually select the images you want to compress in the media library.',
587
+ 'tiny-compress-images'
588
+ );
589
+
590
+ $this->render_compression_timing_radiobutton(
591
+ $name,
592
+ $label,
593
+ $description,
594
+ 'manual',
595
+ $checked,
596
+ false
597
+ );
598
+
599
+ echo '</div>';
600
+ }
601
+
602
+ public function render_sizes() {
603
  echo '<input type="hidden" name="' .
604
  self::get_prefixed_name( 'sizes[' . self::DUMMY_SIZE . ']' ) . '" value="on"/>';
605
 
627
  $checked = ( $option['tinify'] ? ' checked="checked"' : '' );
628
  if ( Tiny_Image::is_original( $size ) ) {
629
  $label = esc_html__( 'Original image', 'tiny-compress-images' ) . ' (' .
630
+ esc_html__(
631
+ 'overwritten by compressed image',
632
+ 'tiny-compress-images'
633
+ ) . ')';
634
  } elseif ( Tiny_Image::is_retina( $size ) ) {
635
  $label = esc_html__( 'WP Retina 2x sizes', 'tiny-compress-images' );
636
  } else {
657
  public function render_image_sizes_notice(
658
  $active_sizes_count, $resize_original_enabled, $compress_wr2x ) {
659
  echo '<p>';
660
+ esc_html_e(
661
+ 'Remember each selected size counts as a compression.',
662
+ 'tiny-compress-images'
663
+ );
664
+ echo '</p>';
665
+ echo '<p>';
666
  if ( $resize_original_enabled ) {
667
  $active_sizes_count++;
668
  }
684
  'strong' => array(),
685
  );
686
 
687
+ /* translators: %1$s: number of images */
688
  printf( wp_kses( __(
689
+ 'With these settings you can compress <strong>at least %1$s images</strong> for free each month.', // WPCS: Needed for proper translation.
690
  'tiny-compress-images'
691
+ ), $strong ), $free_images_per_month );
692
 
693
  if ( self::wr2x_active() ) {
694
  echo '</p>';
703
  'tiny-compress-images'
704
  );
705
  }
706
+ } // End if().
707
  echo '</p>';
708
  }
709
 
710
  public function render_resize() {
711
+ $strong = array(
712
+ 'strong' => array(),
713
+ );
714
+
715
  echo '<p class="tiny-resize-unavailable" style="display: none">';
716
  esc_html_e(
717
  'Enable compression of the original image size for more options.',
724
  $checked = ( $this->get_resize_enabled() ? ' checked="checked"' : '' );
725
 
726
  $label = esc_html__(
727
+ 'Resize the original image',
728
  'tiny-compress-images'
729
  );
730
 
731
+ echo '<div class="tiny-resize-available">';
732
  echo '<input type="checkbox" id="' . $id . '" name="' . $name .
733
  '" value="on" ' . $checked . '/>';
734
+ echo '<label for="' . $id . '">' . $label . '</label><br>';
 
 
735
 
736
+ echo '<div class="tiny-resize-available tiny-resize-resolution">';
737
+ echo '<span>';
738
+ echo wp_kses( __( '<strong>Save space</strong> by setting a maximum width and height for all images uploaded.', 'tiny-compress-images' ), $strong ); // WPCS: Needed for proper translation.
739
+ echo '<br>';
740
+ echo wp_kses( __( 'Resizing takes <strong>1 additional compression</strong> for each image that is larger.', 'tiny-compress-images' ), $strong ); // WPCS: Needed for proper translation.
741
+ echo '</span>';
742
+ echo '<div class="tiny-resize-inputs">';
743
+ printf( '%s: ', esc_html__( 'Max Width' ) );
744
  $this->render_resize_input( 'width' );
745
+ printf( '%s: ', esc_html__( 'Max Height' ) );
746
  $this->render_resize_input( 'height' );
747
+ echo '</div></div></div>';
 
 
 
 
 
 
 
 
 
748
 
749
  $this->render_preserve_input(
750
  'creation',
751
  esc_html__(
752
  'Preserve creation date and time in the original image',
753
  'tiny-compress-images'
754
+ )
 
755
  );
756
 
757
  $this->render_preserve_input(
772
  );
773
  }
774
 
775
+ public function render_compression_timing_radiobutton(
776
+ $name,
777
+ $label,
778
+ $desc,
779
+ $value,
780
+ $checked,
781
+ $disabled
782
+ ) {
783
+ if ( $disabled ) {
784
+ echo '<div class="notice notice-warning inline"><p>';
785
+ echo '<strong>' . esc_html__( 'Warning', 'tiny-compress-images' ) . '</strong> — ';
786
+ if ( $this->old_offload_s3_version_installed() ) {
787
+ $message = esc_html_e(
788
+ 'Background compressions are not compatible with the version of WP Offload S3 you have installed. Please update to version 0.7.2 at least.', // WPCS: Needed for proper translation.
789
+ 'tiny-compress-images'
790
+ );
791
+ } elseif ( $this->remove_local_files_setting_enabled() ) {
792
+ $message = esc_html_e(
793
+ 'For background compression to work you will need to configure WP Offload S3 to keep a copy of the images on the server.', // WPCS: Needed for proper translation.
794
+ 'tiny-compress-images'
795
+ );
796
+ }
797
+ echo '</p></div>';
798
+ echo '<p class="tiny-radio disabled">';
799
+ } else {
800
+ echo '<p class="tiny-radio">';
801
+ }
802
+ $id = sprintf( self::get_prefixed_name( 'compression_timing_%s' ), $value );
803
+ $label = esc_html( $label, 'tiny-compress-images' );
804
+ $desc = esc_html( $desc, 'tiny-compress-images' );
805
+ $disabled = ( $disabled ? ' disabled="disabled"' : '' );
806
+ echo '<input type="radio" id="' . $id . '" name="' . $name .
807
+ '" value="' . $value . '" ' . $checked . ' ' . $disabled . '/>';
808
+ echo '<label for="' . $id . '">' . $label . '</label>';
809
+ echo '<br>';
810
+ echo '<span class="description">' . $desc . '</span>';
811
+ echo '<br>';
812
+ echo '</p>';
813
+ }
814
+
815
  public function render_preserve_input( $name, $description ) {
816
  echo '<p class="tiny-preserve">';
817
  $id = sprintf( self::get_prefixed_name( 'preserve_data_%s' ), $name );
839
  return get_option( $field );
840
  }
841
 
842
+ public function limit_reached() {
843
+ $this->compressor->get_compression_count();
844
+ return $this->compressor->limit_reached();
845
+ }
846
+
847
  public function after_compress_callback( $compressor ) {
848
  $count = $compressor->get_compression_count();
849
  if ( ! is_null( $count ) ) {
851
  update_option( $field, $count );
852
  }
853
  if ( $compressor->limit_reached() ) {
854
+ $link = '<a href="https://tinypng.com/dashboard/api" target="_blank">' .
855
  esc_html__( 'TinyPNG API account', 'tiny-compress-images' ) . '</a>';
856
 
857
  $this->notices->add('limit-reached',
858
+ esc_html__(
859
+ 'You have reached your free limit this month.',
860
+ 'tiny-compress-images'
861
+ ) . ' ' .
862
  sprintf(
863
+ /* translators: %s: link saying TinyPNG API account */
 
 
 
 
 
 
864
  esc_html__(
865
  'Upgrade your %s if you like to compress more images.',
866
  'tiny-compress-images'
948
  $compressor->create_key( $_POST['email'], array(
949
  'name' => $_POST['name'],
950
  'identifier' => $identifier,
951
+ 'link' => 'http://localhost',
952
  ) );
953
 
954
  update_option( self::get_prefixed_name( 'api_key_pending' ), true );
src/class-tiny-wp-base.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015-2017 Voormedia B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
1
  <?php
2
  /*
3
  * Tiny Compress Images - WordPress plugin.
4
+ * Copyright (C) 2015-2018 Tinify B.V.
5
  *
6
  * This program is free software; you can redistribute it and/or modify it
7
  * under the terms of the GNU General Public License as published by the Free
src/config/class-tiny-config.php CHANGED
@@ -8,4 +8,5 @@ class Tiny_Config {
8
  /* URL is only used by fopen driver. */
9
  const URL = 'https://api.tinify.com/shrink';
10
  const MONTHLY_FREE_COMPRESSIONS = 500;
 
11
  }
8
  /* URL is only used by fopen driver. */
9
  const URL = 'https://api.tinify.com/shrink';
10
  const MONTHLY_FREE_COMPRESSIONS = 500;
11
+ const META_KEY = 'tiny_compress_images';
12
  }
src/css/admin.css CHANGED
@@ -166,11 +166,89 @@ div.tiny-account-status.wide div.create button.loading, div.tiny-account-status.
166
  }
167
  }
168
 
169
- p.tiny-resize-resolution {
170
- margin-left: 24px;
171
  }
172
 
173
- p.tiny-resize-resolution input {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  margin-right: 6px;
175
  }
176
 
@@ -297,5 +375,5 @@ input[type=number][name*="tinypng_resize_original"] {
297
  }
298
 
299
  .tiny-compress-images h4 {
300
- margin: 0.5em 0;
301
  }
166
  }
167
  }
168
 
169
+ .incompatible-plugins.error h3 {
170
+ margin: 10px 0;
171
  }
172
 
173
+ .incompatible-plugins.error table {
174
+ margin-bottom: 10px;
175
+ }
176
+
177
+ .incompatible-plugins.error table td.bullet {
178
+ width: 20px;
179
+ }
180
+
181
+ .incompatible-plugins.error table td.name {
182
+ padding-right: 100px;
183
+ }
184
+
185
+ table.tinify-settings p.intro {
186
+ color: #777777;
187
+ }
188
+
189
+ table.tinify-settings div.sizes {
190
+ margin: 20px 0;
191
+ }
192
+
193
+ table.tinify-settings input[type="checkbox"], table.tinify-settings input[type="radio"] {
194
+ margin-right: 12px;
195
+ }
196
+
197
+ div.optimization-options {
198
+ margin-top: 20px;
199
+ }
200
+
201
+ p.tiny-radio {
202
+ margin-right: 12px;
203
+ }
204
+
205
+ p.tiny-radio span.description {
206
+ display: inline-block;
207
+ }
208
+
209
+ @media only screen and (max-width: 782px) {
210
+ p.tiny-radio span.description {
211
+ margin-left: 38px;
212
+ }
213
+ }
214
+
215
+ p.tiny-radio.disabled label, p.tiny-radio.disabled span.description {
216
+ opacity: 0.5;
217
+ }
218
+
219
+ p.tiny-radio label {
220
+ font-weight: bold;
221
+ }
222
+
223
+ p.tiny-radio span {
224
+ margin-left: 28px;
225
+ color: #777777;
226
+ line-height: 30px;
227
+ }
228
+
229
+ div.tiny-resize-available {
230
+ margin-top: 10px;
231
+ }
232
+
233
+ div.tiny-resize-resolution {
234
+ margin: 10px 0 20px 28px;
235
+ }
236
+
237
+ @media only screen and (max-width: 782px) {
238
+ div.tiny-resize-resolution {
239
+ margin-left: 38px;
240
+ }
241
+ }
242
+
243
+ div.tiny-resize-resolution span {
244
+ color: #777777;
245
+ }
246
+
247
+ div.tiny-resize-inputs {
248
+ margin-top: 10px;
249
+ }
250
+
251
+ div.tiny-resize-inputs input {
252
  margin-right: 6px;
253
  }
254
 
375
  }
376
 
377
  .tiny-compress-images h4 {
378
+ margin: 5px 0;
379
  }
src/css/bulk-optimization.css CHANGED
@@ -270,19 +270,22 @@ div.tiny-bulk-optimization table.whitebox {
270
  }
271
  }
272
 
273
- div.tiny-bulk-optimization table.whitebox th.column-author {
274
- /* WP 3.1-4.2 */ width: auto;
275
  }
276
 
277
- div.tiny-bulk-optimization table.whitebox thead th.thumbnail {
278
- width: 30px;
 
 
279
  }
280
 
281
- div.tiny-bulk-optimization table.whitebox thead th.savings {
282
- width: 70px;
283
  }
284
 
285
- div.tiny-bulk-optimization table.whitebox thead th.status {
 
286
  }
287
 
288
  div.tiny-bulk-optimization table.whitebox th.thumbnail {
@@ -319,6 +322,11 @@ div.tiny-bulk-optimization table.whitebox tr.failed button.toggle-row:before {
319
  content: "\f158"; /* more compatibility*/
320
  }
321
 
 
 
 
 
 
322
  div.tiny-bulk-optimization table.whitebox tr.failed.is-expanded span.icon {
323
  display: none;
324
  }
270
  }
271
  }
272
 
273
+ div.tiny-bulk-optimization table.whitebox th.column-primary {
274
+ width: 30%;
275
  }
276
 
277
+ @media only screen and (max-width: 782px) {
278
+ div.tiny-bulk-optimization table.whitebox th.column-primary {
279
+ width: 100%;
280
+ }
281
  }
282
 
283
+ div.tiny-bulk-optimization table.whitebox th.column-author {
284
+ /* WP 3.1-4.2 */ width: auto;
285
  }
286
 
287
+ div.tiny-bulk-optimization table.whitebox thead th.thumbnail {
288
+ width: 30px;
289
  }
290
 
291
  div.tiny-bulk-optimization table.whitebox th.thumbnail {
322
  content: "\f158"; /* more compatibility*/
323
  }
324
 
325
+ div.tiny-bulk-optimization table.whitebox tr.no-action button.toggle-row:before {
326
+ color: gray;
327
+ content: "\f158"; /* more compatibility*/
328
+ }
329
+
330
  div.tiny-bulk-optimization table.whitebox tr.failed.is-expanded span.icon {
331
  display: none;
332
  }
src/js/admin.js CHANGED
@@ -1,10 +1,10 @@
1
  (function() {
2
  function compressImage(event) {
3
- var element = jQuery(event.target)
4
- var container = element.closest('div.tiny-ajax-container')
5
- element.attr('disabled', 'disabled')
6
- container.find('span.spinner').removeClass('hidden')
7
- container.find('span.dashicons').remove()
8
  jQuery.ajax({
9
  url: ajaxurl,
10
  type: 'POST',
@@ -14,31 +14,72 @@
14
  id: element.data('id') || element.attr('data-id')
15
  },
16
  success: function(data) {
17
- container.html(data)
18
  },
19
  error: function() {
20
- element.removeAttr('disabled')
21
- container.find('span.spinner').addClass('hidden')
22
  }
23
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
  function submitKey(event) {
27
- event.preventDefault()
28
- jQuery(event.target).attr({disabled: true}).addClass('loading')
29
-
30
- var action
31
- var parent = jQuery(event.target).closest('div')
32
-
33
- if (jQuery(event.target).data('tiny-action') == 'update-key') {
34
- action = 'update'
35
- var key = parent.find('#tinypng_api_key').val()
36
- } else if (jQuery(event.target).data('tiny-action') == 'create-key') {
37
- action = 'create'
38
- var name = parent.find('#tinypng_api_key_name').val()
39
- var email = parent.find('#tinypng_api_key_email').val()
 
 
 
40
  } else {
41
- return false
42
  }
43
 
44
  jQuery.ajax({
@@ -49,40 +90,40 @@
49
  action: 'tiny_settings_' + action + '_api_key',
50
  key: key,
51
  name: name,
52
- email: email,
53
  },
54
-
55
  success: function(json) {
56
- var status = JSON.parse(json)
 
57
  if (status.ok) {
58
- var target = jQuery('#tiny-account-status')
59
  if (target.length) {
60
  jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) {
61
- jQuery(event.target).attr({disabled: false}).removeClass('loading')
62
- target.replaceWith(data)
63
- })
64
  }
 
65
  } else {
66
- jQuery(event.target).attr({disabled: false}).removeClass('loading')
67
- parent.addClass('failure')
68
- parent.find('p.message').text(status.message).show()
69
  }
70
  },
71
-
72
  error: function() {
73
- jQuery(event.target).attr({disabled: false}).removeClass('loading')
74
- parent.addClass('failure')
75
- parent.find('p.message').text('Something went wrong, try again soon').show()
76
  }
77
- })
78
 
79
- return false
80
  }
81
 
82
  function dismissNotice(event) {
83
- var element = jQuery(event.target)
84
- var notice = element.closest('.tiny-notice')
85
- element.attr('disabled', 'disabled')
86
  jQuery.ajax({
87
  url: ajaxurl,
88
  type: 'POST',
@@ -94,57 +135,59 @@
94
  },
95
  success: function(data) {
96
  if (data) {
97
- notice.remove()
98
  }
99
  },
100
  error: function() {
101
- element.removeAttr('disabled')
102
  }
103
- })
104
- return false
105
  }
106
 
107
  function updateResizeSettings() {
108
  if (propOf('#tinypng_sizes_0', 'checked')) {
109
- jQuery('.tiny-resize-available').show()
110
- jQuery('.tiny-resize-unavailable').hide()
111
  } else {
112
- jQuery('.tiny-resize-available').hide()
113
- jQuery('.tiny-resize-unavailable').show()
114
  }
115
 
116
- var original_enabled = propOf('#tinypng_resize_original_enabled', 'checked')
117
  jQuery('#tinypng_resize_original_width, #tinypng_resize_original_height').each(function (i, el) {
118
- el.disabled = !original_enabled
119
- })
120
  }
121
 
122
  function updatePreserveSettings() {
123
  if (propOf('#tinypng_sizes_0', 'checked')) {
124
- jQuery('.tiny-preserve').show()
125
  } else {
126
- jQuery('.tiny-preserve').hide()
127
- jQuery('#tinypng_preserve_data_creation').attr('checked', false)
128
- jQuery('#tinypng_preserve_data_copyright').attr('checked', false)
129
- jQuery('#tinypng_preserve_data_location').attr('checked', false)
130
  }
131
  }
132
 
133
  function updateSettings() {
134
- updateResizeSettings()
135
- updatePreserveSettings()
136
  }
137
 
138
- var adminpage = ''
139
  if (typeof window.adminpage !== 'undefined') {
140
- adminpage = window.adminpage
141
  }
142
 
 
 
143
  function eventOn(event, eventSelector, callback) {
144
  if (typeof jQuery.fn.on === 'function') {
145
- jQuery(document).on(event, eventSelector, callback)
146
  } else {
147
- jQuery(eventSelector).live(event, callback)
148
  }
149
  }
150
 
@@ -152,9 +195,9 @@
152
  if (typeof jQuery.fn.prop === 'function') {
153
  /* Added in 1.6. Before jQuery 1.6, the .attr() method sometimes took
154
  property values into account. */
155
- return jQuery(selector).prop(property)
156
  } else {
157
- return jQuery(selector).attr(property)
158
  }
159
  }
160
 
@@ -162,75 +205,82 @@
162
  if (typeof jQuery.fn.prop === 'function') {
163
  /* Added in 1.6. Before jQuery 1.6, the .attr() method sometimes took
164
  property values into account. */
165
- jQuery(selector).prop(property, value)
166
  } else {
167
- jQuery(selector).attr(property, value)
168
  }
169
  }
170
 
171
  function changeEnterKeyTarget(selector, button) {
172
  eventOn('keyup keypress', selector, function(event) {
173
- var code = event.keyCode || event.which
174
- if (code == 13) {
175
- jQuery(button).click()
176
- return false
177
  }
178
- })
179
  }
180
 
181
  switch (adminpage) {
182
  case 'upload-php':
183
- eventOn('click', 'button.tiny-compress', compressImage)
 
 
184
 
185
- setPropOf('button.tiny-compress', 'disabled', null)
 
186
 
187
- jQuery('<option>').val('tiny_bulk_action').text(tinyCompress.L10nBulkAction).appendTo('select[name=action]')
188
- jQuery('<option>').val('tiny_bulk_action').text(tinyCompress.L10nBulkAction).appendTo('select[name=action2]')
189
- break
190
  case 'post-php':
191
- eventOn('click', 'button.tiny-compress', compressImage)
192
- break
193
  case 'options-media-php':
 
194
  case 'settings_page_media': // Enhanced Media Library plugin
195
- changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]')
196
- changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]')
197
 
198
- eventOn('click', '[data-tiny-action=create-key]', submitKey)
199
- eventOn('click', '[data-tiny-action=update-key]', submitKey)
200
 
201
- var target = jQuery('#tiny-account-status[data-state=pending]')
202
  if (target.length) {
203
  jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) {
204
- target.replaceWith(data)
205
- })
206
  }
207
 
208
  eventOn('click', 'input[name*=tinypng_sizes], #tinypng_resize_original_enabled', function() {
209
  /* Unfortunately, we need some additional information to display
210
  the correct notice. */
211
- totalSelectedSizes = jQuery('input[name*=tinypng_sizes]:checked').length
212
- compressWr2x = propOf('#tinypng_sizes_wr2x', 'checked')
213
  if (compressWr2x) {
214
  totalSelectedSizes--;
215
  }
216
 
217
- var image_count_url = ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_image_sizes_notice&image_sizes_selected=' + totalSelectedSizes
218
  if (propOf('#tinypng_resize_original_enabled', 'checked') && propOf('#tinypng_sizes_0', 'checked')) {
219
- image_count_url += '&resize_original=true'
220
  }
221
  if (compressWr2x) {
222
- image_count_url += '&compress_wr2x=true'
223
  }
224
- jQuery('#tiny-image-sizes-notice').load(image_count_url)
225
- })
226
 
227
- jQuery('#tinypng_sizes_0, #tinypng_resize_original_enabled').click(updateSettings)
228
- updateSettings()
 
229
 
 
 
230
  }
231
 
232
- jQuery('.tiny-notice a.tiny-dismiss').click(dismissNotice)
233
  jQuery(function() {
234
- jQuery('.tiny-notice.is-dismissible button').unbind('click').click(dismissNotice)
235
- })
236
- }).call()
1
  (function() {
2
  function compressImage(event) {
3
+ var element = jQuery(event.target);
4
+ var container = element.closest('div.tiny-ajax-container');
5
+ element.attr('disabled', 'disabled');
6
+ container.find('span.spinner').removeClass('hidden');
7
+ container.find('span.dashicons').remove();
8
  jQuery.ajax({
9
  url: ajaxurl,
10
  type: 'POST',
14
  id: element.data('id') || element.attr('data-id')
15
  },
16
  success: function(data) {
17
+ container.html(data);
18
  },
19
  error: function() {
20
+ element.removeAttr('disabled');
21
+ container.find('span.spinner').addClass('hidden');
22
  }
23
+ });
24
+ }
25
+
26
+ function compressImageSelection() {
27
+ jQuery('span.auto-compress').each(function(index, element) {
28
+ jQuery(element).siblings('button').click()
29
+ });
30
+ }
31
+
32
+ function watchCompressingImages() {
33
+ if (jQuery('.details-container[data-status="compressing"]').length > 0) {
34
+ statusCheckIntervalId = setInterval(checkCompressingImages, 5000);
35
+ }
36
+ }
37
+
38
+ function checkCompressingImages() {
39
+ jQuery('.details-container[data-status="compressing"]').each(function(index, element) {
40
+ element = jQuery(element);
41
+ var container = element.closest('div.tiny-ajax-container');
42
+ jQuery.ajax({
43
+ url: ajaxurl,
44
+ type: 'POST',
45
+ data: {
46
+ _nonce: tinyCompress.nonce,
47
+ action: 'tiny_get_compression_status',
48
+ id: element.attr('data-id')
49
+ },
50
+ success: function(data) {
51
+ container.html(data);
52
+ if (jQuery('.details-container[data-status="compressing"]').length === 0) {
53
+ clearInterval(statusCheckIntervalId);
54
+ }
55
+ },
56
+ error: function() {
57
+ element.removeAttr('disabled');
58
+ container.find('span.spinner').addClass('hidden');
59
+ }
60
+ });
61
+ });
62
  }
63
 
64
  function submitKey(event) {
65
+ event.preventDefault();
66
+ jQuery(event.target).attr({disabled: true}).addClass('loading');
67
+
68
+ var action;
69
+ var parent = jQuery(event.target).closest('div');
70
+ var key;
71
+ var email;
72
+ var name;
73
+
74
+ if (jQuery(event.target).data('tiny-action') === 'update-key') {
75
+ action = 'update';
76
+ key = parent.find('#tinypng_api_key').val();
77
+ } else if (jQuery(event.target).data('tiny-action') === 'create-key') {
78
+ action = 'create';
79
+ name = parent.find('#tinypng_api_key_name').val();
80
+ email = parent.find('#tinypng_api_key_email').val();
81
  } else {
82
+ return false;
83
  }
84
 
85
  jQuery.ajax({
90
  action: 'tiny_settings_' + action + '_api_key',
91
  key: key,
92
  name: name,
93
+ email: email
94
  },
 
95
  success: function(json) {
96
+ var status = jQuery.parseJSON(json);
97
+
98
  if (status.ok) {
99
+ var target = jQuery('#tiny-account-status');
100
  if (target.length) {
101
  jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) {
102
+ jQuery(event.target).attr({disabled: false}).removeClass('loading');
103
+ target.replaceWith(data);
104
+ });
105
  }
106
+ jQuery('div.tiny-notice[data-name="setting"]').remove();
107
  } else {
108
+ jQuery(event.target).attr({disabled: false}).removeClass('loading');
109
+ parent.addClass('failure');
110
+ parent.find('p.message').text(status.message).show();
111
  }
112
  },
 
113
  error: function() {
114
+ jQuery(event.target).attr({disabled: false}).removeClass('loading');
115
+ parent.addClass('failure');
116
+ parent.find('p.message').text('Something went wrong, try again soon').show();
117
  }
118
+ });
119
 
120
+ return false;
121
  }
122
 
123
  function dismissNotice(event) {
124
+ var element = jQuery(event.target);
125
+ var notice = element.closest('.tiny-notice');
126
+ element.attr('disabled', 'disabled');
127
  jQuery.ajax({
128
  url: ajaxurl,
129
  type: 'POST',
135
  },
136
  success: function(data) {
137
  if (data) {
138
+ notice.remove();
139
  }
140
  },
141
  error: function() {
142
+ element.removeAttr('disabled');
143
  }
144
+ });
145
+ return false;
146
  }
147
 
148
  function updateResizeSettings() {
149
  if (propOf('#tinypng_sizes_0', 'checked')) {
150
+ jQuery('.tiny-resize-available').show();
151
+ jQuery('.tiny-resize-unavailable').hide();
152
  } else {
153
+ jQuery('.tiny-resize-available').hide();
154
+ jQuery('.tiny-resize-unavailable').show();
155
  }
156
 
157
+ var original_enabled = propOf('#tinypng_resize_original_enabled', 'checked');
158
  jQuery('#tinypng_resize_original_width, #tinypng_resize_original_height').each(function (i, el) {
159
+ el.disabled = !original_enabled;
160
+ });
161
  }
162
 
163
  function updatePreserveSettings() {
164
  if (propOf('#tinypng_sizes_0', 'checked')) {
165
+ jQuery('.tiny-preserve').show();
166
  } else {
167
+ jQuery('.tiny-preserve').hide();
168
+ jQuery('#tinypng_preserve_data_creation').attr('checked', false);
169
+ jQuery('#tinypng_preserve_data_copyright').attr('checked', false);
170
+ jQuery('#tinypng_preserve_data_location').attr('checked', false);
171
  }
172
  }
173
 
174
  function updateSettings() {
175
+ updateResizeSettings();
176
+ updatePreserveSettings();
177
  }
178
 
179
+ var adminpage = '';
180
  if (typeof window.adminpage !== 'undefined') {
181
+ adminpage = window.adminpage;
182
  }
183
 
184
+ var statusCheckIntervalId;
185
+
186
  function eventOn(event, eventSelector, callback) {
187
  if (typeof jQuery.fn.on === 'function') {
188
+ jQuery(document).on(event, eventSelector, callback);
189
  } else {
190
+ jQuery(eventSelector).live(event, callback);
191
  }
192
  }
193
 
195
  if (typeof jQuery.fn.prop === 'function') {
196
  /* Added in 1.6. Before jQuery 1.6, the .attr() method sometimes took
197
  property values into account. */
198
+ return jQuery(selector).prop(property);
199
  } else {
200
+ return jQuery(selector).attr(property);
201
  }
202
  }
203
 
205
  if (typeof jQuery.fn.prop === 'function') {
206
  /* Added in 1.6. Before jQuery 1.6, the .attr() method sometimes took
207
  property values into account. */
208
+ jQuery(selector).prop(property, value);
209
  } else {
210
+ jQuery(selector).attr(property, value);
211
  }
212
  }
213
 
214
  function changeEnterKeyTarget(selector, button) {
215
  eventOn('keyup keypress', selector, function(event) {
216
+ var code = event.keyCode || event.which;
217
+ if (code === 13) {
218
+ jQuery(button).click();
219
+ return false;
220
  }
221
+ });
222
  }
223
 
224
  switch (adminpage) {
225
  case 'upload-php':
226
+ eventOn('click', 'button.tiny-compress', compressImage);
227
+
228
+ setPropOf('button.tiny-compress', 'disabled', null);
229
 
230
+ compressImageSelection();
231
+ watchCompressingImages();
232
 
233
+ jQuery('<option>').val('tiny_bulk_action').text(tinyCompress.L10nBulkAction).appendTo('select[name=action]');
234
+ jQuery('<option>').val('tiny_bulk_action').text(tinyCompress.L10nBulkAction).appendTo('select[name=action2]');
235
+ break;
236
  case 'post-php':
237
+ eventOn('click', 'button.tiny-compress', compressImage);
238
+ break;
239
  case 'options-media-php':
240
+ case 'settings_page_tinify':
241
  case 'settings_page_media': // Enhanced Media Library plugin
242
+ changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]');
243
+ changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]');
244
 
245
+ eventOn('click', '[data-tiny-action=create-key]', submitKey);
246
+ eventOn('click', '[data-tiny-action=update-key]', submitKey);
247
 
248
+ var target = jQuery('#tiny-account-status[data-state=pending]');
249
  if (target.length) {
250
  jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) {
251
+ target.replaceWith(data);
252
+ });
253
  }
254
 
255
  eventOn('click', 'input[name*=tinypng_sizes], #tinypng_resize_original_enabled', function() {
256
  /* Unfortunately, we need some additional information to display
257
  the correct notice. */
258
+ var totalSelectedSizes = jQuery('input[name*=tinypng_sizes]:checked').length;
259
+ var compressWr2x = propOf('#tinypng_sizes_wr2x', 'checked');
260
  if (compressWr2x) {
261
  totalSelectedSizes--;
262
  }
263
 
264
+ var image_count_url = ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_image_sizes_notice&image_sizes_selected=' + totalSelectedSizes;
265
  if (propOf('#tinypng_resize_original_enabled', 'checked') && propOf('#tinypng_sizes_0', 'checked')) {
266
+ image_count_url += '&resize_original=true';
267
  }
268
  if (compressWr2x) {
269
+ image_count_url += '&compress_wr2x=true';
270
  }
271
+ jQuery('#tiny-image-sizes-notice').load(image_count_url);
272
+ });
273
 
274
+ eventOn('click', '#tinypng_auto_compress_enabled', function() {
275
+ updateSettings();
276
+ });
277
 
278
+ jQuery('#tinypng_sizes_0, #tinypng_resize_original_enabled').click(updateSettings);
279
+ updateSettings();
280
  }
281
 
282
+ jQuery('.tiny-notice a.tiny-dismiss').click(dismissNotice);
283
  jQuery(function() {
284
+ jQuery('.tiny-notice.is-dismissible button').unbind('click').click(dismissNotice);
285
+ });
286
+ }).call();
src/js/bulk-optimization.js CHANGED
@@ -1,53 +1,55 @@
1
  (function() {
 
 
2
  function updateProgressBar(successFullCompressions) {
3
- var totalToOptimize = parseInt(jQuery("div#compression-progress-bar").data("number-to-optimize"))
4
 
5
- var optimizedSoFar = parseInt(jQuery("#optimized-so-far").text())
6
- jQuery("#optimized-so-far").html(successFullCompressions + optimizedSoFar)
7
 
8
- var percentage = "100%"
9
  if (totalToOptimize > 0) {
10
- percentage = Math.round((successFullCompressions + optimizedSoFar) / totalToOptimize * 100, 1) + "%"
11
  }
12
- jQuery("div#compression-progress-bar #progress-size").css("width", percentage)
13
- jQuery("div#compression-progress-bar #percentage").html("(" + percentage + ")")
14
 
15
- var numberToOptimize = parseInt(jQuery("#optimizable-image-sizes").html())
16
- jQuery("#optimizable-image-sizes").html(numberToOptimize - successFullCompressions)
17
  }
18
 
19
  function updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize) {
20
-
21
- window.currentLibraryBytes = window.currentLibraryBytes + successFullSaved
22
-
23
- var imagesSizedOptimized = parseInt(jQuery("#optimized-image-sizes").text()) + successFullCompressions
24
- var initialLibraryBytes = parseInt(jQuery("#unoptimized-library-size").data("bytes"))
25
- var percentage = (1 - window.currentLibraryBytes / initialLibraryBytes)
26
- var chartSize = jQuery("div#optimization-chart").data("full-circle-size")
27
-
28
- jQuery("#optimized-image-sizes").html(imagesSizedOptimized)
29
- jQuery("#optimized-library-size").attr("data-bytes", window.currentLibraryBytes)
30
- jQuery("#optimized-library-size").html(newHumanReadableLibrarySize)
31
- jQuery("#savings-percentage").html(Math.round(percentage * 1000) / 10 + "%")
32
- jQuery("div#optimization-chart svg circle.main").css("stroke-dasharray", "" + (chartSize * percentage) + " " + chartSize)
33
-
34
  }
35
 
36
  function handleCancellation() {
37
- jQuery("div#bulk-optimization-actions").hide()
38
- jQuery("div.progress").css("animation", "none")
39
  }
40
 
41
  function updateRowAfterCompression(row, data) {
42
- var successFullCompressions = parseInt(data.success)
43
- var successFullSaved = parseInt(data.size_change)
44
- var newHumanReadableLibrarySize = data.human_readable_library_size
45
- if (successFullCompressions == 0) {
46
- row.find(".status").html(tinyCompress.L10nNoActionTaken)
 
47
  } else {
48
- row.find(".status").html(successFullCompressions + " " + tinyCompress.L10nCompressed)
 
49
  updateProgressBar(successFullCompressions);
50
- updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize)
51
  }
52
  }
53
 
@@ -56,66 +58,74 @@
56
  handleCancellation();
57
  }
58
 
59
- var row = jQuery("#optimization-items tr").eq(parseInt(i)+1)
60
 
61
  if (error) {
62
- row.addClass("failed")
63
- row.find(".status").html(tinyCompress.L10nInternalError + "<br>" + error.toString())
64
- row.find(".status").attr("title", error.toString())
65
- data = {}
 
66
  } else if (data == null) {
67
- row.addClass("failed")
68
- row.find(".status").html(tinyCompress.L10nError)
69
- data = {}
 
70
  } else if (data.error) {
71
- row.addClass("failed")
72
- row.find(".status").html(tinyCompress.L10nError + "<br>" + data.error)
73
- row.find(".status").attr("title", data.error)
 
74
  } else if (data.failed > 0) {
75
- row.addClass("failed")
76
- row.find(".status").html("<span class=\"icon dashicons dashicons-no error\"></span><span class=\"message\">" + tinyCompress.L10nLatestError + ": " + data.message + "</span>");
77
- row.find(".status").attr("title", data.message)
 
78
  } else {
79
- row.addClass("success")
80
- updateRowAfterCompression(row, data)
81
  }
82
 
83
- row.find(".name").html(items[i].post_title + "<button class=\"toggle-row\" type=\"button\"><span class=\"screen-reader-text\">" + tinyCompress.L10nShowMoreDetails + "</span></button>")
84
 
85
  if (!data.image_sizes_optimized) {
86
- data.image_sizes_optimized = "-";
87
  }
88
  if (!data.initial_total_size) {
89
- data.initial_total_size = "-";
90
  }
91
  if (!data.optimized_total_size) {
92
- data.optimized_total_size = "-";
93
  }
94
- if (!data.savings || data.savings == 0) {
95
- data.savings = "-";
96
  } else {
97
- data.savings += "%";
98
  }
99
 
100
- row.find(".thumbnail").html(data.thumbnail)
101
- row.find(".sizes-optimized").html(data.image_sizes_optimized)
102
- row.find(".initial-size").html(data.initial_total_size)
103
- row.find(".optimized-size").html(data.optimized_total_size)
104
- row.find(".savings").html(data.savings)
 
 
 
105
 
106
- if (items[++i]) {
 
 
 
107
  if (!window.optimizationCancelled) {
108
  drawSomeRows(items, 1);
109
  }
110
- bulkOptimizeItem(items, i)
111
- } else {
112
- var message = jQuery("<div class=\"updated\"><p></p></div>")
113
- message.find("p").html(tinyCompress.L10nAllDone)
114
- message.insertAfter(jQuery("#tiny-bulk-optimization h1"))
115
- jQuery("div#optimization-spinner").css("display", "none")
116
- jQuery("div.progress").css("width", "100%")
117
- jQuery("div#bulk-optimization-actions").hide()
118
- jQuery("div.progress").css("animation", "none")
119
  }
120
  }
121
 
@@ -124,119 +134,122 @@
124
  return;
125
  }
126
 
127
- var item = items[i]
128
- var row = jQuery("#optimization-items tr").eq(parseInt(i)+1)
129
- row.find(".status").removeClass("todo")
130
- row.find(".status").html(tinyCompress.L10nCompressing)
131
  jQuery.ajax({
132
  url: ajaxurl,
133
- type: "POST",
134
- dataType: "json",
135
  data: {
136
  _nonce: tinyCompress.nonce,
137
- action: "tiny_compress_image_for_bulk",
138
  id: items[i].ID,
139
  current_size: window.currentLibraryBytes
140
  },
141
- success: function(data) { bulkOptimizationCallback(null, data, items, i)},
142
- error: function(xhr, textStatus, errorThrown) { bulkOptimizationCallback(errorThrown, null, items, i) }
143
- })
144
- jQuery("#tiny-progress span").html(i + 1)
145
  }
146
 
147
  function prepareBulkOptimization(items) {
148
- window.allBulkOptimizationItems = items
149
- updateProgressBar(0)
150
  }
151
 
152
  function startBulkOptimization(items) {
153
- window.optimizationCancelled = false
154
- window.totalRowsDrawn = 0
155
- window.currentLibraryBytes = parseInt(jQuery("#optimized-library-size").data("bytes"))
156
-
157
- jQuery("div.progress").css("animation", "progress-bar 80s linear infinite")
158
- jQuery("div#optimization-spinner").css("display", "inline-block")
159
- updateProgressBar(0)
160
- drawSomeRows(items, 10)
161
- bulkOptimizeItem(items, 0)
 
 
 
 
 
162
  }
163
 
164
  function drawSomeRows(items, rowsToDraw) {
165
- var list = jQuery("#optimization-items tbody")
166
- var row
167
  for (var drawNow = window.totalRowsDrawn; drawNow < Math.min( rowsToDraw + window.totalRowsDrawn, items.length); drawNow++) {
168
- row = jQuery("<tr class=\"media-item\">" +
169
- "<th class=\"thumbnail\" />" +
170
- "<td class=\"column-primary name\" />" +
171
- "<td class=\"column-author sizes-optimized\" data-colname=\"" + tinyCompress.L10nSizesOptimized + "\" ></>" +
172
- "<td class=\"column-author initial-size\" data-colname=\"" + tinyCompress.L10nInitialSize + "\" ></>" +
173
- "<td class=\"column-author optimized-size\" data-colname=\"" + tinyCompress.L10nCurrentSize + "\" ></>" +
174
- "<td class=\"column-author savings\" data-colname=\"" + tinyCompress.L10nSavings + "\" ></>" +
175
- "<td class=\"status todo\" data-colname=\"" + tinyCompress.L10nStatus + "\" />" +
176
- "</tr>")
177
- row.find(".status").html(tinyCompress.L10nWaiting)
178
- row.find(".name").html(items[drawNow].post_title)
179
- list.append(row)
180
- }
181
- window.totalRowsDrawn = drawNow
182
  }
183
 
184
  function cancelOptimization() {
185
  window.optimizationCancelled = true;
186
- jQuery("div#optimization-spinner").css("display", "none");
187
- jQuery(jQuery("#optimization-items tr td.status.todo")).html(tinyCompress.L10nCancelled)
188
- jQuery("div#bulk-optimization-actions input").removeClass("visible")
189
- jQuery("div#bulk-optimization-actions input#id-cancelling").addClass("visible")
190
  }
191
 
192
- jQuery("div#bulk-optimization-actions input").click(function() {
193
- if ((jQuery(this).attr("id") == "id-start") && jQuery(this).hasClass("visible")) {
194
- jQuery("div#bulk-optimization-actions input#id-start").removeClass("visible")
195
- jQuery("div#bulk-optimization-actions input#id-optimizing").addClass("visible")
196
  startBulkOptimization(window.allBulkOptimizationItems);
197
  }
198
- if ((jQuery(this).attr("id") == "id-cancel") && jQuery(this).hasClass("visible")) {
199
  cancelOptimization();
200
  }
201
  });
202
 
203
- jQuery("div#bulk-optimization-actions input").hover(function() {
204
- if ((jQuery(this).attr("id") == "id-optimizing") && jQuery(this).hasClass("visible")) {
205
- window.lastActiveButton = jQuery("div#bulk-optimization-actions input.visible")
206
- lastActiveButton.removeClass("visible")
207
- jQuery("div#bulk-optimization-actions input#id-cancel").addClass("visible")
208
  }
209
  }, function() {
210
- if ((jQuery(this).attr("id") == "id-cancel") && jQuery(this).hasClass("visible")) {
211
- window.lastActiveButton.addClass("visible")
212
- jQuery("div#bulk-optimization-actions input#id-cancel").removeClass("visible")
213
  }
214
  });
215
 
216
  function attachToolTipEventHandlers() {
217
- var tooltip = '#tiny-bulk-optimization div.tooltip'
218
- var tip = 'div.tip'
219
- var toolTipTimeout = null
220
  jQuery(tooltip).mouseleave(function(){
221
- var that = this
222
  toolTipTimeout = setTimeout(function() {
223
  if (jQuery(that).find(tip).is(':visible')) {
224
- jQuery(tooltip).find(tip).hide()
225
  }
226
- }, 100)
227
- })
228
  jQuery(tooltip).mouseenter(function(){
229
- jQuery(this).find(tip).show()
230
- clearTimeout(toolTipTimeout)
231
- })
232
  jQuery(tooltip).find(tip).mouseenter(function(){
233
- clearTimeout(toolTipTimeout)
234
- })
235
  }
236
 
237
- attachToolTipEventHandlers()
238
 
239
- window.bulkOptimizationAutorun = startBulkOptimization
240
- window.bulkOptimization = prepareBulkOptimization
241
 
242
- }).call()
1
  (function() {
2
+ var parallelCompressions = 5;
3
+
4
  function updateProgressBar(successFullCompressions) {
5
+ var totalToOptimize = parseInt(jQuery('div#compression-progress-bar').data('number-to-optimize'), 10);
6
 
7
+ var optimizedSoFar = parseInt(jQuery('#optimized-so-far').text(), 10);
8
+ jQuery('#optimized-so-far').html(successFullCompressions + optimizedSoFar);
9
 
10
+ var percentage = '100%';
11
  if (totalToOptimize > 0) {
12
+ percentage = Math.round((successFullCompressions + optimizedSoFar) / totalToOptimize * 100, 1) + '%';
13
  }
14
+ jQuery('div#compression-progress-bar #progress-size').css('width', percentage);
15
+ jQuery('div#compression-progress-bar #percentage').html('(' + percentage + ')');
16
 
17
+ var numberToOptimize = parseInt(jQuery('#optimizable-image-sizes').html(), 10);
18
+ jQuery('#optimizable-image-sizes').html(numberToOptimize - successFullCompressions);
19
  }
20
 
21
  function updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize) {
22
+ window.currentLibraryBytes = window.currentLibraryBytes + successFullSaved;
23
+
24
+ var imagesSizedOptimized = parseInt(jQuery('#optimized-image-sizes').text(), 10) + successFullCompressions;
25
+ var initialLibraryBytes = parseInt(jQuery('#unoptimized-library-size').data('bytes'), 10);
26
+ var percentage = (1 - window.currentLibraryBytes / initialLibraryBytes);
27
+ var chartSize = jQuery('div#optimization-chart').data('full-circle-size');
28
+
29
+ jQuery('#optimized-image-sizes').html(imagesSizedOptimized);
30
+ jQuery('#optimized-library-size').attr('data-bytes', window.currentLibraryBytes);
31
+ jQuery('#optimized-library-size').html(newHumanReadableLibrarySize);
32
+ jQuery('#savings-percentage').html(Math.round(percentage * 1000) / 10 + '%');
33
+ jQuery('div#optimization-chart svg circle.main').css('stroke-dasharray', '' + (chartSize * percentage) + ' ' + chartSize);
 
 
34
  }
35
 
36
  function handleCancellation() {
37
+ jQuery('div#bulk-optimization-actions').hide();
38
+ jQuery('div.progress').css('animation', 'none');
39
  }
40
 
41
  function updateRowAfterCompression(row, data) {
42
+ var successFullCompressions = parseInt(data.success, 10);
43
+ var successFullSaved = parseInt(data.size_change, 10);
44
+ var newHumanReadableLibrarySize = data.human_readable_library_size;
45
+ if (successFullCompressions === 0) {
46
+ row.addClass('no-action');
47
+ row.find('.status').html('<span class="icon dashicons dashicons-no alert"></span>' + tinyCompress.L10nNoActionTaken).attr('data-status', 'no-action-taken');
48
  } else {
49
+ row.addClass('success');
50
+ row.find('.status').html('<span class="icon dashicons dashicons-yes success"></span>' + successFullCompressions + ' ' + tinyCompress.L10nCompressed).attr('data-status', 'compressed');
51
  updateProgressBar(successFullCompressions);
52
+ updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize);
53
  }
54
  }
55
 
58
  handleCancellation();
59
  }
60
 
61
+ var row = jQuery('#optimization-items tr').eq(parseInt(i, 10)+1);
62
 
63
  if (error) {
64
+ row.addClass('failed');
65
+ row.find('.status').html(tinyCompress.L10nInternalError + '<br>' + error.toString());
66
+ row.find('.status').attr('title', error.toString());
67
+ row.find('.status').attr('data-status', 'error');
68
+ data = {};
69
  } else if (data == null) {
70
+ row.addClass('failed');
71
+ row.find('.status').html(tinyCompress.L10nError);
72
+ row.find('.status').attr('data-status', 'error');
73
+ data = {};
74
  } else if (data.error) {
75
+ row.addClass('failed');
76
+ row.find('.status').html(tinyCompress.L10nError + '<br>' + data.error);
77
+ row.find('.status').attr('title', data.error);
78
+ row.find('.status').attr('data-status', 'error');
79
  } else if (data.failed > 0) {
80
+ row.addClass('failed');
81
+ row.find('.status').html('<span class=\'icon dashicons dashicons-no error\'></span><span class=\'message\'>' + tinyCompress.L10nLatestError + ': ' + data.message + '</span>');
82
+ row.find('.status').attr('title', data.message);
83
+ row.find('.status').attr('data-status', 'error');
84
  } else {
85
+ updateRowAfterCompression(row, data);
 
86
  }
87
 
88
+ row.find('.name').html(items[i].post_title + '<button class=\'toggle-row\' type=\'button\'><span class=\'screen-reader-text\'>' + tinyCompress.L10nShowMoreDetails + '</span></button>');
89
 
90
  if (!data.image_sizes_optimized) {
91
+ data.image_sizes_optimized = '-';
92
  }
93
  if (!data.initial_total_size) {
94
+ data.initial_total_size = '-';
95
  }
96
  if (!data.optimized_total_size) {
97
+ data.optimized_total_size = '-';
98
  }
99
+ if (!data.savings || data.savings === 0) {
100
+ data.savings = '-';
101
  } else {
102
+ data.savings += '%';
103
  }
104
 
105
+ row.find('.thumbnail').html(data.thumbnail);
106
+ row.find('.sizes-optimized').html(data.image_sizes_optimized);
107
+ row.find('.initial-size').html(data.initial_total_size);
108
+ row.find('.optimized-size').html(data.optimized_total_size);
109
+ row.find('.savings').html(data.savings);
110
+
111
+ var totalToOptimize = jQuery('td.status[data-status="waiting"],td.status[data-status="compressing"]').length;
112
+ var nextImage;
113
 
114
+ if (jQuery('td.status[data-status="waiting"]').length > 0) {
115
+ nextImage = jQuery('tr.media-item').index(jQuery('td.status[data-status="waiting"]:first').parents('tr'));
116
+ }
117
+ if (nextImage !== undefined && items[nextImage]) {
118
  if (!window.optimizationCancelled) {
119
  drawSomeRows(items, 1);
120
  }
121
+ bulkOptimizeItem(items, nextImage);
122
+ } else if (totalToOptimize === 0) {
123
+ var message = jQuery('<div class=\'updated\'><p></p></div>');
124
+ message.find('p').html(tinyCompress.L10nAllDone);
125
+ message.insertAfter(jQuery('#tiny-bulk-optimization h1'));
126
+ jQuery('div#optimization-spinner').css('display', 'none');
127
+ jQuery('div#bulk-optimization-actions').hide();
128
+ jQuery('div.progress').css('animation', 'none');
 
129
  }
130
  }
131
 
134
  return;
135
  }
136
 
137
+ var row = jQuery('#optimization-items tr').eq(parseInt(i, 10)+1);
138
+ row.find('.status').removeClass('todo');
139
+ row.find('.status').html('<span class="icon spinner"></span>' + tinyCompress.L10nCompressing).attr('data-status', 'compressing');
 
140
  jQuery.ajax({
141
  url: ajaxurl,
142
+ type: 'POST',
143
+ dataType: 'json',
144
  data: {
145
  _nonce: tinyCompress.nonce,
146
+ action: 'tiny_compress_image_for_bulk',
147
  id: items[i].ID,
148
  current_size: window.currentLibraryBytes
149
  },
150
+ success: function(data) { bulkOptimizationCallback(null, data, items, i); },
151
+ error: function(xhr, textStatus, errorThrown) { bulkOptimizationCallback(errorThrown, null, items, i, parallelCompressions); }
152
+ });
153
+ jQuery('#tiny-progress span').html(i + 1);
154
  }
155
 
156
  function prepareBulkOptimization(items) {
157
+ window.allBulkOptimizationItems = items;
158
+ updateProgressBar(0);
159
  }
160
 
161
  function startBulkOptimization(items) {
162
+ window.optimizationCancelled = false;
163
+ window.totalRowsDrawn = 0;
164
+ window.currentLibraryBytes = parseInt(jQuery('#optimized-library-size').data('bytes'), 10);
165
+
166
+ jQuery('div.progress').css('animation', 'progress-bar 80s linear infinite');
167
+ jQuery('div#optimization-spinner').css('display', 'inline-block');
168
+ updateProgressBar(0);
169
+ drawSomeRows(items, 5 + parallelCompressions);
170
+
171
+ for (var i = 0; i < parallelCompressions; i++) {
172
+ if (items.length >= i+1) {
173
+ bulkOptimizeItem(items, i);
174
+ }
175
+ }
176
  }
177
 
178
  function drawSomeRows(items, rowsToDraw) {
179
+ var list = jQuery('#optimization-items tbody');
180
+ var row;
181
  for (var drawNow = window.totalRowsDrawn; drawNow < Math.min( rowsToDraw + window.totalRowsDrawn, items.length); drawNow++) {
182
+ row = jQuery('<tr class=\'media-item\'>' +
183
+ '<th class=\'thumbnail\' />' +
184
+ '<td class=\'column-primary name\' />' +
185
+ '<td class=\'column-author initial-size\' data-colname=\'' + tinyCompress.L10nInitialSize + '\' ></>' +
186
+ '<td class=\'column-author optimized-size\' data-colname=\'' + tinyCompress.L10nCurrentSize + '\' ></>' +
187
+ '<td class=\'column-author savings\' data-colname=\'' + tinyCompress.L10nSavings + '\' ></>' +
188
+ '<td class=\'column-author status todo\' data-colname=\'' + tinyCompress.L10nStatus + '\' />' +
189
+ '</tr>');
190
+ row.find('.status').html(tinyCompress.L10nWaiting).attr('data-status', 'waiting');
191
+ row.find('.name').html(items[drawNow].post_title);
192
+ list.append(row);
193
+ }
194
+ window.totalRowsDrawn = drawNow;
 
195
  }
196
 
197
  function cancelOptimization() {
198
  window.optimizationCancelled = true;
199
+ jQuery('div#optimization-spinner').css('display', 'none');
200
+ jQuery(jQuery('#optimization-items tr td.status.todo')).html(tinyCompress.L10nCancelled).attr('data-status', 'cancelled');
201
+ jQuery('div#bulk-optimization-actions input').removeClass('visible');
202
+ jQuery('div#bulk-optimization-actions input#id-cancelling').addClass('visible');
203
  }
204
 
205
+ jQuery('div#bulk-optimization-actions input').click(function() {
206
+ if ((jQuery(this).attr('id') === 'id-start') && jQuery(this).hasClass('visible')) {
207
+ jQuery('div#bulk-optimization-actions input#id-start').removeClass('visible');
208
+ jQuery('div#bulk-optimization-actions input#id-optimizing').addClass('visible');
209
  startBulkOptimization(window.allBulkOptimizationItems);
210
  }
211
+ if ((jQuery(this).attr('id') === 'id-cancel') && jQuery(this).hasClass('visible')) {
212
  cancelOptimization();
213
  }
214
  });
215
 
216
+ jQuery('div#bulk-optimization-actions input').hover(function() {
217
+ if ((jQuery(this).attr('id') === 'id-optimizing') && jQuery(this).hasClass('visible')) {
218
+ window.lastActiveButton = jQuery('div#bulk-optimization-actions input.visible');
219
+ window.lastActiveButton.removeClass('visible');
220
+ jQuery('div#bulk-optimization-actions input#id-cancel').addClass('visible');
221
  }
222
  }, function() {
223
+ if ((jQuery(this).attr('id') === 'id-cancel') && jQuery(this).hasClass('visible')) {
224
+ window.lastActiveButton.addClass('visible');
225
+ jQuery('div#bulk-optimization-actions input#id-cancel').removeClass('visible');
226
  }
227
  });
228
 
229
  function attachToolTipEventHandlers() {
230
+ var tooltip = '#tiny-bulk-optimization div.tooltip';
231
+ var tip = 'div.tip';
232
+ var toolTipTimeout = null;
233
  jQuery(tooltip).mouseleave(function(){
234
+ var that = this;
235
  toolTipTimeout = setTimeout(function() {
236
  if (jQuery(that).find(tip).is(':visible')) {
237
+ jQuery(tooltip).find(tip).hide();
238
  }
239
+ }, 100);
240
+ });
241
  jQuery(tooltip).mouseenter(function(){
242
+ jQuery(this).find(tip).show();
243
+ clearTimeout(toolTipTimeout);
244
+ });
245
  jQuery(tooltip).find(tip).mouseenter(function(){
246
+ clearTimeout(toolTipTimeout);
247
+ });
248
  }
249
 
250
+ attachToolTipEventHandlers();
251
 
252
+ window.bulkOptimizationAutorun = startBulkOptimization;
253
+ window.bulkOptimization = prepareBulkOptimization;
254
 
255
+ }).call();
src/js/dashboard-widget.js CHANGED
@@ -1,10 +1,10 @@
1
  (function() {
2
  function generateDashboardWidget(element) {
3
- var element = jQuery(element)
4
- var container = element.find('.inside')
5
- jQuery('.chart').addClass('hidden')
6
  // Adding a class to the widget element so that classes are only used in the stylesheet
7
- jQuery('#tinypng_dashboard_widget').addClass('tiny_dashboard_widget')
8
  attachHandlers(container);
9
  retrieveStats(container);
10
  }
@@ -19,38 +19,40 @@
19
  id: '#tinypng_dashboard_widget'
20
  },
21
  success: function(data) {
22
- if (data == 0) {
23
- container.append("<p> An error occured. </p>")
24
  } else {
25
- renderWidget(data, container);
26
  }
27
  },
28
  error: function() {
29
- container.append("<p> An error occured. </p>")
30
  }
31
- })
32
  }
33
 
34
  function attachHandlers(container) {
35
- setContainerClass(container);
36
- jQuery(window).resize(function(){setContainerClass(container)});
37
- jQuery('#tinypng_dashboard_widget .hndle').click(function() {
38
- jQuery(this).siblings('.inside').removeClass('mobile')
39
- })
 
 
40
  }
41
 
42
  function setContainerClass(container) {
43
  if (jQuery(container).width() < 400) {
44
- jQuery(container).addClass('mobile')
45
  } else if (jQuery(container).width() < 490 && jQuery(container).width() >= 400) {
46
- jQuery(container).addClass('tablet')
47
- jQuery(container).removeClass('mobile')
48
  } else if (jQuery(container).width() >= 490) {
49
- jQuery(container).removeClass('tablet').removeClass('mobile')
50
  }
51
  }
52
 
53
- function renderWidget(data, container) {
54
  var stats = jQuery.parseJSON(data);
55
  var savings = stats['display-percentage'];
56
  var libraryOptimized = optimizedPercentage(stats);
@@ -61,50 +63,50 @@
61
  }
62
 
63
  function renderPercentage(percentage) {
64
- jQuery('#savings-percentage').find('span').html(percentage)
65
  }
66
 
67
  function renderContent(percentage, stats, savingsPercentage) {
68
  renderPercentage(savingsPercentage);
69
- if ( 0 == stats['uploaded-images'] + stats['available-unoptimised-sizes'] ) {
70
- jQuery('#tinypng_dashboard_widget').addClass('no-images-uploaded')
71
- } else if ( percentage == 0 ) {
72
- jQuery('#tinypng_dashboard_widget').addClass('not-optimized')
73
- } else if ( percentage == 100 ) {
74
- jQuery('#tinypng_dashboard_widget').addClass('full-optimized')
75
  } else {
76
- jQuery("#uploaded-images").html( stats['uploaded-images'] )
77
- jQuery("#unoptimised-sizes").html( stats['available-unoptimised-sizes'] )
78
- jQuery('#tinypng_dashboard_widget').addClass('half-optimized')
79
  }
80
- jQuery('#ie8-compressed').find('span').html(savingsPercentage)
81
  }
82
 
83
  function chartOptions(percentage) {
84
- chart = {};
85
- chart['size'] = 160;
86
- chart['radius'] = chart['size'] / 2 * 0.9;
87
- chart['main-radius'] = chart['radius'] * 0.88;
88
  chart['circle-size'] = 2 * Math.PI * chart['main-radius'];
89
  chart['dash-array-size'] = percentage / 100 * chart['circle-size'];
90
- return chart
91
  }
92
 
93
  function optimizedPercentage(stats) {
94
- if ( 0 != stats['unoptimized-library-size'] ) {
95
  return Math.round((stats['optimized-image-sizes'] / (stats['optimized-image-sizes'] + stats['available-unoptimised-sizes']) * 100), 0);
96
  } else {
97
- return 0
98
  }
99
  }
100
 
101
  function renderChart(savingsPercentage) {
102
- chart = chartOptions(savingsPercentage);
103
- jQuery('#optimization-chart svg circle.main').css('stroke-dasharray', chart['dash-array-size'] + ' ' + chart['circle-size'])
104
- style =
105
- " @keyframes shwoosh {" +
106
- " from { stroke-dasharray: 0 " + chart['circle-size'] + "}" +
107
- " to { stroke-dasharray:" + chart['dash-array-size'] + " " + chart['circle-size'] + "}}"
108
 
109
  // JQuery bug where you cannot append to style tag https://bugs.jquery.com/ticket/9832
110
  try {
@@ -116,6 +118,6 @@
116
 
117
  // Check if widget is loaded
118
  if (jQuery('#tinypng_dashboard_widget').length) {
119
- generateDashboardWidget('#tinypng_dashboard_widget')
120
  }
121
- }).call()
1
  (function() {
2
  function generateDashboardWidget(element) {
3
+ element = jQuery(element);
4
+ var container = element.find('.inside');
5
+ jQuery('.chart').addClass('hidden');
6
  // Adding a class to the widget element so that classes are only used in the stylesheet
7
+ jQuery('#tinypng_dashboard_widget').addClass('tiny_dashboard_widget');
8
  attachHandlers(container);
9
  retrieveStats(container);
10
  }
19
  id: '#tinypng_dashboard_widget'
20
  },
21
  success: function(data) {
22
+ if (data === 0) {
23
+ container.append('<p> An error occured. </p>');
24
  } else {
25
+ renderWidget(data);
26
  }
27
  },
28
  error: function() {
29
+ container.append('<p> An error occured. </p>');
30
  }
31
+ });
32
  }
33
 
34
  function attachHandlers(container) {
35
+ setContainerClass(container);
36
+ jQuery(window).resize(function(){
37
+ setContainerClass(container);
38
+ });
39
+ jQuery('#tinypng_dashboard_widget .hndle').click(function() {
40
+ jQuery(this).siblings('.inside').removeClass('mobile');
41
+ });
42
  }
43
 
44
  function setContainerClass(container) {
45
  if (jQuery(container).width() < 400) {
46
+ jQuery(container).addClass('mobile');
47
  } else if (jQuery(container).width() < 490 && jQuery(container).width() >= 400) {
48
+ jQuery(container).addClass('tablet');
49
+ jQuery(container).removeClass('mobile');
50
  } else if (jQuery(container).width() >= 490) {
51
+ jQuery(container).removeClass('tablet').removeClass('mobile');
52
  }
53
  }
54
 
55
+ function renderWidget(data) {
56
  var stats = jQuery.parseJSON(data);
57
  var savings = stats['display-percentage'];
58
  var libraryOptimized = optimizedPercentage(stats);
63
  }
64
 
65
  function renderPercentage(percentage) {
66
+ jQuery('#savings-percentage').find('span').html(percentage);
67
  }
68
 
69
  function renderContent(percentage, stats, savingsPercentage) {
70
  renderPercentage(savingsPercentage);
71
+ if ( 0 === stats['uploaded-images'] + stats['available-unoptimised-sizes'] ) {
72
+ jQuery('#tinypng_dashboard_widget').addClass('no-images-uploaded');
73
+ } else if ( percentage === 0 ) {
74
+ jQuery('#tinypng_dashboard_widget').addClass('not-optimized');
75
+ } else if ( percentage === 100 ) {
76
+ jQuery('#tinypng_dashboard_widget').addClass('full-optimized');
77
  } else {
78
+ jQuery('#uploaded-images').html( stats['uploaded-images'] );
79
+ jQuery('#unoptimised-sizes').html( stats['available-unoptimised-sizes'] );
80
+ jQuery('#tinypng_dashboard_widget').addClass('half-optimized');
81
  }
82
+ jQuery('#ie8-compressed').find('span').html(savingsPercentage);
83
  }
84
 
85
  function chartOptions(percentage) {
86
+ var chart = {};
87
+ chart.size = 160;
88
+ chart.radius = chart.size / 2 * 0.9;
89
+ chart['main-radius'] = chart.radius * 0.88;
90
  chart['circle-size'] = 2 * Math.PI * chart['main-radius'];
91
  chart['dash-array-size'] = percentage / 100 * chart['circle-size'];
92
+ return chart;
93
  }
94
 
95
  function optimizedPercentage(stats) {
96
+ if ( 0 !== stats['unoptimized-library-size'] ) {
97
  return Math.round((stats['optimized-image-sizes'] / (stats['optimized-image-sizes'] + stats['available-unoptimised-sizes']) * 100), 0);
98
  } else {
99
+ return 0;
100
  }
101
  }
102
 
103
  function renderChart(savingsPercentage) {
104
+ var chart = chartOptions(savingsPercentage);
105
+ jQuery('#optimization-chart svg circle.main').css('stroke-dasharray', chart['dash-array-size'] + ' ' + chart['circle-size']);
106
+ var style =
107
+ ' @keyframes shwoosh {' +
108
+ ' from { stroke-dasharray: 0 ' + chart['circle-size'] + '}' +
109
+ ' to { stroke-dasharray:' + chart['dash-array-size'] + ' ' + chart['circle-size'] + '}}';
110
 
111
  // JQuery bug where you cannot append to style tag https://bugs.jquery.com/ticket/9832
112
  try {
118
 
119
  // Check if widget is loaded
120
  if (jQuery('#tinypng_dashboard_widget').length) {
121
+ generateDashboardWidget('#tinypng_dashboard_widget');
122
  }
123
+ }).call();
src/vendor/tinify/Tinify.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace Tinify;
4
 
5
- const VERSION = "1.5.0";
6
 
7
  class Tinify {
8
  const AUTHENTICATED = true;
2
 
3
  namespace Tinify;
4
 
5
+ const VERSION = "1.5.2";
6
 
7
  class Tinify {
8
  const AUTHENTICATED = true;
src/vendor/tinify/Tinify/Client.php CHANGED
@@ -20,6 +20,17 @@ class Client {
20
  }
21
 
22
  function __construct($key, $appIdentifier = NULL, $proxy = NULL) {
 
 
 
 
 
 
 
 
 
 
 
23
  $userAgent = join(" ", array_filter(array(self::userAgent(), $appIdentifier)));
24
 
25
  $this->options = array(
20
  }
21
 
22
  function __construct($key, $appIdentifier = NULL, $proxy = NULL) {
23
+ $curl = curl_version();
24
+
25
+ if (!($curl["features"] & CURL_VERSION_SSL)) {
26
+ throw new ClientException("Your curl version does not support secure connections");
27
+ }
28
+
29
+ if ($curl["version_number"] < 0x071201) {
30
+ $version = $curl["version"];
31
+ throw new ClientException("Your curl version ${version} is outdated; please upgrade to 7.18.1 or higher");
32
+ }
33
+
34
  $userAgent = join(" ", array_filter(array(self::userAgent(), $appIdentifier)));
35
 
36
  $this->options = array(
src/views/account-status-connected.php CHANGED
@@ -15,18 +15,20 @@
15
  if ( $status->ok ) {
16
  $compressions = self::get_compression_count();
17
  /* It is not possible to check if a subscription is free or flexible. */
18
- if ( Tiny_Config::MONTHLY_FREE_COMPRESSIONS == $compressions ) {
19
- $link = '<a href="https://tinypng.com/dashboard/developers" target="_blank">' . esc_html__( 'TinyPNG API account', 'tiny-compress-images' ) . '</a>';
20
- printf( esc_html__(
21
- 'You have reached your limit of %s compressions this month.',
22
  'tiny-compress-images'
23
- ), $compressions );
24
  echo '<br>';
 
25
  printf( esc_html__(
26
- 'If you need to compress more images you can change your %s.',
27
  'tiny-compress-images'
28
  ), $link );
29
  } else {
 
30
  printf( esc_html__(
31
  'You have made %s compressions this month.',
32
  'tiny-compress-images'
@@ -46,6 +48,7 @@
46
  ?></p>
47
  <p><?php
48
  if ( defined( 'TINY_API_KEY' ) ) {
 
49
  echo sprintf( esc_html__(
50
  'The API key has been configured in %s',
51
  'tiny-compress-images'
@@ -61,9 +64,10 @@
61
  <div class="update" style="display: none">
62
  <h4><?php echo esc_html__( 'Change your API key', 'tiny-compress-images' ); ?></h4>
63
  <p class="introduction"><?php
64
- $link = sprintf( '<a href="https://tinypng.com/dashboard/developers" target="_blank">%s</a>',
65
  esc_html__( 'API dashboard', 'tiny-compress-images' )
66
  );
 
67
  printf( esc_html__(
68
  'Enter your API key. If you have lost your key, go to your %s to retrieve it.',
69
  'tiny-compress-images'
15
  if ( $status->ok ) {
16
  $compressions = self::get_compression_count();
17
  /* It is not possible to check if a subscription is free or flexible. */
18
+ if ( self::limit_reached() ) {
19
+ $link = '<a href="https://tinypng.com/dashboard/api" target="_blank">' . esc_html__( 'TinyPNG API account', 'tiny-compress-images' ) . '</a>';
20
+ esc_html_e(
21
+ 'You have reached your free limit this month.',
22
  'tiny-compress-images'
23
+ );
24
  echo '<br>';
25
+ /* translators: %s: link saying TinyPNG API account */
26
  printf( esc_html__(
27
+ 'If you need to compress more images you can upgrade your %s.',
28
  'tiny-compress-images'
29
  ), $link );
30
  } else {
31
+ /* translators: %s: number of compressions */
32
  printf( esc_html__(
33
  'You have made %s compressions this month.',
34
  'tiny-compress-images'
48
  ?></p>
49
  <p><?php
50
  if ( defined( 'TINY_API_KEY' ) ) {
51
+ /* translators: %s: wp-config.php */
52
  echo sprintf( esc_html__(
53
  'The API key has been configured in %s',
54
  'tiny-compress-images'
64
  <div class="update" style="display: none">
65
  <h4><?php echo esc_html__( 'Change your API key', 'tiny-compress-images' ); ?></h4>
66
  <p class="introduction"><?php
67
+ $link = sprintf( '<a href="https://tinypng.com/dashboard/api" target="_blank">%s</a>',
68
  esc_html__( 'API dashboard', 'tiny-compress-images' )
69
  );
70
+ /* translators: %s: link saying API dashboard */
71
  printf( esc_html__(
72
  'Enter your API key. If you have lost your key, go to your %s to retrieve it.',
73
  'tiny-compress-images'
src/views/account-status-create-advanced.php CHANGED
@@ -36,9 +36,10 @@ $email = trim( $user->user_email );
36
  ?></h4>
37
 
38
  <p class="introduction"><?php
39
- $link = sprintf( '<a href="https://tinypng.com/dashboard/developers" target="_blank">%s</a>',
40
  esc_html__( 'API dashboard', 'tiny-compress-images' )
41
  );
 
42
  printf( esc_html__(
43
  'Enter your API key. Go to your %s to retrieve it.',
44
  'tiny-compress-images'
36
  ?></h4>
37
 
38
  <p class="introduction"><?php
39
+ $link = sprintf( '<a href="https://tinypng.com/dashboard/api" target="_blank">%s</a>',
40
  esc_html__( 'API dashboard', 'tiny-compress-images' )
41
  );
42
+ /* translators: %s: link saying API dashboard */
43
  printf( esc_html__(
44
  'Enter your API key. Go to your %s to retrieve it.',
45
  'tiny-compress-images'
src/views/account-status-create-simple.php CHANGED
@@ -9,6 +9,7 @@
9
  echo esc_html__( 'Enter your API key.', 'tiny-compress-images' );
10
  echo ' ';
11
 
 
12
  printf( esc_html__(
13
  'If needed you can go to the %s to retrieve it.',
14
  'tiny-compress-images'
9
  echo esc_html__( 'Enter your API key.', 'tiny-compress-images' );
10
  echo ' ';
11
 
12
+ /* translators: %s: link saying TinyPNG developer section */
13
  printf( esc_html__(
14
  'If needed you can go to the %s to retrieve it.',
15
  'tiny-compress-images'
src/views/bulk-optimization-form.php CHANGED
@@ -1,12 +1,7 @@
1
  <div id="bulk-optimization-actions" class="optimization-buttons">
2
  <?php
3
- if ( $auto_start_bulk ) {
4
- $button_start_visibility = '';
5
- $button_optimizing_visibility = ' visible';
6
- } else {
7
- $button_start_visibility = ' visible';
8
- $button_optimizing_visibility = '';
9
- }
10
  submit_button( esc_attr__( 'Start Bulk Optimization', 'tiny-compress-images' ), 'button-primary button-hero' . $button_start_visibility, 'id-start', false );
11
  submit_button( esc_attr__( 'Optimizing', 'tiny-compress-images' ) . '...', 'button-primary button-hero' . $button_optimizing_visibility, 'id-optimizing', false );
12
  submit_button( esc_attr__( 'Cancel', 'tiny-compress-images' ), 'button-primary button-hero red', 'id-cancel', false );
1
  <div id="bulk-optimization-actions" class="optimization-buttons">
2
  <?php
3
+ $button_start_visibility = ' visible';
4
+ $button_optimizing_visibility = '';
 
 
 
 
 
5
  submit_button( esc_attr__( 'Start Bulk Optimization', 'tiny-compress-images' ), 'button-primary button-hero' . $button_start_visibility, 'id-start', false );
6
  submit_button( esc_attr__( 'Optimizing', 'tiny-compress-images' ) . '...', 'button-primary button-hero' . $button_optimizing_visibility, 'id-optimizing', false );
7
  submit_button( esc_attr__( 'Cancel', 'tiny-compress-images' ), 'button-primary button-hero red', 'id-cancel', false );
src/views/bulk-optimization.php CHANGED
@@ -53,16 +53,21 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
53
  } elseif ( 0 == sizeof( $active_tinify_sizes ) ) {
54
  esc_html_e( 'Based on your current settings, nothing will be optimized. There are no active sizes selected for optimization.', 'tiny-compress-images' );
55
  } elseif ( 0 == $stats['available-unoptimised-sizes'] ) {
 
56
  printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() );
57
  } elseif ( $stats['optimized-image-sizes'] > 0 ) {
58
  if ( $percentage_of_files > 75 ) {
 
59
  printf( esc_html__( '%s, you are doing great!', 'tiny-compress-images' ), $this->friendly_user_name() );
60
  } else {
 
61
  printf( esc_html__( '%s, you are doing good.', 'tiny-compress-images' ), $this->friendly_user_name() );
62
  }
63
  echo ' ';
64
- printf( esc_html__( '%1$d %2$s of your image library is optimized.', 'tiny-compress-images' ), $percentage_of_files, '%' );
 
65
  echo ' ';
 
66
  printf( esc_html__( 'Start the %s to optimize the remainder of your library.', 'tiny-compress-images' ), esc_html__( 'bulk optimization', 'tiny-compress-images' ) );
67
  } else {
68
  esc_html_e( 'Here you can start optimizing your entire library. Press the big button to start improving your website speed instantly!', 'tiny-compress-images' );
@@ -101,6 +106,7 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
101
  <?php if ( $stats['uploaded-images'] > 0 && sizeof( $active_tinify_sizes ) > 0 && $stats['available-unoptimised-sizes'] > 0 ) { ?>
102
  <p>
103
  <?php
 
104
  printf( esc_html__( 'With your current settings you can still optimize %1$s image sizes from your %2$s uploaded JPEG and PNG images.',
105
  'tiny-compress-images'), $stats['available-unoptimised-sizes'], $stats['uploaded-images'] );
106
  ?>
@@ -127,15 +133,19 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
127
  </p>
128
  <p>
129
  <?php if ( sizeof( $active_tinify_sizes ) > 0 ) { ?>
130
- <?php printf( wp_kses( _n( 'For each uploaded image <strong>%d size</strong> is compressed.', 'For each uploaded image <strong>%d sizes</strong> are compressed.', count( $active_tinify_sizes ), 'tiny-compress-images' ), array(
 
 
131
  'strong' => array(),
132
  ) ), count( $active_tinify_sizes ) ) ?>
133
  <?php } ?>
134
- <?php printf( wp_kses( __( 'You can change these settings %s.', 'tiny-compress-images' ), array(
 
 
135
  'a' => array(
136
  'href' => array(),
137
  ),
138
- ) ), '<a href=' . admin_url( 'options-media.php#tiny-compress-images' ) . '>' . __( 'here', 'tiny-compress-images' ) . '</a>' )?>
139
  </p>
140
  </div>
141
  </div>
@@ -153,13 +163,14 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
153
  <span class="dashicons dashicons-info"></span>
154
  <div class="tip">
155
  <p><?php
 
156
  printf( wp_kses( __( 'If you wish to compress more than <strong>%1$d %2$s</strong> a month and you are still on a free account %3$s.', 'tiny-compress-images' ),
157
  array(
158
  'strong' => array(),
159
  'a' => array(
160
  'href' => array(),
161
  ),
162
- ) ), Tiny_Config::MONTHLY_FREE_COMPRESSIONS, esc_html__( 'image sizes', 'tiny-compress-images' ), '<a href="https://tinypng.com/dashboard/developers">' . esc_html__( ' upgrade here', 'tiny-compress-images' ) . '</a>' );
163
  ?></p>
164
  </div>
165
  </div>
@@ -234,13 +245,7 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
234
  </div>
235
  </div>
236
  <script type="text/javascript">
237
- <?php
238
- if ( $auto_start_bulk ) {
239
- echo 'jQuery(function() { bulkOptimizationAutorun(' . json_encode( $this->get_ids_to_compress() ) . ')})';
240
- } else {
241
- echo 'jQuery(function() { bulkOptimization(' . json_encode( $stats['available-for-optimization'] ) . ')})';
242
- }
243
- ?>
244
  </script>
245
  <table class="wp-list-table widefat fixed striped media whitebox" id="optimization-items" >
246
  <thead>
@@ -248,11 +253,10 @@ div.tiny-bulk-optimization div.dashboard div.optimize div.progressbar div.progre
248
  <?php // column-author WP 3.8-4.2 mobile view ?>
249
  <th class="thumbnail"></th>
250
  <th class="column-primary" ><?php esc_html_e( 'File', 'tiny-compress-images' ) ?></th>
251
- <th class="column-author"><?php esc_html_e( 'Sizes Optimized', 'tiny-compress-images' ) ?></th>
252
  <th class="column-author"><?php esc_html_e( 'Initial Size', 'tiny-compress-images' ) ?></th>
253
  <th class="column-author"><?php esc_html_e( 'Current Size', 'tiny-compress-images' ) ?></th>
254
  <th class="column-author savings" ><?php esc_html_e( 'Savings', 'tiny-compress-images' ) ?></th>
255
- <th class="status" ><?php esc_html_e( 'Status', 'tiny-compress-images' ) ?></th>
256
  </tr>
257
  </thead>
258
  <tbody>
53
  } elseif ( 0 == sizeof( $active_tinify_sizes ) ) {
54
  esc_html_e( 'Based on your current settings, nothing will be optimized. There are no active sizes selected for optimization.', 'tiny-compress-images' );
55
  } elseif ( 0 == $stats['available-unoptimised-sizes'] ) {
56
+ /* translators: %s: friendly user name */
57
  printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() );
58
  } elseif ( $stats['optimized-image-sizes'] > 0 ) {
59
  if ( $percentage_of_files > 75 ) {
60
+ /* translators: %s: friendly user name */
61
  printf( esc_html__( '%s, you are doing great!', 'tiny-compress-images' ), $this->friendly_user_name() );
62
  } else {
63
+ /* translators: %s: friendly user name */
64
  printf( esc_html__( '%s, you are doing good.', 'tiny-compress-images' ), $this->friendly_user_name() );
65
  }
66
  echo ' ';
67
+ /* translators: %1$d%2$s: percentage optimised */
68
+ printf( esc_html__( '%1$d%2$s of your image library is optimized.', 'tiny-compress-images' ), $percentage_of_files, '%' );
69
  echo ' ';
70
+ /* translators: %s: bulk optimization title */
71
  printf( esc_html__( 'Start the %s to optimize the remainder of your library.', 'tiny-compress-images' ), esc_html__( 'bulk optimization', 'tiny-compress-images' ) );
72
  } else {
73
  esc_html_e( 'Here you can start optimizing your entire library. Press the big button to start improving your website speed instantly!', 'tiny-compress-images' );
106
  <?php if ( $stats['uploaded-images'] > 0 && sizeof( $active_tinify_sizes ) > 0 && $stats['available-unoptimised-sizes'] > 0 ) { ?>
107
  <p>
108
  <?php
109
+ /* translators: %1$s: number of sizes that can be optimised, %2$s number of images */
110
  printf( esc_html__( 'With your current settings you can still optimize %1$s image sizes from your %2$s uploaded JPEG and PNG images.',
111
  'tiny-compress-images'), $stats['available-unoptimised-sizes'], $stats['uploaded-images'] );
112
  ?>
133
  </p>
134
  <p>
135
  <?php if ( sizeof( $active_tinify_sizes ) > 0 ) { ?>
136
+ <?php
137
+ /* translators: %d: number of sizes to be compressed */
138
+ printf( wp_kses( _n( 'For each uploaded image <strong>%d size</strong> is compressed.', 'For each uploaded image <strong>%d sizes</strong> are compressed.', count( $active_tinify_sizes ), 'tiny-compress-images' ), array(
139
  'strong' => array(),
140
  ) ), count( $active_tinify_sizes ) ) ?>
141
  <?php } ?>
142
+ <?php
143
+ /* translators: %s: link to settings page saying here */
144
+ printf( wp_kses( __( 'You can change these settings %s.', 'tiny-compress-images' ), array(
145
  'a' => array(
146
  'href' => array(),
147
  ),
148
+ ) ), '<a href=' . admin_url( 'options-general.php?page=tinify' ) . '>' . __( 'here', 'tiny-compress-images' ) . '</a>' )?>
149
  </p>
150
  </div>
151
  </div>
163
  <span class="dashicons dashicons-info"></span>
164
  <div class="tip">
165
  <p><?php
166
+ /* translators: %1$d %2$s: number of image sizes, %3$s: link saying upgrade here */
167
  printf( wp_kses( __( 'If you wish to compress more than <strong>%1$d %2$s</strong> a month and you are still on a free account %3$s.', 'tiny-compress-images' ),
168
  array(
169
  'strong' => array(),
170
  'a' => array(
171
  'href' => array(),
172
  ),
173
+ ) ), Tiny_Config::MONTHLY_FREE_COMPRESSIONS, esc_html__( 'image sizes', 'tiny-compress-images' ), '<a href="https://tinypng.com/dashboard/api">' . esc_html__( ' upgrade here', 'tiny-compress-images' ) . '</a>' );
174
  ?></p>
175
  </div>
176
  </div>
245
  </div>
246
  </div>
247
  <script type="text/javascript">
248
+ <?php echo 'jQuery(function() { bulkOptimization(' . json_encode( $stats['available-for-optimization'] ) . ')})'; ?>
 
 
 
 
 
 
249
  </script>
250
  <table class="wp-list-table widefat fixed striped media whitebox" id="optimization-items" >
251
  <thead>
253
  <?php // column-author WP 3.8-4.2 mobile view ?>
254
  <th class="thumbnail"></th>
255
  <th class="column-primary" ><?php esc_html_e( 'File', 'tiny-compress-images' ) ?></th>
 
256
  <th class="column-author"><?php esc_html_e( 'Initial Size', 'tiny-compress-images' ) ?></th>
257
  <th class="column-author"><?php esc_html_e( 'Current Size', 'tiny-compress-images' ) ?></th>
258
  <th class="column-author savings" ><?php esc_html_e( 'Savings', 'tiny-compress-images' ) ?></th>
259
+ <th class="column-author status" ><?php esc_html_e( 'Status', 'tiny-compress-images' ) ?></th>
260
  </tr>
261
  </thead>
262
  <tbody>
src/views/compress-details-processing.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="details-container">
2
  <div class="details">
3
  <span class="icon spinner"></span>
4
  <span class="message">
1
+ <div class="details-container" data-status="compressing" data-id="<?php echo $tiny_image->get_id() ?>">
2
  <div class="details">
3
  <span class="icon spinner"></span>
4
  <span class="message">
src/views/compress-details.php CHANGED
@@ -6,7 +6,7 @@ $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
6
  $error = $tiny_image->get_latest_error();
7
  $total = $tiny_image->get_count( array( 'modified', 'missing', 'has_been_compressed', 'compressed' ) );
8
  $active = $tiny_image->get_count( array( 'uncompressed', 'never_compressed' ), $active_tinify_sizes );
9
- $image_statistics = $tiny_image->get_statistics();
10
  $available_unoptimized_sizes = $image_statistics['available_unoptimized_sizes'];
11
  $size_before = $image_statistics['initial_total_size'];
12
  $size_after = $image_statistics['optimized_total_size'];
@@ -15,9 +15,13 @@ $size_active = array_fill_keys( $active_tinify_sizes, true );
15
  $size_exists = array_fill_keys( $available_sizes, true );
16
  ksort( $size_exists );
17
 
 
 
 
 
18
  ?>
19
  <div class="details-container">
20
- <div class="details" >
21
  <?php if ( $error ) {
22
  // dashicons-warning available for WP 4.3+ ?>
23
  <span class="icon dashicons dashicons-no error"></span>
@@ -31,35 +35,47 @@ ksort( $size_exists );
31
  <span class="icon spinner hidden"></span>
32
  <?php if ( $total['has_been_compressed'] > 0 || (0 == $total['has_been_compressed'] && 0 == $available_unoptimized_sizes) ) { ?>
33
  <span class="message">
34
- <?php printf( wp_kses( _n( '<strong>%d</strong> size compressed', '<strong>%d</strong> sizes compressed', $total['has_been_compressed'], 'tiny-compress-images' ), array(
 
 
35
  'strong' => array(),
36
- ) ), $total['has_been_compressed'] ) ?>
 
37
  </span>
38
- <br/>
39
  <?php } ?>
40
- <?php if ( $available_unoptimized_sizes > 0 ) { ?>
41
  <span class="message">
42
- <?php printf( esc_html( _n( '%d size to be compressed', '%d sizes to be compressed', $available_unoptimized_sizes, 'tiny-compress-images' ) ), $available_unoptimized_sizes ) ?>
 
 
 
43
  </span>
44
- <br />
45
  <?php } ?>
46
  <?php if ( $size_before - $size_after ) { ?>
47
  <span class="message">
48
- <?php printf( esc_html__( 'Total savings %.0f%%', 'tiny-compress-images' ), (1 - $size_after / floatval( $size_before )) * 100 ) ?>
 
 
 
49
  </span>
50
- <br />
51
  <?php } ?>
52
  <?php if ( $error ) { ?>
53
  <span class="message error_message">
54
  <?php echo esc_html__( 'Latest error', 'tiny-compress-images' ) . ': ' . esc_html( $error, 'tiny-compress-images' ) ?>
55
  </span>
56
- <br/>
57
  <?php } ?>
58
  <a class="thickbox message" href="#TB_inline?width=700&amp;height=500&amp;inlineId=modal_<?php echo $tiny_image->get_id() ?>">
59
  <?php esc_html_e( 'Details', 'tiny-compress-images' ) ?>
60
  </a>
61
  </div>
62
- <?php if ( $active['uncompressed'] > 0 ) { ?>
 
 
 
63
  <button type="button" class="tiny-compress button button-small button-primary" data-id="<?php echo $tiny_image->get_id() ?>">
64
  <?php esc_html_e( 'Compress', 'tiny-compress-images' ) ?>
65
  </button>
@@ -69,7 +85,10 @@ ksort( $size_exists );
69
  <div class="modal" id="modal_<?php echo $tiny_image->get_id() ?>">
70
  <div class="tiny-compression-details">
71
  <h3>
72
- <?php printf( esc_html__( 'Compression details for %s', 'tiny-compress-images' ), $tiny_image->get_name() ) ?>
 
 
 
73
  </h3>
74
  <table>
75
  <tr>
@@ -89,8 +108,9 @@ ksort( $size_exists );
89
  <tr class="<?php echo ( 0 == $i % 2 ) ? 'even' : 'odd' ?>">
90
  <?php
91
  echo '<td>';
 
92
  echo ( Tiny_Image::is_original( $size_name ) ? esc_html__( 'Original', 'tiny-compress-images' ) : esc_html( ucfirst( rtrim( $size_name, '_wr2x' ) ) ) );
93
- echo ' ';
94
  if ( ! array_key_exists( $size_name, $active_sizes ) && ! Tiny_Image::is_retina( $size_name ) ) {
95
  echo '<em>' . esc_html__( '(not in use)', 'tiny-compress-images' ) . '</em>';
96
  } elseif ( $size->missing() && ( Tiny_Settings::wr2x_active() || ! Tiny_Image::is_retina( $size_name ) ) ) {
@@ -100,16 +120,19 @@ ksort( $size_exists );
100
  } elseif ( Tiny_Image::is_retina( $size_name ) ) {
101
  echo '<em>' . esc_html__( '(WP Retina 2x)', 'tiny-compress-images' ) . '</em>';
102
  } elseif ( $size->resized() ) {
 
103
  printf( '<em>' . esc_html__( '(resized to %1$dx%2$d)', 'tiny-compress-images' ) . '</em>', $size->meta['output']['width'], $size->meta['output']['height'] );
104
  }
105
  echo '</td>';
106
 
107
  if ( $size->is_duplicate() ) {
108
  echo '<td>-</td>';
 
109
  printf( '<td colspan=2><em>' . esc_html__( 'Same file as "%s"', 'tiny-compress-images' ) . '</em></td>', esc_html( ucfirst( $size->duplicate_of_size() ) ) );
110
  } elseif ( $size->has_been_compressed() ) {
111
  echo '<td>' . size_format( $size->meta['input']['size'], 1 ) . '</td>';
112
  echo '<td>' . size_format( $size->meta['output']['size'], 1 ) . '</td>';
 
113
  echo '<td>' . sprintf( esc_html__( '%s ago' ), human_time_diff( $size->end_time( $size_name ) ) ) . '</td>';
114
  } elseif ( ! $size->exists() ) {
115
  echo '<td>-</td>';
@@ -147,11 +170,13 @@ ksort( $size_exists );
147
  <strong>
148
  <?php
149
  if ( $size_before - $size_after ) {
 
150
  printf( esc_html__( 'Total savings %1$.0f%% (%2$s)', 'tiny-compress-images' ),
151
  ( 1 - $size_after / floatval( $size_before ) ) * 100,
152
  size_format( $size_before - $size_after, 1 )
153
  );
154
  } else {
 
155
  printf( esc_html__( 'Total savings %.0f%%', 'tiny-compress-images' ), 0 );
156
  }
157
  ?>
6
  $error = $tiny_image->get_latest_error();
7
  $total = $tiny_image->get_count( array( 'modified', 'missing', 'has_been_compressed', 'compressed' ) );
8
  $active = $tiny_image->get_count( array( 'uncompressed', 'never_compressed' ), $active_tinify_sizes );
9
+ $image_statistics = $tiny_image->get_statistics( $active_sizes, $active_tinify_sizes );
10
  $available_unoptimized_sizes = $image_statistics['available_unoptimized_sizes'];
11
  $size_before = $image_statistics['initial_total_size'];
12
  $size_after = $image_statistics['optimized_total_size'];
15
  $size_exists = array_fill_keys( $available_sizes, true );
16
  ksort( $size_exists );
17
 
18
+ $images_to_compress = array();
19
+ if ( ! empty( $_REQUEST['ids'] ) ) {
20
+ $images_to_compress = array_map( 'intval', explode( '-', $_REQUEST['ids'] ) );
21
+ }
22
  ?>
23
  <div class="details-container">
24
+ <div class="details">
25
  <?php if ( $error ) {
26
  // dashicons-warning available for WP 4.3+ ?>
27
  <span class="icon dashicons dashicons-no error"></span>
35
  <span class="icon spinner hidden"></span>
36
  <?php if ( $total['has_been_compressed'] > 0 || (0 == $total['has_been_compressed'] && 0 == $available_unoptimized_sizes) ) { ?>
37
  <span class="message">
38
+ <?php
39
+ /* translators: %d: number of compressed sizes */
40
+ printf( wp_kses( _n( '<strong>%d</strong> size compressed', '<strong>%d</strong> sizes compressed', $total['has_been_compressed'], 'tiny-compress-images' ), array(
41
  'strong' => array(),
42
+ ) ), $total['has_been_compressed'] );
43
+ ?>
44
  </span>
45
+ <br>
46
  <?php } ?>
47
+ <?php if ( $active['uncompressed'] > 0 ) { ?>
48
  <span class="message">
49
+ <?php
50
+ /* translators: %d: number of sizes to be compressed */
51
+ printf( esc_html( _n( '%d size to be compressed', '%d sizes to be compressed', $available_unoptimized_sizes, 'tiny-compress-images' ) ), $available_unoptimized_sizes );
52
+ ?>
53
  </span>
54
+ <br>
55
  <?php } ?>
56
  <?php if ( $size_before - $size_after ) { ?>
57
  <span class="message">
58
+ <?php
59
+ /* translators: %.0f%: savings percentage */
60
+ printf( esc_html__( 'Total savings %.0f%%', 'tiny-compress-images' ), (1 - $size_after / floatval( $size_before )) * 100 );
61
+ ?>
62
  </span>
63
+ <br>
64
  <?php } ?>
65
  <?php if ( $error ) { ?>
66
  <span class="message error_message">
67
  <?php echo esc_html__( 'Latest error', 'tiny-compress-images' ) . ': ' . esc_html( $error, 'tiny-compress-images' ) ?>
68
  </span>
69
+ <br>
70
  <?php } ?>
71
  <a class="thickbox message" href="#TB_inline?width=700&amp;height=500&amp;inlineId=modal_<?php echo $tiny_image->get_id() ?>">
72
  <?php esc_html_e( 'Details', 'tiny-compress-images' ) ?>
73
  </a>
74
  </div>
75
+ <?php if ( $available_unoptimized_sizes > 0 ) { ?>
76
+ <?php if ( in_array( $tiny_image->get_id(), $images_to_compress ) ) { ?>
77
+ <span class="hidden auto-compress"></span>
78
+ <?php } ?>
79
  <button type="button" class="tiny-compress button button-small button-primary" data-id="<?php echo $tiny_image->get_id() ?>">
80
  <?php esc_html_e( 'Compress', 'tiny-compress-images' ) ?>
81
  </button>
85
  <div class="modal" id="modal_<?php echo $tiny_image->get_id() ?>">
86
  <div class="tiny-compression-details">
87
  <h3>
88
+ <?php
89
+ /* translators: %s is the image filename */
90
+ printf( esc_html__( 'Compression details for %s', 'tiny-compress-images' ), $tiny_image->get_name() );
91
+ ?>
92
  </h3>
93
  <table>
94
  <tr>
108
  <tr class="<?php echo ( 0 == $i % 2 ) ? 'even' : 'odd' ?>">
109
  <?php
110
  echo '<td>';
111
+ echo '<span title="' . esc_html( basename( $size->filename ) ) . '">';
112
  echo ( Tiny_Image::is_original( $size_name ) ? esc_html__( 'Original', 'tiny-compress-images' ) : esc_html( ucfirst( rtrim( $size_name, '_wr2x' ) ) ) );
113
+ echo '</span>' . ' ';
114
  if ( ! array_key_exists( $size_name, $active_sizes ) && ! Tiny_Image::is_retina( $size_name ) ) {
115
  echo '<em>' . esc_html__( '(not in use)', 'tiny-compress-images' ) . '</em>';
116
  } elseif ( $size->missing() && ( Tiny_Settings::wr2x_active() || ! Tiny_Image::is_retina( $size_name ) ) ) {
120
  } elseif ( Tiny_Image::is_retina( $size_name ) ) {
121
  echo '<em>' . esc_html__( '(WP Retina 2x)', 'tiny-compress-images' ) . '</em>';
122
  } elseif ( $size->resized() ) {
123
+ /* translators: %1$dx%2$d: resized image width x height */
124
  printf( '<em>' . esc_html__( '(resized to %1$dx%2$d)', 'tiny-compress-images' ) . '</em>', $size->meta['output']['width'], $size->meta['output']['height'] );
125
  }
126
  echo '</td>';
127
 
128
  if ( $size->is_duplicate() ) {
129
  echo '<td>-</td>';
130
+ /* translators: %s: name of similar thumbnail size */
131
  printf( '<td colspan=2><em>' . esc_html__( 'Same file as "%s"', 'tiny-compress-images' ) . '</em></td>', esc_html( ucfirst( $size->duplicate_of_size() ) ) );
132
  } elseif ( $size->has_been_compressed() ) {
133
  echo '<td>' . size_format( $size->meta['input']['size'], 1 ) . '</td>';
134
  echo '<td>' . size_format( $size->meta['output']['size'], 1 ) . '</td>';
135
+ /* translators: %s human friendly time difference */
136
  echo '<td>' . sprintf( esc_html__( '%s ago' ), human_time_diff( $size->end_time( $size_name ) ) ) . '</td>';
137
  } elseif ( ! $size->exists() ) {
138
  echo '<td>-</td>';
170
  <strong>
171
  <?php
172
  if ( $size_before - $size_after ) {
173
+ /* translators: %1$.0f%%: savings percentage, %2$s: total file size savings */
174
  printf( esc_html__( 'Total savings %1$.0f%% (%2$s)', 'tiny-compress-images' ),
175
  ( 1 - $size_after / floatval( $size_before ) ) * 100,
176
  size_format( $size_before - $size_after, 1 )
177
  );
178
  } else {
179
+ /* translators: %.0f%%: savings percentage */
180
  printf( esc_html__( 'Total savings %.0f%%', 'tiny-compress-images' ), 0 );
181
  }
182
  ?>
src/views/dashboard-widget.php CHANGED
@@ -22,34 +22,54 @@ div#tinypng_dashboard_widget div#optimization-chart svg circle.main {
22
  </div>
23
  <div class="description not-optimized">
24
  <p>
25
- <?php printf( esc_html__( 'Hi %s, you haven’t compressed any images in your media library.', 'tiny-compress-images' ), $this->friendly_user_name() ) ?>
26
- <?php printf( wp_kses( __( 'If you like you can to optimize your whole library in one go with the %s page.', 'tiny-compress-images' ), array(
 
 
 
 
27
  'a' => array(
28
  'href' => array(),
29
  ),
30
- ) ), $link )?>
 
31
  </p>
32
  </div>
33
  <div class="description half-optimized">
34
  <p>
35
- <?php printf( esc_html__( '%s, you are doing good.', 'tiny-compress-images' ), $this->friendly_user_name() ) ?>
36
- <?php printf( esc_html__( 'With your current settings you can still optimize %1$s image sizes from your %2$s uploaded JPEG and PNG images.', 'tiny-compress-images' ), '<span id="unoptimised-sizes"></span>', '<span id="uploaded-images"></span>' ) ?>
37
- <?php printf( wp_kses( __( 'Start the %s to optimize the remainder of your library.', 'tiny-compress-images' ), array(
 
 
 
 
 
 
38
  'a' => array(
39
  'href' => array(),
40
  ),
41
- ) ), $link )?>
 
42
  </p>
43
  </div>
44
  <div class="description full-optimized">
45
- <p><?php printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() ) ?></p>
 
 
 
 
 
46
  </div>
47
  <div class="description" id="ie8-compressed">
48
  <p>
49
- <?php printf( wp_kses( __( 'You have <strong>saved %s</strong> of your media library size.', 'tiny-compress-images' ), array(
 
 
50
  'span' => array(),
51
  'strong' => array(),
52
- ) ), '<span></span>%' )?>
 
53
  </p>
54
  </div>
55
 
22
  </div>
23
  <div class="description not-optimized">
24
  <p>
25
+ <?php
26
+ /* translators: %s: friendly user name */
27
+ printf( esc_html__( 'Hi %s, you haven’t compressed any images in your media library.', 'tiny-compress-images' ), $this->friendly_user_name() );
28
+ echo ' ';
29
+ /* translators: %s: bulk optimization page */
30
+ printf( wp_kses( __( 'If you like you can to optimize your whole library in one go with the %s page.', 'tiny-compress-images' ), array(
31
  'a' => array(
32
  'href' => array(),
33
  ),
34
+ ) ), $link );
35
+ ?>
36
  </p>
37
  </div>
38
  <div class="description half-optimized">
39
  <p>
40
+ <?php
41
+ /* translators: %s: friendly user name */
42
+ printf( esc_html__( '%s, you are doing good.', 'tiny-compress-images' ), $this->friendly_user_name() );
43
+ echo ' ';
44
+ /* translators: %s: number of optimizable sizes and number of uploaded images */
45
+ printf( esc_html__( 'With your current settings you can still optimize %1$s image sizes from your %2$s uploaded JPEG and PNG images.', 'tiny-compress-images' ), '<span id="unoptimised-sizes"></span>', '<span id="uploaded-images"></span>' );
46
+ echo ' ';
47
+ /* translators: %s: bulk optimization link */
48
+ printf( wp_kses( __( 'Start the %s to optimize the remainder of your library.', 'tiny-compress-images' ), array(
49
  'a' => array(
50
  'href' => array(),
51
  ),
52
+ ) ), $link );
53
+ ?>
54
  </p>
55
  </div>
56
  <div class="description full-optimized">
57
+ <p>
58
+ <?php
59
+ /* translators: %s: friendly user name */
60
+ printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() );
61
+ ?>
62
+ </p>
63
  </div>
64
  <div class="description" id="ie8-compressed">
65
  <p>
66
+ <?php
67
+ /* translators: %s: savings percentage */
68
+ printf( wp_kses( __( 'You have <strong>saved %s</strong> of your media library size.', 'tiny-compress-images' ), array(
69
  'span' => array(),
70
  'strong' => array(),
71
+ ) ), '<span></span>%' );
72
+ ?>
73
  </p>
74
  </div>
75
 
src/views/settings.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <h1><?php esc_html_e( 'Compress JPEG & PNG images', 'tiny-compress-images' ) ?></h2>
3
+ <p><?php esc_html_e( 'Speed up your website. Optimize your JPEG and PNG images automatically with TinyPNG.', 'tiny-compress-images' ) ?></p>
4
+
5
+ <div class="tiny-compress-images">
6
+ <span id="tiny-compress-images"></span>
7
+ <form action="<?php echo esc_url( admin_url( 'options.php' ) ); ?>" id="tinify-settings" method="post">
8
+ <?php settings_fields( 'tinify' ) ?>
9
+ <table class="form-table tinify-settings">
10
+ <tbody>
11
+ <tr>
12
+ <th scope="row"><?php esc_html_e( 'Tinify account', 'tiny-compress-images' ) ?></th>
13
+ <td>
14
+ <?php $this->render_pending_status() ?>
15
+ </td>
16
+ </tr>
17
+ <tr>
18
+ <th scope="row"><?php esc_html_e( 'New image uploads', 'tiny-compress-images' ) ?></th>
19
+ <td>
20
+ <?php $this->render_compression_timing_settings() ?>
21
+ </td>
22
+ </tr>
23
+ <tr>
24
+ <th scope="row"><?php esc_html_e( 'Image sizes', 'tiny-compress-images' ) ?></th>
25
+ <td>
26
+ <h4><?php esc_html_e( 'Select image sizes to be compressed', 'tiny-compress-images' ) ?></h4>
27
+ <p class="intro">
28
+ <?php
29
+ esc_html_e(
30
+ 'Wordpress generates resized versions of every image. Choose which sizes to compress.',
31
+ 'tiny-compress-images'
32
+ )
33
+ ?>
34
+ </p>
35
+ <div class="sizes">
36
+ <?php $this->render_sizes() ?>
37
+ </div>
38
+ </td>
39
+ </tr>
40
+ <tr>
41
+ <th scope="row"><?php esc_html_e( 'Original image', 'tiny-compress-images' ) ?></th>
42
+ <td>
43
+ <?php $this->render_resize() ?>
44
+ </td>
45
+ </tr>
46
+ </tbody>
47
+ </table>
48
+ <p class="submit">
49
+ <input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_html_e( 'Save Changes' ) ?>">
50
+ </p>
51
+ </form>
52
+ </div>
53
+ </div>
tiny-compress-images.php CHANGED
@@ -2,7 +2,7 @@
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: 2.2.6
6
  * Author: TinyPNG
7
  * Author URI: https://tinypng.com
8
  * Text Domain: tiny-compress-images
@@ -14,6 +14,7 @@ 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-image-size.php';
18
  require dirname( __FILE__ ) . '/src/class-tiny-image.php';
19
  require dirname( __FILE__ ) . '/src/class-tiny-settings.php';
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: 3.0.0
6
  * Author: TinyPNG
7
  * Author URI: https://tinypng.com
8
  * Text Domain: tiny-compress-images
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-bulk-optimization.php';
18
  require dirname( __FILE__ ) . '/src/class-tiny-image-size.php';
19
  require dirname( __FILE__ ) . '/src/class-tiny-image.php';
20
  require dirname( __FILE__ ) . '/src/class-tiny-settings.php';