Repository navigation
Fix course filter reporting zero activity for everyone - #3
Merged
Merged
Conversation
Filtering the student list by course showed every student as having no activity, no completions and no active days, even where they plainly had. $wpdb->prepare() substitutes placeholders in the order they appear in the SQL text, but base_query() pushed its parameters in the order the clauses were assembled. The course filter is appended to the activity subquery's WHERE clause, which in the finished SQL comes *after* the three window comparisons in the SELECT list. So with a course filter applied the bindings shifted by one: completions_recent event_time >= 8131 <- the course ID active_days_long event_time >= <short window> activity WHERE course_id = 1781259752 <- a unix timestamp No row has a course_id equal to a timestamp, so the activity subquery returned nothing, every student left-joined to NULL and the list read as all zeroes. The placeholder count still matched, which is why nothing errored and why the unfiltered list — the only shape exercised during development — was always correct. Parameters are now pushed in SQL-text order, with a comment explaining why the assembly order and the binding order differ. This is the second placeholder-ordering bug in this file, so it also adds tests/placeholder-order.php: a dependency-free regression test that substitutes parameters the way prepare() does and asserts each value is the right kind of value — a timestamp comparison gets a timestamp, a course filter gets a post ID. It reports 9 failures against the 0.1.1 code and passes on this one. A CI workflow runs it, plus a lint pass, on PHP 7.4 and 8.3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Filtering the student list by course showed every student as having no activity — no completions, no active days — regardless of what they had actually done. The unfiltered list was always correct.
Cause
$wpdb->prepare()fills placeholders in SQL-text order.base_query()pushed parameters in the order the clauses were assembled. The course filter is appended to the activity subquery'sWHERE, which sits after the three window comparisons in theSELECTlist — so with a course filter every binding shifted by one:No row has a
course_idequal to a timestamp, so the subquery returned nothing, every student left-joined toNULL, and the list read as all zeroes.The placeholder count still matched, so nothing errored. And the unfiltered shape — the only one exercised during development — was unaffected, which is why this reached a release.
Fix
Parameters are pushed in SQL-text order, with a comment on why assembly order and binding order differ.
Regression test
This is the second placeholder-ordering bug in this file, so a fix alone felt insufficient.
tests/placeholder-order.phpsubstitutes parameters exactly asprepare()does and asserts each value is the right kind of value — timestamp comparisons get timestamps, course filters get post IDs — across six query shapes. No dependencies; runs with plainphp..github/workflows/test.ymlruns it plus a lint pass on PHP 7.4 and 8.3, on push and PR.Also
MSSA_VERSIONand the readme stable tagtests/excluded from the distributed zip — still 14 filesreadme.txt's changelogVerifying after merge
Open the Student Activity screen, pick a course, and confirm students with recorded lessons in it now show their real figures.