LLMS_Table_Students

LLMS_Table_Students class


Source Source

File: includes/admin/reporting/tables/llms.table.students.php

class LLMS_Table_Students extends LLMS_Admin_Table {

	/**
	 * Unique ID for the Table
	 *
	 * @var string
	 */
	protected $id = 'students';

	/**
	 * Value of the field being filtered by
	 *
	 * Only applicable if $filterby is set.
	 *
	 * @since 3.31.0
	 * @var string
	 */
	protected $filter = '';

	/**
	 * Field results are filtered by
	 *
	 * @since 3.31.0
	 * @var string
	 */
	protected $filterby = 'course_membership';

	/**
	 * Is the Table Exportable?
	 *
	 * @var boolean
	 */
	protected $is_exportable = true;

	/**
	 * Determine if the table is filterable
	 *
	 * @since 3.31.0
	 * @var boolean
	 */
	protected $is_filterable = true;

	/**
	 * If true, tfoot will add ajax pagination links
	 *
	 * @var boolean
	 */
	protected $is_paginated = true;

	/**
	 * Determine of the table is searchable
	 *
	 * @var boolean
	 */
	protected $is_searchable = true;

	/**
	 * Results sort order
	 *
	 * 'ASC' or 'DESC'
	 * Only applicable of $orderby is not set.
	 *
	 * @var string
	 */
	protected $order = 'ASC';

	/**
	 * Field results are sorted by
	 *
	 * @var string
	 */
	protected $orderby = 'name';

	/**
	 * Number of records to display per page
	 *
	 * @var int
	 */
	protected $per_page = 25;

	/**
	 * Retrieve data for the columns
	 *
	 * @since 3.2.0
	 * @since 3.15.0 Unknown.
	 * @since 3.36.0 Added "Last Seen" column.
	 * @since 3.36.1 Fixed "Last Seen" column displaying wrong date when the student last login date was saved as timestamp.
	 * @since 4.7.0 Speed up the query used to retrieve the last seen column by avoiding the found rows calculation.
	 * @since 6.0.0 Don't access `LLMS_Events_Query` properties directly
	 *              Use `LLMS_Student::get_awards_count()` for retrieving the number of earned achievements and certificates.
	 *
	 * @param string       $key     The column id / key.
	 * @param LLMS_Student $student Instance of the LLMS_Student.
	 * @return mixed
	 */
	public function get_data( $key, $student ) {

		switch ( $key ) {

			case 'achievements':
				$url   = LLMS_Admin_Reporting::get_current_tab_url(
					array(
						'stab'       => 'achievements',
						'student_id' => $student->get_id(),
					)
				);
				$value = '<a href="' . esc_url( $url ) . '">' . $student->get_awards_count( 'achievement' ) . '</a>';
				break;

			case 'certificates':
				$url   = LLMS_Admin_Reporting::get_current_tab_url(
					array(
						'stab'       => 'certificates',
						'student_id' => $student->get_id(),
					)
				);
				$value = '<a href="' . esc_url( $url ) . '">' . $student->get_awards_count( 'certificate' ) . '</a>';
				break;

			case 'completions':
				$courses = $student->get_completed_courses();
				$value   = count( $courses['results'] );
				break;

			case 'enrollments':
				$url         = LLMS_Admin_Reporting::get_current_tab_url(
					array(
						'stab'       => 'courses',
						'student_id' => $student->get_id(),
					)
				);
				$enrollments = $student->get_courses(
					array(
						'limit' => 1,
					)
				);
				$value       = '<a href="' . esc_url( $url ) . '">' . $enrollments['found'] . '</a>';
				break;

			case 'id':
				$id = $student->get_id();
				if ( current_user_can( 'list_users' ) ) {
					$value = '<a href="' . esc_url( get_edit_user_link( $id ) ) . '">' . $id . '</a>';
				} else {
					$value = $id;
				}
				break;

			case 'last_seen':
				$query = new LLMS_Events_Query(
					array(
						'actor'         => $student->get_id(),
						'per_page'      => 1,
						'sort'          => array(
							'date' => 'DESC',
						),
						'no_found_rows' => true,
					)
				);

				if ( $query->has_results() ) {
					$events = $query->get_events();
					$last   = array_shift( $events );
					$value  = $last->get( 'date' );
				} else {
					$value = $student->get( 'last_login' );
				}

				$value = $value ? date_i18n( get_option( 'date_format' ), is_numeric( $value ) ? $value : strtotime( $value ) ) : '&ndash;';

				break;

			case 'memberships':
				$url   = LLMS_Admin_Reporting::get_current_tab_url(
					array(
						'stab'       => 'memberships',
						'student_id' => $student->get_id(),
					)
				);
				$value = '<a href="' . esc_url( $url ) . '">' . count( $student->get_membership_levels() ) . '</a>';
				break;

			case 'name':
				$first = $student->get( 'first_name' );
				$last  = $student->get( 'last_name' );

				if ( ! $first || ! $last ) {
					$value = $student->get( 'display_name' );
				} else {
					$value = $last . ', ' . $first;
				}

				$url   = LLMS_Admin_Reporting::get_current_tab_url(
					array(
						'student_id' => $student->get_id(),
					)
				);
				$value = '<a href="' . esc_url( $url ) . '">' . $value . '</a>';

				break;

			case 'overall_grade':
				$value = $student->get_overall_grade( true );
				if ( is_numeric( $value ) ) {
					$value .= '%';
				}
				break;

			case 'overall_progress':
				$value = $this->get_progress_bar_html( $student->get_overall_progress( true ) );
				break;

			case 'registered':
				$value = $student->get_registration_date();
				break;

			default:
				$value = $key;

		}

		return $this->filter_get_data( $value, $key, $student );

	}

