Skip to content

Conversation

@arifulhoque7
Copy link
Contributor

@arifulhoque7 arifulhoque7 commented Nov 18, 2025

Close issue , Related PRO PR

Fix Description: Event Update Issue in WPUF + Events Calendar Integration

Problem Summary

Editing an existing event via the WPUF Frontend Dashboard was creating a new event instead of updating the original.
Example: Editing event 6219 resulted in new events 6233, 6239, etc.

Root Cause

In both WPUF Free and Pro, the save_event() method always triggered create() instead of save().

Buggy Logic

// Always removed the ID
if ( isset( $args['ID'] ) ) {
    unset( $args['ID'] );
}

// Always created new events
$event = tribe_events()->set_args( $args )->create();

This caused:

  • The post ID to be discarded

  • TEC ORM to always execute create()

  • The update flow never executed


Solution Implemented

Update detection and proper TEC ORM update handling were added.
The fix was applied in:

  • ProTEC_Compatibility.php

  • FreeTEC_V6_Compatibility.php

Updated Logic

// Detect update
$post_id   = isset( $postarr['ID'] ) ? intval( $postarr['ID'] ) : 0;
$is_update = $post_id > 0;

// Remove ID for ORM, handled separately
if ( isset( $args['ID'] ) ) {
unset( $args['ID'] );
}

// Apply correct operation
if ( $is_update ) {
// Update event
$event = tribe_events()->where( 'id', $post_id )->set_args( $args )->save();
$event_id = $event ? $post_id : 0;
} else {
// Create new event
$event = tribe_events()->set_args( $args )->create();
$event_id = ( $event instanceof \WP_Post ) ? $event->ID : 0;
}


Key Improvements

1. Proper Update Detection

(lines 320–322 Pro, 467–469 Free)

  • Checks if an event ID exists

  • Determines whether to update or create

2. Correct TEC ORM Operations

(lines 343–349 Pro, 492–498 Free)

  • Update:
    tribe_events()->where('id', $post_id)->set_args($args)->save()

  • Create:
    tribe_events()->set_args($args)->create()

3. Unified Event ID Handling

(lines 345–348 Pro, 494–497 Free)

  • Standardized $event_id return value

  • Replaced all $event->ID references with $event_id


Technical Notes

This fix correctly uses The Events Calendar ORM API:

  • Create:
    tribe_events()->set_args($args)->create()

  • Update:
    tribe_events()->where('id', $post_id)->set_args($args)->save()

Matches TEC’s documented pattern:

tribe_organizers()
    ->where('id', 51)
    ->set('title', 'New Title')
    ->save();

Impact

Before Fix After Fix
Every edit created a new event duplicate Existing event updates correctly
Original post remained unchanged Event retains the same ID
update() path never executed Full compatibility with TEC ORM
Risk of database clutter No breaking changes, backward compatible

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved distinction between event creation and update operations for more reliable event handling.
    • Enhanced consistency of event ID tracking throughout the event lifecycle and downstream operations.

@arifulhoque7 arifulhoque7 requested a review from sapayth November 18, 2025 03:42
@arifulhoque7 arifulhoque7 self-assigned this Nov 18, 2025
@arifulhoque7 arifulhoque7 added needs: testing needs: dev review This PR needs review by a developer labels Nov 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2025

Walkthrough

The save_event function in the TEC V6 Compatibility module has been refactored to distinguish between update and create operations. It now computes post_id and is_update from the incoming data, delegates to appropriate ORM methods, and uses event_id consistently across all downstream operations including post updates and tagging assignments.

Changes

Cohort / File(s) Summary
Events Calendar Compatibility Logic Update
includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php
Modified save_event method to distinguish between update and create paths; delegates to tribe_events()->where('id', post_id)->set_args($args)->save() for updates or tribe_events()->set_args($args)->create() for creation; updated downstream operations to use event_id consistently; adjusted return value and action hook payload to reflect event_id for both paths

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Path distinction logic: Verify correctness of update vs. create path detection and argument handling in both branches
  • event_id consistency: Confirm event_id is properly propagated through post updates, tag assignments, term assignments, and action hooks
  • Return value handling: Ensure the change from returning WP_Post object ID to event_id doesn't break downstream consumers
  • ORM method chaining: Validate the ORM method calls (where, set_args, save, create) work correctly in both scenarios

