diff --git a/src/class-tiny-notices.php b/src/class-tiny-notices.php index fce2979..f62391a 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' ) ); + } + } + + private function feedback_notice_show() { + include __DIR__ . '/views/notice-feedback.php'; + } } 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/notice-feedback.php b/src/views/notice-feedback.php new file mode 100644 index 0000000..813a909 --- /dev/null +++ b/src/views/notice-feedback.php @@ -0,0 +1,16 @@ +%s', + esc_url( $review_url ), + esc_html__( 'Leave a review', 'tiny-compress-images' ) +); +?> + +
\ No newline at end of file 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/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' ) ); + } + +}