Files
2026-03-18 14:21:32 -07:00

271 lines
7.5 KiB
PHP

<?php
/**
* Cron Class
*
* Handles scheduled cache regeneration for stale pages.
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
class WP_To_HTML_Cron {
/**
* Single instance
*/
private static $instance = null;
/**
* Cron hook name
*/
const CRON_HOOK = 'wp_to_html_scheduled_regeneration';
/**
* Get singleton instance
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
// Register the cron action
add_action(self::CRON_HOOK, array($this, 'run_scheduled_regeneration'));
// Add custom cron schedules
add_filter('cron_schedules', array($this, 'add_cron_schedules'));
}
/**
* Add custom cron schedules
*
* @param array $schedules Existing schedules
* @return array Modified schedules
*/
public function add_cron_schedules($schedules) {
$schedules['wp_to_html_hourly'] = array(
'interval' => HOUR_IN_SECONDS,
'display' => __('Every Hour (WP-to-HTML)', 'wp-to-html'),
);
$schedules['wp_to_html_twicedaily'] = array(
'interval' => 12 * HOUR_IN_SECONDS,
'display' => __('Twice Daily (WP-to-HTML)', 'wp-to-html'),
);
return $schedules;
}
/**
* Schedule the cron event
*/
public static function schedule_cron() {
$settings = WP_To_HTML::get_settings();
$interval = isset($settings['cron_interval']) ? $settings['cron_interval'] : 'wp_to_html_hourly';
// Don't schedule if disabled
if ($interval === 'disabled') {
self::unschedule_cron();
return;
}
// Only schedule if not already scheduled
if (!wp_next_scheduled(self::CRON_HOOK)) {
wp_schedule_event(time(), $interval, self::CRON_HOOK);
}
}
/**
* Unschedule the cron event
*/
public static function unschedule_cron() {
$timestamp = wp_next_scheduled(self::CRON_HOOK);
if ($timestamp) {
wp_unschedule_event($timestamp, self::CRON_HOOK);
}
// Clear all events with this hook
wp_clear_scheduled_hook(self::CRON_HOOK);
}
/**
* Reschedule cron with new interval
*
* @param string $interval New interval
*/
public static function reschedule_cron($interval) {
self::unschedule_cron();
if ($interval !== 'disabled') {
wp_schedule_event(time(), $interval, self::CRON_HOOK);
}
}
/**
* Run the scheduled regeneration
*/
public function run_scheduled_regeneration() {
$settings = WP_To_HTML::get_settings();
// Check if plugin is enabled
if (!$settings['enabled']) {
return;
}
$generator = WP_To_HTML_Generator::get_instance();
$stale_posts = $this->get_stale_posts();
$total = count($stale_posts);
// Set initial status
self::set_regeneration_status(array(
'status' => 'running',
'source' => 'cron',
'started' => time(),
'total' => $total,
'processed' => 0,
'converted' => 0,
'skipped' => 0,
'errors' => 0,
));
$converted = 0;
$errors = 0;
foreach ($stale_posts as $index => $post_id) {
$result = $generator->generate($post_id);
if (is_wp_error($result)) {
$errors++;
} else {
$converted++;
}
// Update status periodically (every 5 pages or at the end)
if (($index + 1) % 5 === 0 || ($index + 1) === $total) {
self::set_regeneration_status(array(
'status' => 'running',
'source' => 'cron',
'started' => time(),
'total' => $total,
'processed' => $index + 1,
'converted' => $converted,
'skipped' => 0,
'errors' => $errors,
));
}
}
// Mark complete
self::set_regeneration_status(array(
'status' => 'complete',
'source' => 'cron',
'completed' => time(),
'total' => $total,
'processed' => $total,
'converted' => $converted,
'skipped' => 0,
'errors' => $errors,
));
// Log the regeneration
update_option('wp_to_html_last_cron_run', array(
'time' => current_time('mysql'),
'timestamp' => time(),
'regenerated' => $converted,
));
}
/**
* Set regeneration status transient
*
* @param array $status Status data
*/
public static function set_regeneration_status($status) {
set_transient('wp_to_html_regeneration_status', $status, 5 * MINUTE_IN_SECONDS);
}
/**
* Get regeneration status
*
* @return array|false Status data or false if not set
*/
public static function get_regeneration_status() {
return get_transient('wp_to_html_regeneration_status');
}
/**
* Clear regeneration status
*/
public static function clear_regeneration_status() {
delete_transient('wp_to_html_regeneration_status');
}
/**
* Get posts that need regeneration
*
* @return array Array of post IDs
*/
private function get_stale_posts() {
$stale_posts = array();
$metadata_dir = WP_TO_HTML_CACHE_DIR . '.metadata/';
if (!file_exists($metadata_dir)) {
return $stale_posts;
}
// Scan metadata directory for cached posts
$metadata_files = glob($metadata_dir . '*.json');
foreach ($metadata_files as $metadata_file) {
$metadata = json_decode(file_get_contents($metadata_file), true);
if (!$metadata || !isset($metadata['post_id'])) {
continue;
}
$post_id = $metadata['post_id'];
$post = get_post($post_id);
// Skip if post no longer exists
if (!$post) {
continue;
}
// Check if post was modified after cache was generated
$post_modified = strtotime($post->post_modified);
$cache_generated = isset($metadata['generated_timestamp']) ? $metadata['generated_timestamp'] : 0;
if ($post_modified > $cache_generated) {
$stale_posts[] = $post_id;
}
}
return $stale_posts;
}
/**
* Get the next scheduled run time
*
* @return int|false Timestamp or false if not scheduled
*/
public static function get_next_run() {
return wp_next_scheduled(self::CRON_HOOK);
}
/**
* Get the last cron run info
*
* @return array|false
*/
public static function get_last_run() {
return get_option('wp_to_html_last_cron_run', false);
}
}