Manual and scheduled sync previously processed every WooCommerce product inline in a single PHP request/AJAX call, with several sequential BC API calls per product. At real catalog sizes this exceeds PHP's max_execution_time and the proxy's read timeout, surfacing as a 502 Bad Gateway on "Sync Now". Adds WBC_Batch_Sync, which queues the catalog in chunks of 25 via Action Scheduler (bundled with WooCommerce) and processes them asynchronously. The manual sync AJAX call now returns immediately after queuing, and the admin UI polls for progress instead of waiting on one long request. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
160 lines
4.4 KiB
PHP
160 lines
4.4 KiB
PHP
<?php
|
|
/**
|
|
* Cron Scheduler for WooCommerce Business Central Integration
|
|
*
|
|
* @package WooBusinessCentral
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class WBC_Cron
|
|
*
|
|
* Handles scheduled tasks for syncing with Business Central.
|
|
*/
|
|
class WBC_Cron {
|
|
|
|
/**
|
|
* Cron event name
|
|
*/
|
|
const SYNC_EVENT = 'wbc_product_sync_event';
|
|
|
|
/**
|
|
* Cleanup event name
|
|
*/
|
|
const CLEANUP_EVENT = 'wbc_log_cleanup_event';
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct() {
|
|
// Register cleanup cron if not scheduled
|
|
if ( ! wp_next_scheduled( self::CLEANUP_EVENT ) ) {
|
|
wp_schedule_event( time(), 'daily', self::CLEANUP_EVENT );
|
|
}
|
|
|
|
// Hook the cleanup handler
|
|
add_action( self::CLEANUP_EVENT, array( $this, 'run_log_cleanup' ) );
|
|
}
|
|
|
|
/**
|
|
* Run scheduled product sync
|
|
*
|
|
* Queues background batches via WBC_Batch_Sync rather than running the
|
|
* whole catalog inline - WP-Cron events run under the same PHP time/memory
|
|
* limits as any other request and would otherwise time out at scale.
|
|
*/
|
|
public function run_scheduled_sync() {
|
|
WBC_Logger::info( 'Cron', 'Starting scheduled product sync' );
|
|
|
|
$result = WBC_Batch_Sync::queue_full_sync();
|
|
|
|
if ( isset( $result['success'] ) && $result['success'] ) {
|
|
WBC_Logger::info( 'Cron', 'Scheduled product sync queued', $result );
|
|
} else {
|
|
WBC_Logger::error( 'Cron', 'Scheduled product sync failed to queue', $result );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run log cleanup
|
|
*/
|
|
public function run_log_cleanup() {
|
|
$deleted = WBC_Logger::cleanup_old_logs( 30 );
|
|
WBC_Logger::info( 'Cron', 'Log cleanup completed', array( 'deleted_count' => $deleted ) );
|
|
}
|
|
|
|
/**
|
|
* Reschedule the sync event with a new frequency
|
|
*
|
|
* @param string $frequency New frequency (hourly, twice_daily, daily).
|
|
*/
|
|
public static function reschedule_sync( $frequency ) {
|
|
// Clear existing schedule
|
|
$timestamp = wp_next_scheduled( self::SYNC_EVENT );
|
|
if ( $timestamp ) {
|
|
wp_unschedule_event( $timestamp, self::SYNC_EVENT );
|
|
}
|
|
|
|
// Schedule with new frequency
|
|
wp_schedule_event( time(), $frequency, self::SYNC_EVENT );
|
|
|
|
WBC_Logger::info( 'Cron', 'Sync schedule updated', array( 'frequency' => $frequency ) );
|
|
}
|
|
|
|
/**
|
|
* Get next scheduled sync time
|
|
*
|
|
* @return int|false Timestamp of next scheduled sync or false if not scheduled.
|
|
*/
|
|
public static function get_next_sync_time() {
|
|
return wp_next_scheduled( self::SYNC_EVENT );
|
|
}
|
|
|
|
/**
|
|
* Get next scheduled sync time formatted
|
|
*
|
|
* @return string Formatted date/time string or 'Not scheduled'.
|
|
*/
|
|
public static function get_next_sync_formatted() {
|
|
$next = self::get_next_sync_time();
|
|
|
|
if ( ! $next ) {
|
|
return __( 'Not scheduled', 'woo-business-central' );
|
|
}
|
|
|
|
return wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $next );
|
|
}
|
|
|
|
/**
|
|
* Get last sync time
|
|
*
|
|
* @return string|false Last sync time or false if never synced.
|
|
*/
|
|
public static function get_last_sync_time() {
|
|
return get_option( 'wbc_last_sync_time', false );
|
|
}
|
|
|
|
/**
|
|
* Get last sync time formatted
|
|
*
|
|
* @return string Formatted date/time string or 'Never'.
|
|
*/
|
|
public static function get_last_sync_formatted() {
|
|
$last = self::get_last_sync_time();
|
|
|
|
if ( ! $last ) {
|
|
return __( 'Never', 'woo-business-central' );
|
|
}
|
|
|
|
return wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $last ) );
|
|
}
|
|
|
|
/**
|
|
* Update last sync time
|
|
*/
|
|
public static function update_last_sync_time() {
|
|
update_option( 'wbc_last_sync_time', current_time( 'mysql' ) );
|
|
}
|
|
|
|
/**
|
|
* Clear all scheduled events
|
|
*/
|
|
public static function clear_all_schedules() {
|
|
// Clear sync event
|
|
$sync_timestamp = wp_next_scheduled( self::SYNC_EVENT );
|
|
if ( $sync_timestamp ) {
|
|
wp_unschedule_event( $sync_timestamp, self::SYNC_EVENT );
|
|
}
|
|
|
|
// Clear cleanup event
|
|
$cleanup_timestamp = wp_next_scheduled( self::CLEANUP_EVENT );
|
|
if ( $cleanup_timestamp ) {
|
|
wp_unschedule_event( $cleanup_timestamp, self::CLEANUP_EVENT );
|
|
}
|
|
}
|
|
}
|