'*' . $term . '*',
'search_columns' => array( 'user_login', 'user_email', 'display_name' ),
'number' => self::SEARCH_LIMIT,
'orderby' => 'display_name',
'fields' => array( 'ID', 'display_name', 'user_login', 'user_email' ),
)
);
$results = array();
foreach ( $query->get_results() as $user ) {
$results[] = array(
'id' => (int) $user->ID,
'label' => self::user_label( $user ),
);
}
wp_send_json_success( $results );
}
/**
* "Display Name (login, email)" for a user in the picker.
*
* @param object $user User (ID, display_name, user_login, user_email).
* @return string
*/
private static function user_label( $user ) {
/* translators: 1: display name, 2: username, 3: email address. */
return sprintf( __( '%1$s (%2$s, %3$s)', 'accessnow-lms' ), $user->display_name, $user->user_login, $user->user_email );
}
/**
* Users named in the enrolment form: the picker's IDs, plus anything typed in the box
* (user IDs, usernames or emails separated by commas or new lines, which also works without
* JavaScript).
*
* @param array $ids Picked user IDs.
* @param string $text Typed text.
* @return array { users: int[], unknown: string[] }
*/
public static function resolve_users( array $ids, $text ) {
$users = array();
$unknown = array();
foreach ( $ids as $id ) {
if ( get_userdata( absint( $id ) ) ) {
$users[] = absint( $id );
}
}
foreach ( preg_split( '/[,\n]+/', (string) $text ) as $token ) {
$token = trim( $token );
if ( '' === $token ) {
continue;
}
if ( ctype_digit( $token ) ) {
$user = get_userdata( (int) $token );
} elseif ( is_email( $token ) ) {
$user = get_user_by( 'email', $token );
} else {
$user = get_user_by( 'login', $token );
}
if ( $user ) {
$users[] = (int) $user->ID;
} else {
$unknown[] = $token;
}
}
return array(
'users' => array_values( array_unique( $users ) ),
'unknown' => $unknown,
);
}
/**
* Enrol each named user in each chosen course and print the outcome.
*/
private static function handle_enroll_form() {
$picked = isset( $_POST['enroll_user_ids'] ) ? array_map( 'absint', (array) wp_unslash( $_POST['enroll_user_ids'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified by the caller.
$typed = isset( $_POST['enroll_users'] ) ? sanitize_textarea_field( wp_unslash( $_POST['enroll_users'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified by the caller.
$courses = isset( $_POST['enroll_course_ids'] ) ? array_map( 'absint', (array) wp_unslash( $_POST['enroll_course_ids'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified by the caller.
$notify = ! empty( $_POST['notify_student'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified by the caller.
$until = isset( $_POST['enroll_access_until'] ) ? sanitize_text_field( wp_unslash( $_POST['enroll_access_until'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified by the caller.
$expires = '' === $until ? null : Enrollment::expiry_from_date( $until );
if ( '' !== $until && null === $expires ) {
echo '
' . esc_html__( 'The access end date is not a valid date.', 'accessnow-lms' ) . '
';
return;
}
$courses = array_values(
array_unique(
array_filter(
$courses,
function ( $id ) {
return 'slms_course' === get_post_type( $id );
}
)
)
);
$found = self::resolve_users( $picked, $typed );
if ( $found['unknown'] ) {
printf(
'',
/* translators: %s: comma-separated list of what was typed. */
esc_html( sprintf( __( 'No user found for: %s', 'accessnow-lms' ), implode( ', ', $found['unknown'] ) ) )
);
}
if ( ! $found['users'] || ! $courses ) {
echo '' . esc_html__( 'Choose at least one student and one course.', 'accessnow-lms' ) . '
';
return;
}
$new = 0;
$already = 0;
foreach ( $found['users'] as $user_id ) {
foreach ( $courses as $course_id ) {
if ( Enrollment::get_active_enrollment( $user_id, $course_id ) ) {
++$already;
continue;
}
$enrollment_id = Enrollment::enroll( $user_id, $course_id, get_current_user_id() );
if ( $enrollment_id ) {
++$new;
if ( $expires ) {
Enrollment::set_expiry( $enrollment_id, $expires );
}
// Self-enrolment sends its email on its own; for an administrator it is this checkbox.
if ( $notify ) {
Notifications::send_enrollment_email( $user_id, $course_id );
}
}
}
}
$message = sprintf(
/* translators: %s: number of new enrolments. */
_n( '%s new enrollment.', '%s new enrollments.', $new, 'accessnow-lms' ),
number_format_i18n( $new )
);
if ( $already ) {
$message .= ' ' . sprintf(
/* translators: %s: number of enrolments that already existed. */
_n( '%s was already enrolled.', '%s were already enrolled.', $already, 'accessnow-lms' ),
number_format_i18n( $already )
);
}
printf( '', esc_html( $message ) );
}
public static function render_page() {
if ( ! current_user_can( 'manage_slms_enrollments' ) ) {
wp_die( esc_html__( 'You do not have permission to manage enrollments.', 'accessnow-lms' ) );
}
// Handle add enrollment
if ( isset( $_POST['accessnow_slms_enroll_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['accessnow_slms_enroll_nonce'] ) ), 'accessnow_slms_admin_enroll' ) ) {
self::handle_enroll_form();
}
// Handle bulk actions
if ( isset( $_POST['slms_bulk_action'] ) && isset( $_POST['enrollment_ids'] ) ) {
check_admin_referer( 'accessnow_slms_bulk_enrollments' );
$action = sanitize_text_field( wp_unslash( $_POST['slms_bulk_action'] ) );
$ids = array_map( 'absint', (array) wp_unslash( $_POST['enrollment_ids'] ) );
if ( 'drop' === $action ) {
foreach ( $ids as $id ) {
Enrollment::drop( $id, get_current_user_id() );
}
echo '' . esc_html__( 'Enrollments updated.', 'accessnow-lms' ) . '
';
} elseif ( 'set_access' === $action || 'clear_access' === $action ) {
$until = isset( $_POST['slms_access_until'] ) ? sanitize_text_field( wp_unslash( $_POST['slms_access_until'] ) ) : '';
$expires = 'set_access' === $action ? Enrollment::expiry_from_date( $until ) : null;
if ( 'set_access' === $action && null === $expires ) {
echo '' . esc_html__( 'Choose the last day of access first.', 'accessnow-lms' ) . '
';
} else {
$changed = 0;
foreach ( $ids as $id ) {
$enrollment = Enrollment::get_enrollment_by_id( $id );
// Dropped enrolments give no access, so their end date means nothing.
if ( $enrollment && 'dropped' !== $enrollment->status && Enrollment::set_expiry( $id, $expires ) ) {
++$changed;
}
}
printf(
'',
/* translators: %s: number of enrolments. */
esc_html( sprintf( _n( 'Access end date updated for %s enrollment.', 'Access end date updated for %s enrollments.', $changed, 'accessnow-lms' ), number_format_i18n( $changed ) ) )
);
}
} elseif ( 'reenroll' === $action ) {
$reenrolled = 0;
foreach ( $ids as $id ) {
$enrollment = Enrollment::get_enrollment_by_id( $id );
if ( $enrollment && in_array( $enrollment->status, array( 'completed', 'dropped' ), true ) ) {
$new_id = Enrollment::enroll( $enrollment->user_id, $enrollment->course_id, get_current_user_id() );
if ( $new_id ) {
++$reenrolled;
}
}
}
if ( $reenrolled ) {
printf(
'',
/* translators: %s: number of students. */
esc_html( sprintf( _n( '%s student re-enrolled.', '%s students re-enrolled.', $reenrolled, 'accessnow-lms' ), number_format_i18n( $reenrolled ) ) )
);
}
}
}
// List filters from the query string: read-only, so no nonce.
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$filter_course = isset( $_GET['course_id'] ) ? absint( $_GET['course_id'] ) : 0;
$filter_status = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : '';
$paged = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;
// phpcs:enable WordPress.Security.NonceVerification.Recommended
if ( ! in_array( $filter_status, array( '', 'active', 'completed', 'dropped' ), true ) ) {
$filter_status = '';
}
$per_page = 20;
$args = array(
'per_page' => $per_page,
'offset' => ( $paged - 1 ) * $per_page,
);
if ( $filter_course ) {
$args['course_id'] = $filter_course;
}
if ( $filter_status ) {
$args['status'] = $filter_status;
}
$enrollments = Enrollment::get_all_enrollments( $args );
$total = Enrollment::count_enrollments( $args );
$total_pages = ceil( $total / $per_page );
$courses = get_posts(
array(
'post_type' => 'slms_course',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
)
);
?>
1 ) : ?>
add_query_arg( 'paged', '%#%' ),
'format' => '',
'total' => $total_pages,
'current' => $paged,
)
)
);
?>