— delete rows older than N days * wp apwpm purge --yes — wipe the whole table * wp apwpm export — dump rows to CSV * wp apwpm digest [period] — send a digest email now * wp apwpm scan-files — run a file-integrity scan immediately * * @package ActivityPilot */ if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) { return; } class APWPM_CLI { /** * Format one CSV row. * * @param array $fields Field values. * @return string */ protected static function csv_row( array $fields ) { $cells = array(); foreach ( $fields as $field ) { $field = (string) $field; if ( false !== strpbrk( $field, ",\"\n\r" ) ) { $field = '"' . str_replace( '"', '""', $field ) . '"'; } $cells[] = $field; } return implode( ',', $cells ); } /** * Write CSV contents via WP_Filesystem (Plugin Check–compatible). * * @param string $file Destination path. * @param array $lines CSV lines without trailing newlines. */ protected static function write_csv_file( $file, array $lines ) { if ( ! function_exists( 'WP_Filesystem' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } WP_Filesystem(); global $wp_filesystem; if ( ! $wp_filesystem || ! $wp_filesystem->put_contents( $file, implode( "\n", $lines ) . "\n", FS_CHMOD_FILE ) ) { WP_CLI::error( 'Cannot write ' . $file ); } } /** * List recent activity. * * ## OPTIONS * * [--per_page=] * [--user_id=] * [--severity=] * [--search=] * * @when after_wp_load */ public function list( $args, $assoc ) { $result = APWPM_DB::get_logs( array( 'per_page' => (int) ( $assoc['per_page'] ?? 20 ), 'user_id' => (int) ( $assoc['user_id'] ?? 0 ), 'severities' => isset( $assoc['severity'] ) ? array( $assoc['severity'] ) : array(), 'search' => $assoc['search'] ?? '', ) ); $rows = array(); foreach ( $result['items'] as $r ) { $rows[] = array( 'id' => $r->id, 'when' => $r->created_at, 'user' => $r->user_login, 'sev' => $r->severity, 'action' => $r->action_type, 'desc' => mb_substr( wp_strip_all_tags( (string) $r->description ), 0, 80 ), ); } WP_CLI\Utils\format_items( 'table', $rows, array( 'id', 'when', 'user', 'sev', 'action', 'desc' ) ); } /** @when after_wp_load */ public function count( $args, $assoc ) { WP_CLI::line( APWPM_DB::count_all_logs() ); } /** @when after_wp_load */ public function verify( $args, $assoc ) { $limit = isset( $assoc['limit'] ) ? (int) $assoc['limit'] : 5000; $result = APWPM_Integrity::verify( $limit ); if ( ! empty( $result['ok'] ) ) { WP_CLI::success( sprintf( 'Hash chain intact (%d rows checked).', (int) $result['checked'] ) ); } else { WP_CLI::error( sprintf( 'Hash chain broken at row #%d (after %d rows).', (int) $result['broken_at'], (int) $result['checked'] ) ); } } /** * Prune entries older than N days. * * ## OPTIONS * * : Threshold in days. * * [--yes] * * @when after_wp_load */ public function prune( $args, $assoc ) { WP_CLI\Utils\get_flag_value( $assoc, 'yes' ) || WP_CLI::confirm( 'Delete rows older than ' . (int) $args[0] . ' days?' ); $n = APWPM_DB::prune_older_than( (int) $args[0] ); WP_CLI::success( sprintf( 'Pruned %d rows.', (int) $n ) ); } /** * Purge all activity rows. * * ## OPTIONS * [--yes] * * @when after_wp_load */ public function purge( $args, $assoc ) { WP_CLI\Utils\get_flag_value( $assoc, 'yes' ) || WP_CLI::confirm( 'Truncate the entire activity log?' ); APWPM_DB::truncate(); WP_CLI::success( 'Activity log truncated.' ); } /** * Export to CSV. * * ## OPTIONS * * * @when after_wp_load */ public function export( $args, $assoc ) { $file = $args[0]; $lines = array( self::csv_row( array( 'id', 'created_at', 'user_login', 'action_type', 'object_type', 'object_title', 'severity', 'description' ) ), ); $page = 0; $per = 500; do { $rows = APWPM_DB::get_logs_export_batch( $per, $page * $per ); foreach ( (array) $rows as $r ) { $lines[] = self::csv_row( array( $r->id, $r->created_at, $r->user_login, $r->action_type, $r->object_type, $r->object_title, $r->severity, wp_strip_all_tags( (string) $r->description ), ) ); } $page++; } while ( ! empty( $rows ) ); self::write_csv_file( $file, $lines ); WP_CLI::success( 'Exported to ' . $file ); } /** * Send an activity digest now. * * ## OPTIONS * * [] * : daily | weekly | monthly. Default weekly. * * @when after_wp_load */ public function digest( $args, $assoc ) { $period = $args[0] ?? 'weekly'; $report = APWPM_Reports::build_report( $period ); APWPM_Reports::email_report( $report ); WP_CLI::success( 'Digest sent.' ); } /** @when after_wp_load */ public function scan_files( $args, $assoc ) { APWPM_File_Integrity::scan(); WP_CLI::success( 'File integrity scan complete.' ); } } WP_CLI::add_command( 'apwpm', 'APWPM_CLI' );