271 lines
7.5 KiB
PHP
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);
|
|
}
|
|
}
|