	/**
	 * Retrieve data for a cell in an export file
	 *
	 * Should be overridden in extending classes.
	 *
	 * @since 3.15.0
	 * @since 3.26.1 Unknown.
	 *
	 * @param string       $key     The column id / key.
	 * @param LLMS_Student $student Instance of the LLMS_Student.
	 * @return mixed
	 */
	public function get_export_data( $key, $student ) {

		switch ( $key ) {

			case 'id':
				$value = $student->get_id();
				break;

			case 'courses_cancelled':
			case 'courses_enrolled':
			case 'courses_expired':
				$status  = explode( '_', $key );
				$status  = array_pop( $status );
				$courses = $student->get_courses(
					array(
						'status' => $status,
					)
				);
				$titles  = array();
				foreach ( $courses['results'] as $id ) {
					$titles[] = get_the_title( $id );
				}
				$value = implode( ', ', $titles );

				break;

			case 'email':
				$value = $student->get( 'user_email' );
				break;

			case 'memberships_cancelled':
			case 'memberships_enrolled':
			case 'memberships_expired':
				$status      = explode( '_', $key );
				$status      = array_pop( $status );
				$memberships = $student->get_memberships(
					array(
						'status' => $status,
					)
				);
				$titles      = array();
				foreach ( $memberships['results'] as $id ) {
					$titles[] = get_the_title( $id );
				}
				$value = implode( ', ', $titles );

				break;

			case 'name_first':
				$value = $student->get( 'first_name' );
				break;

			case 'name_last':
				$value = $student->get( 'last_name' );
				break;

			case 'overall_grade':
				$value = $student->get_overall_grade( false );
				if ( is_numeric( $value ) ) {
					$value .= '%';
				}
				break;

			case 'overall_progress':
				$value = $student->get_overall_progress( false ) . '%';
				break;

			case 'billing_address_1':
			case 'billing_address_2':
			case 'billing_city':
			case 'billing_state':
			case 'billing_zip':
			case 'billing_country':
			case 'phone':
				$value = $student->get( $key );
				break;

			default:
				$value = $this->get_data( $key, $student );

		}

		return $this->filter_get_data( $value, $key, $student, 'export' );

	}

	/**
	 * Get the Text to be used as the placeholder in a searchable tables search input
	 *
	 * @since 3.2.0
	 * @since 3.15.0 Unknown.
	 *
	 * @return string
	 */
	public function get_table_search_form_placeholder() {
		return apply_filters( 'llms_table_get_' . $this->id . '_search_placeholder', __( 'Search students by name or email...', 'lifterlms' ) );
	}

	/**
	 * Get HTML for the filters displayed in the head of the table
	 *
	 * This overrides the LLMS_Admin_Table method.
	 *
	 * @since 3.31.0
	 * @since 3.37.2 Unknown.
	 *
	 * @return string
	 */
	public function get_table_filters_html() {
		$select_id       = sprintf( '%1$s-%2$s-filter', $this->id, 'course-membership' );
		$additional_data = array();
		// Limit Course/Membership results based on instructor access.
		if ( ! current_user_can( 'view_others_lifterlms_reports' ) && current_user_can( 'view_lifterlms_reports' ) ) {
			$instructor = llms_get_instructor();
			if ( $instructor ) {
				$additional_data[] = sprintf( 'data-instructor_id="%d"', $instructor->get( 'id' ) );
			}
		}
		$additional_data = implode( ' ', $additional_data );
		ob_start();
		?>
		<div class="llms-table-filters">
			<div class="llms-table-filter-wrap">
				<label class="screen-reader-text" for="<?php echo $select_id; ?>">
					<?php _e( 'Choose Course/Membership', 'lifterlms' ); ?>
				</label>
				<select data-post-type="llms_membership,course" class="llms-posts-select2 llms-table-filter" id="<?php echo $select_id; ?>" name="course_membership" style="min-width:200px;max-width:500px;"<?php echo $additional_data; ?>></select>
			</div>
		</div>
		<?php
		return ob_get_clean();
	}

