prefix . 'sixrsh_logs'; // phpcs:disable WordPress.DB.DirectDatabaseQuery $wpdb->insert( $table, array( 'event_type' => sanitize_text_field( $event_type ), 'customer_phone' => sanitize_text_field( $phone ), 'template_name' => sanitize_text_field( $template_name ), 'status' => in_array( $status, array( 'success', 'failed', 'info' ), true ) ? $status : 'failed', 'error_message' => sanitize_textarea_field( $error ), 'created_at' => current_time( 'mysql', true ), ), array( '%s', '%s', '%s', '%s', '%s', '%s' ) ); // Prune oldest rows if we exceed MAX_ROWS. $count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}sixrsh_logs" ); if ( $count > self::MAX_ROWS ) { $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}sixrsh_logs WHERE log_id IN ( SELECT log_id FROM ( SELECT log_id FROM {$wpdb->prefix}sixrsh_logs ORDER BY log_id ASC LIMIT %d ) AS sub )", self::PRUNE_COUNT ) ); } // phpcs:enable WordPress.DB.DirectDatabaseQuery } catch ( \Throwable $e ) { // Fail silently — never crash WordPress. error_log( '[6rsh WhatsApp] Logger exception: ' . $e->getMessage() ); } } /** * Lightweight diagnostic trace — records a lifecycle stage so the owner can * see exactly what happened (hook fired, phone, dispatched) in the Logs page. * * @param string $stage Stage label (e.g. "event:wc-processing"). * @param string $phone Phone if known. * @param string $detail Free-form detail. * * @return void */ public static function trace( string $stage, string $phone = '', string $detail = '' ): void { self::log( $stage, $phone, '', 'info', $detail ); } /** * Retrieve log rows, newest first. * * @param array $filters Associative array: event_type, status. * @param int $limit Max rows to return. * * @return array */ public static function get_logs( array $filters = array(), int $limit = 200 ): array { global $wpdb; try { $table = $wpdb->prefix . 'sixrsh_logs'; $where = array( '1=1' ); $args = array(); if ( ! empty( $filters['event_type'] ) ) { $where[] = 'event_type = %s'; $args[] = sanitize_text_field( $filters['event_type'] ); } if ( ! empty( $filters['status'] ) && in_array( $filters['status'], array( 'success', 'failed' ), true ) ) { $where[] = 'status = %s'; $args[] = $filters['status']; } $where_sql = implode( ' AND ', $where ); $limit_int = max( 1, min( 1000, $limit ) ); if ( ! empty( $args ) ) { $args[] = $limit_int; // phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}sixrsh_logs WHERE {$where_sql} ORDER BY log_id DESC LIMIT %d", ...$args ), ARRAY_A ); // phpcs:enable } else { // phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}sixrsh_logs ORDER BY log_id DESC LIMIT %d", $limit_int ), ARRAY_A ); // phpcs:enable } return is_array( $results ) ? $results : array(); } catch ( \Throwable $e ) { error_log( '[6rsh WhatsApp] Logger::get_logs exception: ' . $e->getMessage() ); return array(); } } /** * Delete all log rows. * * @return void */ public static function clear_logs(): void { global $wpdb; try { // phpcs:disable WordPress.DB.DirectDatabaseQuery $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}sixrsh_logs" ); // phpcs:enable } catch ( \Throwable $e ) { error_log( '[6rsh WhatsApp] Logger::clear_logs exception: ' . $e->getMessage() ); } } }