Skip to content

Make Reports Overview students and courses tabs read HPPS progress tables - #8171

Draft
donnapep wants to merge 19 commits into
trunkfrom
hpps-reports-overview-aggregates
Draft

Make Reports Overview students and courses tabs read HPPS progress tables#8171
donnapep wants to merge 19 commits into
trunkfrom
hpps-reports-overview-aggregates

Conversation

@donnapep

@donnapep donnapep commented Aug 14, 2026

Copy link
Copy Markdown
Member

SEN-83

Proposed Changes

Sensei can store student progress in two ways: the older comment-based storage, or the newer High-Performance Progress Storage (HPPS) tables. On HPPS sites, progress is also mirrored into the comment storage (synchronization is required in that mode), so the Reports screen's Students and Courses tabs — which still read several of their numbers from the comment storage — show correct numbers today.

The problem is that these tabs only stay correct as long as that synchronization is on and never drifts. This change makes both tabs read directly from whichever storage the site actually uses, so they're correct on their own and no longer depend on synchronized comment data. The numbers you see are unchanged in every case; as a bonus, each row's values are now looked up once per page instead of once per row, so the tabs run far fewer database queries.

Now reading from whichever storage the site is set to use:

  • Students tab: the header counts, and each row's Active Courses, Completed Courses, Average Grade, and Last Activity (including sorting and the date filter).
  • Courses tab: Completions, Completion Rate, Average Progress, Average Grade, and Days to Completion in the header, plus the matching per-row values.

Known limitation: the Courses tab's per-row Days to Completion value comes from a separate progress service that has a pre-existing HPPS issue, tracked separately. It's out of scope here.

Testing Instructions

Do this first on a site using the default (comment-based) storage, then repeat on HPPS to confirm the numbers match.

  • Make sure you have a course or two with several enrolled students, some completed lessons, and some graded quizzes.
  • In WP Admin, go to Sensei LMS → Reports. On the Students tab, write down the column header totals and, for a couple of students, their Active Courses, Completed Courses, Average Grade, and Last Activity.
  • Open the Courses tab. Write down the header totals and, for a couple of courses, their Enrolled, Completions, Completion Rate, Average Progress, Average Grade, and Days to Completion.
  • On each tab, click Export all rows (CSV) and confirm the exported values match what's on screen.
  • Turn on HPPS: go to Sensei LMS → Settings → Experimental, set the progress storage to the tables (High-Performance Progress Storage) option, leave synchronization enabled, and save.
  • Go back to Sensei LMS → Reports and reload the Students and Courses tabs. Confirm every number matches what you wrote down before.
  • On the Students tab, click the Last Activity column heading to sort by it, then use the Last Activity date filter and click Filter. Confirm sorting and filtering still work.
  • Export both tabs to CSV again and confirm the values still match the screen.

Deprecated Code

These per-row filters no longer run, because the values now come from a single batched query per page. They have no replacement:

  • sensei_analysis_user_courses_started
  • sensei_analysis_user_courses_ended
  • sensei_analysis_user_lesson_grades
  • sensei_analysis_course_percentage
  • sensei_analysis_course_completions

donnapep and others added 13 commits August 14, 2026 12:58
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs/plans/sen83.md was staged before this task started and got
swept into the previous commit. Remove it from git tracking; the
working-artifact file stays on disk, untracked, as intended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rides the existing grade join with GROUP BY user_id so per-row
average grade can be primed once per page, instead of one query per
user. Implemented in both the tables-based and comments-based
services, with tests pinning parity between them (auto-passed
lessons without a real quiz attempt are excluded in both).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend prime_row_aggregates() in the students overview list table to
also fetch per-user grade totals via Grading_Stats_Service_Interface,
and have get_row_data() read from that primed cache instead of
running per-row Sensei_Utils::sensei_check_for_activity /
Sensei_Grading::get_user_graded_lessons_sum calls. Deprecate the
now-unused sensei_analysis_user_lesson_grades filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ports count_statuses_by_post, get_lesson_completion_counts, and
get_courses_average_days_to_completion into both the comments-based
and tables-based Progress_Aggregation_Service implementations. These
generalize the private per-course queries currently in
Sensei_Reports_Overview_Service_Courses to work with prepared
placeholders instead of raw ID interpolation, powering the Courses
overview aggregates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the raw comments-table queries in
Sensei_Reports_Overview_Service_Courses with calls to
Progress_Query_Service_Factory's aggregation service, so students count,
lesson completions, and average days to completion read from HPPS
progress tables when tables storage is active.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Branch the students report's last-activity join on the active progress
storage mode. In tables mode it derives last_activity_date from
sensei_lms_progress, mirroring the quiz-effective-status join used by
Tables_Based_Progress_Aggregation_Service::count_lesson_statuses_with_quiz()
so passed/graded lessons (whose granular status lives on the quiz
progress row) are counted correctly. Comments mode is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Course-scoped counterpart to get_grade_totals_by_user, needed so the
reports overview courses table can prime its per-row average grade
in one query per page instead of one query per course row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the per-row sensei_check_for_activity() + get_course_users_grades_sum()
calls with a single get_grade_totals_by_course() call primed once per page,
matching the pattern already used for the students table. Deprecates the
now-unused sensei_analysis_course_percentage filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the per-course average progress calculation out of
get_total_average_progress() into a new public
get_average_progress_per_course() method, so the courses list table can
prime per-row progress from primed table-aware data instead of running
per-row comment queries. get_total_average_progress() now sums the
per-course values, keeping its return value unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the courses list table's remaining per-row comment queries
(completions, feeding both the completions and completion_rate columns,
and average_progress) with cache lookups primed for the current page via
count_statuses_by_post() and the new
get_average_progress_per_course() service method. This makes both
columns storage-aware in HPPS mode, same as the other columns on this
table. Also deprecates the now-unused sensei_analysis_course_completions
filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 14, 2026 18:13
@donnapep donnapep added this to the 4.26.3 milestone Aug 14, 2026
@donnapep donnapep added the Deprecation This change introduces a deprecation. label Aug 14, 2026
@donnapep donnapep self-assigned this Aug 14, 2026
@donnapep donnapep added the HPPS label Aug 14, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Reports → Overview Students and Courses tabs to read progress/grade metrics from the active progress storage backend (comments vs HPPS tables), and reduces query volume by priming per-page aggregates rather than recalculating per row.

