Skip to content

Commit 0e73187

Browse files
committed
fix: resets the register when the container is changed
1 parent 99e92b5 commit 0e73187

File tree

2 files changed

+226
-1
lines changed

2 files changed

+226
-1
lines changed

src/AdminNotices.php

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class AdminNotices
2424
/**
2525
* @var string used in actions, filters, and data storage
2626
*/
27-
protected static $namespace = '';
27+
protected static $namespace;
2828

2929
/**
3030
* @var string the URL to the package, used for enqueuing scripts
@@ -89,6 +89,18 @@ public static function removeNotice(string $notificationId): void
8989
public static function setContainer(ContainerInterface $container): void
9090
{
9191
self::$container = $container;
92+
self::$registrar = null;
93+
}
94+
95+
/**
96+
* Removes the container so the register will be stored locally
97+
*
98+
* @since 1.0.0
99+
*/
100+
public static function removeContainer(): void
101+
{
102+
self::$container = null;
103+
self::$registrar = null;
92104
}
93105

94106
/**
@@ -100,6 +112,10 @@ public static function setContainer(ContainerInterface $container): void
100112
*/
101113
public static function initialize(string $namespace, string $pluginUrl): void
102114
{
115+
if (empty($namespace)) {
116+
throw new RuntimeException('Namespace must be provided');
117+
}
118+
103119
self::$packageUrl = $pluginUrl;
104120
self::$namespace = $namespace;
105121

@@ -119,6 +135,52 @@ public static function getNotices(): array
119135
return self::getRegistrar()->getNotices();
120136
}
121137