	/**
	 * Retrieve an array of query arguments to pass to the LLMS_Student_Query
	 *
	 * @since 3.28.0
	 * @since 3.31.0 Added logic to setup the query args in order to allow the filtering by Course or Membership.
	 *
	 * @return array
	 */
	private function get_query_args() {

		$query_args = array(
			'page'     => $this->get_current_page(),
			'post_id'  => array(),
			'per_page' => $this->get_per_page(),
			'sort'     => $this->get_sort(),
		);

		if ( 'status' === $this->get_filterby() && 'any' !== $this->get_filter() ) {

			$query_args['statuses'] = array( $this->get_filter() );

		} elseif ( 'course_membership' === $this->get_filterby() && '' !== $this->get_filter() ) {

			$query_args['post_id']  = absint( $this->get_filter() );
			$query_args['statuses'] = 'enrolled';

		}

		if ( $this->get_search() ) {
			$query_args['search'] = $this->get_search();
		}

		return $query_args;

	}

	/**
	 * Execute a query to retrieve results from the table
	 *
	 * @since 3.2.0
	 * @since 3.28.0 Unknown.
	 * @since 6.0.0 Don't access `LLMS_Student_Query` properties directly.
	 *
	 * @param array $args Array of query args.
	 * @return void
	 */
	public function get_results( $args = array() ) {

		// Current user can't access this report.
		if ( ! current_user_can( 'view_others_lifterlms_reports' ) && ! current_user_can( 'view_lifterlms_reports' ) ) {
			return;
		}

		$this->parse_args( $args );

		$query_args = $this->get_query_args();

		if ( current_user_can( 'view_others_lifterlms_reports' ) ) {

			$query = new LLMS_Student_Query( $query_args );

		} elseif ( current_user_can( 'view_lifterlms_reports' ) ) {

			$instructor = llms_get_instructor();
			if ( ! $instructor ) {
				return;
			}
			$query = $instructor->get_students( $query_args );

		}

		$this->max_pages    = $query->get_max_pages();
		$this->is_last_page = $query->is_last_page();

		$this->tbody_data = $query->get_students();

	}

	/**
	 * Setup the array of sort arguments to pass to the LLMS_Student_Query for the table
	 *
	 * @since 3.28.0
	 *
	 * @return array
	 */
	private function get_sort() {

		$sort = array();
		switch ( $this->get_orderby() ) {

			case 'id':
				$sort = array(
					'id' => $this->get_order(),
				);
				break;

			case 'name':
				$sort = array(
					'last_name'  => $this->get_order(),
					'first_name' => 'ASC',
					'id'         => 'ASC',
				);
				break;

			case 'overall_grade':
				$sort = array(
					'overall_grade' => $this->get_order(),
					'last_name'     => 'ASC',
					'first_name'    => 'ASC',
					'id'            => 'ASC',
				);
				break;

			case 'overall_progress':
				$sort = array(
					'overall_progress' => $this->get_order(),
					'last_name'        => 'ASC',
					'first_name'       => 'ASC',
					'id'               => 'ASC',
				);
				break;

			case 'registered':
				$sort = array(
					'registered' => $this->get_order(),
					'last_name'  => 'ASC',
					'first_name' => 'ASC',
					'id'         => 'ASC',
				);
				break;

		}

		return $sort;

	}

	/**
	 * Parse arguments passed to get_results() method & setup table class variables.
	 *
	 * @since 3.28.0
	 * @since 3.31.0 Added logic to parse 'filterby' and 'filter' args when this table is filterable.
	 *
	 * @param array $args Array of arguments.
	 * @return void
	 */
	protected function parse_args( $args = array() ) {

		if ( ! $args ) {
			$args = $this->get_args();
		}

		$args = $this->clean_args( $args );

		if ( isset( $args['page'] ) ) {
			$this->current_page = absint( $args['page'] );
		}

		$this->order   = isset( $args['order'] ) ? $args['order'] : $this->get_order();
		$this->orderby = isset( $args['orderby'] ) ? $args['orderby'] : $this->get_orderby();

		$this->per_page = isset( $args['per_page'] ) ? $args['per_page'] : $this->get_per_page();

		if ( $this->is_filterable ) {
			$this->filterby = isset( $args['filterby'] ) ? $args['filterby'] : $this->get_filterby();
			$this->filter   = isset( $args['filter'] ) ? $args['filter'] : $this->get_filter();
		}

		if ( isset( $args['search'] ) ) {
			$this->search = $args['search'];
		}

	}

