-
Notifications
You must be signed in to change notification settings - Fork 842
Forms: Add form fill duration to feedback #45786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: minor | ||
| Type: added | ||
|
|
||
| Forms: add form fill duration to form entries |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -466,6 +466,18 @@ const { state, actions } = store( NAMESPACE, { | |
| event.stopPropagation(); | ||
| context.submissionError = null; | ||
|
|
||
| // Calculate and set the form fill duration before submission | ||
| if ( context.formFirstInteractionTime ) { | ||
| const duration = Math.round( ( Date.now() - context.formFirstInteractionTime ) / 1000 ); // Duration in seconds | ||
| const form = document.getElementById( 'jp-form-' + context.formHash ); | ||
| if ( form ) { | ||
| const durationField = form.querySelector( 'input[name="form_fill_duration"]' ); | ||
| if ( durationField ) { | ||
| durationField.value = duration; | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+469
to
+479
|
||
|
|
||
| const { success, error, data, refreshArgs } = yield submitForm( context.formHash ); | ||
|
|
||
| if ( success ) { | ||
|
|
@@ -558,6 +570,14 @@ const { state, actions } = store( NAMESPACE, { | |
| registerField( fieldId, fieldType, fieldLabel, fieldValue, fieldIsRequired, fieldExtra ); | ||
| }, | ||
|
|
||
| trackFirstInteraction() { | ||
| const context = getContext(); | ||
| // Store the first interaction time when user focuses on any form field | ||
| if ( ! context.formFirstInteractionTime ) { | ||
| context.formFirstInteractionTime = Date.now(); | ||
| } | ||
| }, | ||
|
|
||
| scrollToWrapper() { | ||
| const context = getContext(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -360,6 +360,44 @@ public function test_country_code_included_in_serialized_response() { | |
| remove_filter( 'jetpack_get_country_from_ip', $filter_callback, 10 ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that form_fill_duration is included in serialized response and persists after save/load. | ||
| */ | ||
| public function test_form_fill_duration_persists_after_save() { | ||
|
|
||
| $form_id = Utility::get_form_id(); | ||
| // Create a form submission with form_fill_duration | ||
| $_post_data = Utility::get_post_request( | ||
| array( | ||
| 'name' => 'John Doe', | ||
| 'email' => '[email protected]', | ||
| 'message' => 'Test message', | ||
| 'form_fill_duration' => '45', // 45 seconds | ||
| ), | ||
| 'g' . $form_id | ||
| ); | ||
|
|
||
| $form = new Contact_Form( | ||
| array( | ||
| 'title' => 'Test Form', | ||
| 'description' => 'This is a test form.', | ||
| ), | ||
| "[contact-field label='Name' type='name' required='1'/][contact-field label='Email' type='email' required='1'/][contact-field label='Message' type='textarea' required='1'/]" | ||
| ); | ||
|
|
||
| // Create a contact form response | ||
| $response = Feedback::from_submission( $_post_data, $form ); | ||
| $feedback_post_id = $response->save(); | ||
| $saved_response = Feedback::get( $feedback_post_id ); | ||
|
|
||
| // The form_fill_duration should be present and match the test value. | ||
| $this->assertNotEmpty( $response->get_form_fill_duration(), 'Form fill duration should not be empty' ); | ||
| $this->assertNotEmpty( $saved_response->get_form_fill_duration(), 'Form fill duration should not be empty after save/load' ); | ||
| $this->assertEquals( $response->get_form_fill_duration(), $saved_response->get_form_fill_duration(), 'Form fill duration should match after save/load' ); | ||
| $this->assertEquals( 45, $saved_response->get_form_fill_duration(), 'Form fill duration should be 45 seconds' ); | ||
| $this->assertIsInt( $saved_response->get_form_fill_duration(), 'Form fill duration should be an integer' ); | ||
| } | ||
|
|
||
| /** | ||
| * Test the browser information is parsed correctly from user agent. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: minor | ||
| Type: enhancement | ||
|
|
||
| Forms: Add form fill duration to feedback entries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sanitize_callback 'absint' will convert null values to 0, which is inconsistent with the schema type that allows null. This will prevent null values from being properly represented in the API response for older submissions. Consider using a custom sanitization callback that preserves null values or removing the sanitize_callback since the field is readonly and already sanitized during storage.