138+
/**
139+
* Rests a dismissed notice for a given user so the notice will be shown again
140+
*
141+
* @since 1.0.0
142+
*/
143+
public static function resetNoticeForUser(string $notificationId, int $userId): void
144+
{
145+
global $wpdb;
146+
147+
$preferencesKey = $wpdb->get_blog_prefix() . 'persisted_preferences';
148+
$preferences = get_user_meta($userId, $preferencesKey, true);
149+
150+
$notificationKey = self::$namespace . '/' . $notificationId;
151+
if (isset($preferences['stellarwp/admin-notices'][$notificationKey])) {
152+
unset($preferences['stellarwp/admin-notices'][$notificationKey]);
153+
update_user_meta($userId, $preferencesKey, $preferences);
154+
}
155+
}
156+
157+
/**
158+
* Resets all dismissed notices for a given user so all notices will be shown again
159+
*
160+
* @since 1.0.0
161+
*/
162+
public static function resetAllNoticesForUser(int $userId): void
163+
{
164+
global $wpdb;
165+
166+
$preferencesKey = $wpdb->get_blog_prefix() . 'persisted_preferences';
167+
$preferences = get_user_meta($userId, $preferencesKey, true);
168+
169+
if (isset($preferences['stellarwp/admin-notices'])) {
170+
$preferenceRemoved = false;
171+
foreach ($preferences['stellarwp/admin-notices'] as $key => $value) {
172+
if (strpos($key, self::$namespace . '/') === 0) {
173+
unset($preferences['stellarwp/admin-notices'][$key]);
174+
$preferenceRemoved = true;
175+
}
176+
}
177+
178+
if ($preferenceRemoved) {
179+
update_user_meta($userId, $preferencesKey, $preferences);
180+
}
181+
}
182+
}
183+
122184
/**
123185
* Hook action to display the notices in the admin
124186
*
@@ -129,6 +191,11 @@ public static function setUpNotices(): void
129191
(new DisplayNoticesInAdmin())(...self::getNotices());
130192
}
131193

194+
/**
195+
* Hook action to enqueue the scripts needed for dismissing notices
196+
*
197+
* @since 1.0.0
198+
*/
132199
public static function enqueueScripts(): void
133200
{
134201
// use the version from the composer.json file

tests/unit/AdminNoticesTest.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use StellarWP\AdminNotices\AdminNotice;
6+
use StellarWP\AdminNotices\AdminNotices;
7+
use StellarWP\AdminNotices\Contracts\NotificationsRegistrarInterface;
8+
use StellarWP\AdminNotices\Tests\Support\Helper\TestCase;
9+
use StellarWP\AdminNotices\Tests\Support\Traits\WithUopz;
10+
11+
/**
12+
* @coversDefaultClass \StellarWP\AdminNotices\AdminNotices
13+
*/
14+
class AdminNoticesTest extends TestCase
15+
{
16+
use WithUopz;
17+
18+
/**
19+
* @covers ::show
20+
*
21+
* @since 1.0.0
22+
*/
23+
public function testShouldRegisterAdminNotice()
24+
{
25+
$mockRegistrar = $this->createMock(NotificationsRegistrarInterface::class);
26+
$mockRegistrar
27+
->expects($this->once())
28+
->method('registerNotice')
29+
->with($this->isInstanceOf(StellarWP\AdminNotices\AdminNotice::class));
30+
31+
$this->setUpContainerWithMockRegistrar($mockRegistrar);
32+
33+
$notice = AdminNotices::show('test', 'This is a test message.');
34+
$this->assertInstanceOf(StellarWP\AdminNotices\AdminNotice::class, $notice);
35+
$this->assertEquals('This is a test message.', $notice->getRenderTextOrCallback());
36+
$this->assertSame('/test', $notice->getId());
37+
}
38+
39+
/**
40+
* @covers ::render
41+
*
42+
* @since 1.0.0
43+
*/
44+
public function testShouldRenderAdminNotice()
45+
{
46+
$notice = new AdminNotice('test', 'This is a test message.');
47+
48+
AdminNotices::render($notice);
49+
50+
$this->expectOutputString(
51+
'<div class=\'notice notice-info\' data-notice-id=\'test\'>This is a test message.</div>'
52+
);
53+
}
54+
55+
/**
56+
* @covers ::render
57+
*
58+
* @since 1.0.0
59+
*/
60+
public function testShouldReturnAdminNoticeHtml()
61+
{
62+
$notice = new AdminNotice('test', 'This is a test message.');
63+
64+
$html = AdminNotices::render($notice, false);
65+
66+
$this->assertEquals(
67+
'<div class=\'notice notice-info\' data-notice-id=\'test\'>This is a test message.</div>',
68+
$html
69+
);
70+
}
71+
72+
/**
73+
* @covers ::removeNotice
74+
*
75+
* @since 1.0.0
76+
*/
77+
public function testShouldRemoveNotice()
78+
{
79+
$mockRegistrar = $this->createMock(NotificationsRegistrarInterface::class);
80+
$mockRegistrar
81+
->expects($this->once())
82+
->method('unregisterNotice')
83+
->with('test');
84+
85+
$this->setUpContainerWithMockRegistrar($mockRegistrar);
86+
87+
AdminNotices::removeNotice('test');
88+
}
89+
90+
/**
91+
* @covers ::initialize
92+
*
93+
* @since 1.0.0
94+
*/
95+
public function testInitialize(): void
96+
{
97+
AdminNotices::initialize('test', 'https://example.com');
98+
99+
$this->assertSame(10, has_action('admin_notices', [AdminNotices::class, 'setUpNotices']));
100+
$this->assertSame(10, has_action('admin_enqueue_scripts', [AdminNotices::class, 'enqueueScripts']));
101+
}
102+
103+
/**
104+
* @covers ::initialize
105+
*
106+
* @since 1.0.0
107+
*/
108+
public function testShouldThrowExceptionOnEmptyNamespace()
109+
{
110+
$this->expectException(RuntimeException::class);
111+
$this->expectExceptionMessage('Namespace must be provided');
112+
113+
AdminNotices::initialize('', 'https://example.com');
114+
}
115+
116+
/**
117+
* Adds a container to the AdminNotices class with a mock registrar
118+
*
119+
* @since 1.0.0
120+
*/
121+
private function setUpContainerWithMockRegistrar($mockRegistrar): void
122+
{
123+
AdminNotices::setContainer(new ServiceContainer($mockRegistrar));
124+
}
125+
}
126+
127+
/**
128+
* A simple service container for testing
129+
*
130+
* @since 1.0.0
131+
*/
132+
class ServiceContainer implements Psr\Container\ContainerInterface
133+
{
134+
private $mockRegistrar;
135+
136+
public function __construct($mockRegistrar)
137+
{
138+
$this->mockRegistrar = $mockRegistrar;
139+
}
140+
141+
public function get(string $id)
142+
{
143+
if ($id === NotificationsRegistrarInterface::class) {
144+
return $this->mockRegistrar;
145+
}
146+
147+
throw new RuntimeException('Service not found');
148+
}
149+
150+
public function has(string $id): bool
151+
{
152+
if ($id === NotificationsRegistrarInterface::class) {
153+
return true;
154+
}
155+
156+
throw new RuntimeException('Service not found');
157+
}
158+
}

0 commit comments

Comments
 (0)