Skip to content

Instantly share code, notes, and snippets.

@RadGH
Last active February 17, 2025 02:53
Show Gist options
  • Select an option

  • Save RadGH/2e419f7b67974f969e55fa3556f652fc to your computer and use it in GitHub Desktop.

Select an option

Save RadGH/2e419f7b67974f969e55fa3556f652fc to your computer and use it in GitHub Desktop.
Edit an existing gravityforms entry on the frontend
<?php
if ( !defined( 'ABSPATH' ) ) exit;
// This is an example for a specific form type.
// You must also call new Renewal(); somewhere.
// Alternatively this class can be used as an abstract class (inherit-only) and then you can extend this class for multiple forms.
class Renewal {
// Gravity Forms settings use during submission and to edit existing entries.
public $form_id = 1;
// You must put all fields with values (except for file inputs) into this array. This allows them to be given values.
// You may need to add your own function for certain field types.
// Each field needs to have the "Allow populate from URL" option enabled and given a name that you use as the "name" parameter here.
// Gravity Forms has WILDLY INCONSISTENT hooks for filtering the field value otherwise.
public $fields = array(
// key // gravity form details
// 'user_id' => array( 'field_id' => 1, 'name' => false, 'type' => 'text' ),
);
public function __construct() {
// Certain functions needed when adding hooks are loaded elsewhere in the theme. Hook at init to fix this.
add_action( 'after_setup_theme', array( $this, 'add_gravityform_editable_hooks' ) );
}
/**
* Return true if the given user is able to make edits to the entry.
*
* @param $user_id
* @param $entry_id
*
* @return bool
*/
public function can_user_edit_entry( $user_id, $entry_id ) {
$entry = GFAPI::get_entry( $entry_id );
if ( !$entry || is_wp_error($entry) ) return false;
// Must be an entry belonging to this renewal form
if ( $entry['form_id'] != $this->form_id ) return false;
// Check if user is owner of the entry
if ( (int) $entry['created_by'] != (int) $user_id ) return false;
// Check if status of entry is no longer "active". Only active entries can be edited
if ( $entry['status'] !== 'active' ) return false;
return true;
}
/**
* Get the user's current inactive pli renewal entry
* - Must be active (not trashed)
* - Must be created by the user_id
*
* @param $user_id
*
* @return int|false
*/
public function get_user_active_entry( $user_id = null ) {
if ( $user_id === null ) $user_id = get_current_user_id();
// Get entries by this user from this form in the last year, where reinstatement required = 1
$search_args = array(
'status' => 'active',
'field_filters' => array(
array(
'key' => 'created_by',
'value' => $user_id
),
),
);
$existing_entry_ids = GFAPI::get_entry_ids( $this->form_id, $search_args );
if ( $existing_entry_ids ) {
return (int) $existing_entry_ids[0];
}else{
return false;
}
}
/**
* Add hooks so that this form can be modified
*/
public function add_gravityform_editable_hooks() {
// Form id must be specified
if ( $this->form_id === null ) return;
// Allow editing previous insurance entry, if reinstatement needed and admin reinstatement tracking allows for it
add_filter( "gform_entry_id_pre_save_lead_{$this->form_id}", array( $this, 'edit_existing_entry' ), 50, 2 );
// Add saved files to edited entry when the form started to be rendered
add_filter( "gform_pre_render_{$this->form_id}", array( $this, 'prepare_previously_uploaded_files' ), 20, 3 );
// Fill in the value of all fields that have a name. The name must match the "autofill parameter name" in the field's settings.
foreach( $this->fields as $key => $field ) {
if ( $field['name'] ) switch( $field['type'] ) {
case 'text':
// Fill text field
add_filter( "gform_field_value_{$field['name']}", array( $this, 'fill_field_value_text' ), 20, 3 );
break;
case 'sub_field_text':
// Fill sub_field_text field
add_filter( "gform_field_value_{$field['name']}", array( $this, 'fill_field_value_sub_field_text' ), 20, 3 );
break;
}
}
}
/**
* Set up "uploaded_files" using values from the previous entry. Allows you to keep your previous upload, or remove it and start over.
*
* @param $form
* @param $ajax
* @param $field_values
*
* @return mixed
*/
public function prepare_previously_uploaded_files( $form, $ajax, $field_values ) {
$user_id = get_current_user_id();
$entry_id = $this->get_user_active_entry( $user_id );
if ( ! $this->can_user_edit_entry( $user_id, $entry_id ) ) return $form;
$entry = GFAPI::get_entry( $entry_id );
if ( !isset(GFFormsModel::$uploaded_files[$form['id']]) ) {
GFFormsModel::$uploaded_files[$form['id']] = array();
}
foreach( $form['fields'] as $field ) {
if ( ! $field instanceof GF_Field_FileUpload ) continue;
$value = rgar( $entry, $field->id );
GFFormsModel::$uploaded_files[$form['id']]["input_{$field->id}"] = basename($value);
}
return $form;
}
/**
* Gets a field from $this->fields based on field_id instead of name
*
* @param $value
*
* @return bool|mixed
*/
public function get_field_definition_by_field_id( $value ) {
foreach( $this->fields as $key => $f ) {
if ( $f['field_id'] == $value ) return $f;
}
return false;
}
/**
* Gets a field from $this->fields based on pre-populate name instead of key
*
* @param $value
*
* @return bool|mixed
*/
public function get_field_definition_by_field_name( $value ) {
foreach( $this->fields as $key => $f ) {
if ( $f['name'] == $value ) return $f;
}
return false;
}
/**
* Allow editing previous form entry
*
* @param $entry_id
* @param $form
*
* @return mixed
*/
public function edit_existing_entry( $entry_id, $form ) {
if ( $entry_id !== null ) return $entry_id;
$user_id = get_current_user_id();
// Get the user's existing entry
$existing_entry_id = $this->get_user_active_entry( $user_id );
// If they have not previously submitted an entry, use the new one.
if ( !$existing_entry_id ) {
return $entry_id;
}
// If the user is permitted to edit an existing entry, return that entry ID to be updated instead of the new one.
if ( $this->can_user_edit_entry( $user_id, $existing_entry_id ) ) {
return $existing_entry_id;
}
return $entry_id;
}
/**
* Fill text fields with the value of an existing entry
*
* @param null $value
* @param GF_Field|null $field
* @param null $name
*
* @return string
*/
public function fill_field_value_text( $value = null, GF_Field $field = null, $name = null ) {
$existing_entry_id = $this->get_user_active_entry();
if ( $existing_entry_id ) {
$value = gform_get_meta( $existing_entry_id, $field['id'] );
}
return $value;
}
/**
* Fill text fields for sub-fields from an existing entry. These fields use meta keys like "15.3" for "Address -> City".
*
* @param null $value
* @param GF_Field|null $field
* @param null $name
*
* @return bool|mixed|null
*/
public function fill_field_value_sub_field_text( $value = null, GF_Field $field = null, $name = null ) {
$existing_entry_id = $this->get_user_active_entry();
if ( $existing_entry_id ) {
$field_definition = $this->get_field_definition_by_field_name( $name );
if ( $field_definition ) {
$meta_key = $field['id'] . '.' . $field_definition['sub_field_index']; // 15.3 = Address[city]
$value = gform_get_meta( $existing_entry_id, $meta_key );
}
}
return $value;
}
}
@RadGH
Copy link
Copy Markdown
Author

