diff --git a/src/class-tiny-notices.php b/src/class-tiny-notices.php
index fce2979..eae648d 100644
--- a/src/class-tiny-notices.php
+++ b/src/class-tiny-notices.php
@@ -22,6 +22,30 @@ class Tiny_Notices extends Tiny_WP_Base {
private $notices;
private $dismissals;
+ /**
+ * Tiny_Settings instance.
+ *
+ * @var Tiny_Settings
+ */
+ private $settings;
+
+ /**
+ * The number of compressions required before showing the feedback notice.
+ *
+ * @var int
+ */
+ private $compressions_for_feedback = 10;
+
+ /**
+ * Tiny_Notices constructor.
+ *
+ * @param Tiny_Settings $settings The settings instance.
+ */
+ public function __construct( $settings ) {
+ parent::__construct();
+ $this->settings = $settings;
+ }
+
protected static $incompatible_plugins = array(
'CheetahO Image Optimizer' => 'cheetaho-image-optimizer/cheetaho.php',
'EWWW Image Optimizer' => 'ewww-image-optimizer/ewww-image-optimizer.php',
@@ -102,6 +126,7 @@ private function show_stored() {
public function show_notices() {
$this->incompatible_plugins_notice();
$this->outdated_platform_notice();
+ $this->feedback_notice();
}
public function add( $name, $message ) {
@@ -303,4 +328,21 @@ function () use ( $notice ) {
}
);
}
+
+ /**
+ * Checks if the feedback notice should be displayed and hooks it to admin_notices.
+ *
+ * @return void
+ */
+ private function feedback_notice() {
+ if ( ! isset( $this->dismissals['feedback'] ) &&
+ $this->settings->get_compression_count() > $this->compressions_for_feedback
+ ) {
+ add_action( 'admin_notices', array( $this, 'feedback_notice_show' ) );
+ }
+ }
+
+ public function feedback_notice_show() {
+ include __DIR__ . '/views/notice-feedback.php';
+ }
}
diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php
index 2236332..facff18 100644
--- a/src/class-tiny-plugin.php
+++ b/src/class-tiny-plugin.php
@@ -861,18 +861,6 @@ public function clean_attachment( $post_id ) {
$tiny_image->delete_converted_image();
}
- public static function request_review() {
- $review_url =
- 'https://wordpress.org/support/plugin/tiny-compress-images/reviews/#new-post';
- $review_block = esc_html__( 'Enjoying TinyPNG?', 'tiny-compress-images' );
- $review_block .= ' ';
- $review_block .= sprintf(
- '%s',
- esc_url( $review_url ),
- esc_html__( 'Write a review', 'tiny-compress-images' )
- );
- return $review_block;
- }
public function mark_image_as_compressed() {
$response = $this->validate_ajax_attachment_request();
diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php
index 290b8b0..d19e876 100644
--- a/src/class-tiny-settings.php
+++ b/src/class-tiny-settings.php
@@ -29,7 +29,7 @@ class Tiny_Settings extends Tiny_WP_Base {
public function __construct() {
parent::__construct();
- $this->notices = new Tiny_Notices();
+ $this->notices = new Tiny_Notices( $this );
new Tiny_Diagnostics( $this );
}
diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php
index 3ab5b62..109afe3 100644
--- a/src/views/bulk-optimization.php
+++ b/src/views/bulk-optimization.php
@@ -55,6 +55,8 @@
} elseif ( 0 == $stats['available-unoptimized-sizes'] ) {
/* translators: %s: friendly user name */
printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() );
+ echo '
';
+ require __DIR__ . '/request-review.php';
} elseif ( $stats['optimized-image-sizes'] > 0 ) {
if ( $percentage_of_files > 75 ) {
/* translators: %s: friendly user name */
diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php
index fadab1e..2441757 100644
--- a/src/views/dashboard-widget.php
+++ b/src/views/dashboard-widget.php
@@ -72,7 +72,7 @@
/* translators: %s: friendly user name */
printf( esc_html__( '%s, this is great! Your entire library is optimized!', 'tiny-compress-images' ), $this->friendly_user_name() );
echo ' ';
- echo Tiny_Plugin::request_review();
+ require __DIR__ . '/request-review.php';
?>
diff --git a/test/helpers/wordpress.php b/test/helpers/wordpress.php index ff1b2c0..45e2406 100644 --- a/test/helpers/wordpress.php +++ b/test/helpers/wordpress.php @@ -337,6 +337,34 @@ public function getTestMetadata($path = '14/01', $name = 'test') * @param mixed $expected_args arguments to the hook */ public static function assertHook($hookname, $expected_args = null) + { + $found = self::findHook($hookname, $expected_args); + + $message = is_null($expected_args) + ? sprintf('Expected hook "%s" to be called.', $hookname) + : sprintf('Expected hook "%s" to be called with the given arguments.', $hookname); + + Assert::assertTrue($found, $message); + } + + /** + * Testhelper to assert a hook has NOT been registered. + * + * @param string $hookname name of the filter or action + * @param mixed $expected_args arguments to the hook + */ + public static function assertNotHook($hookname, $expected_args = null) + { + $found = self::findHook($hookname, $expected_args); + + $message = is_null($expected_args) + ? sprintf('Expected hook "%s" NOT to be called.', $hookname) + : sprintf('Expected hook "%s" NOT to be called with the given arguments.', $hookname); + + Assert::assertFalse($found, $message); + } + + private static function findHook($hookname, $expected_args = null) { $hooks = array('add_action', 'add_filter'); $found = false; @@ -363,11 +391,7 @@ public static function assertHook($hookname, $expected_args = null) } } - $message = is_null($expected_args) - ? sprintf('Expected hook "%s" to be called.', $hookname) - : sprintf('Expected hook "%s" to be called with the given arguments.', $hookname); - - Assert::assertTrue($found, $message); + return $found; } } diff --git a/test/integration/compression.spec.ts b/test/integration/compression.spec.ts index 140d7d0..711ef28 100644 --- a/test/integration/compression.spec.ts +++ b/test/integration/compression.spec.ts @@ -220,7 +220,7 @@ test.describe('compression', () => { // Since 4.2 it is no longer a link but a button. const isButton = WPVersion >= 4.2; if (isButton) { - await page.getByRole('button', { name: 'Dismiss this notice.' }).click(); + await page.locator('.error.notice').getByRole('button', { name: 'Dismiss this notice.' }).click(); } else { await page.getByRole('link', { name: 'Dismiss' }).click(); } diff --git a/test/integration/utils.ts b/test/integration/utils.ts index 25ca8fd..8ee8a1b 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -202,7 +202,7 @@ export async function deactivatePlugin(page: Page, pluginSlug: string) { await plugin.getByLabel('Deactivate').click(); } -export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif'; delivery: 'picture' | 'htaccess' }) { +export async function setConversionSettings(page: Page, settings: { convert: boolean; output?: 'smallest' | 'webp' | 'avif'; delivery?: 'picture' | 'htaccess' }) { await page.goto('/wp-admin/options-general.php?page=tinify'); if (settings.convert) { diff --git a/test/unit/TinySettingsAjaxTest.php b/test/unit/TinySettingsAjaxTest.php index 40fb44b..1e05c81 100644 --- a/test/unit/TinySettingsAjaxTest.php +++ b/test/unit/TinySettingsAjaxTest.php @@ -4,6 +4,7 @@ class Tiny_Settings_Ajax_Test extends Tiny_TestCase { protected $notices; + private $settings; public function set_up() { parent::set_up(); @@ -12,7 +13,8 @@ public function set_up() { public function test_settings_ajax_init() { $tiny_settings = new Tiny_Settings(); - $tiny_settings->ajax_init(); + $this->settings = $tiny_settings; + $this->settings->ajax_init(); WordPressStubs::assertHook('wp_ajax_tiny_image_sizes_notice', array( $tiny_settings, 'image_sizes_notice' )); WordPressStubs::assertHook('wp_ajax_tiny_account_status', array( $tiny_settings, 'account_status' )); @@ -21,7 +23,7 @@ public function test_settings_ajax_init() { } public function test_notices_ajax_init() { - $tiny_notices = new Tiny_Notices(); + $tiny_notices = new Tiny_Notices( $this->settings ); $tiny_notices->ajax_init(); WordPressStubs::assertHook('wp_ajax_tiny_dismiss_notice', array( $tiny_notices, 'dismiss' )); diff --git a/test/unit/Tiny_Notices_Test.php b/test/unit/Tiny_Notices_Test.php new file mode 100644 index 0000000..bccbc99 --- /dev/null +++ b/test/unit/Tiny_Notices_Test.php @@ -0,0 +1,86 @@ +wp->addMethod( 'get_user_meta' ); + $this->wp->addMethod( 'update_user_meta' ); + $this->wp->addMethod( 'get_current_user_id' ); + + $this->settings = $this->createMock( Tiny_Settings::class ); + $this->settings->method( 'get_compression_count' )->willReturn( 0 ); + + $this->wp->stub( 'current_user_can', function () { + return true; + } ); + + $this->subject = new Tiny_Notices( $this->settings ); + } + + /** + * Verifies that when the current user has the manage_options capability, + * calling admin_init() registers at least one admin_notices action. + */ + public function test_registers_notices_when_user_can_manage_options() { + $this->subject->add( 'test', 'Test notice message' ); + + $this->subject->admin_init(); + + WordPressStubs::assertHook( 'admin_notices' ); + } + + /** + * Verifies that feedback_notice_show is hooked to admin_notices when the + * feedback notice has not been dismissed + */ + public function test_registers_feedback_notice_when_not_dismissed() { + $this->settings = $this->createMock( Tiny_Settings::class ); + $this->settings->method( 'get_compression_count' )->willReturn( 20 ); + $this->subject = new Tiny_Notices( $this->settings ); + + $this->subject->show_notices(); + + WordPressStubs::assertHook( 'admin_notices', array( $this->subject, 'feedback_notice_show' ) ); + } + + /** + * Verifies that feedback_notice_show is hooked to admin_notices when the + * compression count is just above compressions_for_feedback + */ + public function test_registers_feedback_notice_when_compressioncount_reached() { + $this->settings = $this->createMock( Tiny_Settings::class ); + $this->settings->method( 'get_compression_count' )->willReturn( 11 ); + $this->subject = new Tiny_Notices( $this->settings ); + + $this->subject->show_notices(); + + WordPressStubs::assertHook( 'admin_notices', array( $this->subject, 'feedback_notice_show' ) ); + } + + + /** + * Verifies that feedback_notice_show is NOT hooked to admin_notices when + * the feedback notice has been dismissed by the user. + */ + public function test_will_not_show_feedback_notice_when_dismissed() { + $this->settings = $this->createMock( Tiny_Settings::class ); + $this->subject = new Tiny_Notices( $this->settings ); + + $this->wp->stub( 'get_user_meta', function () { + return array( 'feedback' => true ); + } ); + + $this->subject->admin_init(); + + WordPressStubs::assertNotHook( 'admin_notices', array( $this->subject, 'feedback_notice_show' ) ); + } + +}