-
Notifications
You must be signed in to change notification settings - Fork 328
Closed
Labels
P0High priorityHigh priorityTeam SIssues for Squad 1Issues for Squad 1Type: EnhancementImprovement of an existing featureImprovement of an existing feature
Description
Feature Description
- Register single scheduled event at each frequency
- Unregister single scheduled event when the feature is disabled
- Query users at each interval and store each as a custom post
Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
- The
Email_Reporting_Scheduler.phpclass is defined and integrated into the mainEmail_Reportingclass. - When the Proactive User Engagement feature is enabled:
- Three distinct "Initiator" single scheduled events are registered using
wp_schedule_single_event, one for each required frequency:weekly,monthly, andquarterly. - Each "Initiator" scheduler is responsible for dealing with only one frequency and will schedule its own next run each time it executes.
- Three distinct "Initiator" single scheduled events are registered using
- The weekly "Initiator" scheduler must honor the site's "Week starts on" setting from Settings > General, scheduling its run for the first day of the week based on this setting.
- When the Proactive User Engagement feature is disabled, or the plugin is uninstalled via
Core\Util\Uninstallation, all corresponding scheduled events are unscheduled and removed. - When a frequency-level "Initiator" scheduler runs, it must perform the following actions:
- Schedule the next scheduler for its frequency.
- Create a unique ID for the batch to track all subsequent steps.
- Retrieve users whose subscription frequency matches the scheduler's schedule.
- Create a new CPT post (
googlesitekit_email_log) for each retrieved user ID.- Store the following metadata in the CPT post: the UUID as the batch ID and the
report_frequencyin post meta. - Calculate and store the report date range object in
report_reference_datesin the format{ startDate: datestamp, sendDate: datestamp, compareStartDate: datestamp, compareEndDate: datestamp }. - Set the
post_statusof the new CPT post toscheduled. - Set the author of the post to be the user ID of the recipient.
- Store the following metadata in the CPT post: the UUID as the batch ID and the
- Spawn the first "Worker" scheduled event for
+1 minutes, passing the batch_id. - Spawn a "Fallback" scheduled event for
+1 hour, passing the frequency.
Implementation Brief
Add Core\Email_Reporting\Frequency_Planner class
- Implement
next_occurrencemethod:- It accepts
$frequency,$timestampand$time_zonearguments - Compute the initial timestamp for each frequency:
Weekly: determine the target weekday fromget_option( 'start_of_week' )(defaults to 0 = Sunday). Build the next occurrence at the start of that day in site local time (calculate this withwp_timezone()).Monthly/Quarterly: schedule relative to the current date—e.g., monthly on the first of the next month at midnight, quarterly on the first day of the next quarter.
- Each branch should return the computed timestamp that will be used for scheduling the next event
- It accepts
Add Core\Email_Reporting\Subscribed_Users_Query
- It should receive instances of
Google\Site_Kit\Core\User\Email_Reporting_SettingsandModulesand pass them to a class properties. - Add
for_frequency( $frequency )method to resolve the subscriber list:- Filter WordPress users (admins + shared users) whose stored email-reporting preference matches the frequency.
- Retrieve via the new user-settings API (
Google\Site_Kit\Core\User\Email_Reporting_Settingsclass), by enumerating user meta keyed byemail_reporting_settingsfrequency andsubscribedflag. - To build the query, you can reuse the query for Admins -
Has_Connected_Admins::query_connected_adminsand ameta_querythat requires theEmail_Reporting_Settings::OPTIONmeta to contain['subscribed' => true, 'frequency' => $frequency].- The user-setting API stores its data in user meta keyed by
$user_options->get_meta_key( Email_Reporting_Settings::OPTION ), so build the query with that meta key. SeeDebug_Data::get_connected_user_count_field
- The user-setting API stores its data in user meta keyed by
- For view only users pull the shared roles from the dashboard sharing option
$this->modules->get_module_sharing_settings()->get_all_shared_roles()(seeModule_Sharing_Settings::get_all_shared_roles()). Then if not empty - flatten to a unique list, then fetch users withrole__inset to that array and the same meta query as above (subscribed and matching frequency). - Call a helper like
get_subscribed_user_ids( $frequency )that performs those two queries, merges the resulting ID arrays, and deduplicates them
Introduce Core\Email_Reporting\Email_Reporting_Scheduler as the event scheduler hub.
- Register it from the feature’s entry point (
Email_Reporting::register()) so it hooks into the plugin lifecycle. - Define scheduler constants (
WEEKLY,MONTHLY,QUARTERLY) - Define action names:
- It should receive instance of
Frequency_Plannerin the constructor and pass it to the class property - Add a new method
schedule_initiator_events- Loop over the frequency array and for each frequency invoke
schedule_initiator_oncemethod passing it the$frequencyas value
- Loop over the frequency array and for each frequency invoke
- Add
schedule_initiator_once( $frequency ):- Check if there is already an event scheduled using
wp_next_scheduledto return early if it returns value - Retrieve the next occurrence from
$frequency_planner->next_occurrence( $frequency, time(), wp_timezone() ) - Scheduled the next initiator using
wp_schedule_single_eventand computed next occurrence. Useself::ACTION_INITIATORfor a the hook and passfrequencyin arguments array
- Check if there is already an event scheduled using
- Add
schedule_next_initiator( $frequency, $timestamp )- Like in
schedule_initiator_once- compute thenext_occurrenceand schedule the event (no need to usewp_next_scheduled- just go straight to scheduling the event). Pass received$frequencyand$timestamp, and usewp_timezone()as last argument
- Like in
- Add
schedule_worker( $batch_id, $frequency, $timestamp, $delay = MINUTE_IN_SECONDS )- Check if worker (
self::ACTION_WORKER) has not been scheduled already (! wp_next_scheduled)- Return early if it is
- Otherwise proceed with
wp_schedule_single_eventand use passed$timestamp + $delayfor the timestamp (first) argument,self::ACTION_WORKERfor hook, andbatch_id,frequencyandtimestampas arguments array
- Check if worker (
- Add
schedule_fallback( $frequency, $delay = HOUR_IN_SECONDS )- Like previously, if
self::ACTION_FALLBACKis not scheduled, scheduled it fortime() + $delayand pass[ 'frequency => $frequency]to the arguments array
- Like previously, if
- Implement
unschedule_all():- Clear every pending initiator, worker, and fallback action. Use
wp_unschedule_hook()or iterate overwp_get_scheduled_event()for each action name, mirroring cleanup patternsUninstallation::clear_scheduled_events()Invoke it when the globalenabledoption switches off.
- Clear every pending initiator, worker, and fallback action. Use
- Add new CRONs to the
Uninstallation::SCHEDULED_EVENTSso they are cleared on uninstall.
Add Core\Email_Reporting\Initiator_Task
- Accept instance of
Email_Reporting_SchedulerandSubscribed_Users_Queryand store in a class property - Add
handle_callback_action( $frequency )method:- Schedule next run via
Email_Reporting_Scheduler::schedule_next_initiator( $frequency, $time() ) - Generate a fresh batch UUID (use
wp_generate_uuid4()). - Return the subscribed user for the frequency by invoking
Subscribed_Users_Query::for_frequency( $frequency ) - Loop over the returned subscribers list (if not empty) and for each user ID, insert a
Email_Log::POST_TYPEpost (through a helper onEmail_Log):post_author= user ID.post_title=Email_Log::META_BATCH_ID(batch UUID),post_status=Email_Log::STATUS_SCHEDULED.meta_inputincludesEmail_Log::META_BATCH_ID(batch UUID),Email_Log::META_REPORT_FREQUENCY(current frequency),Email_Log::META_REPORT_REFERENCE_DATES(date range object for report queries to use) and initializes any other worker fields such assend_attemptsto0.
- After all posts are created, trigger the follow-up worker using
Email_Reporting_Scheduler::schedule_worker()and fallback withEmail_Reporting_Scheduler::schedule_fallback()
- Schedule next run via
Update Google\Site_Kit\Core\Email_Reporting\Email_Reporting
- It should accept instance of
Modulesin the constructor, and updateincludes/Plugin.php- pass the$modulesto the class instantiation - In
register():- Instantiate
FrequencyPlanner,Subscribed_Users_Query,Email_Reporting_SchedulerandInitiator_Task - Invoke
Email_Reporting_Scheduler::schedule_initiator_events()when feature is enabledGoogle\Site_Kit\Core\Email_Reporting\Email_Reporting_Settings::is_email_reporting_enabled() - Hook into the
Email_Reporting_Scheduler::ACTION_INITIATORand invokehandle_callback_actionfromInitiator_Taskinstance. - Include feature toggle listeners (e.g. hook into the site-level settings datastore update, or expose a public
on_feature_enabled()method invoked when the global option flips on/off -Google\Site_Kit\Core\Email_Reporting\Email_Reporting_Settings).- Use the existing
on_changesetting method, you can see an example heresite-kit-wp/includes/Modules/Search_Console.php
Lines 109 to 119 in bd4aed5
$this->get_settings()->on_change( function ( $old_value, $new_value ) { if ( is_array( $old_value ) && is_array( $new_value ) && isset( array_diff_assoc( $new_value, $old_value )['propertyID'] ) ) { $this->reset_data_available(); } } );
- Use the existing
- Instantiate
- Uninstall cleanup via
Core\Util\Uninstall::register_uninstall_hook()referencing a newEmail_Reporting_Scheduler::unschedule_all()when setting is disabled
Test Coverage
- Add tests for new classes, some examples to test:
- When feature is enabled schedules exactly one event per frequency with the expected timestamps (mock
start_of_weekand ensure weekly lands on that weekday). - Disabling the feature removes all initiator events; uninstall hook clears them as well.
- Running an initiator schedules its next occurrence, spawns worker and fallback events with the correct arguments, and creates CPT posts with the right author, status, and meta.
- If no subscribers are returned, no CPT posts are inserted but worker/fallback are still scheduled.
Subscribed_Users_Queryis returning correct users for subscribed frequency
- When feature is enabled schedules exactly one event per frequency with the expected timestamps (mock
QA Brief
- Enable
proactiveUserEngagementfeature flag - Go to SK settings > admin settings - verify that Email reports are enabled
- Use a plugin like WP Crontrol to check scheduled events, in the search field include
googlesitekit - Verify that there are 3 events of
googlesitekit_email_reporting_initiatorwith different frequency -weekly,monthlyandquarterly
* Weekly should be scheduled for the first beginning of the week current (if today is Mon) or next Monday, monthly should be scheduled for the first (1st) of the next month, and quarterly for the closest quarter
- Go to admin settings and disable email reports
- Verify that no
googlesitekit_email_reporting_initiatorevent is scheduled
Changelog entry
- Add infrastructure for scheduled events at various intervals.
Metadata
Metadata
Assignees
Labels
P0High priorityHigh priorityTeam SIssues for Squad 1Issues for Squad 1Type: EnhancementImprovement of an existing featureImprovement of an existing feature