users = $this->prefix . 'users';
$this->sessions = $this->prefix . 'sessions';
$this->activity = $this->prefix . 'activity';
$this->wpal_DBConnect( $uname, $pass, $db, $host );
}
/**
* Establishes a connection to the external database.
*
* Uses WordPress’s wpdb class to connect to the external database and displays an admin
* notice if the connection fails.
*
* @since 1.0.0
* @param string $uname Database username.
* @param string $pass Database password.
* @param string $db Database name.
* @param string $host Database host.
*/
protected function wpal_DBConnect( $uname, $pass, $db, $host ) {
$this->wpaldb = new wpdb( $uname, $pass, $db, $host );
$allowed_screens = [
'toplevel_page_wpal-settings',
'wpal_page_wpal-db-settings',
'wpal_page_wpal-export-data',
];
if ( ! empty( $this->wpaldb->error ) ) {
$this->wpaldb = null;
add_action( 'current_screen', function( $screen ) use($allowed_screens) {
if ( isset( $screen->id ) && in_array( $screen->id, $allowed_screens, true )) {
add_action( 'admin_notices', function() {
?>
id ) && in_array( $screen->id, $allowed_screens, true ) ) {
add_action( 'admin_notices', function() {
?>
wpaldb ) ) {
return false;
}
$charset_collate = $this->wpaldb->get_charset_collate();
// Create users table.
$users_table_sql = "CREATE TABLE IF NOT EXISTS {$this->users} (
user_id INT NOT NULL,
user_name VARCHAR(100) NOT NULL,
user_email VARCHAR(150) NOT NULL,
user_role VARCHAR(50) NOT NULL,
user_active TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (user_id)
) $charset_collate;";
if ( false === $this->wpaldb->query( $users_table_sql ) ) {
return new WP_Error( 'db_create_users_error', 'Failed to create users table.');
}
// Create sessions table.
$sessions_table_sql = "CREATE TABLE IF NOT EXISTS {$this->sessions} (
session_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
session_token VARCHAR(255) NOT NULL,
user_ip VARCHAR(45) NOT NULL,
user_agent VARCHAR(255) NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY (session_token),
FOREIGN KEY (user_id) REFERENCES {$this->users}(user_id) ON DELETE CASCADE ON UPDATE CASCADE
) $charset_collate;";
if ( false === $this->wpaldb->query( $sessions_table_sql ) ) {
return new WP_Error( 'db_create_sessions_error', 'Failed to create sessions table.');
}
// Create activity table.
$activity_table_sql = "CREATE TABLE IF NOT EXISTS {$this->activity} (
activity_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
activity_id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
activity_type VARCHAR(100) NOT NULL,
activity_details TEXT NOT NULL,
activity_session VARCHAR(255),
PRIMARY KEY (activity_id),
FOREIGN KEY (user_id) REFERENCES {$this->users}(user_id) ON DELETE CASCADE ON UPDATE CASCADE
) $charset_collate;";
if ( false === $this->wpaldb->query( $activity_table_sql ) ) {
return new WP_Error( 'db_create_activity_error', 'Failed to create activity table.');
}
return true;
}
/**
* Inserts a user record into the users table.
*
* Adds a new user with their ID, username, email, and role. Checks for duplicates
* and sanitizes inputs for data integrity.
*
* @since 1.0.0
* @param int $user_id User ID from WordPress.
* @param string $user_name Username of the user.
* @param string $user_email Email address of the user.
* @param string $user_role Role of the user (e.g., 'administrator', 'subscriber').
* @return bool|WP_Error True on success, WP_Error on failure or duplicate.
*/
public function wpal_insertUser( $user_id, $user_name, $user_email, $user_role ) {
if ( empty( $this->wpaldb ) ) {
return false;
}
$data = [
'user_id' => $user_id,
'user_name' => sanitize_text_field( $user_name ),
'user_email' => sanitize_email( $user_email ),
'user_role' => sanitize_text_field( $user_role ),
];
$format = [ '%d', '%s', '%s', '%s' ];
// Check if user already exists.
$exists = $this->wpaldb->get_var(
$this->wpaldb->prepare(
"SELECT COUNT(*) FROM {$this->users} WHERE user_id = %d",
$user_id
)
);
if ( $exists > 0 ) {
return new WP_Error( 'db_duplicate_user', 'User already exists.');
}
// Attempt insert.
$inserted = $this->wpaldb->insert( $this->users, $data, $format );
if ( false === $inserted ) {
return new WP_Error( 'db_insert_error', 'Failed to insert user.');
}
return true;
}
/**
* Updates a user’s active status in the users table.
*
* Modifies the `user_active` field for the specified user ID, typically to mark
* users as inactive (0) or active (1).
*
* @since 1.0.0
* @param int $user_id User ID to update.
* @param int $user_active New active status (0 for inactive, 1 for active).
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public function wpal_updateUser( $user_id, $user_active ) {
if ( empty( $this->wpaldb ) ) {
return false;
}
$data = [ 'user_active' => $user_active ];
$where = [ 'user_id' => $user_id ];
$updated = $this->wpaldb->update( $this->users, $data, $where, [ '%d' ], [ '%d' ] );
if ( false === $updated ) {
return new WP_Error( 'db_update_error', 'Failed to update user.');
}
return true;
}
/**
* Inserts a session record into the sessions table.
*
* Adds a new session with the session token, user IP, user agent, and associated user ID.
* Sanitizes inputs for data integrity.
*
* @since 1.0.0
* @param string $session_token Unique session token.
* @param string $user_ip User’s IP address.
* @param string $user_agent User’s browser user-agent string.
* @param int $user_id User ID associated with the session.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public function wpal_insertSession( $session_token, $user_ip, $user_agent, $user_id ) {
if ( empty( $this->wpaldb ) ) {
return false;
}
$data = [
'session_token' => sanitize_text_field( $session_token ),
'user_ip' => sanitize_text_field( $user_ip ),
'user_agent' => sanitize_text_field( $user_agent ),
'user_id' => $user_id,
];
$format = [ '%s', '%s', '%s', '%d' ];
$inserted = $this->wpaldb->insert( $this->sessions, $data, $format );
if ( false === $inserted ) {
return new WP_Error( 'db_insert_error', 'Failed to insert session.');
}
return true;
}
/**
* Inserts an activity record into the activity table.
*
* Adds a new activity with user ID, activity type, details, and session token.
* Sanitizes inputs for data integrity.
*
* @since 1.0.0
* @param int $user_id User ID associated with the activity.
* @param string $activity_type Type of activity (e.g., 'user', 'post').
* @param string $activity_details Detailed description of the activity.
* @param string $activity_session Session token linking to a session.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public function wpal_insertActivity( $user_id, $activity_type, $activity_details, $activity_session ) {
if ( empty( $this->wpaldb ) ) {
return false;
}
$log_count = $this->wpaldb->get_var(
$this->wpaldb->prepare(
"SELECT COUNT(*) FROM {$this->activity} WHERE %d = %d", 1, 1
)
);
if ( $log_count >= 1000 ) {
update_option( 'wpal_log_limit_notice', 1 );
return;
}
$data = [
'user_id' => $user_id,
'activity_type' => sanitize_text_field( $activity_type ),
'activity_details' => sanitize_textarea_field( $activity_details ),
'activity_session' => sanitize_text_field( $activity_session ),
];
$format = [ '%d', '%s', '%s', '%s' ];
$inserted = $this->wpaldb->insert( $this->activity, $data, $format );
if ( false === $inserted ) {
return new WP_Error( 'db_insert_error', 'Failed to insert activity.');
}
return true;
}
/**
* Displays the latest 100 activity records in an HTML table.
*
* Retrieves and displays the most recent 100 activity records, joining with the
* `wpal_users` table to include user details. Outputs an HTML table in the admin interface.
*
* @since 1.0.0
*/
public function wpal_displayActivityTable() {
if ( empty( $this->wpaldb ) ) {
return;
}
$users_table = $this->users;
$activity_table = $this->activity;
$query = $this->wpaldb->prepare(
"
SELECT
a.activity_id,
a.user_id,
u.user_name AS user_name,
u.user_role,
a.activity_type,
a.activity_details,
a.activity_session,
a.activity_time
FROM {$activity_table} AS a
LEFT JOIN {$users_table} AS u ON a.user_id = u.user_id
ORDER BY a.activity_time DESC
LIMIT %d
", 100
);
$results = $this->wpaldb->get_results( $query );
$allowed_screens = [
'toplevel_page_wpal-settings',
'wpal_page_wpal-db-settings',
'wpal_page_wpal-export-data',
];
if ( empty( $results ) ) {
add_action( 'current_screen', function( $screen ) use($allowed_screens) {
if ( isset( $screen->id ) && in_array( $screen->id, $allowed_screens, true )) {
add_action( 'admin_notices', function() {
?>
|
|
|
|
|
|
|
|
| activity_time ); ?> |
activity_id ); ?> |
user_id ); ?> |
user_name ); ?> |
user_role ); ?> |
activity_type ); ?> |
activity_details ); ?> |
activity_session ); ?> |
wpaldb ) ) {
return;
}
$users_table = $this->users;
$activity_table = $this->activity;
if (
isset( $_GET['export_activity_csv'] ) &&
'1' === $_GET['export_activity_csv'] &&
isset( $_GET['_wpnonce'] ) &&
wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'export_activity_csv_nonce' )
) {
$export_query = "
SELECT
a.activity_time,
a.activity_id,
a.user_id,
u.user_name,
u.user_role,
a.activity_type,
a.activity_details,
a.activity_session
FROM {$activity_table} AS a
LEFT JOIN {$users_table} AS u ON a.user_id = u.user_id
ORDER BY a.activity_time DESC
LIMIT 1000
";
$export_results = $this->wpaldb->get_results( $export_query, ARRAY_A );
if ( null === $export_results ) {
?>