id, 'slms' ) ) {
return;
}
// Dismissed for good (older versions stored an expiry time, which counts as dismissed too).
$user_id = get_current_user_id();
if ( get_user_meta( $user_id, 'accessnow_slms_dismiss_reg_notice', true ) ) {
return;
}
if ( isset( $_GET['accessnow_slms_dismiss_reg_notice'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ?? '' ) ), 'accessnow_slms_dismiss_reg' ) ) {
update_user_meta( $user_id, 'accessnow_slms_dismiss_reg_notice', 1 );
return;
}
$dismiss_url = wp_nonce_url( add_query_arg( 'accessnow_slms_dismiss_reg_notice', '1' ), 'accessnow_slms_dismiss_reg' );
if ( empty( $slms_settings['allow_registration'] ) ) {
$message = __( 'Student registration is disabled. To allow visitors to create accounts and enroll in courses, enable "Allow Student Registration" in', 'accessnow-lms' );
$settings_url = admin_url( 'admin.php?page=slms-settings' );
$link_label = __( 'AccessNow LMS → Settings', 'accessnow-lms' );
} else {
$message = __( 'Student registration is enabled in AccessNow LMS, but WordPress registration is turned off. To let visitors create accounts, enable "Anyone can register" in', 'accessnow-lms' );
$settings_url = admin_url( 'options-general.php' );
$link_label = __( 'Settings → General', 'accessnow-lms' );
}
printf(
'
',
esc_html__( 'AccessNow LMS:', 'accessnow-lms' ),
esc_html( $message ),
esc_url( $settings_url ),
esc_html( $link_label ),
esc_url( $dismiss_url ),
esc_html__( 'Dismiss', 'accessnow-lms' )
);
}
public static function register_menu() {
// Shown to anyone who can edit courses (editors, instructors). Its Dashboard stays admin-only,
// so for them WordPress opens the menu at Courses.
add_menu_page(
__( 'AccessNow LMS', 'accessnow-lms' ),
__( 'AccessNow LMS', 'accessnow-lms' ),
'edit_slms_courses',
'slms-main',
array( __CLASS__, 'render_dashboard' ),
'dashicons-welcome-learn-more',
30
);
add_submenu_page(
'slms-main',
__( 'Dashboard', 'accessnow-lms' ),
__( 'Dashboard', 'accessnow-lms' ),
'manage_options',
'slms-main',
array( __CLASS__, 'render_dashboard' )
);
add_submenu_page(
'slms-main',
__( 'Enrollments', 'accessnow-lms' ),
__( 'Enrollments', 'accessnow-lms' ),
'manage_slms_enrollments',
'slms-enrollments',
array( Enrollment_Admin::class, 'render_page' )
);
add_submenu_page(
'slms-main',
__( 'Reports', 'accessnow-lms' ),
__( 'Reports', 'accessnow-lms' ),
'manage_slms_reports',
'slms-reports',
array( Reports::class, 'render_page' )
);
add_submenu_page(
'slms-main',
__( 'Settings', 'accessnow-lms' ),
__( 'Settings', 'accessnow-lms' ),
'manage_options',
'slms-settings',
array( __CLASS__, 'render_settings' )
);
// WordPress checks access to post-new.php?post_type=... before the page sets its menu parent,
// so without a menu entry for it the check falls back to Posts > Add New, which needs
// edit_posts. Someone who can create courses but not posts (an instructor) gets an Add New
// entry for each type they can create; admins' and editors' menus are unchanged.
if ( ! current_user_can( 'edit_posts' ) ) {
foreach ( array_keys( Capabilities::POST_TYPES ) as $post_type ) {
$type = get_post_type_object( $post_type );
if ( $type && current_user_can( $type->cap->create_posts ) ) {
add_submenu_page( 'slms-main', $type->labels->add_new_item, $type->labels->add_new_item, $type->cap->create_posts, 'post-new.php?post_type=' . $post_type );
}
}
}
}
public static function render_dashboard() {
echo '' . esc_html__( 'AccessNow LMS Dashboard', 'accessnow-lms' ) . '
';
$total_courses = wp_count_posts( 'slms_course' )->publish;
$total_lessons = wp_count_posts( 'slms_lesson' )->publish;
$total_enrollments = Enrollment::count_enrollments( array( 'status' => 'active' ) );
echo '
';
printf( '
', esc_html( number_format_i18n( (int) $total_courses ) ), esc_html__( 'Courses', 'accessnow-lms' ) );
printf( '
', esc_html( number_format_i18n( (int) $total_lessons ) ), esc_html__( 'Lessons', 'accessnow-lms' ) );
printf( '
', esc_html( number_format_i18n( (int) $total_enrollments ) ), esc_html__( 'Active Enrollments', 'accessnow-lms' ) );
echo '
';
}
public static function render_settings() {
if ( isset( $_POST['accessnow_slms_settings_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['accessnow_slms_settings_nonce'] ) ), 'accessnow_slms_save_settings' ) && current_user_can( 'manage_options' ) ) {
$settings = array(
'allow_registration' => isset( $_POST['allow_registration'] ) ? 1 : 0,
'header_inherit' => isset( $_POST['header_inherit'] ) ? 1 : 0,
'points_lesson_complete' => absint( $_POST['points_lesson_complete'] ?? 10 ),
'points_quiz_pass' => absint( $_POST['points_quiz_pass'] ?? 25 ),
'points_course_complete' => absint( $_POST['points_course_complete'] ?? 100 ),
'email_enrollment' => isset( $_POST['email_enrollment'] ) ? 1 : 0,
'email_completion' => isset( $_POST['email_completion'] ) ? 1 : 0,
'email_quiz_result' => isset( $_POST['email_quiz_result'] ) ? 1 : 0,
'email_admin_enrollment' => isset( $_POST['email_admin_enrollment'] ) ? 1 : 0,
'delete_data_on_uninstall' => isset( $_POST['delete_data_on_uninstall'] ) ? 1 : 0,
);
Settings::save( $settings );
echo '' . esc_html__( 'Settings saved.', 'accessnow-lms' ) . '
';
}
$settings = Settings::all();
$defaults = array(
'allow_registration' => 0,
'header_inherit' => 1,
'points_lesson_complete' => 10,
'points_quiz_pass' => 25,
'points_course_complete' => 100,
// As Notifications sends them before the settings are first saved: only the quiz email is on.
'email_enrollment' => 0,
'email_completion' => 0,
'email_quiz_result' => 1,
'email_admin_enrollment' => 0,
'delete_data_on_uninstall' => 0,
);
$settings = wp_parse_args( $settings, $defaults );
echo '' . esc_html__( 'AccessNow LMS Settings', 'accessnow-lms' ) . '
';
echo '
';
}
public static function enqueue_assets( $hook ) {
$screen = get_current_screen();
if ( ! $screen || false === strpos( $screen->id, 'slms' ) ) {
return;
}
wp_enqueue_style( 'slms-admin', ACCESSNOW_SLMS_PLUGIN_URL . 'assets/css/slms-admin.css', array(), ACCESSNOW_SLMS_VERSION );
wp_enqueue_script( 'slms-admin', ACCESSNOW_SLMS_PLUGIN_URL . 'assets/js/slms-admin.js', array( 'jquery', 'jquery-ui-sortable' ), ACCESSNOW_SLMS_VERSION, true );
wp_localize_script(
'slms-admin',
'slms_admin',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'accessnow_slms_admin' ),
'i18n' => array(
'select_attachments' => __( 'Select Attachments', 'accessnow-lms' ),
/* translators: %s: a student's name. */
'remove_user' => __( 'Remove %s', 'accessnow-lms' ),
'no_users' => __( 'No matching users.', 'accessnow-lms' ),
'user_found' => __( 'One matching user. Press the down arrow to choose it.', 'accessnow-lms' ),
/* translators: %d: number of matching users (2 or more). */
'users_found' => __( '%d matching users. Use the up and down arrows to choose.', 'accessnow-lms' ),
/* translators: %s: a student's name. */
'user_added' => __( '%s added.', 'accessnow-lms' ),
'correct_answer' => __( 'Correct answer', 'accessnow-lms' ),
'option' => __( 'Option', 'accessnow-lms' ),
'remove_option' => __( 'Remove option', 'accessnow-lms' ),
'remove_answer' => __( 'Remove answer', 'accessnow-lms' ),
),
)
);
}
/* ─── Lesson Columns: Course + Unit ──────────────────────── */
public static function lesson_columns( $columns ) {
$new = array();
foreach ( $columns as $key => $label ) {
$new[ $key ] = $label;
if ( 'title' === $key ) {
$new['slms_course'] = __( 'Course', 'accessnow-lms' );
$new['slms_unit'] = __( 'Unit', 'accessnow-lms' );
}
}
return $new;
}
/**
* Print an edit link to a post, or a dash when it doesn't exist.
*
* @param int $target_id Post ID.
*/
private static function edit_link_or_dash( $target_id ) {
$target = $target_id ? get_post( $target_id ) : null;
if ( $target ) {
printf( '%s', esc_url( get_edit_post_link( $target->ID ) ), esc_html( $target->post_title ) );
} else {
echo '—';
}
}
public static function lesson_column_data( $column, $post_id ) {
$unit_id = (int) get_post_meta( $post_id, '_slms_parent_unit', true );
if ( 'slms_unit' === $column ) {
self::edit_link_or_dash( $unit_id );
}
if ( 'slms_course' === $column ) {
self::edit_link_or_dash( $unit_id ? (int) get_post_meta( $unit_id, '_slms_parent_course', true ) : 0 );
}
}
/* ─── Unit Columns: Course ───────────────────────────────── */
public static function unit_columns( $columns ) {
$new = array();
foreach ( $columns as $key => $label ) {
$new[ $key ] = $label;
if ( 'title' === $key ) {
$new['slms_course'] = __( 'Course', 'accessnow-lms' );
}
}
return $new;
}
public static function unit_column_data( $column, $post_id ) {
if ( 'slms_course' === $column ) {
self::edit_link_or_dash( (int) get_post_meta( $post_id, '_slms_parent_course', true ) );
}
}
/* ─── Quiz Columns: Lesson + Course ──────────────────────── */
public static function quiz_columns( $columns ) {
$new = array();
foreach ( $columns as $key => $label ) {
$new[ $key ] = $label;
if ( 'title' === $key ) {
$new['slms_course'] = __( 'Course', 'accessnow-lms' );
$new['slms_lesson'] = __( 'Lesson', 'accessnow-lms' );
}
}
return $new;
}
public static function quiz_column_data( $column, $post_id ) {
$lesson_id = (int) get_post_meta( $post_id, '_slms_parent_lesson', true );
if ( 'slms_lesson' === $column ) {
self::edit_link_or_dash( $lesson_id );
}
if ( 'slms_course' === $column ) {
$unit_id = $lesson_id ? (int) get_post_meta( $lesson_id, '_slms_parent_unit', true ) : 0;
self::edit_link_or_dash( $unit_id ? (int) get_post_meta( $unit_id, '_slms_parent_course', true ) : 0 );
}
}
/* ─── Course Columns: Units + Lessons count ──────────────── */
public static function course_columns( $columns ) {
$new = array();
foreach ( $columns as $key => $label ) {
$new[ $key ] = $label;
if ( 'title' === $key ) {
$new['slms_units'] = __( 'Units', 'accessnow-lms' );
$new['slms_lessons'] = __( 'Lessons', 'accessnow-lms' );
}
}
return $new;
}
public static function course_column_data( $column, $post_id ) {
if ( 'slms_units' === $column ) {
$count = count(
get_posts(
array(
'post_type' => 'slms_unit',
'posts_per_page' => -1,
'post_status' => 'any',
'meta_key' => '_slms_parent_course', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- course structure is stored as post meta.
'meta_value' => $post_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- course structure is stored as post meta.
'fields' => 'ids',
)
)
);
echo (int) $count;
}
if ( 'slms_lessons' === $column ) {
$units = get_posts(
array(
'post_type' => 'slms_unit',
'posts_per_page' => -1,
'post_status' => 'any',
'meta_key' => '_slms_parent_course', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- course structure is stored as post meta.
'meta_value' => $post_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- course structure is stored as post meta.
'fields' => 'ids',
)
);
$count = 0;
foreach ( $units as $unit_id ) {
$count += count(
get_posts(
array(
'post_type' => 'slms_lesson',
'posts_per_page' => -1,
'post_status' => 'any',
'meta_key' => '_slms_parent_unit', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- course structure is stored as post meta.
'meta_value' => $unit_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- course structure is stored as post meta.
'fields' => 'ids',
)
)
);
}
echo (int) $count;
}
}
}