Skip to content

Add multi-select for engagement trigger associated items - #3238

Open
faisalahammad wants to merge 12 commits into
gocodebox:devfrom
faisalahammad:fix/3233-multi-select-engagement-triggers
Open

Add multi-select for engagement trigger associated items#3238
faisalahammad wants to merge 12 commits into
gocodebox:devfrom
faisalahammad:fix/3233-multi-select-engagement-triggers

Conversation

@faisalahammad

@faisalahammad faisalahammad commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Description

Currently engagement triggers can target either one specific post (course, lesson, membership) or any post of that type. This adds the ability to select multiple items, limiting triggers to a specific set of courses, lessons, memberships, etc.

Fixes #3233

Changes

  • Multi-select UI: Single-select Select2 replaced with a multi-select for each trigger post type (course, lesson, membership, access plan, quiz, section). Multiple IDs can be picked for a single engagement.
  • Storage: Each selected ID is stored in its own _llms_engagement_trigger_post postmeta row (one row per ID). An empty selection stores a single any row. This keeps the trigger query as a regular equality match instead of FIND_IN_SET.
  • Query: get_engagements() uses meta_value = %d OR meta_value = 'any', matching the per-row storage. Backward compatible with existing single-ID engagements.
  • Admin list table: The trigger column loops the stored IDs and renders each as a linked item.

How has this been tested?

Physically tested in a local WordPress install against the built plugin zip.

Test 1: Multi-select UI

  1. Go to Engagements > Add New
  2. Select a trigger type (e.g. "Course Enrolled")
  3. Select two or more courses from the course selector
  4. Fill in the engagement type and engagement fields
  5. Click Publish
    Result: Multiple courses are saved (one postmeta row per ID) and listed in the admin columns.

Test 2: Backward compatibility

  1. Create an engagement with a single course selected
  2. Verify it still works correctly (stored as a single ID, matched properly)
    Result: Single-ID engagements unaffected.

Test 3: "Any" behavior

  1. Create an engagement with no courses selected (leave blank)
  2. Save and reload
    Result: Trigger applies to all courses (stored as "any").

Test 4: Trigger fires for each selected item

  1. With two courses selected, enroll a student in course A and confirm the engagement fires
  2. Enroll in course B and confirm it fires again
    Result: Engagement triggers for both selected courses.

Automated tests: engagement and notification PHPUnit suites pass (class-llms-test-engagements, class-llms-test-engagement-handler, notification earned tests). PHPCS (check-cs-errors) passes clean.

Screenshots

image

Types of changes

New feature (non-breaking change which adds functionality).

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.

Allow selecting multiple courses, lessons, memberships, etc. for
engagement triggers instead of a single item or Any.

- Enable Select2 multi-select on trigger post fields
- Store multiple IDs as comma-separated string in postmeta
- Use FIND_IN_SET() for backward-compatible SQL matching
- Update admin list table to display multiple linked items

Fixes gocodebox#3233
@faisalahammad
faisalahammad requested a review from brianhogg as a code owner July 13, 2026 21:36
@brianhogg brianhogg moved this to Awaiting Review in Development Jul 13, 2026

@brianhogg brianhogg 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.

Thanks for the submission! I've added some comments.

To confirm for this and for the other PRs, have they been physically tested or just tested via AI? While using AI to create the code is fine, we did update the contributing guidelines to make clear that the PR needs to use the template that appears when you physically open the PR in github, which includes the checkbox stating that the PR has been tested.

Comment thread includes/admin/post-types/meta-boxes/class.llms.meta.box.engagement.php Outdated
Comment thread includes/admin/post-types/post-tables/class.llms.admin.post.table.engagements.php Outdated
Comment thread includes/admin/post-types/meta-boxes/class.llms.meta.box.engagement.php Outdated
Comment thread includes/class.llms.engagements.php Outdated
@github-project-automation github-project-automation Bot moved this from Awaiting Review to To do in Development Jul 15, 2026
- Drop llms_filter_input_sanitize_string wrapper in save(), read $_POST
  directly with wp_unslash + absint (nonce verified at top of save)
- Echo trigger links as built so esc_url/esc_html run at point of echo
  instead of building a links array
- Restore "Any ___" placeholders for all trigger post-type selectors
- Store each selected trigger post ID in its own _llms_engagement_trigger_post
  meta row and query with regular equality instead of FIND_IN_SET
- Guard get_term() against WP_Error in the track title fallback

Refs gocodebox#3238

@faisalahammad faisalahammad left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review. All four comments are addressed in 0070aa6.

  • Removed the llms_filter_input_sanitize_string wrapper and read $_POST directly with wp_unslash and absint (nonce checked at the top of save).
  • Echo the trigger links inside the loop so esc_url and esc_html run at the point of echo.
  • Restored the Any ___ placeholders for all trigger post types.
  • Dropped FIND_IN_SET. Each selected ID is stored in its own _llms_engagement_trigger_post meta row and the query uses a regular equality match.

Also updated this PR description to use the default template with the testing checklist filled in. Ready for another look.

Comment thread .changelogs/3233-multi-select-engagement-triggers.yml
@brianhogg

Copy link
Copy Markdown
Contributor

@faisalahammad Please also confirm the comment above #3238 (review)

Comment thread includes/admin/post-types/meta-boxes/class.llms.meta.box.engagement.php Outdated
Nonce is verified at the top of save() so the sniff recognizes it
without the ignore. Addresses PR review feedback.

Refs gocodebox#3238
@faisalahammad

Copy link
Copy Markdown
Contributor Author

Addressed the open review comments in f65c81a.

  • Metabox phpcs:ignore (line 357): removed it. The nonce is verified at the top of save() so check-cs-errors passes without the ignore.
  • Changelog: agreed to keep "all or some" in this PR. The exclude-when-All part is deferred to a follow-up.

Both threads resolved. Ready for another look when you have time.

@faisalahammad

Copy link
Copy Markdown
Contributor Author

To confirm both points above:

  • This PR was physically tested in a local WordPress install, not AI only. I installed the built plugin zip and went through each test case in the description by hand (multi-select save, single-ID backward compat, blank "any" behavior, and the engagement firing for each selected course). The trigger fired as expected in each case.
  • The PR description follows the pull request template. All four checklist items are checked, including "My code has been tested."

@brianhogg let me know if you would like more detail on the manual test steps.

@brianhogg brianhogg moved this from To do to Review in Progress in Development Jul 15, 2026
@brianhogg brianhogg added this to the 10.1 milestone Jul 15, 2026
@brianhogg

Copy link
Copy Markdown
Contributor

@faisalahammad Will test but looks like we're pretty much there. Feel free to update the changelog yml to add your @faisalahammad attribution if you'd like that to appear. Thanks!

@github-project-automation github-project-automation Bot moved this from Review in Progress to Approved in Development Jul 16, 2026
@faisalahammad

Copy link
Copy Markdown
Contributor Author

Re: brianhogg attribution — added in commit 453c41c. Changelog yml now carries attributions: [@faisalahammad] on the 3233 entry, which renders as Thanks @faisalahammad! when the release tooling runs. Schema validates clean.

@brianhogg

Copy link
Copy Markdown
Contributor

@faisalahammad Could the height of the box to select item(s) be the standard height by default? I'm not sure why it's double height in the screenshot (possibly WP 7.0 related formatting), as it should expand if many courses are picked.

@brianhogg brianhogg moved this from Approved to Review in Progress in Development Jul 17, 2026
@faisalahammad

Copy link
Copy Markdown
Contributor Author

@brianhogg Hi, I’ve tried adjusting the height of the box to the standard size, but I wasn’t able to reduce it. Could you please help me look into this? Thanks!

@brianhogg

Copy link
Copy Markdown
Contributor

@faisalahammad Fixed the styling to match multi-select boxes like Enroll New Students (edit course), but when testing the engagements persist to postmeta, however do not load back after saving or reloading. Is this different than what you're seeing?

CleanShot.2026-07-21.at.05.28.37.mp4

@brianhogg brianhogg 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.

Does not work when testing. Selected trigger post(s) persist, but do not load back into the editor after save/reload.

@github-project-automation github-project-automation Bot moved this from Review in Progress to To do in Development Jul 21, 2026
@brianhogg brianhogg modified the milestones: 10.1, 11.0 Jul 21, 2026
@faisalahammad

Copy link
Copy Markdown
Contributor Author

Hi @brianhogg,
Sorry for the trouble. Should I resolve the conflicts and push? I'm confused because you've already merged into the 'dev' branch. Thanks for your help!

Passes saved trigger post IDs as the field selected key so the
Select renderer marks each option selected and Select2 hydrates
them on editor reload.

Refs gocodebox#3238
@faisalahammad

Copy link
Copy Markdown
Contributor Author

Fixed. Saved trigger post IDs now load back into the multi-select on editor reload.

The faux field (_faux_engagement_trigger_post_*) stores no meta, so the Select renderer's default selected value was empty — no <option> got marked selected, and ajax-Select2 hydrates only from existing <option selected> markup. The fix passes the saved IDs as the field selected key, which the renderer already honors (same pattern as the coupon/voucher multi-selects).

Demo: https://screendrop-worker.faisalahammad24.workers.dev/5c1d7b4c

@brianhogg could you take another look?

@brianhogg brianhogg modified the milestones: 11.0, 10.1 Jul 21, 2026
@brianhogg brianhogg moved this from To do to Review in Progress in Development Jul 23, 2026
@brianhogg brianhogg modified the milestones: 10.1, 10.2 Jul 23, 2026
@brianhogg brianhogg moved this from Review in Progress to Awaiting Review in Development Jul 23, 2026
@brianhogg brianhogg modified the milestones: 10.2, 10.3 Aug 21, 2026
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.

2 participants