RadGH commented Jun 25, 2020

Updated so you do not need to manually type in all the field names and IDs. Hooray!

@RadGH
Copy link
Copy Markdown
Author

RadGH commented Jul 14, 2020

Updated:

  • Added support for Checkbox fields which has one name and multiple values (array). Add others to the "$compound_field_types" array.
  • Added support for "compound" fields like the Name and Address field, with multiple sub-inputs that each have a name and value.
  • Continued support for "date" field which, although it acts like a compound field, only returns a single value.
  • Fixed hooks running every page load, which would get the form data even if the form was never used on a page.

PS: Gravity forms is ridiculously inconsistent

@RadGH
Copy link
Copy Markdown
Author

RadGH commented May 16, 2022

Updated:

  1. Major change: You no longer need to manually enable auto populate on every field. Fields are made to prepopulate automatically based on "add_form_prepopulate_names".

  2. A working example is provided, see QUICK TEST INSTRUCTIONS and import this form: https://gist.github.com/RadGH/afb032d642515aedbb068f6b5990b668

  3. Files handled better. If you do not remove or replace a file, it will now be preserved

  4. The class "GF_Form_12" is an example you should copy and customize. The class "Editable_GF_Form" you generally shouldn't need to touch.

@Antonio78
Copy link
Copy Markdown

Hi, how can I prevent confirmation emails from being sent when the form is in edit mode?
I have tried adding a remove filter, and also changing the email sending filter but to no avail..

@ashish200025
Copy link
Copy Markdown

HI RadGH

Is there way we can show the uploaded file when file is multi File upload input Field?

Thanks

@LoreGre
Copy link
Copy Markdown

LoreGre commented Nov 22, 2024

Hi,
please someone find solutions for multi files upload issue?

@LoreGre
Copy link
Copy Markdown

LoreGre commented Nov 22, 2024

I edit row 425 like this. But the filename not work. Please let me know if someone solve it. regards

`$value = rgar( $entry, $field->id );

	if( !str_contains($value, '[') ){
		GFFormsModel::$uploaded_files[ $form['id'] ]["input_{$field->id}"] = basename($value);
	} else {
		$values = json_decode($value);
		$urls = array();
		foreach($values as $url){
			$urls[] = basename($url);
		}
		GFFormsModel::$uploaded_files[ $form['id'] ]["input_{$field->id}"] = $urls;
	}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment