Created
February 24, 2020 23:56
-
-
Save RadGH/378b2013d432c27b2c96897c1b23e72f to your computer and use it in GitHub Desktop.
WordPress Bulk process users on hourly cron event
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Check expiration date for a set of users. | |
| * | |
| * @return string | |
| */ | |
| function dtl_course_expiry_check( $debug = false ) { | |
| // option to start over when used manually via query string | |
| if ( isset($_REQUEST['startover']) ) update_option( 'dtl-ce-user-index', 0, false ); | |
| // Pluggable required for get_user_count to work. | |
| // Sometimes it was undefined, not sure why. Maybe fixed already but just in case | |
| if ( !function_exists('wp_get_current_user')) { | |
| include_once(ABSPATH . "wp-includes/pluggable.php"); | |
| } | |
| // total number of users | |
| $count = count_users(); | |
| $total_users = $count['total_users']; | |
| // get cached number of users per query. this resets at the end of each batch, see below. | |
| $users_per_query = (int) get_option( 'dtl-ce-users-per-query' ); | |
| if ( !$users_per_query ) $users_per_query = 20; | |
| // user index to start at from the database. | |
| // this is like pagination but uses an offset like in MySQL | |
| // so $user_index = 2 means the query will start at the third user. | |
| $user_index = (int) get_option( 'dtl-ce-user-index' ); | |
| if ( !$user_index ) $user_index = 0; | |
| // start over if the user index exceeds the total number of users | |
| if ( $user_index > $total_users ) $user_index = 0; | |
| // when we're starting at the beginning, process the completed "batch" | |
| // this means we finished, and are starting over. | |
| if ( $user_index === 0 ) { | |
| $last_batch_start_time = get_option( 'dtl-ce-batch-start-time' ); | |
| $last_batch_end_time = time(); | |
| $last_batch_emails_sent = get_option( 'dtl-ce-batch-emails-sent' ); | |
| $last_batch = array( | |
| 'start' => $last_batch_start_time, | |
| 'end' => $last_batch_end_time, | |
| 'time_diff' => $last_batch_start_time ? human_time_diff( $last_batch_start_time, $last_batch_end_time ) : "N/A first run", | |
| 'emails_sent' => $last_batch_emails_sent, | |
| ); | |
| // debug to see when cron triggers via email response | |
| /* | |
| $complete_time_local = get_date_from_gmt( date('Y-m-d H:i:s', $last_batch['end']), 'F jS, Y H:i' ); | |
| wp_mail( | |
| '[email protected]', | |
| 'BLI Debug - Course Expiry Batch Completed ' . date('H:i:s'), | |
| 'Hi myself, a batch is finished processing. ' . "\n\n<br>\n\n" . '<p>The process took '. $last_batch['time_diff'] . ' and ' . $last_batch['emails_sent'] . ' email(s) were sent. The process completed on ' . $complete_time_local . '.</p>' | |
| ); | |
| */ | |
| // to process all users daily this number should be X, where: | |
| // X = ( total users / queries per day ) | |
| // For hourly cron with 1000 users: | |
| // X = ( 1000 / 24 ) | |
| // X = 41.6 users per hour | |
| $queries_per_day = 24; // 24 = hourly, 1 = daily, etc. | |
| // this would give 42 users per query with the above example | |
| $users_per_query = ceil( $total_users / $queries_per_day ); | |
| update_option( 'dtl-ce-users-per-query', $users_per_query, false ); | |
| // save the duration of the last batch | |
| update_option( 'dtl-ce-last-batch', $last_batch, false ); | |
| // save the start time for this batch | |
| update_option( 'dtl-ce-batch-start-time', time(), false ); | |
| // reset email sent counter for this new batch | |
| update_option( 'dtl-ce-batch-emails-sent', 0, false ); | |
| } | |
| // search for users who haven't been checked | |
| $args = array( | |
| // this many users | |
| 'number' => $users_per_query, | |
| // starting at this position | |
| 'offset' => $user_index, | |
| // order by, doesn't actually matter | |
| 'orderby' => 'ID', | |
| 'order' => 'ASC', | |
| ); | |
| // get users | |
| $users = new WP_User_Query( $args ); | |
| // if no users were returned, start over by setting the user index beyond total users. | |
| // this will reset to 0 on the next iteration, going into "if ( $user_index === 0 )" above. | |
| if ( empty($users->get_results()) ) { | |
| update_option( 'dtl-ce-user-index', $total_users + 1 ); | |
| return dtl_course_expiry_check( $debug ); | |
| } | |
| // loop through users | |
| foreach( $users->get_results() as $user ) { | |
| // do something with WP_User $user or int $user->ID | |
| // increase the user index | |
| $user_index++; | |
| } | |
| // save the user index so we can continue from where we left off next cron event | |
| update_option( 'dtl-ce-user-index', $user_index, false ); | |
| // save the current progress | |
| update_option( 'dtl-ce-current-progress', $user_index / $total_users, false ); | |
| if ( $debug ) { | |
| // debugging stuff | |
| ob_start(); | |
| echo '<pre>'; | |
| echo '$total_users: ', $total_users, '<br>'; | |
| echo '$users_per_query: ', $users_per_query, '<br>'; | |
| echo '$user_index: ', $user_index, '<br>'; | |
| echo 'progress: ', round(100 * (get_option('dtl-ce-current-progress')), 2), '%<br>'; | |
| echo '$args: <br>'; | |
| var_dump($args); | |
| echo '$users this query: ', count($users->get_results()), '<br>'; | |
| echo '$users display names: <br>'; | |
| foreach( $users->get_results() as $u ) { | |
| if ( !$u instanceof WP_User ) continue; | |
| echo "\t", $u->get('display_name'), ' (#', $u->get('ID'), ')<br>'; | |
| } | |
| echo 'this batch duration: <br>'; | |
| var_dump( human_time_diff( get_option('dtl-ce-batch-start-time'), time() ) ); | |
| echo 'last batch: <br>'; | |
| var_dump( get_option('dtl-ce-last-batch') ); | |
| echo '</pre>'; | |
| } | |
| } | |
| // run this function during our scheduled cron event | |
| add_action( 'wp_cron_dtl_course_expiry_check', 'dtl_course_expiry_check' ); | |
| // allow to run manually in the browser, with debug mode, by adding ?manual_expiry_check | |
| if ( isset($_GET['manual_expiry_check']) ) { | |
| add_action( 'init', function() { | |
| dtl_course_expiry_check( true ); // true = debug | |
| exit; | |
| } ); | |
| } | |
| // Schedule an event every hour to handle cron events | |
| function dtlce_start_cron() { | |
| if ( !wp_next_scheduled ( 'wp_cron_dtl_course_expiry_check' ) ) { | |
| wp_schedule_event(time(), 'hourly', 'wp_cron_dtl_course_expiry_check'); | |
| } | |
| } | |
| register_activation_hook( __FILE__, 'dtlce_start_cron' ); | |
| // Clear the scheduled cron event if plugin gets deactivated | |
| function dtlce_clear_cron() { | |
| wp_clear_scheduled_hook('wp_cron_dtl_course_expiry_check'); | |
| } | |
| register_deactivation_hook( __FILE__, 'dtlce_clear_cron' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment