Activity Logs — who changed what, when. Call log() from * the actual mutation points (Form::create/update/delete, Entry::delete, * Settings::update) rather than trying to infer changes after the fact. */ class Activity_Log { public static function table() { global $wpdb; return $wpdb->prefix . 'chargeforms_activity_log'; } /** * @param string $action Short machine key, e.g. 'form_created', 'form_deleted', 'settings_updated'. * @param string $object_type 'form' | 'entry' | 'settings'. * @param int|null $object_id * @param string $description Human-readable line already assembled by the caller (who has the context — a title, a count — to phrase it well). */ public static function log( $action, $object_type, $object_id, $description ) { global $wpdb; $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- custom plugin table, no core API exists for it. self::table(), [ 'user_id' => get_current_user_id() ?: null, 'action' => $action, 'object_type' => $object_type, 'object_id' => $object_id, 'description' => $description, // GMT (roadmap issue #27) — every timestamp column this // plugin writes is now consistently GMT; the Tools > // Activity Logs "X ago" display converts back for // comparison rather than assuming site-local. 'created_at' => current_time( 'mysql', true ), ], [ '%d', '%s', '%s', '%d', '%s', '%s' ] ); } public static function query( array $args = [] ) { global $wpdb; $page = max( 1, (int) ( $args['page'] ?? 1 ) ); $per_page = max( 1, (int) ( $args['per_page'] ?? 20 ) ); $offset = ( $page - 1 ) * $per_page; $table = self::table(); $total = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom plugin table, no core API exists for it; per-request freshness needed. $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom plugin table, no core API exists for it; per-request freshness needed. $wpdb->prepare( 'SELECT * FROM %i ORDER BY created_at DESC, id DESC LIMIT %d OFFSET %d', $table, $per_page, $offset ), ARRAY_A ); return [ 'items' => $rows ?: [], 'total' => $total, 'page' => $page, 'per_page' => $per_page, ]; } public static function count_all() { global $wpdb; return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', self::table() ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom plugin table, no core API exists for it; per-request freshness needed. } }