The WordPress Notification System That Shouldn’t Work (But Does)
November 9, 2025 • Bojan
November 9, 2025 • Bojan

Most people think WordPress’s post system is only for blog posts or pages.
But I used it to build a real-time in-app notification system – and it works better than you’d expect.
Here’s how.
Instead of creating a new database table, I registered a hidden custom post type called sf_notification.
register_post_type('sf_notification', array(
'public' => false,
'show_ui' => false,
'show_in_menu' => false,
));
Every notification is just a “post.”
This means:
It’s a little unorthodox, but it gives you a free data layer that scales across hundreds of sites.
A common problem with async actions is duplicate notifications – especially under load.
The solution: an idempotency hash that expires after 5 minutes.
$idempotency_key = md5($type . '_' . $user_id . '_' . serialize($meta) . '_' . $triggered_by);
$last = get_user_meta($user_id, '_sf_last_notification_' . $idempotency_key, true);
if ($last && (time() - intval($last)) < 300) {
return false; // Skip duplicate
}
This makes the system safe to call multiple times without spamming the user.
Not every event should go to every user.
The system checks roles and context dynamically – and ignores self-triggered events.
Example:
It’s fully extensible and easy to map to WordPress roles or custom logic.
Storing notifications as posts could be slow if you’re not careful.
So it batch-loads all meta in one go to prevent N+1 queries.
if (!empty($notifications)) {
$ids = wp_list_pluck($notifications, 'ID');
$meta_keys = ['_notification_type', '_notification_priority', '_notification_status', '_notification_created'];
foreach ($meta_keys as $key) {
foreach ($ids as $id) {
$meta[$key][$id] = get_post_meta($id, $key, true);
}
}
}
Everything is pre-fetched, so the frontend can render instantly.
The UI is powered by Alpine.js, making it reactive without needing a full SPA framework.
Notifications are fetched via AJAX and update live without a refresh.
Simple, lightweight, and no need for extra dependencies.
The best part?
Because notifications are stored as posts, each site in a Multisite automatically has its own notifications table (wp_X_posts).
No extra schema, no cross-site pollution, no migration headaches.
It just works.
This is one of those WordPress hacks that feels like it shouldn’t scale, yet it does.
It works because:
It’s not just a hack.
It’s a repurposed content system turned into a distributed notification engine.
This is WordPress doing what it was never meant to do – and doing it surprisingly well.
Everyone talks about “headless WordPress,” but sometimes the smartest move is using WordPress itself as your backend framework.
A hidden post type, a few smart checks, and some front-end reactivity – and you’ve got a modern notification system running on the world’s most battle-tested CMS.

I’m Bojan Josifoski - I’m a WordPress systems engineer who developed and maintained a proprietary WordPress-based framework used by U.S. financial institutions between 2016 and 2025.