Skip to content

Commit 80f31a5

Browse files
author
Edwin Westerhoud
committed
Persist admin notices and add notice when monthly limit is reached.
1 parent 37544f6 commit 80f31a5

9 files changed

Lines changed: 164 additions & 42 deletions

File tree

src/class-tiny-compress.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,34 @@
2020

2121
abstract class Tiny_Compress {
2222
protected $api_key;
23-
protected $count_callback;
23+
protected $after_compress_callback;
2424

2525
public static function get_ca_file() {
2626
return dirname(__FILE__) . '/cacert.pem';
2727
}
2828

29-
public static function get_compressor($api_key, $count_callback=null) {
29+
public static function get_compressor($api_key, $after_compress_callback=null) {
3030
if (Tiny_PHP::is_curl_available()) {
31-
return new Tiny_Compress_Curl($api_key, $count_callback);
31+
return new Tiny_Compress_Curl($api_key, $after_compress_callback);
3232
} elseif (Tiny_PHP::is_fopen_available()) {
33-
return new Tiny_Compress_Fopen($api_key, $count_callback);
33+
return new Tiny_Compress_Fopen($api_key, $after_compress_callback);
3434
}
3535
throw new Tiny_Exception('No HTTP client is available (cURL or fopen)', 'NoHttpClient');
3636
}
3737

38-
protected function __construct($api_key, $count_callback) {
38+
protected function __construct($api_key, $after_compress_callback) {
3939
$this->api_key = $api_key;
40-
$this->count_callback = $count_callback;
40+
$this->after_compress_callback = $after_compress_callback;
4141
}
4242

4343
abstract protected function shrink($input);
4444
abstract protected function output($url);
4545

4646
public function get_status() {
4747
list($details, $headers) = $this->shrink(null);
48-
$this->update_compression_count($headers);
49-
if ($details["error"] == 'InputMissing') {
48+
49+
$this->call_after_compress_callback($details, $headers);
50+
if ($details["error"] == 'InputMissing' || $details["error"] == 'TooManyRequests') {
5051
return Tiny_Compressor_Status::Green;
5152
} else {
5253
return Tiny_Compressor_Status::Red;
@@ -55,7 +56,7 @@ public function get_status() {
5556

5657
public function compress($input) {
5758
list($details, $headers) = $this->shrink($input);
58-
$this->update_compression_count($headers);
59+
$this->call_after_compress_callback($details, $headers);
5960
$outputUrl = $headers["Location"];
6061
if (isset($details['error']) && $details['error']) {
6162
throw new Tiny_Exception($details['message'], $details['error']);
@@ -78,9 +79,9 @@ public function compress_file($file) {
7879
return $details;
7980
}
8081

81-
protected function update_compression_count($headers) {
82-
if ($this->count_callback && isset($headers["Compression-Count"])) {
83-
call_user_func($this->count_callback, $headers["Compression-Count"]);
82+
protected function call_after_compress_callback($details, $headers) {
83+
if ($this->after_compress_callback) {
84+
call_user_func($this->after_compress_callback, $details, $headers);
8485
}
8586
}
8687

src/class-tiny-plugin.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ class Tiny_Plugin extends Tiny_WP_Base {
2323
const MEDIA_COLUMN_HEADER = 'Compression';
2424

2525
private $settings;
26-
private $compressor;
2726

2827
public static function jpeg_quality() {
2928
return 95;
@@ -32,11 +31,10 @@ public static function jpeg_quality() {
3231
public function __construct() {
3332
parent::__construct();
3433
$this->settings = new Tiny_Settings();
35-
$this->compressor = $this->settings->get_compressor();
3634
}
3735

3836
public function set_compressor($compressor) {
39-
$this->compressor = $compressor;
37+
$this->settings->set_compressor($compressor);
4038
}
4139

4240
public function init() {
@@ -72,7 +70,7 @@ public function compress_attachment($metadata, $attachment_id) {
7270
$mime_type = get_post_mime_type($attachment_id);
7371
$tiny_metadata = new Tiny_Metadata($attachment_id);
7472

75-
if ($this->compressor === null || strpos($mime_type, 'image/') !== 0) {
73+
if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) {
7674
return $metadata;
7775
}
7876

@@ -84,7 +82,7 @@ public function compress_attachment($metadata, $attachment_id) {
8482

8583
if ($settings[Tiny_Metadata::ORIGINAL]['tinify'] && !$tiny_metadata->is_compressed()) {
8684
try {
87-
$response = $this->compressor->compress_file("$prefix${path_info['basename']}");
85+
$response = $this->settings->get_compressor()->compress_file("$prefix${path_info['basename']}");
8886
$tiny_metadata->add_response($response);
8987
} catch (Tiny_Exception $e) {
9088
$tiny_metadata->add_exception($e);
@@ -94,7 +92,7 @@ public function compress_attachment($metadata, $attachment_id) {
9492
foreach ($metadata['sizes'] as $size => $info) {
9593
if (isset($settings[$size]) && $settings[$size]['tinify'] && !$tiny_metadata->is_compressed($size)) {
9694
try {
97-
$response = $this->compressor->compress_file("$prefix${info['file']}");
95+
$response = $this->settings->get_compressor()->compress_file("$prefix${info['file']}");
9896
$tiny_metadata->add_response($response, $size);
9997
} catch (Tiny_Exception $e) {
10098
$tiny_metadata->add_exception($e, $size);

src/class-tiny-settings.php

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,21 @@
1919
*/
2020

2121
class Tiny_Settings extends Tiny_WP_Base {
22-
const PREFIX = 'tinypng_';
2322
const DUMMY_SIZE = '_tiny_dummy';
2423

25-
protected static function get_prefixed_name($name) {
26-
return self::PREFIX . $name;
27-
}
28-
2924
private $sizes;
3025
private $tinify_sizes;
3126
private $compressor;
3227

33-
public function __construct() {
34-
parent::__construct();
28+
public function admin_init() {
29+
parent::admin_init();
30+
3531
try {
36-
$this->compressor = Tiny_Compress::get_compressor($this->get_api_key(), $this->get_method('set_compression_count'));
32+
$this->compressor = Tiny_Compress::get_compressor($this->get_api_key(), $this->get_method('after_compress_callback'));
3733
} catch (Tiny_Exception $e) {
38-
$this->add_admin_notice(self::translate_escape($e->getMessage()));
34+
$this->add_admin_notice('compressor_exception', self::translate_escape($e->getMessage()), true);
3935
}
40-
}
4136

42-
public function admin_init() {
4337
$section = self::get_prefixed_name('settings');
4438
add_settings_section($section, self::translate('PNG and JPEG compression'), $this->get_method('render_section'), 'media');
4539

@@ -63,11 +57,14 @@ public function get_status() {
6357
exit();
6458
}
6559

66-
6760
public function get_compressor() {
6861
return $this->compressor;
6962
}
7063

64+
public function set_compressor($compressor) {
65+
$this->compressor = $compressor;
66+
}
67+
7168
protected function get_api_key() {
7269
if (defined('TINY_API_KEY')) {
7370
return TINY_API_KEY;
@@ -188,9 +185,18 @@ public function get_compression_count() {
188185
return get_option($field);
189186
}
190187

191-
public function set_compression_count($new_count) {
192-
$field = self::get_prefixed_name('status');
193-
update_option($field, $new_count);
188+
public function after_compress_callback($details, $headers) {
189+
if(isset($headers["Compression-Count"])) {
190+
$field = self::get_prefixed_name('status');
191+
update_option($field, $headers["Compression-Count"]);
192+
193+
if (isset($details['error']) && $details['error'] == 'TooManyRequests') {
194+
$link = '<a href="https://tinypng.com/developers" target="_blank">' . self::translate_escape('TinyPNG API subscription') . '</a>';
195+
$this->add_admin_notice('limit_reached', sprintf(self::translate_escape('You have reached your limit of %s compressions this month. Upgrade your %s if you like to compress more images') . '.', $headers["Compression-Count"], $link));
196+
} else {
197+
$this->remove_admin_notice('limit_reached');
198+
}
199+
}
194200
}
195201

196202
public function render_status() {
@@ -199,25 +205,23 @@ public function render_status() {
199205
echo '<p><img src="images/yes.png"> ' . self::translate_escape('API connection successful') . '</p>';
200206
break;
201207
case Tiny_Compressor_Status::Yellow:
202-
echo '<p>' . self::translate_escape('API status could not be checked, enable cURL for more information.') . '</p>';
208+
echo '<p>' . self::translate_escape('API status could not be checked, enable cURL for more information') . '.</p>';
203209
return;
204210
case Tiny_Compressor_Status::Red:
205211
echo '<p><img src="images/no.png"> ' . self::translate_escape('API connection unsuccessful') . '</p>';
206212
return;
207213
}
208214

209-
210215
$compressions = self::get_compression_count();
211216
echo '<p>';
212217
// We currently have no way to check if a user is free or flexible.
213218
if ($compressions == 500) {
214219
$link = '<a href="https://tinypng.com/developers" target="_blank">' . self::translate_escape('TinyPNG API subscription') . '</a>';
215-
printf('You have reached your limit of 500 compressions this month' . '.');
220+
printf(self::translate_escape('You have reached your limit of %s compressions this month') . '.', $compressions);
216221
echo '<br>';
217-
printf(self::translate_escape('If you need to compress more images you can change your %s' . '.'), $link);
218-
}
219-
else {
220-
printf('You have made %s compressions this month' . '.', self::get_compression_count());
222+
printf(self::translate_escape('If you need to compress more images you can change your %s') . '.', $link);
223+
} else {
224+
printf(self::translate_escape('You have made %s compressions this month') . '.', self::get_compression_count());
221225
}
222226
echo '</p>';
223227
}

src/class-tiny-wp-base.php

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
abstract class Tiny_WP_Base {
2222
const NAME = 'tiny-compress-images';
23+
const PREFIX = 'tinypng_';
24+
2325

2426
public static function plugin_version() {
2527
$plugin_data = get_plugin_data(dirname(__FILE__) . '/../tiny-compress-images.php');
@@ -30,6 +32,10 @@ public static function plugin_identification() {
3032
return 'Wordpress/' . $GLOBALS['wp_version'] . ' Tiny/' . self::plugin_version();
3133
}
3234

35+
protected static function get_prefixed_name($name) {
36+
return self::PREFIX . $name;
37+
}
38+
3339
protected static function translate($phrase) {
3440
return translate($phrase, self::NAME);
3541
}
@@ -55,9 +61,63 @@ public function init() {
5561
}
5662

5763
public function admin_init() {
64+
if (!current_user_can('manage_options')) {
65+
return;
66+
}
67+
68+
$notices_name = self::get_prefixed_name('admin_notices');
69+
$notices = get_option($notices_name);
70+
71+
if ($notices) {
72+
$user_id = wp_get_current_user()->ID;
73+
74+
foreach ($notices as $name => $message) {
75+
if (isset($_GET[$name]) && $_GET[$name] == 0) {
76+
add_user_meta($user_id, $name, 'true', true);
77+
continue;
78+
}
79+
80+
if (!get_user_meta($user_id, $name)) {
81+
$this->show_admin_notice($name, $message);
82+
}
83+
}
84+
}
85+
}
86+
87+
public function add_admin_notice($name, $message, $force = false) {
88+
$name = self::get_prefixed_name($name);
89+
$notices_name = self::get_prefixed_name('admin_notices');
90+
$notices = get_option($notices_name);
91+
92+
if (!$notices) {
93+
$notices = array();
94+
}
95+
$notices[$name] = $message;
96+
update_option($notices_name, $notices);
97+
98+
if ($force) {
99+
$user_id = wp_get_current_user()->ID;
100+
delete_user_meta($user_id, $name);
101+
}
102+
}
103+
104+
public function remove_admin_notice($name) {
105+
$name = self::get_prefixed_name($name);
106+
$notices_name = self::get_prefixed_name('admin_notices');
107+
$notices = get_option($notices_name);
108+
unset($notices[$name]);
109+
110+
if ($notices) {
111+
update_option($notices_name, $notices);
112+
} else {
113+
delete_option($notices_name);
114+
}
115+
116+
$user_id = wp_get_current_user()->ID;
117+
delete_user_meta($user_id, $name);
58118
}
59119

60-
public function add_admin_notice($message) {
61-
add_action('admin_notices', create_function('', "echo '<div class=\"error\"><p>Tiny Compress Images: $message</p></div>';"));
120+
private function show_admin_notice($name, $message) {
121+
add_action('admin_notices', create_function('', "echo '<div class=\"error\"><p>Tiny Compress Images: $message | <a href=\"?$name=0\">Dismiss</a></p></div>';"));
62122
}
63123
}
1.04 KB
Binary file not shown.

src/languages/tiny-compress-images-nl_NL.po

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,30 @@ msgstr "Kon de metadata niet vinden van het bestand"
102102

103103
msgid "The API key has been configured in %s"
104104
msgstr "De API-sleutel is geconfigureerd in %s"
105+
106+
msgid "Connection status"
107+
msgstr "Verbinding status"
108+
109+
msgid "TinyPNG API subscription"
110+
msgstr "TinyPNG API subscription"
111+
112+
msgid "API connection successful"
113+
msgstr "API-verbinding succesvol"
114+
115+
msgid "API connection unsuccessful"
116+
msgstr "API-verbinding onsuccesvol"
117+
118+
msgid "API status could not be checked, enable cURL for more information"
119+
msgstr "API-status kon niet worden gecontroleerd, schakel cURL in voor meer informatie"
120+
121+
msgid "You have made %s compressions this month"
122+
msgstr "Je hebt deze maand %s compressies gedaan"
123+
124+
msgid "You have reached your limit of %s compressions this month"
125+
msgstr "Je hebt je maandelijkse limiet van %s compressies bereikt"
126+
127+
msgid "If you need to compress more images you can change your %s"
128+
msgstr "Als je meer plaatjes wilt comprimeren kun je je %s aanpassen"
129+
130+
msgid "You have reached your limit of %s compressions this month. Upgrade your %s if you like to compress more images"
131+
msgstr "Je hebt je maandelijkse limiet van %s compressies bereikt. Upgrade je %s als je meer plaatjes wilt comprimeren"

test/helpers/wordpress.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function __construct() {
5656
$this->addMethod('wp_upload_dir');
5757
$this->addMethod('plugin_basename');
5858
$this->addMethod('is_multisite');
59+
$this->addMethod('current_user_can');
5960
$this->defaults();
6061
}
6162

test/integration/CompressIntegrationTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,22 @@ public function testShrink() {
3131
$this->upload_image(dirname(__FILE__) . '/../fixtures/example-tinypng.png');
3232
$this->assertContains('Compressed size', self::$driver->findElement(WebDriverBy::cssSelector('td.tiny-compress-images'))->getText());
3333
}
34+
35+
public function testLimitReached() {
36+
$this->set_api_key('LIMIT123');
37+
$this->upload_image(dirname(__FILE__) . '/../fixtures/example-tinypng.png');
38+
$elements = self::$driver->findElement(WebDriverBy::className('error'))->findElements(WebDriverBy::tagName('p'));
39+
$error_messages = array_map('innerText', $elements);
40+
$this->assertContains('Tiny Compress Images: You have reached your limit of 500 compressions this month. Upgrade your TinyPNG API subscription if you like to compress more images. | Dismiss', $error_messages);
41+
}
42+
43+
public function testLimitReachedDismisses() {
44+
$this->set_api_key('LIMIT123');
45+
$this->upload_image(dirname(__FILE__) . '/../fixtures/example-tinypng.png');
46+
$dismiss_links = self::$driver->findElements(WebDriverBy::xpath('//a[contains(@href, "tinypng_limit_reached=0")]'));
47+
$dismiss_links[0]->click();
48+
$elements = self::$driver->findElement(WebDriverBy::className('error'))->findElements(WebDriverBy::tagName('p'));
49+
$error_messages = array_map('innerText', $elements);
50+
$this->assertNotContains('Tiny Compress Images: You have reached your limit of 500 compressions this month. Upgrade your TinyPNG API subscription if you like to compress more images. | Dismiss', $error_messages);
51+
}
3452
}

test/mock-tinypng-webservice/shrink.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ function mock_fail_status_response() {
4646
return json_encode($response);
4747
}
4848

49+
function mock_limit_reached_response() {
50+
header("Content-Type: application/json; charset=utf-8");
51+
header("Compression-Count: 500");
52+
53+
$response = array(
54+
"error" => "TooManyRequests",
55+
"message" => "Your monthly limit has been exceeded"
56+
);
57+
return json_encode($response);
58+
}
59+
4960
$request_headers = apache_request_headers();
5061
$basic_auth = base64_decode(str_replace('Basic ', '', $request_headers['Authorization']));
5162
$api_key_elements = explode(':', $basic_auth);
@@ -60,6 +71,8 @@ function mock_fail_status_response() {
6071
print_r(mock_ok_status_response());
6172
} else if ($api_key == 'INVALID123') {
6273
print_r(mock_fail_status_response());
74+
} else if ($api_key == 'LIMIT123') {
75+
print_r(mock_limit_reached_response());
6376
} else {
6477
header('HTTP/1.1 401 Unauthorized');
6578
print_r(json_encode(array(

0 commit comments

Comments
 (0)