PHPackages                             duckdev/wp-review-notice - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. duckdev/wp-review-notice

ActiveLibrary[Admin Panels](/categories/admin)

duckdev/wp-review-notice
========================

Simple library to gently ask for a wp.org plugin review after a few days of plugin usage, with swappable storage drivers and a testable, DI-friendly architecture.

2.0.0(1mo ago)31271GPL-2.0-or-laterPHPPHP &gt;=7.4CI passing

Since Jul 27Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/duckdev/wp-review-notice)[ Packagist](https://packagist.org/packages/duckdev/wp-review-notice)[ Docs](https://github.com/duckdev/wp-review-notice)[ RSS](/packages/duckdev-wp-review-notice/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (5)Dependencies (6)Versions (7)Used By (0)

[ ![](https://camo.githubusercontent.com/838ee08209c53949b986b1d1c9c01b23693a9c2f6438a28e370f26c630223818/68747470733a2f2f6475636b6465762e636f6d2f77702d636f6e74656e742f75706c6f6164732f323032302f31322f63726f707065642d6475636b6465762d6c6f676f2d6d69642e706e67)](http://duckdev.com)

WP Review Notice
================

[](#wp-review-notice)

[![Tests](https://github.com/duckdev/wp-review-notice/actions/workflows/tests.yml/badge.svg)](https://github.com/duckdev/wp-review-notice/actions/workflows/tests.yml)[![PHPCS](https://github.com/duckdev/wp-review-notice/actions/workflows/phpcs.yml/badge.svg)](https://github.com/duckdev/wp-review-notice/actions/workflows/phpcs.yml)

A small, opinionated WordPress library that gently asks for a wp.org plugin review after a few days of usage. Built around a tiny set of focused, swappable collaborators so it stays trivially testable and easy to extend.

📖 **Full documentation:** [docs.duckdev.com/wp-libraries/wp-review-notice/overview](https://docs.duckdev.com/wp-libraries/wp-review-notice/overview)

Installation
------------

[](#installation)

```
composer require duckdev/wp-review-notice
```

Requires **PHP 7.4+** and WordPress **6.0+**.

Quick start
-----------

[](#quick-start)

```
add_action( 'plugins_loaded', function () {
    \DuckDev\Reviews\Notice::create(
        'my-plugin', // wp.org plugin slug (e.g. "hello-dolly").
        'My Plugin', // Display name shown in the notice copy.
        array(
            'days'    => 7,
            'cap'     => 'manage_options',
            'screens' => array( 'dashboard', 'plugins' ), // empty = all admin screens.
        )
    )->register();
} );
```

`register()` is what hooks `admin_notices` + `admin_init` and seeds the show-time schedule. Calling `create()` without `register()` does nothing — useful for tests or for configuring a notice you want to render manually.

Options
-------

[](#options)

KeyTypeDefaultDescription`days``int``7`Days to wait before showing the notice for the first time.`screens``array``[]`Allowed admin screen IDs. Empty = every admin screen.`cap``string``manage_options`Capability required to see and act on the notice.`classes``array``[]`Extra CSS classes appended to the `notice notice-info` wrapper.`domain``string``duckdev`Text domain used for the bundled copy.`message``string``''` (auto-generated)Custom HTML message. Not escaped — sanitise it yourself.`action_labels``array`bundled labelsKeys: `review`, `later`, `dismiss`. Set any to `''` to hide that link.`prefix``string`slug with `-` → `_`Storage namespace. Keys are written as `{prefix}_review_{key}`.Filters
-------

[](#filters)

```
add_filter( 'duckdev_reviews_notice_message', function ( $message, $days ) {
    return "We're glad you've been with us for {$days}+ days!";
}, 10, 2 );
```

Architecture
------------

[](#architecture)

The library is split into small collaborators, each behind an interface:

```
Notice (facade, DI container)
 ├── KeyPrefixer           — "{prefix}_review_{key}" namespacing
 ├── TimerStoreInterface   — when the next show is due  (default: SiteOptionTimerStore)
 ├── DismissalStoreInterface — per-user dismissal flag  (default: UserMetaDismissalStore)
 ├── ScreenResolverInterface  — current admin screen check
 ├── CapabilityCheckerInterface — capability gate
 ├── ActionRouter          — handles later/dismiss GET dispatch
 └── RendererInterface     — emits the notice HTML       (default: DefaultRenderer)

```

Every collaborator is constructor-injectable, so tests (and unusual integrations) can swap any single piece without forking the library.

### Custom storage / rendering

[](#custom-storage--rendering)

```
use DuckDev\Reviews\Notice;
use DuckDev\Reviews\Support\Config;

$notice = new Notice(
    Config::fromArray( 'my-plugin', 'My Plugin' ),
    new MyRedisTimerStore(),       // implements TimerStoreInterface
    null,                          // default user-meta dismissal
    null,                          // default admin-screen resolver
    null,                          // default capability checker
    new MyBlockEditorRenderer()    // implements RendererInterface
);
$notice->register();
```

Upgrading from v1
-----------------

[](#upgrading-from-v1)

v2 is a clean break — there is no compatibility shim.

v1v2`Notice::get( $slug, $name, $opts )``Notice::create( $slug, $name, $opts )->register()`Constructor auto-registered on `is_admin()``register()` is explicitStorage keys `{prefix}_reviews_time` etc.`{prefix}_review_time`, `{prefix}_review_dismissed`, `{prefix}_review_action`Message echoed rawMessage run through `wp_kses_post()``is_time()` mutated storage`isDue()` is a pure read; `start()` seeds on `register()`Existing v1 schedules will be ignored after upgrade (different option key), so users will see the prompt again on the new schedule. If that matters, write a tiny migration in your plugin to rename the option once.

Development
-----------

[](#development)

```
composer install
composer test    # PHPUnit
composer phpcs   # WPCS lint
```

CI runs PHPUnit against PHP 7.4 – 8.3 and WPCS on every push.

License
-------

[](#license)

GPL-2.0-or-later — see [LICENSE](LICENSE).

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance90

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 57.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~450 days

Total

5

Last Release

47d ago

Major Versions

v1.0.3 → 2.0.02026-07-01

PHP version history (2 changes)v1.0.0PHP &gt;=5.6

2.0.0PHP &gt;=7.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/17586?v=4)[Schmidt](/maintainers/Jo)[@jo](https://github.com/jo)

---

Top Contributors

[![joel-james](https://avatars.githubusercontent.com/u/7510463?v=4)](https://github.com/joel-james "joel-james (15 commits)")[![Joel-James](https://avatars.githubusercontent.com/u/7510463?v=4)](https://github.com/Joel-James "Joel-James (9 commits)")[![uglyrobot](https://avatars.githubusercontent.com/u/6445085?v=4)](https://github.com/uglyrobot "uglyrobot (2 commits)")

---

Tags

phpwordpresswordpress-pluginwordpress-reviewwordpressadminreviewsnotices

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/duckdev-wp-review-notice/health.svg)

```
[![Health](https://phpackages.com/badges/duckdev-wp-review-notice/health.svg)](https://phpackages.com/packages/duckdev-wp-review-notice)
```

###  Alternatives

[wecodemore/current-admin-info

Displays info about the current admin screen and its globals, contextual hooks, etc.

842.7k](/packages/wecodemore-current-admin-info)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
