Skip to content

Commit f05e69a

Browse files
Feature: rebuild support for custom notices (#9)
1 parent 219e081 commit f05e69a

File tree

12 files changed

+1235
-287
lines changed

12 files changed

+1235
-287
lines changed

README.md

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ Parameters:
7373

7474
1. `string $id` - A unique identifier for the notice.
7575
2. `string|callback $message` - The message to display. This can be a string or a callback that
76-
returns a string
76+
returns a string. The callback receives an instance of the `AdminNotice` class and an instance of
77+
the [NoticeElementProperties](src/DataTransferObjects/NoticeElementProperties.php) class — the
78+
latter of which is useful for custom notices.
7779

7880
```php
7981
use StellarWP\AdminNotices\AdminNotices;
82+
use StellarWP\AdminNotices\AdminNotice;
83+
use \StellarWP\AdminNotices\DataTransferObjects\NoticeElementProperties;
8084

8185
AdminNotices::show('my_notice', 'This is a notice');
82-
AdminNotices::show('my_notice', function () {
86+
AdminNotices::show('my_notice', function (AdminNotice $notice, NoticeElementProperties $elements) {
8387
return 'This is a notice';
8488
});
8589
```
@@ -287,7 +291,7 @@ $notice = AdminNotices::show('my_notice', 'This is a notice')
287291
});
288292
```
289293

290-
## Visual & behavior options
294+
## Standard Notice Visual & behavior options
291295

292296
### `autoParagraph($autoParagraph)`, `withoutAutoParagraph()`
293297

@@ -316,32 +320,6 @@ $notice = AdminNotices::show('my_notice', 'This is a notice')
316320
->withoutAutoParagraph();
317321
```
318322

319-
### `withWrapper($with)`, `withoutWrapper()`
320-
321-
**Default:** true
322-
323-
Sets whether the rendered notice should be wrapped in the standard WordPress notice wrapper.
324-
325-
Parameters:
326-
327-
1. `bool $with = true` - Whether to wrap the notice in the standard WordPress notice wrapper
328-
329-
```php
330-
use StellarWP\AdminNotices\AdminNotices;
331-
332-
// Wrap the notice in the standard WordPress notice wrapper
333-
$notice = AdminNotices::show('my_notice', 'This is a notice')
334-
->withWrapper();
335-
336-
// Do not wrap the notice in the standard WordPress notice wrapper
337-
$notice = AdminNotices::show('my_notice', 'This is a notice')
338-
->withWrapper(false);
339-
340-
// Also has an alias for readability
341-
$notice = AdminNotices::show('my_notice', 'This is a notice')
342-
->withoutWrapper();
343-
```
344-
345323
### `urgency($urgency)`
346324