Poem

🐰 The rabbit hops through update trails, ✨
Create and save now tell their tales,
Event IDs dance in perfect rows,
Update or birth—the logic flows! 🌱

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix/duplicate-event-on-update' directly and clearly describes the main issue being fixed: preventing duplicate events when updating existing events through the WPUF frontend.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php (3)

540-540: Consider action hook naming for updates.

The action hook wpuf_tec_after_create_event now fires for both create and update operations. This could be misleading for developers who hook into this action expecting it to only fire on event creation.

Consider one of these approaches:

  1. Rename the action to wpuf_tec_after_save_event to reflect both operations
  2. Add a separate action wpuf_tec_after_update_event for updates
  3. Add a parameter to indicate whether it was a create or update operation

Example for option 3:

-                    do_action( 'wpuf_tec_after_create_event', $event_id, $args, $postarr, $meta_vars, $form_id, $form_settings );
+                    do_action( 'wpuf_tec_after_create_event', $event_id, $args, $postarr, $meta_vars, $form_id, $form_settings, $is_update );

Or maintain backward compatibility with a new action:

do_action( 'wpuf_tec_after_create_event', $event_id, $args, $postarr, $meta_vars, $form_id, $form_settings );
if ( $is_update ) {
    do_action( 'wpuf_tec_after_update_event', $event_id, $args, $postarr, $meta_vars, $form_id, $form_settings );
}

497-503: Consider additional validation for update operation.

The update path assumes $event_id = $post_id when $event is truthy, but it doesn't verify that the update actually succeeded or that the post still exists afterward. The create path is more defensive with the instanceof \WP_Post check.

