prefix . '100p_generation_history'; } /** * Check if the table exists. * * @return bool */ private function table_exists() { global $wpdb; $table = $this->get_table_name(); return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table ) ) ) === $table; } /** * Log a generation event. * * @param array $args { * @type string $template_id Template identifier. * @type string $template_name Human-readable template name. * @type int $page_id Page/post where generation occurred. * @type string $format Output format (pdf, png). * @type string $status Generation status (success, error). * @type string $quality Render quality. * @type array $variables Resolved variable key-value pairs. * @type string $visitor_ip Visitor IP address. * } * @return bool */ public function log_generation( $args ) { global $wpdb; if ( ! $this->table_exists() ) { return false; } // Support legacy positional arguments for backward compat. if ( is_string( $args ) ) { $args = [ 'template_id' => func_get_arg( 0 ), 'page_id' => func_num_args() > 1 ? func_get_arg( 1 ) : 0, 'format' => func_num_args() > 2 ? func_get_arg( 2 ) : 'pdf', 'status' => func_num_args() > 3 ? func_get_arg( 3 ) : 'success', 'template_name' => func_num_args() > 4 ? func_get_arg( 4 ) : '', ]; } $template_id = isset( $args['template_id'] ) ? sanitize_text_field( $args['template_id'] ) : ''; $template_name = isset( $args['template_name'] ) ? sanitize_text_field( $args['template_name'] ) : ''; $page_id = isset( $args['page_id'] ) ? absint( $args['page_id'] ) : 0; $format = isset( $args['format'] ) ? sanitize_key( $args['format'] ) : 'pdf'; $status = isset( $args['status'] ) ? sanitize_key( $args['status'] ) : 'success'; $quality = isset( $args['quality'] ) ? sanitize_key( $args['quality'] ) : 'high'; $variables = isset( $args['variables'] ) && is_array( $args['variables'] ) ? $args['variables'] : []; $visitor_ip = isset( $args['visitor_ip'] ) ? sanitize_text_field( $args['visitor_ip'] ) : ''; if ( empty( $template_name ) ) { $template_service = new Hundred_Prints_Template_Service(); $template = $template_service->get_template( $template_id ); if ( is_array( $template ) && isset( $template['name'] ) ) { $template_name = $template['name']; } else { $template_name = 'Unknown Template'; } } $format = in_array( $format, [ 'pdf', 'png' ], true ) ? $format : 'pdf'; $status = in_array( $status, [ 'success', 'error' ], true ) ? $status : 'success'; return (bool) $wpdb->insert( $this->get_table_name(), [ 'generation_uuid' => wp_generate_uuid4(), 'template_id' => $template_id, 'template_name' => $template_name, 'page_id' => $page_id, 'user_id' => get_current_user_id() ?: null, 'visitor_ip' => $visitor_ip, 'variables_json' => wp_json_encode( $variables ), 'output_format' => $format, 'render_quality' => $quality, 'status' => $status, ], [ '%s', '%s', '%s', '%d', '%d', '%s', '%s', '%s', '%s', '%s' ] ); } /** * Delete generation history older than the configured retention period. * * @param int|null $days Retention window in days. * @return int|false Number of rows deleted, or false on failure. */ public function prune_old_logs( $days = null ) { global $wpdb; if ( ! $this->table_exists() ) { return false; } if ( null === $days ) { $settings = function_exists( 'hundred_prints_get_settings' ) ? hundred_prints_get_settings() : []; $days = isset( $settings['log_retention_days'] ) ? absint( $settings['log_retention_days'] ) : 30; } $days = min( 365, max( 1, absint( $days ) ) ); $cutoff = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp', true ) - ( $days * DAY_IN_SECONDS ) ); return $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->get_table_name()} WHERE created_at < %s", $cutoff ) ); } /** * Get total count of generations. */ public function get_total_generations() { global $wpdb; if ( ! $this->table_exists() ) { return 0; } $table = $this->get_table_name(); return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $table" ); } /** * Get count of active blocks. */ public function get_active_blocks_count() { global $wpdb; $query = "SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'publish' AND post_content LIKE '%wp-block-100prints-document%'"; return (int) $wpdb->get_var( $query ); } /** * Get recent activity log entries. */ public function get_recent_activity( $limit = 10 ) { global $wpdb; if ( ! $this->table_exists() ) { return []; } $table = $this->get_table_name(); $query = $wpdb->prepare( "SELECT * FROM $table ORDER BY created_at DESC LIMIT %d", $limit ); return $wpdb->get_results( $query ); } /** * Get count of generations in the last 30 days. */ public function get_generations_last_30_days() { global $wpdb; if ( ! $this->table_exists() ) { return 0; } $table = $this->get_table_name(); $query = "SELECT COUNT(*) FROM $table WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; return (int) $wpdb->get_var( $query ); } /** * Get the success rate of generated documents. */ public function get_success_rate() { global $wpdb; if ( ! $this->table_exists() ) { return 100.0; } $total = $this->get_total_generations(); if ( $total === 0 ) { return 100.0; } $table = $this->get_table_name(); $success = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table WHERE status = %s", 'success' ) ); return round( ( $success / $total ) * 100, 1 ); } /** * Get daily generation counts for the last 30 days. */ public function get_daily_counts_30_days() { global $wpdb; if ( ! $this->table_exists() ) { return []; } $table = $this->get_table_name(); $query = "SELECT DATE(created_at) as date, COUNT(*) as count FROM $table WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(created_at) ORDER BY DATE(created_at) ASC"; $results = $wpdb->get_results( $query, ARRAY_A ); // Fill in missing dates to prevent blank graph segments. $daily_data = []; for ( $i = 29; $i >= 0; $i-- ) { $date = date( 'Y-m-d', strtotime( "-$i days" ) ); $daily_data[ $date ] = 0; } foreach ( $results as $row ) { if ( isset( $daily_data[ $row['date'] ] ) ) { $daily_data[ $row['date'] ] = (int) $row['count']; } } return $daily_data; } /** * Get template usage breakdown. */ public function get_template_breakdown() { global $wpdb; if ( ! $this->table_exists() ) { return []; } $table = $this->get_table_name(); $query = "SELECT template_id, template_name, COUNT(*) as count, MAX(created_at) as last_used FROM $table GROUP BY template_id, template_name ORDER BY count DESC"; return $wpdb->get_results( $query ); } /** * Get all logs for CSV exports. */ public function get_all_activity_logs() { global $wpdb; if ( ! $this->table_exists() ) { return []; } $table = $this->get_table_name(); return $wpdb->get_results( "SELECT * FROM $table ORDER BY created_at DESC" ); } /** * Get a single generation history record by ID. * * @param int $id Record ID. * @return object|null */ public function get_record( $id ) { global $wpdb; if ( ! $this->table_exists() ) { return null; } $table = $this->get_table_name(); return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE id = %d", absint( $id ) ) ); } /** * Delete a single generation history record. * * @param int $id Record ID. * @return bool */ public function delete_record( $id ) { global $wpdb; if ( ! $this->table_exists() ) { return false; } $table = $this->get_table_name(); return (bool) $wpdb->delete( $table, [ 'id' => absint( $id ) ], [ '%d' ] ); } /** * Bulk delete generation history records. * * @param array $ids Array of record IDs. * @return int Number of rows deleted. */ public function bulk_delete( array $ids ) { global $wpdb; if ( ! $this->table_exists() || empty( $ids ) ) { return 0; } $table = $this->get_table_name(); $ids = array_map( 'absint', $ids ); $placeholders = implode( ', ', array_fill( 0, count( $ids ), '%d' ) ); return (int) $wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE id IN ($placeholders)", ...$ids ) ); } }