347325
**Default:** 'info'
@@ -446,6 +424,75 @@ $notice = AdminNotices::show('my_notice', 'This is a notice')
446424
->notDismissible();
447425
```
448426

427+
## Custom Notices
428+
429+
Sometimes you want to display a notice, but you want to completely style it yourself. This is
430+
possible and pretty straightforward to do.
431+
432+
Start by using the `custom` method on the notice. This will disable all standard visual and behavior
433+
434+
```php
435+
use StellarWP\AdminNotices\AdminNotices;
436+
437+
$notice = AdminNotices::show('my_notice_custom', 'This is a notice')
438+
->custom();
439+
```
440+
441+
### `location()`
442+
443+
***Default:*** 'standard'
444+
445+
Sets the location in one of the standard WordPress notice locations. By default, the notice will be
446+
displayed in the standard location.
447+
448+
Parameters:
449+
450+
1. `string $location` - The location to display the notice. Can be 'standard', 'above_header', '
451+
below_header', or 'inline'. Note that 'standard' and 'below_header' are the same location.
452+
453+
```php
454+
use StellarWP\AdminNotices\AdminNotices;
455+
456+
// Display the notice above the header
457+
$notice = AdminNotices::show('my_notice_custom', 'This is a notice')
458+
->custom()
459+
->location('above_header');
460+
```
461+
462+
### Dismissing
463+
464+
The `dismissible` method is not available for custom notices. If you want to add a dismiss button,
465+
you will need to do so manually. Fortunately, there is a simple way to do this.
466+
467+
```php
468+
use StellarWP\AdminNotices\AdminNotices;
469+
use StellarWP\AdminNotices\AdminNotice;
470+
use \StellarWP\AdminNotices\DataTransferObjects\NoticeElementProperties;
471+
472+
$renderCallback = function (AdminNotice $notice, NoticeElementProperties $elements) {
473+
return "
474+
<div>
475+
<p>This is a custom notice</p>
476+
<button type='button' {$elements->closeAttributes()}>
477+
<span class='screen-reader-text'>Dismiss this notice.</span>
478+
</button>
479+
</div>
480+
";
481+
};
482+
483+
AdminNotices::show('my_notice', $renderCallback)
484+
->custom();
485+
```
486+
487+
The [$elements](src/DataTransferObjects/NoticeElementProperties.php) object provides a
488+
`customCloserAttributes` method that returns the necessary attributes to be place on the dismiss
489+
button. This method will add the necessary attributes to dismiss the notice when clicked. This will
490+
permanently dismiss the notice, and fade out the notice, similar to the standard WordPress
491+
dismissible notices.
492+
493+
If you want the notice to be marked as dismissed, but not fade out, you can pass "clear" to the
494+
`customerCloserAttributes` method: e.g. `$elements->customCloserAttributes('clear')`.
495+
449496
## Resetting dismissed notices
450497

451498
For dismissible notices, when the user dismisses the notice, it is permanently dismissed. If you

src/Actions/RenderAdminNotice.php

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
namespace StellarWP\AdminNotices\Actions;
77

88
use StellarWP\AdminNotices\AdminNotice;
9+
use StellarWP\AdminNotices\DataTransferObjects\NoticeElementProperties;
910
use StellarWP\AdminNotices\Traits\HasNamespace;
11+
use WP_HTML_Tag_Processor;
1012

1113
/**
1214
* Renders the admin notice based on the configuration of the notice.
@@ -21,38 +23,51 @@ class RenderAdminNotice
2123
/**
2224
* Renders the admin notice
2325
*
26+
* @unreleased custom notices have a completely different render flow
2427
* @since 1.1.0 added namespacing and notice is passed to the __invoke method
2528
* @since 1.0.0
2629
*/
2730
public function __invoke(AdminNotice $notice): string
2831
{
29-
if (!$notice->usesWrapper()) {
30-
return $notice->getRenderedContent();
32+
$elementProperties = new NoticeElementProperties($notice, $this->namespace);
33+
$renderTextOrCallback = $notice->getRenderTextOrCallback();
34+
35+
if (is_callable($renderTextOrCallback)) {
36+
$content = $renderTextOrCallback($notice, $elementProperties);
37+
} else {
38+
$content = $renderTextOrCallback;
39+
}
40+
41+
if ($notice->isCustom()) {
42+
return $this->applyCustomAttributesToContent($content, $notice);
3143
}
3244

3345
return sprintf(
34-
"<div class='%s' data-stellarwp-$this->namespace-notice-id='%s'>%s</div>",
35-
esc_attr($this->getWrapperClasses($notice)),
36-
$notice->getId(),
37-
$notice->getRenderedContent()
46+
"<div class='%s' $elementProperties->idAttribute>%s</div>",
47+
esc_attr($this->getStandardWrapperClasses($notice)),
48+
$notice->shouldAutoParagraph() ? wpautop($content) : $content
3849
);
3950
}
4051

4152
/**
4253
* Generates the classes for the standard WordPress notice wrapper.
4354
*
55+
* @unreleased notice is assumed to be standard only
4456
* @since 1.1.0 notice is passed instead of accessed as a property
4557
* @since 1.0.0
4658
*/
47-
private function getWrapperClasses(AdminNotice $notice): string
59+
private function getStandardWrapperClasses(AdminNotice $notice): string
4860
{
49-
$classes = ['notice', 'notice-' . $notice->getUrgency()];
61+
$classes = [
62+
'notice',
63+
"notice-{$notice->getUrgency()}",
64+
];
5065

5166
if ($notice->isDismissible()) {
5267
$classes[] = "is-dismissible";
5368
}
5469

55-
if ($notice->isInline()) {
70+
if ($notice->getLocation() && $notice->getLocation()->isInline()) {
5671
$classes[] = 'inline';
5772
}
5873

@@ -62,4 +77,26 @@ private function getWrapperClasses(AdminNotice $notice): string
6277

6378
return implode(' ', $classes);
6479
}
80+
81+
/**
82+
* Apply the needed custom attributes to the content.
83+
*
84+
* @unreleased
85+
*/
86+
private function applyCustomAttributesToContent(
87+
string $content,
88+
AdminNotice $notice
89+
): string {
90+
$tags = new WP_HTML_Tag_Processor($content);
91+
92+
$tags->next_tag();
93+
94+
$tags->set_attribute("data-stellarwp-{$this->namespace}-notice-id", $notice->getId());
95+
96+
if ($notice->getLocation()) {
97+
$tags->set_attribute("data-stellarwp-{$this->namespace}-location", (string)$notice->getLocation());
98+
}
99+
100+
return $tags->__toString();
101+
}
65102
}

src/AdminNotice.php

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DateTimeZone;
1010
use Exception;
1111
use InvalidArgumentException;
12+
use StellarWP\AdminNotices\ValueObjects\NoticeLocation;
1213
use StellarWP\AdminNotices\ValueObjects\NoticeUrgency;
1314
use StellarWP\AdminNotices\ValueObjects\ScreenCondition;
1415
use StellarWP\AdminNotices\ValueObjects\UserCapability;
@@ -66,19 +67,19 @@ class AdminNotice
6667
protected $alternateStyles = false;
6768

6869
/**
69-
* @var bool
70+
* @var bool Indicates that the notice is customized and not the standard WordPress notice
7071
*/
71-
protected $withWrapper = true;
72+
protected $custom = false;
7273

7374
/**
7475
* @var bool
7576
*/
7677
protected $dismissible = false;
7778

7879
/**
79-
* @var bool
80+
* @var NoticeLocation|null
8081
*/
81-
protected $inline = false;
82+
protected $location;
8283

8384
/**
8485
* @since 1.0.0
@@ -94,6 +95,7 @@ public function __construct(string $id, $renderTextOrCallback)
9495
$this->id = $id;
9596
$this->renderTextOrCallback = $renderTextOrCallback;
9697
$this->urgency = NoticeUrgency::info();
98+
$this->location = NoticeLocation::standard();
9799
}
98100

99101
/**
@@ -317,64 +319,57 @@ public function usesAlternateStyles(): bool
317319
return $this->alternateStyles;
318320
}
319321

320-
/**
321-
* Sets the notice to display without the standard WordPress wrapper
322-
*
323-
* @since 1.0.0
324-
*/
325-
public function withWrapper(bool $withWrapper = true): self
322+
public function custom(bool $custom = true): self
326323
{
327-
$this->withWrapper = $withWrapper;
324+
$this->custom = $custom;
328325

329326
return $this;
330327
}
331328

332-
/**
333-
* Sets the notice to display without the standard WordPress wrapper
334-
*
335-
* @since 1.0.0
336-
*/
337-
public function withoutWrapper(): self
329+
public function standard(): self
338330
{
339-
$this->withWrapper = false;
331+
$this->custom = false;
340332

341333
return $this;
342334
}
343335

344336
/**
345-
* Returns whether the notice is inline
337+
* Sets the notice to be inline
346338
*
339+
* @unreleased removed parameter in favor of new location parameter
347340
* @since 1.2.0
348341
*/
349-
public function isInline(): bool
342+
public function inline(): self
350343
{
351-
return $this->inline;
344+
$this->location = NoticeLocation::inline();
345+
346+
return $this;
352347
}
353348

354349
/**
355-
* Sets the notice to be inline
350+
* Prevents the notice from being moved from the place it's rendered
356351
*
357-
* @since 1.2.0
352+
* @unreleased
358353
*/
359-
public function inline(bool $inline = true): self
354+
public function inPlace(): self
360355
{
361-
$this->inline = $inline;
356+
$this->location = null;
362357

363358
return $this;
364359
}
365360

366-
/**
367-
* Sets the notice to be not inline
368-
*
369-
* @since 1.2.0
370-
*/
371-
public function notInline(): self
361+
public function location($location): self
372362
{
373-
$this->inline = false;
363+
$this->location = $location instanceof NoticeLocation ? $location : new NoticeLocation($location);
374364

375365
return $this;
376366
}
377367

368+
public function getLocation(): ?NoticeLocation
369+
{
370+
return $this->location;
371+
}
372+
378373
/**
379374
* Sets the notice to be dismissible, usable when the notice is displayed in the standard wrapper
380375
*
@@ -509,14 +504,9 @@ public function getUrgency(): NoticeUrgency
509504
return $this->urgency;
510505
}
511506

512-
/**
513-
* Returns whether the notice should be displayed with the standard WordPress wrapper
514-
*
515-
* @since 1.0.0
516-
*/
517-
public function usesWrapper(): bool
507+
public function isCustom(): bool
518508
{
519-
return $this->withWrapper;
509+
return $this->custom;
520510
}
521511

522512
/**

0 commit comments

Comments
 (0)