*/ private static $buffer = array(); private static $registered = false; public static function init() { if ( self::$registered ) { return; } self::$registered = true; // Self-heal a malformed overflow transient persisted by an older // buggy build (`(array) false` ended up storing `[false]`). $existing = get_transient( self::TRANSIENT_KEY ); if ( false !== $existing && ! is_array( $existing ) ) { delete_transient( self::TRANSIENT_KEY ); } add_action( 'shutdown', array( __CLASS__, 'flush' ), 99 ); add_action( 'apwpm_queue_drain', array( __CLASS__, 'drain_overflow' ) ); if ( ! wp_next_scheduled( 'apwpm_queue_drain' ) ) { wp_schedule_event( time() + 60, 'apwpm_minutely', 'apwpm_queue_drain' ); } } public static function add_minutely_schedule( $schedules ) { if ( ! isset( $schedules['apwpm_minutely'] ) ) { $schedules['apwpm_minutely'] = array( 'interval' => MINUTE_IN_SECONDS, 'display' => __( 'Every minute (APWPM)', 'activitypilot' ), ); } return $schedules; } public static function enabled() { $s = (array) get_option( 'apwpm_settings', array() ); return ! empty( $s['enable_async'] ); } /** * Push a fully-formed row onto the in-process buffer. */ public static function push( array $row ) { self::$buffer[] = $row; } public static function pending_count() { return count( self::$buffer ); } /** * Bulk-insert buffered rows. Falls back to a transient if the DB * write fails so we don't lose entries. */ public static function flush() { if ( empty( self::$buffer ) ) { return 0; } $rows = self::$buffer; self::$buffer = array(); // Wrap in try/catch — we're on the shutdown hook, an exception here // would otherwise be silently swallowed but could still trip earlier // output handlers. Better to log and move on. try { return self::bulk_insert( $rows ); } catch ( \Throwable $e ) { return 0; } } protected static function bulk_insert( array $rows ) { // Strip out anything that isn't a real row payload. $rows = array_values( array_filter( $rows, function ( $r ) { return is_array( $r ) && ! empty( $r ); } ) ); if ( empty( $rows ) ) { return 0; } $inserted = 0; foreach ( $rows as $row ) { if ( false !== APWPM_DB::insert( $row ) ) { $inserted++; } } if ( $inserted < count( $rows ) ) { $existing = get_transient( self::TRANSIENT_KEY ); $existing = is_array( $existing ) ? $existing : array(); set_transient( self::TRANSIENT_KEY, array_merge( $existing, $rows ), DAY_IN_SECONDS ); return $inserted; } return $inserted; } public static function drain_overflow() { $rows = get_transient( self::TRANSIENT_KEY ); // get_transient() returns false when missing/expired — don't cast it to an array, // otherwise we'd end up with [false] and crash bulk_insert(). if ( ! is_array( $rows ) || empty( $rows ) ) { if ( false !== $rows ) { // Stored value was malformed (e.g. boolean from a legacy bug). Drop it. delete_transient( self::TRANSIENT_KEY ); } return; } delete_transient( self::TRANSIENT_KEY ); self::bulk_insert( $rows ); } } add_filter( 'cron_schedules', array( 'APWPM_Queue', 'add_minutely_schedule' ) );