Changes:

  • Prime per-page aggregates for Students/Courses list tables (course status counts, grade totals, completions, average progress) and reuse them for row rendering + CSV export.
  • Extend the internal aggregation/grading stats services with grouped “totals” APIs (by user, by post, lesson completion counts, courses avg days-to-completion).
  • Update unit tests to seed fixtures through the appropriate repositories and validate tables-mode behavior (last activity, sorting, per-row aggregates).

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit-tests/reports/overview/services/test-class-sensei-reports-overview-service-courses.php Adds HPPS-aware fixtures and new coverage for per-course average progress calculations.
tests/unit-tests/reports/overview/list-table/test-class-sensei-reports-overview-list-table-students.php Adds tests asserting primed per-row course counts and grade totals behavior.
tests/unit-tests/reports/overview/list-table/test-class-sensei-reports-overview-list-table-courses.php Adds tests asserting primed per-row grade totals, completions, and average progress behavior.
tests/unit-tests/reports/overview/data-provider/test-class-sensei-reports-overview-data-provider-students.php Adds tables-mode coverage for last activity sourcing and sorting; aligns repository mode during tests.
tests/unit-tests/internal/services/test-class-tables-based-progress-aggregation-service.php Expands coverage for newly added aggregation methods and table-mode parity behaviors.
tests/unit-tests/internal/services/test-class-tables-based-grading-stats-service.php Adds coverage for new grade totals grouped APIs in tables mode.
tests/unit-tests/internal/services/test-class-comments-based-progress-aggregation-service.php Adds coverage for newly added aggregation methods in comments mode.
tests/unit-tests/internal/services/test-class-comments-based-grading-stats-service.php Adds coverage for new grade totals grouped APIs in comments mode.
includes/reports/overview/services/class-sensei-reports-overview-service-courses.php Refactors average progress + days-to-completion to use backend-appropriate aggregation services.
includes/reports/overview/list-table/class-sensei-reports-overview-list-table-students.php Primes per-page user aggregates (course counts, grade totals) and deprecates now-unused per-row filters.
includes/reports/overview/list-table/class-sensei-reports-overview-list-table-courses.php Primes per-page course aggregates (grade totals, completions, average progress) and removes per-row queries/filters.
includes/reports/overview/list-table/class-sensei-reports-overview-list-table-abstract.php Adds an extension point to prime caches before CSV row generation.
includes/reports/overview/data-provider/class-sensei-reports-overview-data-provider-students.php Adds tables-mode last activity join logic for correct sorting/filtering when using HPPS tables.
includes/internal/services/class-tables-based-progress-aggregation-service.php Adds grouped aggregation APIs (by user/post, lesson completions, courses avg days-to-completion).
includes/internal/services/class-tables-based-grading-stats-service.php Adds grouped grade totals APIs (by user/course) for tables mode.
includes/internal/services/class-progress-aggregation-service-interface.php Extends the interface to include the new aggregation methods.
includes/internal/services/class-grading-stats-service-interface.php Extends the interface to include the new grade totals methods.
includes/internal/services/class-comments-based-progress-aggregation-service.php Implements the new aggregation APIs for comments mode.
includes/internal/services/class-comments-based-grading-stats-service.php Implements the new grade totals APIs for comments mode.
changelog/prime-students-reports-course-counts Changelog entry for students per-row course counts using HPPS.
changelog/fix-reports-overview-students-last-activity-hpps Changelog entry for students last activity using HPPS.
changelog/fix-reports-overview-students-average-grade-hpps Changelog entry for students average grade using HPPS.
changelog/fix-reports-overview-courses-completions-progress-hpps Changelog entry for courses completions/progress using HPPS.
changelog/fix-reports-overview-courses-average-grade-hpps Changelog entry for courses average grade using HPPS.
changelog/fix-reports-overview-courses-aggregates-hpps Changelog entry for courses aggregates using HPPS.
Suppressed comments (2)

