gen_log_query = $gen_log_query ?? new PRAutoBlogger_Board_Gen_Log_Query(); } /** * Return the full board snapshot consumed by the AJAX poller. * * Each column is an array of card objects. Cards contain only the data * needed to render the board card and provide click-throughs. * * @return array{ * generating: array>, * in_review: array>, * published: array>, * failed: array>, * has_active_runs: bool, * } */ public function get_board_snapshot(): array { $generating = $this->gen_log_query->get_generating_cards(); $in_review = $this->get_in_review_cards(); $published = $this->get_published_cards(); $failed = $this->gen_log_query->get_failed_cards(); return array( 'generating' => $generating, 'in_review' => $in_review, 'published' => $published, 'failed' => $failed, 'has_active_runs' => ! empty( $generating ), ); } /** * Cards for runs that are currently in-progress. * Delegates to PRAutoBlogger_Board_Gen_Log_Query. * * @return array> */ public function get_generating_cards(): array { return $this->gen_log_query->get_generating_cards(); } /** * Cards for generation runs that ended in an error state. * Delegates to PRAutoBlogger_Board_Gen_Log_Query. * * @return array> */ public function get_failed_cards(): array { return $this->gen_log_query->get_failed_cards(); } /** * Cards for generated draft posts awaiting human review. * * @return array> */ public function get_in_review_cards(): array { $query = new WP_Query( array( 'post_type' => 'post', 'post_status' => 'draft', 'posts_per_page' => 20, 'meta_query' => array( array( 'key' => '_prautoblogger_generated', 'value' => '1', ), ), 'orderby' => 'date', 'order' => 'DESC', ) ); $cards = array(); foreach ( $query->posts as $post ) { if ( ! ( $post instanceof WP_Post ) ) { continue; } $run_id = (string) get_post_meta( $post->ID, '_prautoblogger_run_id', true ); $cost_total = (float) get_post_meta( $post->ID, '_prautoblogger_total_cost', true ); $cards[] = array( 'run_id' => $run_id, 'post_id' => $post->ID, 'title' => $post->post_title, 'cost_total' => $cost_total, 'created_at' => strtotime( $post->post_date_gmt ), 'click_action' => 'review', 'review_url' => admin_url( 'admin.php?page=prautoblogger-review-queue' ), 'edit_url' => get_edit_post_link( $post->ID, 'raw' ), ); } return $cards; } /** * Cards for published posts within the configured window. * * @return array> */ public function get_published_cards(): array { $window_days = max( 1, (int) get_option( 'prautoblogger_board_published_window_days', 7 ) ); $date_after = gmdate( 'Y-m-d H:i:s', time() - ( $window_days * DAY_IN_SECONDS ) ); $query = new WP_Query( array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 20, 'date_query' => array( array( 'after' => $date_after, 'inclusive' => true, ), ), 'meta_query' => array( array( 'key' => '_prautoblogger_generated', 'value' => '1', ), ), 'orderby' => 'date', 'order' => 'DESC', ) ); $cards = array(); foreach ( $query->posts as $post ) { if ( ! ( $post instanceof WP_Post ) ) { continue; } $run_id = (string) get_post_meta( $post->ID, '_prautoblogger_run_id', true ); $cost_total = (float) get_post_meta( $post->ID, '_prautoblogger_total_cost', true ); $cards[] = array( 'run_id' => $run_id, 'post_id' => $post->ID, 'title' => $post->post_title, 'cost_total' => $cost_total, 'published_at' => strtotime( $post->post_date_gmt ), 'click_action' => 'edit', 'edit_url' => get_edit_post_link( $post->ID, 'raw' ), 'post_url' => get_permalink( $post->ID ), ); } return $cards; } }