Skip to content

Daily Digest Reminders

This document describes the daily digest reminder system that notifies users about upcoming birthdays and todos via email.

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

Assumption: A real server cron job triggers WordPress cron every 5 minutes:

Terminal window
*/5 * * * * wget -q -O - https://cael.is/wp-cron.php?doing_wp_cron

Each 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]

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_user hook)
  • Theme is deactivated (all user cron jobs cleared)
  1. Per-user cron job triggers process_user_reminders($user_id) at user’s preferred time
  2. Generates weekly digest for that user (today/tomorrow/rest of week)
  3. Sends digest via all enabled notification channels for that user
  4. Work history update runs once per day (via transient check)

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

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

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)

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_time user 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_reminder hook

Unschedules a user’s reminder cron job.

Parameters:

  • $user_id - User ID

Returns: true on success

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.

Processes reminders for a specific user (called by per-user cron).

Parameters:

  • $user_id - User ID

Behavior:

  1. Verifies user exists
  2. Gets weekly digest for user
  3. Sends via all enabled notification channels
  4. Runs update_expired_work_history() once per day (via transient check)

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()

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' => [...],
],
]

Gets all users who should receive reminders.

Returns: Array of user IDs

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 null if it has passed

Recurring dates:

  • Calculates occurrence for current year
  • If already passed, returns next year’s occurrence

Background maintenance task that runs with reminders:

  • Finds people with is_current = true work history entries
  • Checks if end_date has passed
  • Automatically sets is_current = false
  • Uses transient to ensure it only runs once per day across all users

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.com

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)

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": "..." }
]
}
]

POST /rondo/v1/reminders/trigger

Response:

{
"success": true,
"message": "Processed 5 user(s), sent 8 notification(s).",
"users_processed": 5,
"notifications_sent": 8
}

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 /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 /rondo/v1/user/notification-channels

Response:

{
"channels": ["email"],
"notification_time": "09:00",
"mention_notifications": "digest"
}

POST /rondo/v1/user/notification-channels

Body:

{
"channels": ["email"]
}

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.

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.

  • WordPress cron must be functioning
  • Email (wp_mail) must be configured for email channel
  • Consider using SMTP plugin for email reliability

Admins can manually trigger reminders from Settings → Administration → “Trigger Reminder Emails” button.

This sends reminders for all users who have dates occurring today.

Terminal window
wp cron event list

Look 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";
}

Test that wp_mail() works:

wp_mail('test@example.com', 'Test Subject', 'Test message');
  1. Check cron is running - WordPress cron requires page visits or server cron
  2. Check email configuration - Use an SMTP plugin like WP Mail SMTP
  3. Check spam folder - Emails may be filtered
  4. Check user emails - Users must have valid email addresses
  5. Check user preferences - User must have email channel enabled
  1. Check timezone - Uses WordPress timezone (wp_timezone())
  2. Check date format - Birthdates must be in Y-m-d format

Server cron requirement: Rondo Club requires a real server cron job that triggers WordPress cron every 5 minutes for precise notification timing:

Terminal window
# crontab -e
*/5 * * * * wget -q -O - https://cael.is/wp-cron.php?doing_wp_cron

Disable WordPress’s pseudo-cron in wp-config.php:

define('DISABLE_WP_CRON', true);

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:

Terminal window
# Process reminders for all users (ignores timing)
wp prm reminders trigger --force
# Process reminders for specific user
wp prm reminders trigger --user=123

To add a new notification channel:

  1. Create a new class extending Rondo\Notifications\Channel in includes/class-notification-channels.php
  2. Implement required methods: send(), is_enabled_for_user(), get_user_config(), get_channel_id(), get_channel_name()
  3. Register the channel in Rondo\Core\Reminders constructor
  4. Add UI toggle in Settings page
  5. 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
}