	/**
	 * Define the structure of arguments used to pass to the get_results method
	 *
	 * @since 2.3.0
	 * @since 3.28.0 Unknown.
	 *
	 * @return array
	 */
	public function set_args() {
		return array(
			'per_page' => apply_filters( 'llms_table_' . $this->id . '_per_page', $this->per_page ),
		);
	}

	/**
	 * Define the structure of the table
	 *
	 * @since 3.2.0
	 * @since 3.15.0 Unknown.
	 * @since 3.36.0 Add "Last Seen" column.
	 *
	 * @return array
	 */
	public function set_columns() {
		return array(
			'id'                    => array(
				'exportable' => true,
				'sortable'   => true,
				'title'      => __( 'ID', 'lifterlms' ),
			),
			'email'                 => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Email', 'lifterlms' ),
			),
			'name'                  => array(
				'sortable' => true,
				'title'    => __( 'Name', 'lifterlms' ),
			),
			'name_last'             => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Last Name', 'lifterlms' ),
			),
			'name_first'            => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'First Name', 'lifterlms' ),
			),
			'registered'            => array(
				'exportable' => true,
				'sortable'   => true,
				'title'      => __( 'Registration Date', 'lifterlms' ),
			),
			'last_seen'             => array(
				'exportable' => true,
				'sortable'   => false,
				'title'      => __( 'Last Seen', 'lifterlms' ),
			),
			'overall_progress'      => array(
				'exportable' => true,
				'sortable'   => true,
				'title'      => __( 'Progress', 'lifterlms' ),
			),
			'overall_grade'         => array(
				'exportable' => true,
				'sortable'   => true,
				'title'      => __( 'Grade', 'lifterlms' ),
			),
			'enrollments'           => array(
				'sortable' => false,
				'title'    => __( 'Enrollments', 'lifterlms' ),
			),
			'completions'           => array(
				'sortable' => false,
				'title'    => __( 'Completions', 'lifterlms' ),
			),
			'certificates'          => array(
				'sortable' => false,
				'title'    => __( 'Certificates', 'lifterlms' ),
			),
			'achievements'          => array(
				'sortable' => false,
				'title'    => __( 'Achievements', 'lifterlms' ),
			),
			'memberships'           => array(
				'sortable' => false,
				'title'    => __( 'Memberships', 'lifterlms' ),
			),
			'billing_address_1'     => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing Address 1', 'lifterlms' ),
			),
			'billing_address_2'     => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing Address 2', 'lifterlms' ),
			),
			'billing_city'          => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing City', 'lifterlms' ),
			),
			'billing_state'         => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing State', 'lifterlms' ),
			),
			'billing_zip'           => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing Zip', 'lifterlms' ),
			),
			'billing_country'       => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Billing Country', 'lifterlms' ),
			),
			'phone'                 => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Phone', 'lifterlms' ),
			),
			'courses_enrolled'      => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Courses (Enrolled)', 'lifterlms' ),
			),
			'courses_cancelled'     => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Courses (Cancelled)', 'lifterlms' ),
			),
			'courses_expired'       => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Courses (Expired)', 'lifterlms' ),
			),
			'memberships_enrolled'  => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Memberships (Enrolled)', 'lifterlms' ),
			),
			'memberships_cancelled' => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Memberships (Cancelled)', 'lifterlms' ),
			),
			'memberships_expired'   => array(
				'exportable'  => true,
				'export_only' => true,
				'title'       => __( 'Memberships (Expired)', 'lifterlms' ),
			),
		);
	}

	/**
	 * Set the table's title.
	 *
	 * @since 3.28.0
	 *
	 * @return string
	 */
	protected function set_title() {
		return __( 'Students', 'lifterlms' );
	}

}


Top ↑

Methods Methods

  • get_data — Retrieve data for the columns
  • get_export_data — Retrieve data for a cell in an export file
  • get_query_args — Retrieve an array of query arguments to pass to the LLMS_Student_Query
  • get_results — Execute a query to retrieve results from the table
  • get_sort — Setup the array of sort arguments to pass to the LLMS_Student_Query for the table
  • get_table_filters_html — Get HTML for the filters displayed in the head of the table
  • get_table_search_form_placeholder — Get the Text to be used as the placeholder in a searchable tables search input
  • parse_args — Parse arguments passed to get_results() method & setup table class variables.
  • set_args — Define the structure of arguments used to pass to the get_results method
  • set_columns — Define the structure of the table
  • set_title — Set the table's title.

Top ↑

Changelog Changelog

Changelog
Version Description
3.37.2 The post filter on the students table now limits post results based on instructor access.
3.36.1 Fixed "Last Seen" column displaying wrong date when the student last login date was saved as timestamp.
3.36.0 Add "Last Seen" column.
3.31.0 Allow filtering the table by Course or Membership
3.28.0 Unknown.
3.2.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.