Skip to content

Fix fatal error when quiz's parent lesson has been deleted - #3192

Open
thisismyurl wants to merge 3 commits into
gocodebox:devfrom
thisismyurl:fix/orphaned-quiz-fatal-error-v3
Open

Fix fatal error when quiz's parent lesson has been deleted#3192
thisismyurl wants to merge 3 commits into
gocodebox:devfrom
thisismyurl:fix/orphaned-quiz-fatal-error-v3

Conversation

@thisismyurl

Copy link
Copy Markdown

TL;DR: Delete a lesson and the quiz that used to live in it will fatal-error anyone who tries to access it — two access-check functions call methods on the false that llms_get_post() returns when the lesson is gone. This patches both with a null guard. One of the two also had a copy-paste bug where the guard was checking the wrong variable. AI helped me trace the call stack and verify both fixes are load-bearing.


Description

When a quiz's parent lesson has been permanently deleted, two functions in llms.functions.access.php can trigger a fatal PHP error.

llms_is_post_restricted_by_prerequisite()
After the llms_quiz switch case resolves $lesson_id and calls llms_get_post( $lesson_id ), the return value can be false if the lesson no longer exists. The immediately following call to $lesson->get_course() then produces a fatal error on the false value.

llms_is_post_restricted_by_time_period()
Same scenario. Additionally, the original guard is if ( ! $lesson_id ) placed after the llms_get_post() call — but $lesson_id is already guaranteed truthy at that point (we returned false earlier if it wasn't). The guard was checking the wrong variable. Changed to if ( ! $lesson ) so it actually checks the llms_get_post() return value.

Both are fixed by adding a null check on the llms_get_post() result and returning false (unrestricted) when the lesson no longer exists.

No upstream issue exists for this bug.

How has this been tested?

  1. Create a course with a lesson and a quiz inside that lesson.
  2. Delete the lesson permanently (skip trash).
  3. Visit the quiz URL as a non-enrolled or logged-out user.
  4. Before this fix: fatal PHP error. After: page renders normally (unrestricted, no crash).

The fix was verified by code analysis: removing either null check causes the next method call on a false value to produce a fatal error (Call to a member function get_course() on bool).

Types of changes

Bug fix (non-breaking change which fixes an issue)

Checklist:

  • This PR requires and contains at least one changelog file.
  • My code has been tested.
  • My code passes all existing automated tests.
  • My code follows the LifterLMS Coding & Documentation Standards.

(full disclosure: AI helped me identify the issue and verify my work)

When a quiz's parent lesson has been permanently deleted, two access functions
can trigger a fatal error by calling methods on a null object:

- llms_is_post_restricted_by_prerequisite(): After llms_get_post( $lesson_id )
returns false, the next line calls $lesson->get_course() which produces a
fatal error. Added a null check that returns false (unrestricted).

- llms_is_post_restricted_by_time_period(): Same scenario. Also fixes a
copy-paste error: the guard was if ( ! $lesson_id ) placed after
llms_get_post(), but $lesson_id is already truthy at that point.
@thisismyurl
thisismyurl requested a review from brianhogg as a code owner June 16, 2026 16:38
Copilot AI review requested due to automatic review settings June 16, 2026 16:38
@brianhogg brianhogg moved this to Awaiting Review in Development Jun 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Prevents fatal errors when determining quiz access restrictions if the quiz’s parent lesson has been deleted.

Changes:

  • Add a null-guard in llms_is_post_restricted_by_prerequisite() to avoid calling get_course() on a missing lesson.
  • Fix a copy/paste guard bug in llms_is_post_restricted_by_time_period() by checking the resolved lesson object instead of the already-truthy $lesson_id.
  • Add a changelog entry documenting the fix.

Reviewed changes

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

File Description
includes/functions/llms.functions.access.php Adds/fixes guards to prevent fatals when a related lesson is missing.
.changelogs/fix-orphaned-quiz-fatal-error.yml Documents the patch fix and rationale.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 397 to +400
$lesson = llms_get_post( $lesson_id );
if ( ! $lesson ) {
return false;
}
Comment on lines +482 to 484
if ( ! $lesson ) {
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Awaiting Review

Development

Successfully merging this pull request may close these issues.

4 participants