Daily Digest Reminders
This document describes the daily digest reminder system that notifies users about upcoming birthdays and todos via email.
Overview
Section titled “Overview”Rondo Club includes an automated reminder system that:
- Runs via per-user WordPress cron jobs at each user’s preferred notification time
- Sends a daily digest email/notification listing:
- Birthdays today + todos due today (including overdue)
- Birthdays tomorrow + todos due tomorrow
- Birthdays for the rest of the week (days 3-7) + todos due in that period
- Sends daily digest emails to users who have notifications enabled
- Notifies all users who have access to the people
How It Works
Section titled “How It Works”Per-User Cron Scheduling
Section titled “Per-User Cron Scheduling”Assumption: A real server cron job triggers WordPress cron every 5 minutes:
*/5 * * * * wget -q -O - https://cael.is/wp-cron.php?doing_wp_cronEach user has an individual cron job scheduled at their preferred notification time:
- Cron Hook:
rondo_user_reminder(with user ID as argument) - Schedule: Daily recurring at user’s preferred time (default: 09:00 UTC)
- Arguments:
[$user_id]
Scheduling Events
Section titled “Scheduling Events”Cron jobs are scheduled when:
- Theme is activated (for all existing users)
- User updates their notification time preference in Settings
Cron jobs are unscheduled when:
- User changes their notification time (old time is replaced with new)
- User account is deleted (via WordPress
delete_userhook) - Theme is deactivated (all user cron jobs cleared)
Daily Digest Flow
Section titled “Daily Digest Flow”- Per-user cron job triggers
process_user_reminders($user_id)at user’s preferred time - Generates weekly digest for that user (today/tomorrow/rest of week)
- Sends digest via all enabled notification channels for that user
- Work history update runs once per day (via transient check)
Digest Format
Section titled “Digest Format”Each user receives one notification per day containing:
- TODAY - Birthdays today + todos due today (including overdue)
- TOMORROW - Birthdays tomorrow + todos due tomorrow
- THIS WEEK - Birthdays in the next 5 days (days 3-7) + todos due in that period
Example: If today is Monday, June 15th:
- TODAY: John’s Birthday (June 15), ☐ Call about project → John Doe
- TOMORROW: Mom’s Birthday (June 16), ☐ Send gift → Mom
- THIS WEEK: Friend’s Birthday (June 18), ☐ Schedule meeting (Jun 18) → Friend
Implementation
Section titled “Implementation”Classes
Section titled “Classes”Rondo\Core\Reminders (includes/class-reminders.php)
- Main orchestrator for reminder processing
- Generates weekly digests per user (birthdays from person records)
- Coordinates notification channels
Rondo\Notifications\Channel (includes/class-notification-channels.php)
- Abstract base class for notification channels
- Defines interface:
send(),is_enabled_for_user(),get_user_config()
Rondo\Notifications\EmailChannel (includes/class-email-channel.php)
- Email notification implementation
- Formats digest as plain text email
Cron Configuration
Section titled “Cron Configuration”Per-User Cron Hook: rondo_user_reminder (with user ID argument)
Scheduling (in Rondo\Core\Reminders class):
// Schedule individual user's cron at their preferred time$reminders->schedule_user_reminder($user_id);
// Schedule all users during theme activation$reminders->schedule_all_user_reminders();Legacy Cron Hook: rondo_daily_reminder_check (deprecated, kept for backward compatibility)
Key Methods
Section titled “Key Methods”schedule_user_reminder($user_id)
Section titled “schedule_user_reminder($user_id)”Schedules a cron job for a specific user at their preferred notification time.
Parameters:
$user_id- User ID
Returns: true on success, WP_Error on failure
Behavior:
- Gets user’s preferred time from
rondo_notification_timeuser meta (default:09:00) - Calculates next occurrence (if time passed today, schedules for tomorrow)
- Unschedules any existing cron for this user
- Schedules new daily recurring cron with
rondo_user_reminderhook
unschedule_user_reminder($user_id)
Section titled “unschedule_user_reminder($user_id)”Unschedules a user’s reminder cron job.
Parameters:
$user_id- User ID
Returns: true on success
schedule_all_user_reminders()
Section titled “schedule_all_user_reminders()”Schedules reminder cron jobs for all users who should receive reminders.
Returns: Number of users scheduled
Usage: Called during theme activation and by admin “Reschedule cron jobs” button.
process_user_reminders($user_id)
Section titled “process_user_reminders($user_id)”Processes reminders for a specific user (called by per-user cron).
Parameters:
$user_id- User ID
Behavior:
- Verifies user exists
- Gets weekly digest for user
- Sends via all enabled notification channels
- Runs
update_expired_work_history()once per day (via transient check)
process_daily_reminders() [DEPRECATED]
Section titled “process_daily_reminders() [DEPRECATED]”DEPRECATED: Use process_user_reminders() with per-user cron jobs instead.
This method is kept for backward compatibility. When called, it:
- Calls
schedule_all_user_reminders()to reschedule per-user cron jobs - Runs
update_expired_work_history()
get_weekly_digest($user_id)
Section titled “get_weekly_digest($user_id)”Returns weekly digest for a specific user, including both birthdays and todos.
Parameters:
$user_id- User ID
Returns: Array with four keys:
[ 'today' => [ [ 'id' => 123, 'title' => "John's Birthday", 'next_occurrence' => '2025-06-15', 'related_people' => [...], // ... more fields ], ], 'tomorrow' => [...], 'rest_of_week' => [...], 'todos' => [ 'today' => [ [ 'id' => 456, 'content' => 'Call about project', 'due_date' => '2025-06-15', 'person_id' => 789, 'person_name' => 'John Doe', 'is_overdue' => false, ], ], 'tomorrow' => [...], 'rest_of_week' => [...], ],]get_all_users_to_notify()
Section titled “get_all_users_to_notify()”Gets all users who should receive reminders.
Returns: Array of user IDs
get_upcoming_reminders($days_ahead)
Section titled “get_upcoming_reminders($days_ahead)”Legacy method for backward compatibility. Returns all reminders within specified window (used by REST API for dashboard/UI).
Parameters:
$days_ahead- Number of days to look ahead (default: 30)
calculate_next_occurrence($date_string, $is_recurring)
Section titled “calculate_next_occurrence($date_string, $is_recurring)”Calculates when a date will next occur.
Non-recurring dates:
- Returns the date if it’s today or in the future
- Returns
nullif it has passed
Recurring dates:
- Calculates occurrence for current year
- If already passed, returns next year’s occurrence
update_expired_work_history()
Section titled “update_expired_work_history()”Background maintenance task that runs with reminders:
- Finds people with
is_current = truework history entries - Checks if
end_datehas passed - Automatically sets
is_current = false - Uses transient to ensure it only runs once per day across all users
Notification Channels
Section titled “Notification Channels”Email Channel
Section titled “Email Channel”User Meta: rondo_notification_channels (array containing 'email')
Email Format:
Subject: [Rondo Club] Your Reminders & Todos - June 15, 2025
Hello User,
Here are your upcoming birthdays and to-dos for this week:
📅 TODAY• John's Birthday - June 15, 2025☐ Call about project (overdue) → John Doe
📅 TOMORROW• Mom's Birthday - June 16, 2025☐ Send gift → Mom
📅 THIS WEEK• Friend's Birthday - June 18, 2025☐ Schedule meeting (June 18, 2025) → Friend
Visit Rondo Club to see more details.
https://your-site.comUser Preferences
Section titled “User Preferences”Users can enable/disable email notifications in Settings.
User Meta Keys:
rondo_notification_channels- Array of enabled channels:['email']rondo_notification_time- Preferred notification time in HH:MM format, 5-minute increments (default:09:00)
REST API Integration
Section titled “REST API Integration”Get Upcoming Reminders
Section titled “Get Upcoming Reminders”GET /rondo/v1/reminders
Parameters:
days_ahead- Days to look ahead (default: 30, max: 365)
Response:
[ { "id": 123, "title": "John's Birthday", "date_value": "1985-06-15", "next_occurrence": "2025-06-15", "days_until": 5, "is_recurring": true, "related_people": [ { "id": 456, "name": "John Doe", "thumbnail": "..." } ] }]Trigger Reminders Manually (Admin Only)
Section titled “Trigger Reminders Manually (Admin Only)”POST /rondo/v1/reminders/trigger
Response:
{ "success": true, "message": "Processed 5 user(s), sent 8 notification(s).", "users_processed": 5, "notifications_sent": 8}Reschedule All Cron Jobs (Admin Only)
Section titled “Reschedule All Cron Jobs (Admin Only)”POST /rondo/v1/reminders/reschedule-cron
Reschedules all user reminder cron jobs based on their notification time preferences.
Response:
{ "success": true, "message": "Successfully rescheduled reminder cron jobs for 5 user(s).", "users_scheduled": 5}Get Cron Status (Admin Only)
Section titled “Get Cron Status (Admin Only)”GET /rondo/v1/reminders/cron-status
Returns status of all user reminder cron jobs.
Response:
{ "total_users": 5, "scheduled_users": 5, "users": [ { "user_id": 1, "display_name": "Admin User", "next_run": "2026-01-08 09:00:00", "next_run_timestamp": 1736326800 } ], "current_time": "2026-01-07 15:30:00", "current_timestamp": 1736263800, "legacy_cron_scheduled": false, "legacy_next_run": null}Get Notification Channels
Section titled “Get Notification Channels”GET /rondo/v1/user/notification-channels
Response:
{ "channels": ["email"], "notification_time": "09:00", "mention_notifications": "digest"}Update Notification Channels
Section titled “Update Notification Channels”POST /rondo/v1/user/notification-channels
Body:
{ "channels": ["email"]}Update Notification Time
Section titled “Update Notification Time”POST /rondo/v1/user/notification-time
Body:
{ "time": "09:00"}Note: When notification time is updated, the user’s cron job is automatically rescheduled to the new time.
Configuration
Section titled “Configuration”Birthday Detection
Section titled “Birthday Detection”Birthdays are detected from the birthdate field on person records. All birthdays are treated as recurring (yearly) events and are included in the daily digest if they occur within the next 7 days.
Server Requirements
Section titled “Server Requirements”- WordPress cron must be functioning
- Email (wp_mail) must be configured for email channel
- Consider using SMTP plugin for email reliability
Testing Reminders
Section titled “Testing Reminders”Manual Trigger (Admin Only)
Section titled “Manual Trigger (Admin Only)”Admins can manually trigger reminders from Settings → Administration → “Trigger Reminder Emails” button.
This sends reminders for all users who have dates occurring today.
Check Cron Status
Section titled “Check Cron Status”wp cron event listLook for rondo_user_reminder events in the output. Each user should have their own scheduled event.
Check specific user’s cron (PHP):
$user_id = 123;$next_run = wp_next_scheduled('rondo_user_reminder', [$user_id]);if ($next_run) { echo "User $user_id next reminder: " . date('Y-m-d H:i:s', $next_run);} else { echo "No cron scheduled for user $user_id";}Verify Email
Section titled “Verify Email”Test that wp_mail() works:
Troubleshooting
Section titled “Troubleshooting”Emails Not Sending
Section titled “Emails Not Sending”- Check cron is running - WordPress cron requires page visits or server cron
- Check email configuration - Use an SMTP plugin like WP Mail SMTP
- Check spam folder - Emails may be filtered
- Check user emails - Users must have valid email addresses
- Check user preferences - User must have email channel enabled
Wrong Reminder Dates
Section titled “Wrong Reminder Dates”- Check timezone - Uses WordPress timezone (
wp_timezone()) - Check date format - Birthdates must be in Y-m-d format
Cron Not Running
Section titled “Cron Not Running”Server cron requirement: Rondo Club requires a real server cron job that triggers WordPress cron every 5 minutes for precise notification timing:
# crontab -e*/5 * * * * wget -q -O - https://cael.is/wp-cron.php?doing_wp_cronDisable WordPress’s pseudo-cron in wp-config.php:
define('DISABLE_WP_CRON', true);Reschedule User Cron Jobs
Section titled “Reschedule User Cron Jobs”If cron jobs are not running for users, admins can reschedule all user cron jobs from Settings → Administration → “Reschedule cron jobs” button.
Via WP-CLI:
# Process reminders for all users (ignores timing)wp prm reminders trigger --force
# Process reminders for specific userwp prm reminders trigger --user=123Adding New Notification Channels
Section titled “Adding New Notification Channels”To add a new notification channel:
- Create a new class extending
Rondo\Notifications\Channelinincludes/class-notification-channels.php - Implement required methods:
send(),is_enabled_for_user(),get_user_config(),get_channel_id(),get_channel_name() - Register the channel in
Rondo\Core\Remindersconstructor - Add UI toggle in Settings page
- Add REST API endpoint if needed for configuration
Example:
class Rondo_Telegram_Channel extends Rondo\Notifications\Channel { public function get_channel_id() { return 'telegram'; }
public function get_channel_name() { return __('Telegram', 'personal-crm'); }
// ... implement other methods}Related Documentation
Section titled “Related Documentation”- Data Model - Person post type with birthdate field
- iCal Feed - Calendar subscription
- Access Control - User permissions