Consider adding validation for the update path:

                 if ( $is_update ) {
                     $event = tribe_events()->where( 'id', $post_id )->set_args( $args )->save();
-                    $event_id = $event ? $post_id : 0;
+                    // Verify the post exists after update
+                    $event_id = ( $event && get_post( $post_id ) ) ? $post_id : 0;
                 } else {

This ensures the event post actually exists before proceeding with tags and terms assignment.


32-43: Nonce verification is in place upstream—consider refactoring to use passed parameters instead of direct $_POST access.

The nonce verification concern is resolved: check_ajax_referer( 'wpuf_form_add' ) is called at the start of submit_post() in Frontend_Form_Ajax.php, before any form processing occurs. This protects the entire call chain leading to convert_form_data_to_orm_format().

However, lines 32 and 42 in TEC_V6_Compatibility.php directly access $_POST despite receiving sanitized $form_data as a parameter. Consider refactoring convert_form_data_to_orm_format() to rely on the passed parameters instead of redundantly accessing $_POST directly. This improves consistency and maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61f733e and 4ba8652.

📒 Files selected for processing (1)
  • includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php (3 hunks)
🧰 Additional context used
🪛 GitHub Actions: Inspections
includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php

[error] 1-1: Processing form data without nonce verification. Command failed: vendor/bin/phpcs includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php -q --report=checkstyle | cs2pr --graceful-warnings

Comment on lines +520 to +469
if ( ! empty( $args['categories'] ) ) {
wp_set_post_terms( $event->ID, $args['categories'], 'tribe_events_cat', false );
wp_set_post_terms( $event_id, $args['categories'], 'tribe_events_cat', false );
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Update detection logic looks correct.

The logic correctly identifies update operations by checking for a positive post ID in $postarr['ID']. This is the key fix that prevents duplicate event creation.

Please verify that TEC ORM handles gracefully when where('id', $post_id) is called with a non-existent post ID. Run this script to confirm the TEC ORM behavior:


🏁 Script executed:

#!/bin/bash
# Description: Search for TEC ORM update patterns and error handling in the codebase

# Search for other usages of tribe_events()->where() to understand the pattern
rg -n -A5 -B2 "tribe_events\(\)->where\(" --type=php

# Search for TEC ORM save() method usage and return value handling
rg -n -A3 "->save\(\)" --type=php -g "*TEC*.php"

Length of output: 1497


I see partial results from the script. Let me search more thoroughly for TEC ORM error handling patterns and documentation.


🏁 Script executed:

#!/bin/bash
# Search for save() method usage patterns in PHP files (fixed syntax)
rg -n -A3 'save\(\)' --type=php -g '!node_modules' | head -50

# Search for any TEC ORM documentation or comments
rg -n 'tribe_events' --type=php -B2 -A2 | grep -E '(comment|doc|/\*|return|TEC)' | head -30

# Search for the tribe_events function definition or usage context
rg -n 'where.*save' --type=php -C2

Length of output: 5275


Let me search more specifically for TEC ORM patterns and type handling in this file:


🏁 Script executed:

#!/bin/bash
# Search the entire TEC_V6_Compatibility.php file for WP_Post checks and save() patterns
cat includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php | grep -n "WP_Post\|instanceof\|save\|->where"

# Also check if there are comments about TEC ORM or tribe_events return values
cat includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php | grep -n -i "tec\|tribe_events\|return" | head -40

Length of output: 4118


Inconsistent error handling between update and create paths.

The update operation at line 498-499 only checks if $event is truthy, whereas the create operation at line 501-502 explicitly validates that $event instanceof \WP_Post. To maintain consistency and prevent potential issues if save() returns a truthy non-Post value, update the error handling:

$event = tribe_events()->where( 'id', $post_id )->set_args( $args )->save();
$event_id = ( $event instanceof \WP_Post ) ? $post_id : 0;

This mirrors the type safety check used in the create path and ensures the operation truly succeeded.

🤖 Prompt for AI Agents
In includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php
around lines 466 to 469, the update path only checks that $event is truthy while
the create path explicitly validates $event instanceof \WP_Post; modify the
update handling to mirror the create path by checking the returned $event is an
instance of \WP_Post and set $event_id to $post_id only in that case (otherwise
set to 0), ensuring type-safe success detection after calling save().

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify TEC ORM API return values for save() and create().

The branching logic correctly separates update and create operations, which is the primary fix for the duplicate event issue. However, the assumptions about return values need verification:

  • Line 499: Assumes save() returns a truthy value on success
  • Line 502: Assumes create() returns a WP_Post instance on success

Please verify the TEC ORM API documentation or search for the expected return values:


🌐 Web query:

The Events Calendar ORM save method return value

💡 Result:

Short answer: The ORM's save() has a mixed return and — per The Events Calendar docs — can return NULL when updating (this is a known/being-investigated issue). See the ORM update docs and overview. [1][2]

Sources:

  • Update Arguments / save() note. [1]
  • ORM overview (notes save() update currently not working for all repositories). [2]

🌐 Web query:

The Events Calendar ORM create method return value

💡 Result:

  • Using the ORM: tribe_events()->set_args( $args )->create() — returns the newly created WP_Post object on success, or false on failure. [1]

  • Legacy helper: tribe_create_event( $args ) — returns the new event ID (int) on success, or false on failure. [2]

Sources: The Events Calendar docs. [1] Create Events (ORM) — API docs. [2] tribe_create_event() reference.


Fix update path: save() returns NULL on success, breaking the event_id assignment.

The create path (lines 500-502) correctly handles the return value. However, the update path has a critical flaw:

The TEC ORM's save() method can return NULL when updating, which is a known/being-investigated issue. Since line 499 checks $event ? $post_id : 0;, a NULL return (even on success) will incorrectly set $event_id = 0, defeating the purpose of this fix.

Required fix: Replace the NULL-unsafe check at line 499 with a check that verifies the update succeeded, such as checking if the post exists after the update attempt or using a different validation approach.

@Rubaiyat-E-Mohammad Rubaiyat-E-Mohammad added QA Approved This PR is approved by the QA team and removed needs: testing labels Nov 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs: dev review This PR needs review by a developer QA Approved This PR is approved by the QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants