Compare commits
3 Commits
08b9ad24a5
...
290c4e427f
| Author | SHA1 | Date | |
|---|---|---|---|
| 290c4e427f | |||
| 1b4449ae12 | |||
| 4145a92ca7 |
@@ -12,7 +12,7 @@ See: .planning/PROJECT.md (updated 2026-01-14)
|
||||
Phase: 7 of 7 (Testing & Polish)
|
||||
Plan: 3 of 3 in current phase
|
||||
Status: Phase complete - PROJECT COMPLETE!
|
||||
Last activity: 2026-01-29 — Completed Plan 07-03 (Admin Flow & Deployment Prep)
|
||||
Last activity: 2026-01-29 — Completed Quick Task 002: Fix duplicate mentor notifications on job republish
|
||||
|
||||
Progress: ████████████████████ 100%
|
||||
|
||||
@@ -113,10 +113,17 @@ All 7 phases finished. All identified UX/notification issues resolved. System is
|
||||
|
||||
**Production deployment:** Ready to proceed following `.planning/phases/07-testing-polish/DEPLOYMENT-CHECKLIST.md`
|
||||
|
||||
### Quick Tasks Completed
|
||||
|
||||
| # | Description | Date | Commit | Directory |
|
||||
|---|-------------|------|--------|-----------|
|
||||
| 001 | UX & Notification Polish | 2026-01-29 | N/A | [001-ux-notification-polish](./quick/001-ux-notification-polish/) |
|
||||
| 002 | Fix duplicate mentor notifications on job republish | 2026-01-29 | 4145a92 | [002-fix-duplicate-mentor-notifications-on-jo](./quick/002-fix-duplicate-mentor-notifications-on-jo/) |
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-01-29
|
||||
Stopped at: Completed Quick Task 001 (UX & Notification Polish) - all 4 deferred issues resolved
|
||||
Stopped at: Completed Quick Task 002: Fix duplicate mentor notifications on job republish
|
||||
Resume file: None
|
||||
|
||||
**Project Status:** ✅ COMPLETE - All 7 phases finished, all polish items complete, system ready for production deployment
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
phase: quick-002
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- includes/class-notifications.php
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Mentors receive notification when a job is first published"
|
||||
- "Mentors do NOT receive notification when a previously-published job is edited and republished"
|
||||
- "Each job can only trigger mentor notifications once in its lifetime"
|
||||
artifacts:
|
||||
- path: "includes/class-notifications.php"
|
||||
provides: "Duplicate notification guard using post meta"
|
||||
contains: "_ddhh_mentors_notified"
|
||||
key_links:
|
||||
- from: "notify_mentors_on_job_publish"
|
||||
to: "post_meta _ddhh_mentors_notified"
|
||||
via: "get_post_meta check before scheduling, update_post_meta after scheduling"
|
||||
pattern: "get_post_meta.*_ddhh_mentors_notified"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Fix duplicate mentor notifications when a job is edited and republished.
|
||||
|
||||
Purpose: Mentors currently receive "new job" notifications every time a job transitions to
|
||||
publish status -- including after edits (pending -> publish). The notification should only
|
||||
fire once per job, on the very first publication. Subsequent republications after edits
|
||||
should be silent for mentors (the admin already gets a separate edit notification).
|
||||
|
||||
Output: Updated `notify_mentors_on_job_publish` method with a post meta guard that prevents
|
||||
duplicate notifications.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@~/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@includes/class-notifications.php
|
||||
@includes/class-scheduler.php
|
||||
|
||||
The bug is in `notify_mentors_on_job_publish()` (line ~430). The current guard:
|
||||
|
||||
```php
|
||||
if ( 'publish' !== $new_status || 'publish' === $old_status ) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
This correctly prevents re-notification when a published post is updated (publish -> publish),
|
||||
but it does NOT prevent re-notification when a previously-published job is edited and reset
|
||||
to pending (per decision 03-02: "Post status reset to pending after edit"), then republished
|
||||
by admin (pending -> publish). This second publish triggers notifications again.
|
||||
|
||||
The job lifecycle that causes the bug:
|
||||
1. Provider submits -> status: pending
|
||||
2. Admin publishes -> pending to publish -> mentors notified (CORRECT)
|
||||
3. Provider edits -> status reset to pending (per 03-02)
|
||||
4. Admin republishes -> pending to publish -> mentors notified AGAIN (BUG)
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add post meta guard to prevent duplicate mentor notifications</name>
|
||||
<files>includes/class-notifications.php</files>
|
||||
<action>
|
||||
In the `notify_mentors_on_job_publish` method, add a post meta check AFTER the existing
|
||||
status transition guard (line ~437) and BEFORE the mentor query (line ~442):
|
||||
|
||||
1. Check if post meta `_ddhh_mentors_notified` exists and equals `'1'` for this post.
|
||||
If it does, log a message like "DDHH Job Manager: Skipping mentor notification for
|
||||
job #%d - mentors already notified on initial publish" and return early.
|
||||
|
||||
2. After the `DDHH_JM_Scheduler::schedule_mentor_notification_batch()` call succeeds
|
||||
(line ~457), set post meta: `update_post_meta( $post->ID, '_ddhh_mentors_notified', '1' )`.
|
||||
|
||||
Use underscore-prefixed meta key `_ddhh_mentors_notified` so it is hidden from the
|
||||
WordPress custom fields UI.
|
||||
|
||||
Do NOT change any other logic in this method or file. The existing status transition
|
||||
guard should remain as-is (it still serves a purpose for publish->publish transitions).
|
||||
</action>
|
||||
<verify>
|
||||
1. Read the modified file and confirm:
|
||||
- `get_post_meta( $post->ID, '_ddhh_mentors_notified', true )` check exists before mentor query
|
||||
- `update_post_meta( $post->ID, '_ddhh_mentors_notified', '1' )` exists after scheduling
|
||||
- No other methods were modified
|
||||
2. Run `php -l includes/class-notifications.php` to confirm no syntax errors
|
||||
</verify>
|
||||
<done>
|
||||
The `notify_mentors_on_job_publish` method checks for `_ddhh_mentors_notified` post meta
|
||||
before scheduling notifications, and sets that meta after scheduling. This ensures mentors
|
||||
are only notified once per job, regardless of how many times the job transitions through
|
||||
pending -> publish.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. `php -l includes/class-notifications.php` passes with no syntax errors
|
||||
2. The `_ddhh_mentors_notified` meta key is checked before notification scheduling
|
||||
3. The `_ddhh_mentors_notified` meta key is set after successful scheduling
|
||||
4. No other notification methods were modified
|
||||
5. The existing `transition_post_status` guard logic is preserved
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- First publish of a job (pending -> publish) triggers mentor notifications and sets meta flag
|
||||
- Subsequent publishes of the same job (pending -> publish after edit) skip mentor notifications
|
||||
- Admin notifications for edits/republications are unaffected
|
||||
- No PHP syntax errors introduced
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/quick/002-fix-duplicate-mentor-notifications-on-jo/002-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
phase: quick-002
|
||||
plan: 01
|
||||
subsystem: notifications
|
||||
tags: [mentor-notifications, duplicate-prevention, post-meta, bug-fix]
|
||||
requires: [05-01, 05-03]
|
||||
provides:
|
||||
- Duplicate notification prevention using post meta
|
||||
- One-time mentor notification guarantee per job
|
||||
affects: []
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Post meta flags for one-time event tracking"
|
||||
- "Idempotent notification scheduling"
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- includes/class-notifications.php
|
||||
decisions:
|
||||
- key: "Use post meta `_ddhh_mentors_notified` for duplicate prevention"
|
||||
context: "Need to track whether mentors have been notified for a specific job"
|
||||
options: ["Post meta flag", "Custom database table", "Transient cache"]
|
||||
chosen: "Post meta flag"
|
||||
rationale: "Simple, reliable, persists forever, underscore-prefix hides from UI"
|
||||
- key: "Set meta flag after scheduling, not after emails sent"
|
||||
context: "When to mark job as notified"
|
||||
options: ["After scheduling batch", "After all emails sent", "Before scheduling"]
|
||||
chosen: "After scheduling batch"
|
||||
rationale: "Scheduling is synchronous and reliable; email sending is async and could fail individually"
|
||||
metrics:
|
||||
duration: 2
|
||||
completed: 2026-01-29
|
||||
---
|
||||
|
||||
# Quick Task 002: Fix Duplicate Mentor Notifications
|
||||
|
||||
**One-liner:** Post meta guard prevents mentor re-notification on job republish after edits
|
||||
|
||||
## What Was Built
|
||||
|
||||
Fixed a bug where mentors received duplicate "new job" notifications when a job was edited and republished.
|
||||
|
||||
**The Problem:**
|
||||
The job lifecycle includes a status reset to `pending` after provider edits (decision 03-02). This means:
|
||||
1. Provider submits → pending
|
||||
2. Admin publishes → pending to publish → mentors notified ✓
|
||||
3. Provider edits → status reset to pending
|
||||
4. Admin republishes → pending to publish → mentors notified AGAIN ✗
|
||||
|
||||
The existing guard `if ( 'publish' === $old_status )` only prevented publish→publish transitions, not pending→publish after edits.
|
||||
|
||||
**The Solution:**
|
||||
Added a post meta flag `_ddhh_mentors_notified` that:
|
||||
- Is checked before scheduling notifications (early return if already set)
|
||||
- Is set after successful batch scheduling
|
||||
- Persists for the lifetime of the job post
|
||||
- Uses underscore prefix to hide from WordPress custom fields UI
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
**Modified:** `includes/class-notifications.php`
|
||||
|
||||
1. **Pre-scheduling guard** (after line 439):
|
||||
- `get_post_meta( $post->ID, '_ddhh_mentors_notified', true )`
|
||||
- If value is `'1'`, log skip message and return early
|
||||
- Prevents duplicate scheduling entirely
|
||||
|
||||
2. **Post-scheduling flag** (after line 469):
|
||||
- `update_post_meta( $post->ID, '_ddhh_mentors_notified', '1' )`
|
||||
- Sets flag after `schedule_mentor_notification_batch()` succeeds
|
||||
- Ensures future republish attempts skip notification
|
||||
|
||||
**Why after scheduling, not after sending?**
|
||||
- Scheduling is synchronous and happens immediately
|
||||
- Email sending is async (Action Scheduler batches)
|
||||
- Individual emails might fail, but we still don't want re-notifications
|
||||
- The intent to notify has been recorded, which is what matters
|
||||
|
||||
## Verification
|
||||
|
||||
**Syntax Check:**
|
||||
```bash
|
||||
php -l includes/class-notifications.php
|
||||
# No syntax errors detected
|
||||
```
|
||||
|
||||
**Code Review:**
|
||||
- ✅ `get_post_meta` check exists before mentor query
|
||||
- ✅ `update_post_meta` exists after scheduling
|
||||
- ✅ No other notification methods modified
|
||||
- ✅ Existing publish→publish guard preserved
|
||||
- ✅ Underscore-prefixed meta key (hidden from UI)
|
||||
|
||||
## Job Lifecycle Flow (After Fix)
|
||||
|
||||
1. **Initial submission** (pending):
|
||||
- No notification (job not published yet)
|
||||
- `_ddhh_mentors_notified` = not set
|
||||
|
||||
2. **First publish** (pending → publish):
|
||||
- ✅ Mentors notified
|
||||
- `_ddhh_mentors_notified` = '1'
|
||||
|
||||
3. **Provider edits** (publish → pending):
|
||||
- No notification (deactivation)
|
||||
- `_ddhh_mentors_notified` = still '1'
|
||||
|
||||
4. **Republish after edit** (pending → publish):
|
||||
- ❌ Mentors NOT notified (meta flag prevents it)
|
||||
- `_ddhh_mentors_notified` = still '1'
|
||||
|
||||
5. **Any future republish**:
|
||||
- ❌ Mentors NOT notified (meta flag persists)
|
||||
|
||||
## Impact
|
||||
|
||||
**Fixed:**
|
||||
- Mentors no longer receive duplicate notifications for the same job
|
||||
- Reduces notification fatigue and confusion
|
||||
- Maintains trust in the notification system
|
||||
|
||||
**Unchanged:**
|
||||
- Admin notifications for edits (still sent, as intended)
|
||||
- First-time publish notifications (still sent)
|
||||
- Publish→publish guard (still prevents updates to published jobs)
|
||||
- Mentor opt-in/opt-out functionality
|
||||
|
||||
**Edge Cases Handled:**
|
||||
- Job edited multiple times: Only first publish notifies
|
||||
- Job unpublished and republished: Only first publish notifies
|
||||
- Job trashed and restored: Meta persists, no re-notification
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Testing Notes
|
||||
|
||||
**To verify in production:**
|
||||
|
||||
1. Create test job, submit as provider → status: pending
|
||||
2. Admin publishes → Check Action Scheduler for mentor notification batches
|
||||
3. Provider edits job → status: pending
|
||||
4. Admin republishes → Check Action Scheduler - should see NO new batches
|
||||
5. Check error_log for: "Skipping mentor notification for job #X - mentors already notified on initial publish"
|
||||
|
||||
**Manual database check:**
|
||||
```sql
|
||||
SELECT post_id, meta_value
|
||||
FROM wp_postmeta
|
||||
WHERE meta_key = '_ddhh_mentors_notified';
|
||||
```
|
||||
|
||||
Should show '1' for all published jobs that have triggered notifications.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Blockers:** None
|
||||
**Dependencies satisfied:** Builds on existing notification system (05-01, 05-03)
|
||||
**Follow-up needed:** None - fix is complete and self-contained
|
||||
|
||||
This was a targeted bug fix with no architectural implications. The notification system is now fully idempotent - each job triggers exactly one mentor notification batch in its lifetime.
|
||||
@@ -438,6 +438,18 @@ class DDHH_JM_Notifications {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if mentors have already been notified for this job
|
||||
$already_notified = get_post_meta( $post->ID, '_ddhh_mentors_notified', true );
|
||||
if ( '1' === $already_notified ) {
|
||||
error_log(
|
||||
sprintf(
|
||||
'DDHH Job Manager: Skipping mentor notification for job #%d - mentors already notified on initial publish',
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get opted-in mentors
|
||||
$mentor_ids = DDHH_JM_User_Preferences::get_opted_in_mentors();
|
||||
|
||||
@@ -456,6 +468,9 @@ class DDHH_JM_Notifications {
|
||||
// Schedule async batch notifications
|
||||
$batch_count = DDHH_JM_Scheduler::schedule_mentor_notification_batch( $mentor_ids, $post->ID );
|
||||
|
||||
// Mark job as having notified mentors to prevent duplicate notifications
|
||||
update_post_meta( $post->ID, '_ddhh_mentors_notified', '1' );
|
||||
|
||||
// Log success
|
||||
error_log(
|
||||
sprintf(
|
||||
|
||||
Reference in New Issue
Block a user