<?php
/**
 * Name: Auto-Publish Missed Schedule
 * Description: Automatically detect and publish posts that missed their scheduled time due to server issues or low traffic to fix WordPress scheduling problems automatically
 * Category: Content
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "Fix Scheduled Post Failures",
 *     "description": "Automatically publish posts that failed to publish due to low traffic, server downtime, or cron timing issues."
 *   },
 *   {
 *     "title": "High-Traffic Sites",
 *     "description": "Ensure scheduled content publishes on time even during traffic spikes when default WordPress cron becomes unreliable."
 *   },
 *   {
 *     "title": "Time-Sensitive Publishing",
 *     "description": "Critical for news sites or product launches where scheduled posts absolutely must publish at exact times despite server issues."
 *   }
 * ]
 * Added: 2025-09-24
 * Tags: schedule, publish, cron, automation, posts
 * WhereToFind: {
 *   "location": "Works automatically in background",
 *   "url": "",
 *   "instructions": "Missed scheduled posts auto-publish on page load",
 *   "newTab": false
 * }
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardAutoPublishMissedSchedule {

    public function __construct() {
        // Use 'wp' hook only (runs once per page load on frontend)
        add_action('wp', [$this, 'check_missed_schedule']);
        // Also check on admin pages but throttled
        add_action('admin_init', [$this, 'check_missed_schedule_admin']);
    }

    public function check_missed_schedule_admin() {
        // Only check every 5 minutes in admin to avoid excessive queries
        $last_check = get_transient('switchboard_missed_schedule_last_check');
        if ($last_check) {
            return; // Already checked recently
        }

        $this->check_missed_schedule();

        // Set transient for 5 minutes
        set_transient('switchboard_missed_schedule_last_check', time(), 300);
    }

    public function check_missed_schedule() {
        global $wpdb;

        if (!$wpdb) {
            return;
        }

        // Find posts with missed schedule
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Finding missed scheduled posts requires direct query
        $missed_posts = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT ID FROM $wpdb->posts
                WHERE post_status = %s
                AND post_date_gmt <= UTC_TIMESTAMP()
                LIMIT 10",
                'future'
            )
        );

        if (empty($missed_posts) || !is_array($missed_posts)) {
            return;
        }

        $published_count = 0;
        foreach ($missed_posts as $post) {
            if (is_object($post) && isset($post->ID)) {
                // Verify post still has future status (avoid race conditions)
                $current_status = get_post_status($post->ID);
                if ($current_status === 'future') {
                    wp_publish_post($post->ID);
                    $published_count++;
                }
            }
        }

        // Log for debugging (optional - only if you want feedback)
        if ($published_count > 0 && current_user_can('manage_options')) {
            // Store count for potential admin notice
            set_transient('switchboard_missed_schedule_published', $published_count, 60);
        }
    }

    /**
     * Register data locations for cleanup system
     */
    public function register_data_locations() {
        return [
            'options' => [],
            'option_patterns' => [
                '_transient_switchboard_missed_schedule_last_check',
                '_transient_timeout_switchboard_missed_schedule_last_check',
                '_transient_switchboard_missed_schedule_published',
                '_transient_timeout_switchboard_missed_schedule_published',
            ],
            'tables' => [],
            'post_meta' => [],
            'user_meta' => [],
        ];
    }
}

$switchboard_instance = new SwitchboardAutoPublishMissedSchedule();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
