33 exit ; // Exit if accessed directly
44}
55
6+ use Sensei \Internal \Services \Grading_Listing_Service_Interface ;
7+ use Sensei \Internal \Services \Grading_Item ;
8+ use Sensei \Internal \Services \Progress_Query_Service_Factory ;
9+
610/**
711 * Admin Grading Overview Data Table in Sensei.
812 *
@@ -19,12 +23,22 @@ class Sensei_Grading_Main extends Sensei_List_Table {
1923 public $ user_ids = false ;
2024 public $ page_slug = 'sensei_grading ' ;
2125
26+ /**
27+ * The grading listing service.
28+ *
29+ * @var Grading_Listing_Service_Interface
30+ */
31+ private Grading_Listing_Service_Interface $ grading_listing_service ;
32+
2233 /**
2334 * Constructor
2435 *
2536 * @since 1.3.0
37+ *
38+ * @param array|null $args Constructor arguments.
39+ * @param Grading_Listing_Service_Interface|null $grading_listing_service The grading listing service.
2640 */
27- public function __construct ( $ args = null ) {
41+ public function __construct ( $ args = null , ? Grading_Listing_Service_Interface $ grading_listing_service = null ) {
2842
2943 $ defaults = array (
3044 'course_id ' => 0 ,
@@ -44,6 +58,9 @@ public function __construct( $args = null ) {
4458 $ this ->view = $ args ['view ' ];
4559 }
4660
61+ $ this ->grading_listing_service = $ grading_listing_service
62+ ?? ( new Progress_Query_Service_Factory () )->create_grading_listing_service ();
63+
4764 // Load Parent token into constructor
4865 parent ::__construct ( 'grading_main ' );
4966
@@ -237,30 +254,45 @@ public function prepare_items() {
237254 */
238255 $ activity_args = apply_filters ( 'sensei_grading_filter_statuses ' , $ activity_args );
239256
240- // WP_Comment_Query doesn't support SQL_CALC_FOUND_ROWS, so instead do this twice
241- $ total_statuses = Sensei_Utils::sensei_check_for_activity (
242- array_merge (
243- $ activity_args ,
244- array (
245- 'count ' => true ,
246- 'offset ' => 0 ,
247- 'number ' => 0 ,
248- )
249- )
250- );
251-
252- // Ensure we change our range to fit (in case a search threw off the pagination) - Should this be added to all views?
253- if ( $ total_statuses < $ activity_args ['offset ' ] ) {
254- $ new_paged = floor ( $ total_statuses / $ activity_args ['number ' ] );
255- $ activity_args ['offset ' ] = $ new_paged * $ activity_args ['number ' ];
257+ // Apply teacher and temp-user restrictions so that both listing rows
258+ // and cached per-status counts reflect these filters. For tables-based
259+ // storage, these args are applied as SQL clauses. For comments-based,
260+ // post__in flows through to WP_Comment_Query and the remaining args
261+ // are handled by existing post-filters on sensei_check_for_activity.
262+ $ count_restrictions = apply_filters ( 'sensei_count_statuses_args ' , array ( 'type ' => 'lesson ' ) );
263+
264+ // Merge teacher's post__in restriction.
265+ if ( ! empty ( $ count_restrictions ['post__in ' ] ) ) {
266+ if ( ! empty ( $ activity_args ['post__in ' ] ) ) {
267+ // Intersect: keep only lessons in both the course filter and teacher filter.
268+ $ intersected = array_values (
269+ array_intersect ( $ activity_args ['post__in ' ], $ count_restrictions ['post__in ' ] )
270+ );
271+
272+ // Force no-results when the intersection is empty (e.g. teacher
273+ // does not own any lessons in the selected course).
274+ $ activity_args ['post__in ' ] = empty ( $ intersected ) ? array ( 0 ) : $ intersected ;
275+ } elseif ( ! empty ( $ activity_args ['post_id ' ] ) ) {
276+ // Validate that the specific lesson belongs to this teacher's courses.
277+ if ( ! in_array ( (int ) $ activity_args ['post_id ' ], array_map ( 'intval ' , $ count_restrictions ['post__in ' ] ), true ) ) {
278+ $ activity_args ['post__in ' ] = array ( 0 );
279+ }
280+ } else {
281+ $ activity_args ['post__in ' ] = $ count_restrictions ['post__in ' ];
282+ }
256283 }
257- $ statuses = Sensei_Utils::sensei_check_for_activity ( $ activity_args , true );
258- // Need to always return an array, even with only 1 item
259- if ( ! is_array ( $ statuses ) ) {
260- $ statuses = array ( $ statuses );
284+
285+ // Pass through temp-user exclusion for the listing service.
286+ if ( ! empty ( $ count_restrictions ['exclude_user_login_prefixes ' ] ) ) {
287+ $ activity_args ['exclude_user_login_prefixes ' ] = $ count_restrictions ['exclude_user_login_prefixes ' ];
288+ if ( ! empty ( $ count_restrictions ['include_statuses_override ' ] ) ) {
289+ $ activity_args ['include_statuses_override ' ] = $ count_restrictions ['include_statuses_override ' ];
290+ }
261291 }
262- $ this ->total_items = $ total_statuses ;
263- $ this ->items = $ statuses ;
292+
293+ $ result = $ this ->grading_listing_service ->get_lesson_progress_items ( $ activity_args );
294+ $ this ->total_items = $ result ['total_count ' ];
295+ $ this ->items = $ result ['items ' ];
264296
265297 $ total_items = $ this ->total_items ;
266298 $ total_pages = ceil ( $ total_items / $ per_page );
@@ -277,46 +309,52 @@ public function prepare_items() {
277309 * Generates content for a single row of the table, overriding parent
278310 *
279311 * @since 1.7.0
280- * @param object $item The current item
312+ * @param Grading_Item $item The current item.
281313 */
282314 protected function get_row_data ( $ item ) {
283- global $ wp_version ;
315+ $ status = $ item ->status ;
316+ $ user_id = $ item ->user_id ;
317+ $ lesson_id = $ item ->lesson_id ;
318+ $ updated = $ item ->updated_at ;
319+ $ grade_val = $ item ->grade ;
320+
321+ $ grade_display = null !== $ grade_val ? $ grade_val . '% ' : __ ( 'N/A ' , 'sensei-lms ' );
284322
285323 $ grade = '' ;
286- if ( 'complete ' == $ item -> comment_approved ) {
324+ if ( 'complete ' == $ status ) {
287325 $ status_html = '<span class="graded"> ' . esc_html__ ( 'Completed ' , 'sensei-lms ' ) . '</span> ' ;
288326 $ grade = __ ( 'No Grade ' , 'sensei-lms ' );
289- } elseif ( 'graded ' == $ item -> comment_approved ) {
327+ } elseif ( 'graded ' == $ status ) {
290328 $ status_html = '<span class="graded"> ' . esc_html__ ( 'Graded ' , 'sensei-lms ' ) . '</span> ' ;
291- $ grade = get_comment_meta ( $ item -> comment_ID , ' grade ' , true ) . ' % ' ;
292- } elseif ( 'passed ' == $ item -> comment_approved ) {
329+ $ grade = $ grade_display ;
330+ } elseif ( 'passed ' == $ status ) {
293331 $ status_html = '<span class="passed"> ' . esc_html__ ( 'Passed ' , 'sensei-lms ' ) . '</span> ' ;
294- $ grade = get_comment_meta ( $ item -> comment_ID , ' grade ' , true ) . ' % ' ;
295- } elseif ( 'failed ' == $ item -> comment_approved ) {
332+ $ grade = $ grade_display ;
333+ } elseif ( 'failed ' == $ status ) {
296334 $ status_html = '<span class="failed"> ' . esc_html__ ( 'Failed ' , 'sensei-lms ' ) . '</span> ' ;
297- $ grade = get_comment_meta ( $ item -> comment_ID , ' grade ' , true ) . ' % ' ;
298- } elseif ( 'ungraded ' == $ item -> comment_approved ) {
335+ $ grade = $ grade_display ;
336+ } elseif ( 'ungraded ' == $ status ) {
299337 $ status_html = '<span class="ungraded"> ' . esc_html__ ( 'Ungraded ' , 'sensei-lms ' ) . '</span> ' ;
300338 $ grade = __ ( 'N/A ' , 'sensei-lms ' );
301339 } else {
302340 $ status_html = '<span class="in-progress"> ' . esc_html__ ( 'In Progress ' , 'sensei-lms ' ) . '</span> ' ;
303341 $ grade = __ ( 'N/A ' , 'sensei-lms ' );
304342 }
305343
306- $ title = Sensei_Learner::get_full_name ( $ item -> user_id );
344+ $ title = Sensei_Learner::get_full_name ( $ user_id );
307345
308- $ quiz_id = Sensei ()->lesson ->lesson_quizzes ( $ item -> comment_post_ID , 'any ' );
346+ $ quiz_id = Sensei ()->lesson ->lesson_quizzes ( $ lesson_id , 'any ' );
309347 $ quiz_link = add_query_arg (
310348 array (
311349 'page ' => $ this ->page_slug ,
312- 'user ' => $ item -> user_id ,
350+ 'user ' => $ user_id ,
313351 'quiz_id ' => $ quiz_id ,
314352 ),
315353 admin_url ( 'admin.php ' )
316354 );
317355
318356 $ grade_link = '' ;
319- switch ( $ item -> comment_approved ) {
357+ switch ( $ status ) {
320358 case 'ungraded ' :
321359 $ grade_link = '<a class="button-primary button" href=" ' . esc_url ( $ quiz_link ) . '"> ' . esc_html__ ( 'Grade quiz ' , 'sensei-lms ' ) . '</a> ' ;
322360 break ;
@@ -328,7 +366,7 @@ protected function get_row_data( $item ) {
328366 break ;
329367 }
330368
331- $ course_id = get_post_meta ( $ item -> comment_post_ID , '_lesson_course ' , true );
369+ $ course_id = get_post_meta ( $ lesson_id , '_lesson_course ' , true );
332370 $ course_title = '' ;
333371
334372 if ( ! empty ( $ course_id ) ) {
@@ -347,19 +385,19 @@ protected function get_row_data( $item ) {
347385 add_query_arg (
348386 array (
349387 'page ' => $ this ->page_slug ,
350- 'lesson_id ' => $ item -> comment_post_ID ,
388+ 'lesson_id ' => $ lesson_id ,
351389 ),
352390 admin_url ( 'admin.php ' )
353391 )
354- ) . '"> ' . esc_html ( get_the_title ( $ item -> comment_post_ID ) ) . '</a> ' ;
392+ ) . '"> ' . esc_html ( get_the_title ( $ lesson_id ) ) . '</a> ' ;
355393
356394 /**
357395 * Filter columns data for the Grading list table.
358396 *
359397 * @hook sensei_grading_main_column_data
360398 *
361399 * @param {array} $column_data Column data for a row.
362- * @param {object } $item Activity comment object .
400+ * @param {Grading_Item } $item Grading item for the row .
363401 * @param {int} $course_id The course ID.
364402 * @return {array} Filtered column data.
365403 */
@@ -370,14 +408,14 @@ protected function get_row_data( $item ) {
370408 add_query_arg (
371409 array (
372410 'page ' => $ this ->page_slug ,
373- 'user_id ' => $ item -> user_id ,
411+ 'user_id ' => $ user_id ,
374412 ),
375413 admin_url ( 'admin.php ' )
376414 )
377415 ) . '"> ' . esc_html ( $ title ) . '</a></strong> ' ,
378416 'course ' => $ course_title ,
379417 'lesson ' => $ lesson_title ,
380- 'updated ' => $ item -> comment_date ,
418+ 'updated ' => $ updated ,
381419 'user_status ' => $ status_html ,
382420 'user_grade ' => $ grade ,
383421 'action ' => $ grade_link ,
@@ -500,7 +538,8 @@ public function get_views() {
500538
501539 // Setup counters.
502540 $ count_args = array (
503- 'type ' => 'lesson ' ,
541+ 'type ' => 'lesson ' ,
542+ 'exclude_unsubmitted_quiz_completions ' => true ,
504543 );
505544 $ query_args = array (
506545 'page ' => $ this ->page_slug ,
@@ -566,7 +605,23 @@ public function get_views() {
566605 */
567606 $ count_args = apply_filters ( 'sensei_grading_count_statuses ' , $ count_args );
568607
569- $ counts = Sensei ()->grading ->count_statuses ( $ count_args );
608+ // Use cached per-status counts from prepare_items() when available,
609+ // avoiding a second full-table scan with the same JOINs.
610+ $ cached_counts = $ this ->grading_listing_service ->get_status_counts ();
611+ if ( null !== $ cached_counts ) {
612+ // Ensure all expected statuses exist with 0 defaults, matching
613+ // the shape that count_statuses() returns.
614+ $ defaults = array_fill_keys (
615+ array ( 'graded ' , 'ungraded ' , 'passed ' , 'failed ' , 'in-progress ' , 'complete ' ),
616+ 0
617+ );
618+ $ counts = array_merge ( $ defaults , $ cached_counts );
619+
620+ /** This filter is documented in includes/class-sensei-grading.php */
621+ $ counts = apply_filters ( 'sensei_count_statuses ' , $ counts , 'sensei_lesson_status ' );
622+ } else {
623+ $ counts = Sensei ()->grading ->count_statuses ( $ count_args );
624+ }
570625
571626 $ inprogress_lessons_count = $ counts ['in-progress ' ];
572627 $ ungraded_lessons_count = $ counts ['ungraded ' ];
0 commit comments