includes/reports/overview/list-table/class-sensei-reports-overview-list-table-courses.php:332

  • $average_progress_by_course omits courses that have no enrolled students or no lessons, but the row renderer defaults missing entries to 0%. That changes the previous behavior (N/A) and can mislead by implying zero progress rather than “not applicable”. Preserve N/A when the course has no computable average, while still showing 0% for real computed zeroes.
		$average_course_progress = $this->average_progress_by_course[ (int) $item->ID ] ?? 0;
		$average_course_progress = esc_html( sprintf( '%d%%', round( $average_course_progress ) ) );

includes/reports/overview/list-table/class-sensei-reports-overview-list-table-students.php:62

  • The PR description’s “Deprecated Code” list omits sensei_analysis_user_lesson_grades, but this list table now explicitly deprecates that hook as well. Please update the PR description (and any release notes) so consumers aren’t surprised by the additional deprecated filter.
		if ( has_filter( 'sensei_analysis_user_courses_started' ) ) {
			_deprecated_hook( 'sensei_analysis_user_courses_started', '$$next-version$$' );
		}
		if ( has_filter( 'sensei_analysis_user_courses_ended' ) ) {
			_deprecated_hook( 'sensei_analysis_user_courses_ended', '$$next-version$$' );
		}
		if ( has_filter( 'sensei_analysis_user_lesson_grades' ) ) {
			_deprecated_hook( 'sensei_analysis_user_lesson_grades', '$$next-version$$' );
		}

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

WordPress Playground Preview

The changes in this pull request can previewed and tested using a WordPress Playground instance.

Open WordPress Playground Preview

@donnapep
donnapep marked this pull request as draft August 14, 2026 19:21
donnapep and others added 2 commits August 14, 2026 15:27
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@donnapep donnapep modified the milestones: 4.26.3, 4.26.4 Aug 19, 2026
donnapep and others added 3 commits August 25, 2026 09:55
A course with no enrolled students or no lessons has no computable
average progress. Restore the previous N/A display for those courses
instead of showing 0%, which wrongly implied zero progress.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the ordering in class-sensei-reports-overview-list-table-lessons.php.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@donnapep

Copy link
Copy Markdown
Member Author

Split into 8 stacked, individually-testable PRs (one field each). Reviewing/merging these in order supersedes this PR:

  1. Read Reports Overview header counts from HPPS #8203 — Header counts (both tabs)
  2. Read students per-row course counts from HPPS #8204 — Students: Active + Completed Courses
  3. Read students per-row Average Grade from HPPS #8205 — Students: Average Grade
  4. Read students Last Activity from HPPS tables #8206 — Students: Last Activity (column, sorting, date filter)
  5. Read Courses Overview aggregates from HPPS #8207 — Courses: header aggregates
  6. Read courses per-row Average Grade from HPPS #8208 — Courses: Average Grade
  7. Read courses per-row Completions and Average Progress from HPPS #8209 — Courses: Completions + Average Progress
  8. Inject Reports Overview progress services via constructor #8210 — Constructor injection cleanup (internal)

Each is stacked on the previous (#8203 → trunk). Keeping this PR open as the tracking umbrella.

@donnapep

donnapep commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

⚠️ WPML regression risk when migrating these reads to the HPPS tables

PR #8224 (fix/wpml-progress-queries-language) fixes WPML on the comments read path via the sensei_check_for_activity_args hook, which translates course/lesson IDs from the admin's language to the original language (progress is stored under original-language IDs).

That hook only fires inside Sensei_Utils::sensei_check_for_activity(). The PRs in this stack replace those per-row calls with table-side services that take raw course/lesson IDs:

On tables + WPML secondary language, those IDs are translations while progress is stored under originals → completions/grades/progress come back 0 / N/A.

Before merging any of these: translate the incoming IDs to original language inside the table service, reusing the existing per-ID filters (sensei_course_progress_get_course_id / sensei_lesson_progress_get_lesson_id) — the same pattern the single-record repos already use — and add a WPML + tables test. No change needed in #8224 itself; the fix belongs on the table path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Deprecation This change introduces a deprecation. HPPS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants